mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge branch 'main' into ts53-ts
This commit is contained in:
@@ -145,9 +145,9 @@ namespace Semmle.Autobuild.Cpp.Tests
|
|||||||
|
|
||||||
bool IBuildActions.IsMacOs() => IsMacOs;
|
bool IBuildActions.IsMacOs() => IsMacOs;
|
||||||
|
|
||||||
public bool IsArm { get; set; }
|
public bool IsRunningOnAppleSilicon { get; set; }
|
||||||
|
|
||||||
bool IBuildActions.IsArm() => IsArm;
|
bool IBuildActions.IsRunningOnAppleSilicon() => IsRunningOnAppleSilicon;
|
||||||
|
|
||||||
string IBuildActions.PathCombine(params string[] parts)
|
string IBuildActions.PathCombine(params string[] parts)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,3 +1,17 @@
|
|||||||
|
## 0.12.0
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* The expressions `AssignPointerAddExpr` and `AssignPointerSubExpr` are no longer subtypes of `AssignBitwiseOperation`.
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* The "Returning stack-allocated memory" (`cpp/return-stack-allocated-memory`) query now also detects returning stack-allocated memory allocated by calls to `alloca`, `strdupa`, and `strndupa`.
|
||||||
|
* Added models for `strlcpy` and `strlcat`.
|
||||||
|
* Added models for the `sprintf` variants from the `StrSafe.h` header.
|
||||||
|
* Added SQL API models for `ODBC`.
|
||||||
|
* Added taint models for `realloc` and related functions.
|
||||||
|
|
||||||
## 0.11.0
|
## 0.11.0
|
||||||
|
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: minorAnalysis
|
|
||||||
---
|
|
||||||
* Added taint models for `realloc` and related functions.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: breaking
|
|
||||||
---
|
|
||||||
* The expressions `AssignPointerAddExpr` and `AssignPointerSubExpr` are no longer subtypes of `AssignBitwiseOperation`.
|
|
||||||
13
cpp/ql/lib/change-notes/released/0.12.0.md
Normal file
13
cpp/ql/lib/change-notes/released/0.12.0.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
## 0.12.0
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* The expressions `AssignPointerAddExpr` and `AssignPointerSubExpr` are no longer subtypes of `AssignBitwiseOperation`.
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* The "Returning stack-allocated memory" (`cpp/return-stack-allocated-memory`) query now also detects returning stack-allocated memory allocated by calls to `alloca`, `strdupa`, and `strndupa`.
|
||||||
|
* Added models for `strlcpy` and `strlcat`.
|
||||||
|
* Added models for the `sprintf` variants from the `StrSafe.h` header.
|
||||||
|
* Added SQL API models for `ODBC`.
|
||||||
|
* Added taint models for `realloc` and related functions.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.11.0
|
lastReleaseVersion: 0.12.0
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-all
|
name: codeql/cpp-all
|
||||||
version: 0.11.1-dev
|
version: 0.12.1-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dbscheme: semmlecode.cpp.dbscheme
|
dbscheme: semmlecode.cpp.dbscheme
|
||||||
extractor: cpp
|
extractor: cpp
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ abstract class MustFlowConfiguration extends string {
|
|||||||
*/
|
*/
|
||||||
abstract predicate isSink(Operand sink);
|
abstract predicate isSink(Operand sink);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow through `instr` is prohibited.
|
||||||
|
*/
|
||||||
|
predicate isBarrier(Instruction instr) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||||
* into account in the analysis.
|
* into account in the analysis.
|
||||||
@@ -48,18 +53,21 @@ abstract class MustFlowConfiguration extends string {
|
|||||||
*/
|
*/
|
||||||
final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) {
|
final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) {
|
||||||
this.isSource(source.getInstruction()) and
|
this.isSource(source.getInstruction()) and
|
||||||
source.getASuccessor+() = sink
|
source.getASuccessor*() = sink
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if `node` flows from a source. */
|
/** Holds if `node` flows from a source. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) {
|
private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) {
|
||||||
config.isSource(node)
|
not config.isBarrier(node) and
|
||||||
or
|
(
|
||||||
exists(Instruction mid |
|
config.isSource(node)
|
||||||
step(mid, node, config) and
|
or
|
||||||
flowsFromSource(mid, pragma[only_bind_into](config))
|
exists(Instruction mid |
|
||||||
|
step(mid, node, config) and
|
||||||
|
flowsFromSource(mid, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,14 @@ class Node0Impl extends TIRDataFlowNode0 {
|
|||||||
/** Gets the operands corresponding to this node, if any. */
|
/** Gets the operands corresponding to this node, if any. */
|
||||||
Operand asOperand() { result = this.(OperandNode0).getOperand() }
|
Operand asOperand() { result = this.(OperandNode0).getOperand() }
|
||||||
|
|
||||||
|
/** Gets the location of this node. */
|
||||||
|
final Location getLocation() { result = this.getLocationImpl() }
|
||||||
|
|
||||||
|
/** INTERNAL: Do not use. */
|
||||||
|
Location getLocationImpl() {
|
||||||
|
none() // overridden by subclasses
|
||||||
|
}
|
||||||
|
|
||||||
/** INTERNAL: Do not use. */
|
/** INTERNAL: Do not use. */
|
||||||
string toStringImpl() {
|
string toStringImpl() {
|
||||||
none() // overridden by subclasses
|
none() // overridden by subclasses
|
||||||
@@ -131,9 +139,15 @@ abstract class InstructionNode0 extends Node0Impl {
|
|||||||
override DataFlowType getType() { result = getInstructionType(instr, _) }
|
override DataFlowType getType() { result = getInstructionType(instr, _) }
|
||||||
|
|
||||||
override string toStringImpl() {
|
override string toStringImpl() {
|
||||||
// This predicate is overridden in subclasses. This default implementation
|
if instr.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
||||||
// does not use `Instruction.toString` because that's expensive to compute.
|
then result = "this"
|
||||||
result = instr.getOpcode().toString()
|
else result = instr.getAst().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Location getLocationImpl() {
|
||||||
|
if exists(instr.getAst().getLocation())
|
||||||
|
then result = instr.getAst().getLocation()
|
||||||
|
else result instanceof UnknownDefaultLocation
|
||||||
}
|
}
|
||||||
|
|
||||||
final override predicate isGLValue() { exists(getInstructionType(instr, true)) }
|
final override predicate isGLValue() { exists(getInstructionType(instr, true)) }
|
||||||
@@ -173,7 +187,17 @@ abstract class OperandNode0 extends Node0Impl {
|
|||||||
|
|
||||||
override DataFlowType getType() { result = getOperandType(op, _) }
|
override DataFlowType getType() { result = getOperandType(op, _) }
|
||||||
|
|
||||||
override string toStringImpl() { result = op.toString() }
|
override string toStringImpl() {
|
||||||
|
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
||||||
|
then result = "this"
|
||||||
|
else result = op.getDef().getAst().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Location getLocationImpl() {
|
||||||
|
if exists(op.getDef().getAst().getLocation())
|
||||||
|
then result = op.getDef().getAst().getLocation()
|
||||||
|
else result instanceof UnknownDefaultLocation
|
||||||
|
}
|
||||||
|
|
||||||
final override predicate isGLValue() { exists(getOperandType(op, true)) }
|
final override predicate isGLValue() { exists(getOperandType(op, true)) }
|
||||||
}
|
}
|
||||||
@@ -621,6 +645,24 @@ class GlobalLikeVariable extends Variable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the smallest indirection for the type `t`.
|
||||||
|
*
|
||||||
|
* For most types this is `1`, but for `ArrayType`s (which are allocated on
|
||||||
|
* the stack) this is `0`
|
||||||
|
*/
|
||||||
|
int getMinIndirectionsForType(Type t) {
|
||||||
|
if t.getUnspecifiedType() instanceof Cpp::ArrayType then result = 0 else result = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getMinIndirectionForGlobalUse(Ssa::GlobalUse use) {
|
||||||
|
result = getMinIndirectionsForType(use.getUnspecifiedType())
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getMinIndirectionForGlobalDef(Ssa::GlobalDef def) {
|
||||||
|
result = getMinIndirectionsForType(def.getUnspecifiedType())
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if data can flow from `node1` to `node2` in a way that loses the
|
* Holds if data can flow from `node1` to `node2` in a way that loses the
|
||||||
* calling context. For example, this would happen with flow through a
|
* calling context. For example, this would happen with flow through a
|
||||||
@@ -632,20 +674,20 @@ predicate jumpStep(Node n1, Node n2) {
|
|||||||
v = globalUse.getVariable() and
|
v = globalUse.getVariable() and
|
||||||
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
||||||
|
|
|
|
||||||
globalUse.getIndirectionIndex() = 1 and
|
globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
|
||||||
v = n2.asVariable()
|
v = n2.asVariable()
|
||||||
or
|
or
|
||||||
v = n2.asIndirectVariable(globalUse.getIndirectionIndex())
|
v = n2.asIndirectVariable(globalUse.getIndirection())
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(Ssa::GlobalDef globalDef |
|
exists(Ssa::GlobalDef globalDef |
|
||||||
v = globalDef.getVariable() and
|
v = globalDef.getVariable() and
|
||||||
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
||||||
|
|
|
|
||||||
globalDef.getIndirectionIndex() = 1 and
|
globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
|
||||||
v = n1.asVariable()
|
v = n1.asVariable()
|
||||||
or
|
or
|
||||||
v = n1.asIndirectVariable(globalDef.getIndirectionIndex())
|
v = n1.asIndirectVariable(globalDef.getIndirection())
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ cached
|
|||||||
private newtype TIRDataFlowNode =
|
private newtype TIRDataFlowNode =
|
||||||
TNode0(Node0Impl node) { DataFlowImplCommon::forceCachingInSameStage() } or
|
TNode0(Node0Impl node) { DataFlowImplCommon::forceCachingInSameStage() } or
|
||||||
TVariableNode(Variable var, int indirectionIndex) {
|
TVariableNode(Variable var, int indirectionIndex) {
|
||||||
indirectionIndex = [1 .. Ssa::getMaxIndirectionsForType(var.getUnspecifiedType())]
|
indirectionIndex =
|
||||||
|
[getMinIndirectionsForType(var.getUnspecifiedType()) .. Ssa::getMaxIndirectionsForType(var.getUnspecifiedType())]
|
||||||
} or
|
} or
|
||||||
TPostFieldUpdateNode(FieldAddress operand, int indirectionIndex) {
|
TPostFieldUpdateNode(FieldAddress operand, int indirectionIndex) {
|
||||||
indirectionIndex =
|
indirectionIndex =
|
||||||
@@ -346,7 +347,9 @@ class Node extends TIRDataFlowNode {
|
|||||||
* Gets the variable corresponding to this node, if any. This can be used for
|
* Gets the variable corresponding to this node, if any. This can be used for
|
||||||
* modeling flow in and out of global variables.
|
* modeling flow in and out of global variables.
|
||||||
*/
|
*/
|
||||||
Variable asVariable() { this = TVariableNode(result, 1) }
|
Variable asVariable() {
|
||||||
|
this = TVariableNode(result, getMinIndirectionsForType(result.getUnspecifiedType()))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the `indirectionIndex`'th indirection of this node's underlying variable, if any.
|
* Gets the `indirectionIndex`'th indirection of this node's underlying variable, if any.
|
||||||
@@ -354,7 +357,7 @@ class Node extends TIRDataFlowNode {
|
|||||||
* This can be used for modeling flow in and out of global variables.
|
* This can be used for modeling flow in and out of global variables.
|
||||||
*/
|
*/
|
||||||
Variable asIndirectVariable(int indirectionIndex) {
|
Variable asIndirectVariable(int indirectionIndex) {
|
||||||
indirectionIndex > 1 and
|
indirectionIndex > getMinIndirectionsForType(result.getUnspecifiedType()) and
|
||||||
this = TVariableNode(result, indirectionIndex)
|
this = TVariableNode(result, indirectionIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,6 +435,10 @@ private class Node0 extends Node, TNode0 {
|
|||||||
|
|
||||||
override Declaration getFunction() { result = node.getFunction() }
|
override Declaration getFunction() { result = node.getFunction() }
|
||||||
|
|
||||||
|
override Location getLocationImpl() { result = node.getLocation() }
|
||||||
|
|
||||||
|
override string toStringImpl() { result = node.toString() }
|
||||||
|
|
||||||
override DataFlowType getType() { result = node.getType() }
|
override DataFlowType getType() { result = node.getType() }
|
||||||
|
|
||||||
override predicate isGLValue() { node.isGLValue() }
|
override predicate isGLValue() { node.isGLValue() }
|
||||||
@@ -448,18 +455,6 @@ class InstructionNode extends Node0 {
|
|||||||
|
|
||||||
/** Gets the instruction corresponding to this node. */
|
/** Gets the instruction corresponding to this node. */
|
||||||
Instruction getInstruction() { result = instr }
|
Instruction getInstruction() { result = instr }
|
||||||
|
|
||||||
override Location getLocationImpl() {
|
|
||||||
if exists(instr.getAst().getLocation())
|
|
||||||
then result = instr.getAst().getLocation()
|
|
||||||
else result instanceof UnknownDefaultLocation
|
|
||||||
}
|
|
||||||
|
|
||||||
override string toStringImpl() {
|
|
||||||
if instr.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
|
||||||
then result = "this"
|
|
||||||
else result = instr.getAst().toString()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -473,18 +468,6 @@ class OperandNode extends Node, Node0 {
|
|||||||
|
|
||||||
/** Gets the operand corresponding to this node. */
|
/** Gets the operand corresponding to this node. */
|
||||||
Operand getOperand() { result = op }
|
Operand getOperand() { result = op }
|
||||||
|
|
||||||
override Location getLocationImpl() {
|
|
||||||
if exists(op.getDef().getAst().getLocation())
|
|
||||||
then result = op.getDef().getAst().getLocation()
|
|
||||||
else result instanceof UnknownDefaultLocation
|
|
||||||
}
|
|
||||||
|
|
||||||
override string toStringImpl() {
|
|
||||||
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
|
||||||
then result = "this"
|
|
||||||
else result = op.getDef().getAst().toString()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1293,31 +1276,90 @@ abstract private class IndirectExprNodeBase extends Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
|
/** A signature for converting an indirect node to an expression. */
|
||||||
{
|
private signature module IndirectNodeToIndirectExprSig {
|
||||||
IndirectOperandIndirectExprNode() {
|
/** The indirect node class to be converted to an expression */
|
||||||
exists(Expr e, int n, int indirectionIndex |
|
class IndirectNode;
|
||||||
indirectExprNodeShouldBeIndirectOperand(this, e, n, indirectionIndex) and
|
|
||||||
not indirectExprNodeShouldBeIndirectOperand(_, e, n + 1, indirectionIndex)
|
/**
|
||||||
)
|
* Holds if the indirect expression at indirection index `indirectionIndex`
|
||||||
|
* of `node` is `e`. The integer `n` specifies how many conversions has been
|
||||||
|
* applied to `node`.
|
||||||
|
*/
|
||||||
|
predicate indirectNodeHasIndirectExpr(IndirectNode node, Expr e, int n, int indirectionIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A module that implements the logic for deciding whether an indirect node
|
||||||
|
* should be an `IndirectExprNode`.
|
||||||
|
*/
|
||||||
|
private module IndirectNodeToIndirectExpr<IndirectNodeToIndirectExprSig Sig> {
|
||||||
|
import Sig
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This predicate shifts the indirection index by one when `conv` is a
|
||||||
|
* `ReferenceDereferenceExpr`.
|
||||||
|
*
|
||||||
|
* This is necessary because `ReferenceDereferenceExpr` is a conversion
|
||||||
|
* in the AST, but appears as a `LoadInstruction` in the IR.
|
||||||
|
*/
|
||||||
|
bindingset[e, indirectionIndex]
|
||||||
|
private predicate adjustForReference(
|
||||||
|
Expr e, int indirectionIndex, Expr conv, int adjustedIndirectionIndex
|
||||||
|
) {
|
||||||
|
conv.(ReferenceDereferenceExpr).getExpr() = e and
|
||||||
|
adjustedIndirectionIndex = indirectionIndex - 1
|
||||||
|
or
|
||||||
|
not conv instanceof ReferenceDereferenceExpr and
|
||||||
|
conv = e and
|
||||||
|
adjustedIndirectionIndex = indirectionIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
final override Expr getConvertedExpr(int n, int index) {
|
/** Holds if `node` should be an `IndirectExprNode`. */
|
||||||
indirectExprNodeShouldBeIndirectOperand(this, result, n, index)
|
predicate charpred(IndirectNode node) {
|
||||||
|
exists(Expr e, int n, int indirectionIndex |
|
||||||
|
indirectNodeHasIndirectExpr(node, e, n, indirectionIndex) and
|
||||||
|
not exists(Expr conv, int adjustedIndirectionIndex |
|
||||||
|
adjustForReference(e, indirectionIndex, conv, adjustedIndirectionIndex) and
|
||||||
|
indirectNodeHasIndirectExpr(_, conv, n + 1, adjustedIndirectionIndex)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction
|
private module IndirectOperandIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
|
||||||
|
class IndirectNode = IndirectOperand;
|
||||||
|
|
||||||
|
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectOperand/4;
|
||||||
|
}
|
||||||
|
|
||||||
|
module IndirectOperandToIndirectExpr =
|
||||||
|
IndirectNodeToIndirectExpr<IndirectOperandIndirectExprNodeImpl>;
|
||||||
|
|
||||||
|
private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
|
||||||
{
|
{
|
||||||
IndirectInstructionIndirectExprNode() {
|
IndirectOperandIndirectExprNode() { IndirectOperandToIndirectExpr::charpred(this) }
|
||||||
exists(Expr e, int n, int indirectionIndex |
|
|
||||||
indirectExprNodeShouldBeIndirectInstruction(this, e, n, indirectionIndex) and
|
|
||||||
not indirectExprNodeShouldBeIndirectInstruction(_, e, n + 1, indirectionIndex)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
final override Expr getConvertedExpr(int n, int index) {
|
final override Expr getConvertedExpr(int n, int index) {
|
||||||
indirectExprNodeShouldBeIndirectInstruction(this, result, n, index)
|
IndirectOperandToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module IndirectInstructionIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
|
||||||
|
class IndirectNode = IndirectInstruction;
|
||||||
|
|
||||||
|
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectInstruction/4;
|
||||||
|
}
|
||||||
|
|
||||||
|
module IndirectInstructionToIndirectExpr =
|
||||||
|
IndirectNodeToIndirectExpr<IndirectInstructionIndirectExprNodeImpl>;
|
||||||
|
|
||||||
|
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction
|
||||||
|
{
|
||||||
|
IndirectInstructionIndirectExprNode() { IndirectInstructionToIndirectExpr::charpred(this) }
|
||||||
|
|
||||||
|
final override Expr getConvertedExpr(int n, int index) {
|
||||||
|
IndirectInstructionToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,22 +113,12 @@ private newtype TDefOrUseImpl =
|
|||||||
TGlobalUse(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
TGlobalUse(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
||||||
// Represents a final "use" of a global variable to ensure that
|
// Represents a final "use" of a global variable to ensure that
|
||||||
// the assignment to a global variable isn't ruled out as dead.
|
// the assignment to a global variable isn't ruled out as dead.
|
||||||
exists(VariableAddressInstruction vai, int defIndex |
|
isGlobalUse(v, f, _, indirectionIndex)
|
||||||
vai.getEnclosingIRFunction() = f and
|
|
||||||
vai.getAstVariable() = v and
|
|
||||||
isDef(_, _, _, vai, _, defIndex) and
|
|
||||||
indirectionIndex = [0 .. defIndex] + 1
|
|
||||||
)
|
|
||||||
} or
|
} or
|
||||||
TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
||||||
// Represents the initial "definition" of a global variable when entering
|
// Represents the initial "definition" of a global variable when entering
|
||||||
// a function body.
|
// a function body.
|
||||||
exists(VariableAddressInstruction vai |
|
isGlobalDefImpl(v, f, _, indirectionIndex)
|
||||||
vai.getEnclosingIRFunction() = f and
|
|
||||||
vai.getAstVariable() = v and
|
|
||||||
isUse(_, _, vai, _, indirectionIndex) and
|
|
||||||
not isDef(_, _, vai.getAUse(), _, _, _)
|
|
||||||
)
|
|
||||||
} or
|
} or
|
||||||
TIteratorDef(
|
TIteratorDef(
|
||||||
Operand iteratorDerefAddress, BaseSourceVariableInstruction container, int indirectionIndex
|
Operand iteratorDerefAddress, BaseSourceVariableInstruction container, int indirectionIndex
|
||||||
@@ -150,6 +140,27 @@ private newtype TDefOrUseImpl =
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate isGlobalUse(
|
||||||
|
GlobalLikeVariable v, IRFunction f, int indirection, int indirectionIndex
|
||||||
|
) {
|
||||||
|
exists(VariableAddressInstruction vai |
|
||||||
|
vai.getEnclosingIRFunction() = f and
|
||||||
|
vai.getAstVariable() = v and
|
||||||
|
isDef(_, _, _, vai, indirection, indirectionIndex)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate isGlobalDefImpl(
|
||||||
|
GlobalLikeVariable v, IRFunction f, int indirection, int indirectionIndex
|
||||||
|
) {
|
||||||
|
exists(VariableAddressInstruction vai |
|
||||||
|
vai.getEnclosingIRFunction() = f and
|
||||||
|
vai.getAstVariable() = v and
|
||||||
|
isUse(_, _, vai, indirection, indirectionIndex) and
|
||||||
|
not isDef(_, _, _, vai, _, indirectionIndex)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate unspecifiedTypeIsModifiableAt(Type unspecified, int indirectionIndex) {
|
private predicate unspecifiedTypeIsModifiableAt(Type unspecified, int indirectionIndex) {
|
||||||
indirectionIndex = [1 .. getIndirectionForUnspecifiedType(unspecified).getNumberOfIndirections()] and
|
indirectionIndex = [1 .. getIndirectionForUnspecifiedType(unspecified).getNumberOfIndirections()] and
|
||||||
exists(CppType cppType |
|
exists(CppType cppType |
|
||||||
@@ -438,7 +449,7 @@ class GlobalUse extends UseImpl, TGlobalUse {
|
|||||||
|
|
||||||
override FinalGlobalValue getNode() { result.getGlobalUse() = this }
|
override FinalGlobalValue getNode() { result.getGlobalUse() = this }
|
||||||
|
|
||||||
override int getIndirection() { result = ind + 1 }
|
override int getIndirection() { isGlobalUse(global, f, result, ind) }
|
||||||
|
|
||||||
/** Gets the global variable associated with this use. */
|
/** Gets the global variable associated with this use. */
|
||||||
GlobalLikeVariable getVariable() { result = global }
|
GlobalLikeVariable getVariable() { result = global }
|
||||||
@@ -460,7 +471,9 @@ class GlobalUse extends UseImpl, TGlobalUse {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override SourceVariable getSourceVariable() { sourceVariableIsGlobal(result, global, f, ind) }
|
override SourceVariable getSourceVariable() {
|
||||||
|
sourceVariableIsGlobal(result, global, f, this.getIndirection())
|
||||||
|
}
|
||||||
|
|
||||||
final override Cpp::Location getLocation() { result = f.getLocation() }
|
final override Cpp::Location getLocation() { result = f.getLocation() }
|
||||||
|
|
||||||
@@ -501,16 +514,18 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
|
|||||||
|
|
||||||
/** Gets the global variable associated with this definition. */
|
/** Gets the global variable associated with this definition. */
|
||||||
override SourceVariable getSourceVariable() {
|
override SourceVariable getSourceVariable() {
|
||||||
sourceVariableIsGlobal(result, global, f, indirectionIndex)
|
sourceVariableIsGlobal(result, global, f, this.getIndirection())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getIndirection() { result = indirectionIndex }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the type of this use after specifiers have been deeply stripped
|
* Gets the type of this use after specifiers have been deeply stripped
|
||||||
* and typedefs have been resolved.
|
* and typedefs have been resolved.
|
||||||
*/
|
*/
|
||||||
Type getUnspecifiedType() { result = global.getUnspecifiedType() }
|
Type getUnspecifiedType() { result = global.getUnspecifiedType() }
|
||||||
|
|
||||||
override string toString() { result = "GlobalDef" }
|
override string toString() { result = "Def of " + this.getSourceVariable() }
|
||||||
|
|
||||||
override Location getLocation() { result = f.getLocation() }
|
override Location getLocation() { result = f.getLocation() }
|
||||||
|
|
||||||
@@ -980,7 +995,7 @@ class GlobalDef extends TGlobalDef, SsaDefOrUse {
|
|||||||
final override Location getLocation() { result = global.getLocation() }
|
final override Location getLocation() { result = global.getLocation() }
|
||||||
|
|
||||||
/** Gets a textual representation of this definition. */
|
/** Gets a textual representation of this definition. */
|
||||||
override string toString() { result = "GlobalDef" }
|
override string toString() { result = global.toString() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this definition has index `index` in block `block`, and
|
* Holds if this definition has index `index` in block `block`, and
|
||||||
@@ -990,6 +1005,9 @@ class GlobalDef extends TGlobalDef, SsaDefOrUse {
|
|||||||
global.hasIndexInBlock(block, index, sv)
|
global.hasIndexInBlock(block, index, sv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the indirection index of this definition. */
|
||||||
|
int getIndirection() { result = global.getIndirection() }
|
||||||
|
|
||||||
/** Gets the indirection index of this definition. */
|
/** Gets the indirection index of this definition. */
|
||||||
int getIndirectionIndex() { result = global.getIndirectionIndex() }
|
int getIndirectionIndex() { result = global.getIndirectionIndex() }
|
||||||
|
|
||||||
|
|||||||
@@ -872,7 +872,7 @@ private module Cached {
|
|||||||
upper = countIndirectionsForCppType(type) and
|
upper = countIndirectionsForCppType(type) and
|
||||||
ind = ind0 + [lower .. upper] and
|
ind = ind0 + [lower .. upper] and
|
||||||
indirectionIndex = ind - (ind0 + lower) and
|
indirectionIndex = ind - (ind0 + lower) and
|
||||||
(if type.hasType(any(Cpp::ArrayType arrayType), true) then lower = 0 else lower = 1)
|
lower = getMinIndirectionsForType(any(Type t | type.hasUnspecifiedType(t, _)))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,10 +49,11 @@ private class FgetsFunction extends DataFlowFunction, TaintFunction, ArrayFuncti
|
|||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
|
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
|
||||||
output.isParameterDeref(0) and
|
(
|
||||||
description = "string read by " + this.getName()
|
output.isParameterDeref(0) or
|
||||||
or
|
output.isReturnValue() or
|
||||||
output.isReturnValue() and
|
output.isReturnValueDeref()
|
||||||
|
) and
|
||||||
description = "string read by " + this.getName()
|
description = "string read by " + this.getName()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ private class Getaddrinfo extends TaintFunction, ArrayFunction, RemoteFlowSource
|
|||||||
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam in [0, 1] }
|
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam in [0, 1] }
|
||||||
|
|
||||||
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
|
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
|
||||||
output.isParameterDeref(3) and
|
output.isParameterDeref(3, 2) and
|
||||||
description = "address returned by " + this.getName()
|
description = "address returned by " + this.getName()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,19 +147,32 @@ private class SnprintfImpl extends Snprintf {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The Microsoft `StringCchPrintf` function and variants.
|
* The Microsoft `StringCchPrintf` function and variants.
|
||||||
|
* See: https://learn.microsoft.com/en-us/windows/win32/api/strsafe/
|
||||||
|
* and
|
||||||
|
* https://learn.microsoft.com/en-us/previous-versions/windows/embedded/ms860435(v=msdn.10)
|
||||||
*/
|
*/
|
||||||
private class StringCchPrintf extends FormattingFunction {
|
private class StringCchPrintf extends FormattingFunction {
|
||||||
StringCchPrintf() {
|
StringCchPrintf() {
|
||||||
this instanceof TopLevelFunction and
|
this instanceof TopLevelFunction and
|
||||||
this.hasGlobalName([
|
exists(string baseName |
|
||||||
"StringCchPrintf", "StringCchPrintfEx", "StringCchPrintf_l", "StringCchPrintf_lEx",
|
baseName in [
|
||||||
"StringCbPrintf", "StringCbPrintfEx", "StringCbPrintf_l", "StringCbPrintf_lEx"
|
"StringCchPrintf", //StringCchPrintf(pszDest, cchDest, pszFormat, ...)
|
||||||
]) and
|
"StringCchPrintfEx", //StringCchPrintfEx(pszDest,cchDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, ...)
|
||||||
|
"StringCchPrintf_l", //StringCchPrintf_l(pszDest, cbDest, pszFormat, locale, ...)
|
||||||
|
"StringCchPrintf_lEx", //StringCchPrintf_lEx(pszDest, cchDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, locale, ...)
|
||||||
|
"StringCbPrintf", //StringCbPrintf(pszDest, cbDest, pszFormat, ...)
|
||||||
|
"StringCbPrintfEx", //StringCbPrintfEx(pszDest, cbDest, ppszDestEnd, pcbRemaining, dwFlags, pszFormat, ...)
|
||||||
|
"StringCbPrintf_l", //StringCbPrintf_l(pszDest, cbDest, pszFormat, locale, ...)
|
||||||
|
"StringCbPrintf_lEx" //StringCbPrintf_lEx(pszDest, cbDest, ppszDestEnd, pcbRemaining, dwFlags, pszFormat, locale, ...)
|
||||||
|
]
|
||||||
|
|
|
||||||
|
this.hasGlobalName(baseName + ["", "A", "W"])
|
||||||
|
) and
|
||||||
not exists(this.getDefinition().getFile().getRelativePath())
|
not exists(this.getDefinition().getFile().getRelativePath())
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getFormatParameterIndex() {
|
override int getFormatParameterIndex() {
|
||||||
if this.getName().matches("%Ex") then result = 5 else result = 2
|
if this.getName().matches("%Ex" + ["", "A", "W"]) then result = 5 else result = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getOutputParameterIndex(boolean isStream) { result = 0 and isStream = false }
|
override int getOutputParameterIndex(boolean isStream) { result = 0 and isStream = false }
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, Rem
|
|||||||
override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 }
|
override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 }
|
||||||
|
|
||||||
override predicate hasRemoteFlowSink(FunctionInput input, string description) {
|
override predicate hasRemoteFlowSink(FunctionInput input, string description) {
|
||||||
input.isParameterDeref(1) and description = "buffer sent by " + this.getName()
|
input.isParameterDeref(1, 1) and description = "buffer sent by " + this.getName()
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasSocketInput(FunctionInput input) { input.isParameter(0) }
|
override predicate hasSocketInput(FunctionInput input) { input.isParameter(0) }
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The standard function `strcat` and its wide, sized, and Microsoft variants.
|
* The standard function `strcat` and its wide, sized, and Microsoft variants.
|
||||||
|
*
|
||||||
|
* Does not include `strlcat`, which is covered by `StrlcatFunction`
|
||||||
*/
|
*/
|
||||||
class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction {
|
class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction {
|
||||||
StrcatFunction() {
|
StrcatFunction() {
|
||||||
@@ -90,3 +92,64 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
|
|||||||
buffer = true
|
buffer = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `strlcat` function.
|
||||||
|
*/
|
||||||
|
class StrlcatFunction extends TaintFunction, ArrayFunction, SideEffectFunction {
|
||||||
|
StrlcatFunction() {
|
||||||
|
this.hasGlobalName("strlcat") // strlcat(dst, src, dst_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the index of the parameter that is the size of the copy (in characters).
|
||||||
|
*/
|
||||||
|
int getParamSize() { result = 2 }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the index of the parameter that is the source of the copy.
|
||||||
|
*/
|
||||||
|
int getParamSrc() { result = 1 }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the index of the parameter that is the destination to be appended to.
|
||||||
|
*/
|
||||||
|
int getParamDest() { result = 0 }
|
||||||
|
|
||||||
|
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||||
|
(
|
||||||
|
input.isParameter(2)
|
||||||
|
or
|
||||||
|
input.isParameterDeref(0)
|
||||||
|
or
|
||||||
|
input.isParameterDeref(1)
|
||||||
|
) and
|
||||||
|
output.isParameterDeref(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate hasArrayInput(int param) {
|
||||||
|
param = 0 or
|
||||||
|
param = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate hasArrayOutput(int param) { param = 0 }
|
||||||
|
|
||||||
|
override predicate hasArrayWithNullTerminator(int param) { param = 1 }
|
||||||
|
|
||||||
|
override predicate hasArrayWithUnknownSize(int param) { param = 0 }
|
||||||
|
|
||||||
|
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||||
|
|
||||||
|
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||||
|
|
||||||
|
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||||
|
i = 0 and
|
||||||
|
buffer = true and
|
||||||
|
mustWrite = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||||
|
(i = 0 or i = 1) and
|
||||||
|
buffer = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
|||||||
"wcsxfrm_l", // _strxfrm_l(dest, src, max_amount, locale)
|
"wcsxfrm_l", // _strxfrm_l(dest, src, max_amount, locale)
|
||||||
"_mbsnbcpy", // _mbsnbcpy(dest, src, max_amount)
|
"_mbsnbcpy", // _mbsnbcpy(dest, src, max_amount)
|
||||||
"stpcpy", // stpcpy(dest, src)
|
"stpcpy", // stpcpy(dest, src)
|
||||||
"stpncpy" // stpcpy(dest, src, max_amount)
|
"stpncpy", // stpncpy(dest, src, max_amount)
|
||||||
|
"strlcpy" // strlcpy(dst, src, dst_size)
|
||||||
])
|
])
|
||||||
or
|
or
|
||||||
(
|
(
|
||||||
@@ -53,6 +54,11 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
|||||||
*/
|
*/
|
||||||
private predicate isSVariant() { this.getName().matches("%\\_s") }
|
private predicate isSVariant() { this.getName().matches("%\\_s") }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the function returns the total length the string would have had if the size was unlimited.
|
||||||
|
*/
|
||||||
|
private predicate returnsTotalLength() { this.getName() = "strlcpy" }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the index of the parameter that is the maximum size of the copy (in characters).
|
* Gets the index of the parameter that is the maximum size of the copy (in characters).
|
||||||
*/
|
*/
|
||||||
@@ -60,7 +66,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
|||||||
if this.isSVariant()
|
if this.isSVariant()
|
||||||
then result = 1
|
then result = 1
|
||||||
else (
|
else (
|
||||||
this.getName().matches(["%ncpy%", "%nbcpy%", "%xfrm%"]) and
|
this.getName().matches(["%ncpy%", "%nbcpy%", "%xfrm%", "strlcpy"]) and
|
||||||
result = 2
|
result = 2
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -100,6 +106,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
|||||||
input.isParameterDeref(this.getParamSrc()) and
|
input.isParameterDeref(this.getParamSrc()) and
|
||||||
output.isReturnValueDeref()
|
output.isReturnValueDeref()
|
||||||
or
|
or
|
||||||
|
not this.returnsTotalLength() and
|
||||||
input.isParameter(this.getParamDest()) and
|
input.isParameter(this.getParamDest()) and
|
||||||
output.isReturnValue()
|
output.isReturnValue()
|
||||||
}
|
}
|
||||||
@@ -110,8 +117,9 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
|||||||
exists(this.getParamSize()) and
|
exists(this.getParamSize()) and
|
||||||
input.isParameterDeref(this.getParamSrc()) and
|
input.isParameterDeref(this.getParamSrc()) and
|
||||||
(
|
(
|
||||||
output.isParameterDeref(this.getParamDest()) or
|
output.isParameterDeref(this.getParamDest())
|
||||||
output.isReturnValueDeref()
|
or
|
||||||
|
not this.returnsTotalLength() and output.isReturnValueDeref()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import semmle.code.cpp.Parameter
|
|||||||
|
|
||||||
private newtype TFunctionInput =
|
private newtype TFunctionInput =
|
||||||
TInParameter(ParameterIndex i) or
|
TInParameter(ParameterIndex i) or
|
||||||
TInParameterDeref(ParameterIndex i) or
|
TInParameterDeref(ParameterIndex i, int indirectionIndex) { indirectionIndex = [1, 2] } or
|
||||||
TInQualifierObject() or
|
TInQualifierObject() or
|
||||||
TInQualifierAddress() or
|
TInQualifierAddress() or
|
||||||
TInReturnValueDeref()
|
TInReturnValueDeref()
|
||||||
@@ -245,15 +245,18 @@ class InParameter extends FunctionInput, TInParameter {
|
|||||||
*/
|
*/
|
||||||
class InParameterDeref extends FunctionInput, TInParameterDeref {
|
class InParameterDeref extends FunctionInput, TInParameterDeref {
|
||||||
ParameterIndex index;
|
ParameterIndex index;
|
||||||
|
int indirectionIndex;
|
||||||
|
|
||||||
InParameterDeref() { this = TInParameterDeref(index) }
|
InParameterDeref() { this = TInParameterDeref(index, indirectionIndex) }
|
||||||
|
|
||||||
override string toString() { result = "InParameterDeref " + index.toString() }
|
override string toString() { result = "InParameterDeref " + index.toString() }
|
||||||
|
|
||||||
/** Gets the zero-based index of the parameter. */
|
/** Gets the zero-based index of the parameter. */
|
||||||
ParameterIndex getIndex() { result = index }
|
ParameterIndex getIndex() { result = index }
|
||||||
|
|
||||||
override predicate isParameterDeref(ParameterIndex i) { i = index }
|
override predicate isParameterDeref(ParameterIndex i, int indirection) {
|
||||||
|
i = index and indirectionIndex = indirection
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -321,10 +324,10 @@ class InReturnValueDeref extends FunctionInput, TInReturnValueDeref {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private newtype TFunctionOutput =
|
private newtype TFunctionOutput =
|
||||||
TOutParameterDeref(ParameterIndex i) or
|
TOutParameterDeref(ParameterIndex i, int indirectionIndex) { indirectionIndex = [1, 2] } or
|
||||||
TOutQualifierObject() or
|
TOutQualifierObject() or
|
||||||
TOutReturnValue() or
|
TOutReturnValue() or
|
||||||
TOutReturnValueDeref()
|
TOutReturnValueDeref(int indirections) { indirections = [1, 2] }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An output from a function. This can be:
|
* An output from a function. This can be:
|
||||||
@@ -498,17 +501,16 @@ class FunctionOutput extends TFunctionOutput {
|
|||||||
*/
|
*/
|
||||||
class OutParameterDeref extends FunctionOutput, TOutParameterDeref {
|
class OutParameterDeref extends FunctionOutput, TOutParameterDeref {
|
||||||
ParameterIndex index;
|
ParameterIndex index;
|
||||||
|
int indirectionIndex;
|
||||||
|
|
||||||
OutParameterDeref() { this = TOutParameterDeref(index) }
|
OutParameterDeref() { this = TOutParameterDeref(index, indirectionIndex) }
|
||||||
|
|
||||||
override string toString() { result = "OutParameterDeref " + index.toString() }
|
override string toString() { result = "OutParameterDeref " + index.toString() }
|
||||||
|
|
||||||
ParameterIndex getIndex() { result = index }
|
ParameterIndex getIndex() { result = index }
|
||||||
|
|
||||||
override predicate isParameterDeref(ParameterIndex i) { i = index }
|
|
||||||
|
|
||||||
override predicate isParameterDeref(ParameterIndex i, int ind) {
|
override predicate isParameterDeref(ParameterIndex i, int ind) {
|
||||||
this.isParameterDeref(i) and ind = 1
|
i = index and ind = indirectionIndex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,4 +574,8 @@ class OutReturnValueDeref extends FunctionOutput, TOutReturnValueDeref {
|
|||||||
override string toString() { result = "OutReturnValueDeref" }
|
override string toString() { result = "OutReturnValueDeref" }
|
||||||
|
|
||||||
override predicate isReturnValueDeref() { any() }
|
override predicate isReturnValueDeref() { any() }
|
||||||
|
|
||||||
|
override predicate isReturnValueDeref(int indirectionIndex) {
|
||||||
|
this = TOutReturnValueDeref(indirectionIndex)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,7 @@ private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
|||||||
* `upper` is true, and can be traced back to a guard represented by `reason`.
|
* `upper` is true, and can be traced back to a guard represented by `reason`.
|
||||||
*/
|
*/
|
||||||
predicate bounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
|
predicate bounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
|
||||||
exists(SemanticExprConfig::Expr semExpr |
|
exists(SemanticExprConfig::Expr semExpr | semExpr.getUnconvertedResultExpression() = e |
|
||||||
semExpr.getUnconverted().getUnconvertedResultExpression() = e
|
|
||||||
|
|
|
||||||
semBounded(semExpr, b, delta, upper, reason)
|
semBounded(semExpr, b, delta, upper, reason)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -30,9 +28,7 @@ predicate bounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
|
|||||||
* The `Expr` may be a conversion.
|
* The `Expr` may be a conversion.
|
||||||
*/
|
*/
|
||||||
predicate convertedBounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
|
predicate convertedBounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
|
||||||
exists(SemanticExprConfig::Expr semExpr |
|
exists(SemanticExprConfig::Expr semExpr | semExpr.getConvertedResultExpression() = e |
|
||||||
semExpr.getConverted().getConvertedResultExpression() = e
|
|
||||||
|
|
|
||||||
semBounded(semExpr, b, delta, upper, reason)
|
semBounded(semExpr, b, delta, upper, reason)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ predicate exprMightOverflowNegatively(Expr expr) {
|
|||||||
lowerBound(expr) < exprMinVal(expr)
|
lowerBound(expr) < exprMinVal(expr)
|
||||||
or
|
or
|
||||||
exists(SemanticExprConfig::Expr semExpr |
|
exists(SemanticExprConfig::Expr semExpr |
|
||||||
semExpr.getUnconverted().getAst() = expr and
|
semExpr.getAst() = expr and
|
||||||
ConstantStage::potentiallyOverflowingExpr(false, semExpr) and
|
ConstantStage::potentiallyOverflowingExpr(false, semExpr) and
|
||||||
not ConstantStage::initialBounded(semExpr, _, _, false, _, _, _)
|
not ConstantStage::initialBounded(semExpr, _, _, false, _, _, _)
|
||||||
)
|
)
|
||||||
@@ -126,7 +126,7 @@ predicate exprMightOverflowPositively(Expr expr) {
|
|||||||
upperBound(expr) > exprMaxVal(expr)
|
upperBound(expr) > exprMaxVal(expr)
|
||||||
or
|
or
|
||||||
exists(SemanticExprConfig::Expr semExpr |
|
exists(SemanticExprConfig::Expr semExpr |
|
||||||
semExpr.getUnconverted().getAst() = expr and
|
semExpr.getAst() = expr and
|
||||||
ConstantStage::potentiallyOverflowingExpr(true, semExpr) and
|
ConstantStage::potentiallyOverflowingExpr(true, semExpr) and
|
||||||
not ConstantStage::initialBounded(semExpr, _, _, true, _, _, _)
|
not ConstantStage::initialBounded(semExpr, _, _, true, _, _, _)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,9 +12,6 @@ class SemBasicBlock extends Specific::BasicBlock {
|
|||||||
/** Holds if this block (transitively) dominates `otherblock`. */
|
/** Holds if this block (transitively) dominates `otherblock`. */
|
||||||
final predicate bbDominates(SemBasicBlock otherBlock) { Specific::bbDominates(this, otherBlock) }
|
final predicate bbDominates(SemBasicBlock otherBlock) { Specific::bbDominates(this, otherBlock) }
|
||||||
|
|
||||||
/** Holds if this block has dominance information. */
|
|
||||||
final predicate hasDominanceInformation() { Specific::hasDominanceInformation(this) }
|
|
||||||
|
|
||||||
/** Gets an expression that is evaluated in this basic block. */
|
/** Gets an expression that is evaluated in this basic block. */
|
||||||
final SemExpr getAnExpr() { result.getBasicBlock() = this }
|
final SemExpr getAnExpr() { result.getBasicBlock() = this }
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
private import Semantic
|
private import Semantic
|
||||||
private import SemanticExprSpecific::SemanticExprConfig as Specific
|
private import SemanticExprSpecific::SemanticExprConfig as Specific
|
||||||
|
private import SemanticType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An language-neutral expression.
|
* An language-neutral expression.
|
||||||
@@ -241,8 +242,21 @@ class SemConvertExpr extends SemUnaryExpr {
|
|||||||
SemConvertExpr() { opcode instanceof Opcode::Convert }
|
SemConvertExpr() { opcode instanceof Opcode::Convert }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private import semmle.code.cpp.ir.IR as IR
|
||||||
|
|
||||||
|
/** A conversion instruction which is guaranteed to not overflow. */
|
||||||
|
private class SafeConversion extends IR::ConvertInstruction {
|
||||||
|
SafeConversion() {
|
||||||
|
exists(SemType tFrom, SemType tTo |
|
||||||
|
tFrom = getSemanticType(super.getUnary().getResultIRType()) and
|
||||||
|
tTo = getSemanticType(super.getResultIRType()) and
|
||||||
|
conversionCannotOverflow(tFrom, tTo)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class SemCopyValueExpr extends SemUnaryExpr {
|
class SemCopyValueExpr extends SemUnaryExpr {
|
||||||
SemCopyValueExpr() { opcode instanceof Opcode::CopyValue }
|
SemCopyValueExpr() { opcode instanceof Opcode::CopyValue or this instanceof SafeConversion }
|
||||||
}
|
}
|
||||||
|
|
||||||
class SemNegateExpr extends SemUnaryExpr {
|
class SemNegateExpr extends SemUnaryExpr {
|
||||||
|
|||||||
@@ -12,87 +12,10 @@ private import semmle.code.cpp.ir.ValueNumbering
|
|||||||
module SemanticExprConfig {
|
module SemanticExprConfig {
|
||||||
class Location = Cpp::Location;
|
class Location = Cpp::Location;
|
||||||
|
|
||||||
/** A `ConvertInstruction` or a `CopyValueInstruction`. */
|
|
||||||
private class Conversion extends IR::UnaryInstruction {
|
|
||||||
Conversion() {
|
|
||||||
this instanceof IR::CopyValueInstruction
|
|
||||||
or
|
|
||||||
this instanceof IR::ConvertInstruction
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if this instruction converts a value of type `tFrom` to a value of type `tTo`. */
|
|
||||||
predicate converts(SemType tFrom, SemType tTo) {
|
|
||||||
tFrom = getSemanticType(this.getUnary().getResultIRType()) and
|
|
||||||
tTo = getSemanticType(this.getResultIRType())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a conversion-like instruction that consumes `op`, and
|
|
||||||
* which is guaranteed to not overflow.
|
|
||||||
*/
|
|
||||||
private IR::Instruction safeConversion(IR::Operand op) {
|
|
||||||
exists(Conversion conv, SemType tFrom, SemType tTo |
|
|
||||||
conv.converts(tFrom, tTo) and
|
|
||||||
conversionCannotOverflow(tFrom, tTo) and
|
|
||||||
conv.getUnaryOperand() = op and
|
|
||||||
result = conv
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if `i1 = i2` or if `i2` is a safe conversion that consumes `i1`. */
|
|
||||||
private predicate idOrSafeConversion(IR::Instruction i1, IR::Instruction i2) {
|
|
||||||
not i1.getResultIRType() instanceof IR::IRVoidType and
|
|
||||||
(
|
|
||||||
i1 = i2
|
|
||||||
or
|
|
||||||
i2 = safeConversion(i1.getAUse()) and
|
|
||||||
i1.getBlock() = i2.getBlock()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
module Equiv = QlBuiltins::EquivalenceRelation<IR::Instruction, idOrSafeConversion/2>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The expressions on which we perform range analysis.
|
* The expressions on which we perform range analysis.
|
||||||
*/
|
*/
|
||||||
class Expr extends Equiv::EquivalenceClass {
|
class Expr = IR::Instruction;
|
||||||
/** Gets the n'th instruction in this equivalence class. */
|
|
||||||
private IR::Instruction getInstruction(int n) {
|
|
||||||
result =
|
|
||||||
rank[n + 1](IR::Instruction instr, int i, IR::IRBlock block |
|
|
||||||
this = Equiv::getEquivalenceClass(instr) and block.getInstruction(i) = instr
|
|
||||||
|
|
|
||||||
instr order by i
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets a textual representation of this element. */
|
|
||||||
string toString() { result = this.getUnconverted().toString() }
|
|
||||||
|
|
||||||
/** Gets the basic block of this expression. */
|
|
||||||
IR::IRBlock getBlock() { result = this.getUnconverted().getBlock() }
|
|
||||||
|
|
||||||
/** Gets the unconverted instruction associated with this expression. */
|
|
||||||
IR::Instruction getUnconverted() { result = this.getInstruction(0) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the final instruction associated with this expression. This
|
|
||||||
* represents the result after applying all the safe conversions.
|
|
||||||
*/
|
|
||||||
IR::Instruction getConverted() {
|
|
||||||
exists(int n |
|
|
||||||
result = this.getInstruction(n) and
|
|
||||||
not exists(this.getInstruction(n + 1))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the type of the result produced by this instruction. */
|
|
||||||
IR::IRType getResultIRType() { result = this.getConverted().getResultIRType() }
|
|
||||||
|
|
||||||
/** Gets the location of the source code for this expression. */
|
|
||||||
Location getLocation() { result = this.getUnconverted().getLocation() }
|
|
||||||
}
|
|
||||||
|
|
||||||
SemBasicBlock getExprBasicBlock(Expr e) { result = getSemanticBasicBlock(e.getBlock()) }
|
SemBasicBlock getExprBasicBlock(Expr e) { result = getSemanticBasicBlock(e.getBlock()) }
|
||||||
|
|
||||||
@@ -139,12 +62,12 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
predicate stringLiteral(Expr expr, SemType type, string value) {
|
predicate stringLiteral(Expr expr, SemType type, string value) {
|
||||||
anyConstantExpr(expr, type, value) and
|
anyConstantExpr(expr, type, value) and
|
||||||
expr.getUnconverted() instanceof IR::StringConstantInstruction
|
expr instanceof IR::StringConstantInstruction
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate binaryExpr(Expr expr, Opcode opcode, SemType type, Expr leftOperand, Expr rightOperand) {
|
predicate binaryExpr(Expr expr, Opcode opcode, SemType type, Expr leftOperand, Expr rightOperand) {
|
||||||
exists(IR::BinaryInstruction instr |
|
exists(IR::BinaryInstruction instr |
|
||||||
instr = expr.getUnconverted() and
|
instr = expr and
|
||||||
type = getSemanticType(instr.getResultIRType()) and
|
type = getSemanticType(instr.getResultIRType()) and
|
||||||
leftOperand = getSemanticExpr(instr.getLeft()) and
|
leftOperand = getSemanticExpr(instr.getLeft()) and
|
||||||
rightOperand = getSemanticExpr(instr.getRight()) and
|
rightOperand = getSemanticExpr(instr.getRight()) and
|
||||||
@@ -154,14 +77,14 @@ module SemanticExprConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate unaryExpr(Expr expr, Opcode opcode, SemType type, Expr operand) {
|
predicate unaryExpr(Expr expr, Opcode opcode, SemType type, Expr operand) {
|
||||||
exists(IR::UnaryInstruction instr | instr = expr.getUnconverted() |
|
exists(IR::UnaryInstruction instr | instr = expr |
|
||||||
type = getSemanticType(instr.getResultIRType()) and
|
type = getSemanticType(instr.getResultIRType()) and
|
||||||
operand = getSemanticExpr(instr.getUnary()) and
|
operand = getSemanticExpr(instr.getUnary()) and
|
||||||
// REVIEW: Merge the two operand types.
|
// REVIEW: Merge the two operand types.
|
||||||
opcode.toString() = instr.getOpcode().toString()
|
opcode.toString() = instr.getOpcode().toString()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(IR::StoreInstruction instr | instr = expr.getUnconverted() |
|
exists(IR::StoreInstruction instr | instr = expr |
|
||||||
type = getSemanticType(instr.getResultIRType()) and
|
type = getSemanticType(instr.getResultIRType()) and
|
||||||
operand = getSemanticExpr(instr.getSourceValue()) and
|
operand = getSemanticExpr(instr.getSourceValue()) and
|
||||||
opcode instanceof Opcode::Store
|
opcode instanceof Opcode::Store
|
||||||
@@ -170,13 +93,13 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
predicate nullaryExpr(Expr expr, Opcode opcode, SemType type) {
|
predicate nullaryExpr(Expr expr, Opcode opcode, SemType type) {
|
||||||
exists(IR::LoadInstruction load |
|
exists(IR::LoadInstruction load |
|
||||||
load = expr.getUnconverted() and
|
load = expr and
|
||||||
type = getSemanticType(load.getResultIRType()) and
|
type = getSemanticType(load.getResultIRType()) and
|
||||||
opcode instanceof Opcode::Load
|
opcode instanceof Opcode::Load
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(IR::InitializeParameterInstruction init |
|
exists(IR::InitializeParameterInstruction init |
|
||||||
init = expr.getUnconverted() and
|
init = expr and
|
||||||
type = getSemanticType(init.getResultIRType()) and
|
type = getSemanticType(init.getResultIRType()) and
|
||||||
opcode instanceof Opcode::InitializeParameter
|
opcode instanceof Opcode::InitializeParameter
|
||||||
)
|
)
|
||||||
@@ -199,8 +122,6 @@ module SemanticExprConfig {
|
|||||||
dominator.dominates(dominated)
|
dominator.dominates(dominated)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate hasDominanceInformation(BasicBlock block) { any() }
|
|
||||||
|
|
||||||
private predicate id(Cpp::Locatable x, Cpp::Locatable y) { x = y }
|
private predicate id(Cpp::Locatable x, Cpp::Locatable y) { x = y }
|
||||||
|
|
||||||
private predicate idOf(Cpp::Locatable x, int y) = equivalenceRelation(id/2)(x, y)
|
private predicate idOf(Cpp::Locatable x, int y) = equivalenceRelation(id/2)(x, y)
|
||||||
@@ -209,17 +130,7 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
newtype TSsaVariable =
|
newtype TSsaVariable =
|
||||||
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
|
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
|
||||||
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() } or
|
TSsaOperand(IR::PhiInputOperand op) { op.isDefinitionInexact() }
|
||||||
TSsaPointerArithmeticGuard(ValueNumber instr) {
|
|
||||||
exists(Guard g, IR::Operand use |
|
|
||||||
use = instr.getAUse() and use.getIRType() instanceof IR::IRAddressType
|
|
||||||
|
|
|
||||||
g.comparesLt(use, _, _, _, _) or
|
|
||||||
g.comparesLt(_, use, _, _, _) or
|
|
||||||
g.comparesEq(use, _, _, _, _) or
|
|
||||||
g.comparesEq(_, use, _, _, _)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
class SsaVariable extends TSsaVariable {
|
class SsaVariable extends TSsaVariable {
|
||||||
string toString() { none() }
|
string toString() { none() }
|
||||||
@@ -228,9 +139,7 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
IR::Instruction asInstruction() { none() }
|
IR::Instruction asInstruction() { none() }
|
||||||
|
|
||||||
ValueNumber asPointerArithGuard() { none() }
|
IR::PhiInputOperand asOperand() { none() }
|
||||||
|
|
||||||
IR::Operand asOperand() { none() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SsaInstructionVariable extends SsaVariable, TSsaInstruction {
|
class SsaInstructionVariable extends SsaVariable, TSsaInstruction {
|
||||||
@@ -245,20 +154,8 @@ module SemanticExprConfig {
|
|||||||
final override IR::Instruction asInstruction() { result = instr }
|
final override IR::Instruction asInstruction() { result = instr }
|
||||||
}
|
}
|
||||||
|
|
||||||
class SsaPointerArithmeticGuard extends SsaVariable, TSsaPointerArithmeticGuard {
|
|
||||||
ValueNumber vn;
|
|
||||||
|
|
||||||
SsaPointerArithmeticGuard() { this = TSsaPointerArithmeticGuard(vn) }
|
|
||||||
|
|
||||||
final override string toString() { result = vn.toString() }
|
|
||||||
|
|
||||||
final override Location getLocation() { result = vn.getLocation() }
|
|
||||||
|
|
||||||
final override ValueNumber asPointerArithGuard() { result = vn }
|
|
||||||
}
|
|
||||||
|
|
||||||
class SsaOperand extends SsaVariable, TSsaOperand {
|
class SsaOperand extends SsaVariable, TSsaOperand {
|
||||||
IR::Operand op;
|
IR::PhiInputOperand op;
|
||||||
|
|
||||||
SsaOperand() { this = TSsaOperand(op) }
|
SsaOperand() { this = TSsaOperand(op) }
|
||||||
|
|
||||||
@@ -266,7 +163,7 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
final override Location getLocation() { result = op.getLocation() }
|
final override Location getLocation() { result = op.getLocation() }
|
||||||
|
|
||||||
final override IR::Operand asOperand() { result = op }
|
final override IR::PhiInputOperand asOperand() { result = op }
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) {
|
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) {
|
||||||
@@ -289,97 +186,29 @@ module SemanticExprConfig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr getAUse(SsaVariable v) {
|
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
|
||||||
result.getUnconverted().(IR::LoadInstruction).getSourceValue() = v.asInstruction()
|
|
||||||
or
|
|
||||||
result.getUnconverted() = v.asPointerArithGuard().getAnInstruction()
|
|
||||||
}
|
|
||||||
|
|
||||||
SemType getSsaVariableType(SsaVariable v) {
|
SemType getSsaVariableType(SsaVariable v) {
|
||||||
result = getSemanticType(v.asInstruction().getResultIRType())
|
result = getSemanticType(v.asInstruction().getResultIRType())
|
||||||
|
or
|
||||||
|
result = getSemanticType(v.asOperand().getUse().getResultIRType())
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicBlock getSsaVariableBasicBlock(SsaVariable v) {
|
BasicBlock getSsaVariableBasicBlock(SsaVariable v) {
|
||||||
result = v.asInstruction().getBlock()
|
result = v.asInstruction().getBlock()
|
||||||
or
|
or
|
||||||
result = v.asOperand().getUse().getBlock()
|
result = v.asOperand().getAnyDef().getBlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
private newtype TReadPosition =
|
/** Holds if `inp` is an input to the phi node along the edge originating in `bb`. */
|
||||||
TReadPositionBlock(IR::IRBlock block) or
|
predicate phiInputFromBlock(SsaVariable phi, SsaVariable inp, BasicBlock bb) {
|
||||||
TReadPositionPhiInputEdge(IR::IRBlock pred, IR::IRBlock succ) {
|
|
||||||
exists(IR::PhiInputOperand input |
|
|
||||||
pred = input.getPredecessorBlock() and
|
|
||||||
succ = input.getUse().getBlock()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
class SsaReadPosition extends TReadPosition {
|
|
||||||
string toString() { none() }
|
|
||||||
|
|
||||||
Location getLocation() { none() }
|
|
||||||
|
|
||||||
predicate hasRead(SsaVariable v) { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SsaReadPositionBlock extends SsaReadPosition, TReadPositionBlock {
|
|
||||||
IR::IRBlock block;
|
|
||||||
|
|
||||||
SsaReadPositionBlock() { this = TReadPositionBlock(block) }
|
|
||||||
|
|
||||||
final override string toString() { result = block.toString() }
|
|
||||||
|
|
||||||
final override Location getLocation() { result = block.getLocation() }
|
|
||||||
|
|
||||||
final override predicate hasRead(SsaVariable v) {
|
|
||||||
exists(IR::Operand operand |
|
|
||||||
operand.getDef() = v.asInstruction() or
|
|
||||||
operand.getDef() = v.asPointerArithGuard().getAnInstruction()
|
|
||||||
|
|
|
||||||
not operand instanceof IR::PhiInputOperand and
|
|
||||||
operand.getUse().getBlock() = block
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SsaReadPositionPhiInputEdge extends SsaReadPosition, TReadPositionPhiInputEdge {
|
|
||||||
IR::IRBlock pred;
|
|
||||||
IR::IRBlock succ;
|
|
||||||
|
|
||||||
SsaReadPositionPhiInputEdge() { this = TReadPositionPhiInputEdge(pred, succ) }
|
|
||||||
|
|
||||||
final override string toString() { result = pred.toString() + "->" + succ.toString() }
|
|
||||||
|
|
||||||
final override Location getLocation() { result = succ.getLocation() }
|
|
||||||
|
|
||||||
final override predicate hasRead(SsaVariable v) {
|
|
||||||
exists(IR::PhiInputOperand operand |
|
|
||||||
operand.getDef() = v.asInstruction() or
|
|
||||||
operand.getDef() = v.asPointerArithGuard().getAnInstruction()
|
|
||||||
|
|
|
||||||
operand.getPredecessorBlock() = pred and
|
|
||||||
operand.getUse().getBlock() = succ
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate hasReadOfSsaVariable(SsaReadPosition pos, SsaVariable v) { pos.hasRead(v) }
|
|
||||||
|
|
||||||
predicate readBlock(SsaReadPosition pos, BasicBlock block) { pos = TReadPositionBlock(block) }
|
|
||||||
|
|
||||||
predicate phiInputEdge(SsaReadPosition pos, BasicBlock origBlock, BasicBlock phiBlock) {
|
|
||||||
pos = TReadPositionPhiInputEdge(origBlock, phiBlock)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate phiInput(SsaReadPosition pos, SsaVariable phi, SsaVariable input) {
|
|
||||||
exists(IR::PhiInputOperand operand |
|
exists(IR::PhiInputOperand operand |
|
||||||
pos = TReadPositionPhiInputEdge(operand.getPredecessorBlock(), operand.getUse().getBlock())
|
bb = operand.getPredecessorBlock() and
|
||||||
|
|
|
||||||
phi.asInstruction() = operand.getUse() and
|
phi.asInstruction() = operand.getUse() and
|
||||||
(
|
(
|
||||||
input.asInstruction() = operand.getDef()
|
inp.asInstruction() = operand.getDef()
|
||||||
or
|
or
|
||||||
input.asOperand() = operand
|
inp.asOperand() = operand
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -433,7 +262,7 @@ module SemanticExprConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the expression associated with `instr`. */
|
/** Gets the expression associated with `instr`. */
|
||||||
SemExpr getSemanticExpr(IR::Instruction instr) { result = Equiv::getEquivalenceClass(instr) }
|
SemExpr getSemanticExpr(IR::Instruction instr) { result = instr }
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate getSemanticExpr = SemanticExprConfig::getSemanticExpr/1;
|
predicate getSemanticExpr = SemanticExprConfig::getSemanticExpr/1;
|
||||||
|
|||||||
@@ -35,32 +35,4 @@ predicate semImplies_v2(SemGuard g1, boolean b1, SemGuard g2, boolean b2) {
|
|||||||
Specific::implies_v2(g1, b1, g2, b2)
|
Specific::implies_v2(g1, b1, g2, b2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `guard` directly controls the position `controlled` with the
|
|
||||||
* value `testIsTrue`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
predicate semGuardDirectlyControlsSsaRead(
|
|
||||||
SemGuard guard, SemSsaReadPosition controlled, boolean testIsTrue
|
|
||||||
) {
|
|
||||||
guard.directlyControls(controlled.(SemSsaReadPositionBlock).getBlock(), testIsTrue)
|
|
||||||
or
|
|
||||||
exists(SemSsaReadPositionPhiInputEdge controlledEdge | controlledEdge = controlled |
|
|
||||||
guard.directlyControls(controlledEdge.getOrigBlock(), testIsTrue) or
|
|
||||||
guard.hasBranchEdge(controlledEdge.getOrigBlock(), controlledEdge.getPhiBlock(), testIsTrue)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `guard` controls the position `controlled` with the value `testIsTrue`.
|
|
||||||
*/
|
|
||||||
predicate semGuardControlsSsaRead(SemGuard guard, SemSsaReadPosition controlled, boolean testIsTrue) {
|
|
||||||
semGuardDirectlyControlsSsaRead(guard, controlled, testIsTrue)
|
|
||||||
or
|
|
||||||
exists(SemGuard guard0, boolean testIsTrue0 |
|
|
||||||
semImplies_v2(guard0, testIsTrue0, guard, testIsTrue) and
|
|
||||||
semGuardControlsSsaRead(guard0, controlled, testIsTrue0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
SemGuard semGetComparisonGuard(SemRelationalExpr e) { result = Specific::comparisonGuard(e) }
|
SemGuard semGetComparisonGuard(SemRelationalExpr e) { result = Specific::comparisonGuard(e) }
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ class SemSsaExplicitUpdate extends SemSsaVariable {
|
|||||||
|
|
||||||
SemSsaExplicitUpdate() { Specific::explicitUpdate(this, sourceExpr) }
|
SemSsaExplicitUpdate() { Specific::explicitUpdate(this, sourceExpr) }
|
||||||
|
|
||||||
final SemExpr getSourceExpr() { result = sourceExpr }
|
|
||||||
|
|
||||||
final SemExpr getDefiningExpr() { result = sourceExpr }
|
final SemExpr getDefiningExpr() { result = sourceExpr }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,68 +29,8 @@ class SemSsaPhiNode extends SemSsaVariable {
|
|||||||
SemSsaPhiNode() { Specific::phi(this) }
|
SemSsaPhiNode() { Specific::phi(this) }
|
||||||
|
|
||||||
final SemSsaVariable getAPhiInput() { result = Specific::getAPhiInput(this) }
|
final SemSsaVariable getAPhiInput() { result = Specific::getAPhiInput(this) }
|
||||||
}
|
|
||||||
|
final predicate hasInputFromBlock(SemSsaVariable inp, SemBasicBlock bb) {
|
||||||
class SemSsaReadPosition instanceof Specific::SsaReadPosition {
|
Specific::phiInputFromBlock(this, inp, bb)
|
||||||
final string toString() { result = super.toString() }
|
}
|
||||||
|
|
||||||
final Specific::Location getLocation() { result = super.getLocation() }
|
|
||||||
|
|
||||||
final predicate hasReadOfVar(SemSsaVariable var) { Specific::hasReadOfSsaVariable(this, var) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class SemSsaReadPositionPhiInputEdge extends SemSsaReadPosition {
|
|
||||||
SemBasicBlock origBlock;
|
|
||||||
SemBasicBlock phiBlock;
|
|
||||||
|
|
||||||
SemSsaReadPositionPhiInputEdge() { Specific::phiInputEdge(this, origBlock, phiBlock) }
|
|
||||||
|
|
||||||
predicate phiInput(SemSsaPhiNode phi, SemSsaVariable inp) { Specific::phiInput(this, phi, inp) }
|
|
||||||
|
|
||||||
SemBasicBlock getOrigBlock() { result = origBlock }
|
|
||||||
|
|
||||||
SemBasicBlock getPhiBlock() { result = phiBlock }
|
|
||||||
}
|
|
||||||
|
|
||||||
class SemSsaReadPositionBlock extends SemSsaReadPosition {
|
|
||||||
SemBasicBlock block;
|
|
||||||
|
|
||||||
SemSsaReadPositionBlock() { Specific::readBlock(this, block) }
|
|
||||||
|
|
||||||
SemBasicBlock getBlock() { result = block }
|
|
||||||
|
|
||||||
SemExpr getAnExpr() { result = this.getBlock().getAnExpr() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `inp` is an input to `phi` along a back edge.
|
|
||||||
*/
|
|
||||||
predicate semBackEdge(SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge) {
|
|
||||||
edge.phiInput(phi, inp) and
|
|
||||||
// Conservatively assume that every edge is a back edge if we don't have dominance information.
|
|
||||||
(
|
|
||||||
phi.getBasicBlock().bbDominates(edge.getOrigBlock()) or
|
|
||||||
irreducibleSccEdge(edge.getOrigBlock(), phi.getBasicBlock()) or
|
|
||||||
not edge.getOrigBlock().hasDominanceInformation()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the edge from b1 to b2 is part of a multiple-entry cycle in an irreducible control flow
|
|
||||||
* graph.
|
|
||||||
*
|
|
||||||
* An ireducible control flow graph is one where the usual dominance-based back edge detection does
|
|
||||||
* not work, because there is a cycle with multiple entry points, meaning there are
|
|
||||||
* mutually-reachable basic blocks where neither dominates the other. For such a graph, we first
|
|
||||||
* remove all detectable back-edges using the normal condition that the predecessor block is
|
|
||||||
* dominated by the successor block, then mark all edges in a cycle in the resulting graph as back
|
|
||||||
* edges.
|
|
||||||
*/
|
|
||||||
private predicate irreducibleSccEdge(SemBasicBlock b1, SemBasicBlock b2) {
|
|
||||||
trimmedEdge(b1, b2) and trimmedEdge+(b2, b1)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate trimmedEdge(SemBasicBlock pred, SemBasicBlock succ) {
|
|
||||||
pred.getASuccessor() = succ and
|
|
||||||
not succ.bbDominates(pred)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ private predicate constantIntegerExpr(SemExpr e, int val) {
|
|||||||
// Copy of another constant
|
// Copy of another constant
|
||||||
exists(SemSsaExplicitUpdate v, SemExpr src |
|
exists(SemSsaExplicitUpdate v, SemExpr src |
|
||||||
e = v.getAUse() and
|
e = v.getAUse() and
|
||||||
src = v.getSourceExpr() and
|
src = v.getDefiningExpr() and
|
||||||
constantIntegerExpr(src, val)
|
constantIntegerExpr(src, val)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -22,30 +22,7 @@ module CppLangImplConstant implements LangSig<Sem, FloatDelta> {
|
|||||||
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
|
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
|
* Holds if `e2 >= e1 + delta` (if `upper = false`) or `e2 <= e1 + delta` (if `upper = true`).
|
||||||
*/
|
*/
|
||||||
predicate hasBound(SemExpr e, SemExpr bound, float delta, boolean upper) { none() }
|
predicate additionalBoundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the value of `dest` is known to be `src + delta`.
|
|
||||||
*/
|
|
||||||
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, float delta) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the type that range analysis should use to track the result of the specified expression,
|
|
||||||
* if a type other than the original type of the expression is to be used.
|
|
||||||
*
|
|
||||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
|
||||||
* actually references but whose values can be tracked as the type contained in the box.
|
|
||||||
*/
|
|
||||||
SemType getAlternateType(SemExpr e) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the type that range analysis should use to track the result of the specified source
|
|
||||||
* variable, if a type other than the original type of the expression is to be used.
|
|
||||||
*
|
|
||||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
|
||||||
* actually references but whose values can be tracked as the type contained in the box.
|
|
||||||
*/
|
|
||||||
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
private import RangeAnalysisConstantSpecific
|
private import RangeAnalysisConstantSpecific
|
||||||
private import RangeAnalysisRelativeSpecific
|
private import RangeAnalysisRelativeSpecific
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||||
private import RangeUtils
|
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExpr
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExpr
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticCFG
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticCFG
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticGuard
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticGuard
|
||||||
@@ -72,14 +71,14 @@ module Sem implements Semantic {
|
|||||||
|
|
||||||
class BasicBlock = SemBasicBlock;
|
class BasicBlock = SemBasicBlock;
|
||||||
|
|
||||||
|
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||||
|
|
||||||
|
int getBlockId1(BasicBlock bb) { result = bb.getUniqueId() }
|
||||||
|
|
||||||
class Guard = SemGuard;
|
class Guard = SemGuard;
|
||||||
|
|
||||||
predicate implies_v2 = semImplies_v2/4;
|
predicate implies_v2 = semImplies_v2/4;
|
||||||
|
|
||||||
predicate guardDirectlyControlsSsaRead = semGuardDirectlyControlsSsaRead/3;
|
|
||||||
|
|
||||||
predicate guardControlsSsaRead = semGuardControlsSsaRead/3;
|
|
||||||
|
|
||||||
class Type = SemType;
|
class Type = SemType;
|
||||||
|
|
||||||
class IntegerType = SemIntegerType;
|
class IntegerType = SemIntegerType;
|
||||||
@@ -88,19 +87,17 @@ module Sem implements Semantic {
|
|||||||
|
|
||||||
class AddressType = SemAddressType;
|
class AddressType = SemAddressType;
|
||||||
|
|
||||||
|
SemType getExprType(SemExpr e) { result = e.getSemType() }
|
||||||
|
|
||||||
|
SemType getSsaType(SemSsaVariable var) { result = var.getType() }
|
||||||
|
|
||||||
class SsaVariable = SemSsaVariable;
|
class SsaVariable = SemSsaVariable;
|
||||||
|
|
||||||
class SsaPhiNode = SemSsaPhiNode;
|
class SsaPhiNode = SemSsaPhiNode;
|
||||||
|
|
||||||
class SsaExplicitUpdate = SemSsaExplicitUpdate;
|
class SsaExplicitUpdate = SemSsaExplicitUpdate;
|
||||||
|
|
||||||
class SsaReadPosition = SemSsaReadPosition;
|
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, int delta) { none() }
|
||||||
|
|
||||||
class SsaReadPositionPhiInputEdge = SemSsaReadPositionPhiInputEdge;
|
|
||||||
|
|
||||||
class SsaReadPositionBlock = SemSsaReadPositionBlock;
|
|
||||||
|
|
||||||
predicate backEdge = semBackEdge/3;
|
|
||||||
|
|
||||||
predicate conversionCannotOverflow(Type fromType, Type toType) {
|
predicate conversionCannotOverflow(Type fromType, Type toType) {
|
||||||
SemanticType::conversionCannotOverflow(fromType, toType)
|
SemanticType::conversionCannotOverflow(fromType, toType)
|
||||||
@@ -109,7 +106,7 @@ module Sem implements Semantic {
|
|||||||
|
|
||||||
module SignAnalysis implements SignAnalysisSig<Sem> {
|
module SignAnalysis implements SignAnalysisSig<Sem> {
|
||||||
private import SignAnalysisCommon as SA
|
private import SignAnalysisCommon as SA
|
||||||
import SA::SignAnalysis<FloatDelta, Util>
|
import SA::SignAnalysis<FloatDelta>
|
||||||
}
|
}
|
||||||
|
|
||||||
module ConstantBounds implements BoundSig<SemLocation, Sem, FloatDelta> {
|
module ConstantBounds implements BoundSig<SemLocation, Sem, FloatDelta> {
|
||||||
@@ -172,18 +169,16 @@ private module ModulusAnalysisInstantiated implements ModulusAnalysisSig<Sem> {
|
|||||||
class ModBound = AllBounds::SemBound;
|
class ModBound = AllBounds::SemBound;
|
||||||
|
|
||||||
private import codeql.rangeanalysis.ModulusAnalysis as MA
|
private import codeql.rangeanalysis.ModulusAnalysis as MA
|
||||||
import MA::ModulusAnalysis<SemLocation, Sem, FloatDelta, AllBounds, Util>
|
import MA::ModulusAnalysis<SemLocation, Sem, FloatDelta, AllBounds>
|
||||||
}
|
}
|
||||||
|
|
||||||
module Util = RangeUtil<FloatDelta, CppLangImplConstant>;
|
|
||||||
|
|
||||||
module ConstantStage =
|
module ConstantStage =
|
||||||
RangeStage<SemLocation, Sem, FloatDelta, ConstantBounds, FloatOverflow, CppLangImplConstant,
|
RangeStage<SemLocation, Sem, FloatDelta, ConstantBounds, FloatOverflow, CppLangImplConstant,
|
||||||
SignAnalysis, ModulusAnalysisInstantiated, Util>;
|
SignAnalysis, ModulusAnalysisInstantiated>;
|
||||||
|
|
||||||
module RelativeStage =
|
module RelativeStage =
|
||||||
RangeStage<SemLocation, Sem, FloatDelta, RelativeBounds, FloatOverflow, CppLangImplRelative,
|
RangeStage<SemLocation, Sem, FloatDelta, RelativeBounds, FloatOverflow, CppLangImplRelative,
|
||||||
SignAnalysis, ModulusAnalysisInstantiated, Util>;
|
SignAnalysis, ModulusAnalysisInstantiated>;
|
||||||
|
|
||||||
private newtype TSemReason =
|
private newtype TSemReason =
|
||||||
TSemNoReason() or
|
TSemNoReason() or
|
||||||
|
|||||||
@@ -54,30 +54,7 @@ module CppLangImplRelative implements LangSig<Sem, FloatDelta> {
|
|||||||
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
|
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
|
* Holds if `e2 >= e1 + delta` (if `upper = false`) or `e2 <= e1 + delta` (if `upper = true`).
|
||||||
*/
|
*/
|
||||||
predicate hasBound(SemExpr e, SemExpr bound, float delta, boolean upper) { none() }
|
predicate additionalBoundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the value of `dest` is known to be `src + delta`.
|
|
||||||
*/
|
|
||||||
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, float delta) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the type that range analysis should use to track the result of the specified expression,
|
|
||||||
* if a type other than the original type of the expression is to be used.
|
|
||||||
*
|
|
||||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
|
||||||
* actually references but whose values can be tracked as the type contained in the box.
|
|
||||||
*/
|
|
||||||
SemType getAlternateType(SemExpr e) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the type that range analysis should use to track the result of the specified source
|
|
||||||
* variable, if a type other than the original type of the expression is to be used.
|
|
||||||
*
|
|
||||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
|
||||||
* actually references but whose values can be tracked as the type contained in the box.
|
|
||||||
*/
|
|
||||||
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,165 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides utility predicates for range analysis.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
|
||||||
private import RangeAnalysisRelativeSpecific
|
|
||||||
private import codeql.rangeanalysis.RangeAnalysis
|
|
||||||
private import RangeAnalysisImpl
|
|
||||||
private import ConstantAnalysis
|
|
||||||
|
|
||||||
module RangeUtil<DeltaSig D, LangSig<Sem, D> Lang> implements UtilSig<Sem, D> {
|
|
||||||
/**
|
|
||||||
* Gets an expression that equals `v - d`.
|
|
||||||
*/
|
|
||||||
private SemExpr semSsaRead(SemSsaVariable v, D::Delta delta) {
|
|
||||||
// There are various language-specific extension points that can be removed once we no longer
|
|
||||||
// expect to match the original Java implementation's results exactly.
|
|
||||||
result = v.getAUse() and delta = D::fromInt(0)
|
|
||||||
or
|
|
||||||
exists(D::Delta d1, SemConstantIntegerExpr c |
|
|
||||||
result.(SemAddExpr).hasOperands(semSsaRead(v, d1), c) and
|
|
||||||
delta = D::fromFloat(D::toFloat(d1) - c.getIntValue())
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(SemSubExpr sub, D::Delta d1, SemConstantIntegerExpr c |
|
|
||||||
result = sub and
|
|
||||||
sub.getLeftOperand() = semSsaRead(v, d1) and
|
|
||||||
sub.getRightOperand() = c and
|
|
||||||
delta = D::fromFloat(D::toFloat(d1) + c.getIntValue())
|
|
||||||
)
|
|
||||||
or
|
|
||||||
result = v.(SemSsaExplicitUpdate).getSourceExpr() and
|
|
||||||
delta = D::fromFloat(0)
|
|
||||||
or
|
|
||||||
result.(SemCopyValueExpr).getOperand() = semSsaRead(v, delta)
|
|
||||||
or
|
|
||||||
result.(SemStoreExpr).getOperand() = semSsaRead(v, delta)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a condition that tests whether `v` equals `e + delta`.
|
|
||||||
*
|
|
||||||
* If the condition evaluates to `testIsTrue`:
|
|
||||||
* - `isEq = true` : `v == e + delta`
|
|
||||||
* - `isEq = false` : `v != e + delta`
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
SemGuard semEqFlowCond(
|
|
||||||
SemSsaVariable v, SemExpr e, D::Delta delta, boolean isEq, boolean testIsTrue
|
|
||||||
) {
|
|
||||||
exists(boolean eqpolarity |
|
|
||||||
result.isEquality(semSsaRead(v, delta), e, eqpolarity) and
|
|
||||||
(testIsTrue = true or testIsTrue = false) and
|
|
||||||
eqpolarity.booleanXor(testIsTrue).booleanNot() = isEq
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(boolean testIsTrue0 |
|
|
||||||
semImplies_v2(result, testIsTrue, semEqFlowCond(v, e, delta, isEq, testIsTrue0), testIsTrue0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `v` is an `SsaExplicitUpdate` that equals `e + delta`.
|
|
||||||
*/
|
|
||||||
predicate semSsaUpdateStep(SemSsaExplicitUpdate v, SemExpr e, D::Delta delta) {
|
|
||||||
exists(SemExpr defExpr | defExpr = v.getSourceExpr() |
|
|
||||||
defExpr.(SemCopyValueExpr).getOperand() = e and delta = D::fromFloat(0)
|
|
||||||
or
|
|
||||||
defExpr.(SemStoreExpr).getOperand() = e and delta = D::fromFloat(0)
|
|
||||||
or
|
|
||||||
defExpr.(SemAddOneExpr).getOperand() = e and delta = D::fromFloat(1)
|
|
||||||
or
|
|
||||||
defExpr.(SemSubOneExpr).getOperand() = e and delta = D::fromFloat(-1)
|
|
||||||
or
|
|
||||||
e = defExpr and
|
|
||||||
not (
|
|
||||||
defExpr instanceof SemCopyValueExpr or
|
|
||||||
defExpr instanceof SemStoreExpr or
|
|
||||||
defExpr instanceof SemAddOneExpr or
|
|
||||||
defExpr instanceof SemSubOneExpr
|
|
||||||
) and
|
|
||||||
delta = D::fromFloat(0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `e1 + delta` equals `e2`.
|
|
||||||
*/
|
|
||||||
predicate semValueFlowStep(SemExpr e2, SemExpr e1, D::Delta delta) {
|
|
||||||
e2.(SemCopyValueExpr).getOperand() = e1 and delta = D::fromFloat(0)
|
|
||||||
or
|
|
||||||
e2.(SemStoreExpr).getOperand() = e1 and delta = D::fromFloat(0)
|
|
||||||
or
|
|
||||||
e2.(SemAddOneExpr).getOperand() = e1 and delta = D::fromFloat(1)
|
|
||||||
or
|
|
||||||
e2.(SemSubOneExpr).getOperand() = e1 and delta = D::fromFloat(-1)
|
|
||||||
or
|
|
||||||
Lang::additionalValueFlowStep(e2, e1, delta)
|
|
||||||
or
|
|
||||||
exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
|
|
||||||
D::fromInt(x.(SemConstantIntegerExpr).getIntValue()) = delta
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(SemExpr x, SemSubExpr sub |
|
|
||||||
e2 = sub and
|
|
||||||
sub.getLeftOperand() = e1 and
|
|
||||||
sub.getRightOperand() = x
|
|
||||||
|
|
|
||||||
D::fromInt(-x.(SemConstantIntegerExpr).getIntValue()) = delta
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the type used to track the specified expression's range information.
|
|
||||||
*
|
|
||||||
* Usually, this just `e.getSemType()`, but the language can override this to track immutable boxed
|
|
||||||
* primitive types as the underlying primitive type.
|
|
||||||
*/
|
|
||||||
SemType getTrackedType(SemExpr e) {
|
|
||||||
result = Lang::getAlternateType(e)
|
|
||||||
or
|
|
||||||
not exists(Lang::getAlternateType(e)) and result = e.getSemType()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the type used to track the specified source variable's range information.
|
|
||||||
*
|
|
||||||
* Usually, this just `e.getType()`, but the language can override this to track immutable boxed
|
|
||||||
* primitive types as the underlying primitive type.
|
|
||||||
*/
|
|
||||||
SemType getTrackedTypeForSsaVariable(SemSsaVariable var) {
|
|
||||||
result = Lang::getAlternateTypeForSsaVariable(var)
|
|
||||||
or
|
|
||||||
not exists(Lang::getAlternateTypeForSsaVariable(var)) and result = var.getType()
|
|
||||||
}
|
|
||||||
|
|
||||||
import Ranking
|
|
||||||
}
|
|
||||||
|
|
||||||
import Ranking
|
|
||||||
|
|
||||||
module Ranking {
|
|
||||||
/**
|
|
||||||
* Holds if `rix` is the number of input edges to `phi`.
|
|
||||||
*/
|
|
||||||
predicate maxPhiInputRank(SemSsaPhiNode phi, int rix) {
|
|
||||||
rix = max(int r | rankedPhiInput(phi, _, _, r))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `inp` is an input to `phi` along `edge` and this input has index `r`
|
|
||||||
* in an arbitrary 1-based numbering of the input edges to `phi`.
|
|
||||||
*/
|
|
||||||
predicate rankedPhiInput(
|
|
||||||
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int r
|
|
||||||
) {
|
|
||||||
edge.phiInput(phi, inp) and
|
|
||||||
edge =
|
|
||||||
rank[r](SemSsaReadPositionPhiInputEdge e |
|
|
||||||
e.phiInput(phi, _)
|
|
||||||
|
|
|
||||||
e order by e.getOrigBlock().getUniqueId()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,10 +11,9 @@ private import RangeAnalysisImpl
|
|||||||
private import SignAnalysisSpecific as Specific
|
private import SignAnalysisSpecific as Specific
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||||
private import ConstantAnalysis
|
private import ConstantAnalysis
|
||||||
private import RangeUtils
|
|
||||||
private import Sign
|
private import Sign
|
||||||
|
|
||||||
module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
module SignAnalysis<DeltaSig D> {
|
||||||
private import codeql.rangeanalysis.internal.RangeUtils::MakeUtils<Sem, D>
|
private import codeql.rangeanalysis.internal.RangeUtils::MakeUtils<Sem, D>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,13 +38,13 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
|
|
||||||
/** An SSA definition whose sign is determined by the sign of that definitions source expression. */
|
/** An SSA definition whose sign is determined by the sign of that definitions source expression. */
|
||||||
private class ExplicitSignDef extends FlowSignDef instanceof SemSsaExplicitUpdate {
|
private class ExplicitSignDef extends FlowSignDef instanceof SemSsaExplicitUpdate {
|
||||||
final override Sign getSign() { result = semExprSign(super.getSourceExpr()) }
|
final override Sign getSign() { result = semExprSign(super.getDefiningExpr()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
|
/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
|
||||||
private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode {
|
private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode {
|
||||||
final override Sign getSign() {
|
final override Sign getSign() {
|
||||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
|
exists(SemSsaVariable inp, SsaReadPositionPhiInputEdge edge |
|
||||||
edge.phiInput(this, inp) and
|
edge.phiInput(this, inp) and
|
||||||
result = semSsaSign(inp, edge)
|
result = semSsaSign(inp, edge)
|
||||||
)
|
)
|
||||||
@@ -148,7 +147,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
not this instanceof ConstantSignExpr and
|
not this instanceof ConstantSignExpr and
|
||||||
(
|
(
|
||||||
// Only track numeric types.
|
// Only track numeric types.
|
||||||
Utils::getTrackedType(this) instanceof SemNumericType
|
Sem::getExprType(this) instanceof SemNumericType
|
||||||
or
|
or
|
||||||
// Unless the language says to track this expression anyway.
|
// Unless the language says to track this expression anyway.
|
||||||
Specific::trackUnknownNonNumericExpr(this)
|
Specific::trackUnknownNonNumericExpr(this)
|
||||||
@@ -170,11 +169,11 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
override Sign getSignRestriction() {
|
override Sign getSignRestriction() {
|
||||||
// Propagate via SSA
|
// Propagate via SSA
|
||||||
// Propagate the sign from the def of `v`, incorporating any inference from guards.
|
// Propagate the sign from the def of `v`, incorporating any inference from guards.
|
||||||
result = semSsaSign(v, any(SemSsaReadPositionBlock bb | bb.getAnExpr() = this))
|
result = semSsaSign(v, any(SsaReadPositionBlock bb | bb.getBlock().getAnExpr() = this))
|
||||||
or
|
or
|
||||||
// No block for this read. Just use the sign of the def.
|
// No block for this read. Just use the sign of the def.
|
||||||
// REVIEW: How can this happen?
|
// REVIEW: How can this happen?
|
||||||
not exists(SemSsaReadPositionBlock bb | bb.getAnExpr() = this) and
|
not exists(SsaReadPositionBlock bb | bb.getBlock().getAnExpr() = this) and
|
||||||
result = semSsaDefSign(v)
|
result = semSsaDefSign(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,7 +202,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
|
|
||||||
/** An expression of an unsigned type. */
|
/** An expression of an unsigned type. */
|
||||||
private class UnsignedExpr extends FlowSignExpr {
|
private class UnsignedExpr extends FlowSignExpr {
|
||||||
UnsignedExpr() { Utils::getTrackedType(this) instanceof SemUnsignedIntegerType }
|
UnsignedExpr() { Sem::getExprType(this) instanceof SemUnsignedIntegerType }
|
||||||
|
|
||||||
override Sign getSignRestriction() {
|
override Sign getSignRestriction() {
|
||||||
result = TPos() or
|
result = TPos() or
|
||||||
@@ -276,7 +275,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
override SemUnboxExpr cast;
|
override SemUnboxExpr cast;
|
||||||
|
|
||||||
UnboxSignExpr() {
|
UnboxSignExpr() {
|
||||||
exists(SemType fromType | fromType = Utils::getTrackedType(cast.getOperand()) |
|
exists(SemType fromType | fromType = Sem::getExprType(cast.getOperand()) |
|
||||||
// Only numeric source types are handled here.
|
// Only numeric source types are handled here.
|
||||||
fromType instanceof SemNumericType
|
fromType instanceof SemNumericType
|
||||||
)
|
)
|
||||||
@@ -290,11 +289,11 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* to only include bounds for which we might determine a sign.
|
* to only include bounds for which we might determine a sign.
|
||||||
*/
|
*/
|
||||||
private predicate lowerBound(
|
private predicate lowerBound(
|
||||||
SemExpr lowerbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
|
SemExpr lowerbound, SemSsaVariable v, SsaReadPosition pos, boolean isStrict
|
||||||
) {
|
) {
|
||||||
exists(boolean testIsTrue, SemRelationalExpr comp |
|
exists(boolean testIsTrue, SemRelationalExpr comp |
|
||||||
pos.hasReadOfVar(v) and
|
pos.hasReadOfVar(v) and
|
||||||
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
guardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||||
not unknownSign(lowerbound)
|
not unknownSign(lowerbound)
|
||||||
|
|
|
|
||||||
testIsTrue = true and
|
testIsTrue = true and
|
||||||
@@ -314,11 +313,11 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* to only include bounds for which we might determine a sign.
|
* to only include bounds for which we might determine a sign.
|
||||||
*/
|
*/
|
||||||
private predicate upperBound(
|
private predicate upperBound(
|
||||||
SemExpr upperbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
|
SemExpr upperbound, SemSsaVariable v, SsaReadPosition pos, boolean isStrict
|
||||||
) {
|
) {
|
||||||
exists(boolean testIsTrue, SemRelationalExpr comp |
|
exists(boolean testIsTrue, SemRelationalExpr comp |
|
||||||
pos.hasReadOfVar(v) and
|
pos.hasReadOfVar(v) and
|
||||||
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
guardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||||
not unknownSign(upperbound)
|
not unknownSign(upperbound)
|
||||||
|
|
|
|
||||||
testIsTrue = true and
|
testIsTrue = true and
|
||||||
@@ -340,10 +339,10 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* - `isEq = true` : `v = eqbound`
|
* - `isEq = true` : `v = eqbound`
|
||||||
* - `isEq = false` : `v != eqbound`
|
* - `isEq = false` : `v != eqbound`
|
||||||
*/
|
*/
|
||||||
private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isEq) {
|
private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SsaReadPosition pos, boolean isEq) {
|
||||||
exists(SemGuard guard, boolean testIsTrue, boolean polarity, SemExpr e |
|
exists(SemGuard guard, boolean testIsTrue, boolean polarity, SemExpr e |
|
||||||
pos.hasReadOfVar(pragma[only_bind_into](v)) and
|
pos.hasReadOfVar(pragma[only_bind_into](v)) and
|
||||||
semGuardControlsSsaRead(guard, pragma[only_bind_into](pos), testIsTrue) and
|
guardControlsSsaRead(guard, pragma[only_bind_into](pos), testIsTrue) and
|
||||||
e = ssaRead(pragma[only_bind_into](v), D::fromInt(0)) and
|
e = ssaRead(pragma[only_bind_into](v), D::fromInt(0)) and
|
||||||
guard.isEquality(eqbound, e, polarity) and
|
guard.isEquality(eqbound, e, polarity) and
|
||||||
isEq = polarity.booleanXor(testIsTrue).booleanNot() and
|
isEq = polarity.booleanXor(testIsTrue).booleanNot() and
|
||||||
@@ -355,7 +354,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* Holds if `bound` is a bound for `v` at `pos` that needs to be positive in
|
* Holds if `bound` is a bound for `v` at `pos` that needs to be positive in
|
||||||
* order for `v` to be positive.
|
* order for `v` to be positive.
|
||||||
*/
|
*/
|
||||||
private predicate posBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
private predicate posBound(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||||
upperBound(bound, v, pos, _) or
|
upperBound(bound, v, pos, _) or
|
||||||
eqBound(bound, v, pos, true)
|
eqBound(bound, v, pos, true)
|
||||||
}
|
}
|
||||||
@@ -364,7 +363,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* Holds if `bound` is a bound for `v` at `pos` that needs to be negative in
|
* Holds if `bound` is a bound for `v` at `pos` that needs to be negative in
|
||||||
* order for `v` to be negative.
|
* order for `v` to be negative.
|
||||||
*/
|
*/
|
||||||
private predicate negBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
private predicate negBound(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||||
lowerBound(bound, v, pos, _) or
|
lowerBound(bound, v, pos, _) or
|
||||||
eqBound(bound, v, pos, true)
|
eqBound(bound, v, pos, true)
|
||||||
}
|
}
|
||||||
@@ -373,24 +372,24 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v`
|
* Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v`
|
||||||
* can be zero.
|
* can be zero.
|
||||||
*/
|
*/
|
||||||
private predicate zeroBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
private predicate zeroBound(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||||
lowerBound(bound, v, pos, _) or
|
lowerBound(bound, v, pos, _) or
|
||||||
upperBound(bound, v, pos, _) or
|
upperBound(bound, v, pos, _) or
|
||||||
eqBound(bound, v, pos, _)
|
eqBound(bound, v, pos, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if `bound` allows `v` to be positive at `pos`. */
|
/** Holds if `bound` allows `v` to be positive at `pos`. */
|
||||||
private predicate posBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
private predicate posBoundOk(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||||
posBound(bound, v, pos) and TPos() = semExprSign(bound)
|
posBound(bound, v, pos) and TPos() = semExprSign(bound)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if `bound` allows `v` to be negative at `pos`. */
|
/** Holds if `bound` allows `v` to be negative at `pos`. */
|
||||||
private predicate negBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
private predicate negBoundOk(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||||
negBound(bound, v, pos) and TNeg() = semExprSign(bound)
|
negBound(bound, v, pos) and TNeg() = semExprSign(bound)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if `bound` allows `v` to be zero at `pos`. */
|
/** Holds if `bound` allows `v` to be zero at `pos`. */
|
||||||
private predicate zeroBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
private predicate zeroBoundOk(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||||
lowerBound(bound, v, pos, _) and TNeg() = semExprSign(bound)
|
lowerBound(bound, v, pos, _) and TNeg() = semExprSign(bound)
|
||||||
or
|
or
|
||||||
lowerBound(bound, v, pos, false) and TZero() = semExprSign(bound)
|
lowerBound(bound, v, pos, false) and TZero() = semExprSign(bound)
|
||||||
@@ -408,7 +407,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* Holds if there is a bound that might restrict whether `v` has the sign `s`
|
* Holds if there is a bound that might restrict whether `v` has the sign `s`
|
||||||
* at `pos`.
|
* at `pos`.
|
||||||
*/
|
*/
|
||||||
private predicate hasGuard(SemSsaVariable v, SemSsaReadPosition pos, Sign s) {
|
private predicate hasGuard(SemSsaVariable v, SsaReadPosition pos, Sign s) {
|
||||||
s = TPos() and posBound(_, v, pos)
|
s = TPos() and posBound(_, v, pos)
|
||||||
or
|
or
|
||||||
s = TNeg() and negBound(_, v, pos)
|
s = TNeg() and negBound(_, v, pos)
|
||||||
@@ -421,7 +420,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* might be ruled out by a guard.
|
* might be ruled out by a guard.
|
||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private Sign guardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
private Sign guardedSsaSign(SemSsaVariable v, SsaReadPosition pos) {
|
||||||
result = semSsaDefSign(v) and
|
result = semSsaDefSign(v) and
|
||||||
pos.hasReadOfVar(v) and
|
pos.hasReadOfVar(v) and
|
||||||
hasGuard(v, pos, result)
|
hasGuard(v, pos, result)
|
||||||
@@ -432,7 +431,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* can rule it out.
|
* can rule it out.
|
||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private Sign unguardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
private Sign unguardedSsaSign(SemSsaVariable v, SsaReadPosition pos) {
|
||||||
result = semSsaDefSign(v) and
|
result = semSsaDefSign(v) and
|
||||||
pos.hasReadOfVar(v) and
|
pos.hasReadOfVar(v) and
|
||||||
not hasGuard(v, pos, result)
|
not hasGuard(v, pos, result)
|
||||||
@@ -443,7 +442,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* ruled out the sign but does not.
|
* ruled out the sign but does not.
|
||||||
* This does not check that the definition of `v` also allows the sign.
|
* This does not check that the definition of `v` also allows the sign.
|
||||||
*/
|
*/
|
||||||
private Sign guardedSsaSignOk(SemSsaVariable v, SemSsaReadPosition pos) {
|
private Sign guardedSsaSignOk(SemSsaVariable v, SsaReadPosition pos) {
|
||||||
result = TPos() and
|
result = TPos() and
|
||||||
forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos))
|
forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos))
|
||||||
or
|
or
|
||||||
@@ -455,7 +454,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a possible sign for `v` at `pos`. */
|
/** Gets a possible sign for `v` at `pos`. */
|
||||||
private Sign semSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
private Sign semSsaSign(SemSsaVariable v, SsaReadPosition pos) {
|
||||||
result = unguardedSsaSign(v, pos)
|
result = unguardedSsaSign(v, pos)
|
||||||
or
|
or
|
||||||
result = guardedSsaSign(v, pos) and
|
result = guardedSsaSign(v, pos) and
|
||||||
@@ -471,7 +470,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
Sign semExprSign(SemExpr e) {
|
Sign semExprSign(SemExpr e) {
|
||||||
exists(Sign s | s = e.(SignExpr).getSign() |
|
exists(Sign s | s = e.(SignExpr).getSign() |
|
||||||
if
|
if
|
||||||
Utils::getTrackedType(e) instanceof SemUnsignedIntegerType and
|
Sem::getExprType(e) instanceof SemUnsignedIntegerType and
|
||||||
s = TNeg() and
|
s = TNeg() and
|
||||||
not Specific::ignoreTypeRestrictions(e)
|
not Specific::ignoreTypeRestrictions(e)
|
||||||
then result = TPos()
|
then result = TPos()
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
## 0.8.3
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* The `cpp/uninitialized-local` query has been improved to produce fewer false positives.
|
||||||
|
|
||||||
## 0.8.2
|
## 0.8.2
|
||||||
|
|
||||||
No user-facing changes.
|
No user-facing changes.
|
||||||
|
|||||||
@@ -27,16 +27,26 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
|||||||
ReturnStackAllocatedMemoryConfig() { this = "ReturnStackAllocatedMemoryConfig" }
|
ReturnStackAllocatedMemoryConfig() { this = "ReturnStackAllocatedMemoryConfig" }
|
||||||
|
|
||||||
override predicate isSource(Instruction source) {
|
override predicate isSource(Instruction source) {
|
||||||
// Holds if `source` is a node that represents the use of a stack variable
|
exists(Function func |
|
||||||
exists(VariableAddressInstruction var, Function func |
|
|
||||||
var = source and
|
|
||||||
func = source.getEnclosingFunction() and
|
|
||||||
var.getAstVariable() instanceof StackVariable and
|
|
||||||
// Pointer-to-member types aren't properly handled in the dbscheme.
|
|
||||||
not var.getResultType() instanceof PointerToMemberType and
|
|
||||||
// Rule out FPs caused by extraction errors.
|
// Rule out FPs caused by extraction errors.
|
||||||
not any(ErrorExpr e).getEnclosingFunction() = func and
|
not any(ErrorExpr e).getEnclosingFunction() = func and
|
||||||
not intentionallyReturnsStackPointer(func)
|
not intentionallyReturnsStackPointer(func) and
|
||||||
|
func = source.getEnclosingFunction()
|
||||||
|
|
|
||||||
|
// `source` is an instruction that represents the use of a stack variable
|
||||||
|
exists(VariableAddressInstruction var |
|
||||||
|
var = source and
|
||||||
|
var.getAstVariable() instanceof StackVariable and
|
||||||
|
// Pointer-to-member types aren't properly handled in the dbscheme.
|
||||||
|
not var.getResultType() instanceof PointerToMemberType
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// `source` is an instruction that represents the return value of a
|
||||||
|
// function that is known to return stack-allocated memory.
|
||||||
|
exists(Call call |
|
||||||
|
call.getTarget().hasGlobalName(["alloca", "strdupa", "strndupa", "_alloca", "_malloca"]) and
|
||||||
|
source.getUnconvertedResultExpression() = call
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,10 +95,10 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
from
|
from
|
||||||
MustFlowPathNode source, MustFlowPathNode sink, VariableAddressInstruction var,
|
MustFlowPathNode source, MustFlowPathNode sink, Instruction instr,
|
||||||
ReturnStackAllocatedMemoryConfig conf
|
ReturnStackAllocatedMemoryConfig conf
|
||||||
where
|
where
|
||||||
conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
|
conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
|
||||||
source.getInstruction() = var
|
source.getInstruction() = instr
|
||||||
select sink.getInstruction(), source, sink, "May return stack-allocated memory from $@.",
|
select sink.getInstruction(), source, sink, "May return stack-allocated memory from $@.",
|
||||||
var.getAst(), var.getAst().toString()
|
instr.getAst(), instr.getAst().toString()
|
||||||
|
|||||||
@@ -13,7 +13,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
import semmle.code.cpp.ir.IR
|
||||||
|
import semmle.code.cpp.ir.dataflow.MustFlow
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auxiliary predicate: Types that don't require initialization
|
* Auxiliary predicate: Types that don't require initialization
|
||||||
@@ -33,31 +34,6 @@ predicate allocatedType(Type t) {
|
|||||||
allocatedType(t.getUnspecifiedType())
|
allocatedType(t.getUnspecifiedType())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A declaration of a local variable that leaves the
|
|
||||||
* variable uninitialized.
|
|
||||||
*/
|
|
||||||
DeclStmt declWithNoInit(LocalVariable v) {
|
|
||||||
result.getADeclaration() = v and
|
|
||||||
not exists(v.getInitializer()) and
|
|
||||||
/* The type of the variable is not stack-allocated. */
|
|
||||||
exists(Type t | t = v.getType() | not allocatedType(t))
|
|
||||||
}
|
|
||||||
|
|
||||||
class UninitialisedLocalReachability extends StackVariableReachability {
|
|
||||||
UninitialisedLocalReachability() { this = "UninitialisedLocal" }
|
|
||||||
|
|
||||||
override predicate isSource(ControlFlowNode node, StackVariable v) { node = declWithNoInit(v) }
|
|
||||||
|
|
||||||
override predicate isSink(ControlFlowNode node, StackVariable v) { useOfVarActual(v, node) }
|
|
||||||
|
|
||||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
|
|
||||||
// only report the _first_ possibly uninitialized use
|
|
||||||
useOfVarActual(v, node) or
|
|
||||||
definitionBarrier(v, node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
predicate containsInlineAssembly(Function f) { exists(AsmStmt s | s.getEnclosingFunction() = f) }
|
predicate containsInlineAssembly(Function f) { exists(AsmStmt s | s.getEnclosingFunction() = f) }
|
||||||
|
|
||||||
@@ -82,8 +58,33 @@ VariableAccess commonException() {
|
|||||||
containsInlineAssembly(result.getEnclosingFunction())
|
containsInlineAssembly(result.getEnclosingFunction())
|
||||||
}
|
}
|
||||||
|
|
||||||
from UninitialisedLocalReachability r, LocalVariable v, VariableAccess va
|
predicate isSinkImpl(Instruction sink, VariableAccess va) {
|
||||||
|
exists(LoadInstruction load |
|
||||||
|
va = load.getUnconvertedResultExpression() and
|
||||||
|
not va = commonException() and
|
||||||
|
sink = load.getSourceValue()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
class MustFlow extends MustFlowConfiguration {
|
||||||
|
MustFlow() { this = "MustFlow" }
|
||||||
|
|
||||||
|
override predicate isSource(Instruction source) {
|
||||||
|
source instanceof UninitializedInstruction and
|
||||||
|
exists(Type t | t = source.getResultType() | not allocatedType(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSink(Operand sink) { isSinkImpl(sink.getDef(), _) }
|
||||||
|
|
||||||
|
override predicate allowInterproceduralFlow() { none() }
|
||||||
|
|
||||||
|
override predicate isBarrier(Instruction instr) { instr instanceof ChiInstruction }
|
||||||
|
}
|
||||||
|
|
||||||
|
from
|
||||||
|
VariableAccess va, LocalVariable v, MustFlow conf, MustFlowPathNode source, MustFlowPathNode sink
|
||||||
where
|
where
|
||||||
r.reaches(_, v, va) and
|
conf.hasFlowPath(source, sink) and
|
||||||
not va = commonException()
|
isSinkImpl(sink.getInstruction(), va) and
|
||||||
|
v = va.getTarget()
|
||||||
select va, "The variable $@ may not be initialized at this access.", v, v.getName()
|
select va, "The variable $@ may not be initialized at this access.", v, v.getName()
|
||||||
|
|||||||
@@ -14,25 +14,47 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.security.Security
|
import semmle.code.cpp.security.Security
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
import semmle.code.cpp.security.FlowSources
|
||||||
import TaintedWithPath
|
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||||
|
import semmle.code.cpp.ir.IR
|
||||||
|
import Flow::PathGraph
|
||||||
|
|
||||||
predicate isProcessOperationExplanation(Expr arg, string processOperation) {
|
predicate isProcessOperationExplanation(DataFlow::Node arg, string processOperation) {
|
||||||
exists(int processOperationArg, FunctionCall call |
|
exists(int processOperationArg, FunctionCall call |
|
||||||
isProcessOperationArgument(processOperation, processOperationArg) and
|
isProcessOperationArgument(processOperation, processOperationArg) and
|
||||||
call.getTarget().getName() = processOperation and
|
call.getTarget().getName() = processOperation and
|
||||||
call.getArgument(processOperationArg) = arg
|
call.getArgument(processOperationArg) = [arg.asExpr(), arg.asIndirectExpr()]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Configuration extends TaintTrackingConfiguration {
|
predicate isSource(FlowSource source, string sourceType) {
|
||||||
override predicate isSink(Element arg) { isProcessOperationExplanation(arg, _) }
|
not source instanceof DataFlow::ExprNode and
|
||||||
|
sourceType = source.getSourceType()
|
||||||
}
|
}
|
||||||
|
|
||||||
from string processOperation, Expr arg, Expr source, PathNode sourceNode, PathNode sinkNode
|
module Config implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node node) { isSource(node, _) }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node node) { isProcessOperationExplanation(node, _) }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
isSink(node) and node.asExpr().getUnspecifiedType() instanceof ArithmeticType
|
||||||
|
or
|
||||||
|
node.asInstruction().(StoreInstruction).getResultType() instanceof ArithmeticType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module Flow = TaintTracking::Global<Config>;
|
||||||
|
|
||||||
|
from
|
||||||
|
string processOperation, string sourceType, DataFlow::Node source, DataFlow::Node sink,
|
||||||
|
Flow::PathNode sourceNode, Flow::PathNode sinkNode
|
||||||
where
|
where
|
||||||
isProcessOperationExplanation(arg, processOperation) and
|
source = sourceNode.getNode() and
|
||||||
taintedWithPath(source, arg, sourceNode, sinkNode)
|
sink = sinkNode.getNode() and
|
||||||
select arg, sourceNode, sinkNode,
|
isSource(source, sourceType) and
|
||||||
|
isProcessOperationExplanation(sink, processOperation) and
|
||||||
|
Flow::flowPath(sourceNode, sinkNode)
|
||||||
|
select sink, sourceNode, sinkNode,
|
||||||
"The value of this argument may come from $@ and is being passed to " + processOperation + ".",
|
"The value of this argument may come from $@ and is being passed to " + processOperation + ".",
|
||||||
source, source.toString()
|
source, sourceType
|
||||||
|
|||||||
@@ -15,9 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import semmle.code.cpp.security.BufferWrite
|
import semmle.code.cpp.security.BufferWrite
|
||||||
import semmle.code.cpp.security.Security
|
import semmle.code.cpp.security.FlowSources as FS
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||||
import TaintedWithPath
|
import semmle.code.cpp.controlflow.IRGuards
|
||||||
|
import Flow::PathGraph
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* --- Summary of CWE-120 alerts ---
|
* --- Summary of CWE-120 alerts ---
|
||||||
@@ -47,38 +48,54 @@ predicate isUnboundedWrite(BufferWrite bw) {
|
|||||||
not exists(bw.getMaxData(_)) // and we can't deduce an upper bound to the amount copied
|
not exists(bw.getMaxData(_)) // and we can't deduce an upper bound to the amount copied
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* predicate isMaybeUnboundedWrite(BufferWrite bw)
|
|
||||||
* {
|
|
||||||
* not bw.hasExplicitLimit() // has no explicit size limit
|
|
||||||
* and exists(bw.getMaxData()) // and we can deduce an upper bound to the amount copied
|
|
||||||
* and (not exists(getBufferSize(bw.getDest(), _))) // but we can't work out the size of the destination to be sure
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `e` is a source buffer going into an unbounded write `bw` or a
|
* Holds if `e` is a source buffer going into an unbounded write `bw` or a
|
||||||
* qualifier of (a qualifier of ...) such a source.
|
* qualifier of (a qualifier of ...) such a source.
|
||||||
*/
|
*/
|
||||||
predicate unboundedWriteSource(Expr e, BufferWrite bw) {
|
predicate unboundedWriteSource(Expr e, BufferWrite bw, boolean qualifier) {
|
||||||
isUnboundedWrite(bw) and e = bw.getASource()
|
isUnboundedWrite(bw) and e = bw.getASource() and qualifier = false
|
||||||
or
|
or
|
||||||
exists(FieldAccess fa | unboundedWriteSource(fa, bw) and e = fa.getQualifier())
|
exists(FieldAccess fa | unboundedWriteSource(fa, bw, _) and e = fa.getQualifier()) and
|
||||||
|
qualifier = true
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
predicate isSource(FS::FlowSource source, string sourceType) { source.getSourceType() = sourceType }
|
||||||
* --- user input reach ---
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Configuration extends TaintTrackingConfiguration {
|
predicate isSink(DataFlow::Node sink, BufferWrite bw, boolean qualifier) {
|
||||||
override predicate isSink(Element tainted) { unboundedWriteSource(tainted, _) }
|
unboundedWriteSource(sink.asIndirectExpr(), bw, qualifier)
|
||||||
|
or
|
||||||
override predicate taintThroughGlobals() { any() }
|
// `gets` and `scanf` reads from stdin so there's no real input.
|
||||||
|
// The `BufferWrite` library models this as the call itself being
|
||||||
|
// the source. In this case we mark the output argument as being
|
||||||
|
// the sink so that we report a path where source = sink (because
|
||||||
|
// the same output argument is also included in `isSource`).
|
||||||
|
bw.getASource() = bw and
|
||||||
|
unboundedWriteSource(sink.asDefiningArgument(), bw, qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
predicate lessThanOrEqual(IRGuardCondition g, Expr e, boolean branch) {
|
||||||
* --- put it together ---
|
exists(Operand left |
|
||||||
*/
|
g.comparesLt(left, _, _, true, branch) or
|
||||||
|
g.comparesEq(left, _, _, true, branch)
|
||||||
|
|
|
||||||
|
left.getDef().getUnconvertedResultExpression() = e
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module Config implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { isSource(source, _) }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { isSink(sink, _, _) }
|
||||||
|
|
||||||
|
predicate isBarrierOut(DataFlow::Node node) { isSink(node, _, false) }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
// Block flow if the node is guarded by any <, <= or = operations.
|
||||||
|
node = DataFlow::BarrierGuard<lessThanOrEqual/3>::getABarrierNode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module Flow = TaintTracking::Global<Config>;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* An unbounded write is, for example `strcpy(..., tainted)`. We're looking
|
* An unbounded write is, for example `strcpy(..., tainted)`. We're looking
|
||||||
@@ -87,17 +104,20 @@ class Configuration extends TaintTrackingConfiguration {
|
|||||||
*
|
*
|
||||||
* In the case of `gets` and `scanf`, where the source buffer is implicit, the
|
* In the case of `gets` and `scanf`, where the source buffer is implicit, the
|
||||||
* `BufferWrite` library reports the source buffer to be the same as the
|
* `BufferWrite` library reports the source buffer to be the same as the
|
||||||
* destination buffer. Since those destination-buffer arguments are also
|
* destination buffer. So to report an alert on a pattern like:
|
||||||
* modeled in the taint-tracking library as being _sources_ of taint, they are
|
* ```
|
||||||
* in practice reported as being tainted because the `security.TaintTracking`
|
* char s[32];
|
||||||
* library does not distinguish between taint going into an argument and out of
|
* gets(s);
|
||||||
* an argument. Thus, we get the desired alerts.
|
* ```
|
||||||
|
* we define the sink as the node corresponding to the output argument of `gets`.
|
||||||
|
* This gives us a path where the source is equal to the sink.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
from BufferWrite bw, Expr inputSource, Expr tainted, PathNode sourceNode, PathNode sinkNode
|
from BufferWrite bw, Flow::PathNode source, Flow::PathNode sink, string sourceType
|
||||||
where
|
where
|
||||||
taintedWithPath(inputSource, tainted, sourceNode, sinkNode) and
|
Flow::flowPath(source, sink) and
|
||||||
unboundedWriteSource(tainted, bw)
|
isSource(source.getNode(), sourceType) and
|
||||||
select bw, sourceNode, sinkNode,
|
isSink(sink.getNode(), bw, _)
|
||||||
"This '" + bw.getBWDesc() + "' with input from $@ may overflow the destination.", inputSource,
|
select bw, source, sink,
|
||||||
inputSource.toString()
|
"This '" + bw.getBWDesc() + "' with input from $@ may overflow the destination.",
|
||||||
|
source.getNode(), sourceType
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
char *copy;
|
|
||||||
|
|
||||||
void copyArgv(char **argv) {
|
|
||||||
copy = argv[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
void printWrapper(char *str) {
|
|
||||||
printf(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
copyArgv(argv);
|
|
||||||
|
|
||||||
// This should be avoided
|
|
||||||
printf(copy);
|
|
||||||
|
|
||||||
// This should be avoided too, because it has the same effect
|
|
||||||
printWrapper(copy);
|
|
||||||
|
|
||||||
// This is fine
|
|
||||||
printf("%s", copy);
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<!DOCTYPE qhelp PUBLIC
|
|
||||||
"-//Semmle//qhelp//EN"
|
|
||||||
"qhelp.dtd">
|
|
||||||
<qhelp>
|
|
||||||
<overview>
|
|
||||||
<p>The program uses input from the user, propagated via a global variable, as a format string for <code>printf</code> style functions.
|
|
||||||
This can lead to buffer overflows or data representation problems. An attacker can exploit this weakness to crash the program,
|
|
||||||
disclose information or even execute arbitrary code.</p>
|
|
||||||
|
|
||||||
<p>This rule only identifies inputs from the user that are transferred through global variables before being used in <code>printf</code> style functions.
|
|
||||||
Analyzing the flow of data through global variables is more prone to errors and so this rule may identify some examples of code where
|
|
||||||
the input is not really from the user. For example, when a global variable is set in two places, one that comes from the user and one that does not.
|
|
||||||
In this case we would mark all usages of the global variable as input from the user, but the input from the user may always came after the call to the
|
|
||||||
<code>printf</code> style functions.</p>
|
|
||||||
|
|
||||||
<p>The results of this rule should be considered alongside the related rule "Uncontrolled format string" which tracks the flow of the
|
|
||||||
values input by a user, excluding global variables, until the values are used as the format argument for a <code>printf</code> like function call.</p>
|
|
||||||
|
|
||||||
</overview>
|
|
||||||
<recommendation>
|
|
||||||
<p>Use constant expressions as the format strings. If you need to print a value from the user, use <code>printf("%s", value_from_user)</code>.</p>
|
|
||||||
|
|
||||||
</recommendation>
|
|
||||||
<example>
|
|
||||||
<sample src="UncontrolledFormatStringThroughGlobalVar.c" />
|
|
||||||
|
|
||||||
</example>
|
|
||||||
<references>
|
|
||||||
|
|
||||||
<li>CERT C Coding
|
|
||||||
Standard: <a href="https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings">FIO30-C. Exclude
|
|
||||||
user input from format strings</a>.</li>
|
|
||||||
|
|
||||||
|
|
||||||
</references>
|
|
||||||
</qhelp>
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/**
|
|
||||||
* @name Uncontrolled format string (through global variable)
|
|
||||||
* @description Using externally-controlled format strings in
|
|
||||||
* printf-style functions can lead to buffer overflows
|
|
||||||
* or data representation problems.
|
|
||||||
* @kind path-problem
|
|
||||||
* @problem.severity warning
|
|
||||||
* @security-severity 9.3
|
|
||||||
* @precision high
|
|
||||||
* @id cpp/tainted-format-string-through-global
|
|
||||||
* @tags reliability
|
|
||||||
* security
|
|
||||||
* external/cwe/cwe-134
|
|
||||||
*/
|
|
||||||
|
|
||||||
import cpp
|
|
||||||
import semmle.code.cpp.security.FunctionWithWrappers
|
|
||||||
import semmle.code.cpp.security.Security
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
|
||||||
import TaintedWithPath
|
|
||||||
|
|
||||||
class Configuration extends TaintTrackingConfiguration {
|
|
||||||
override predicate isSink(Element tainted) {
|
|
||||||
exists(PrintfLikeFunction printf | printf.outermostWrapperFunctionCall(tainted, _))
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate taintThroughGlobals() { any() }
|
|
||||||
}
|
|
||||||
|
|
||||||
from
|
|
||||||
PrintfLikeFunction printf, Expr arg, PathNode sourceNode, PathNode sinkNode,
|
|
||||||
string printfFunction, Expr userValue, string cause
|
|
||||||
where
|
|
||||||
printf.outermostWrapperFunctionCall(arg, printfFunction) and
|
|
||||||
not taintedWithoutGlobals(arg) and
|
|
||||||
taintedWithPath(userValue, arg, sourceNode, sinkNode) and
|
|
||||||
isUserInput(userValue, cause)
|
|
||||||
select arg, sourceNode, sinkNode,
|
|
||||||
"The value of this argument may come from $@ and is being used as a formatting argument to " +
|
|
||||||
printfFunction + ".", userValue, cause
|
|
||||||
@@ -14,10 +14,13 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.security.Overflow
|
import semmle.code.cpp.security.Overflow
|
||||||
import semmle.code.cpp.security.Security
|
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
import semmle.code.cpp.dataflow.new.DataFlow
|
||||||
import TaintedWithPath
|
import semmle.code.cpp.ir.IR
|
||||||
|
import semmle.code.cpp.controlflow.IRGuards as IRGuards
|
||||||
|
import semmle.code.cpp.security.FlowSources as FS
|
||||||
import Bounded
|
import Bounded
|
||||||
|
import Flow::PathGraph
|
||||||
|
|
||||||
bindingset[op]
|
bindingset[op]
|
||||||
predicate missingGuard(Operation op, Expr e, string effect) {
|
predicate missingGuard(Operation op, Expr e, string effect) {
|
||||||
@@ -28,28 +31,90 @@ predicate missingGuard(Operation op, Expr e, string effect) {
|
|||||||
not e instanceof VariableAccess and effect = "overflow"
|
not e instanceof VariableAccess and effect = "overflow"
|
||||||
}
|
}
|
||||||
|
|
||||||
class Configuration extends TaintTrackingConfiguration {
|
predicate isSource(FS::FlowSource source, string sourceType) { sourceType = source.getSourceType() }
|
||||||
override predicate isSink(Element e) {
|
|
||||||
exists(Operation op |
|
|
||||||
missingGuard(op, e, _) and
|
|
||||||
op.getAnOperand() = e
|
|
||||||
|
|
|
||||||
op instanceof UnaryArithmeticOperation or
|
|
||||||
op instanceof BinaryArithmeticOperation or
|
|
||||||
op instanceof AssignArithmeticOperation
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isBarrier(Expr e) {
|
predicate isSink(DataFlow::Node sink, Operation op, Expr e) {
|
||||||
super.isBarrier(e) or bounded(e) or e.getUnspecifiedType().(IntegralType).getSize() <= 1
|
e = sink.asExpr() and
|
||||||
|
missingGuard(op, e, _) and
|
||||||
|
op.getAnOperand() = e and
|
||||||
|
(
|
||||||
|
op instanceof UnaryArithmeticOperation or
|
||||||
|
op instanceof BinaryArithmeticOperation or
|
||||||
|
op instanceof AssignArithmeticOperation
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate hasUpperBoundsCheck(Variable var) {
|
||||||
|
exists(RelationalOperation oper, VariableAccess access |
|
||||||
|
oper.getAnOperand() = access and
|
||||||
|
access.getTarget() = var and
|
||||||
|
// Comparing to 0 is not an upper bound check
|
||||||
|
not oper.getAnOperand().getValue() = "0"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate constantInstruction(Instruction instr) {
|
||||||
|
instr instanceof ConstantInstruction or
|
||||||
|
constantInstruction(instr.(UnaryInstruction).getUnary())
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate readsVariable(LoadInstruction load, Variable var) {
|
||||||
|
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
|
||||||
|
exists(Instruction instr | instr = node.asInstruction() |
|
||||||
|
readsVariable(instr, checkedVar) and
|
||||||
|
any(IRGuards::IRGuardCondition guard).ensuresEq(access, _, _, instr.getBlock(), true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module Config implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { isSource(source, _) }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { isSink(sink, _, _) }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
exists(StoreInstruction store | store = node.asInstruction() |
|
||||||
|
// Block flow to "likely small expressions"
|
||||||
|
bounded(store.getSourceValue().getUnconvertedResultExpression())
|
||||||
|
or
|
||||||
|
// Block flow to "small types"
|
||||||
|
store.getResultType().getUnspecifiedType().(IntegralType).getSize() <= 1
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Block flow if there's an upper bound check of the variable anywhere in the program
|
||||||
|
exists(Variable checkedVar, Instruction instr | instr = node.asInstruction() |
|
||||||
|
readsVariable(instr, checkedVar) and
|
||||||
|
hasUpperBoundsCheck(checkedVar)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Block flow if the node is guarded by an equality check
|
||||||
|
exists(Variable checkedVar, Operand access |
|
||||||
|
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
|
||||||
|
readsVariable(access.getDef(), checkedVar)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Block flow to any binary instruction whose operands are both non-constants.
|
||||||
|
exists(BinaryInstruction iTo |
|
||||||
|
iTo = node.asInstruction() and
|
||||||
|
not constantInstruction(iTo.getLeft()) and
|
||||||
|
not constantInstruction(iTo.getRight()) and
|
||||||
|
// propagate taint from either the pointer or the offset, regardless of constantness
|
||||||
|
not iTo instanceof PointerArithmeticInstruction
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
from Expr origin, Expr e, string effect, PathNode sourceNode, PathNode sinkNode, Operation op
|
module Flow = TaintTracking::Global<Config>;
|
||||||
|
|
||||||
|
from
|
||||||
|
Expr e, string effect, Flow::PathNode source, Flow::PathNode sink, Operation op, string sourceType
|
||||||
where
|
where
|
||||||
taintedWithPath(origin, e, sourceNode, sinkNode) and
|
Flow::flowPath(source, sink) and
|
||||||
op.getAnOperand() = e and
|
isSource(source.getNode(), sourceType) and
|
||||||
|
isSink(sink.getNode(), op, e) and
|
||||||
missingGuard(op, e, effect)
|
missingGuard(op, e, effect)
|
||||||
select e, sourceNode, sinkNode,
|
select e, source, sink,
|
||||||
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
|
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
|
||||||
origin, "User-provided value"
|
source, sourceType
|
||||||
|
|||||||
@@ -16,45 +16,30 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.security.Overflow
|
import semmle.code.cpp.security.Overflow
|
||||||
import semmle.code.cpp.security.Security
|
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
import semmle.code.cpp.ir.IR
|
||||||
|
import semmle.code.cpp.controlflow.IRGuards as IRGuards
|
||||||
|
|
||||||
predicate isMaxValue(Expr mie) {
|
predicate isMaxValue(Expr mie) {
|
||||||
exists(MacroInvocation mi |
|
exists(MacroInvocation mi |
|
||||||
mi.getExpr() = mie and
|
mi.getExpr() = mie and
|
||||||
(
|
mi.getMacroName() = ["CHAR_MAX", "LLONG_MAX", "INT_MAX", "SHRT_MAX", "UINT_MAX"]
|
||||||
mi.getMacroName() = "CHAR_MAX" or
|
|
||||||
mi.getMacroName() = "LLONG_MAX" or
|
|
||||||
mi.getMacroName() = "INT_MAX" or
|
|
||||||
mi.getMacroName() = "SHRT_MAX" or
|
|
||||||
mi.getMacroName() = "UINT_MAX"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isMinValue(Expr mie) {
|
predicate isMinValue(Expr mie) {
|
||||||
exists(MacroInvocation mi |
|
exists(MacroInvocation mi |
|
||||||
mi.getExpr() = mie and
|
mi.getExpr() = mie and
|
||||||
(
|
mi.getMacroName() = ["CHAR_MIN", "LLONG_MIN", "INT_MIN", "SHRT_MIN"]
|
||||||
mi.getMacroName() = "CHAR_MIN" or
|
|
||||||
mi.getMacroName() = "LLONG_MIN" or
|
|
||||||
mi.getMacroName() = "INT_MIN" or
|
|
||||||
mi.getMacroName() = "SHRT_MIN"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
class SecurityOptionsArith extends SecurityOptions {
|
predicate isSource(DataFlow::Node source, string cause) {
|
||||||
override predicate isUserInput(Expr expr, string cause) {
|
exists(Expr expr | expr = source.asExpr() |
|
||||||
isMaxValue(expr) and cause = "max value"
|
isMaxValue(expr) and cause = "max value"
|
||||||
or
|
or
|
||||||
isMinValue(expr) and cause = "min value"
|
isMinValue(expr) and cause = "min value"
|
||||||
}
|
)
|
||||||
}
|
|
||||||
|
|
||||||
predicate taintedVarAccess(Expr origin, VariableAccess va, string cause) {
|
|
||||||
isUserInput(origin, cause) and
|
|
||||||
tainted(origin, va)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate causeEffectCorrespond(string cause, string effect) {
|
predicate causeEffectCorrespond(string cause, string effect) {
|
||||||
@@ -65,16 +50,79 @@ predicate causeEffectCorrespond(string cause, string effect) {
|
|||||||
effect = "underflow"
|
effect = "underflow"
|
||||||
}
|
}
|
||||||
|
|
||||||
from Expr origin, Operation op, VariableAccess va, string cause, string effect
|
predicate isSink(DataFlow::Node sink, VariableAccess va, string effect) {
|
||||||
where
|
exists(Operation op |
|
||||||
taintedVarAccess(origin, va, cause) and
|
sink.asExpr() = va and
|
||||||
op.getAnOperand() = va and
|
op.getAnOperand() = va
|
||||||
(
|
|
|
||||||
missingGuardAgainstUnderflow(op, va) and effect = "underflow"
|
missingGuardAgainstUnderflow(op, va) and effect = "underflow"
|
||||||
or
|
or
|
||||||
missingGuardAgainstOverflow(op, va) and effect = "overflow"
|
missingGuardAgainstOverflow(op, va) and effect = "overflow"
|
||||||
) and
|
)
|
||||||
causeEffectCorrespond(cause, effect)
|
}
|
||||||
|
|
||||||
|
predicate hasUpperBoundsCheck(Variable var) {
|
||||||
|
exists(RelationalOperation oper, VariableAccess access |
|
||||||
|
oper.getAnOperand() = access and
|
||||||
|
access.getTarget() = var and
|
||||||
|
// Comparing to 0 is not an upper bound check
|
||||||
|
not oper.getAnOperand().getValue() = "0"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate constantInstruction(Instruction instr) {
|
||||||
|
instr instanceof ConstantInstruction or
|
||||||
|
constantInstruction(instr.(UnaryInstruction).getUnary())
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate readsVariable(LoadInstruction load, Variable var) {
|
||||||
|
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
|
||||||
|
exists(Instruction instr | instr = node.asInstruction() |
|
||||||
|
readsVariable(instr, checkedVar) and
|
||||||
|
any(IRGuards::IRGuardCondition guard).ensuresEq(access, _, _, instr.getBlock(), true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module Config implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { isSource(source, _) }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { isSink(sink, _, _) }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
// Block flow if there's an upper bound check of the variable anywhere in the program
|
||||||
|
exists(Variable checkedVar, Instruction instr | instr = node.asInstruction() |
|
||||||
|
readsVariable(instr, checkedVar) and
|
||||||
|
hasUpperBoundsCheck(checkedVar)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Block flow if the node is guarded by an equality check
|
||||||
|
exists(Variable checkedVar, Operand access |
|
||||||
|
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
|
||||||
|
readsVariable(access.getDef(), checkedVar)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Block flow to any binary instruction whose operands are both non-constants.
|
||||||
|
exists(BinaryInstruction iTo |
|
||||||
|
iTo = node.asInstruction() and
|
||||||
|
not constantInstruction(iTo.getLeft()) and
|
||||||
|
not constantInstruction(iTo.getRight()) and
|
||||||
|
// propagate taint from either the pointer or the offset, regardless of constantness
|
||||||
|
not iTo instanceof PointerArithmeticInstruction
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module Flow = TaintTracking::Global<Config>;
|
||||||
|
|
||||||
|
from DataFlow::Node source, DataFlow::Node sink, VariableAccess va, string cause, string effect
|
||||||
|
where
|
||||||
|
Flow::flow(source, sink) and
|
||||||
|
isSource(source, cause) and
|
||||||
|
causeEffectCorrespond(cause, effect) and
|
||||||
|
isSink(sink, va, effect)
|
||||||
select va,
|
select va,
|
||||||
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
|
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
|
||||||
origin, "Extreme value"
|
source, "Extreme value"
|
||||||
|
|||||||
@@ -15,7 +15,11 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
import semmle.code.cpp.dataflow.new.DataFlow
|
||||||
|
import semmle.code.cpp.security.FlowSources as FS
|
||||||
|
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||||
|
import semmle.code.cpp.ir.IR
|
||||||
|
import semmle.code.cpp.controlflow.IRGuards as IRGuards
|
||||||
|
|
||||||
/** Holds if `expr` might overflow. */
|
/** Holds if `expr` might overflow. */
|
||||||
predicate outOfBoundsExpr(Expr expr, string kind) {
|
predicate outOfBoundsExpr(Expr expr, string kind) {
|
||||||
@@ -27,13 +31,76 @@ predicate outOfBoundsExpr(Expr expr, string kind) {
|
|||||||
else none()
|
else none()
|
||||||
}
|
}
|
||||||
|
|
||||||
from Expr use, Expr origin, string kind
|
predicate isSource(FS::FlowSource source, string sourceType) { sourceType = source.getSourceType() }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink, string kind) {
|
||||||
|
exists(Expr use |
|
||||||
|
use = sink.asExpr() and
|
||||||
|
not use.getUnspecifiedType() instanceof PointerType and
|
||||||
|
outOfBoundsExpr(use, kind) and
|
||||||
|
not inSystemMacroExpansion(use)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate hasUpperBoundsCheck(Variable var) {
|
||||||
|
exists(RelationalOperation oper, VariableAccess access |
|
||||||
|
oper.getAnOperand() = access and
|
||||||
|
access.getTarget() = var and
|
||||||
|
// Comparing to 0 is not an upper bound check
|
||||||
|
not oper.getAnOperand().getValue() = "0"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate constantInstruction(Instruction instr) {
|
||||||
|
instr instanceof ConstantInstruction or
|
||||||
|
constantInstruction(instr.(UnaryInstruction).getUnary())
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate readsVariable(LoadInstruction load, Variable var) {
|
||||||
|
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
|
||||||
|
exists(Instruction instr | instr = node.asInstruction() |
|
||||||
|
readsVariable(instr, checkedVar) and
|
||||||
|
any(IRGuards::IRGuardCondition guard).ensuresEq(access, _, _, instr.getBlock(), true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module Config implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { isSource(source, _) }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
// Block flow if there's an upper bound check of the variable anywhere in the program
|
||||||
|
exists(Variable checkedVar, Instruction instr | instr = node.asInstruction() |
|
||||||
|
readsVariable(instr, checkedVar) and
|
||||||
|
hasUpperBoundsCheck(checkedVar)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Block flow if the node is guarded by an equality check
|
||||||
|
exists(Variable checkedVar, Operand access |
|
||||||
|
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
|
||||||
|
readsVariable(access.getDef(), checkedVar)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Block flow to any binary instruction whose operands are both non-constants.
|
||||||
|
exists(BinaryInstruction iTo |
|
||||||
|
iTo = node.asInstruction() and
|
||||||
|
not constantInstruction(iTo.getLeft()) and
|
||||||
|
not constantInstruction(iTo.getRight()) and
|
||||||
|
// propagate taint from either the pointer or the offset, regardless of constantness
|
||||||
|
not iTo instanceof PointerArithmeticInstruction
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module Flow = TaintTracking::Global<Config>;
|
||||||
|
|
||||||
|
from DataFlow::Node source, DataFlow::Node sink, string kind, string sourceType
|
||||||
where
|
where
|
||||||
not use.getUnspecifiedType() instanceof PointerType and
|
Flow::flow(source, sink) and
|
||||||
outOfBoundsExpr(use, kind) and
|
isSource(source, sourceType) and
|
||||||
tainted(origin, use) and
|
isSink(sink, kind)
|
||||||
origin != use and
|
select sink, "$@ flows an expression which might " + kind + ".", source, sourceType
|
||||||
not inSystemMacroExpansion(use) and
|
|
||||||
// Avoid double-counting: don't include all the conversions of `use`.
|
|
||||||
not use instanceof Conversion
|
|
||||||
select use, "$@ flows an expression which might " + kind + ".", origin, "User-provided value"
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
* @description The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. For all files that were seen during the build, this query counts the lines of code, excluding whitespace or comments.
|
* @description The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. For all files that were seen during the build, this query counts the lines of code, excluding whitespace or comments.
|
||||||
* @kind metric
|
* @kind metric
|
||||||
* @tags summary
|
* @tags summary
|
||||||
|
* telemetry
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: minorAnalysis
|
|
||||||
---
|
|
||||||
* Added SQL API models for `ODBC`.
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: breaking
|
||||||
|
---
|
||||||
|
* The `cpp/tainted-format-string-through-global` query has been deleted. This does not lead to a loss of relevant alerts, as the query duplicated a subset of the alerts from `cpp/tainted-format-string`.
|
||||||
5
cpp/ql/src/change-notes/released/0.8.3.md
Normal file
5
cpp/ql/src/change-notes/released/0.8.3.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
## 0.8.3
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* The `cpp/uninitialized-local` query has been improved to produce fewer false positives.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.8.2
|
lastReleaseVersion: 0.8.3
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/all-asymmetric-algorithms
|
* @id cpp/quantum-readiness/cbom/all-asymmetric-algorithms
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/all-cryptographic-algorithms
|
* @id cpp/quantum-readiness/cbom/all-cryptographic-algorithms
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/all-asymmetric-encryption-algorithms
|
* @id cpp/quantum-readiness/cbom/all-asymmetric-encryption-algorithms
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/authenticated-encryption-algorithms
|
* @id cpp/quantum-readiness/cbom/authenticated-encryption-algorithms
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/block-cipher-mode
|
* @id cpp/quantum-readiness/cbom/block-cipher-mode
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/iv-sources
|
* @id cpp/quantum-readiness/cbom/iv-sources
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/unkown-iv-sources
|
* @id cpp/quantum-readiness/cbom/unkown-iv-sources
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/elliptic-curve-key-length
|
* @id cpp/quantum-readiness/cbom/elliptic-curve-key-length
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/elliptic-curve-algorithms
|
* @id cpp/quantum-readiness/cbom/elliptic-curve-algorithms
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/hash-algorithms
|
* @id cpp/quantum-readiness/cbom/hash-algorithms
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/key-exchange
|
* @id cpp/quantum-readiness/cbom/key-exchange
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/asymmetric-key-generation
|
* @id cpp/quantum-readiness/cbom/asymmetric-key-generation
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/signing-algorithms
|
* @id cpp/quantum-readiness/cbom/signing-algorithms
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/symmetric-encryption-algorithms
|
* @id cpp/quantum-readiness/cbom/symmetric-encryption-algorithms
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/unkwon-asymmetric-key-generation
|
* @id cpp/quantum-readiness/cbom/unkwon-asymmetric-key-generation
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-queries
|
name: codeql/cpp-queries
|
||||||
version: 0.8.3-dev
|
version: 0.8.4-dev
|
||||||
groups:
|
groups:
|
||||||
- cpp
|
- cpp
|
||||||
- queries
|
- queries
|
||||||
|
|||||||
111
cpp/ql/test/library-tests/dataflow/dataflow-tests/TestBase.qll
Normal file
111
cpp/ql/test/library-tests/dataflow/dataflow-tests/TestBase.qll
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
module AstTest {
|
||||||
|
import semmle.code.cpp.dataflow.DataFlow
|
||||||
|
private import semmle.code.cpp.controlflow.Guards
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement
|
||||||
|
* S in `if (guarded(x)) S`.
|
||||||
|
*/
|
||||||
|
// This is tested in `BarrierGuard.cpp`.
|
||||||
|
predicate testBarrierGuard(GuardCondition g, Expr checked, boolean isTrue) {
|
||||||
|
g.(FunctionCall).getTarget().getName() = "guarded" and
|
||||||
|
checked = g.(FunctionCall).getArgument(0) and
|
||||||
|
isTrue = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Common data flow configuration to be used by tests. */
|
||||||
|
module AstTestAllocationConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
||||||
|
or
|
||||||
|
source.asParameter().getName().matches("source%")
|
||||||
|
or
|
||||||
|
source.asExpr().(FunctionCall).getTarget().getName() = "indirect_source"
|
||||||
|
or
|
||||||
|
source.(DataFlow::DefinitionByReferenceNode).getParameter().getName().matches("ref_source%")
|
||||||
|
or
|
||||||
|
// Track uninitialized variables
|
||||||
|
exists(source.asUninitialized())
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
exists(FunctionCall call |
|
||||||
|
call.getTarget().getName() = ["sink", "indirect_sink"] and
|
||||||
|
sink.asExpr() = call.getAnArgument()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node barrier) {
|
||||||
|
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier") or
|
||||||
|
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module AstFlow = DataFlow::Global<AstTestAllocationConfig>;
|
||||||
|
}
|
||||||
|
|
||||||
|
module IRTest {
|
||||||
|
private import cpp
|
||||||
|
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||||
|
private import semmle.code.cpp.ir.IR
|
||||||
|
private import semmle.code.cpp.controlflow.IRGuards
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement
|
||||||
|
* S in `if (guarded(x)) S`.
|
||||||
|
*/
|
||||||
|
// This is tested in `BarrierGuard.cpp`.
|
||||||
|
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean isTrue) {
|
||||||
|
exists(Call call |
|
||||||
|
call = g.getUnconvertedResultExpression() and
|
||||||
|
call.getTarget().hasName("guarded") and
|
||||||
|
checked = call.getArgument(0) and
|
||||||
|
isTrue = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Common data flow configuration to be used by tests. */
|
||||||
|
module IRTestAllocationConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
||||||
|
or
|
||||||
|
source.asIndirectExpr(1).(FunctionCall).getTarget().getName() = "indirect_source"
|
||||||
|
or
|
||||||
|
source.asExpr().(StringLiteral).getValue() = "source"
|
||||||
|
or
|
||||||
|
// indirect_source(n) gives the dataflow node representing the indirect node after n dereferences.
|
||||||
|
exists(int n, string s |
|
||||||
|
n = s.regexpCapture("indirect_source\\((\\d)\\)", 1).toInt() and
|
||||||
|
source.asIndirectExpr(n).(StringLiteral).getValue() = s
|
||||||
|
)
|
||||||
|
or
|
||||||
|
source.asParameter().getName().matches("source%")
|
||||||
|
or
|
||||||
|
source.(DataFlow::DefinitionByReferenceNode).getParameter().getName().matches("ref_source%")
|
||||||
|
or
|
||||||
|
exists(source.asUninitialized())
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
exists(FunctionCall call, Expr e | e = call.getAnArgument() |
|
||||||
|
call.getTarget().getName() = "sink" and
|
||||||
|
sink.asExpr() = e
|
||||||
|
or
|
||||||
|
call.getTarget().getName() = "indirect_sink" and
|
||||||
|
sink.asIndirectExpr() = e
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node barrier) {
|
||||||
|
exists(Expr barrierExpr | barrierExpr in [barrier.asExpr(), barrier.asIndirectExpr()] |
|
||||||
|
barrierExpr.(VariableAccess).getTarget().hasName("barrier")
|
||||||
|
)
|
||||||
|
or
|
||||||
|
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
|
||||||
|
or
|
||||||
|
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getAnIndirectBarrierNode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module IRFlow = DataFlow::Global<IRTestAllocationConfig>;
|
||||||
|
}
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
uniqueEnclosingCallable
|
uniqueEnclosingCallable
|
||||||
|
| test.cpp:864:44:864:58 | {...} | Node should have one enclosing callable but has 0. |
|
||||||
|
| test.cpp:864:47:864:54 | call to source | Node should have one enclosing callable but has 0. |
|
||||||
|
| test.cpp:872:46:872:51 | call to source | Node should have one enclosing callable but has 0. |
|
||||||
|
| test.cpp:872:53:872:56 | 1 | Node should have one enclosing callable but has 0. |
|
||||||
uniqueCallEnclosingCallable
|
uniqueCallEnclosingCallable
|
||||||
|
| test.cpp:864:47:864:54 | call to source | Call should have one enclosing callable but has 0. |
|
||||||
|
| test.cpp:872:46:872:51 | call to source | Call should have one enclosing callable but has 0. |
|
||||||
uniqueType
|
uniqueType
|
||||||
uniqueNodeLocation
|
uniqueNodeLocation
|
||||||
missingLocation
|
missingLocation
|
||||||
@@ -23,6 +29,8 @@ argHasPostUpdate
|
|||||||
| lambdas.cpp:38:2:38:2 | d | ArgumentNode is missing PostUpdateNode. |
|
| lambdas.cpp:38:2:38:2 | d | ArgumentNode is missing PostUpdateNode. |
|
||||||
| lambdas.cpp:45:2:45:2 | e | ArgumentNode is missing PostUpdateNode. |
|
| lambdas.cpp:45:2:45:2 | e | ArgumentNode is missing PostUpdateNode. |
|
||||||
| test.cpp:67:29:67:35 | source1 | ArgumentNode is missing PostUpdateNode. |
|
| test.cpp:67:29:67:35 | source1 | ArgumentNode is missing PostUpdateNode. |
|
||||||
|
| test.cpp:813:19:813:35 | * ... | ArgumentNode is missing PostUpdateNode. |
|
||||||
|
| test.cpp:848:23:848:25 | rpx | ArgumentNode is missing PostUpdateNode. |
|
||||||
postWithInFlow
|
postWithInFlow
|
||||||
| BarrierGuard.cpp:49:6:49:6 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
| BarrierGuard.cpp:49:6:49:6 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
| BarrierGuard.cpp:60:7:60:7 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
| BarrierGuard.cpp:60:7:60:7 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
@@ -136,6 +144,9 @@ postWithInFlow
|
|||||||
| test.cpp:728:3:728:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
| test.cpp:728:3:728:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
| test.cpp:728:4:728:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
|
| test.cpp:728:4:728:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
| test.cpp:734:41:734:41 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
|
| test.cpp:734:41:734:41 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
|
| test.cpp:808:5:808:21 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
|
| test.cpp:808:6:808:21 | global_indirect1 [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
|
| test.cpp:832:5:832:17 | global_direct [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
viableImplInCallContextTooLarge
|
viableImplInCallContextTooLarge
|
||||||
uniqueParameterNodeAtPosition
|
uniqueParameterNodeAtPosition
|
||||||
uniqueParameterNodePosition
|
uniqueParameterNodePosition
|
||||||
|
|||||||
@@ -0,0 +1,306 @@
|
|||||||
|
WARNING: Module DataFlow has been deprecated and may be removed in future (test-source-sink.ql:3,25-42)
|
||||||
|
WARNING: Module DataFlow has been deprecated and may be removed in future (test-source-sink.ql:3,57-74)
|
||||||
|
astFlow
|
||||||
|
| BarrierGuard.cpp:5:19:5:24 | source | BarrierGuard.cpp:9:10:9:15 | source |
|
||||||
|
| BarrierGuard.cpp:13:17:13:22 | source | BarrierGuard.cpp:15:10:15:15 | source |
|
||||||
|
| BarrierGuard.cpp:21:17:21:22 | source | BarrierGuard.cpp:25:10:25:15 | source |
|
||||||
|
| BarrierGuard.cpp:29:16:29:21 | source | BarrierGuard.cpp:31:10:31:15 | source |
|
||||||
|
| BarrierGuard.cpp:29:16:29:21 | source | BarrierGuard.cpp:33:10:33:15 | source |
|
||||||
|
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:51:13:51:13 | x |
|
||||||
|
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:53:13:53:13 | x |
|
||||||
|
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:55:13:55:13 | x |
|
||||||
|
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:62:14:62:14 | x |
|
||||||
|
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:64:14:64:14 | x |
|
||||||
|
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:66:14:66:14 | x |
|
||||||
|
| acrossLinkTargets.cpp:19:27:19:32 | call to source | acrossLinkTargets.cpp:12:8:12:8 | x |
|
||||||
|
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:18:8:18:19 | sourceArray1 |
|
||||||
|
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:22:8:22:20 | & ... |
|
||||||
|
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:23:17:23:29 | & ... |
|
||||||
|
| clang.cpp:29:27:29:32 | call to source | clang.cpp:30:27:30:28 | m1 |
|
||||||
|
| clang.cpp:29:27:29:32 | call to source | clang.cpp:31:27:31:34 | call to getFirst |
|
||||||
|
| clang.cpp:35:32:35:37 | call to source | clang.cpp:38:10:38:11 | m2 |
|
||||||
|
| clang.cpp:44:35:44:40 | call to source | clang.cpp:46:17:46:18 | m2 |
|
||||||
|
| clang.cpp:51:19:51:24 | call to source | clang.cpp:52:8:52:17 | stackArray |
|
||||||
|
| clang.cpp:51:19:51:24 | call to source | clang.cpp:53:17:53:26 | stackArray |
|
||||||
|
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:35:16:35:25 | call to notSource1 |
|
||||||
|
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:43:15:43:24 | call to notSource1 |
|
||||||
|
| dispatch.cpp:10:37:10:42 | call to source | dispatch.cpp:36:16:36:25 | call to notSource2 |
|
||||||
|
| dispatch.cpp:10:37:10:42 | call to source | dispatch.cpp:44:15:44:24 | call to notSource2 |
|
||||||
|
| dispatch.cpp:37:19:37:24 | call to source | dispatch.cpp:11:38:11:38 | x |
|
||||||
|
| dispatch.cpp:45:18:45:23 | call to source | dispatch.cpp:11:38:11:38 | x |
|
||||||
|
| globals.cpp:5:17:5:22 | call to source | globals.cpp:6:10:6:14 | local |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:14:3:14:6 | t |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:18:8:18:8 | call to operator() |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:21:3:21:6 | t |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:29:3:29:6 | t |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:35:8:35:8 | a |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:41:8:41:8 | a |
|
||||||
|
| lambdas.cpp:43:7:43:12 | call to source | lambdas.cpp:46:7:46:7 | w |
|
||||||
|
| ref.cpp:29:11:29:16 | call to source | ref.cpp:62:10:62:11 | x3 |
|
||||||
|
| ref.cpp:53:9:53:10 | x1 | ref.cpp:56:10:56:11 | x1 |
|
||||||
|
| ref.cpp:53:13:53:14 | x2 | ref.cpp:59:10:59:11 | x2 |
|
||||||
|
| ref.cpp:53:17:53:18 | x3 | ref.cpp:62:10:62:11 | x3 |
|
||||||
|
| ref.cpp:53:21:53:22 | x4 | ref.cpp:65:10:65:11 | x4 |
|
||||||
|
| ref.cpp:55:23:55:28 | call to source | ref.cpp:56:10:56:11 | x1 |
|
||||||
|
| ref.cpp:94:15:94:20 | call to source | ref.cpp:129:13:129:15 | val |
|
||||||
|
| ref.cpp:109:15:109:20 | call to source | ref.cpp:132:13:132:15 | val |
|
||||||
|
| ref.cpp:122:23:122:28 | call to source | ref.cpp:123:13:123:15 | val |
|
||||||
|
| ref.cpp:125:19:125:24 | call to source | ref.cpp:126:13:126:15 | val |
|
||||||
|
| self-Iterator.cpp:19:23:19:28 | call to source | self-Iterator.cpp:20:10:20:10 | x |
|
||||||
|
| test.cpp:6:12:6:17 | 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 | test.cpp:15:8:15:9 | t2 |
|
||||||
|
| test.cpp:6:12:6:17 | call to source | test.cpp:26:8:26:9 | t1 |
|
||||||
|
| test.cpp:35:10:35:15 | call to source | test.cpp:30:8:30:8 | t |
|
||||||
|
| test.cpp:36:13:36:18 | call to source | test.cpp:31:8:31:8 | c |
|
||||||
|
| test.cpp:50:14:50:19 | call to source | test.cpp:58:10:58:10 | t |
|
||||||
|
| test.cpp:66:30:66:36 | source1 | test.cpp:71:8:71:9 | x4 |
|
||||||
|
| test.cpp:75:7:75:8 | u1 | test.cpp:76:8:76:9 | u1 |
|
||||||
|
| test.cpp:83:7:83:8 | u2 | test.cpp:84:8:84:18 | ... ? ... : ... |
|
||||||
|
| test.cpp:83:7:83:8 | u2 | test.cpp:86:8:86:9 | i1 |
|
||||||
|
| test.cpp:89:28:89:34 | source1 | test.cpp:90:8:90:14 | source1 |
|
||||||
|
| test.cpp:100:13:100:18 | call to source | test.cpp:103:10:103:12 | ref |
|
||||||
|
| test.cpp:138:27:138:32 | call to source | test.cpp:140:8:140:8 | y |
|
||||||
|
| test.cpp:151:33:151:38 | call to source | test.cpp:144:8:144:8 | s |
|
||||||
|
| test.cpp:151:33:151:38 | call to source | test.cpp:152:8:152:8 | y |
|
||||||
|
| test.cpp:164:34:164:39 | call to source | test.cpp:157:8:157:8 | x |
|
||||||
|
| test.cpp:164:34:164:39 | call to source | test.cpp:165:8:165:8 | y |
|
||||||
|
| test.cpp:171:11:171:16 | call to source | test.cpp:178:8:178:8 | y |
|
||||||
|
| test.cpp:245:14:245:19 | call to source | test.cpp:260:12:260:12 | x |
|
||||||
|
| test.cpp:265:22:265:27 | call to source | test.cpp:266:12:266:12 | x |
|
||||||
|
| test.cpp:305:17:305:22 | call to source | test.cpp:289:14:289:14 | x |
|
||||||
|
| test.cpp:314:4:314:9 | call to source | test.cpp:318:7:318:7 | x |
|
||||||
|
| test.cpp:347:17:347:22 | call to source | test.cpp:349:10:349:18 | globalVar |
|
||||||
|
| test.cpp:359:13:359:18 | call to source | test.cpp:365:10:365:14 | field |
|
||||||
|
| test.cpp:373:13:373:18 | call to source | test.cpp:369:10:369:14 | field |
|
||||||
|
| test.cpp:373:13:373:18 | call to source | test.cpp:375:10:375:14 | field |
|
||||||
|
| test.cpp:382:48:382:54 | source1 | test.cpp:385:8:385:10 | tmp |
|
||||||
|
| test.cpp:388:53:388:59 | source1 | test.cpp:392:8:392:10 | tmp |
|
||||||
|
| test.cpp:388:53:388:59 | source1 | test.cpp:394:10:394:12 | tmp |
|
||||||
|
| test.cpp:399:7:399:9 | tmp | test.cpp:401:8:401:10 | tmp |
|
||||||
|
| test.cpp:405:7:405:9 | tmp | test.cpp:408:8:408:10 | tmp |
|
||||||
|
| test.cpp:416:7:416:11 | local | test.cpp:418:8:418:12 | local |
|
||||||
|
| test.cpp:417:16:417:20 | ref arg local | test.cpp:418:8:418:12 | local |
|
||||||
|
| test.cpp:422:7:422:11 | local | test.cpp:424:8:424:12 | local |
|
||||||
|
| test.cpp:423:20:423:25 | ref arg & ... | test.cpp:424:8:424:12 | local |
|
||||||
|
| test.cpp:433:7:433:11 | local | test.cpp:435:8:435:12 | local |
|
||||||
|
| test.cpp:433:7:433:11 | local | test.cpp:436:8:436:13 | * ... |
|
||||||
|
| test.cpp:434:20:434:24 | ref arg local | test.cpp:435:8:435:12 | local |
|
||||||
|
| test.cpp:434:20:434:24 | ref arg local | test.cpp:436:8:436:13 | * ... |
|
||||||
|
| test.cpp:440:7:440:11 | local | test.cpp:442:8:442:12 | local |
|
||||||
|
| test.cpp:441:18:441:23 | ref arg & ... | test.cpp:442:8:442:12 | local |
|
||||||
|
| test.cpp:448:7:448:11 | local | test.cpp:450:8:450:12 | local |
|
||||||
|
| test.cpp:448:7:448:11 | local | test.cpp:451:8:451:13 | * ... |
|
||||||
|
| test.cpp:449:18:449:22 | ref arg local | test.cpp:450:8:450:12 | local |
|
||||||
|
| test.cpp:449:18:449:22 | ref arg local | test.cpp:451:8:451:13 | * ... |
|
||||||
|
| test.cpp:456:26:456:32 | source1 | test.cpp:457:9:457:22 | (statement expression) |
|
||||||
|
| test.cpp:456:26:456:32 | source1 | test.cpp:468:8:468:12 | local |
|
||||||
|
| test.cpp:472:8:472:13 | call to source | test.cpp:478:8:478:8 | x |
|
||||||
|
| test.cpp:506:8:506:13 | call to source | test.cpp:513:8:513:8 | x |
|
||||||
|
| test.cpp:517:7:517:16 | stackArray | test.cpp:521:8:521:20 | access to array |
|
||||||
|
| test.cpp:519:19:519:24 | call to source | test.cpp:521:8:521:20 | access to array |
|
||||||
|
| test.cpp:551:9:551:9 | y | test.cpp:541:10:541:10 | y |
|
||||||
|
| test.cpp:583:11:583:16 | call to source | test.cpp:590:8:590:8 | x |
|
||||||
|
| test.cpp:628:20:628:25 | ref arg buffer | test.cpp:629:17:629:22 | buffer |
|
||||||
|
| test.cpp:633:18:633:23 | call to source | test.cpp:634:8:634:8 | x |
|
||||||
|
| test.cpp:702:38:702:43 | source | test.cpp:695:8:695:10 | buf |
|
||||||
|
| test.cpp:726:11:726:16 | call to source | test.cpp:735:8:735:8 | x |
|
||||||
|
| test.cpp:733:7:733:7 | x | test.cpp:735:8:735:8 | x |
|
||||||
|
| test.cpp:749:27:749:32 | call to source | test.cpp:740:10:740:10 | x |
|
||||||
|
| test.cpp:751:27:751:32 | call to source | test.cpp:740:10:740:10 | x |
|
||||||
|
| test.cpp:753:32:753:37 | call to source | test.cpp:740:10:740:10 | x |
|
||||||
|
| test.cpp:755:32:755:37 | call to source | test.cpp:740:10:740:10 | x |
|
||||||
|
| test.cpp:769:27:769:32 | call to source | test.cpp:760:10:760:10 | x |
|
||||||
|
| test.cpp:771:27:771:32 | call to source | test.cpp:760:10:760:10 | x |
|
||||||
|
| test.cpp:773:32:773:37 | call to source | test.cpp:760:10:760:10 | x |
|
||||||
|
| test.cpp:775:32:775:37 | call to source | test.cpp:760:10:760:10 | x |
|
||||||
|
| test.cpp:788:31:788:36 | call to source | test.cpp:782:12:782:12 | x |
|
||||||
|
| test.cpp:790:31:790:36 | call to source | test.cpp:782:12:782:12 | x |
|
||||||
|
| test.cpp:797:22:797:28 | ref arg content | test.cpp:798:19:798:25 | content |
|
||||||
|
| test.cpp:842:11:842:16 | call to source | test.cpp:844:8:844:8 | y |
|
||||||
|
| test.cpp:846:13:846:27 | call to indirect_source | test.cpp:848:23:848:25 | rpx |
|
||||||
|
| test.cpp:860:54:860:59 | call to source | test.cpp:861:10:861:37 | static_local_pointer_dynamic |
|
||||||
|
| true_upon_entry.cpp:17:11:17:16 | call to source | true_upon_entry.cpp:21:8:21:8 | x |
|
||||||
|
| true_upon_entry.cpp:27:9:27:14 | call to source | true_upon_entry.cpp:29:8:29:8 | x |
|
||||||
|
| true_upon_entry.cpp:33:11:33:16 | call to source | true_upon_entry.cpp:39:8:39:8 | x |
|
||||||
|
| true_upon_entry.cpp:43:11:43:16 | call to source | true_upon_entry.cpp:49:8:49:8 | x |
|
||||||
|
| true_upon_entry.cpp:54:11:54:16 | call to source | true_upon_entry.cpp:57:8:57:8 | x |
|
||||||
|
| true_upon_entry.cpp:70:11:70:16 | call to source | true_upon_entry.cpp:78:8:78:8 | x |
|
||||||
|
| true_upon_entry.cpp:83:11:83:16 | call to source | true_upon_entry.cpp:86:8:86:8 | x |
|
||||||
|
irFlow
|
||||||
|
| BarrierGuard.cpp:5:19:5:24 | source | BarrierGuard.cpp:9:10:9:15 | source |
|
||||||
|
| BarrierGuard.cpp:13:17:13:22 | source | BarrierGuard.cpp:15:10:15:15 | source |
|
||||||
|
| BarrierGuard.cpp:21:17:21:22 | source | BarrierGuard.cpp:25:10:25:15 | source |
|
||||||
|
| BarrierGuard.cpp:29:16:29:21 | source | BarrierGuard.cpp:31:10:31:15 | source |
|
||||||
|
| BarrierGuard.cpp:29:16:29:21 | source | BarrierGuard.cpp:33:10:33:15 | source |
|
||||||
|
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:53:13:53:13 | x |
|
||||||
|
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:55:13:55:13 | x |
|
||||||
|
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:64:14:64:14 | x |
|
||||||
|
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:66:14:66:14 | x |
|
||||||
|
| acrossLinkTargets.cpp:19:27:19:32 | call to source | acrossLinkTargets.cpp:12:8:12:8 | x |
|
||||||
|
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:18:8:18:19 | sourceArray1 |
|
||||||
|
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:23:17:23:29 | & ... indirection |
|
||||||
|
| clang.cpp:29:27:29:32 | call to source | clang.cpp:30:27:30:28 | m1 |
|
||||||
|
| clang.cpp:29:27:29:32 | call to source | clang.cpp:31:27:31:34 | call to getFirst |
|
||||||
|
| clang.cpp:35:32:35:37 | call to source | clang.cpp:38:10:38:11 | m2 |
|
||||||
|
| clang.cpp:40:42:40:47 | call to source | clang.cpp:42:18:42:19 | m2 |
|
||||||
|
| clang.cpp:44:35:44:40 | call to source | clang.cpp:46:17:46:18 | m2 |
|
||||||
|
| clang.cpp:50:7:50:16 | definition of stackArray | clang.cpp:52:8:52:17 | stackArray |
|
||||||
|
| clang.cpp:50:25:50:30 | call to source | clang.cpp:53:17:53:26 | stackArray indirection |
|
||||||
|
| clang.cpp:50:35:50:40 | call to source | clang.cpp:53:17:53:26 | stackArray indirection |
|
||||||
|
| clang.cpp:51:19:51:24 | call to source | clang.cpp:53:17:53:26 | stackArray indirection |
|
||||||
|
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:35:16:35:25 | call to notSource1 |
|
||||||
|
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:43:15:43:24 | call to notSource1 |
|
||||||
|
| dispatch.cpp:10:37:10:42 | call to source | dispatch.cpp:36:16:36:25 | call to notSource2 |
|
||||||
|
| dispatch.cpp:10:37:10:42 | call to source | dispatch.cpp:44:15:44:24 | call to notSource2 |
|
||||||
|
| dispatch.cpp:16:37:16:42 | call to source | dispatch.cpp:32:16:32:24 | call to isSource2 |
|
||||||
|
| dispatch.cpp:16:37:16:42 | call to source | dispatch.cpp:40:15:40:23 | call to isSource2 |
|
||||||
|
| dispatch.cpp:22:37:22:42 | call to source | dispatch.cpp:31:16:31:24 | call to isSource1 |
|
||||||
|
| dispatch.cpp:22:37:22:42 | call to source | dispatch.cpp:39:15:39:23 | call to isSource1 |
|
||||||
|
| dispatch.cpp:22:37:22:42 | call to source | 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:33:18:33:23 | call to source | dispatch.cpp:23:38:23:38 | x |
|
||||||
|
| dispatch.cpp:37:19:37:24 | call to source | dispatch.cpp:11:38:11:38 | x |
|
||||||
|
| dispatch.cpp:41:17:41:22 | call to source | dispatch.cpp:23:38:23:38 | x |
|
||||||
|
| dispatch.cpp:45:18:45:23 | call to source | dispatch.cpp:11:38:11:38 | x |
|
||||||
|
| dispatch.cpp:69:15:69:20 | call to source | dispatch.cpp:23:38:23:38 | x |
|
||||||
|
| dispatch.cpp:73:14:73:19 | call to source | dispatch.cpp:23:38:23:38 | x |
|
||||||
|
| dispatch.cpp:81:13:81:18 | call to source | dispatch.cpp:23:38:23:38 | 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 | dispatch.cpp:96:8:96:8 | x |
|
||||||
|
| flowOut.cpp:5:16:5:21 | call to source | flowOut.cpp:19:9:19:9 | x |
|
||||||
|
| globals.cpp:5:17:5:22 | call to source | globals.cpp:6:10:6:14 | local |
|
||||||
|
| globals.cpp:13:23:13:28 | call to source | globals.cpp:12:10:12:24 | flowTestGlobal1 |
|
||||||
|
| globals.cpp:23:23:23:28 | call to source | globals.cpp:19:10:19:24 | flowTestGlobal2 |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:14:8:14:8 | t |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:18:8:18:8 | call to operator() |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:21:8:21:8 | t |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:29:8:29:8 | t |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:35:8:35:8 | a |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:41:8:41:8 | a |
|
||||||
|
| lambdas.cpp:43:7:43:12 | call to source | lambdas.cpp:46:7:46:7 | w |
|
||||||
|
| ref.cpp:29:11:29:16 | call to source | ref.cpp:62:10:62:11 | x3 |
|
||||||
|
| ref.cpp:53:9:53:10 | definition of x1 | ref.cpp:56:10:56:11 | x1 |
|
||||||
|
| ref.cpp:53:13:53:14 | definition of x2 | ref.cpp:59:10:59:11 | x2 |
|
||||||
|
| ref.cpp:53:17:53:18 | definition of x3 | ref.cpp:62:10:62:11 | x3 |
|
||||||
|
| ref.cpp:53:21:53:22 | definition of x4 | ref.cpp:65:10:65:11 | x4 |
|
||||||
|
| ref.cpp:55:23:55:28 | call to source | ref.cpp:56:10:56:11 | x1 |
|
||||||
|
| ref.cpp:94:15:94:20 | call to source | ref.cpp:129:13:129:15 | val |
|
||||||
|
| ref.cpp:109:15:109:20 | call to source | ref.cpp:132:13:132:15 | val |
|
||||||
|
| ref.cpp:122:23:122:28 | call to source | ref.cpp:123:13:123:15 | val |
|
||||||
|
| ref.cpp:125:19:125:24 | call to source | ref.cpp:126:13:126:15 | val |
|
||||||
|
| self-Iterator.cpp:19:23:19:30 | call to source | self-Iterator.cpp:20:10:20:10 | x |
|
||||||
|
| test.cpp:6:12:6:17 | 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 | test.cpp:15:8:15:9 | t2 |
|
||||||
|
| test.cpp:6:12:6:17 | call to source | test.cpp:26:8:26:9 | t1 |
|
||||||
|
| test.cpp:35:10:35:15 | call to source | test.cpp:30:8:30:8 | t |
|
||||||
|
| test.cpp:36:13:36:18 | call to source | test.cpp:31:8:31:8 | c |
|
||||||
|
| test.cpp:50:14:50:19 | call to source | test.cpp:58:10:58:10 | t |
|
||||||
|
| test.cpp:66:30:66:36 | source1 | test.cpp:71:8:71:9 | x4 |
|
||||||
|
| test.cpp:75:7:75:8 | definition of u1 | test.cpp:76:8:76:9 | u1 |
|
||||||
|
| test.cpp:83:7:83:8 | definition of u2 | test.cpp:84:8:84:18 | ... ? ... : ... |
|
||||||
|
| test.cpp:83:7:83:8 | definition of u2 | test.cpp:86:8:86:9 | i1 |
|
||||||
|
| test.cpp:89:28:89:34 | source1 indirection | test.cpp:90:8:90:14 | source1 |
|
||||||
|
| test.cpp:100:13:100:18 | call to source | test.cpp:103:10:103:12 | ref |
|
||||||
|
| test.cpp:138:27:138:32 | call to source | test.cpp:140:8:140:8 | y |
|
||||||
|
| test.cpp:151:33:151:38 | call to source | test.cpp:144:8:144:8 | s |
|
||||||
|
| test.cpp:151:33:151:38 | call to source | test.cpp:152:8:152:8 | y |
|
||||||
|
| test.cpp:164:34:164:39 | call to source | test.cpp:157:8:157:8 | x |
|
||||||
|
| test.cpp:164:34:164:39 | call to source | test.cpp:165:8:165:8 | y |
|
||||||
|
| test.cpp:171:11:171:16 | call to source | test.cpp:178:8:178:8 | y |
|
||||||
|
| test.cpp:245:14:245:19 | call to source | test.cpp:260:12:260:12 | x |
|
||||||
|
| test.cpp:265:22:265:27 | call to source | test.cpp:266:12:266:12 | x |
|
||||||
|
| test.cpp:305:17:305:22 | call to source | test.cpp:289:14:289:14 | x |
|
||||||
|
| test.cpp:314:4:314:9 | call to source | test.cpp:318:7:318:7 | x |
|
||||||
|
| test.cpp:333:17:333:22 | call to source | test.cpp:337:10:337:18 | globalVar |
|
||||||
|
| test.cpp:333:17:333:22 | call to source | test.cpp:339:10:339:18 | globalVar |
|
||||||
|
| test.cpp:333:17:333:22 | call to source | test.cpp:343:10:343:18 | globalVar |
|
||||||
|
| test.cpp:333:17:333:22 | call to source | test.cpp:349:10:349:18 | globalVar |
|
||||||
|
| test.cpp:347:17:347:22 | call to source | test.cpp:337:10:337:18 | globalVar |
|
||||||
|
| test.cpp:347:17:347:22 | call to source | test.cpp:339:10:339:18 | globalVar |
|
||||||
|
| test.cpp:347:17:347:22 | call to source | test.cpp:343:10:343:18 | globalVar |
|
||||||
|
| test.cpp:347:17:347:22 | call to source | test.cpp:349:10:349:18 | globalVar |
|
||||||
|
| test.cpp:359:13:359:18 | call to source | test.cpp:365:10:365:14 | field |
|
||||||
|
| test.cpp:373:13:373:18 | call to source | test.cpp:369:10:369:14 | field |
|
||||||
|
| test.cpp:373:13:373:18 | call to source | test.cpp:375:10:375:14 | field |
|
||||||
|
| test.cpp:382:48:382:54 | source1 | test.cpp:385:8:385:10 | tmp |
|
||||||
|
| test.cpp:388:53:388:59 | source1 | test.cpp:392:8:392:10 | tmp |
|
||||||
|
| test.cpp:388:53:388:59 | source1 | test.cpp:394:10:394:12 | tmp |
|
||||||
|
| test.cpp:399:7:399:9 | definition of tmp | test.cpp:401:8:401:10 | tmp |
|
||||||
|
| test.cpp:405:7:405:9 | definition of tmp | test.cpp:408:8:408:10 | tmp |
|
||||||
|
| test.cpp:416:7:416:11 | definition of local | test.cpp:418:8:418:12 | local |
|
||||||
|
| test.cpp:417:16:417:20 | intRefSource output argument | test.cpp:418:8:418:12 | local |
|
||||||
|
| test.cpp:422:7:422:11 | definition of local | test.cpp:424:8:424:12 | local |
|
||||||
|
| test.cpp:423:20:423:25 | intPointerSource output argument | test.cpp:424:8:424:12 | local |
|
||||||
|
| test.cpp:433:7:433:11 | definition of local | test.cpp:435:8:435:12 | local |
|
||||||
|
| test.cpp:434:20:434:24 | intPointerSource output argument | test.cpp:436:8:436:13 | * ... |
|
||||||
|
| test.cpp:440:7:440:11 | definition of local | test.cpp:442:8:442:12 | local |
|
||||||
|
| test.cpp:441:18:441:23 | intArraySource output argument | test.cpp:442:8:442:12 | local |
|
||||||
|
| test.cpp:448:7:448:11 | definition of local | test.cpp:450:8:450:12 | local |
|
||||||
|
| test.cpp:449:18:449:22 | intArraySource output argument | test.cpp:451:8:451:13 | * ... |
|
||||||
|
| test.cpp:456:26:456:32 | source1 | test.cpp:457:9:457:22 | (statement expression) |
|
||||||
|
| test.cpp:456:26:456:32 | source1 | test.cpp:468:8:468:12 | local |
|
||||||
|
| test.cpp:472:8:472:13 | call to source | test.cpp:478:8:478:8 | x |
|
||||||
|
| test.cpp:506:8:506:13 | call to source | test.cpp:513:8:513:8 | x |
|
||||||
|
| test.cpp:519:19:519:24 | call to source | test.cpp:521:8:521:20 | access to array |
|
||||||
|
| test.cpp:531:29:531:34 | call to source | test.cpp:532:8:532:9 | * ... |
|
||||||
|
| test.cpp:547:9:547:9 | definition of x | test.cpp:536:10:536:11 | * ... |
|
||||||
|
| test.cpp:551:9:551:9 | definition of y | test.cpp:541:10:541:10 | y |
|
||||||
|
| test.cpp:562:17:562:31 | call to indirect_source indirection | test.cpp:566:10:566:19 | * ... |
|
||||||
|
| test.cpp:562:17:562:31 | call to indirect_source indirection | test.cpp:568:10:568:19 | * ... |
|
||||||
|
| test.cpp:562:17:562:31 | call to indirect_source indirection | test.cpp:572:10:572:19 | * ... |
|
||||||
|
| test.cpp:562:17:562:31 | call to indirect_source indirection | test.cpp:578:10:578:19 | * ... |
|
||||||
|
| test.cpp:576:17:576:31 | call to indirect_source indirection | test.cpp:566:10:566:19 | * ... |
|
||||||
|
| test.cpp:576:17:576:31 | call to indirect_source indirection | test.cpp:568:10:568:19 | * ... |
|
||||||
|
| test.cpp:576:17:576:31 | call to indirect_source indirection | test.cpp:572:10:572:19 | * ... |
|
||||||
|
| test.cpp:576:17:576:31 | call to indirect_source indirection | test.cpp:578:10:578:19 | * ... |
|
||||||
|
| test.cpp:594:12:594:26 | call to indirect_source indirection | test.cpp:597:8:597:13 | * ... |
|
||||||
|
| test.cpp:601:20:601:20 | intPointerSource output argument | test.cpp:603:8:603:9 | * ... |
|
||||||
|
| test.cpp:607:20:607:20 | intPointerSource output argument | test.cpp:609:8:609:9 | * ... |
|
||||||
|
| test.cpp:614:20:614:20 | intPointerSource output argument | test.cpp:616:8:616:17 | * ... |
|
||||||
|
| test.cpp:628:20:628:25 | intPointerSource output argument | test.cpp:629:17:629:22 | buffer indirection |
|
||||||
|
| test.cpp:633:18:633:23 | call to source | test.cpp:634:8:634:8 | x |
|
||||||
|
| test.cpp:646:7:646:12 | call to source | test.cpp:645:8:645:8 | x |
|
||||||
|
| test.cpp:660:7:660:12 | call to source | test.cpp:658:8:658:8 | x |
|
||||||
|
| test.cpp:664:18:664:23 | call to source | test.cpp:666:8:666:16 | * ... |
|
||||||
|
| test.cpp:681:7:681:12 | call to source | test.cpp:679:8:679:16 | * ... |
|
||||||
|
| test.cpp:733:7:733:7 | definition of x | test.cpp:735:8:735:8 | x |
|
||||||
|
| test.cpp:751:27:751:32 | call to source | test.cpp:740:10:740:10 | x |
|
||||||
|
| test.cpp:753:32:753:37 | call to source | test.cpp:740:10:740:10 | x |
|
||||||
|
| test.cpp:755:32:755:37 | call to source | test.cpp:740:10:740:10 | x |
|
||||||
|
| test.cpp:771:27:771:32 | call to source | test.cpp:760:10:760:10 | x |
|
||||||
|
| test.cpp:773:32:773:37 | call to source | test.cpp:760:10:760:10 | x |
|
||||||
|
| test.cpp:775:32:775:37 | call to source | test.cpp:760:10:760:10 | x |
|
||||||
|
| test.cpp:788:31:788:36 | call to source | test.cpp:782:12:782:12 | x |
|
||||||
|
| test.cpp:790:31:790:36 | call to source | test.cpp:782:12:782:12 | x |
|
||||||
|
| test.cpp:797:22:797:28 | intPointerSource output argument | test.cpp:798:19:798:25 | content indirection |
|
||||||
|
| test.cpp:808:25:808:39 | call to indirect_source indirection | test.cpp:813:19:813:35 | * ... indirection |
|
||||||
|
| test.cpp:818:26:818:31 | call to source | test.cpp:823:10:823:27 | * ... |
|
||||||
|
| test.cpp:832:21:832:26 | call to source | test.cpp:836:10:836:22 | global_direct |
|
||||||
|
| test.cpp:842:11:842:16 | call to source | test.cpp:844:8:844:8 | y |
|
||||||
|
| test.cpp:846:13:846:27 | call to indirect_source indirection | test.cpp:848:17:848:25 | rpx indirection |
|
||||||
|
| test.cpp:853:55:853:62 | call to source | test.cpp:854:10:854:36 | * ... |
|
||||||
|
| test.cpp:860:54:860:59 | call to source | test.cpp:861:10:861:37 | static_local_pointer_dynamic |
|
||||||
|
| test.cpp:872:46:872:51 | call to source | test.cpp:875:10:875:31 | global_pointer_dynamic |
|
||||||
|
| test.cpp:880:64:880:83 | indirect_source(1) indirection | test.cpp:883:10:883:45 | static_local_array_static_indirect_1 |
|
||||||
|
| test.cpp:881:64:881:83 | indirect_source(2) indirection | test.cpp:886:19:886:54 | static_local_array_static_indirect_2 indirection |
|
||||||
|
| test.cpp:890:54:890:61 | source | test.cpp:893:10:893:36 | static_local_pointer_static |
|
||||||
|
| test.cpp:891:65:891:84 | indirect_source(1) indirection | test.cpp:895:19:895:56 | static_local_pointer_static_indirect_1 indirection |
|
||||||
|
| test.cpp:901:56:901:75 | indirect_source(1) indirection | test.cpp:907:10:907:39 | global_array_static_indirect_1 |
|
||||||
|
| test.cpp:902:56:902:75 | indirect_source(2) indirection | test.cpp:911:19:911:48 | global_array_static_indirect_2 indirection |
|
||||||
|
| test.cpp:914:46:914:53 | source | test.cpp:919:10:919:30 | global_pointer_static |
|
||||||
|
| test.cpp:915:57:915:76 | indirect_source(1) indirection | test.cpp:921:19:921:50 | global_pointer_static_indirect_1 indirection |
|
||||||
|
| true_upon_entry.cpp:9:11:9:16 | call to source | true_upon_entry.cpp:13:8:13:8 | x |
|
||||||
|
| true_upon_entry.cpp:17:11:17:16 | call to source | true_upon_entry.cpp:21:8:21:8 | x |
|
||||||
|
| true_upon_entry.cpp:27:9:27:14 | call to source | true_upon_entry.cpp:29:8:29:8 | x |
|
||||||
|
| true_upon_entry.cpp:33:11:33:16 | call to source | true_upon_entry.cpp:39:8:39:8 | x |
|
||||||
|
| true_upon_entry.cpp:43:11:43:16 | call to source | true_upon_entry.cpp:49:8:49:8 | x |
|
||||||
|
| true_upon_entry.cpp:54:11:54:16 | call to source | true_upon_entry.cpp:57:8:57:8 | x |
|
||||||
|
| true_upon_entry.cpp:62:11:62:16 | call to source | true_upon_entry.cpp:66:8:66:8 | x |
|
||||||
|
| true_upon_entry.cpp:70:11:70:16 | call to source | true_upon_entry.cpp:78:8:78:8 | x |
|
||||||
|
| true_upon_entry.cpp:83:11:83:16 | call to source | true_upon_entry.cpp:86:8:86:8 | x |
|
||||||
|
| true_upon_entry.cpp:98:11:98:16 | call to source | true_upon_entry.cpp:105:8:105:8 | x |
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import TestBase
|
||||||
|
|
||||||
|
query predicate astFlow(AstTest::DataFlow::Node source, AstTest::DataFlow::Node sink) {
|
||||||
|
AstTest::AstFlow::flow(source, sink)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate irFlow(IRTest::DataFlow::Node source, IRTest::DataFlow::Node sink) {
|
||||||
|
IRTest::IRFlow::flow(source, sink)
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
int source();
|
int source();
|
||||||
void sink(int); void sink(const int *); void sink(int **); void indirect_sink(...);
|
void sink(...); void indirect_sink(...);
|
||||||
|
|
||||||
void intraprocedural_with_local_flow() {
|
void intraprocedural_with_local_flow() {
|
||||||
int t2;
|
int t2;
|
||||||
@@ -796,4 +796,130 @@ void test() {
|
|||||||
MyStruct a;
|
MyStruct a;
|
||||||
intPointerSource(a.content, a.content);
|
intPointerSource(a.content, a.content);
|
||||||
indirect_sink(a.content); // $ ast ir
|
indirect_sink(a.content); // $ ast ir
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MoreGlobalTests {
|
||||||
|
int **global_indirect1;
|
||||||
|
int **global_indirect2;
|
||||||
|
int **global_direct;
|
||||||
|
|
||||||
|
void set_indirect1()
|
||||||
|
{
|
||||||
|
*global_indirect1 = indirect_source();
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_indirect1() {
|
||||||
|
sink(global_indirect1); // clean
|
||||||
|
indirect_sink(*global_indirect1); // $ ir MISSING: ast
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_indirect2()
|
||||||
|
{
|
||||||
|
**global_indirect2 = source();
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_indirect2() {
|
||||||
|
sink(global_indirect2); // clean
|
||||||
|
sink(**global_indirect2); // $ ir MISSING: ast
|
||||||
|
}
|
||||||
|
|
||||||
|
// overload source with a boolean parameter so
|
||||||
|
// that we can define a variant that return an int**.
|
||||||
|
int** source(bool);
|
||||||
|
|
||||||
|
void set_direct()
|
||||||
|
{
|
||||||
|
global_direct = source(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_direct() {
|
||||||
|
sink(global_direct); // $ ir MISSING: ast
|
||||||
|
indirect_sink(global_direct); // clean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_references() {
|
||||||
|
int x = source();
|
||||||
|
int &y = x;
|
||||||
|
sink(y); // $ ast,ir
|
||||||
|
|
||||||
|
int* px = indirect_source();
|
||||||
|
int*& rpx = px;
|
||||||
|
indirect_sink((int*)rpx); // $ ast,ir
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace GlobalArrays {
|
||||||
|
void test1() {
|
||||||
|
static const int static_local_array_dynamic[] = { ::source() };
|
||||||
|
sink(*static_local_array_dynamic); // $ ir MISSING: ast
|
||||||
|
}
|
||||||
|
|
||||||
|
const int* source(bool);
|
||||||
|
|
||||||
|
void test2() {
|
||||||
|
static const int* static_local_pointer_dynamic = source(true);
|
||||||
|
sink(static_local_pointer_dynamic); // $ ast,ir
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int global_array_dynamic[] = { ::source() };
|
||||||
|
|
||||||
|
void test3() {
|
||||||
|
sink(*global_array_dynamic); // $ MISSING: ir,ast // Missing in IR because no 'IRFunction' for global_array is generated because the type of global_array_dynamic is "deeply const".
|
||||||
|
}
|
||||||
|
|
||||||
|
const int* source(bool);
|
||||||
|
|
||||||
|
static const int* global_pointer_dynamic = source(true);
|
||||||
|
|
||||||
|
void test4() {
|
||||||
|
sink(global_pointer_dynamic); // $ ir MISSING: ast
|
||||||
|
}
|
||||||
|
|
||||||
|
void test5() {
|
||||||
|
static const char static_local_array_static[] = "source";
|
||||||
|
static const char static_local_array_static_indirect_1[] = "indirect_source(1)";
|
||||||
|
static const char static_local_array_static_indirect_2[] = "indirect_source(2)";
|
||||||
|
sink(static_local_array_static); // clean
|
||||||
|
sink(static_local_array_static_indirect_1); // $ ir MISSING: ast
|
||||||
|
indirect_sink(static_local_array_static_indirect_1); // clean
|
||||||
|
sink(static_local_array_static_indirect_2); // clean
|
||||||
|
indirect_sink(static_local_array_static_indirect_2); // $ ir MISSING: ast
|
||||||
|
}
|
||||||
|
|
||||||
|
void test6() {
|
||||||
|
static const char* static_local_pointer_static = "source";
|
||||||
|
static const char* static_local_pointer_static_indirect_1 = "indirect_source(1)";
|
||||||
|
static const char* static_local_pointer_static_indirect_2 = "indirect_source(2)";
|
||||||
|
sink(static_local_pointer_static); // $ ir MISSING: ast
|
||||||
|
sink(static_local_pointer_static_indirect_1); // clean
|
||||||
|
indirect_sink(static_local_pointer_static_indirect_1); // $ ir MISSING: ast
|
||||||
|
sink(static_local_pointer_static_indirect_2); // clean: static_local_pointer_static_indirect_2 does not have 2 indirections
|
||||||
|
indirect_sink(static_local_pointer_static_indirect_2); // clean: static_local_pointer_static_indirect_2 does not have 2 indirections
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char global_array_static[] = "source";
|
||||||
|
static const char global_array_static_indirect_1[] = "indirect_source(1)";
|
||||||
|
static const char global_array_static_indirect_2[] = "indirect_source(2)";
|
||||||
|
|
||||||
|
void test7() {
|
||||||
|
sink(global_array_static); // clean
|
||||||
|
sink(*global_array_static); // clean
|
||||||
|
sink(global_array_static_indirect_1); // $ ir MISSING: ast
|
||||||
|
sink(*global_array_static_indirect_1); // clean
|
||||||
|
indirect_sink(global_array_static); // clean
|
||||||
|
indirect_sink(global_array_static_indirect_1); // clean
|
||||||
|
indirect_sink(global_array_static_indirect_2); // $ ir MISSING: ast
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* global_pointer_static = "source";
|
||||||
|
static const char* global_pointer_static_indirect_1 = "indirect_source(1)";
|
||||||
|
static const char* global_pointer_static_indirect_2 = "indirect_source(2)";
|
||||||
|
|
||||||
|
void test8() {
|
||||||
|
sink(global_pointer_static); // $ ir MISSING: ast
|
||||||
|
sink(global_pointer_static_indirect_1); // clean
|
||||||
|
indirect_sink(global_pointer_static_indirect_1); // $ ir MISSING: ast
|
||||||
|
sink(global_pointer_static_indirect_2); // clean: global_pointer_static_indirect_2 does not have 2 indirections
|
||||||
|
indirect_sink(global_pointer_static_indirect_2); // clean: global_pointer_static_indirect_2 does not have 2 indirections
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,2 @@
|
|||||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:19,45-53)
|
|
||||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:20,24-32)
|
|
||||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:27,15-23)
|
|
||||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:33,22-30)
|
|
||||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:40,25-33)
|
|
||||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:42,17-25)
|
|
||||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:46,20-28)
|
|
||||||
testFailures
|
testFailures
|
||||||
failures
|
failures
|
||||||
|
|||||||
@@ -1,107 +1,3 @@
|
|||||||
|
import TestBase
|
||||||
import TestUtilities.dataflow.FlowTestCommon
|
import TestUtilities.dataflow.FlowTestCommon
|
||||||
|
|
||||||
module AstTest {
|
|
||||||
private import semmle.code.cpp.dataflow.DataFlow
|
|
||||||
private import semmle.code.cpp.controlflow.Guards
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement
|
|
||||||
* S in `if (guarded(x)) S`.
|
|
||||||
*/
|
|
||||||
// This is tested in `BarrierGuard.cpp`.
|
|
||||||
predicate testBarrierGuard(GuardCondition g, Expr checked, boolean isTrue) {
|
|
||||||
g.(FunctionCall).getTarget().getName() = "guarded" and
|
|
||||||
checked = g.(FunctionCall).getArgument(0) and
|
|
||||||
isTrue = true
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Common data flow configuration to be used by tests. */
|
|
||||||
module AstTestAllocationConfig implements DataFlow::ConfigSig {
|
|
||||||
predicate isSource(DataFlow::Node source) {
|
|
||||||
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
|
||||||
or
|
|
||||||
source.asParameter().getName().matches("source%")
|
|
||||||
or
|
|
||||||
source.asExpr().(FunctionCall).getTarget().getName() = "indirect_source"
|
|
||||||
or
|
|
||||||
source.(DataFlow::DefinitionByReferenceNode).getParameter().getName().matches("ref_source%")
|
|
||||||
or
|
|
||||||
// Track uninitialized variables
|
|
||||||
exists(source.asUninitialized())
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isSink(DataFlow::Node sink) {
|
|
||||||
exists(FunctionCall call |
|
|
||||||
call.getTarget().getName() = ["sink", "indirect_sink"] and
|
|
||||||
sink.asExpr() = call.getAnArgument()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrier(DataFlow::Node barrier) {
|
|
||||||
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier") or
|
|
||||||
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module AstFlow = DataFlow::Global<AstTestAllocationConfig>;
|
|
||||||
}
|
|
||||||
|
|
||||||
module IRTest {
|
|
||||||
private import cpp
|
|
||||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
|
||||||
private import semmle.code.cpp.ir.IR
|
|
||||||
private import semmle.code.cpp.controlflow.IRGuards
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement
|
|
||||||
* S in `if (guarded(x)) S`.
|
|
||||||
*/
|
|
||||||
// This is tested in `BarrierGuard.cpp`.
|
|
||||||
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean isTrue) {
|
|
||||||
exists(Call call |
|
|
||||||
call = g.getUnconvertedResultExpression() and
|
|
||||||
call.getTarget().hasName("guarded") and
|
|
||||||
checked = call.getArgument(0) and
|
|
||||||
isTrue = true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Common data flow configuration to be used by tests. */
|
|
||||||
module IRTestAllocationConfig implements DataFlow::ConfigSig {
|
|
||||||
predicate isSource(DataFlow::Node source) {
|
|
||||||
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
|
||||||
or
|
|
||||||
source.asIndirectExpr(1).(FunctionCall).getTarget().getName() = "indirect_source"
|
|
||||||
or
|
|
||||||
source.asParameter().getName().matches("source%")
|
|
||||||
or
|
|
||||||
source.(DataFlow::DefinitionByReferenceNode).getParameter().getName().matches("ref_source%")
|
|
||||||
or
|
|
||||||
exists(source.asUninitialized())
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isSink(DataFlow::Node sink) {
|
|
||||||
exists(FunctionCall call, Expr e | e = call.getAnArgument() |
|
|
||||||
call.getTarget().getName() = "sink" and
|
|
||||||
sink.asExpr() = e
|
|
||||||
or
|
|
||||||
call.getTarget().getName() = "indirect_sink" and
|
|
||||||
sink.asIndirectExpr() = e
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrier(DataFlow::Node barrier) {
|
|
||||||
exists(Expr barrierExpr | barrierExpr in [barrier.asExpr(), barrier.asIndirectExpr()] |
|
|
||||||
barrierExpr.(VariableAccess).getTarget().hasName("barrier")
|
|
||||||
)
|
|
||||||
or
|
|
||||||
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
|
|
||||||
or
|
|
||||||
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getAnIndirectBarrierNode()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module IRFlow = DataFlow::Global<IRTestAllocationConfig>;
|
|
||||||
}
|
|
||||||
|
|
||||||
import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>>
|
import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>>
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
failures
|
|
||||||
testFailures
|
testFailures
|
||||||
|
failures
|
||||||
|
|||||||
@@ -6646,6 +6646,17 @@ WARNING: Module TaintTracking has been deprecated and may be removed in future (
|
|||||||
| taint.cpp:738:17:738:31 | call to indirect_source | taint.cpp:739:30:739:35 | source | |
|
| taint.cpp:738:17:738:31 | call to indirect_source | taint.cpp:739:30:739:35 | source | |
|
||||||
| taint.cpp:739:22:739:28 | call to realloc | taint.cpp:740:7:740:10 | dest | |
|
| taint.cpp:739:22:739:28 | call to realloc | taint.cpp:740:7:740:10 | dest | |
|
||||||
| taint.cpp:739:30:739:35 | source | taint.cpp:739:22:739:28 | call to realloc | TAINT |
|
| taint.cpp:739:30:739:35 | source | taint.cpp:739:22:739:28 | call to realloc | TAINT |
|
||||||
|
| taint.cpp:743:40:743:45 | buffer | taint.cpp:744:5:744:10 | buffer | |
|
||||||
|
| taint.cpp:743:40:743:45 | buffer | taint.cpp:745:27:745:32 | buffer | |
|
||||||
|
| taint.cpp:744:4:744:10 | * ... | taint.cpp:744:3:744:10 | * ... | TAINT |
|
||||||
|
| taint.cpp:744:5:744:10 | buffer | taint.cpp:744:4:744:10 | * ... | TAINT |
|
||||||
|
| taint.cpp:744:14:744:19 | call to source | taint.cpp:744:3:744:21 | ... = ... | |
|
||||||
|
| taint.cpp:745:19:745:25 | call to realloc | taint.cpp:743:40:743:45 | buffer | |
|
||||||
|
| taint.cpp:745:19:745:25 | call to realloc | taint.cpp:745:3:745:37 | ... = ... | |
|
||||||
|
| taint.cpp:745:19:745:25 | call to realloc | taint.cpp:746:10:746:15 | buffer | |
|
||||||
|
| taint.cpp:745:27:745:32 | buffer | taint.cpp:745:19:745:25 | call to realloc | TAINT |
|
||||||
|
| taint.cpp:746:9:746:15 | * ... | taint.cpp:746:8:746:15 | * ... | TAINT |
|
||||||
|
| taint.cpp:746:10:746:15 | buffer | taint.cpp:746:9:746:15 | * ... | TAINT |
|
||||||
| vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | |
|
| vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | |
|
||||||
| vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | |
|
| vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | |
|
||||||
| vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | |
|
| vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | |
|
||||||
|
|||||||
@@ -738,4 +738,10 @@ void test_realloc() {
|
|||||||
char *source = indirect_source();
|
char *source = indirect_source();
|
||||||
char *dest = (char*)realloc(source, 16);
|
char *dest = (char*)realloc(source, 16);
|
||||||
sink(dest); // $ ir MISSING: ast
|
sink(dest); // $ ir MISSING: ast
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_realloc_2_indirections(int **buffer) {
|
||||||
|
**buffer = source();
|
||||||
|
buffer = (int**)realloc(buffer, 16);
|
||||||
|
sink(**buffer); // $ ir MISSING: ast
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,6 @@ import cpp
|
|||||||
import codeql.rangeanalysis.ModulusAnalysis
|
import codeql.rangeanalysis.ModulusAnalysis
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticLocation
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticLocation
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
|
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisImpl
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisImpl
|
||||||
@@ -10,9 +9,7 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
|||||||
import semmle.code.cpp.ir.IR as IR
|
import semmle.code.cpp.ir.IR as IR
|
||||||
import TestUtilities.InlineExpectationsTest
|
import TestUtilities.InlineExpectationsTest
|
||||||
|
|
||||||
module ModulusAnalysisInstantiated =
|
module ModulusAnalysisInstantiated = ModulusAnalysis<SemLocation, Sem, FloatDelta, ConstantBounds>;
|
||||||
ModulusAnalysis<SemLocation, Sem, FloatDelta, ConstantBounds,
|
|
||||||
RangeUtil<FloatDelta, CppLangImplRelative>>;
|
|
||||||
|
|
||||||
module ModulusAnalysisTest implements TestSig {
|
module ModulusAnalysisTest implements TestSig {
|
||||||
string getARelevantTag() { result = "mod" }
|
string getARelevantTag() { result = "mod" }
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ int test2(struct List* p) {
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
for (; p; p = p->next) {
|
for (; p; p = p->next) {
|
||||||
count = (count+1) % 10;
|
count = (count+1) % 10;
|
||||||
range(count); // $ range=<=9 range=>=-9 range="<=Phi: p | Store: count+1"
|
range(count); // $ range=<=9 range=>=-9
|
||||||
}
|
}
|
||||||
range(count); // $ range=>=-9 range=<=9
|
range(count); // $ range=>=-9 range=<=9
|
||||||
return count;
|
return count;
|
||||||
@@ -29,7 +29,7 @@ int test3(struct List* p) {
|
|||||||
for (; p; p = p->next) {
|
for (; p; p = p->next) {
|
||||||
range(count++); // $ range=>=-9 range=<=9
|
range(count++); // $ range=>=-9 range=<=9
|
||||||
count = count % 10;
|
count = count % 10;
|
||||||
range(count); // $ range=<=9 range=>=-9 range="<=Store: ... +++0" range="<=Phi: p | Store: count+1"
|
range(count); // $ range=<=9 range=>=-9
|
||||||
}
|
}
|
||||||
range(count); // $ range=>=-9 range=<=9
|
range(count); // $ range=>=-9 range=<=9
|
||||||
return count;
|
return count;
|
||||||
@@ -317,7 +317,7 @@ int test_mult01(int a, int b) {
|
|||||||
range(b); // $ range=<=23 range=>=-13
|
range(b); // $ range=<=23 range=>=-13
|
||||||
int r = a*b; // $ overflow=+- -143 .. 253
|
int r = a*b; // $ overflow=+- -143 .. 253
|
||||||
range(r);
|
range(r);
|
||||||
total += r; // $ overflow=+
|
total += r; // $ overflow=+-
|
||||||
range(total); // $ MISSING: range=">=... * ...+0"
|
range(total); // $ MISSING: range=">=... * ...+0"
|
||||||
}
|
}
|
||||||
if (3 <= a && a <= 11 && -13 <= b && b <= 0) {
|
if (3 <= a && a <= 11 && -13 <= b && b <= 0) {
|
||||||
@@ -365,7 +365,7 @@ int test_mult02(int a, int b) {
|
|||||||
range(b); // $ range=<=23 range=>=-13
|
range(b); // $ range=<=23 range=>=-13
|
||||||
int r = a*b; // $ overflow=+- -143 .. 253
|
int r = a*b; // $ overflow=+- -143 .. 253
|
||||||
range(r);
|
range(r);
|
||||||
total += r; // $ overflow=+
|
total += r; // $ overflow=+-
|
||||||
range(total); // $ MISSING: range=">=... * ...+0"
|
range(total); // $ MISSING: range=">=... * ...+0"
|
||||||
}
|
}
|
||||||
if (0 <= a && a <= 11 && -13 <= b && b <= 0) {
|
if (0 <= a && a <= 11 && -13 <= b && b <= 0) {
|
||||||
@@ -460,7 +460,7 @@ int test_mult04(int a, int b) {
|
|||||||
range(b); // $ range=<=23 range=>=-13
|
range(b); // $ range=<=23 range=>=-13
|
||||||
int r = a*b; // $ overflow=+- -391 .. 221
|
int r = a*b; // $ overflow=+- -391 .. 221
|
||||||
range(r);
|
range(r);
|
||||||
total += r; // $ overflow=-
|
total += r; // $ overflow=+-
|
||||||
range(total); // $ MISSING: range="<=... * ...+0"
|
range(total); // $ MISSING: range="<=... * ...+0"
|
||||||
}
|
}
|
||||||
if (-17 <= a && a <= 0 && -13 <= b && b <= 0) {
|
if (-17 <= a && a <= 0 && -13 <= b && b <= 0) {
|
||||||
@@ -508,7 +508,7 @@ int test_mult05(int a, int b) {
|
|||||||
range(b); // $ range=<=23 range=>=-13
|
range(b); // $ range=<=23 range=>=-13
|
||||||
int r = a*b; // $ overflow=+- -391 .. 221
|
int r = a*b; // $ overflow=+- -391 .. 221
|
||||||
range(r);
|
range(r);
|
||||||
total += r; // $ overflow=-
|
total += r; // $ overflow=+-
|
||||||
range(total); // $ MISSING: range="<=... * ...+0"
|
range(total); // $ MISSING: range="<=... * ...+0"
|
||||||
}
|
}
|
||||||
if (-17 <= a && a <= -2 && -13 <= b && b <= 0) {
|
if (-17 <= a && a <= -2 && -13 <= b && b <= 0) {
|
||||||
@@ -974,7 +974,7 @@ void test_mod_neg(int s) {
|
|||||||
|
|
||||||
void test_mod_ternary(int s, bool b) {
|
void test_mod_ternary(int s, bool b) {
|
||||||
int s2 = s % (b ? 5 : 500);
|
int s2 = s % (b ? 5 : 500);
|
||||||
range(s2); // $ range=>=-499 range=<=499 range="<=Phi: ... ? ... : ...-1"
|
range(s2); // $ range=>=-499 range=<=499
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_mod_ternary2(int s, bool b1, bool b2) {
|
void test_mod_ternary2(int s, bool b1, bool b2) {
|
||||||
|
|||||||
@@ -130,3 +130,19 @@ void test_div(int x) {
|
|||||||
range(x >> 2); // $ range=>=0 range=<=2
|
range(x >> 2); // $ range=>=0 range=<=2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct X { int n; };
|
||||||
|
void read_argument(const X *);
|
||||||
|
|
||||||
|
// This test exists purely to ensure that modulus analysis terminates in the
|
||||||
|
// presence of inexact phi operands. The LoadInstruction on `while(x->n) { ... }`
|
||||||
|
// reads from a PhiInstruction with two input operands: an exact operand defined
|
||||||
|
// by the StoreInstruction generated by `x->n--` and an inexact operand coming
|
||||||
|
// from the WriteSideEffect generated by `read_argument(x)`. If we don't consider
|
||||||
|
// the inexact operand modulus analysis fails to terminate.
|
||||||
|
void nonterminating_without_operands_as_ssa(X *x) {
|
||||||
|
read_argument(x);
|
||||||
|
while (x->n) {
|
||||||
|
x->n--;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.SignAnalysisCommon
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.SignAnalysisCommon
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
|
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||||
import semmle.code.cpp.ir.IR as IR
|
import semmle.code.cpp.ir.IR as IR
|
||||||
import TestUtilities.InlineExpectationsTest
|
import TestUtilities.InlineExpectationsTest
|
||||||
|
|
||||||
module SignAnalysisInstantiated =
|
module SignAnalysisInstantiated = SignAnalysis<FloatDelta>;
|
||||||
SignAnalysis<FloatDelta, RangeUtil<FloatDelta, CppLangImplRelative>>;
|
|
||||||
|
|
||||||
module SignAnalysisTest implements TestSig {
|
module SignAnalysisTest implements TestSig {
|
||||||
string getARelevantTag() { result = "sign" }
|
string getARelevantTag() { result = "sign" }
|
||||||
|
|||||||
@@ -4,7 +4,12 @@ uniqueType
|
|||||||
uniqueNodeLocation
|
uniqueNodeLocation
|
||||||
missingLocation
|
missingLocation
|
||||||
uniqueNodeToString
|
uniqueNodeToString
|
||||||
| cpp11.cpp:50:15:50:16 | (no string representation) | Node should have one toString but has 0. |
|
| builtin.c:5:5:5:11 | (no string representation) | Node should have one toString but has 0. |
|
||||||
|
| misc.c:227:7:227:28 | (no string representation) | Node should have one toString but has 0. |
|
||||||
|
| static_init_templates.cpp:80:18:80:23 | (no string representation) | Node should have one toString but has 0. |
|
||||||
|
| static_init_templates.cpp:80:18:80:23 | (no string representation) | Node should have one toString but has 0. |
|
||||||
|
| static_init_templates.cpp:89:18:89:23 | (no string representation) | Node should have one toString but has 0. |
|
||||||
|
| static_init_templates.cpp:89:18:89:23 | (no string representation) | Node should have one toString but has 0. |
|
||||||
parameterCallable
|
parameterCallable
|
||||||
localFlowIsLocal
|
localFlowIsLocal
|
||||||
readStepIsLocal
|
readStepIsLocal
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ edges
|
|||||||
| test.cpp:189:16:189:16 | p | test.cpp:189:16:189:16 | (reference to) |
|
| test.cpp:189:16:189:16 | p | test.cpp:189:16:189:16 | (reference to) |
|
||||||
| test.cpp:190:10:190:13 | (reference dereference) | test.cpp:190:10:190:13 | (reference to) |
|
| test.cpp:190:10:190:13 | (reference dereference) | test.cpp:190:10:190:13 | (reference to) |
|
||||||
| test.cpp:190:10:190:13 | pRef | test.cpp:190:10:190:13 | (reference dereference) |
|
| test.cpp:190:10:190:13 | pRef | test.cpp:190:10:190:13 | (reference dereference) |
|
||||||
|
| test.cpp:237:12:237:17 | call to alloca | test.cpp:237:12:237:17 | call to alloca |
|
||||||
|
| test.cpp:237:12:237:17 | call to alloca | test.cpp:238:9:238:9 | p |
|
||||||
|
| test.cpp:249:13:249:20 | call to strndupa | test.cpp:249:13:249:20 | call to strndupa |
|
||||||
|
| test.cpp:249:13:249:20 | call to strndupa | test.cpp:250:9:250:10 | s2 |
|
||||||
|
| test.cpp:250:9:250:10 | s2 | test.cpp:250:9:250:10 | (void *)... |
|
||||||
nodes
|
nodes
|
||||||
| test.cpp:17:9:17:11 | & ... | semmle.label | & ... |
|
| test.cpp:17:9:17:11 | & ... | semmle.label | & ... |
|
||||||
| test.cpp:17:10:17:11 | mc | semmle.label | mc |
|
| test.cpp:17:10:17:11 | mc | semmle.label | mc |
|
||||||
@@ -101,6 +106,14 @@ nodes
|
|||||||
| test.cpp:190:10:190:13 | (reference dereference) | semmle.label | (reference dereference) |
|
| test.cpp:190:10:190:13 | (reference dereference) | semmle.label | (reference dereference) |
|
||||||
| test.cpp:190:10:190:13 | (reference to) | semmle.label | (reference to) |
|
| test.cpp:190:10:190:13 | (reference to) | semmle.label | (reference to) |
|
||||||
| test.cpp:190:10:190:13 | pRef | semmle.label | pRef |
|
| test.cpp:190:10:190:13 | pRef | semmle.label | pRef |
|
||||||
|
| test.cpp:237:12:237:17 | call to alloca | semmle.label | call to alloca |
|
||||||
|
| test.cpp:237:12:237:17 | call to alloca | semmle.label | call to alloca |
|
||||||
|
| test.cpp:238:9:238:9 | p | semmle.label | p |
|
||||||
|
| test.cpp:245:9:245:15 | call to strdupa | semmle.label | call to strdupa |
|
||||||
|
| test.cpp:249:13:249:20 | call to strndupa | semmle.label | call to strndupa |
|
||||||
|
| test.cpp:249:13:249:20 | call to strndupa | semmle.label | call to strndupa |
|
||||||
|
| test.cpp:250:9:250:10 | (void *)... | semmle.label | (void *)... |
|
||||||
|
| test.cpp:250:9:250:10 | s2 | semmle.label | s2 |
|
||||||
#select
|
#select
|
||||||
| test.cpp:17:9:17:11 | CopyValue: & ... | test.cpp:17:10:17:11 | mc | test.cpp:17:9:17:11 | & ... | May return stack-allocated memory from $@. | test.cpp:17:10:17:11 | mc | mc |
|
| test.cpp:17:9:17:11 | CopyValue: & ... | test.cpp:17:10:17:11 | mc | test.cpp:17:9:17:11 | & ... | May return stack-allocated memory from $@. | test.cpp:17:10:17:11 | mc | mc |
|
||||||
| test.cpp:25:9:25:11 | Load: ptr | test.cpp:23:18:23:19 | mc | test.cpp:25:9:25:11 | ptr | May return stack-allocated memory from $@. | test.cpp:23:18:23:19 | mc | mc |
|
| test.cpp:25:9:25:11 | Load: ptr | test.cpp:23:18:23:19 | mc | test.cpp:25:9:25:11 | ptr | May return stack-allocated memory from $@. | test.cpp:23:18:23:19 | mc | mc |
|
||||||
@@ -115,3 +128,6 @@ nodes
|
|||||||
| test.cpp:177:10:177:23 | Convert: (void *)... | test.cpp:176:25:176:34 | localArray | test.cpp:177:10:177:23 | (void *)... | May return stack-allocated memory from $@. | test.cpp:176:25:176:34 | localArray | localArray |
|
| test.cpp:177:10:177:23 | Convert: (void *)... | test.cpp:176:25:176:34 | localArray | test.cpp:177:10:177:23 | (void *)... | May return stack-allocated memory from $@. | test.cpp:176:25:176:34 | localArray | localArray |
|
||||||
| test.cpp:183:10:183:19 | CopyValue: (reference to) | test.cpp:182:21:182:27 | myLocal | test.cpp:183:10:183:19 | (reference to) | May return stack-allocated memory from $@. | test.cpp:182:21:182:27 | myLocal | myLocal |
|
| test.cpp:183:10:183:19 | CopyValue: (reference to) | test.cpp:182:21:182:27 | myLocal | test.cpp:183:10:183:19 | (reference to) | May return stack-allocated memory from $@. | test.cpp:182:21:182:27 | myLocal | myLocal |
|
||||||
| test.cpp:190:10:190:13 | CopyValue: (reference to) | test.cpp:189:16:189:16 | p | test.cpp:190:10:190:13 | (reference to) | May return stack-allocated memory from $@. | test.cpp:189:16:189:16 | p | p |
|
| test.cpp:190:10:190:13 | CopyValue: (reference to) | test.cpp:189:16:189:16 | p | test.cpp:190:10:190:13 | (reference to) | May return stack-allocated memory from $@. | test.cpp:189:16:189:16 | p | p |
|
||||||
|
| test.cpp:238:9:238:9 | Load: p | test.cpp:237:12:237:17 | call to alloca | test.cpp:238:9:238:9 | p | May return stack-allocated memory from $@. | test.cpp:237:12:237:17 | call to alloca | call to alloca |
|
||||||
|
| test.cpp:245:9:245:15 | Call: call to strdupa | test.cpp:245:9:245:15 | call to strdupa | test.cpp:245:9:245:15 | call to strdupa | May return stack-allocated memory from $@. | test.cpp:245:9:245:15 | call to strdupa | call to strdupa |
|
||||||
|
| test.cpp:250:9:250:10 | Convert: (void *)... | test.cpp:249:13:249:20 | call to strndupa | test.cpp:250:9:250:10 | (void *)... | May return stack-allocated memory from $@. | test.cpp:249:13:249:20 | call to strndupa | call to strndupa |
|
||||||
|
|||||||
@@ -229,4 +229,23 @@ int* id(int* px) {
|
|||||||
void f() {
|
void f() {
|
||||||
int x;
|
int x;
|
||||||
int* px = id(&x); // GOOD
|
int* px = id(&x); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
void *alloca(size_t);
|
||||||
|
|
||||||
|
void* test_alloca() {
|
||||||
|
void* p = alloca(10);
|
||||||
|
return p; // BAD
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strdupa(const char *);
|
||||||
|
char *strndupa(const char *, size_t);
|
||||||
|
|
||||||
|
char* test_strdupa(const char* s) {
|
||||||
|
return strdupa(s); // BAD
|
||||||
|
}
|
||||||
|
|
||||||
|
void* test_strndupa(const char* s, size_t size) {
|
||||||
|
char* s2 = strndupa(s, size);
|
||||||
|
return s2; // BAD
|
||||||
}
|
}
|
||||||
@@ -1,23 +1,12 @@
|
|||||||
edges
|
edges
|
||||||
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data |
|
| test.cpp:37:73:37:76 | data indirection | test.cpp:43:32:43:35 | data indirection |
|
||||||
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data |
|
| test.cpp:64:30:64:35 | call to getenv indirection | test.cpp:73:24:73:27 | data indirection |
|
||||||
| test.cpp:37:73:37:76 | data indirection | test.cpp:43:32:43:35 | data |
|
|
||||||
| test.cpp:37:73:37:76 | data indirection | test.cpp:43:32:43:35 | data |
|
|
||||||
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data |
|
|
||||||
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data |
|
|
||||||
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data indirection |
|
|
||||||
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data indirection |
|
|
||||||
| test.cpp:73:24:73:27 | data | test.cpp:37:73:37:76 | data |
|
|
||||||
| test.cpp:73:24:73:27 | data indirection | test.cpp:37:73:37:76 | data indirection |
|
| test.cpp:73:24:73:27 | data indirection | test.cpp:37:73:37:76 | data indirection |
|
||||||
subpaths
|
|
||||||
nodes
|
nodes
|
||||||
| test.cpp:37:73:37:76 | data | semmle.label | data |
|
|
||||||
| test.cpp:37:73:37:76 | data indirection | semmle.label | data indirection |
|
| test.cpp:37:73:37:76 | data indirection | semmle.label | data indirection |
|
||||||
| test.cpp:43:32:43:35 | data | semmle.label | data |
|
| test.cpp:43:32:43:35 | data indirection | semmle.label | data indirection |
|
||||||
| test.cpp:43:32:43:35 | data | semmle.label | data |
|
| test.cpp:64:30:64:35 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||||
| test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv |
|
|
||||||
| test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv |
|
|
||||||
| test.cpp:73:24:73:27 | data | semmle.label | data |
|
|
||||||
| test.cpp:73:24:73:27 | data indirection | semmle.label | data indirection |
|
| test.cpp:73:24:73:27 | data indirection | semmle.label | data indirection |
|
||||||
|
subpaths
|
||||||
#select
|
#select
|
||||||
| test.cpp:43:32:43:35 | data | test.cpp:64:30:64:35 | call to getenv | test.cpp:43:32:43:35 | data | The value of this argument may come from $@ and is being passed to LoadLibraryA. | test.cpp:64:30:64:35 | call to getenv | call to getenv |
|
| test.cpp:43:32:43:35 | data indirection | test.cpp:64:30:64:35 | call to getenv indirection | test.cpp:43:32:43:35 | data indirection | The value of this argument may come from $@ and is being passed to LoadLibraryA. | test.cpp:64:30:64:35 | call to getenv indirection | an environment variable |
|
||||||
|
|||||||
@@ -1,103 +1,45 @@
|
|||||||
edges
|
edges
|
||||||
| test.cpp:24:30:24:36 | command | test.cpp:26:10:26:16 | command |
|
| test.cpp:24:30:24:36 | command indirection | test.cpp:26:10:26:16 | command indirection |
|
||||||
| test.cpp:24:30:24:36 | command | test.cpp:26:10:26:16 | command |
|
| test.cpp:29:30:29:36 | command indirection | test.cpp:31:10:31:16 | command indirection |
|
||||||
| test.cpp:29:30:29:36 | command | test.cpp:31:10:31:16 | command |
|
| test.cpp:42:18:42:34 | call to getenv indirection | test.cpp:24:30:24:36 | command indirection |
|
||||||
| test.cpp:29:30:29:36 | command | test.cpp:31:10:31:16 | command |
|
| test.cpp:43:18:43:34 | call to getenv indirection | test.cpp:29:30:29:36 | command indirection |
|
||||||
| test.cpp:42:18:42:23 | call to getenv | test.cpp:24:30:24:36 | command |
|
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer indirection |
|
||||||
| test.cpp:42:18:42:34 | call to getenv | test.cpp:24:30:24:36 | command |
|
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data indirection |
|
||||||
| test.cpp:43:18:43:23 | call to getenv | test.cpp:29:30:29:36 | command |
|
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | dataref indirection |
|
||||||
| test.cpp:43:18:43:34 | call to getenv | test.cpp:29:30:29:36 | command |
|
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:65:10:65:14 | data2 indirection |
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer |
|
| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer indirection |
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer |
|
| test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer indirection |
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer |
|
| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer indirection |
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer |
|
| test.cpp:113:8:113:12 | call to fgets indirection | test.cpp:114:9:114:11 | ptr indirection |
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data |
|
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data |
|
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data |
|
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data |
|
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
|
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
|
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
|
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
|
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
|
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
|
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:65:10:65:14 | data2 |
|
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:65:10:65:14 | data2 |
|
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:65:10:65:14 | data2 |
|
|
||||||
| test.cpp:56:12:56:17 | buffer | test.cpp:65:10:65:14 | data2 |
|
|
||||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer |
|
|
||||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer |
|
|
||||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data |
|
|
||||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data |
|
|
||||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | dataref |
|
|
||||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | dataref |
|
|
||||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | dataref |
|
|
||||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:65:10:65:14 | data2 |
|
|
||||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:65:10:65:14 | data2 |
|
|
||||||
| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer |
|
|
||||||
| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer |
|
|
||||||
| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer |
|
|
||||||
| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer |
|
|
||||||
| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer |
|
|
||||||
| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer |
|
|
||||||
| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer |
|
|
||||||
| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer |
|
|
||||||
| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer |
|
|
||||||
| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer |
|
|
||||||
| test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer |
|
|
||||||
| test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer |
|
|
||||||
| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer |
|
|
||||||
| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer |
|
|
||||||
| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer |
|
|
||||||
| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer |
|
|
||||||
| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer |
|
|
||||||
| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer |
|
|
||||||
subpaths
|
|
||||||
nodes
|
nodes
|
||||||
| test.cpp:24:30:24:36 | command | semmle.label | command |
|
| test.cpp:24:30:24:36 | command indirection | semmle.label | command indirection |
|
||||||
| test.cpp:26:10:26:16 | command | semmle.label | command |
|
| test.cpp:26:10:26:16 | command indirection | semmle.label | command indirection |
|
||||||
| test.cpp:26:10:26:16 | command | semmle.label | command |
|
| test.cpp:29:30:29:36 | command indirection | semmle.label | command indirection |
|
||||||
| test.cpp:29:30:29:36 | command | semmle.label | command |
|
| test.cpp:31:10:31:16 | command indirection | semmle.label | command indirection |
|
||||||
| test.cpp:31:10:31:16 | command | semmle.label | command |
|
| test.cpp:42:18:42:34 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||||
| test.cpp:31:10:31:16 | command | semmle.label | command |
|
| test.cpp:43:18:43:34 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||||
| test.cpp:42:18:42:23 | call to getenv | semmle.label | call to getenv |
|
|
||||||
| test.cpp:42:18:42:34 | call to getenv | semmle.label | call to getenv |
|
|
||||||
| test.cpp:43:18:43:23 | call to getenv | semmle.label | call to getenv |
|
|
||||||
| test.cpp:43:18:43:34 | call to getenv | semmle.label | call to getenv |
|
|
||||||
| test.cpp:56:12:56:17 | buffer | semmle.label | buffer |
|
|
||||||
| test.cpp:56:12:56:17 | buffer | semmle.label | buffer |
|
|
||||||
| test.cpp:56:12:56:17 | fgets output argument | semmle.label | fgets output argument |
|
| test.cpp:56:12:56:17 | fgets output argument | semmle.label | fgets output argument |
|
||||||
| test.cpp:62:10:62:15 | buffer | semmle.label | buffer |
|
| test.cpp:62:10:62:15 | buffer indirection | semmle.label | buffer indirection |
|
||||||
| test.cpp:62:10:62:15 | buffer | semmle.label | buffer |
|
| test.cpp:63:10:63:13 | data indirection | semmle.label | data indirection |
|
||||||
| test.cpp:63:10:63:13 | data | semmle.label | data |
|
| test.cpp:64:10:64:16 | dataref indirection | semmle.label | dataref indirection |
|
||||||
| test.cpp:63:10:63:13 | data | semmle.label | data |
|
| test.cpp:65:10:65:14 | data2 indirection | semmle.label | data2 indirection |
|
||||||
| test.cpp:64:10:64:16 | dataref | semmle.label | dataref |
|
|
||||||
| test.cpp:64:10:64:16 | dataref | semmle.label | dataref |
|
|
||||||
| test.cpp:64:10:64:16 | dataref | semmle.label | dataref |
|
|
||||||
| test.cpp:65:10:65:14 | data2 | semmle.label | data2 |
|
|
||||||
| test.cpp:65:10:65:14 | data2 | semmle.label | data2 |
|
|
||||||
| test.cpp:76:12:76:17 | buffer | semmle.label | buffer |
|
|
||||||
| test.cpp:76:12:76:17 | buffer | semmle.label | buffer |
|
|
||||||
| test.cpp:76:12:76:17 | fgets output argument | semmle.label | fgets output argument |
|
| test.cpp:76:12:76:17 | fgets output argument | semmle.label | fgets output argument |
|
||||||
| test.cpp:78:10:78:15 | buffer | semmle.label | buffer |
|
| test.cpp:78:10:78:15 | buffer indirection | semmle.label | buffer indirection |
|
||||||
| test.cpp:78:10:78:15 | buffer | semmle.label | buffer |
|
|
||||||
| test.cpp:98:17:98:22 | buffer | semmle.label | buffer |
|
|
||||||
| test.cpp:98:17:98:22 | buffer | semmle.label | buffer |
|
|
||||||
| test.cpp:98:17:98:22 | recv output argument | semmle.label | recv output argument |
|
| test.cpp:98:17:98:22 | recv output argument | semmle.label | recv output argument |
|
||||||
| test.cpp:99:15:99:20 | buffer | semmle.label | buffer |
|
| test.cpp:99:15:99:20 | buffer indirection | semmle.label | buffer indirection |
|
||||||
| test.cpp:99:15:99:20 | buffer | semmle.label | buffer |
|
|
||||||
| test.cpp:106:17:106:22 | buffer | semmle.label | buffer |
|
|
||||||
| test.cpp:106:17:106:22 | buffer | semmle.label | buffer |
|
|
||||||
| test.cpp:106:17:106:22 | recv output argument | semmle.label | recv output argument |
|
| test.cpp:106:17:106:22 | recv output argument | semmle.label | recv output argument |
|
||||||
| test.cpp:107:15:107:20 | buffer | semmle.label | buffer |
|
| test.cpp:107:15:107:20 | buffer indirection | semmle.label | buffer indirection |
|
||||||
| test.cpp:107:15:107:20 | buffer | semmle.label | buffer |
|
| test.cpp:113:8:113:12 | call to fgets indirection | semmle.label | call to fgets indirection |
|
||||||
|
| test.cpp:114:9:114:11 | ptr indirection | semmle.label | ptr indirection |
|
||||||
|
subpaths
|
||||||
#select
|
#select
|
||||||
| test.cpp:26:10:26:16 | command | test.cpp:42:18:42:23 | call to getenv | test.cpp:26:10:26:16 | command | The value of this argument may come from $@ and is being passed to system. | test.cpp:42:18:42:23 | call to getenv | call to getenv |
|
| test.cpp:26:10:26:16 | command indirection | test.cpp:42:18:42:34 | call to getenv indirection | test.cpp:26:10:26:16 | command indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:42:18:42:34 | call to getenv indirection | an environment variable |
|
||||||
| test.cpp:31:10:31:16 | command | test.cpp:43:18:43:23 | call to getenv | test.cpp:31:10:31:16 | command | The value of this argument may come from $@ and is being passed to system. | test.cpp:43:18:43:23 | call to getenv | call to getenv |
|
| test.cpp:31:10:31:16 | command indirection | test.cpp:43:18:43:34 | call to getenv indirection | test.cpp:31:10:31:16 | command indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:43:18:43:34 | call to getenv indirection | an environment variable |
|
||||||
| test.cpp:62:10:62:15 | buffer | test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | buffer | buffer |
|
| test.cpp:62:10:62:15 | buffer indirection | test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | fgets output argument | string read by fgets |
|
||||||
| test.cpp:63:10:63:13 | data | test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | buffer | buffer |
|
| test.cpp:63:10:63:13 | data indirection | test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | fgets output argument | string read by fgets |
|
||||||
| test.cpp:64:10:64:16 | dataref | test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | buffer | buffer |
|
| test.cpp:64:10:64:16 | dataref indirection | test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | dataref indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | fgets output argument | string read by fgets |
|
||||||
| test.cpp:65:10:65:14 | data2 | test.cpp:56:12:56:17 | buffer | test.cpp:65:10:65:14 | data2 | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | buffer | buffer |
|
| test.cpp:65:10:65:14 | data2 indirection | test.cpp:56:12:56:17 | fgets output argument | test.cpp:65:10:65:14 | data2 indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | fgets output argument | string read by fgets |
|
||||||
| test.cpp:78:10:78:15 | buffer | test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer | The value of this argument may come from $@ and is being passed to system. | test.cpp:76:12:76:17 | buffer | buffer |
|
| test.cpp:78:10:78:15 | buffer indirection | test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:76:12:76:17 | fgets output argument | string read by fgets |
|
||||||
| test.cpp:99:15:99:20 | buffer | test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer | The value of this argument may come from $@ and is being passed to LoadLibrary. | test.cpp:98:17:98:22 | buffer | buffer |
|
| test.cpp:99:15:99:20 | buffer indirection | test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer indirection | The value of this argument may come from $@ and is being passed to LoadLibrary. | test.cpp:98:17:98:22 | recv output argument | buffer read by recv |
|
||||||
| test.cpp:107:15:107:20 | buffer | test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer | The value of this argument may come from $@ and is being passed to LoadLibrary. | test.cpp:106:17:106:22 | buffer | buffer |
|
| test.cpp:107:15:107:20 | buffer indirection | test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer indirection | The value of this argument may come from $@ and is being passed to LoadLibrary. | test.cpp:106:17:106:22 | recv output argument | buffer read by recv |
|
||||||
|
| test.cpp:114:9:114:11 | ptr indirection | test.cpp:113:8:113:12 | call to fgets indirection | test.cpp:114:9:114:11 | ptr indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:113:8:113:12 | call to fgets indirection | string read by fgets |
|
||||||
|
|||||||
@@ -107,3 +107,9 @@ void testAcceptRecv(int socket1, int socket2)
|
|||||||
LoadLibrary(buffer); // BAD: using data from recv
|
LoadLibrary(buffer); // BAD: using data from recv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void argumentUse(char *ptr, FILE *stream) {
|
||||||
|
char buffer[80];
|
||||||
|
ptr = fgets(buffer, sizeof(buffer), stream);
|
||||||
|
system(ptr); // BAD
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,32 @@
|
|||||||
edges
|
edges
|
||||||
subpaths
|
| main.cpp:6:27:6:30 | argv indirection | main.cpp:10:20:10:23 | argv indirection |
|
||||||
|
| main.cpp:10:20:10:23 | argv indirection | tests.cpp:631:32:631:35 | argv indirection |
|
||||||
|
| tests.cpp:613:19:613:24 | source indirection | tests.cpp:615:17:615:22 | source indirection |
|
||||||
|
| tests.cpp:622:19:622:24 | source indirection | tests.cpp:625:2:625:16 | ... = ... indirection |
|
||||||
|
| tests.cpp:625:2:625:16 | ... = ... indirection | tests.cpp:625:4:625:7 | s indirection [post update] [home indirection] |
|
||||||
|
| tests.cpp:625:4:625:7 | s indirection [post update] [home indirection] | tests.cpp:628:14:628:14 | s indirection [home indirection] |
|
||||||
|
| tests.cpp:628:14:628:14 | s indirection [home indirection] | tests.cpp:628:14:628:19 | home indirection |
|
||||||
|
| tests.cpp:628:14:628:14 | s indirection [home indirection] | tests.cpp:628:16:628:19 | home indirection |
|
||||||
|
| tests.cpp:628:16:628:19 | home indirection | tests.cpp:628:14:628:19 | home indirection |
|
||||||
|
| tests.cpp:631:32:631:35 | argv indirection | tests.cpp:656:9:656:15 | access to array indirection |
|
||||||
|
| tests.cpp:631:32:631:35 | argv indirection | tests.cpp:657:9:657:15 | access to array indirection |
|
||||||
|
| tests.cpp:656:9:656:15 | access to array indirection | tests.cpp:613:19:613:24 | source indirection |
|
||||||
|
| tests.cpp:657:9:657:15 | access to array indirection | tests.cpp:622:19:622:24 | source indirection |
|
||||||
nodes
|
nodes
|
||||||
|
| main.cpp:6:27:6:30 | argv indirection | semmle.label | argv indirection |
|
||||||
|
| main.cpp:10:20:10:23 | argv indirection | semmle.label | argv indirection |
|
||||||
|
| tests.cpp:613:19:613:24 | source indirection | semmle.label | source indirection |
|
||||||
|
| tests.cpp:615:17:615:22 | source indirection | semmle.label | source indirection |
|
||||||
|
| tests.cpp:622:19:622:24 | source indirection | semmle.label | source indirection |
|
||||||
|
| tests.cpp:625:2:625:16 | ... = ... indirection | semmle.label | ... = ... indirection |
|
||||||
|
| tests.cpp:625:4:625:7 | s indirection [post update] [home indirection] | semmle.label | s indirection [post update] [home indirection] |
|
||||||
|
| tests.cpp:628:14:628:14 | s indirection [home indirection] | semmle.label | s indirection [home indirection] |
|
||||||
|
| tests.cpp:628:14:628:19 | home indirection | semmle.label | home indirection |
|
||||||
|
| tests.cpp:628:16:628:19 | home indirection | semmle.label | home indirection |
|
||||||
|
| tests.cpp:631:32:631:35 | argv indirection | semmle.label | argv indirection |
|
||||||
|
| tests.cpp:656:9:656:15 | access to array indirection | semmle.label | access to array indirection |
|
||||||
|
| tests.cpp:657:9:657:15 | access to array indirection | semmle.label | access to array indirection |
|
||||||
|
subpaths
|
||||||
#select
|
#select
|
||||||
|
| tests.cpp:615:2:615:7 | call to strcpy | main.cpp:6:27:6:30 | argv indirection | tests.cpp:615:17:615:22 | source indirection | This 'call to strcpy' with input from $@ may overflow the destination. | main.cpp:6:27:6:30 | argv indirection | a command-line argument |
|
||||||
|
| tests.cpp:628:2:628:7 | call to strcpy | main.cpp:6:27:6:30 | argv indirection | tests.cpp:628:14:628:19 | home indirection | This 'call to strcpy' with input from $@ may overflow the destination. | main.cpp:6:27:6:30 | argv indirection | a command-line argument |
|
||||||
|
|||||||
@@ -407,7 +407,7 @@ void test15()
|
|||||||
{
|
{
|
||||||
if (ptr[5] == ' ') // GOOD
|
if (ptr[5] == ' ') // GOOD
|
||||||
{
|
{
|
||||||
// ...
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -608,6 +608,26 @@ int test23() {
|
|||||||
return sizeof(buffer) / sizeof(buffer[101]); // GOOD
|
return sizeof(buffer) / sizeof(buffer[101]); // GOOD
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* strcpy(char *, const char *);
|
||||||
|
|
||||||
|
void test24(char* source) {
|
||||||
|
char buffer[100];
|
||||||
|
strcpy(buffer, source); // BAD
|
||||||
|
}
|
||||||
|
|
||||||
|
struct my_struct {
|
||||||
|
char* home;
|
||||||
|
};
|
||||||
|
|
||||||
|
void test25(char* source) {
|
||||||
|
my_struct s;
|
||||||
|
|
||||||
|
s.home = source;
|
||||||
|
|
||||||
|
char buf[100];
|
||||||
|
strcpy(buf, s.home); // BAD
|
||||||
|
}
|
||||||
|
|
||||||
int tests_main(int argc, char *argv[])
|
int tests_main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
long long arr17[19];
|
long long arr17[19];
|
||||||
@@ -633,6 +653,8 @@ int tests_main(int argc, char *argv[])
|
|||||||
test21(argc == 0);
|
test21(argc == 0);
|
||||||
test22(argc == 0, argv[0]);
|
test22(argc == 0, argv[0]);
|
||||||
test23();
|
test23();
|
||||||
|
test24(argv[0]);
|
||||||
|
test25(argv[0]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,18 @@
|
|||||||
edges
|
edges
|
||||||
| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array |
|
| tests.c:16:26:16:29 | argv indirection | tests.c:28:22:28:28 | access to array indirection |
|
||||||
| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array |
|
| tests.c:16:26:16:29 | argv indirection | tests.c:29:28:29:34 | access to array indirection |
|
||||||
| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array |
|
| tests.c:16:26:16:29 | argv indirection | tests.c:34:10:34:16 | access to array indirection |
|
||||||
| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array |
|
|
||||||
| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array |
|
|
||||||
| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array |
|
|
||||||
| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array |
|
|
||||||
| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array |
|
|
||||||
| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array |
|
|
||||||
| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array |
|
|
||||||
| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array |
|
|
||||||
| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array |
|
|
||||||
subpaths
|
|
||||||
nodes
|
nodes
|
||||||
| tests.c:28:22:28:25 | argv | semmle.label | argv |
|
| tests.c:16:26:16:29 | argv indirection | semmle.label | argv indirection |
|
||||||
| tests.c:28:22:28:25 | argv | semmle.label | argv |
|
| tests.c:28:22:28:28 | access to array indirection | semmle.label | access to array indirection |
|
||||||
| tests.c:28:22:28:28 | access to array | semmle.label | access to array |
|
| tests.c:29:28:29:34 | access to array indirection | semmle.label | access to array indirection |
|
||||||
| tests.c:28:22:28:28 | access to array | semmle.label | access to array |
|
| tests.c:31:15:31:23 | scanf output argument | semmle.label | scanf output argument |
|
||||||
| tests.c:29:28:29:31 | argv | semmle.label | argv |
|
| tests.c:33:21:33:29 | scanf output argument | semmle.label | scanf output argument |
|
||||||
| tests.c:29:28:29:31 | argv | semmle.label | argv |
|
| tests.c:34:10:34:16 | access to array indirection | semmle.label | access to array indirection |
|
||||||
| tests.c:29:28:29:34 | access to array | semmle.label | access to array |
|
subpaths
|
||||||
| tests.c:29:28:29:34 | access to array | semmle.label | access to array |
|
|
||||||
| tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 |
|
|
||||||
| tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 |
|
|
||||||
| tests.c:33:21:33:29 | buffer100 | semmle.label | buffer100 |
|
|
||||||
| tests.c:33:21:33:29 | buffer100 | semmle.label | buffer100 |
|
|
||||||
| tests.c:34:10:34:13 | argv | semmle.label | argv |
|
|
||||||
| tests.c:34:10:34:13 | argv | semmle.label | argv |
|
|
||||||
| tests.c:34:10:34:16 | access to array | semmle.label | access to array |
|
|
||||||
| tests.c:34:10:34:16 | access to array | semmle.label | access to array |
|
|
||||||
#select
|
#select
|
||||||
| tests.c:28:3:28:9 | call to sprintf | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv |
|
| tests.c:28:3:28:9 | call to sprintf | tests.c:16:26:16:29 | argv indirection | tests.c:28:22:28:28 | access to array indirection | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:16:26:16:29 | argv indirection | a command-line argument |
|
||||||
| tests.c:29:3:29:9 | call to sprintf | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:29:28:29:31 | argv | argv |
|
| tests.c:29:3:29:9 | call to sprintf | tests.c:16:26:16:29 | argv indirection | tests.c:29:28:29:34 | access to array indirection | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:16:26:16:29 | argv indirection | a command-line argument |
|
||||||
| tests.c:31:15:31:23 | buffer100 | tests.c:31:15:31:23 | buffer100 | tests.c:31:15:31:23 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:31:15:31:23 | buffer100 | buffer100 |
|
| tests.c:31:15:31:23 | buffer100 | tests.c:31:15:31:23 | scanf output argument | tests.c:31:15:31:23 | scanf output argument | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:31:15:31:23 | scanf output argument | value read by scanf |
|
||||||
| tests.c:33:21:33:29 | buffer100 | tests.c:33:21:33:29 | buffer100 | tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:33:21:33:29 | buffer100 | buffer100 |
|
| tests.c:33:21:33:29 | buffer100 | tests.c:33:21:33:29 | scanf output argument | tests.c:33:21:33:29 | scanf output argument | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:33:21:33:29 | scanf output argument | value read by scanf |
|
||||||
| tests.c:34:25:34:33 | buffer100 | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | This 'sscanf string argument' with input from $@ may overflow the destination. | tests.c:34:10:34:13 | argv | argv |
|
| tests.c:34:25:34:33 | buffer100 | tests.c:16:26:16:29 | argv indirection | tests.c:34:10:34:16 | access to array indirection | This 'sscanf string argument' with input from $@ may overflow the destination. | tests.c:16:26:16:29 | argv indirection | a command-line argument |
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
edges
|
|
||||||
| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy |
|
|
||||||
| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy |
|
|
||||||
| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy |
|
|
||||||
| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy |
|
|
||||||
| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy |
|
|
||||||
| globalVars.c:8:7:8:10 | copy | globalVars.c:33:15:33:18 | copy |
|
|
||||||
| globalVars.c:8:7:8:10 | copy | globalVars.c:35:11:35:14 | copy |
|
|
||||||
| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 |
|
|
||||||
| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 |
|
|
||||||
| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 |
|
|
||||||
| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 |
|
|
||||||
| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 |
|
|
||||||
| globalVars.c:9:7:9:11 | copy2 | globalVars.c:44:15:44:19 | copy2 |
|
|
||||||
| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 |
|
|
||||||
| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 |
|
|
||||||
| globalVars.c:11:22:11:25 | argv | globalVars.c:8:7:8:10 | copy |
|
|
||||||
| globalVars.c:11:22:11:25 | argv | globalVars.c:12:2:12:15 | ... = ... |
|
|
||||||
| globalVars.c:12:2:12:15 | ... = ... | globalVars.c:8:7:8:10 | copy |
|
|
||||||
| globalVars.c:15:21:15:23 | val | globalVars.c:9:7:9:11 | copy2 |
|
|
||||||
| globalVars.c:15:21:15:23 | val | globalVars.c:16:2:16:12 | ... = ... |
|
|
||||||
| globalVars.c:16:2:16:12 | ... = ... | globalVars.c:9:7:9:11 | copy2 |
|
|
||||||
| globalVars.c:24:11:24:14 | argv | globalVars.c:11:22:11:25 | argv |
|
|
||||||
| globalVars.c:24:11:24:14 | argv | globalVars.c:11:22:11:25 | argv |
|
|
||||||
| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy |
|
|
||||||
| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy |
|
|
||||||
| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy |
|
|
||||||
| globalVars.c:30:15:30:18 | copy | globalVars.c:35:11:35:14 | copy |
|
|
||||||
| globalVars.c:33:15:33:18 | copy | globalVars.c:35:11:35:14 | copy |
|
|
||||||
| globalVars.c:35:11:35:14 | copy | globalVars.c:15:21:15:23 | val |
|
|
||||||
| globalVars.c:35:11:35:14 | copy | globalVars.c:35:11:35:14 | copy |
|
|
||||||
| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 |
|
|
||||||
| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 |
|
|
||||||
| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 |
|
|
||||||
| globalVars.c:41:15:41:19 | copy2 | globalVars.c:50:9:50:13 | copy2 |
|
|
||||||
| globalVars.c:41:15:41:19 | copy2 | globalVars.c:50:9:50:13 | copy2 |
|
|
||||||
| globalVars.c:44:15:44:19 | copy2 | globalVars.c:50:9:50:13 | copy2 |
|
|
||||||
| globalVars.c:44:15:44:19 | copy2 | globalVars.c:50:9:50:13 | copy2 |
|
|
||||||
subpaths
|
|
||||||
nodes
|
|
||||||
| globalVars.c:8:7:8:10 | copy | semmle.label | copy |
|
|
||||||
| globalVars.c:9:7:9:11 | copy2 | semmle.label | copy2 |
|
|
||||||
| globalVars.c:11:22:11:25 | argv | semmle.label | argv |
|
|
||||||
| globalVars.c:12:2:12:15 | ... = ... | semmle.label | ... = ... |
|
|
||||||
| globalVars.c:15:21:15:23 | val | semmle.label | val |
|
|
||||||
| globalVars.c:16:2:16:12 | ... = ... | semmle.label | ... = ... |
|
|
||||||
| globalVars.c:24:11:24:14 | argv | semmle.label | argv |
|
|
||||||
| globalVars.c:24:11:24:14 | argv | semmle.label | argv |
|
|
||||||
| globalVars.c:27:9:27:12 | copy | semmle.label | copy |
|
|
||||||
| globalVars.c:27:9:27:12 | copy | semmle.label | copy |
|
|
||||||
| globalVars.c:30:15:30:18 | copy | semmle.label | copy |
|
|
||||||
| globalVars.c:30:15:30:18 | copy | semmle.label | copy |
|
|
||||||
| globalVars.c:30:15:30:18 | copy | semmle.label | copy |
|
|
||||||
| globalVars.c:33:15:33:18 | copy | semmle.label | copy |
|
|
||||||
| globalVars.c:35:11:35:14 | copy | semmle.label | copy |
|
|
||||||
| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 |
|
|
||||||
| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 |
|
|
||||||
| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 |
|
|
||||||
| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 |
|
|
||||||
| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 |
|
|
||||||
| globalVars.c:44:15:44:19 | copy2 | semmle.label | copy2 |
|
|
||||||
| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 |
|
|
||||||
| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 |
|
|
||||||
#select
|
|
||||||
| globalVars.c:27:9:27:12 | copy | globalVars.c:24:11:24:14 | argv | globalVars.c:27:9:27:12 | copy | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | globalVars.c:24:11:24:14 | argv | argv |
|
|
||||||
| globalVars.c:30:15:30:18 | copy | globalVars.c:24:11:24:14 | argv | globalVars.c:30:15:30:18 | copy | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(str), which calls printf(format). | globalVars.c:24:11:24:14 | argv | argv |
|
|
||||||
| globalVars.c:38:9:38:13 | copy2 | globalVars.c:24:11:24:14 | argv | globalVars.c:38:9:38:13 | copy2 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | globalVars.c:24:11:24:14 | argv | argv |
|
|
||||||
| globalVars.c:41:15:41:19 | copy2 | globalVars.c:24:11:24:14 | argv | globalVars.c:41:15:41:19 | copy2 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(str), which calls printf(format). | globalVars.c:24:11:24:14 | argv | argv |
|
|
||||||
| globalVars.c:50:9:50:13 | copy2 | globalVars.c:24:11:24:14 | argv | globalVars.c:50:9:50:13 | copy2 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | globalVars.c:24:11:24:14 | argv | argv |
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql
|
|
||||||
@@ -1,13 +1,8 @@
|
|||||||
edges
|
edges
|
||||||
| examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data |
|
|
||||||
| examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data |
|
|
||||||
| examples.cpp:63:26:63:30 | fscanf output argument | examples.cpp:66:11:66:14 | data |
|
| examples.cpp:63:26:63:30 | fscanf output argument | examples.cpp:66:11:66:14 | data |
|
||||||
| examples.cpp:63:26:63:30 | fscanf output argument | examples.cpp:66:11:66:14 | data |
|
|
||||||
subpaths
|
|
||||||
nodes
|
nodes
|
||||||
| examples.cpp:63:26:63:30 | & ... | semmle.label | & ... |
|
|
||||||
| examples.cpp:63:26:63:30 | fscanf output argument | semmle.label | fscanf output argument |
|
| examples.cpp:63:26:63:30 | fscanf output argument | semmle.label | fscanf output argument |
|
||||||
| examples.cpp:66:11:66:14 | data | semmle.label | data |
|
| examples.cpp:66:11:66:14 | data | semmle.label | data |
|
||||||
| examples.cpp:66:11:66:14 | data | semmle.label | data |
|
subpaths
|
||||||
#select
|
#select
|
||||||
| examples.cpp:66:11:66:14 | data | examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | examples.cpp:63:26:63:30 | & ... | User-provided value |
|
| examples.cpp:66:11:66:14 | data | examples.cpp:63:26:63:30 | fscanf output argument | examples.cpp:66:11:66:14 | data | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | examples.cpp:63:26:63:30 | fscanf output argument | value read by fscanf |
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
| examples.cpp:66:9:66:14 | -- ... | $@ flows an expression which might overflow negatively. | examples.cpp:63:26:63:30 | & ... | User-provided value |
|
| examples.cpp:66:9:66:14 | -- ... | $@ flows an expression which might overflow negatively. | examples.cpp:63:26:63:30 | fscanf output argument | value read by fscanf |
|
||||||
|
|||||||
@@ -1,86 +1,59 @@
|
|||||||
edges
|
edges
|
||||||
| test2.cpp:12:21:12:21 | v | test2.cpp:14:11:14:11 | v |
|
| test2.cpp:12:21:12:21 | v | test2.cpp:14:11:14:11 | v |
|
||||||
| test2.cpp:12:21:12:21 | v | test2.cpp:14:11:14:11 | v |
|
|
||||||
| test2.cpp:25:22:25:23 | & ... | test2.cpp:27:13:27:13 | v |
|
|
||||||
| test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:27:13:27:13 | v |
|
| test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:27:13:27:13 | v |
|
||||||
| test2.cpp:27:13:27:13 | v | test2.cpp:12:21:12:21 | v |
|
| test2.cpp:27:13:27:13 | v | test2.cpp:12:21:12:21 | v |
|
||||||
| test2.cpp:36:9:36:14 | buffer | test2.cpp:39:9:39:11 | num |
|
|
||||||
| test2.cpp:36:9:36:14 | buffer | test2.cpp:39:9:39:11 | num |
|
|
||||||
| test2.cpp:36:9:36:14 | buffer | test2.cpp:39:9:39:11 | num |
|
|
||||||
| test2.cpp:36:9:36:14 | buffer | test2.cpp:39:9:39:11 | num |
|
|
||||||
| test2.cpp:36:9:36:14 | buffer | test2.cpp:40:3:40:5 | num |
|
|
||||||
| test2.cpp:36:9:36:14 | buffer | test2.cpp:40:3:40:5 | num |
|
|
||||||
| test2.cpp:36:9:36:14 | buffer | test2.cpp:40:3:40:5 | num |
|
|
||||||
| test2.cpp:36:9:36:14 | buffer | test2.cpp:40:3:40:5 | num |
|
|
||||||
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:39:9:39:11 | num |
|
|
||||||
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:39:9:39:11 | num |
|
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:39:9:39:11 | num |
|
||||||
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:40:3:40:5 | num |
|
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:40:3:40:5 | num |
|
||||||
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:40:3:40:5 | num |
|
| test3.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections |
|
||||||
| test5.cpp:5:5:5:17 | getTaintedInt indirection | test5.cpp:17:6:17:18 | call to getTaintedInt |
|
| test3.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 |
|
||||||
|
| test3.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 |
|
||||||
| test5.cpp:5:5:5:17 | getTaintedInt indirection | test5.cpp:17:6:17:18 | call to getTaintedInt |
|
| test5.cpp:5:5:5:17 | getTaintedInt indirection | test5.cpp:17:6:17:18 | call to getTaintedInt |
|
||||||
| test5.cpp:5:5:5:17 | getTaintedInt indirection | test5.cpp:18:6:18:18 | call to getTaintedInt |
|
| test5.cpp:5:5:5:17 | getTaintedInt indirection | test5.cpp:18:6:18:18 | call to getTaintedInt |
|
||||||
| test5.cpp:9:7:9:9 | buf | test5.cpp:5:5:5:17 | getTaintedInt indirection |
|
|
||||||
| test5.cpp:9:7:9:9 | buf | test5.cpp:5:5:5:17 | getTaintedInt indirection |
|
|
||||||
| test5.cpp:9:7:9:9 | gets output argument | test5.cpp:5:5:5:17 | getTaintedInt indirection |
|
| test5.cpp:9:7:9:9 | gets output argument | test5.cpp:5:5:5:17 | getTaintedInt indirection |
|
||||||
| test5.cpp:18:6:18:18 | call to getTaintedInt | test5.cpp:19:6:19:6 | y |
|
| test5.cpp:18:6:18:18 | call to getTaintedInt | test5.cpp:19:6:19:6 | y |
|
||||||
| test5.cpp:18:6:18:18 | call to getTaintedInt | test5.cpp:19:6:19:6 | y |
|
| test.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections |
|
||||||
| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
|
| test.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 |
|
||||||
| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
|
| test.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 |
|
||||||
| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
|
|
||||||
| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
|
|
||||||
| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
|
|
||||||
| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
|
|
||||||
| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
|
|
||||||
| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
|
|
||||||
| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
|
|
||||||
| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
|
|
||||||
| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
|
|
||||||
| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
|
|
||||||
subpaths
|
|
||||||
nodes
|
nodes
|
||||||
| test2.cpp:12:21:12:21 | v | semmle.label | v |
|
| test2.cpp:12:21:12:21 | v | semmle.label | v |
|
||||||
| test2.cpp:14:11:14:11 | v | semmle.label | v |
|
| test2.cpp:14:11:14:11 | v | semmle.label | v |
|
||||||
| test2.cpp:14:11:14:11 | v | semmle.label | v |
|
|
||||||
| test2.cpp:25:22:25:23 | & ... | semmle.label | & ... |
|
|
||||||
| test2.cpp:25:22:25:23 | fscanf output argument | semmle.label | fscanf output argument |
|
| test2.cpp:25:22:25:23 | fscanf output argument | semmle.label | fscanf output argument |
|
||||||
| test2.cpp:27:13:27:13 | v | semmle.label | v |
|
| test2.cpp:27:13:27:13 | v | semmle.label | v |
|
||||||
| test2.cpp:36:9:36:14 | buffer | semmle.label | buffer |
|
|
||||||
| test2.cpp:36:9:36:14 | buffer | semmle.label | buffer |
|
|
||||||
| test2.cpp:36:9:36:14 | fgets output argument | semmle.label | fgets output argument |
|
| test2.cpp:36:9:36:14 | fgets output argument | semmle.label | fgets output argument |
|
||||||
| test2.cpp:39:9:39:11 | num | semmle.label | num |
|
| test2.cpp:39:9:39:11 | num | semmle.label | num |
|
||||||
| test2.cpp:39:9:39:11 | num | semmle.label | num |
|
|
||||||
| test2.cpp:40:3:40:5 | num | semmle.label | num |
|
|
||||||
| test2.cpp:40:3:40:5 | num | semmle.label | num |
|
| test2.cpp:40:3:40:5 | num | semmle.label | num |
|
||||||
|
| test3.c:10:27:10:30 | argv indirection | semmle.label | argv indirection |
|
||||||
| test5.cpp:5:5:5:17 | getTaintedInt indirection | semmle.label | getTaintedInt indirection |
|
| test5.cpp:5:5:5:17 | getTaintedInt indirection | semmle.label | getTaintedInt indirection |
|
||||||
| test5.cpp:9:7:9:9 | buf | semmle.label | buf |
|
|
||||||
| test5.cpp:9:7:9:9 | buf | semmle.label | buf |
|
|
||||||
| test5.cpp:9:7:9:9 | gets output argument | semmle.label | gets output argument |
|
| test5.cpp:9:7:9:9 | gets output argument | semmle.label | gets output argument |
|
||||||
| test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
|
| test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
|
||||||
| test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
|
|
||||||
| test5.cpp:18:6:18:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
|
| test5.cpp:18:6:18:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
|
||||||
| test5.cpp:19:6:19:6 | y | semmle.label | y |
|
| test5.cpp:19:6:19:6 | y | semmle.label | y |
|
||||||
| test5.cpp:19:6:19:6 | y | semmle.label | y |
|
| test.c:10:27:10:30 | argv indirection | semmle.label | argv indirection |
|
||||||
| test.c:11:29:11:32 | argv | semmle.label | argv |
|
|
||||||
| test.c:11:29:11:32 | argv | semmle.label | argv |
|
|
||||||
| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
|
| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
|
||||||
| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
|
|
||||||
| test.c:41:17:41:20 | argv | semmle.label | argv |
|
|
||||||
| test.c:41:17:41:20 | argv | semmle.label | argv |
|
|
||||||
| test.c:44:7:44:10 | len2 | semmle.label | len2 |
|
| test.c:44:7:44:10 | len2 | semmle.label | len2 |
|
||||||
| test.c:44:7:44:10 | len2 | semmle.label | len2 |
|
|
||||||
| test.c:51:17:51:20 | argv | semmle.label | argv |
|
|
||||||
| test.c:51:17:51:20 | argv | semmle.label | argv |
|
|
||||||
| test.c:54:7:54:10 | len3 | semmle.label | len3 |
|
|
||||||
| test.c:54:7:54:10 | len3 | semmle.label | len3 |
|
| test.c:54:7:54:10 | len3 | semmle.label | len3 |
|
||||||
|
subpaths
|
||||||
#select
|
#select
|
||||||
| test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | & ... | test2.cpp:14:11:14:11 | v | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
|
| test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:14:11:14:11 | v | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf |
|
||||||
| test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | & ... | test2.cpp:14:11:14:11 | v | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
|
| test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:14:11:14:11 | v | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf |
|
||||||
| test2.cpp:39:9:39:11 | num | test2.cpp:36:9:36:14 | buffer | test2.cpp:39:9:39:11 | num | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:36:9:36:14 | buffer | User-provided value |
|
| test2.cpp:39:9:39:11 | num | test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:39:9:39:11 | num | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:36:9:36:14 | fgets output argument | string read by fgets |
|
||||||
| test2.cpp:40:3:40:5 | num | test2.cpp:36:9:36:14 | buffer | test2.cpp:40:3:40:5 | num | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:36:9:36:14 | buffer | User-provided value |
|
| test2.cpp:40:3:40:5 | num | test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:40:3:40:5 | num | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:36:9:36:14 | fgets output argument | string read by fgets |
|
||||||
| test5.cpp:17:6:17:18 | call to getTaintedInt | test5.cpp:9:7:9:9 | buf | test5.cpp:17:6:17:18 | call to getTaintedInt | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
|
| test5.cpp:17:6:17:18 | call to getTaintedInt | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:17:6:17:18 | call to getTaintedInt | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||||
| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | buf | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
|
| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||||
| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | buf | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
|
| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||||
| test.c:14:15:14:28 | maxConnections | test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test.c:11:29:11:32 | argv | User-provided value |
|
| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
| test.c:14:15:14:28 | maxConnections | test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:11:29:11:32 | argv | User-provided value |
|
| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
| test.c:44:7:44:10 | len2 | test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:41:17:41:20 | argv | User-provided value |
|
| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
| test.c:54:7:54:10 | len3 | test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:51:17:51:20 | argv | User-provided value |
|
| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:44:7:44:10 | len2 | test3.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:44:7:44:10 | len2 | test3.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:44:7:44:10 | len2 | test.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:44:7:44:10 | len2 | test.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:54:7:54:10 | len3 | test3.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:54:7:54:10 | len3 | test3.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:54:7:54:10 | len3 | test.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:54:7:54:10 | len3 | test.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
|||||||
@@ -1,18 +1,23 @@
|
|||||||
| test2.cpp:14:11:14:15 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
|
| test2.cpp:14:11:14:15 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf |
|
||||||
| test2.cpp:15:11:15:19 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
|
| test2.cpp:15:11:15:19 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf |
|
||||||
| test2.cpp:16:11:16:21 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
|
| test2.cpp:16:11:16:21 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf |
|
||||||
| test2.cpp:17:11:17:22 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
|
| test2.cpp:17:11:17:22 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf |
|
||||||
| test2.cpp:39:9:39:18 | ... + ... | $@ flows an expression which might overflow. | test2.cpp:36:9:36:14 | buffer | User-provided value |
|
| test2.cpp:39:9:39:18 | ... + ... | $@ flows an expression which might overflow. | test2.cpp:36:9:36:14 | fgets output argument | string read by fgets |
|
||||||
| test2.cpp:40:3:40:13 | ... += ... | $@ flows an expression which might overflow. | test2.cpp:36:9:36:14 | buffer | User-provided value |
|
| test2.cpp:40:3:40:13 | ... += ... | $@ flows an expression which might overflow. | test2.cpp:36:9:36:14 | fgets output argument | string read by fgets |
|
||||||
| test3.c:12:31:12:34 | * ... | $@ flows an expression which might overflow negatively. | test3.c:11:15:11:18 | argv | User-provided value |
|
| test3.c:12:11:12:34 | * ... | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
| test3.c:13:16:13:19 | * ... | $@ flows an expression which might overflow negatively. | test3.c:11:15:11:18 | argv | User-provided value |
|
| test3.c:12:11:12:34 | * ... | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
| test4.cpp:13:17:13:20 | access to array | $@ flows an expression which might overflow negatively. | test4.cpp:9:13:9:16 | argv | User-provided value |
|
| test3.c:13:11:13:20 | * ... | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
| test5.cpp:10:9:10:15 | call to strtoul | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
|
| test3.c:13:11:13:20 | * ... | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
| test5.cpp:17:6:17:27 | ... * ... | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
|
| test4.cpp:13:7:13:20 | access to array | $@ flows an expression which might overflow negatively. | test4.cpp:8:27:8:30 | argv indirection | a command-line argument |
|
||||||
| test5.cpp:19:6:19:13 | ... * ... | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
|
| test5.cpp:10:9:10:27 | call to strtoul | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||||
| test6.cpp:11:15:11:15 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | & ... | User-provided value |
|
| test5.cpp:17:6:17:27 | ... * ... | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||||
| test6.cpp:16:15:16:15 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | & ... | User-provided value |
|
| test5.cpp:19:6:19:13 | ... * ... | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||||
| test6.cpp:30:16:30:16 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | & ... | User-provided value |
|
| test6.cpp:11:10:11:15 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | fscanf output argument | value read by fscanf |
|
||||||
| test.c:14:15:14:35 | ... * ... | $@ flows an expression which might overflow. | test.c:11:29:11:32 | argv | User-provided value |
|
| test6.cpp:16:10:16:15 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | fscanf output argument | value read by fscanf |
|
||||||
| test.c:44:7:44:12 | ... -- | $@ flows an expression which might overflow negatively. | test.c:41:17:41:20 | argv | User-provided value |
|
| test6.cpp:30:11:30:16 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | fscanf output argument | value read by fscanf |
|
||||||
| test.c:54:7:54:12 | ... -- | $@ flows an expression which might overflow negatively. | test.c:51:17:51:20 | argv | User-provided value |
|
| test.c:14:15:14:35 | ... * ... | $@ flows an expression which might overflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:14:15:14:35 | ... * ... | $@ flows an expression which might overflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:44:7:44:12 | ... -- | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:44:7:44:12 | ... -- | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:54:7:54:12 | ... -- | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
| test.c:54:7:54:12 | ... -- | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||||
|
|||||||
@@ -22,16 +22,10 @@ edges
|
|||||||
| test.cpp:52:19:52:37 | call to malloc | test.cpp:53:12:53:23 | ... + ... |
|
| test.cpp:52:19:52:37 | call to malloc | test.cpp:53:12:53:23 | ... + ... |
|
||||||
| test.cpp:53:12:53:23 | ... + ... | test.cpp:51:33:51:35 | end |
|
| test.cpp:53:12:53:23 | ... + ... | test.cpp:51:33:51:35 | end |
|
||||||
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:67:9:67:14 | ... = ... |
|
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:67:9:67:14 | ... = ... |
|
||||||
| test.cpp:194:15:194:33 | call to malloc | test.cpp:195:17:195:23 | ... + ... |
|
|
||||||
| test.cpp:195:17:195:23 | ... + ... | test.cpp:195:17:195:23 | ... + ... |
|
|
||||||
| test.cpp:195:17:195:23 | ... + ... | test.cpp:201:5:201:19 | ... = ... |
|
|
||||||
| test.cpp:195:17:195:23 | ... + ... | test.cpp:201:5:201:19 | ... = ... |
|
|
||||||
| test.cpp:205:15:205:33 | call to malloc | test.cpp:206:17:206:23 | ... + ... |
|
| test.cpp:205:15:205:33 | call to malloc | test.cpp:206:17:206:23 | ... + ... |
|
||||||
| test.cpp:206:17:206:23 | ... + ... | test.cpp:206:17:206:23 | ... + ... |
|
| test.cpp:206:17:206:23 | ... + ... | test.cpp:206:17:206:23 | ... + ... |
|
||||||
| test.cpp:206:17:206:23 | ... + ... | test.cpp:213:5:213:13 | ... = ... |
|
| test.cpp:206:17:206:23 | ... + ... | test.cpp:213:5:213:13 | ... = ... |
|
||||||
| test.cpp:206:17:206:23 | ... + ... | test.cpp:213:5:213:13 | ... = ... |
|
| test.cpp:206:17:206:23 | ... + ... | test.cpp:213:5:213:13 | ... = ... |
|
||||||
| test.cpp:231:18:231:30 | new[] | test.cpp:232:3:232:20 | ... = ... |
|
|
||||||
| test.cpp:238:20:238:32 | new[] | test.cpp:239:5:239:22 | ... = ... |
|
|
||||||
| test.cpp:260:13:260:24 | new[] | test.cpp:261:14:261:21 | ... + ... |
|
| test.cpp:260:13:260:24 | new[] | test.cpp:261:14:261:21 | ... + ... |
|
||||||
| test.cpp:261:14:261:21 | ... + ... | test.cpp:261:14:261:21 | ... + ... |
|
| test.cpp:261:14:261:21 | ... + ... | test.cpp:261:14:261:21 | ... + ... |
|
||||||
| test.cpp:261:14:261:21 | ... + ... | test.cpp:264:13:264:14 | * ... |
|
| test.cpp:261:14:261:21 | ... + ... | test.cpp:264:13:264:14 | * ... |
|
||||||
@@ -127,18 +121,10 @@ nodes
|
|||||||
| test.cpp:53:12:53:23 | ... + ... | semmle.label | ... + ... |
|
| test.cpp:53:12:53:23 | ... + ... | semmle.label | ... + ... |
|
||||||
| test.cpp:60:34:60:37 | mk_array output argument | semmle.label | mk_array output argument |
|
| test.cpp:60:34:60:37 | mk_array output argument | semmle.label | mk_array output argument |
|
||||||
| test.cpp:67:9:67:14 | ... = ... | semmle.label | ... = ... |
|
| test.cpp:67:9:67:14 | ... = ... | semmle.label | ... = ... |
|
||||||
| test.cpp:194:15:194:33 | call to malloc | semmle.label | call to malloc |
|
|
||||||
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
|
|
||||||
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
|
|
||||||
| test.cpp:201:5:201:19 | ... = ... | semmle.label | ... = ... |
|
|
||||||
| test.cpp:205:15:205:33 | call to malloc | semmle.label | call to malloc |
|
| test.cpp:205:15:205:33 | call to malloc | semmle.label | call to malloc |
|
||||||
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
|
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
|
||||||
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
|
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
|
||||||
| test.cpp:213:5:213:13 | ... = ... | semmle.label | ... = ... |
|
| test.cpp:213:5:213:13 | ... = ... | semmle.label | ... = ... |
|
||||||
| test.cpp:231:18:231:30 | new[] | semmle.label | new[] |
|
|
||||||
| test.cpp:232:3:232:20 | ... = ... | semmle.label | ... = ... |
|
|
||||||
| test.cpp:238:20:238:32 | new[] | semmle.label | new[] |
|
|
||||||
| test.cpp:239:5:239:22 | ... = ... | semmle.label | ... = ... |
|
|
||||||
| test.cpp:260:13:260:24 | new[] | semmle.label | new[] |
|
| test.cpp:260:13:260:24 | new[] | semmle.label | new[] |
|
||||||
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
|
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
|
||||||
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
|
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
|
||||||
@@ -220,10 +206,7 @@ subpaths
|
|||||||
| test.cpp:30:14:30:15 | * ... | test.cpp:28:15:28:37 | call to malloc | test.cpp:30:14:30:15 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:28:15:28:37 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
|
| test.cpp:30:14:30:15 | * ... | test.cpp:28:15:28:37 | call to malloc | test.cpp:30:14:30:15 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:28:15:28:37 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
|
||||||
| test.cpp:32:14:32:21 | * ... | test.cpp:28:15:28:37 | call to malloc | test.cpp:32:14:32:21 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:28:15:28:37 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
|
| test.cpp:32:14:32:21 | * ... | test.cpp:28:15:28:37 | call to malloc | test.cpp:32:14:32:21 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:28:15:28:37 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
|
||||||
| test.cpp:67:9:67:14 | ... = ... | test.cpp:52:19:52:37 | call to malloc | test.cpp:67:9:67:14 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:52:19:52:37 | call to malloc | call to malloc | test.cpp:53:20:53:23 | size | size |
|
| test.cpp:67:9:67:14 | ... = ... | test.cpp:52:19:52:37 | call to malloc | test.cpp:67:9:67:14 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:52:19:52:37 | call to malloc | call to malloc | test.cpp:53:20:53:23 | size | size |
|
||||||
| test.cpp:201:5:201:19 | ... = ... | test.cpp:194:15:194:33 | call to malloc | test.cpp:201:5:201:19 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:194:15:194:33 | call to malloc | call to malloc | test.cpp:195:21:195:23 | len | len |
|
|
||||||
| test.cpp:213:5:213:13 | ... = ... | test.cpp:205:15:205:33 | call to malloc | test.cpp:213:5:213:13 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:205:15:205:33 | call to malloc | call to malloc | test.cpp:206:21:206:23 | len | len |
|
| test.cpp:213:5:213:13 | ... = ... | test.cpp:205:15:205:33 | call to malloc | test.cpp:213:5:213:13 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:205:15:205:33 | call to malloc | call to malloc | test.cpp:206:21:206:23 | len | len |
|
||||||
| test.cpp:232:3:232:20 | ... = ... | test.cpp:231:18:231:30 | new[] | test.cpp:232:3:232:20 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:231:18:231:30 | new[] | new[] | test.cpp:232:11:232:15 | index | index |
|
|
||||||
| test.cpp:239:5:239:22 | ... = ... | test.cpp:238:20:238:32 | new[] | test.cpp:239:5:239:22 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:238:20:238:32 | new[] | new[] | test.cpp:239:13:239:17 | index | index |
|
|
||||||
| test.cpp:264:13:264:14 | * ... | test.cpp:260:13:260:24 | new[] | test.cpp:264:13:264:14 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:260:13:260:24 | new[] | new[] | test.cpp:261:19:261:21 | len | len |
|
| test.cpp:264:13:264:14 | * ... | test.cpp:260:13:260:24 | new[] | test.cpp:264:13:264:14 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:260:13:260:24 | new[] | new[] | test.cpp:261:19:261:21 | len | len |
|
||||||
| test.cpp:274:5:274:10 | ... = ... | test.cpp:270:13:270:24 | new[] | test.cpp:274:5:274:10 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:270:13:270:24 | new[] | new[] | test.cpp:271:19:271:21 | len | len |
|
| test.cpp:274:5:274:10 | ... = ... | test.cpp:270:13:270:24 | new[] | test.cpp:274:5:274:10 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:270:13:270:24 | new[] | new[] | test.cpp:271:19:271:21 | len | len |
|
||||||
| test.cpp:358:14:358:26 | end_plus_one indirection | test.cpp:355:14:355:27 | new[] | test.cpp:358:14:358:26 | end_plus_one indirection | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size |
|
| test.cpp:358:14:358:26 | end_plus_one indirection | test.cpp:355:14:355:27 | new[] | test.cpp:358:14:358:26 | end_plus_one indirection | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size |
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ void test12(unsigned len, unsigned index) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
p[index] = '\0'; // $ deref=L195->L201 // BAD
|
p[index] = '\0'; // $ MISSING: deref=L195->L201 // BAD [NOT DETECTED]
|
||||||
}
|
}
|
||||||
|
|
||||||
void test13(unsigned len, unsigned index) {
|
void test13(unsigned len, unsigned index) {
|
||||||
@@ -229,14 +229,14 @@ void test15(unsigned index) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int* newname = new int[size];
|
int* newname = new int[size];
|
||||||
newname[index] = 0; // $ alloc=L231 deref=L232 // GOOD [FALSE POSITIVE]
|
newname[index] = 0; // GOOD
|
||||||
}
|
}
|
||||||
|
|
||||||
void test16(unsigned index) {
|
void test16(unsigned index) {
|
||||||
unsigned size = index + 13;
|
unsigned size = index + 13;
|
||||||
if(size >= index) {
|
if(size >= index) {
|
||||||
int* newname = new int[size];
|
int* newname = new int[size];
|
||||||
newname[index] = 0; // $ alloc=L238 deref=L239 // GOOD [FALSE POSITIVE]
|
newname[index] = 0; // GOOD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
| tests.cpp:38:31:38:34 | data | $@ flows an expression which might overflow. | tests.cpp:57:27:57:31 | & ... | User-provided value |
|
| tests.cpp:38:25:38:34 | data | $@ flows an expression which might overflow. | tests.cpp:57:27:57:31 | fscanf output argument | value read by fscanf |
|
||||||
|
|||||||
@@ -1,14 +1,7 @@
|
|||||||
| test.cpp:12:6:12:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:11:6:11:8 | foo | foo |
|
| test.cpp:12:6:12:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:11:6:11:8 | foo | foo |
|
||||||
| test.cpp:30:6:30:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:26:6:26:8 | foo | foo |
|
|
||||||
| test.cpp:46:6:46:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:42:6:42:8 | foo | foo |
|
|
||||||
| test.cpp:55:7:55:9 | foo | The variable $@ may not be initialized at this access. | test.cpp:50:6:50:8 | foo | foo |
|
|
||||||
| test.cpp:67:7:67:9 | foo | The variable $@ may not be initialized at this access. | test.cpp:61:6:61:8 | foo | foo |
|
|
||||||
| test.cpp:92:6:92:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:82:6:82:8 | foo | foo |
|
|
||||||
| test.cpp:113:6:113:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:111:6:111:8 | foo | foo |
|
| test.cpp:113:6:113:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:111:6:111:8 | foo | foo |
|
||||||
| test.cpp:132:9:132:9 | j | The variable $@ may not be initialized at this access. | test.cpp:126:6:126:6 | j | j |
|
|
||||||
| test.cpp:219:3:219:3 | x | The variable $@ may not be initialized at this access. | test.cpp:218:7:218:7 | x | x |
|
| test.cpp:219:3:219:3 | x | The variable $@ may not be initialized at this access. | test.cpp:218:7:218:7 | x | x |
|
||||||
| test.cpp:243:13:243:13 | i | The variable $@ may not be initialized at this access. | test.cpp:241:6:241:6 | i | i |
|
| test.cpp:243:13:243:13 | i | The variable $@ may not be initialized at this access. | test.cpp:241:6:241:6 | i | i |
|
||||||
| test.cpp:329:9:329:11 | val | The variable $@ may not be initialized at this access. | test.cpp:321:6:321:8 | val | val |
|
|
||||||
| test.cpp:336:10:336:10 | a | The variable $@ may not be initialized at this access. | test.cpp:333:7:333:7 | a | a |
|
| test.cpp:336:10:336:10 | a | The variable $@ may not be initialized at this access. | test.cpp:333:7:333:7 | a | a |
|
||||||
| test.cpp:369:10:369:10 | a | The variable $@ may not be initialized at this access. | test.cpp:358:7:358:7 | a | a |
|
| test.cpp:369:10:369:10 | a | The variable $@ may not be initialized at this access. | test.cpp:358:7:358:7 | a | a |
|
||||||
| test.cpp:378:9:378:11 | val | The variable $@ may not be initialized at this access. | test.cpp:359:6:359:8 | val | val |
|
| test.cpp:378:9:378:11 | val | The variable $@ may not be initialized at this access. | test.cpp:359:6:359:8 | val | val |
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ void test4(bool b) {
|
|||||||
if (b) {
|
if (b) {
|
||||||
foo = 1;
|
foo = 1;
|
||||||
}
|
}
|
||||||
use(foo); // BAD
|
use(foo); // BAD [NOT DETECTED]
|
||||||
}
|
}
|
||||||
|
|
||||||
void test5() {
|
void test5() {
|
||||||
@@ -43,7 +43,7 @@ void test5(int count) {
|
|||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
foo = i;
|
foo = i;
|
||||||
}
|
}
|
||||||
use(foo); // BAD
|
use(foo); // BAD [NOT DETECTED]
|
||||||
}
|
}
|
||||||
|
|
||||||
void test6(bool b) {
|
void test6(bool b) {
|
||||||
@@ -52,7 +52,7 @@ void test6(bool b) {
|
|||||||
foo = 42;
|
foo = 42;
|
||||||
}
|
}
|
||||||
if (b) {
|
if (b) {
|
||||||
use(foo); // GOOD (REPORTED, FP)
|
use(foo); // GOOD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ void test7(bool b) {
|
|||||||
set = true;
|
set = true;
|
||||||
}
|
}
|
||||||
if (set) {
|
if (set) {
|
||||||
use(foo); // GOOD (REPORTED, FP)
|
use(foo); // GOOD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ void test9(int count) {
|
|||||||
if (!set) {
|
if (!set) {
|
||||||
foo = 42;
|
foo = 42;
|
||||||
}
|
}
|
||||||
use(foo); // GOOD (REPORTED, FP)
|
use(foo); // GOOD
|
||||||
}
|
}
|
||||||
|
|
||||||
void test10() {
|
void test10() {
|
||||||
@@ -129,7 +129,7 @@ int absWrong(int i) {
|
|||||||
} else if (i < 0) {
|
} else if (i < 0) {
|
||||||
j = -i;
|
j = -i;
|
||||||
}
|
}
|
||||||
return j; // wrong: j may not be initialized before use
|
return j; // wrong: j may not be initialized before use [NOT DETECTED]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example from qhelp
|
// Example from qhelp
|
||||||
@@ -326,7 +326,7 @@ int test28() {
|
|||||||
a = false;
|
a = false;
|
||||||
c = false;
|
c = false;
|
||||||
}
|
}
|
||||||
return val; // GOOD [FALSE POSITIVE]
|
return val; // GOOD
|
||||||
}
|
}
|
||||||
|
|
||||||
int test29() {
|
int test29() {
|
||||||
@@ -472,4 +472,64 @@ void test44() {
|
|||||||
int y = 1;
|
int y = 1;
|
||||||
|
|
||||||
void(x + y); // BAD
|
void(x + y); // BAD
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class State { StateA, StateB, StateC };
|
||||||
|
|
||||||
|
int exhaustive_switch(State s) {
|
||||||
|
int y;
|
||||||
|
switch(s) {
|
||||||
|
case State::StateA:
|
||||||
|
y = 1;
|
||||||
|
break;
|
||||||
|
case State::StateB:
|
||||||
|
y = 2;
|
||||||
|
break;
|
||||||
|
case State::StateC:
|
||||||
|
y = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return y; // GOOD (y is always initialized)
|
||||||
|
}
|
||||||
|
|
||||||
|
int exhaustive_switch_2(State s) {
|
||||||
|
int y;
|
||||||
|
switch(s) {
|
||||||
|
case State::StateA:
|
||||||
|
y = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
y = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return y; // GOOD (y is always initialized)
|
||||||
|
}
|
||||||
|
|
||||||
|
int non_exhaustive_switch(State s) {
|
||||||
|
int y;
|
||||||
|
switch(s) {
|
||||||
|
case State::StateA:
|
||||||
|
y = 1;
|
||||||
|
break;
|
||||||
|
case State::StateB:
|
||||||
|
y = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return y; // BAD [NOT DETECTED] (y is not initialized when s = StateC)
|
||||||
|
}
|
||||||
|
|
||||||
|
int non_exhaustive_switch_2(State s) {
|
||||||
|
int y;
|
||||||
|
switch(s) {
|
||||||
|
case State::StateA:
|
||||||
|
y = 1;
|
||||||
|
break;
|
||||||
|
case State::StateB:
|
||||||
|
y = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(s != State::StateC) {
|
||||||
|
return y; // GOOD (y is not initialized when s = StateC, but if s = StateC we won't reach this point)
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -159,9 +159,9 @@ namespace Semmle.Autobuild.CSharp.Tests
|
|||||||
|
|
||||||
bool IBuildActions.IsMacOs() => IsMacOs;
|
bool IBuildActions.IsMacOs() => IsMacOs;
|
||||||
|
|
||||||
public bool IsArm { get; set; }
|
public bool IsRunningOnAppleSilicon { get; set; }
|
||||||
|
|
||||||
bool IBuildActions.IsArm() => IsArm;
|
bool IBuildActions.IsRunningOnAppleSilicon() => IsRunningOnAppleSilicon;
|
||||||
|
|
||||||
public string PathCombine(params string[] parts)
|
public string PathCombine(params string[] parts)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using Semmle.Util;
|
using Semmle.Util;
|
||||||
@@ -119,10 +120,10 @@ namespace Semmle.Autobuild.Shared
|
|||||||
bool IsMacOs();
|
bool IsMacOs();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether we are running on arm.
|
/// Gets a value indicating whether we are running on Apple Silicon.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if we are running on arm.</returns>
|
/// <returns>True if we are running on Apple Silicon.</returns>
|
||||||
bool IsArm();
|
bool IsRunningOnAppleSilicon();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Combine path segments, Path.Combine().
|
/// Combine path segments, Path.Combine().
|
||||||
@@ -240,9 +241,25 @@ namespace Semmle.Autobuild.Shared
|
|||||||
|
|
||||||
bool IBuildActions.IsMacOs() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
bool IBuildActions.IsMacOs() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||||
|
|
||||||
bool IBuildActions.IsArm() =>
|
bool IBuildActions.IsRunningOnAppleSilicon()
|
||||||
RuntimeInformation.ProcessArchitecture == Architecture.Arm64 ||
|
{
|
||||||
RuntimeInformation.ProcessArchitecture == Architecture.Arm;
|
var thisBuildActions = (IBuildActions)this;
|
||||||
|
|
||||||
|
if (!thisBuildActions.IsMacOs())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
thisBuildActions.RunProcess("sysctl", "machdep.cpu.brand_string", workingDirectory: null, env: null, out var stdOut);
|
||||||
|
return stdOut?.Any(s => s?.ToLowerInvariant().Contains("apple") == true) ?? false;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string IBuildActions.PathCombine(params string[] parts) => Path.Combine(parts);
|
string IBuildActions.PathCombine(params string[] parts) => Path.Combine(parts);
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user