mirror of
https://github.com/github/codeql.git
synced 2025-12-23 04:06:37 +01:00
Merge tag 'codeql-cli/latest'
Compatible with the latest released version of the CodeQL CLI
This commit is contained in:
@@ -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
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
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
|
||||
version: 0.11.0
|
||||
version: 0.12.0
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -31,6 +31,11 @@ abstract class MustFlowConfiguration extends string {
|
||||
*/
|
||||
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
|
||||
* into account in the analysis.
|
||||
@@ -48,18 +53,21 @@ abstract class MustFlowConfiguration extends string {
|
||||
*/
|
||||
final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) {
|
||||
this.isSource(source.getInstruction()) and
|
||||
source.getASuccessor+() = sink
|
||||
source.getASuccessor*() = sink
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `node` flows from a source. */
|
||||
pragma[nomagic]
|
||||
private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) {
|
||||
config.isSource(node)
|
||||
or
|
||||
exists(Instruction mid |
|
||||
step(mid, node, config) and
|
||||
flowsFromSource(mid, pragma[only_bind_into](config))
|
||||
not config.isBarrier(node) and
|
||||
(
|
||||
config.isSource(node)
|
||||
or
|
||||
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. */
|
||||
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. */
|
||||
string toStringImpl() {
|
||||
none() // overridden by subclasses
|
||||
@@ -131,9 +139,15 @@ abstract class InstructionNode0 extends Node0Impl {
|
||||
override DataFlowType getType() { result = getInstructionType(instr, _) }
|
||||
|
||||
override string toStringImpl() {
|
||||
// This predicate is overridden in subclasses. This default implementation
|
||||
// does not use `Instruction.toString` because that's expensive to compute.
|
||||
result = instr.getOpcode().toString()
|
||||
if instr.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
||||
then result = "this"
|
||||
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)) }
|
||||
@@ -173,7 +187,17 @@ abstract class OperandNode0 extends Node0Impl {
|
||||
|
||||
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)) }
|
||||
}
|
||||
@@ -632,20 +656,20 @@ predicate jumpStep(Node n1, Node n2) {
|
||||
v = globalUse.getVariable() and
|
||||
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
||||
|
|
||||
globalUse.getIndirectionIndex() = 1 and
|
||||
globalUse.getIndirection() = 1 and
|
||||
v = n2.asVariable()
|
||||
or
|
||||
v = n2.asIndirectVariable(globalUse.getIndirectionIndex())
|
||||
v = n2.asIndirectVariable(globalUse.getIndirection())
|
||||
)
|
||||
or
|
||||
exists(Ssa::GlobalDef globalDef |
|
||||
v = globalDef.getVariable() and
|
||||
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
||||
|
|
||||
globalDef.getIndirectionIndex() = 1 and
|
||||
globalDef.getIndirection() = 1 and
|
||||
v = n1.asVariable()
|
||||
or
|
||||
v = n1.asIndirectVariable(globalDef.getIndirectionIndex())
|
||||
v = n1.asIndirectVariable(globalDef.getIndirection())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -44,11 +44,12 @@ private newtype TIRDataFlowNode =
|
||||
TIndirectArgumentOutNode(ArgumentOperand operand, int indirectionIndex) {
|
||||
Ssa::isModifiableByCall(operand, indirectionIndex)
|
||||
} or
|
||||
TRawIndirectOperand(Operand op, int indirectionIndex) {
|
||||
Ssa::hasRawIndirectOperand(op, indirectionIndex)
|
||||
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
|
||||
Ssa::hasRawIndirectOperand(node.asOperand(), indirectionIndex)
|
||||
} or
|
||||
TRawIndirectInstruction(Instruction instr, int indirectionIndex) {
|
||||
Ssa::hasRawIndirectInstruction(instr, indirectionIndex)
|
||||
TRawIndirectInstruction0(Node0Impl node, int indirectionIndex) {
|
||||
not exists(node.asOperand()) and
|
||||
Ssa::hasRawIndirectInstruction(node.asInstruction(), indirectionIndex)
|
||||
} or
|
||||
TFinalParameterNode(Parameter p, int indirectionIndex) {
|
||||
exists(Ssa::FinalParameterUse use |
|
||||
@@ -431,6 +432,10 @@ private class Node0 extends Node, TNode0 {
|
||||
|
||||
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 predicate isGLValue() { node.isGLValue() }
|
||||
@@ -447,18 +452,6 @@ class InstructionNode extends Node0 {
|
||||
|
||||
/** Gets the instruction corresponding to this node. */
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -472,18 +465,6 @@ class OperandNode extends Node, Node0 {
|
||||
|
||||
/** Gets the operand corresponding to this node. */
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -918,48 +899,146 @@ Type getTypeImpl(Type t, int indirectionIndex) {
|
||||
result instanceof UnknownType
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* A node that represents the indirect value of an operand in the IR
|
||||
* after `index` number of loads.
|
||||
*/
|
||||
class RawIndirectOperand extends Node, TRawIndirectOperand {
|
||||
Operand operand;
|
||||
int indirectionIndex;
|
||||
private module RawIndirectNodes {
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* A node that represents the indirect value of an operand in the IR
|
||||
* after `index` number of loads.
|
||||
*/
|
||||
private class RawIndirectOperand0 extends Node, TRawIndirectOperand0 {
|
||||
Node0Impl node;
|
||||
int indirectionIndex;
|
||||
|
||||
RawIndirectOperand() { this = TRawIndirectOperand(operand, indirectionIndex) }
|
||||
RawIndirectOperand0() { this = TRawIndirectOperand0(node, indirectionIndex) }
|
||||
|
||||
/** Gets the underlying instruction. */
|
||||
Operand getOperand() { result = operand }
|
||||
/** Gets the underlying instruction. */
|
||||
Operand getOperand() { result = node.asOperand() }
|
||||
|
||||
/** Gets the underlying indirection index. */
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
/** Gets the underlying indirection index. */
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
override Declaration getFunction() { result = this.getOperand().getDef().getEnclosingFunction() }
|
||||
override Declaration getFunction() {
|
||||
result = this.getOperand().getDef().getEnclosingFunction()
|
||||
}
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override DataFlowType getType() {
|
||||
exists(int sub, DataFlowType type, boolean isGLValue |
|
||||
type = getOperandType(operand, isGLValue) and
|
||||
if isGLValue = true then sub = 1 else sub = 0
|
||||
|
|
||||
result = getTypeImpl(type.getUnspecifiedType(), indirectionIndex - sub)
|
||||
)
|
||||
override DataFlowType getType() {
|
||||
exists(int sub, DataFlowType type, boolean isGLValue |
|
||||
type = getOperandType(this.getOperand(), isGLValue) and
|
||||
if isGLValue = true then sub = 1 else sub = 0
|
||||
|
|
||||
result = getTypeImpl(type.getUnspecifiedType(), indirectionIndex - sub)
|
||||
)
|
||||
}
|
||||
|
||||
final override Location getLocationImpl() {
|
||||
if exists(this.getOperand().getLocation())
|
||||
then result = this.getOperand().getLocation()
|
||||
else result instanceof UnknownDefaultLocation
|
||||
}
|
||||
|
||||
override string toStringImpl() {
|
||||
result = operandNode(this.getOperand()).toStringImpl() + " indirection"
|
||||
}
|
||||
}
|
||||
|
||||
final override Location getLocationImpl() {
|
||||
if exists(this.getOperand().getLocation())
|
||||
then result = this.getOperand().getLocation()
|
||||
else result instanceof UnknownDefaultLocation
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* A node that represents the indirect value of an instruction in the IR
|
||||
* after `index` number of loads.
|
||||
*/
|
||||
private class RawIndirectInstruction0 extends Node, TRawIndirectInstruction0 {
|
||||
Node0Impl node;
|
||||
int indirectionIndex;
|
||||
|
||||
RawIndirectInstruction0() { this = TRawIndirectInstruction0(node, indirectionIndex) }
|
||||
|
||||
/** Gets the underlying instruction. */
|
||||
Instruction getInstruction() { result = node.asInstruction() }
|
||||
|
||||
/** Gets the underlying indirection index. */
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
override Declaration getFunction() { result = this.getInstruction().getEnclosingFunction() }
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override DataFlowType getType() {
|
||||
exists(int sub, DataFlowType type, boolean isGLValue |
|
||||
type = getInstructionType(this.getInstruction(), isGLValue) and
|
||||
if isGLValue = true then sub = 1 else sub = 0
|
||||
|
|
||||
result = getTypeImpl(type.getUnspecifiedType(), indirectionIndex - sub)
|
||||
)
|
||||
}
|
||||
|
||||
final override Location getLocationImpl() {
|
||||
if exists(this.getInstruction().getLocation())
|
||||
then result = this.getInstruction().getLocation()
|
||||
else result instanceof UnknownDefaultLocation
|
||||
}
|
||||
|
||||
override string toStringImpl() {
|
||||
result = instructionNode(this.getInstruction()).toStringImpl() + " indirection"
|
||||
}
|
||||
}
|
||||
|
||||
override string toStringImpl() {
|
||||
result = operandNode(this.getOperand()).toStringImpl() + " indirection"
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* A node that represents the indirect value of an operand in the IR
|
||||
* after a number of loads.
|
||||
*/
|
||||
class RawIndirectOperand extends Node {
|
||||
int indirectionIndex;
|
||||
Operand operand;
|
||||
|
||||
RawIndirectOperand() {
|
||||
exists(Node0Impl node | operand = node.asOperand() |
|
||||
this = TRawIndirectOperand0(node, indirectionIndex)
|
||||
or
|
||||
this = TRawIndirectInstruction0(node, indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the operand associated with this node. */
|
||||
Operand getOperand() { result = operand }
|
||||
|
||||
/** Gets the underlying indirection index. */
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* A node that represents the indirect value of an instruction in the IR
|
||||
* after a number of loads.
|
||||
*/
|
||||
class RawIndirectInstruction extends Node {
|
||||
int indirectionIndex;
|
||||
Instruction instr;
|
||||
|
||||
RawIndirectInstruction() {
|
||||
exists(Node0Impl node | instr = node.asInstruction() |
|
||||
this = TRawIndirectOperand0(node, indirectionIndex)
|
||||
or
|
||||
this = TRawIndirectInstruction0(node, indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the instruction associated with this node. */
|
||||
Instruction getInstruction() { result = instr }
|
||||
|
||||
/** Gets the underlying indirection index. */
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
}
|
||||
}
|
||||
|
||||
import RawIndirectNodes
|
||||
|
||||
/**
|
||||
* INTERNAL: do not use.
|
||||
*
|
||||
@@ -1021,48 +1100,6 @@ class UninitializedNode extends Node {
|
||||
LocalVariable getLocalVariable() { result = v }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* A node that represents the indirect value of an instruction in the IR
|
||||
* after `index` number of loads.
|
||||
*/
|
||||
class RawIndirectInstruction extends Node, TRawIndirectInstruction {
|
||||
Instruction instr;
|
||||
int indirectionIndex;
|
||||
|
||||
RawIndirectInstruction() { this = TRawIndirectInstruction(instr, indirectionIndex) }
|
||||
|
||||
/** Gets the underlying instruction. */
|
||||
Instruction getInstruction() { result = instr }
|
||||
|
||||
/** Gets the underlying indirection index. */
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
override Declaration getFunction() { result = this.getInstruction().getEnclosingFunction() }
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override DataFlowType getType() {
|
||||
exists(int sub, DataFlowType type, boolean isGLValue |
|
||||
type = getInstructionType(instr, isGLValue) and
|
||||
if isGLValue = true then sub = 1 else sub = 0
|
||||
|
|
||||
result = getTypeImpl(type.getUnspecifiedType(), indirectionIndex - sub)
|
||||
)
|
||||
}
|
||||
|
||||
final override Location getLocationImpl() {
|
||||
if exists(this.getInstruction().getLocation())
|
||||
then result = this.getInstruction().getLocation()
|
||||
else result instanceof UnknownDefaultLocation
|
||||
}
|
||||
|
||||
override string toStringImpl() {
|
||||
result = instructionNode(this.getInstruction()).toStringImpl() + " indirection"
|
||||
}
|
||||
}
|
||||
|
||||
private module GetConvertedResultExpression {
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
|
||||
@@ -1600,26 +1637,29 @@ private module Cached {
|
||||
predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo) }
|
||||
|
||||
private predicate indirectionOperandFlow(RawIndirectOperand nodeFrom, Node nodeTo) {
|
||||
// Reduce the indirection count by 1 if we're passing through a `LoadInstruction`.
|
||||
exists(int ind, LoadInstruction load |
|
||||
hasOperandAndIndex(nodeFrom, load.getSourceAddressOperand(), ind) and
|
||||
nodeHasInstruction(nodeTo, load, ind - 1)
|
||||
)
|
||||
or
|
||||
// If an operand flows to an instruction, then the indirection of
|
||||
// the operand also flows to the indirection of the instruction.
|
||||
exists(Operand operand, Instruction instr, int indirectionIndex |
|
||||
simpleInstructionLocalFlowStep(operand, instr) and
|
||||
hasOperandAndIndex(nodeFrom, operand, pragma[only_bind_into](indirectionIndex)) and
|
||||
hasInstructionAndIndex(nodeTo, instr, pragma[only_bind_into](indirectionIndex))
|
||||
)
|
||||
or
|
||||
// If there's indirect flow to an operand, then there's also indirect
|
||||
// flow to the operand after applying some pointer arithmetic.
|
||||
exists(PointerArithmeticInstruction pointerArith, int indirectionIndex |
|
||||
hasOperandAndIndex(nodeFrom, pointerArith.getAnOperand(),
|
||||
pragma[only_bind_into](indirectionIndex)) and
|
||||
hasInstructionAndIndex(nodeTo, pointerArith, pragma[only_bind_into](indirectionIndex))
|
||||
nodeFrom != nodeTo and
|
||||
(
|
||||
// Reduce the indirection count by 1 if we're passing through a `LoadInstruction`.
|
||||
exists(int ind, LoadInstruction load |
|
||||
hasOperandAndIndex(nodeFrom, load.getSourceAddressOperand(), ind) and
|
||||
nodeHasInstruction(nodeTo, load, ind - 1)
|
||||
)
|
||||
or
|
||||
// If an operand flows to an instruction, then the indirection of
|
||||
// the operand also flows to the indirection of the instruction.
|
||||
exists(Operand operand, Instruction instr, int indirectionIndex |
|
||||
simpleInstructionLocalFlowStep(operand, instr) and
|
||||
hasOperandAndIndex(nodeFrom, operand, pragma[only_bind_into](indirectionIndex)) and
|
||||
hasInstructionAndIndex(nodeTo, instr, pragma[only_bind_into](indirectionIndex))
|
||||
)
|
||||
or
|
||||
// If there's indirect flow to an operand, then there's also indirect
|
||||
// flow to the operand after applying some pointer arithmetic.
|
||||
exists(PointerArithmeticInstruction pointerArith, int indirectionIndex |
|
||||
hasOperandAndIndex(nodeFrom, pointerArith.getAnOperand(),
|
||||
pragma[only_bind_into](indirectionIndex)) and
|
||||
hasInstructionAndIndex(nodeTo, pointerArith, pragma[only_bind_into](indirectionIndex))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1645,6 +1685,7 @@ private module Cached {
|
||||
private predicate indirectionInstructionFlow(
|
||||
RawIndirectInstruction nodeFrom, IndirectOperand nodeTo
|
||||
) {
|
||||
nodeFrom != nodeTo and
|
||||
// If there's flow from an instruction to an operand, then there's also flow from the
|
||||
// indirect instruction to the indirect operand.
|
||||
exists(Operand operand, Instruction instr, int indirectionIndex |
|
||||
|
||||
@@ -113,22 +113,12 @@ private newtype TDefOrUseImpl =
|
||||
TGlobalUse(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
||||
// Represents a final "use" of a global variable to ensure that
|
||||
// the assignment to a global variable isn't ruled out as dead.
|
||||
exists(VariableAddressInstruction vai, int defIndex |
|
||||
vai.getEnclosingIRFunction() = f and
|
||||
vai.getAstVariable() = v and
|
||||
isDef(_, _, _, vai, _, defIndex) and
|
||||
indirectionIndex = [0 .. defIndex] + 1
|
||||
)
|
||||
isGlobalUse(v, f, _, indirectionIndex)
|
||||
} or
|
||||
TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
||||
// Represents the initial "definition" of a global variable when entering
|
||||
// a function body.
|
||||
exists(VariableAddressInstruction vai |
|
||||
vai.getEnclosingIRFunction() = f and
|
||||
vai.getAstVariable() = v and
|
||||
isUse(_, _, vai, _, indirectionIndex) and
|
||||
not isDef(_, _, vai.getAUse(), _, _, _)
|
||||
)
|
||||
isGlobalDefImpl(v, f, _, indirectionIndex)
|
||||
} or
|
||||
TIteratorDef(
|
||||
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) {
|
||||
indirectionIndex = [1 .. getIndirectionForUnspecifiedType(unspecified).getNumberOfIndirections()] and
|
||||
exists(CppType cppType |
|
||||
@@ -438,7 +449,7 @@ class GlobalUse extends UseImpl, TGlobalUse {
|
||||
|
||||
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. */
|
||||
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() }
|
||||
|
||||
@@ -501,16 +514,18 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
|
||||
|
||||
/** Gets the global variable associated with this definition. */
|
||||
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
|
||||
* and typedefs have been resolved.
|
||||
*/
|
||||
Type getUnspecifiedType() { result = global.getUnspecifiedType() }
|
||||
|
||||
override string toString() { result = "GlobalDef" }
|
||||
override string toString() { result = "Def of " + this.getSourceVariable() }
|
||||
|
||||
override Location getLocation() { result = f.getLocation() }
|
||||
|
||||
@@ -980,7 +995,7 @@ class GlobalDef extends TGlobalDef, SsaDefOrUse {
|
||||
final override Location getLocation() { result = global.getLocation() }
|
||||
|
||||
/** 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
|
||||
@@ -990,6 +1005,9 @@ class GlobalDef extends TGlobalDef, SsaDefOrUse {
|
||||
global.hasIndexInBlock(block, index, sv)
|
||||
}
|
||||
|
||||
/** Gets the indirection index of this definition. */
|
||||
int getIndirection() { result = global.getIndirection() }
|
||||
|
||||
/** Gets the indirection index of this definition. */
|
||||
int getIndirectionIndex() { result = global.getIndirectionIndex() }
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ private import implementations.Accept
|
||||
private import implementations.Poll
|
||||
private import implementations.Select
|
||||
private import implementations.MySql
|
||||
private import implementations.ODBC
|
||||
private import implementations.SqLite3
|
||||
private import implementations.PostgreSql
|
||||
private import implementations.System
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.Allocation
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
|
||||
/**
|
||||
* An allocation function (such as `malloc`) that has an argument for the size
|
||||
@@ -121,7 +122,7 @@ private class CallocAllocationFunction extends AllocationFunction {
|
||||
* An allocation function (such as `realloc`) that has an argument for the size
|
||||
* in bytes, and an argument for an existing pointer that is to be reallocated.
|
||||
*/
|
||||
private class ReallocAllocationFunction extends AllocationFunction {
|
||||
private class ReallocAllocationFunction extends AllocationFunction, TaintFunction {
|
||||
int sizeArg;
|
||||
int reallocArg;
|
||||
|
||||
@@ -151,6 +152,10 @@ private class ReallocAllocationFunction extends AllocationFunction {
|
||||
override int getSizeArg() { result = sizeArg }
|
||||
|
||||
override int getReallocPtrArg() { result = reallocArg }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameterDeref(this.getReallocPtrArg()) and output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,10 +49,11 @@ private class FgetsFunction extends DataFlowFunction, TaintFunction, ArrayFuncti
|
||||
}
|
||||
|
||||
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
|
||||
output.isParameterDeref(0) and
|
||||
description = "string read by " + this.getName()
|
||||
or
|
||||
output.isReturnValue() and
|
||||
(
|
||||
output.isParameterDeref(0) or
|
||||
output.isReturnValue() or
|
||||
output.isReturnValueDeref()
|
||||
) and
|
||||
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 hasRemoteFlowSource(FunctionOutput output, string description) {
|
||||
output.isParameterDeref(3) and
|
||||
output.isParameterDeref(3, 2) and
|
||||
description = "address returned by " + this.getName()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,18 +9,17 @@ import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/**
|
||||
* The standard function `memset` and its assorted variants
|
||||
*/
|
||||
private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunction,
|
||||
private class MemsetFunctionModel extends ArrayFunction, DataFlowFunction, AliasFunction,
|
||||
SideEffectFunction
|
||||
{
|
||||
MemsetFunction() {
|
||||
MemsetFunctionModel() {
|
||||
this.hasGlobalOrStdOrBslName("memset")
|
||||
or
|
||||
this.hasGlobalOrStdName("wmemset")
|
||||
or
|
||||
this.hasGlobalName([bzero(), "__builtin_memset", "__builtin_memset_chk"])
|
||||
this.hasGlobalName([
|
||||
bzero(), "__builtin_memset", "__builtin_memset_chk", "RtlZeroMemory", "RtlSecureZeroMemory"
|
||||
])
|
||||
}
|
||||
|
||||
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
|
||||
@@ -60,3 +59,8 @@ private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunct
|
||||
}
|
||||
|
||||
private string bzero() { result = ["bzero", "explicit_bzero"] }
|
||||
|
||||
/**
|
||||
* The standard function `memset` and its assorted variants
|
||||
*/
|
||||
class MemsetFunction extends Function instanceof MemsetFunctionModel { }
|
||||
|
||||
28
cpp/ql/lib/semmle/code/cpp/models/implementations/ODBC.qll
Normal file
28
cpp/ql/lib/semmle/code/cpp/models/implementations/ODBC.qll
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Provides implementation classes modeling the ODBC C/C++ API.
|
||||
* See `semmle.code.cpp.models.Models` for usage information.
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.models.interfaces.Sql
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
||||
|
||||
/**
|
||||
* The `SQLExecDirect`, and `SQLPrepare` from the ODBC C/C++ API:
|
||||
* https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlexecdirect-function?view=sql-server-ver16
|
||||
* https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlprepare-function?view=sql-server-ver16
|
||||
*
|
||||
* Note, `SQLExecute` is not included because it operates on a SQLHSTMT type, not a string.
|
||||
* The SQLHSTMT parameter for `SQLExecute` is set through a `SQLPrepare`, which is modeled.
|
||||
* The other source of input to a `SQLExecute` is via a `SQLBindParameter`, which sanitizes user input,
|
||||
* and would be considered a barrier to SQL injection.
|
||||
*/
|
||||
private class ODBCExecutionFunction extends SqlExecutionFunction {
|
||||
ODBCExecutionFunction() { this.hasGlobalName(["SQLExecDirect", "SQLPrepare"]) }
|
||||
|
||||
override predicate hasSqlArgument(FunctionInput input) { input.isParameterDeref(1) }
|
||||
}
|
||||
// NOTE: no need to define a barrier explicitly.
|
||||
// `SQLBindParameter` is the typical means for sanitizing user input.
|
||||
// https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlbindparameter-function?view=sql-server-ver16
|
||||
// First a query is establisehed via `SQLPrepare`, then parameters are bound via `SQLBindParameter`, before
|
||||
// the query is executed via `SQLExecute`. We are not modeling SQLExecute, so we do not need to model SQLBindParameter.
|
||||
@@ -58,7 +58,7 @@ private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, Rem
|
||||
override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 }
|
||||
|
||||
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) }
|
||||
|
||||
@@ -10,6 +10,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
StrcatFunction() {
|
||||
@@ -90,3 +92,64 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
|
||||
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)
|
||||
"_mbsnbcpy", // _mbsnbcpy(dest, src, max_amount)
|
||||
"stpcpy", // stpcpy(dest, src)
|
||||
"stpncpy" // stpcpy(dest, src, max_amount)
|
||||
"stpncpy", // stpncpy(dest, src, max_amount)
|
||||
"strlcpy" // strlcpy(dst, src, dst_size)
|
||||
])
|
||||
or
|
||||
(
|
||||
@@ -53,6 +54,11 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
||||
*/
|
||||
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).
|
||||
*/
|
||||
@@ -60,7 +66,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
||||
if this.isSVariant()
|
||||
then result = 1
|
||||
else (
|
||||
this.getName().matches(["%ncpy%", "%nbcpy%", "%xfrm%"]) and
|
||||
this.getName().matches(["%ncpy%", "%nbcpy%", "%xfrm%", "strlcpy"]) and
|
||||
result = 2
|
||||
)
|
||||
}
|
||||
@@ -100,6 +106,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
||||
input.isParameterDeref(this.getParamSrc()) and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
not this.returnsTotalLength() and
|
||||
input.isParameter(this.getParamDest()) and
|
||||
output.isReturnValue()
|
||||
}
|
||||
@@ -110,8 +117,9 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
||||
exists(this.getParamSize()) and
|
||||
input.isParameterDeref(this.getParamSrc()) and
|
||||
(
|
||||
output.isParameterDeref(this.getParamDest()) or
|
||||
output.isReturnValueDeref()
|
||||
output.isParameterDeref(this.getParamDest())
|
||||
or
|
||||
not this.returnsTotalLength() and output.isReturnValueDeref()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import semmle.code.cpp.Parameter
|
||||
|
||||
private newtype TFunctionInput =
|
||||
TInParameter(ParameterIndex i) or
|
||||
TInParameterDeref(ParameterIndex i) or
|
||||
TInParameterDeref(ParameterIndex i, int indirectionIndex) { indirectionIndex = [1, 2] } or
|
||||
TInQualifierObject() or
|
||||
TInQualifierAddress() or
|
||||
TInReturnValueDeref()
|
||||
@@ -245,15 +245,18 @@ class InParameter extends FunctionInput, TInParameter {
|
||||
*/
|
||||
class InParameterDeref extends FunctionInput, TInParameterDeref {
|
||||
ParameterIndex index;
|
||||
int indirectionIndex;
|
||||
|
||||
InParameterDeref() { this = TInParameterDeref(index) }
|
||||
InParameterDeref() { this = TInParameterDeref(index, indirectionIndex) }
|
||||
|
||||
override string toString() { result = "InParameterDeref " + index.toString() }
|
||||
|
||||
/** Gets the zero-based index of the parameter. */
|
||||
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 =
|
||||
TOutParameterDeref(ParameterIndex i) or
|
||||
TOutParameterDeref(ParameterIndex i, int indirectionIndex) { indirectionIndex = [1, 2] } or
|
||||
TOutQualifierObject() or
|
||||
TOutReturnValue() or
|
||||
TOutReturnValueDeref()
|
||||
TOutReturnValueDeref(int indirections) { indirections = [1, 2] }
|
||||
|
||||
/**
|
||||
* An output from a function. This can be:
|
||||
@@ -498,17 +501,16 @@ class FunctionOutput extends TFunctionOutput {
|
||||
*/
|
||||
class OutParameterDeref extends FunctionOutput, TOutParameterDeref {
|
||||
ParameterIndex index;
|
||||
int indirectionIndex;
|
||||
|
||||
OutParameterDeref() { this = TOutParameterDeref(index) }
|
||||
OutParameterDeref() { this = TOutParameterDeref(index, indirectionIndex) }
|
||||
|
||||
override string toString() { result = "OutParameterDeref " + index.toString() }
|
||||
|
||||
ParameterIndex getIndex() { result = index }
|
||||
|
||||
override predicate isParameterDeref(ParameterIndex i) { i = index }
|
||||
|
||||
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 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`.
|
||||
*/
|
||||
predicate bounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
|
||||
exists(SemanticExprConfig::Expr semExpr |
|
||||
semExpr.getUnconverted().getUnconvertedResultExpression() = e
|
||||
|
|
||||
exists(SemanticExprConfig::Expr semExpr | semExpr.getUnconvertedResultExpression() = e |
|
||||
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.
|
||||
*/
|
||||
predicate convertedBounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
|
||||
exists(SemanticExprConfig::Expr semExpr |
|
||||
semExpr.getConverted().getConvertedResultExpression() = e
|
||||
|
|
||||
exists(SemanticExprConfig::Expr semExpr | semExpr.getConvertedResultExpression() = e |
|
||||
semBounded(semExpr, b, delta, upper, reason)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ predicate exprMightOverflowNegatively(Expr expr) {
|
||||
lowerBound(expr) < exprMinVal(expr)
|
||||
or
|
||||
exists(SemanticExprConfig::Expr semExpr |
|
||||
semExpr.getUnconverted().getAst() = expr and
|
||||
semExpr.getAst() = expr and
|
||||
ConstantStage::potentiallyOverflowingExpr(false, semExpr) and
|
||||
not ConstantStage::initialBounded(semExpr, _, _, false, _, _, _)
|
||||
)
|
||||
@@ -126,7 +126,7 @@ predicate exprMightOverflowPositively(Expr expr) {
|
||||
upperBound(expr) > exprMaxVal(expr)
|
||||
or
|
||||
exists(SemanticExprConfig::Expr semExpr |
|
||||
semExpr.getUnconverted().getAst() = expr and
|
||||
semExpr.getAst() = expr and
|
||||
ConstantStage::potentiallyOverflowingExpr(true, semExpr) and
|
||||
not ConstantStage::initialBounded(semExpr, _, _, true, _, _, _)
|
||||
)
|
||||
|
||||
@@ -12,9 +12,6 @@ class SemBasicBlock extends Specific::BasicBlock {
|
||||
/** Holds if this block (transitively) dominates `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. */
|
||||
final SemExpr getAnExpr() { result.getBasicBlock() = this }
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
private import Semantic
|
||||
private import SemanticExprSpecific::SemanticExprConfig as Specific
|
||||
private import SemanticType
|
||||
|
||||
/**
|
||||
* An language-neutral expression.
|
||||
@@ -241,8 +242,21 @@ class SemConvertExpr extends SemUnaryExpr {
|
||||
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 {
|
||||
SemCopyValueExpr() { opcode instanceof Opcode::CopyValue }
|
||||
SemCopyValueExpr() { opcode instanceof Opcode::CopyValue or this instanceof SafeConversion }
|
||||
}
|
||||
|
||||
class SemNegateExpr extends SemUnaryExpr {
|
||||
|
||||
@@ -12,87 +12,10 @@ private import semmle.code.cpp.ir.ValueNumbering
|
||||
module SemanticExprConfig {
|
||||
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.
|
||||
*/
|
||||
class Expr extends Equiv::EquivalenceClass {
|
||||
/** 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() }
|
||||
}
|
||||
class Expr = IR::Instruction;
|
||||
|
||||
SemBasicBlock getExprBasicBlock(Expr e) { result = getSemanticBasicBlock(e.getBlock()) }
|
||||
|
||||
@@ -139,12 +62,12 @@ module SemanticExprConfig {
|
||||
|
||||
predicate stringLiteral(Expr expr, SemType type, string value) {
|
||||
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) {
|
||||
exists(IR::BinaryInstruction instr |
|
||||
instr = expr.getUnconverted() and
|
||||
instr = expr and
|
||||
type = getSemanticType(instr.getResultIRType()) and
|
||||
leftOperand = getSemanticExpr(instr.getLeft()) and
|
||||
rightOperand = getSemanticExpr(instr.getRight()) and
|
||||
@@ -154,14 +77,14 @@ module SemanticExprConfig {
|
||||
}
|
||||
|
||||
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
|
||||
operand = getSemanticExpr(instr.getUnary()) and
|
||||
// REVIEW: Merge the two operand types.
|
||||
opcode.toString() = instr.getOpcode().toString()
|
||||
)
|
||||
or
|
||||
exists(IR::StoreInstruction instr | instr = expr.getUnconverted() |
|
||||
exists(IR::StoreInstruction instr | instr = expr |
|
||||
type = getSemanticType(instr.getResultIRType()) and
|
||||
operand = getSemanticExpr(instr.getSourceValue()) and
|
||||
opcode instanceof Opcode::Store
|
||||
@@ -170,13 +93,13 @@ module SemanticExprConfig {
|
||||
|
||||
predicate nullaryExpr(Expr expr, Opcode opcode, SemType type) {
|
||||
exists(IR::LoadInstruction load |
|
||||
load = expr.getUnconverted() and
|
||||
load = expr and
|
||||
type = getSemanticType(load.getResultIRType()) and
|
||||
opcode instanceof Opcode::Load
|
||||
)
|
||||
or
|
||||
exists(IR::InitializeParameterInstruction init |
|
||||
init = expr.getUnconverted() and
|
||||
init = expr and
|
||||
type = getSemanticType(init.getResultIRType()) and
|
||||
opcode instanceof Opcode::InitializeParameter
|
||||
)
|
||||
@@ -199,8 +122,6 @@ module SemanticExprConfig {
|
||||
dominator.dominates(dominated)
|
||||
}
|
||||
|
||||
predicate hasDominanceInformation(BasicBlock block) { any() }
|
||||
|
||||
private predicate id(Cpp::Locatable x, Cpp::Locatable y) { x = y }
|
||||
|
||||
private predicate idOf(Cpp::Locatable x, int y) = equivalenceRelation(id/2)(x, y)
|
||||
@@ -209,17 +130,7 @@ module SemanticExprConfig {
|
||||
|
||||
newtype TSsaVariable =
|
||||
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
|
||||
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() } or
|
||||
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, _, _, _)
|
||||
)
|
||||
}
|
||||
TSsaOperand(IR::PhiInputOperand op) { op.isDefinitionInexact() }
|
||||
|
||||
class SsaVariable extends TSsaVariable {
|
||||
string toString() { none() }
|
||||
@@ -228,9 +139,7 @@ module SemanticExprConfig {
|
||||
|
||||
IR::Instruction asInstruction() { none() }
|
||||
|
||||
ValueNumber asPointerArithGuard() { none() }
|
||||
|
||||
IR::Operand asOperand() { none() }
|
||||
IR::PhiInputOperand asOperand() { none() }
|
||||
}
|
||||
|
||||
class SsaInstructionVariable extends SsaVariable, TSsaInstruction {
|
||||
@@ -245,20 +154,8 @@ module SemanticExprConfig {
|
||||
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 {
|
||||
IR::Operand op;
|
||||
IR::PhiInputOperand op;
|
||||
|
||||
SsaOperand() { this = TSsaOperand(op) }
|
||||
|
||||
@@ -266,7 +163,7 @@ module SemanticExprConfig {
|
||||
|
||||
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) {
|
||||
@@ -289,97 +186,29 @@ module SemanticExprConfig {
|
||||
)
|
||||
}
|
||||
|
||||
Expr getAUse(SsaVariable v) {
|
||||
result.getUnconverted().(IR::LoadInstruction).getSourceValue() = v.asInstruction()
|
||||
or
|
||||
result.getUnconverted() = v.asPointerArithGuard().getAnInstruction()
|
||||
}
|
||||
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
|
||||
|
||||
SemType getSsaVariableType(SsaVariable v) {
|
||||
result = getSemanticType(v.asInstruction().getResultIRType())
|
||||
or
|
||||
result = getSemanticType(v.asOperand().getUse().getResultIRType())
|
||||
}
|
||||
|
||||
BasicBlock getSsaVariableBasicBlock(SsaVariable v) {
|
||||
result = v.asInstruction().getBlock()
|
||||
or
|
||||
result = v.asOperand().getUse().getBlock()
|
||||
result = v.asOperand().getAnyDef().getBlock()
|
||||
}
|
||||
|
||||
private newtype TReadPosition =
|
||||
TReadPositionBlock(IR::IRBlock block) or
|
||||
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) {
|
||||
/** Holds if `inp` is an input to the phi node along the edge originating in `bb`. */
|
||||
predicate phiInputFromBlock(SsaVariable phi, SsaVariable inp, BasicBlock bb) {
|
||||
exists(IR::PhiInputOperand operand |
|
||||
pos = TReadPositionPhiInputEdge(operand.getPredecessorBlock(), operand.getUse().getBlock())
|
||||
|
|
||||
bb = operand.getPredecessorBlock() and
|
||||
phi.asInstruction() = operand.getUse() and
|
||||
(
|
||||
input.asInstruction() = operand.getDef()
|
||||
inp.asInstruction() = operand.getDef()
|
||||
or
|
||||
input.asOperand() = operand
|
||||
inp.asOperand() = operand
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -433,7 +262,7 @@ module SemanticExprConfig {
|
||||
}
|
||||
|
||||
/** 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;
|
||||
|
||||
@@ -35,32 +35,4 @@ predicate semImplies_v2(SemGuard g1, boolean b1, SemGuard g2, boolean 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) }
|
||||
|
||||
@@ -22,75 +22,15 @@ class SemSsaExplicitUpdate extends SemSsaVariable {
|
||||
|
||||
SemSsaExplicitUpdate() { Specific::explicitUpdate(this, sourceExpr) }
|
||||
|
||||
final SemExpr getSourceExpr() { result = sourceExpr }
|
||||
final SemExpr getDefiningExpr() { result = sourceExpr }
|
||||
}
|
||||
|
||||
class SemSsaPhiNode extends SemSsaVariable {
|
||||
SemSsaPhiNode() { Specific::phi(this) }
|
||||
|
||||
final SemSsaVariable getAPhiInput() { result = Specific::getAPhiInput(this) }
|
||||
}
|
||||
|
||||
class SemSsaReadPosition instanceof Specific::SsaReadPosition {
|
||||
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)
|
||||
|
||||
final predicate hasInputFromBlock(SemSsaVariable inp, SemBasicBlock bb) {
|
||||
Specific::phiInputFromBlock(this, inp, bb)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ private predicate constantIntegerExpr(SemExpr e, int val) {
|
||||
// Copy of another constant
|
||||
exists(SemSsaExplicitUpdate v, SemExpr src |
|
||||
e = v.getAUse() and
|
||||
src = v.getSourceExpr() and
|
||||
src = v.getDefiningExpr() and
|
||||
constantIntegerExpr(src, val)
|
||||
)
|
||||
or
|
||||
|
||||
@@ -1,328 +0,0 @@
|
||||
/**
|
||||
* Provides inferences of the form: `e` equals `b + v` modulo `m` where `e` is
|
||||
* an expression, `b` is a `Bound` (typically zero or the value of an SSA
|
||||
* variable), and `v` is an integer in the range `[0 .. m-1]`.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The main recursion has base cases in both `ssaModulus` (for guarded reads) and `semExprModulus`
|
||||
* (for constant values). The most interesting recursive case is `phiModulusRankStep`, which
|
||||
* handles phi inputs.
|
||||
*/
|
||||
|
||||
private import ModulusAnalysisSpecific::Private
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticLocation
|
||||
private import ConstantAnalysis
|
||||
private import RangeUtils
|
||||
private import codeql.rangeanalysis.RangeAnalysis
|
||||
private import RangeAnalysisImpl
|
||||
|
||||
module ModulusAnalysis<DeltaSig D, BoundSig<SemLocation, Sem, D> Bounds, UtilSig<Sem, D> U> {
|
||||
pragma[nomagic]
|
||||
private predicate valueFlowStepSsaEqFlowCond(
|
||||
SemSsaReadPosition pos, SemSsaVariable v, SemExpr e, int delta
|
||||
) {
|
||||
exists(SemGuard guard, boolean testIsTrue |
|
||||
guard = U::semEqFlowCond(v, e, D::fromInt(delta), true, testIsTrue) and
|
||||
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e + delta` equals `v` at `pos`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate valueFlowStepSsa(SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta) {
|
||||
U::semSsaUpdateStep(v, e, D::fromInt(delta)) and pos.hasReadOfVar(v)
|
||||
or
|
||||
pos.hasReadOfVar(v) and
|
||||
valueFlowStepSsaEqFlowCond(pos, v, e, delta)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `add` is the addition of `larg` and `rarg`, neither of which are
|
||||
* `ConstantIntegerExpr`s.
|
||||
*/
|
||||
private predicate nonConstAddition(SemExpr add, SemExpr larg, SemExpr rarg) {
|
||||
exists(SemAddExpr a | a = add |
|
||||
larg = a.getLeftOperand() and
|
||||
rarg = a.getRightOperand()
|
||||
) and
|
||||
not larg instanceof SemConstantIntegerExpr and
|
||||
not rarg instanceof SemConstantIntegerExpr
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `sub` is the subtraction of `larg` and `rarg`, where `rarg` is not
|
||||
* a `ConstantIntegerExpr`.
|
||||
*/
|
||||
private predicate nonConstSubtraction(SemExpr sub, SemExpr larg, SemExpr rarg) {
|
||||
exists(SemSubExpr s | s = sub |
|
||||
larg = s.getLeftOperand() and
|
||||
rarg = s.getRightOperand()
|
||||
) and
|
||||
not rarg instanceof SemConstantIntegerExpr
|
||||
}
|
||||
|
||||
/** Gets an expression that is the remainder modulo `mod` of `arg`. */
|
||||
private SemExpr modExpr(SemExpr arg, int mod) {
|
||||
exists(SemRemExpr rem |
|
||||
result = rem and
|
||||
arg = rem.getLeftOperand() and
|
||||
rem.getRightOperand().(SemConstantIntegerExpr).getIntValue() = mod and
|
||||
mod >= 2
|
||||
)
|
||||
or
|
||||
exists(SemConstantIntegerExpr c |
|
||||
mod = 2.pow([1 .. 30]) and
|
||||
c.getIntValue() = mod - 1 and
|
||||
result.(SemBitAndExpr).hasOperands(arg, c)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a guard that tests whether `v` is congruent with `val` modulo `mod` on
|
||||
* its `testIsTrue` branch.
|
||||
*/
|
||||
private SemGuard moduloCheck(SemSsaVariable v, int val, int mod, boolean testIsTrue) {
|
||||
exists(SemExpr rem, SemConstantIntegerExpr c, int r, boolean polarity |
|
||||
result.isEquality(rem, c, polarity) and
|
||||
c.getIntValue() = r and
|
||||
rem = modExpr(v.getAUse(), mod) and
|
||||
(
|
||||
testIsTrue = polarity and val = r
|
||||
or
|
||||
testIsTrue = polarity.booleanNot() and
|
||||
mod = 2 and
|
||||
val = 1 - r and
|
||||
(r = 0 or r = 1)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a guard ensures that `v` at `pos` is congruent with `val` modulo `mod`.
|
||||
*/
|
||||
private predicate moduloGuardedRead(SemSsaVariable v, SemSsaReadPosition pos, int val, int mod) {
|
||||
exists(SemGuard guard, boolean testIsTrue |
|
||||
pos.hasReadOfVar(v) and
|
||||
guard = moduloCheck(v, val, mod, testIsTrue) and
|
||||
semGuardControlsSsaRead(guard, pos, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `factor` is a power of 2 that divides `mask`. */
|
||||
bindingset[mask]
|
||||
private predicate andmaskFactor(int mask, int factor) {
|
||||
mask % factor = 0 and
|
||||
factor = 2.pow([1 .. 30])
|
||||
}
|
||||
|
||||
/** Holds if `e` is evenly divisible by `factor`. */
|
||||
private predicate evenlyDivisibleExpr(SemExpr e, int factor) {
|
||||
exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() |
|
||||
e.(SemMulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2
|
||||
or
|
||||
e.(SemShiftLeftExpr).getRightOperand() = c and factor = 2.pow(k) and k > 0
|
||||
or
|
||||
e.(SemBitAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the remainder of `val` modulo `mod`.
|
||||
*
|
||||
* For `mod = 0` the result equals `val` and for `mod > 1` the result is within
|
||||
* the range `[0 .. mod-1]`.
|
||||
*/
|
||||
bindingset[val, mod]
|
||||
private int remainder(int val, int mod) {
|
||||
mod = 0 and result = val
|
||||
or
|
||||
mod > 1 and result = ((val % mod) + mod) % mod
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `inp` is an input to `phi` and equals `phi` modulo `mod` along `edge`.
|
||||
*/
|
||||
private predicate phiSelfModulus(
|
||||
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int mod
|
||||
) {
|
||||
exists(Bounds::SemSsaBound phibound, int v, int m |
|
||||
edge.phiInput(phi, inp) and
|
||||
phibound.getAVariable() = phi and
|
||||
ssaModulus(inp, edge, phibound, v, m) and
|
||||
mod = m.gcd(v) and
|
||||
mod != 1
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + val` modulo `mod` is a candidate congruence class for `phi`.
|
||||
*/
|
||||
private predicate phiModulusInit(SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod) {
|
||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
|
||||
edge.phiInput(phi, inp) and
|
||||
ssaModulus(inp, edge, b, val, mod)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate phiModulusRankStep(
|
||||
SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod, int rix
|
||||
) {
|
||||
/*
|
||||
* base case. If any phi input is equal to `b + val` modulo `mod`, that's a potential congruence
|
||||
* class for the phi node.
|
||||
*/
|
||||
|
||||
rix = 0 and
|
||||
phiModulusInit(phi, b, val, mod)
|
||||
or
|
||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int v1, int m1 |
|
||||
mod != 1 and
|
||||
val = remainder(v1, mod)
|
||||
|
|
||||
/*
|
||||
* Recursive case. If `inp` = `b + v2` mod `m2`, we combine that with the preceding potential
|
||||
* congruence class `b + v1` mod `m1`. The result will be the congruence class of `v1` modulo
|
||||
* the greatest common denominator of `m1`, `m2`, and `v1 - v2`.
|
||||
*/
|
||||
|
||||
exists(int v2, int m2 |
|
||||
rankedPhiInput(pragma[only_bind_out](phi), inp, edge, rix) and
|
||||
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
|
||||
ssaModulus(inp, edge, b, v2, m2) and
|
||||
mod = m1.gcd(m2).gcd(v1 - v2)
|
||||
)
|
||||
or
|
||||
/*
|
||||
* Recursive case. If `inp` = `phi` mod `m2`, we combine that with the preceding potential
|
||||
* congruence class `b + v1` mod `m1`. The result will be a congruence class modulo the greatest
|
||||
* common denominator of `m1` and `m2`.
|
||||
*/
|
||||
|
||||
exists(int m2 |
|
||||
rankedPhiInput(phi, inp, edge, rix) and
|
||||
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
|
||||
phiSelfModulus(phi, inp, edge, m2) and
|
||||
mod = m1.gcd(m2)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `phi` is equal to `b + val` modulo `mod`.
|
||||
*/
|
||||
private predicate phiModulus(SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod) {
|
||||
exists(int r |
|
||||
maxPhiInputRank(phi, r) and
|
||||
phiModulusRankStep(phi, b, val, mod, r)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` at `pos` is equal to `b + val` modulo `mod`.
|
||||
*/
|
||||
private predicate ssaModulus(
|
||||
SemSsaVariable v, SemSsaReadPosition pos, Bounds::SemBound b, int val, int mod
|
||||
) {
|
||||
phiModulus(v, b, val, mod) and pos.hasReadOfVar(v)
|
||||
or
|
||||
b.(Bounds::SemSsaBound).getAVariable() = v and pos.hasReadOfVar(v) and val = 0 and mod = 0
|
||||
or
|
||||
exists(SemExpr e, int val0, int delta |
|
||||
semExprModulus(e, b, val0, mod) and
|
||||
valueFlowStepSsa(v, pos, e, delta) and
|
||||
val = remainder(val0 + delta, mod)
|
||||
)
|
||||
or
|
||||
moduloGuardedRead(v, pos, val, mod) and b instanceof Bounds::SemZeroBound
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` is equal to `b + val` modulo `mod`.
|
||||
*
|
||||
* There are two cases for the modulus:
|
||||
* - `mod = 0`: The equality `e = b + val` is an ordinary equality.
|
||||
* - `mod > 1`: `val` lies within the range `[0 .. mod-1]`.
|
||||
*/
|
||||
cached
|
||||
predicate semExprModulus(SemExpr e, Bounds::SemBound b, int val, int mod) {
|
||||
not ignoreExprModulus(e) and
|
||||
(
|
||||
e = b.getExpr(D::fromInt(val)) and mod = 0
|
||||
or
|
||||
evenlyDivisibleExpr(e, mod) and
|
||||
val = 0 and
|
||||
b instanceof Bounds::SemZeroBound
|
||||
or
|
||||
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
|
||||
ssaModulus(v, bb, b, val, mod) and
|
||||
e = v.getAUse() and
|
||||
bb.getAnExpr() = e
|
||||
)
|
||||
or
|
||||
exists(SemExpr mid, int val0, int delta |
|
||||
semExprModulus(mid, b, val0, mod) and
|
||||
U::semValueFlowStep(e, mid, D::fromInt(delta)) and
|
||||
val = remainder(val0 + delta, mod)
|
||||
)
|
||||
or
|
||||
exists(SemConditionalExpr cond, int v1, int v2, int m1, int m2 |
|
||||
cond = e and
|
||||
condExprBranchModulus(cond, true, b, v1, m1) and
|
||||
condExprBranchModulus(cond, false, b, v2, m2) and
|
||||
mod = m1.gcd(m2).gcd(v1 - v2) and
|
||||
mod != 1 and
|
||||
val = remainder(v1, mod)
|
||||
)
|
||||
or
|
||||
exists(Bounds::SemBound b1, Bounds::SemBound b2, int v1, int v2, int m1, int m2 |
|
||||
addModulus(e, true, b1, v1, m1) and
|
||||
addModulus(e, false, b2, v2, m2) and
|
||||
mod = m1.gcd(m2) and
|
||||
mod != 1 and
|
||||
val = remainder(v1 + v2, mod)
|
||||
|
|
||||
b = b1 and b2 instanceof Bounds::SemZeroBound
|
||||
or
|
||||
b = b2 and b1 instanceof Bounds::SemZeroBound
|
||||
)
|
||||
or
|
||||
exists(int v1, int v2, int m1, int m2 |
|
||||
subModulus(e, true, b, v1, m1) and
|
||||
subModulus(e, false, any(Bounds::SemZeroBound zb), v2, m2) and
|
||||
mod = m1.gcd(m2) and
|
||||
mod != 1 and
|
||||
val = remainder(v1 - v2, mod)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate condExprBranchModulus(
|
||||
SemConditionalExpr cond, boolean branch, Bounds::SemBound b, int val, int mod
|
||||
) {
|
||||
semExprModulus(cond.getBranchExpr(branch), b, val, mod)
|
||||
}
|
||||
|
||||
private predicate addModulus(SemExpr add, boolean isLeft, Bounds::SemBound b, int val, int mod) {
|
||||
exists(SemExpr larg, SemExpr rarg | nonConstAddition(add, larg, rarg) |
|
||||
semExprModulus(larg, b, val, mod) and isLeft = true
|
||||
or
|
||||
semExprModulus(rarg, b, val, mod) and isLeft = false
|
||||
)
|
||||
}
|
||||
|
||||
private predicate subModulus(SemExpr sub, boolean isLeft, Bounds::SemBound b, int val, int mod) {
|
||||
exists(SemExpr larg, SemExpr rarg | nonConstSubtraction(sub, larg, rarg) |
|
||||
semExprModulus(larg, b, val, mod) and isLeft = true
|
||||
or
|
||||
semExprModulus(rarg, b, val, mod) and isLeft = false
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
* C++-specific implementation of modulus analysis.
|
||||
*/
|
||||
module Private {
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
|
||||
predicate ignoreExprModulus(SemExpr e) { none() }
|
||||
}
|
||||
@@ -8,14 +8,6 @@ private import RangeAnalysisImpl
|
||||
private import codeql.rangeanalysis.RangeAnalysis
|
||||
|
||||
module CppLangImplConstant implements LangSig<Sem, FloatDelta> {
|
||||
/**
|
||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadCopy(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Ignore the bound on this expression.
|
||||
*
|
||||
@@ -24,70 +16,13 @@ module CppLangImplConstant implements LangSig<Sem, FloatDelta> {
|
||||
*/
|
||||
predicate ignoreExprBound(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Ignore any inferred zero lower bound on this expression.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreZeroLowerBound(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadArithmeticExpr(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the specified variable should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadAssignment(SemSsaVariable v) { none() }
|
||||
|
||||
/**
|
||||
* Adds additional results to `ssaRead()` that are specific to Java.
|
||||
*
|
||||
* This predicate handles propagation of offsets for post-increment and post-decrement expressions
|
||||
* in exactly the same way as the old Java implementation. Once the new implementation matches the
|
||||
* old one, we should remove this predicate and propagate deltas for all similar patterns, whether
|
||||
* or not they come from a post-increment/decrement expression.
|
||||
*/
|
||||
SemExpr specificSsaRead(SemSsaVariable v, float delta) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
|
||||
*/
|
||||
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() }
|
||||
|
||||
/**
|
||||
* 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() }
|
||||
predicate additionalBoundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) { none() }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
private import RangeAnalysisConstantSpecific
|
||||
private import RangeAnalysisRelativeSpecific
|
||||
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.SemanticCFG
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticGuard
|
||||
@@ -52,20 +51,34 @@ module Sem implements Semantic {
|
||||
|
||||
class NegateExpr = SemNegateExpr;
|
||||
|
||||
class AddOneExpr = SemAddOneExpr;
|
||||
class PreIncExpr = SemAddOneExpr;
|
||||
|
||||
class SubOneExpr = SemSubOneExpr;
|
||||
class PreDecExpr = SemSubOneExpr;
|
||||
|
||||
class PostIncExpr extends SemUnaryExpr {
|
||||
PostIncExpr() { none() }
|
||||
}
|
||||
|
||||
class PostDecExpr extends SemUnaryExpr {
|
||||
PostDecExpr() { none() }
|
||||
}
|
||||
|
||||
class CopyValueExpr extends SemUnaryExpr {
|
||||
CopyValueExpr() { this instanceof SemCopyValueExpr or this instanceof SemStoreExpr }
|
||||
}
|
||||
|
||||
class ConditionalExpr = SemConditionalExpr;
|
||||
|
||||
class BasicBlock = SemBasicBlock;
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
int getBlockId1(BasicBlock bb) { result = bb.getUniqueId() }
|
||||
|
||||
class Guard = SemGuard;
|
||||
|
||||
predicate implies_v2 = semImplies_v2/4;
|
||||
|
||||
predicate guardDirectlyControlsSsaRead = semGuardDirectlyControlsSsaRead/3;
|
||||
|
||||
class Type = SemType;
|
||||
|
||||
class IntegerType = SemIntegerType;
|
||||
@@ -74,19 +87,17 @@ module Sem implements Semantic {
|
||||
|
||||
class AddressType = SemAddressType;
|
||||
|
||||
SemType getExprType(SemExpr e) { result = e.getSemType() }
|
||||
|
||||
SemType getSsaType(SemSsaVariable var) { result = var.getType() }
|
||||
|
||||
class SsaVariable = SemSsaVariable;
|
||||
|
||||
class SsaPhiNode = SemSsaPhiNode;
|
||||
|
||||
class SsaExplicitUpdate = SemSsaExplicitUpdate;
|
||||
|
||||
class SsaReadPosition = SemSsaReadPosition;
|
||||
|
||||
class SsaReadPositionPhiInputEdge = SemSsaReadPositionPhiInputEdge;
|
||||
|
||||
class SsaReadPositionBlock = SemSsaReadPositionBlock;
|
||||
|
||||
predicate backEdge = semBackEdge/3;
|
||||
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, int delta) { none() }
|
||||
|
||||
predicate conversionCannotOverflow(Type fromType, Type toType) {
|
||||
SemanticType::conversionCannotOverflow(fromType, toType)
|
||||
@@ -95,7 +106,7 @@ module Sem implements Semantic {
|
||||
|
||||
module SignAnalysis implements SignAnalysisSig<Sem> {
|
||||
private import SignAnalysisCommon as SA
|
||||
import SA::SignAnalysis<FloatDelta, Util>
|
||||
import SA::SignAnalysis<FloatDelta>
|
||||
}
|
||||
|
||||
module ConstantBounds implements BoundSig<SemLocation, Sem, FloatDelta> {
|
||||
@@ -116,7 +127,7 @@ module ConstantBounds implements BoundSig<SemLocation, Sem, FloatDelta> {
|
||||
class SemZeroBound extends SemBound instanceof SemanticBound::SemZeroBound { }
|
||||
|
||||
class SemSsaBound extends SemBound instanceof SemanticBound::SemSsaBound {
|
||||
SemSsaVariable getAVariable() { result = this.(SemanticBound::SemSsaBound).getAVariable() }
|
||||
SemSsaVariable getVariable() { result = this.(SemanticBound::SemSsaBound).getAVariable() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +145,7 @@ module RelativeBounds implements BoundSig<SemLocation, Sem, FloatDelta> {
|
||||
class SemZeroBound extends SemBound instanceof SemanticBound::SemZeroBound { }
|
||||
|
||||
class SemSsaBound extends SemBound instanceof SemanticBound::SemSsaBound {
|
||||
SemSsaVariable getAVariable() { result = this.(SemanticBound::SemSsaBound).getAVariable() }
|
||||
SemSsaVariable getVariable() { result = this.(SemanticBound::SemSsaBound).getAVariable() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,26 +161,24 @@ module AllBounds implements BoundSig<SemLocation, Sem, FloatDelta> {
|
||||
class SemZeroBound extends SemBound instanceof SemanticBound::SemZeroBound { }
|
||||
|
||||
class SemSsaBound extends SemBound instanceof SemanticBound::SemSsaBound {
|
||||
SemSsaVariable getAVariable() { result = this.(SemanticBound::SemSsaBound).getAVariable() }
|
||||
SemSsaVariable getVariable() { result = this.(SemanticBound::SemSsaBound).getAVariable() }
|
||||
}
|
||||
}
|
||||
|
||||
private module ModulusAnalysisInstantiated implements ModulusAnalysisSig<Sem> {
|
||||
class ModBound = AllBounds::SemBound;
|
||||
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.ModulusAnalysis as MA
|
||||
import MA::ModulusAnalysis<FloatDelta, AllBounds, Util>
|
||||
private import codeql.rangeanalysis.ModulusAnalysis as MA
|
||||
import MA::ModulusAnalysis<SemLocation, Sem, FloatDelta, AllBounds>
|
||||
}
|
||||
|
||||
module Util = RangeUtil<FloatDelta, CppLangImplConstant>;
|
||||
|
||||
module ConstantStage =
|
||||
RangeStage<SemLocation, Sem, FloatDelta, ConstantBounds, FloatOverflow, CppLangImplConstant,
|
||||
SignAnalysis, ModulusAnalysisInstantiated, Util>;
|
||||
SignAnalysis, ModulusAnalysisInstantiated>;
|
||||
|
||||
module RelativeStage =
|
||||
RangeStage<SemLocation, Sem, FloatDelta, RelativeBounds, FloatOverflow, CppLangImplRelative,
|
||||
SignAnalysis, ModulusAnalysisInstantiated, Util>;
|
||||
SignAnalysis, ModulusAnalysisInstantiated>;
|
||||
|
||||
private newtype TSemReason =
|
||||
TSemNoReason() or
|
||||
|
||||
@@ -9,14 +9,6 @@ private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||
private import codeql.rangeanalysis.RangeAnalysis
|
||||
|
||||
module CppLangImplRelative implements LangSig<Sem, FloatDelta> {
|
||||
/**
|
||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadCopy(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Ignore the bound on this expression.
|
||||
*
|
||||
@@ -56,70 +48,13 @@ module CppLangImplRelative implements LangSig<Sem, FloatDelta> {
|
||||
t instanceof SemFloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignore any inferred zero lower bound on this expression.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreZeroLowerBound(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadArithmeticExpr(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the specified variable should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadAssignment(SemSsaVariable v) { none() }
|
||||
|
||||
/**
|
||||
* Adds additional results to `ssaRead()` that are specific to Java.
|
||||
*
|
||||
* This predicate handles propagation of offsets for post-increment and post-decrement expressions
|
||||
* in exactly the same way as the old Java implementation. Once the new implementation matches the
|
||||
* old one, we should remove this predicate and propagate deltas for all similar patterns, whether
|
||||
* or not they come from a post-increment/decrement expression.
|
||||
*/
|
||||
SemExpr specificSsaRead(SemSsaVariable v, float delta) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
|
||||
*/
|
||||
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() }
|
||||
|
||||
/**
|
||||
* 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() }
|
||||
predicate additionalBoundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) { none() }
|
||||
}
|
||||
|
||||
@@ -1,171 +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`.
|
||||
*/
|
||||
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()) and
|
||||
not Lang::ignoreSsaReadArithmeticExpr(result)
|
||||
)
|
||||
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()) and
|
||||
not Lang::ignoreSsaReadArithmeticExpr(result)
|
||||
)
|
||||
or
|
||||
result = v.(SemSsaExplicitUpdate).getSourceExpr() and
|
||||
delta = D::fromFloat(0) and
|
||||
not Lang::ignoreSsaReadAssignment(v)
|
||||
or
|
||||
result = Lang::specificSsaRead(v, delta)
|
||||
or
|
||||
result.(SemCopyValueExpr).getOperand() = semSsaRead(v, delta) and
|
||||
not Lang::ignoreSsaReadCopy(result)
|
||||
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,11 @@ private import RangeAnalysisImpl
|
||||
private import SignAnalysisSpecific as Specific
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
private import ConstantAnalysis
|
||||
private import RangeUtils
|
||||
private import Sign
|
||||
|
||||
module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
module SignAnalysis<DeltaSig D> {
|
||||
private import codeql.rangeanalysis.internal.RangeUtils::MakeUtils<Sem, D>
|
||||
|
||||
/**
|
||||
* An SSA definition for which the analysis can compute the sign.
|
||||
*
|
||||
@@ -37,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. */
|
||||
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. */
|
||||
private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode {
|
||||
final override Sign getSign() {
|
||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
|
||||
exists(SemSsaVariable inp, SsaReadPositionPhiInputEdge edge |
|
||||
edge.phiInput(this, inp) and
|
||||
result = semSsaSign(inp, edge)
|
||||
)
|
||||
@@ -146,7 +147,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
not this instanceof ConstantSignExpr and
|
||||
(
|
||||
// Only track numeric types.
|
||||
Utils::getTrackedType(this) instanceof SemNumericType
|
||||
Sem::getExprType(this) instanceof SemNumericType
|
||||
or
|
||||
// Unless the language says to track this expression anyway.
|
||||
Specific::trackUnknownNonNumericExpr(this)
|
||||
@@ -168,11 +169,11 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
override Sign getSignRestriction() {
|
||||
// Propagate via SSA
|
||||
// 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
|
||||
// No block for this read. Just use the sign of the def.
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
@@ -201,7 +202,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
|
||||
/** An expression of an unsigned type. */
|
||||
private class UnsignedExpr extends FlowSignExpr {
|
||||
UnsignedExpr() { Utils::getTrackedType(this) instanceof SemUnsignedIntegerType }
|
||||
UnsignedExpr() { Sem::getExprType(this) instanceof SemUnsignedIntegerType }
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
result = TPos() or
|
||||
@@ -274,7 +275,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
override SemUnboxExpr cast;
|
||||
|
||||
UnboxSignExpr() {
|
||||
exists(SemType fromType | fromType = Utils::getTrackedType(cast.getOperand()) |
|
||||
exists(SemType fromType | fromType = Sem::getExprType(cast.getOperand()) |
|
||||
// Only numeric source types are handled here.
|
||||
fromType instanceof SemNumericType
|
||||
)
|
||||
@@ -288,21 +289,21 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
* to only include bounds for which we might determine a sign.
|
||||
*/
|
||||
private predicate lowerBound(
|
||||
SemExpr lowerbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
|
||||
SemExpr lowerbound, SemSsaVariable v, SsaReadPosition pos, boolean isStrict
|
||||
) {
|
||||
exists(boolean testIsTrue, SemRelationalExpr comp |
|
||||
pos.hasReadOfVar(v) and
|
||||
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||
guardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||
not unknownSign(lowerbound)
|
||||
|
|
||||
testIsTrue = true and
|
||||
comp.getLesserOperand() = lowerbound and
|
||||
comp.getGreaterOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
|
||||
comp.getGreaterOperand() = ssaRead(v, D::fromInt(0)) and
|
||||
(if comp.isStrict() then isStrict = true else isStrict = false)
|
||||
or
|
||||
testIsTrue = false and
|
||||
comp.getGreaterOperand() = lowerbound and
|
||||
comp.getLesserOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
|
||||
comp.getLesserOperand() = ssaRead(v, D::fromInt(0)) and
|
||||
(if comp.isStrict() then isStrict = false else isStrict = true)
|
||||
)
|
||||
}
|
||||
@@ -312,21 +313,21 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
* to only include bounds for which we might determine a sign.
|
||||
*/
|
||||
private predicate upperBound(
|
||||
SemExpr upperbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
|
||||
SemExpr upperbound, SemSsaVariable v, SsaReadPosition pos, boolean isStrict
|
||||
) {
|
||||
exists(boolean testIsTrue, SemRelationalExpr comp |
|
||||
pos.hasReadOfVar(v) and
|
||||
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||
guardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||
not unknownSign(upperbound)
|
||||
|
|
||||
testIsTrue = true and
|
||||
comp.getGreaterOperand() = upperbound and
|
||||
comp.getLesserOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
|
||||
comp.getLesserOperand() = ssaRead(v, D::fromInt(0)) and
|
||||
(if comp.isStrict() then isStrict = true else isStrict = false)
|
||||
or
|
||||
testIsTrue = false and
|
||||
comp.getLesserOperand() = upperbound and
|
||||
comp.getGreaterOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
|
||||
comp.getGreaterOperand() = ssaRead(v, D::fromInt(0)) and
|
||||
(if comp.isStrict() then isStrict = false else isStrict = true)
|
||||
)
|
||||
}
|
||||
@@ -338,11 +339,11 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
* - `isEq = true` : `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 |
|
||||
pos.hasReadOfVar(pragma[only_bind_into](v)) and
|
||||
semGuardControlsSsaRead(guard, pragma[only_bind_into](pos), testIsTrue) and
|
||||
e = Utils::semSsaRead(pragma[only_bind_into](v), D::fromInt(0)) and
|
||||
guardControlsSsaRead(guard, pragma[only_bind_into](pos), testIsTrue) and
|
||||
e = ssaRead(pragma[only_bind_into](v), D::fromInt(0)) and
|
||||
guard.isEquality(eqbound, e, polarity) and
|
||||
isEq = polarity.booleanXor(testIsTrue).booleanNot() and
|
||||
not unknownSign(eqbound)
|
||||
@@ -353,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
|
||||
* 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
|
||||
eqBound(bound, v, pos, true)
|
||||
}
|
||||
@@ -362,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
|
||||
* 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
|
||||
eqBound(bound, v, pos, true)
|
||||
}
|
||||
@@ -371,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`
|
||||
* 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
|
||||
upperBound(bound, v, pos, _) or
|
||||
eqBound(bound, v, 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)
|
||||
}
|
||||
|
||||
/** 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)
|
||||
}
|
||||
|
||||
/** 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)
|
||||
or
|
||||
lowerBound(bound, v, pos, false) and TZero() = semExprSign(bound)
|
||||
@@ -406,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`
|
||||
* 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)
|
||||
or
|
||||
s = TNeg() and negBound(_, v, pos)
|
||||
@@ -419,7 +420,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
* might be ruled out by a guard.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private Sign guardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
private Sign guardedSsaSign(SemSsaVariable v, SsaReadPosition pos) {
|
||||
result = semSsaDefSign(v) and
|
||||
pos.hasReadOfVar(v) and
|
||||
hasGuard(v, pos, result)
|
||||
@@ -430,7 +431,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
* can rule it out.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private Sign unguardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
private Sign unguardedSsaSign(SemSsaVariable v, SsaReadPosition pos) {
|
||||
result = semSsaDefSign(v) and
|
||||
pos.hasReadOfVar(v) and
|
||||
not hasGuard(v, pos, result)
|
||||
@@ -441,7 +442,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
* ruled out the sign but does not.
|
||||
* 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
|
||||
forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos))
|
||||
or
|
||||
@@ -453,7 +454,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
}
|
||||
|
||||
/** 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)
|
||||
or
|
||||
result = guardedSsaSign(v, pos) and
|
||||
@@ -469,7 +470,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
Sign semExprSign(SemExpr e) {
|
||||
exists(Sign s | s = e.(SignExpr).getSign() |
|
||||
if
|
||||
Utils::getTrackedType(e) instanceof SemUnsignedIntegerType and
|
||||
Sem::getExprType(e) instanceof SemUnsignedIntegerType and
|
||||
s = TNeg() and
|
||||
not Specific::ignoreTypeRestrictions(e)
|
||||
then result = TPos()
|
||||
|
||||
@@ -23,9 +23,7 @@
|
||||
* configuration (see `InvalidPointerToDerefConfig`).
|
||||
*
|
||||
* The dataflow traversal defines the set of sources as any dataflow node `n` such that there exists a pointer-arithmetic
|
||||
* instruction `pai` found by `AllocationToInvalidPointer.qll` and a `n.asInstruction() >= pai + deltaDerefSourceAndPai`.
|
||||
* Here, `deltaDerefSourceAndPai` is the constant difference between the source we track for finding a dereference and the
|
||||
* pointer-arithmetic instruction.
|
||||
* instruction `pai` found by `AllocationToInvalidPointer.qll` and a `n.asInstruction() = pai`.
|
||||
*
|
||||
* The set of sinks is defined as any dataflow node `n` such that `addr <= n.asInstruction() + deltaDerefSinkAndDerefAddress`
|
||||
* for some address operand `addr` and constant difference `deltaDerefSinkAndDerefAddress`. Since an address operand is
|
||||
@@ -37,9 +35,8 @@
|
||||
* `deltaDerefSinkAndDerefAddress >= 0`. The load attached to `*p` is the "operation". To ensure that the path makes
|
||||
* intuitive sense, we only pick operations that are control-flow reachable from the dereference sink.
|
||||
*
|
||||
* To compute how many elements the dereference is beyond the end position of the allocation, we sum the two deltas
|
||||
* `deltaDerefSourceAndPai` and `deltaDerefSinkAndDerefAddress`. This is done in the `operationIsOffBy` predicate
|
||||
* (which is the only predicate exposed by this file).
|
||||
* We use the `deltaDerefSinkAndDerefAddress` to compute how many elements the dereference is beyond the end position of
|
||||
* the allocation. This is done in the `operationIsOffBy` predicate (which is the only predicate exposed by this file).
|
||||
*
|
||||
* Handling false positives:
|
||||
*
|
||||
@@ -96,7 +93,7 @@ int invalidPointerToDereferenceFieldFlowBranchLimit() { result = 0 }
|
||||
private module InvalidPointerToDerefBarrier {
|
||||
private module BarrierConfig implements DataFlow::ConfigSig {
|
||||
additional predicate isSource(DataFlow::Node source, PointerArithmeticInstruction pai) {
|
||||
invalidPointerToDerefSource(_, pai, _, _) and
|
||||
invalidPointerToDerefSource(_, pai, _) and
|
||||
// source <= pai
|
||||
bounded2(source.asInstruction(), pai, any(int d | d <= 0))
|
||||
}
|
||||
@@ -169,11 +166,11 @@ private module InvalidPointerToDerefBarrier {
|
||||
*/
|
||||
private module InvalidPointerToDerefConfig implements DataFlow::StateConfigSig {
|
||||
class FlowState extends PointerArithmeticInstruction {
|
||||
FlowState() { invalidPointerToDerefSource(_, this, _, _) }
|
||||
FlowState() { invalidPointerToDerefSource(_, this, _) }
|
||||
}
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState pai) {
|
||||
invalidPointerToDerefSource(_, pai, source, _)
|
||||
invalidPointerToDerefSource(_, pai, source)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
@@ -198,24 +195,17 @@ private import DataFlow::GlobalWithState<InvalidPointerToDerefConfig>
|
||||
|
||||
/**
|
||||
* Holds if `allocSource` is dataflow node that represents an allocation that flows to the
|
||||
* left-hand side of the pointer-arithmetic `pai`, and `derefSource <= pai + derefSourcePaiDelta`.
|
||||
*
|
||||
* For example, if `pai` is a pointer-arithmetic operation `p + size` in an expression such
|
||||
* as `(p + size) + 1` and `derefSource` is the node representing `(p + size) + 1`. In this
|
||||
* case `derefSourcePaiDelta` is 1.
|
||||
* left-hand side of the pointer-arithmetic instruction represented by `derefSource`.
|
||||
*/
|
||||
private predicate invalidPointerToDerefSource(
|
||||
DataFlow::Node allocSource, PointerArithmeticInstruction pai, DataFlow::Node derefSource,
|
||||
int deltaDerefSourceAndPai
|
||||
DataFlow::Node allocSource, PointerArithmeticInstruction pai, DataFlow::Node derefSource
|
||||
) {
|
||||
// Note that `deltaDerefSourceAndPai` is not necessarily equal to `rhsSizeDelta`:
|
||||
// `rhsSizeDelta` is the constant offset added to the size of the allocation, and
|
||||
// `deltaDerefSourceAndPai` is the constant difference between the pointer-arithmetic instruction
|
||||
// and the instruction computing the address for which we will search for a dereference.
|
||||
AllocToInvalidPointer::pointerAddInstructionHasBounds(allocSource, pai, _, _) and
|
||||
// derefSource <= pai + deltaDerefSourceAndPai
|
||||
bounded2(derefSource.asInstruction(), pai, deltaDerefSourceAndPai) and
|
||||
deltaDerefSourceAndPai >= 0
|
||||
derefSource.asInstruction() = pai
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -258,11 +248,9 @@ private Instruction getASuccessor(Instruction instr) {
|
||||
instr.getBlock().getASuccessor+() = result.getBlock()
|
||||
}
|
||||
|
||||
private predicate paiForDereferenceSink(
|
||||
PointerArithmeticInstruction pai, DataFlow::Node derefSink, int deltaDerefSourceAndPai
|
||||
) {
|
||||
private predicate paiForDereferenceSink(PointerArithmeticInstruction pai, DataFlow::Node derefSink) {
|
||||
exists(DataFlow::Node derefSource |
|
||||
invalidPointerToDerefSource(_, pai, derefSource, deltaDerefSourceAndPai) and
|
||||
invalidPointerToDerefSource(_, pai, derefSource) and
|
||||
flow(derefSource, derefSink)
|
||||
)
|
||||
}
|
||||
@@ -274,10 +262,10 @@ private predicate paiForDereferenceSink(
|
||||
*/
|
||||
private predicate derefSinkToOperation(
|
||||
DataFlow::Node derefSink, PointerArithmeticInstruction pai, DataFlow::Node operation,
|
||||
string description, int deltaDerefSourceAndPai, int deltaDerefSinkAndDerefAddress
|
||||
string description, int deltaDerefSinkAndDerefAddress
|
||||
) {
|
||||
exists(Instruction operationInstr, AddressOperand addr |
|
||||
paiForDereferenceSink(pai, pragma[only_bind_into](derefSink), deltaDerefSourceAndPai) and
|
||||
paiForDereferenceSink(pai, pragma[only_bind_into](derefSink)) and
|
||||
isInvalidPointerDerefSink(derefSink, addr, operationInstr, description,
|
||||
deltaDerefSinkAndDerefAddress) and
|
||||
operationInstr = getASuccessor(derefSink.asInstruction()) and
|
||||
@@ -298,11 +286,7 @@ predicate operationIsOffBy(
|
||||
DataFlow::Node allocation, PointerArithmeticInstruction pai, DataFlow::Node derefSource,
|
||||
DataFlow::Node derefSink, string description, DataFlow::Node operation, int delta
|
||||
) {
|
||||
exists(int deltaDerefSourceAndPai, int deltaDerefSinkAndDerefAddress |
|
||||
invalidPointerToDerefSource(allocation, pai, derefSource, deltaDerefSourceAndPai) and
|
||||
flow(derefSource, derefSink) and
|
||||
derefSinkToOperation(derefSink, pai, operation, description, deltaDerefSourceAndPai,
|
||||
deltaDerefSinkAndDerefAddress) and
|
||||
delta = deltaDerefSourceAndPai + deltaDerefSinkAndDerefAddress
|
||||
)
|
||||
invalidPointerToDerefSource(allocation, pai, derefSource) and
|
||||
flow(derefSource, derefSink) and
|
||||
derefSinkToOperation(derefSink, pai, operation, description, delta)
|
||||
}
|
||||
|
||||
@@ -1334,11 +1334,16 @@ funbind(
|
||||
| @assignxorexpr
|
||||
| @assignlshiftexpr
|
||||
| @assignrshiftexpr
|
||||
| @assignpaddexpr
|
||||
;
|
||||
|
||||
@assign_pointer_expr = @assignpaddexpr
|
||||
| @assignpsubexpr
|
||||
;
|
||||
|
||||
@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr
|
||||
@assign_op_expr = @assign_arith_expr
|
||||
| @assign_bitwise_expr
|
||||
| @assign_pointer_expr
|
||||
;
|
||||
|
||||
@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Removed @assignpaddexpr and @assignpsubexpr from @assign_bitwise_expr
|
||||
compatibility: full
|
||||
@@ -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
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -27,16 +27,26 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
||||
ReturnStackAllocatedMemoryConfig() { this = "ReturnStackAllocatedMemoryConfig" }
|
||||
|
||||
override predicate isSource(Instruction source) {
|
||||
// Holds if `source` is a node that represents the use of a stack variable
|
||||
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
|
||||
exists(Function func |
|
||||
// Rule out FPs caused by extraction errors.
|
||||
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
|
||||
MustFlowPathNode source, MustFlowPathNode sink, VariableAddressInstruction var,
|
||||
MustFlowPathNode source, MustFlowPathNode sink, Instruction instr,
|
||||
ReturnStackAllocatedMemoryConfig conf
|
||||
where
|
||||
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 $@.",
|
||||
var.getAst(), var.getAst().toString()
|
||||
instr.getAst(), instr.getAst().toString()
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
*/
|
||||
|
||||
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
|
||||
@@ -33,31 +34,6 @@ predicate allocatedType(Type t) {
|
||||
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]
|
||||
predicate containsInlineAssembly(Function f) { exists(AsmStmt s | s.getEnclosingFunction() = f) }
|
||||
|
||||
@@ -82,8 +58,33 @@ VariableAccess commonException() {
|
||||
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
|
||||
r.reaches(_, v, va) and
|
||||
not va = commonException()
|
||||
conf.hasFlowPath(source, sink) and
|
||||
isSinkImpl(sink.getInstruction(), va) and
|
||||
v = va.getTarget()
|
||||
select va, "The variable $@ may not be initialized at this access.", v, v.getName()
|
||||
|
||||
@@ -14,25 +14,47 @@
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.security.Security
|
||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
||||
import TaintedWithPath
|
||||
import semmle.code.cpp.security.FlowSources
|
||||
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 |
|
||||
isProcessOperationArgument(processOperation, processOperationArg) and
|
||||
call.getTarget().getName() = processOperation and
|
||||
call.getArgument(processOperationArg) = arg
|
||||
call.getArgument(processOperationArg) = [arg.asExpr(), arg.asIndirectExpr()]
|
||||
)
|
||||
}
|
||||
|
||||
class Configuration extends TaintTrackingConfiguration {
|
||||
override predicate isSink(Element arg) { isProcessOperationExplanation(arg, _) }
|
||||
predicate isSource(FlowSource source, string sourceType) {
|
||||
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
|
||||
isProcessOperationExplanation(arg, processOperation) and
|
||||
taintedWithPath(source, arg, sourceNode, sinkNode)
|
||||
select arg, sourceNode, sinkNode,
|
||||
source = sourceNode.getNode() and
|
||||
sink = sinkNode.getNode() and
|
||||
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 + ".",
|
||||
source, source.toString()
|
||||
source, sourceType
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.security.BufferWrite
|
||||
import semmle.code.cpp.security.Security
|
||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
||||
import TaintedWithPath
|
||||
import semmle.code.cpp.security.FlowSources as FS
|
||||
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||
import semmle.code.cpp.controlflow.IRGuards
|
||||
import Flow::PathGraph
|
||||
|
||||
/*
|
||||
* --- 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
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* qualifier of (a qualifier of ...) such a source.
|
||||
*/
|
||||
predicate unboundedWriteSource(Expr e, BufferWrite bw) {
|
||||
isUnboundedWrite(bw) and e = bw.getASource()
|
||||
predicate unboundedWriteSource(Expr e, BufferWrite bw, boolean qualifier) {
|
||||
isUnboundedWrite(bw) and e = bw.getASource() and qualifier = false
|
||||
or
|
||||
exists(FieldAccess fa | unboundedWriteSource(fa, bw) and e = fa.getQualifier())
|
||||
exists(FieldAccess fa | unboundedWriteSource(fa, bw, _) and e = fa.getQualifier()) and
|
||||
qualifier = true
|
||||
}
|
||||
|
||||
/*
|
||||
* --- user input reach ---
|
||||
*/
|
||||
predicate isSource(FS::FlowSource source, string sourceType) { source.getSourceType() = sourceType }
|
||||
|
||||
class Configuration extends TaintTrackingConfiguration {
|
||||
override predicate isSink(Element tainted) { unboundedWriteSource(tainted, _) }
|
||||
|
||||
override predicate taintThroughGlobals() { any() }
|
||||
predicate isSink(DataFlow::Node sink, BufferWrite bw, boolean qualifier) {
|
||||
unboundedWriteSource(sink.asIndirectExpr(), bw, qualifier)
|
||||
or
|
||||
// `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)
|
||||
}
|
||||
|
||||
/*
|
||||
* --- put it together ---
|
||||
*/
|
||||
predicate lessThanOrEqual(IRGuardCondition g, Expr e, boolean branch) {
|
||||
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
|
||||
@@ -87,17 +104,20 @@ class Configuration extends TaintTrackingConfiguration {
|
||||
*
|
||||
* 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
|
||||
* destination buffer. Since those destination-buffer arguments are also
|
||||
* modeled in the taint-tracking library as being _sources_ of taint, they are
|
||||
* in practice reported as being tainted because the `security.TaintTracking`
|
||||
* library does not distinguish between taint going into an argument and out of
|
||||
* an argument. Thus, we get the desired alerts.
|
||||
* destination buffer. So to report an alert on a pattern like:
|
||||
* ```
|
||||
* char s[32];
|
||||
* gets(s);
|
||||
* ```
|
||||
* 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
|
||||
taintedWithPath(inputSource, tainted, sourceNode, sinkNode) and
|
||||
unboundedWriteSource(tainted, bw)
|
||||
select bw, sourceNode, sinkNode,
|
||||
"This '" + bw.getBWDesc() + "' with input from $@ may overflow the destination.", inputSource,
|
||||
inputSource.toString()
|
||||
Flow::flowPath(source, sink) and
|
||||
isSource(source.getNode(), sourceType) and
|
||||
isSink(sink.getNode(), bw, _)
|
||||
select bw, source, sink,
|
||||
"This '" + bw.getBWDesc() + "' with input from $@ may overflow the destination.",
|
||||
source.getNode(), sourceType
|
||||
|
||||
@@ -14,10 +14,13 @@
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.security.Overflow
|
||||
import semmle.code.cpp.security.Security
|
||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
||||
import TaintedWithPath
|
||||
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
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 Flow::PathGraph
|
||||
|
||||
bindingset[op]
|
||||
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"
|
||||
}
|
||||
|
||||
class Configuration extends TaintTrackingConfiguration {
|
||||
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
|
||||
)
|
||||
}
|
||||
predicate isSource(FS::FlowSource source, string sourceType) { sourceType = source.getSourceType() }
|
||||
|
||||
override predicate isBarrier(Expr e) {
|
||||
super.isBarrier(e) or bounded(e) or e.getUnspecifiedType().(IntegralType).getSize() <= 1
|
||||
predicate isSink(DataFlow::Node sink, Operation op, Expr e) {
|
||||
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
|
||||
taintedWithPath(origin, e, sourceNode, sinkNode) and
|
||||
op.getAnOperand() = e and
|
||||
Flow::flowPath(source, sink) and
|
||||
isSource(source.getNode(), sourceType) and
|
||||
isSink(sink.getNode(), op, e) and
|
||||
missingGuard(op, e, effect)
|
||||
select e, sourceNode, sinkNode,
|
||||
select e, source, sink,
|
||||
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
|
||||
origin, "User-provided value"
|
||||
source, sourceType
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
* @id cpp/invalid-pointer-deref
|
||||
* @tags reliability
|
||||
* security
|
||||
* experimental
|
||||
* external/cwe/cwe-119
|
||||
* external/cwe/cwe-125
|
||||
* external/cwe/cwe-193
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.models.interfaces.FlowSource
|
||||
import semmle.code.cpp.models.implementations.Memset
|
||||
import ExposedSystemData::PathGraph
|
||||
import SystemData
|
||||
|
||||
@@ -28,6 +29,10 @@ module ExposedSystemDataConfig implements DataFlow::ConfigSig {
|
||||
fc.getArgument(arg).getAChild*() = sink.asIndirectExpr()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.asIndirectArgument() = any(MemsetFunction func).getACallToThisFunction().getAnArgument()
|
||||
}
|
||||
}
|
||||
|
||||
module ExposedSystemData = TaintTracking::Global<ExposedSystemDataConfig>;
|
||||
|
||||
@@ -28,6 +28,7 @@ import cpp
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.models.interfaces.FlowSource
|
||||
import semmle.code.cpp.security.OutputWrite
|
||||
import semmle.code.cpp.models.implementations.Memset
|
||||
import PotentiallyExposedSystemData::PathGraph
|
||||
import SystemData
|
||||
|
||||
@@ -49,6 +50,10 @@ module PotentiallyExposedSystemDataConfig implements DataFlow::ConfigSig {
|
||||
else child = sink.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.asIndirectArgument() = any(MemsetFunction func).getACallToThisFunction().getAnArgument()
|
||||
}
|
||||
}
|
||||
|
||||
module PotentiallyExposedSystemData = TaintTracking::Global<PotentiallyExposedSystemDataConfig>;
|
||||
|
||||
@@ -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.
|
||||
* @kind metric
|
||||
* @tags summary
|
||||
* telemetry
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.8.2
|
||||
version: 0.8.3
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -29,7 +29,6 @@ edges
|
||||
| test.cpp:69:10:69:10 | arr indirection [post update] [p] | test.cpp:70:5:70:7 | arr indirection [p] |
|
||||
| test.cpp:69:14:69:19 | call to malloc | test.cpp:69:5:69:25 | ... = ... |
|
||||
| test.cpp:70:5:70:7 | arr indirection [p] | test.cpp:67:10:67:19 | mk_array_p indirection [p] |
|
||||
| test.cpp:70:5:70:7 | arr indirection [p] | test.cpp:70:5:70:7 | arr indirection [p] |
|
||||
| test.cpp:76:20:76:29 | call to mk_array_p indirection [p] | test.cpp:79:9:79:11 | arr indirection [p] |
|
||||
| test.cpp:76:20:76:29 | call to mk_array_p indirection [p] | test.cpp:83:9:83:11 | arr indirection [p] |
|
||||
| test.cpp:79:9:79:11 | arr indirection [p] | test.cpp:79:14:79:14 | p |
|
||||
|
||||
@@ -23,6 +23,7 @@ argHasPostUpdate
|
||||
| lambdas.cpp:38:2:38:2 | d | 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:813:19:813:35 | * ... | ArgumentNode is missing PostUpdateNode. |
|
||||
postWithInFlow
|
||||
| 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. |
|
||||
@@ -41,6 +42,9 @@ postWithInFlow
|
||||
| example.c:26:9:26:9 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| example.c:26:19:26:24 | coords [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| example.c:28:23:28:25 | pos [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| flowOut.cpp:5:5:5:12 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| flowOut.cpp:5:6:5:12 | toTaint [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| flowOut.cpp:18:17:18:17 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| globals.cpp:13:5:13:19 | flowTestGlobal1 [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| globals.cpp:23:5:23:19 | flowTestGlobal2 [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:23:3:23:14 | v [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
@@ -133,6 +137,9 @@ postWithInFlow
|
||||
| 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: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
|
||||
uniqueParameterNodeAtPosition
|
||||
uniqueParameterNodePosition
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
int source();
|
||||
void sink(int);
|
||||
|
||||
void source_ref(int *toTaint) { // $ ir-def=*toTaint ast-def=toTaint
|
||||
*toTaint = source();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void modify_copy(int* ptr) { // $ ast-def=ptr
|
||||
int deref = *ptr;
|
||||
int* other = &deref;
|
||||
source_ref(other);
|
||||
}
|
||||
|
||||
void test_output() {
|
||||
int x = 0;
|
||||
modify_copy(&x);
|
||||
sink(x); // $ SPURIOUS: ir
|
||||
}
|
||||
@@ -796,4 +796,44 @@ void test() {
|
||||
MyStruct a;
|
||||
intPointerSource(a.content, a.content);
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,6 @@ edges
|
||||
| A.cpp:152:10:152:10 | d indirection [b] | A.cpp:152:10:152:13 | b |
|
||||
| A.cpp:153:10:153:10 | d indirection [b indirection, c] | A.cpp:153:13:153:13 | b indirection [c] |
|
||||
| A.cpp:153:13:153:13 | b indirection [c] | A.cpp:153:10:153:16 | c |
|
||||
| A.cpp:153:13:153:13 | b indirection [c] | A.cpp:153:13:153:13 | b indirection [c] |
|
||||
| A.cpp:154:10:154:10 | b indirection [c] | A.cpp:154:10:154:13 | c |
|
||||
| A.cpp:159:12:159:18 | new | A.cpp:160:29:160:29 | b |
|
||||
| A.cpp:160:18:160:60 | call to MyList [head] | A.cpp:161:38:161:39 | l1 indirection [head] |
|
||||
@@ -97,10 +96,8 @@ edges
|
||||
| A.cpp:162:38:162:39 | l2 indirection [next indirection, head] | A.cpp:162:18:162:40 | call to MyList [next indirection, next indirection, head] |
|
||||
| A.cpp:162:38:162:39 | l2 indirection [next indirection, head] | A.cpp:181:32:181:35 | next indirection [next indirection, head] |
|
||||
| A.cpp:165:10:165:11 | l3 indirection [next indirection, next indirection, head] | A.cpp:165:14:165:17 | next indirection [next indirection, head] |
|
||||
| A.cpp:165:14:165:17 | next indirection [next indirection, head] | A.cpp:165:14:165:17 | next indirection [next indirection, head] |
|
||||
| A.cpp:165:14:165:17 | next indirection [next indirection, head] | A.cpp:165:20:165:23 | next indirection [head] |
|
||||
| A.cpp:165:20:165:23 | next indirection [head] | A.cpp:165:10:165:29 | head |
|
||||
| A.cpp:165:20:165:23 | next indirection [head] | A.cpp:165:20:165:23 | next indirection [head] |
|
||||
| A.cpp:167:44:167:44 | l indirection [next indirection, head] | A.cpp:167:47:167:50 | next indirection [head] |
|
||||
| A.cpp:167:44:167:44 | l indirection [next indirection, next indirection, head] | A.cpp:167:47:167:50 | next indirection [next indirection, head] |
|
||||
| A.cpp:167:47:167:50 | next indirection [head] | A.cpp:169:12:169:12 | l indirection [head] |
|
||||
@@ -121,7 +118,6 @@ edges
|
||||
| B.cpp:8:25:8:26 | b1 indirection [elem1] | B.cpp:44:16:44:17 | b1 indirection [elem1] |
|
||||
| B.cpp:9:10:9:11 | b2 indirection [box1 indirection, elem1] | B.cpp:9:14:9:17 | box1 indirection [elem1] |
|
||||
| B.cpp:9:14:9:17 | box1 indirection [elem1] | B.cpp:9:10:9:24 | elem1 |
|
||||
| B.cpp:9:14:9:17 | box1 indirection [elem1] | B.cpp:9:14:9:17 | box1 indirection [elem1] |
|
||||
| B.cpp:15:15:15:27 | new | B.cpp:16:37:16:37 | e |
|
||||
| B.cpp:16:16:16:38 | call to Box1 [elem2] | B.cpp:17:25:17:26 | b1 indirection [elem2] |
|
||||
| B.cpp:16:37:16:37 | e | B.cpp:16:16:16:38 | call to Box1 [elem2] |
|
||||
@@ -131,7 +127,6 @@ edges
|
||||
| B.cpp:17:25:17:26 | b1 indirection [elem2] | B.cpp:44:16:44:17 | b1 indirection [elem2] |
|
||||
| B.cpp:19:10:19:11 | b2 indirection [box1 indirection, elem2] | B.cpp:19:14:19:17 | box1 indirection [elem2] |
|
||||
| B.cpp:19:14:19:17 | box1 indirection [elem2] | B.cpp:19:10:19:24 | elem2 |
|
||||
| B.cpp:19:14:19:17 | box1 indirection [elem2] | B.cpp:19:14:19:17 | box1 indirection [elem2] |
|
||||
| B.cpp:33:16:33:17 | e1 | B.cpp:35:7:35:22 | ... = ... |
|
||||
| B.cpp:33:26:33:27 | e2 | B.cpp:36:7:36:22 | ... = ... |
|
||||
| B.cpp:35:7:35:22 | ... = ... | B.cpp:35:13:35:17 | this indirection [post update] [elem1] |
|
||||
@@ -196,17 +191,12 @@ edges
|
||||
| D.cpp:58:20:58:23 | box indirection [post update] [elem] | D.cpp:58:15:58:17 | boxfield indirection [post update] [box indirection, elem] |
|
||||
| D.cpp:59:5:59:7 | this indirection [boxfield indirection, box indirection, elem] | D.cpp:63:8:63:10 | this indirection [boxfield indirection, box indirection, elem] |
|
||||
| D.cpp:63:8:63:10 | this indirection [boxfield indirection, box indirection, elem] | D.cpp:64:10:64:17 | this indirection [boxfield indirection, box indirection, elem] |
|
||||
| D.cpp:64:10:64:17 | boxfield indirection [box indirection, elem] | D.cpp:64:10:64:17 | boxfield indirection [box indirection, elem] |
|
||||
| D.cpp:64:10:64:17 | boxfield indirection [box indirection, elem] | D.cpp:64:20:64:22 | box indirection [elem] |
|
||||
| D.cpp:64:10:64:17 | this indirection [boxfield indirection, box indirection, elem] | D.cpp:64:10:64:17 | boxfield indirection [box indirection, elem] |
|
||||
| D.cpp:64:20:64:22 | box indirection [elem] | D.cpp:64:10:64:28 | elem |
|
||||
| D.cpp:64:20:64:22 | box indirection [elem] | D.cpp:64:20:64:22 | box indirection [elem] |
|
||||
| E.cpp:19:27:19:27 | p indirection [data, buffer indirection] | E.cpp:21:10:21:10 | p indirection [data, buffer indirection] |
|
||||
| E.cpp:21:10:21:10 | p indirection [data, buffer indirection] | E.cpp:21:13:21:16 | data indirection [buffer indirection] |
|
||||
| E.cpp:21:13:21:16 | data indirection [buffer indirection] | E.cpp:21:18:21:23 | buffer indirection |
|
||||
| E.cpp:21:13:21:16 | data indirection [buffer indirection] | E.cpp:21:18:21:23 | buffer indirection |
|
||||
| E.cpp:21:18:21:23 | buffer indirection | E.cpp:21:18:21:23 | buffer indirection |
|
||||
| E.cpp:21:18:21:23 | buffer indirection | E.cpp:21:18:21:23 | buffer indirection |
|
||||
| E.cpp:28:21:28:23 | argument_source output argument | E.cpp:31:10:31:12 | raw indirection |
|
||||
| E.cpp:29:21:29:29 | argument_source output argument | E.cpp:29:24:29:29 | b indirection [post update] [buffer indirection] |
|
||||
| E.cpp:29:24:29:29 | b indirection [post update] [buffer indirection] | E.cpp:32:10:32:10 | b indirection [buffer indirection] |
|
||||
@@ -214,9 +204,6 @@ edges
|
||||
| E.cpp:30:23:30:26 | p indirection [post update] [data, buffer indirection] | E.cpp:33:18:33:19 | & ... indirection [data, buffer indirection] |
|
||||
| E.cpp:30:28:30:33 | data indirection [post update] [buffer indirection] | E.cpp:30:23:30:26 | p indirection [post update] [data, buffer indirection] |
|
||||
| E.cpp:32:10:32:10 | b indirection [buffer indirection] | E.cpp:32:13:32:18 | buffer indirection |
|
||||
| E.cpp:32:10:32:10 | b indirection [buffer indirection] | E.cpp:32:13:32:18 | buffer indirection |
|
||||
| E.cpp:32:13:32:18 | buffer indirection | E.cpp:32:13:32:18 | buffer indirection |
|
||||
| E.cpp:32:13:32:18 | buffer indirection | E.cpp:32:13:32:18 | buffer indirection |
|
||||
| E.cpp:33:18:33:19 | & ... indirection [data, buffer indirection] | E.cpp:19:27:19:27 | p indirection [data, buffer indirection] |
|
||||
| aliasing.cpp:9:3:9:22 | ... = ... | aliasing.cpp:9:6:9:7 | s indirection [post update] [m1] |
|
||||
| aliasing.cpp:9:6:9:7 | s indirection [post update] [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] |
|
||||
@@ -311,11 +298,9 @@ edges
|
||||
| arrays.cpp:43:8:43:8 | o indirection [indirect indirection, arr, data] | arrays.cpp:43:10:43:17 | indirect indirection [arr, data] |
|
||||
| arrays.cpp:43:8:43:25 | access to array indirection [data] | arrays.cpp:43:27:43:30 | data |
|
||||
| arrays.cpp:43:10:43:17 | indirect indirection [arr, data] | arrays.cpp:43:8:43:25 | access to array indirection [data] |
|
||||
| arrays.cpp:43:10:43:17 | indirect indirection [arr, data] | arrays.cpp:43:10:43:17 | indirect indirection [arr, data] |
|
||||
| arrays.cpp:44:8:44:8 | o indirection [indirect indirection, arr, data] | arrays.cpp:44:10:44:17 | indirect indirection [arr, data] |
|
||||
| arrays.cpp:44:8:44:25 | access to array indirection [data] | arrays.cpp:44:27:44:30 | data |
|
||||
| arrays.cpp:44:10:44:17 | indirect indirection [arr, data] | arrays.cpp:44:8:44:25 | access to array indirection [data] |
|
||||
| arrays.cpp:44:10:44:17 | indirect indirection [arr, data] | arrays.cpp:44:10:44:17 | indirect indirection [arr, data] |
|
||||
| arrays.cpp:48:3:48:40 | ... = ... | arrays.cpp:48:22:48:25 | access to array indirection [post update] [data] |
|
||||
| arrays.cpp:48:5:48:12 | o indirection [post update] [indirect indirection, ptr indirection, data] | arrays.cpp:49:8:49:8 | o indirection [indirect indirection, ptr indirection, data] |
|
||||
| arrays.cpp:48:5:48:12 | o indirection [post update] [indirect indirection, ptr indirection, data] | arrays.cpp:50:8:50:8 | o indirection [indirect indirection, ptr indirection, data] |
|
||||
@@ -325,13 +310,11 @@ edges
|
||||
| arrays.cpp:49:8:49:8 | o indirection [indirect indirection, ptr indirection, data] | arrays.cpp:49:10:49:17 | indirect indirection [ptr indirection, data] |
|
||||
| arrays.cpp:49:8:49:25 | access to array indirection [data] | arrays.cpp:49:27:49:30 | data |
|
||||
| arrays.cpp:49:10:49:17 | indirect indirection [ptr indirection, data] | arrays.cpp:49:8:49:25 | access to array indirection [data] |
|
||||
| arrays.cpp:49:10:49:17 | indirect indirection [ptr indirection, data] | arrays.cpp:49:10:49:17 | indirect indirection [ptr indirection, data] |
|
||||
| arrays.cpp:49:10:49:17 | indirect indirection [ptr indirection, data] | arrays.cpp:49:20:49:22 | ptr indirection [data] |
|
||||
| arrays.cpp:49:20:49:22 | ptr indirection [data] | arrays.cpp:49:8:49:25 | access to array indirection [data] |
|
||||
| arrays.cpp:50:8:50:8 | o indirection [indirect indirection, ptr indirection, data] | arrays.cpp:50:10:50:17 | indirect indirection [ptr indirection, data] |
|
||||
| arrays.cpp:50:8:50:25 | access to array indirection [data] | arrays.cpp:50:27:50:30 | data |
|
||||
| arrays.cpp:50:10:50:17 | indirect indirection [ptr indirection, data] | arrays.cpp:50:8:50:25 | access to array indirection [data] |
|
||||
| arrays.cpp:50:10:50:17 | indirect indirection [ptr indirection, data] | arrays.cpp:50:10:50:17 | indirect indirection [ptr indirection, data] |
|
||||
| arrays.cpp:50:10:50:17 | indirect indirection [ptr indirection, data] | arrays.cpp:50:20:50:22 | ptr indirection [data] |
|
||||
| arrays.cpp:50:20:50:22 | ptr indirection [data] | arrays.cpp:50:8:50:25 | access to array indirection [data] |
|
||||
| by_reference.cpp:11:48:11:52 | value | by_reference.cpp:12:5:12:16 | ... = ... |
|
||||
@@ -411,13 +394,11 @@ edges
|
||||
| by_reference.cpp:110:8:110:12 | outer indirection [inner_nested, a] | by_reference.cpp:110:14:110:25 | inner_nested indirection [a] |
|
||||
| by_reference.cpp:110:14:110:25 | inner_nested indirection [a] | by_reference.cpp:110:27:110:27 | a |
|
||||
| by_reference.cpp:111:8:111:12 | outer indirection [inner_ptr indirection, a] | by_reference.cpp:111:14:111:22 | inner_ptr indirection [a] |
|
||||
| by_reference.cpp:111:14:111:22 | inner_ptr indirection [a] | by_reference.cpp:111:14:111:22 | inner_ptr indirection [a] |
|
||||
| by_reference.cpp:111:14:111:22 | inner_ptr indirection [a] | by_reference.cpp:111:25:111:25 | a |
|
||||
| by_reference.cpp:112:8:112:12 | outer indirection [a] | by_reference.cpp:112:14:112:14 | a |
|
||||
| by_reference.cpp:114:8:114:13 | pouter indirection [inner_nested, a] | by_reference.cpp:114:16:114:27 | inner_nested indirection [a] |
|
||||
| by_reference.cpp:114:16:114:27 | inner_nested indirection [a] | by_reference.cpp:114:29:114:29 | a |
|
||||
| by_reference.cpp:115:8:115:13 | pouter indirection [inner_ptr indirection, a] | by_reference.cpp:115:16:115:24 | inner_ptr indirection [a] |
|
||||
| by_reference.cpp:115:16:115:24 | inner_ptr indirection [a] | by_reference.cpp:115:16:115:24 | inner_ptr indirection [a] |
|
||||
| by_reference.cpp:115:16:115:24 | inner_ptr indirection [a] | by_reference.cpp:115:27:115:27 | a |
|
||||
| by_reference.cpp:116:8:116:13 | pouter indirection [a] | by_reference.cpp:116:16:116:16 | a |
|
||||
| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:27:122:38 | outer indirection [post update] [inner_nested, a] |
|
||||
@@ -435,13 +416,11 @@ edges
|
||||
| by_reference.cpp:130:8:130:12 | outer indirection [inner_nested, a] | by_reference.cpp:130:14:130:25 | inner_nested indirection [a] |
|
||||
| by_reference.cpp:130:14:130:25 | inner_nested indirection [a] | by_reference.cpp:130:27:130:27 | a |
|
||||
| by_reference.cpp:131:8:131:12 | outer indirection [inner_ptr indirection, a] | by_reference.cpp:131:14:131:22 | inner_ptr indirection [a] |
|
||||
| by_reference.cpp:131:14:131:22 | inner_ptr indirection [a] | by_reference.cpp:131:14:131:22 | inner_ptr indirection [a] |
|
||||
| by_reference.cpp:131:14:131:22 | inner_ptr indirection [a] | by_reference.cpp:131:25:131:25 | a |
|
||||
| by_reference.cpp:132:8:132:12 | outer indirection [a] | by_reference.cpp:132:14:132:14 | a |
|
||||
| by_reference.cpp:134:8:134:13 | pouter indirection [inner_nested, a] | by_reference.cpp:134:16:134:27 | inner_nested indirection [a] |
|
||||
| by_reference.cpp:134:16:134:27 | inner_nested indirection [a] | by_reference.cpp:134:29:134:29 | a |
|
||||
| by_reference.cpp:135:8:135:13 | pouter indirection [inner_ptr indirection, a] | by_reference.cpp:135:16:135:24 | inner_ptr indirection [a] |
|
||||
| by_reference.cpp:135:16:135:24 | inner_ptr indirection [a] | by_reference.cpp:135:16:135:24 | inner_ptr indirection [a] |
|
||||
| by_reference.cpp:135:16:135:24 | inner_ptr indirection [a] | by_reference.cpp:135:27:135:27 | a |
|
||||
| by_reference.cpp:136:8:136:13 | pouter indirection [a] | by_reference.cpp:136:16:136:16 | a |
|
||||
| clearning.cpp:32:3:32:25 | ... = ... | clearning.cpp:32:6:32:6 | s indirection [post update] [x indirection] |
|
||||
@@ -460,9 +439,6 @@ edges
|
||||
| clearning.cpp:54:5:54:5 | s indirection [post update] [x indirection] | clearning.cpp:55:8:55:8 | s indirection [x indirection] |
|
||||
| clearning.cpp:54:5:54:5 | x indirection | clearning.cpp:54:3:54:7 | ... ++ indirection |
|
||||
| clearning.cpp:55:8:55:8 | s indirection [x indirection] | clearning.cpp:55:10:55:10 | x indirection |
|
||||
| clearning.cpp:55:8:55:8 | s indirection [x indirection] | clearning.cpp:55:10:55:10 | x indirection |
|
||||
| clearning.cpp:55:10:55:10 | x indirection | clearning.cpp:55:10:55:10 | x indirection |
|
||||
| clearning.cpp:55:10:55:10 | x indirection | clearning.cpp:55:10:55:10 | x indirection |
|
||||
| clearning.cpp:60:3:60:22 | ... = ... | clearning.cpp:60:7:60:7 | s indirection [post update] [x indirection] |
|
||||
| clearning.cpp:60:7:60:7 | s indirection [post update] [x indirection] | clearning.cpp:61:3:61:3 | s indirection [x indirection] |
|
||||
| clearning.cpp:60:11:60:20 | call to user_input | clearning.cpp:60:3:60:22 | ... = ... |
|
||||
@@ -474,9 +450,6 @@ edges
|
||||
| clearning.cpp:61:5:61:5 | s indirection [post update] [x indirection] | clearning.cpp:62:8:62:8 | s indirection [x indirection] |
|
||||
| clearning.cpp:61:5:61:5 | x indirection | clearning.cpp:61:3:61:7 | ... ++ indirection |
|
||||
| clearning.cpp:62:8:62:8 | s indirection [x indirection] | clearning.cpp:62:10:62:10 | x indirection |
|
||||
| clearning.cpp:62:8:62:8 | s indirection [x indirection] | clearning.cpp:62:10:62:10 | x indirection |
|
||||
| clearning.cpp:62:10:62:10 | x indirection | clearning.cpp:62:10:62:10 | x indirection |
|
||||
| clearning.cpp:62:10:62:10 | x indirection | clearning.cpp:62:10:62:10 | x indirection |
|
||||
| clearning.cpp:74:20:74:22 | argument_source output argument | clearning.cpp:74:20:74:22 | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:74:20:74:22 | s indirection [post update] [val indirection] | clearning.cpp:76:8:76:8 | s indirection [val indirection] |
|
||||
| clearning.cpp:76:8:76:8 | s indirection [val indirection] | clearning.cpp:76:7:76:12 | * ... |
|
||||
@@ -620,14 +593,12 @@ edges
|
||||
| conflated.cpp:54:13:54:13 | next indirection [post update] [y] | conflated.cpp:54:7:54:10 | ll indirection [post update] [next indirection, y] |
|
||||
| conflated.cpp:54:17:54:26 | call to user_input | conflated.cpp:54:3:54:28 | ... = ... |
|
||||
| conflated.cpp:55:8:55:9 | ll indirection [next indirection, y] | conflated.cpp:55:12:55:15 | next indirection [y] |
|
||||
| conflated.cpp:55:12:55:15 | next indirection [y] | conflated.cpp:55:12:55:15 | next indirection [y] |
|
||||
| conflated.cpp:55:12:55:15 | next indirection [y] | conflated.cpp:55:18:55:18 | y |
|
||||
| conflated.cpp:60:3:60:28 | ... = ... | conflated.cpp:60:13:60:13 | next indirection [post update] [y] |
|
||||
| conflated.cpp:60:7:60:10 | ll indirection [post update] [next indirection, y] | conflated.cpp:61:8:61:9 | ll indirection [next indirection, y] |
|
||||
| conflated.cpp:60:13:60:13 | next indirection [post update] [y] | conflated.cpp:60:7:60:10 | ll indirection [post update] [next indirection, y] |
|
||||
| conflated.cpp:60:17:60:26 | call to user_input | conflated.cpp:60:3:60:28 | ... = ... |
|
||||
| conflated.cpp:61:8:61:9 | ll indirection [next indirection, y] | conflated.cpp:61:12:61:15 | next indirection [y] |
|
||||
| conflated.cpp:61:12:61:15 | next indirection [y] | conflated.cpp:61:12:61:15 | next indirection [y] |
|
||||
| conflated.cpp:61:12:61:15 | next indirection [y] | conflated.cpp:61:18:61:18 | y |
|
||||
| constructors.cpp:18:9:18:9 | this indirection [a_] | constructors.cpp:18:22:18:23 | this indirection [a_] |
|
||||
| constructors.cpp:18:22:18:23 | a_ | constructors.cpp:18:9:18:9 | a indirection |
|
||||
@@ -672,42 +643,36 @@ edges
|
||||
| qualifiers.cpp:22:23:22:23 | call to getInner indirection [post update] [a] | qualifiers.cpp:22:5:22:9 | getInner output argument [inner indirection, a] |
|
||||
| qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:22:5:22:38 | ... = ... |
|
||||
| qualifiers.cpp:23:10:23:14 | outer indirection [inner indirection, a] | qualifiers.cpp:23:16:23:20 | inner indirection [a] |
|
||||
| qualifiers.cpp:23:16:23:20 | inner indirection [a] | qualifiers.cpp:23:16:23:20 | inner indirection [a] |
|
||||
| qualifiers.cpp:23:16:23:20 | inner indirection [a] | qualifiers.cpp:23:23:23:23 | a |
|
||||
| qualifiers.cpp:27:5:27:9 | getInner output argument [inner indirection, a] | qualifiers.cpp:28:10:28:14 | outer indirection [inner indirection, a] |
|
||||
| qualifiers.cpp:27:11:27:18 | setA output argument [a] | qualifiers.cpp:27:5:27:9 | getInner output argument [inner indirection, a] |
|
||||
| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:9:21:9:25 | value |
|
||||
| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:27:11:27:18 | setA output argument [a] |
|
||||
| qualifiers.cpp:28:10:28:14 | outer indirection [inner indirection, a] | qualifiers.cpp:28:16:28:20 | inner indirection [a] |
|
||||
| qualifiers.cpp:28:16:28:20 | inner indirection [a] | qualifiers.cpp:28:16:28:20 | inner indirection [a] |
|
||||
| qualifiers.cpp:28:16:28:20 | inner indirection [a] | qualifiers.cpp:28:23:28:23 | a |
|
||||
| qualifiers.cpp:32:17:32:21 | getInner output argument [inner indirection, a] | qualifiers.cpp:33:10:33:14 | outer indirection [inner indirection, a] |
|
||||
| qualifiers.cpp:32:23:32:30 | pointerSetA output argument [a] | qualifiers.cpp:32:17:32:21 | getInner output argument [inner indirection, a] |
|
||||
| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:12:40:12:44 | value |
|
||||
| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:32:23:32:30 | pointerSetA output argument [a] |
|
||||
| qualifiers.cpp:33:10:33:14 | outer indirection [inner indirection, a] | qualifiers.cpp:33:16:33:20 | inner indirection [a] |
|
||||
| qualifiers.cpp:33:16:33:20 | inner indirection [a] | qualifiers.cpp:33:16:33:20 | inner indirection [a] |
|
||||
| qualifiers.cpp:33:16:33:20 | inner indirection [a] | qualifiers.cpp:33:23:33:23 | a |
|
||||
| qualifiers.cpp:37:19:37:35 | referenceSetA output argument [a] | qualifiers.cpp:37:20:37:24 | getInner output argument [inner indirection, a] |
|
||||
| qualifiers.cpp:37:20:37:24 | getInner output argument [inner indirection, a] | qualifiers.cpp:38:10:38:14 | outer indirection [inner indirection, a] |
|
||||
| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:13:42:13:46 | value |
|
||||
| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:37:19:37:35 | referenceSetA output argument [a] |
|
||||
| qualifiers.cpp:38:10:38:14 | outer indirection [inner indirection, a] | qualifiers.cpp:38:16:38:20 | inner indirection [a] |
|
||||
| qualifiers.cpp:38:16:38:20 | inner indirection [a] | qualifiers.cpp:38:16:38:20 | inner indirection [a] |
|
||||
| qualifiers.cpp:38:16:38:20 | inner indirection [a] | qualifiers.cpp:38:23:38:23 | a |
|
||||
| qualifiers.cpp:42:5:42:40 | ... = ... | qualifiers.cpp:42:25:42:25 | * ... indirection [post update] [a] |
|
||||
| qualifiers.cpp:42:7:42:11 | getInner output argument [inner indirection, a] | qualifiers.cpp:43:10:43:14 | outer indirection [inner indirection, a] |
|
||||
| qualifiers.cpp:42:25:42:25 | * ... indirection [post update] [a] | qualifiers.cpp:42:7:42:11 | getInner output argument [inner indirection, a] |
|
||||
| qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:42:5:42:40 | ... = ... |
|
||||
| qualifiers.cpp:43:10:43:14 | outer indirection [inner indirection, a] | qualifiers.cpp:43:16:43:20 | inner indirection [a] |
|
||||
| qualifiers.cpp:43:16:43:20 | inner indirection [a] | qualifiers.cpp:43:16:43:20 | inner indirection [a] |
|
||||
| qualifiers.cpp:43:16:43:20 | inner indirection [a] | qualifiers.cpp:43:23:43:23 | a |
|
||||
| qualifiers.cpp:47:5:47:42 | ... = ... | qualifiers.cpp:47:27:47:27 | call to getInner indirection [post update] [a] |
|
||||
| qualifiers.cpp:47:6:47:11 | getInner output argument [inner indirection, a] | qualifiers.cpp:48:10:48:14 | outer indirection [inner indirection, a] |
|
||||
| qualifiers.cpp:47:27:47:27 | call to getInner indirection [post update] [a] | qualifiers.cpp:47:6:47:11 | getInner output argument [inner indirection, a] |
|
||||
| qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:47:5:47:42 | ... = ... |
|
||||
| qualifiers.cpp:48:10:48:14 | outer indirection [inner indirection, a] | qualifiers.cpp:48:16:48:20 | inner indirection [a] |
|
||||
| qualifiers.cpp:48:16:48:20 | inner indirection [a] | qualifiers.cpp:48:16:48:20 | inner indirection [a] |
|
||||
| qualifiers.cpp:48:16:48:20 | inner indirection [a] | qualifiers.cpp:48:23:48:23 | a |
|
||||
| realistic.cpp:53:9:53:66 | ... = ... | realistic.cpp:53:35:53:43 | userInput indirection [post update] [bufferLen] |
|
||||
| realistic.cpp:53:13:53:15 | foo indirection [post update] [bar, baz indirection, userInput, bufferLen] | realistic.cpp:61:21:61:23 | foo indirection [bar, baz indirection, userInput, bufferLen] |
|
||||
@@ -717,7 +682,6 @@ edges
|
||||
| realistic.cpp:53:47:53:66 | call to user_input | realistic.cpp:53:9:53:66 | ... = ... |
|
||||
| realistic.cpp:61:21:61:23 | foo indirection [bar, baz indirection, userInput, bufferLen] | realistic.cpp:61:21:61:30 | access to array indirection [baz indirection, userInput, bufferLen] |
|
||||
| realistic.cpp:61:21:61:30 | access to array indirection [baz indirection, userInput, bufferLen] | realistic.cpp:61:32:61:34 | baz indirection [userInput, bufferLen] |
|
||||
| realistic.cpp:61:32:61:34 | baz indirection [userInput, bufferLen] | realistic.cpp:61:32:61:34 | baz indirection [userInput, bufferLen] |
|
||||
| realistic.cpp:61:32:61:34 | baz indirection [userInput, bufferLen] | realistic.cpp:61:37:61:45 | userInput indirection [bufferLen] |
|
||||
| realistic.cpp:61:37:61:45 | userInput indirection [bufferLen] | realistic.cpp:61:14:61:55 | bufferLen |
|
||||
| simple.cpp:18:9:18:9 | this indirection [a_] | simple.cpp:18:22:18:23 | this indirection [a_] |
|
||||
@@ -796,7 +760,6 @@ edges
|
||||
| struct_init.c:31:8:31:12 | outer indirection [nestedAB, a] | struct_init.c:31:14:31:21 | nestedAB indirection [a] |
|
||||
| struct_init.c:31:14:31:21 | nestedAB indirection [a] | struct_init.c:31:23:31:23 | a |
|
||||
| struct_init.c:33:8:33:12 | outer indirection [pointerAB indirection, a] | struct_init.c:33:14:33:22 | pointerAB indirection [a] |
|
||||
| struct_init.c:33:14:33:22 | pointerAB indirection [a] | struct_init.c:33:14:33:22 | pointerAB indirection [a] |
|
||||
| struct_init.c:33:14:33:22 | pointerAB indirection [a] | struct_init.c:33:25:33:25 | a |
|
||||
| struct_init.c:36:10:36:24 | & ... indirection [a] | struct_init.c:14:24:14:25 | ab indirection [a] |
|
||||
| struct_init.c:36:11:36:15 | outer indirection [nestedAB, a] | struct_init.c:36:10:36:24 | & ... indirection [a] |
|
||||
@@ -808,7 +771,6 @@ edges
|
||||
| struct_init.c:43:5:43:7 | & ... indirection [a] | struct_init.c:41:23:44:3 | definition of outer indirection [post update] [pointerAB indirection, a] |
|
||||
| struct_init.c:46:10:46:14 | outer indirection [pointerAB indirection, a] | struct_init.c:46:16:46:24 | pointerAB indirection [a] |
|
||||
| struct_init.c:46:16:46:24 | pointerAB indirection [a] | struct_init.c:14:24:14:25 | ab indirection [a] |
|
||||
| struct_init.c:46:16:46:24 | pointerAB indirection [a] | struct_init.c:46:16:46:24 | pointerAB indirection [a] |
|
||||
nodes
|
||||
| A.cpp:23:10:23:10 | c | semmle.label | c |
|
||||
| A.cpp:25:7:25:17 | ... = ... | semmle.label | ... = ... |
|
||||
@@ -1019,7 +981,6 @@ nodes
|
||||
| E.cpp:21:10:21:10 | p indirection [data, buffer indirection] | semmle.label | p indirection [data, buffer indirection] |
|
||||
| E.cpp:21:13:21:16 | data indirection [buffer indirection] | semmle.label | data indirection [buffer indirection] |
|
||||
| E.cpp:21:18:21:23 | buffer indirection | semmle.label | buffer indirection |
|
||||
| E.cpp:21:18:21:23 | buffer indirection | semmle.label | buffer indirection |
|
||||
| E.cpp:28:21:28:23 | argument_source output argument | semmle.label | argument_source output argument |
|
||||
| E.cpp:29:21:29:29 | argument_source output argument | semmle.label | argument_source output argument |
|
||||
| E.cpp:29:24:29:29 | b indirection [post update] [buffer indirection] | semmle.label | b indirection [post update] [buffer indirection] |
|
||||
@@ -1029,7 +990,6 @@ nodes
|
||||
| E.cpp:31:10:31:12 | raw indirection | semmle.label | raw indirection |
|
||||
| E.cpp:32:10:32:10 | b indirection [buffer indirection] | semmle.label | b indirection [buffer indirection] |
|
||||
| E.cpp:32:13:32:18 | buffer indirection | semmle.label | buffer indirection |
|
||||
| E.cpp:32:13:32:18 | buffer indirection | semmle.label | buffer indirection |
|
||||
| E.cpp:33:18:33:19 | & ... indirection [data, buffer indirection] | semmle.label | & ... indirection [data, buffer indirection] |
|
||||
| aliasing.cpp:9:3:9:22 | ... = ... | semmle.label | ... = ... |
|
||||
| aliasing.cpp:9:6:9:7 | s indirection [post update] [m1] | semmle.label | s indirection [post update] [m1] |
|
||||
@@ -1277,7 +1237,6 @@ nodes
|
||||
| clearning.cpp:54:5:54:5 | x indirection | semmle.label | x indirection |
|
||||
| clearning.cpp:55:8:55:8 | s indirection [x indirection] | semmle.label | s indirection [x indirection] |
|
||||
| clearning.cpp:55:10:55:10 | x indirection | semmle.label | x indirection |
|
||||
| clearning.cpp:55:10:55:10 | x indirection | semmle.label | x indirection |
|
||||
| clearning.cpp:60:3:60:22 | ... = ... | semmle.label | ... = ... |
|
||||
| clearning.cpp:60:7:60:7 | s indirection [post update] [x indirection] | semmle.label | s indirection [post update] [x indirection] |
|
||||
| clearning.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input |
|
||||
@@ -1288,7 +1247,6 @@ nodes
|
||||
| clearning.cpp:61:5:61:5 | x indirection | semmle.label | x indirection |
|
||||
| clearning.cpp:62:8:62:8 | s indirection [x indirection] | semmle.label | s indirection [x indirection] |
|
||||
| clearning.cpp:62:10:62:10 | x indirection | semmle.label | x indirection |
|
||||
| clearning.cpp:62:10:62:10 | x indirection | semmle.label | x indirection |
|
||||
| clearning.cpp:74:20:74:22 | argument_source output argument | semmle.label | argument_source output argument |
|
||||
| clearning.cpp:74:20:74:22 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:76:7:76:12 | * ... | semmle.label | * ... |
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
failures
|
||||
|
||||
@@ -6643,6 +6643,20 @@ WARNING: Module TaintTracking has been deprecated and may be removed in future (
|
||||
| taint.cpp:729:27:729:32 | endptr | taint.cpp:729:26:729:32 | & ... | |
|
||||
| taint.cpp:731:7:731:12 | ref arg endptr | taint.cpp:732:8:732:13 | endptr | |
|
||||
| taint.cpp:732:8:732:13 | endptr | taint.cpp:732:7:732:13 | * ... | TAINT |
|
||||
| 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: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:31:38:31:44 | source1 | |
|
||||
| vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | |
|
||||
|
||||
@@ -730,4 +730,18 @@ void test_strtol(char *source) {
|
||||
sink(l); // $ ast,ir
|
||||
sink(endptr); // $ ast,ir
|
||||
sink(*endptr); // $ ast,ir
|
||||
}
|
||||
|
||||
void *realloc(void *, size_t);
|
||||
|
||||
void test_realloc() {
|
||||
char *source = indirect_source();
|
||||
char *dest = (char*)realloc(source, 16);
|
||||
sink(dest); // $ ir MISSING: ast
|
||||
}
|
||||
|
||||
void test_realloc_2_indirections(int **buffer) {
|
||||
**buffer = source();
|
||||
buffer = (int**)realloc(buffer, 16);
|
||||
sink(**buffer); // $ ir MISSING: ast
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.ModulusAnalysis
|
||||
import codeql.rangeanalysis.ModulusAnalysis
|
||||
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.SemanticLocation
|
||||
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.RangeAnalysisImpl
|
||||
@@ -9,8 +9,7 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
module ModulusAnalysisInstantiated =
|
||||
ModulusAnalysis<FloatDelta, ConstantBounds, RangeUtil<FloatDelta, CppLangImplRelative>>;
|
||||
module ModulusAnalysisInstantiated = ModulusAnalysis<SemLocation, Sem, FloatDelta, ConstantBounds>;
|
||||
|
||||
module ModulusAnalysisTest implements TestSig {
|
||||
string getARelevantTag() { result = "mod" }
|
||||
@@ -31,7 +30,7 @@ import MakeTest<ModulusAnalysisTest>
|
||||
|
||||
private string getAModString(SemExpr e) {
|
||||
exists(SemBound b, int delta, int mod |
|
||||
ModulusAnalysisInstantiated::semExprModulus(e, b, delta, mod) and
|
||||
ModulusAnalysisInstantiated::exprModulus(e, b, delta, mod) and
|
||||
result = b.toString() + "," + delta.toString() + "," + mod.toString() and
|
||||
not (delta = 0 and mod = 0)
|
||||
)
|
||||
|
||||
@@ -18,7 +18,7 @@ int test2(struct List* p) {
|
||||
int count = 0;
|
||||
for (; p; p = p->next) {
|
||||
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
|
||||
return count;
|
||||
@@ -29,7 +29,7 @@ int test3(struct List* p) {
|
||||
for (; p; p = p->next) {
|
||||
range(count++); // $ range=>=-9 range=<=9
|
||||
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
|
||||
return count;
|
||||
@@ -317,7 +317,7 @@ int test_mult01(int a, int b) {
|
||||
range(b); // $ range=<=23 range=>=-13
|
||||
int r = a*b; // $ overflow=+- -143 .. 253
|
||||
range(r);
|
||||
total += r; // $ overflow=+
|
||||
total += r; // $ overflow=+-
|
||||
range(total); // $ MISSING: range=">=... * ...+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
|
||||
int r = a*b; // $ overflow=+- -143 .. 253
|
||||
range(r);
|
||||
total += r; // $ overflow=+
|
||||
total += r; // $ overflow=+-
|
||||
range(total); // $ MISSING: range=">=... * ...+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
|
||||
int r = a*b; // $ overflow=+- -391 .. 221
|
||||
range(r);
|
||||
total += r; // $ overflow=-
|
||||
total += r; // $ overflow=+-
|
||||
range(total); // $ MISSING: range="<=... * ...+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
|
||||
int r = a*b; // $ overflow=+- -391 .. 221
|
||||
range(r);
|
||||
total += r; // $ overflow=-
|
||||
total += r; // $ overflow=+-
|
||||
range(total); // $ MISSING: range="<=... * ...+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) {
|
||||
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) {
|
||||
@@ -1028,4 +1028,73 @@ void test_negate_signed(int s) {
|
||||
if(10 < s && s < 20) {
|
||||
range<int>(-s); // $ range=<=-11 range=>=-19
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// By setting the guard after the use in another guard we
|
||||
// don't get the useful information
|
||||
void test_guard_after_use(int pos, int size, int offset) {
|
||||
if (pos + offset >= size) { // $ overflow=+-
|
||||
return;
|
||||
}
|
||||
if (offset != 1) {
|
||||
return;
|
||||
}
|
||||
range(pos + 1); // $ overflow=+ range="==InitializeParameter: pos+1" MISSING: range="<=InitializeParameter: size-1"
|
||||
}
|
||||
|
||||
int cond();
|
||||
|
||||
|
||||
// This is basically what we get when we have a loop that calls
|
||||
// realloc in some iterations
|
||||
void alloc_in_loop(int origLen) {
|
||||
if (origLen <= 10) {
|
||||
return;
|
||||
}
|
||||
int len = origLen;
|
||||
int index = 0;
|
||||
while (cond()) {
|
||||
if (index == len) {
|
||||
if (len >= 1000) {
|
||||
return;
|
||||
}
|
||||
len = len * 2; // $ overflow=-
|
||||
}
|
||||
// We want that index < len
|
||||
range(index); // $ MISSING: range="<=InitializeParameter: len-1"
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
// This came from a case where it handled the leftovers before an unrolled loop
|
||||
void mask_at_start(int len) {
|
||||
if (len < 0) {
|
||||
return;
|
||||
}
|
||||
int leftOver = len & 63;
|
||||
for (int i = 0; i < leftOver; i++) {
|
||||
range(i); // $ range=<=62 range=>=0 range="<=Store: ... & ... | Store: leftOver-1" range="<=InitializeParameter: len-1"
|
||||
}
|
||||
// Do something with leftOver
|
||||
for (int index = leftOver; index < len; index+=64) {
|
||||
range(index); // $ range="<=InitializeParameter: len-64" range=">=Store: ... & ... | Store: leftOver+0"
|
||||
range(index + 63); // $ range="<=InitializeParameter: len-1" range="==Phi: index+63" range=">=Store: ... & ... | Store: leftOver+63"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Same as above but with modulo
|
||||
void mod_at_start(int len) {
|
||||
if (len < 0) {
|
||||
return;
|
||||
}
|
||||
int leftOver = len % 64;
|
||||
for (int i = 0; i < leftOver; i++) {
|
||||
range(i); // $ range=<=62 range=>=0 range="<=Store: ... % ... | Store: leftOver-1" range="<=InitializeParameter: len-1"
|
||||
}
|
||||
// Do something with leftOver
|
||||
for (int index = leftOver; index < len; index+=64) {
|
||||
range(index); // $ range="<=InitializeParameter: len-64" range=">=Store: ... % ... | Store: leftOver+0"
|
||||
range(index + 63); // $ range="<=InitializeParameter: len-1" range="==Phi: index+63" range=">=Store: ... % ... | Store: leftOver+63"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,3 +130,19 @@ void test_div(int x) {
|
||||
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 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.analysis.RangeUtils
|
||||
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.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
module SignAnalysisInstantiated =
|
||||
SignAnalysis<FloatDelta, RangeUtil<FloatDelta, CppLangImplRelative>>;
|
||||
module SignAnalysisInstantiated = SignAnalysis<FloatDelta>;
|
||||
|
||||
module SignAnalysisTest implements TestSig {
|
||||
string getARelevantTag() { result = "sign" }
|
||||
|
||||
@@ -4,7 +4,12 @@ uniqueType
|
||||
uniqueNodeLocation
|
||||
missingLocation
|
||||
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
|
||||
localFlowIsLocal
|
||||
readStepIsLocal
|
||||
|
||||
@@ -43,6 +43,11 @@ edges
|
||||
| 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 | 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
|
||||
| test.cpp:17:9:17:11 | & ... | semmle.label | & ... |
|
||||
| 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 to) | semmle.label | (reference to) |
|
||||
| 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
|
||||
| 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 |
|
||||
@@ -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: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: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() {
|
||||
int x;
|
||||
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
|
||||
}
|
||||
@@ -2,11 +2,9 @@ edges
|
||||
| test.cpp:15:27:15:30 | argv indirection | test.cpp:22:45:22:52 | userName indirection |
|
||||
| test.cpp:22:13:22:20 | sprintf output argument | test.cpp:23:12:23:19 | command1 indirection |
|
||||
| test.cpp:22:45:22:52 | userName indirection | test.cpp:22:13:22:20 | sprintf output argument |
|
||||
| test.cpp:22:45:22:52 | userName indirection | test.cpp:22:45:22:52 | userName indirection |
|
||||
| test.cpp:47:21:47:26 | call to getenv indirection | test.cpp:50:35:50:43 | envCflags indirection |
|
||||
| test.cpp:50:11:50:17 | sprintf output argument | test.cpp:51:10:51:16 | command indirection |
|
||||
| test.cpp:50:35:50:43 | envCflags indirection | test.cpp:50:11:50:17 | sprintf output argument |
|
||||
| test.cpp:50:35:50:43 | envCflags indirection | test.cpp:50:35:50:43 | envCflags indirection |
|
||||
| test.cpp:62:9:62:16 | fread output argument | test.cpp:64:20:64:27 | filename indirection |
|
||||
| test.cpp:64:11:64:17 | strncat output argument | test.cpp:65:10:65:16 | command indirection |
|
||||
| test.cpp:64:20:64:27 | filename indirection | test.cpp:64:11:64:17 | strncat output argument |
|
||||
|
||||
@@ -4,6 +4,8 @@ edges
|
||||
| test.c:35:16:35:23 | userName indirection | test.c:40:25:40:32 | username indirection |
|
||||
| test.c:38:7:38:20 | globalUsername indirection | test.c:51:18:51:23 | query1 indirection |
|
||||
| test.c:40:25:40:32 | username indirection | test.c:38:7:38:20 | globalUsername indirection |
|
||||
| test.c:75:8:75:16 | gets output argument | test.c:76:17:76:25 | userInput indirection |
|
||||
| test.c:75:8:75:16 | gets output argument | test.c:77:20:77:28 | userInput indirection |
|
||||
| test.cpp:39:27:39:30 | argv indirection | test.cpp:43:27:43:33 | access to array indirection |
|
||||
nodes
|
||||
| test.c:14:27:14:30 | argv indirection | semmle.label | argv indirection |
|
||||
@@ -12,10 +14,15 @@ nodes
|
||||
| test.c:38:7:38:20 | globalUsername indirection | semmle.label | globalUsername indirection |
|
||||
| test.c:40:25:40:32 | username indirection | semmle.label | username indirection |
|
||||
| test.c:51:18:51:23 | query1 indirection | semmle.label | query1 indirection |
|
||||
| test.c:75:8:75:16 | gets output argument | semmle.label | gets output argument |
|
||||
| test.c:76:17:76:25 | userInput indirection | semmle.label | userInput indirection |
|
||||
| test.c:77:20:77:28 | userInput indirection | semmle.label | userInput indirection |
|
||||
| test.cpp:39:27:39:30 | argv indirection | semmle.label | argv indirection |
|
||||
| test.cpp:43:27:43:33 | access to array indirection | semmle.label | access to array indirection |
|
||||
subpaths
|
||||
#select
|
||||
| test.c:21:18:21:23 | query1 | test.c:14:27:14:30 | argv indirection | test.c:21:18:21:23 | query1 indirection | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg). | test.c:14:27:14:30 | argv indirection | user input (a command-line argument) |
|
||||
| test.c:51:18:51:23 | query1 | test.c:14:27:14:30 | argv indirection | test.c:51:18:51:23 | query1 indirection | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg). | test.c:14:27:14:30 | argv indirection | user input (a command-line argument) |
|
||||
| test.c:76:17:76:25 | userInput | test.c:75:8:75:16 | gets output argument | test.c:76:17:76:25 | userInput indirection | This argument to a SQL query function is derived from $@ and then passed to SQLPrepare(StatementText). | test.c:75:8:75:16 | gets output argument | user input (string read by gets) |
|
||||
| test.c:77:20:77:28 | userInput | test.c:75:8:75:16 | gets output argument | test.c:77:20:77:28 | userInput indirection | This argument to a SQL query function is derived from $@ and then passed to SQLExecDirect(StatementText). | test.c:75:8:75:16 | gets output argument | user input (string read by gets) |
|
||||
| test.cpp:43:27:43:33 | access to array | test.cpp:39:27:39:30 | argv indirection | test.cpp:43:27:43:33 | access to array indirection | This argument to a SQL query function is derived from $@ and then passed to pqxx::work::exec1((unnamed parameter 0)). | test.cpp:39:27:39:30 | argv indirection | user input (a command-line argument) |
|
||||
|
||||
@@ -50,3 +50,29 @@ void badFunc() {
|
||||
snprintf(query1, 1000, "SELECT UID FROM USERS where name = \"%s\"", userName);
|
||||
mysql_query(0, query1); // BAD
|
||||
}
|
||||
|
||||
//ODBC Library Rountines
|
||||
typedef unsigned char SQLCHAR;
|
||||
typedef long int SQLINTEGER;
|
||||
typedef int SQLRETURN;
|
||||
typedef void* SQLHSTMT;
|
||||
|
||||
char* gets(char *str);
|
||||
|
||||
|
||||
SQLRETURN SQLPrepare(
|
||||
SQLHSTMT StatementHandle,
|
||||
SQLCHAR * StatementText,
|
||||
SQLINTEGER TextLength);
|
||||
|
||||
SQLRETURN SQLExecDirect(
|
||||
SQLHSTMT StatementHandle,
|
||||
SQLCHAR * StatementText,
|
||||
SQLINTEGER TextLength);
|
||||
|
||||
void ODBCTests(){
|
||||
char userInput[100];
|
||||
gets(userInput);
|
||||
SQLPrepare(0, userInput, 100); // BAD
|
||||
SQLExecDirect(0, userInput, 100); // BAD
|
||||
}
|
||||
@@ -1,23 +1,12 @@
|
||||
edges
|
||||
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data |
|
||||
| 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 |
|
||||
| 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:37:73:37:76 | data indirection | test.cpp:43:32:43:35 | data indirection |
|
||||
| test.cpp:64:30:64:35 | call to getenv indirection | test.cpp:73:24:73:27 | data indirection |
|
||||
| test.cpp:73:24:73:27 | data indirection | test.cpp:37:73:37:76 | data indirection |
|
||||
subpaths
|
||||
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:43:32:43:35 | data | semmle.label | data |
|
||||
| test.cpp:43:32:43:35 | data | semmle.label | data |
|
||||
| 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:43:32:43:35 | data indirection | semmle.label | data indirection |
|
||||
| test.cpp:64:30:64:35 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:73:24:73:27 | data indirection | semmle.label | data indirection |
|
||||
subpaths
|
||||
#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,48 @@
|
||||
edges
|
||||
| test.cpp:24:30:24:36 | command | test.cpp:26:10:26:16 | command |
|
||||
| test.cpp:24:30:24:36 | command | test.cpp:26:10:26:16 | command |
|
||||
| test.cpp:29:30:29:36 | command | test.cpp:31:10:31:16 | command |
|
||||
| test.cpp:29:30:29:36 | command | test.cpp:31:10:31:16 | command |
|
||||
| test.cpp:42:18:42:23 | call to getenv | test.cpp:24:30:24:36 | command |
|
||||
| test.cpp:42:18:42:34 | call to getenv | test.cpp:24:30:24:36 | command |
|
||||
| test.cpp:43:18:43:23 | call to getenv | test.cpp:29:30:29:36 | command |
|
||||
| test.cpp:43:18:43:34 | call to getenv | test.cpp:29:30:29:36 | command |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer |
|
||||
| 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
|
||||
| test.cpp:24:30:24:36 | command indirection | test.cpp:26:10:26:16 | command indirection |
|
||||
| test.cpp:29:30:29:36 | command indirection | test.cpp:31:10:31:16 | command indirection |
|
||||
| test.cpp:42:18:42:34 | call to getenv indirection | test.cpp:24:30:24:36 | command indirection |
|
||||
| test.cpp:43:18:43:34 | call to getenv indirection | test.cpp:29:30:29:36 | command indirection |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer indirection |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data indirection |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | (reference dereference) indirection |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | dataref indirection |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:65:10:65:14 | data2 indirection |
|
||||
| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer indirection |
|
||||
| test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer indirection |
|
||||
| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer indirection |
|
||||
| test.cpp:113:8:113:12 | call to fgets indirection | test.cpp:114:9:114:11 | ptr indirection |
|
||||
nodes
|
||||
| test.cpp:24:30:24:36 | command | semmle.label | command |
|
||||
| test.cpp:26:10:26:16 | command | semmle.label | command |
|
||||
| test.cpp:26:10:26:16 | command | semmle.label | command |
|
||||
| test.cpp:29:30:29:36 | command | semmle.label | command |
|
||||
| test.cpp:31:10:31:16 | command | semmle.label | command |
|
||||
| test.cpp:31:10:31:16 | command | semmle.label | command |
|
||||
| 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:24:30:24:36 | command indirection | semmle.label | command indirection |
|
||||
| test.cpp:26:10:26:16 | command indirection | semmle.label | command indirection |
|
||||
| test.cpp:29:30:29:36 | command indirection | semmle.label | command indirection |
|
||||
| test.cpp:31:10:31:16 | command indirection | semmle.label | command indirection |
|
||||
| test.cpp:42:18:42:34 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:43:18:43:34 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| 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 | semmle.label | buffer |
|
||||
| test.cpp:63:10:63:13 | data | semmle.label | data |
|
||||
| test.cpp:63:10:63:13 | data | semmle.label | data |
|
||||
| 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:62:10:62:15 | buffer indirection | semmle.label | buffer indirection |
|
||||
| test.cpp:63:10:63:13 | data indirection | semmle.label | data indirection |
|
||||
| test.cpp:64:10:64:16 | (reference dereference) indirection | semmle.label | (reference dereference) indirection |
|
||||
| test.cpp:64:10:64:16 | dataref indirection | semmle.label | dataref indirection |
|
||||
| test.cpp:65:10:65:14 | data2 indirection | semmle.label | data2 indirection |
|
||||
| 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 | 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:78:10:78:15 | buffer indirection | semmle.label | buffer indirection |
|
||||
| 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 | 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:99:15:99:20 | buffer indirection | semmle.label | buffer indirection |
|
||||
| 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 | semmle.label | buffer |
|
||||
| test.cpp:107:15:107:20 | buffer indirection | semmle.label | buffer indirection |
|
||||
| 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
|
||||
| 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: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: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: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: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: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: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: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: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: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 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 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 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 | (reference dereference) indirection | test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | (reference dereference) 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 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 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 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 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 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
|
||||
}
|
||||
}
|
||||
|
||||
void argumentUse(char *ptr, FILE *stream) {
|
||||
char buffer[80];
|
||||
ptr = fgets(buffer, sizeof(buffer), stream);
|
||||
system(ptr); // BAD
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ edges
|
||||
| test.cpp:18:10:18:15 | str indirection [post update] [string] | test.cpp:19:5:19:7 | str indirection [string] |
|
||||
| test.cpp:18:19:18:24 | call to malloc | test.cpp:18:5:18:30 | ... = ... |
|
||||
| test.cpp:19:5:19:7 | str indirection [string] | test.cpp:16:11:16:21 | mk_string_t indirection [string] |
|
||||
| test.cpp:19:5:19:7 | str indirection [string] | test.cpp:19:5:19:7 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:42:13:42:15 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:72:17:72:19 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:80:17:80:19 | str indirection [string] |
|
||||
@@ -16,7 +15,6 @@ edges
|
||||
| test.cpp:90:10:90:15 | str indirection [post update] [string] | test.cpp:91:5:91:7 | str indirection [string] |
|
||||
| test.cpp:90:19:90:24 | call to malloc | test.cpp:90:5:90:34 | ... = ... |
|
||||
| test.cpp:91:5:91:7 | str indirection [string] | test.cpp:88:11:88:30 | mk_string_t_plus_one indirection [string] |
|
||||
| test.cpp:91:5:91:7 | str indirection [string] | test.cpp:91:5:91:7 | str indirection [string] |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:99:13:99:15 | str indirection [string] |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:129:17:129:19 | str indirection [string] |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:137:17:137:19 | str indirection [string] |
|
||||
@@ -26,7 +24,6 @@ edges
|
||||
| test.cpp:147:5:147:34 | ... = ... | test.cpp:147:10:147:15 | str indirection [post update] [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:148:5:148:7 | str indirection [string] |
|
||||
| test.cpp:147:19:147:24 | call to malloc | test.cpp:147:5:147:34 | ... = ... |
|
||||
| test.cpp:148:5:148:7 | str indirection [string] | test.cpp:148:5:148:7 | str indirection [string] |
|
||||
| test.cpp:148:5:148:7 | str indirection [string] | test.cpp:152:13:152:15 | str indirection [string] |
|
||||
| test.cpp:148:5:148:7 | str indirection [string] | test.cpp:154:13:154:15 | str indirection [string] |
|
||||
| test.cpp:148:5:148:7 | str indirection [string] | test.cpp:156:13:156:15 | str indirection [string] |
|
||||
|
||||
@@ -1,4 +1,32 @@
|
||||
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
|
||||
| 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
|
||||
| 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
|
||||
{
|
||||
// ...
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -608,6 +608,26 @@ int test23() {
|
||||
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[])
|
||||
{
|
||||
long long arr17[19];
|
||||
@@ -633,6 +653,8 @@ int tests_main(int argc, char *argv[])
|
||||
test21(argc == 0);
|
||||
test22(argc == 0, argv[0]);
|
||||
test23();
|
||||
test24(argv[0]);
|
||||
test25(argv[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,37 +1,18 @@
|
||||
edges
|
||||
| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array |
|
||||
| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array |
|
||||
| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array |
|
||||
| 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
|
||||
| tests.c:16:26:16:29 | argv indirection | tests.c:28:22:28:28 | access to array indirection |
|
||||
| tests.c:16:26:16:29 | argv indirection | tests.c:29:28:29:34 | access to array indirection |
|
||||
| tests.c:16:26:16:29 | argv indirection | tests.c:34:10:34:16 | access to array indirection |
|
||||
nodes
|
||||
| tests.c:28:22:28:25 | argv | semmle.label | argv |
|
||||
| tests.c:28:22:28:25 | argv | semmle.label | argv |
|
||||
| tests.c:28:22:28:28 | access to array | semmle.label | access to array |
|
||||
| tests.c:28:22:28:28 | access to array | semmle.label | access to array |
|
||||
| tests.c:29:28:29:31 | argv | semmle.label | argv |
|
||||
| tests.c:29:28:29:31 | argv | semmle.label | argv |
|
||||
| tests.c:29:28:29:34 | access to array | semmle.label | access to array |
|
||||
| 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 |
|
||||
| tests.c:16:26:16:29 | argv indirection | semmle.label | argv indirection |
|
||||
| tests.c:28:22:28:28 | access to array indirection | semmle.label | access to array indirection |
|
||||
| tests.c:29:28:29:34 | access to array indirection | semmle.label | access to array indirection |
|
||||
| tests.c:31:15:31:23 | scanf output argument | semmle.label | scanf output argument |
|
||||
| tests.c:33:21:33:29 | scanf output argument | semmle.label | scanf output argument |
|
||||
| tests.c:34:10:34:16 | access to array indirection | semmle.label | access to array indirection |
|
||||
subpaths
|
||||
#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: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: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: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: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: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: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 | 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 | 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: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,13 +1,8 @@
|
||||
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 |
|
||||
subpaths
|
||||
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:66:11:66:14 | data | semmle.label | data |
|
||||
| examples.cpp:66:11:66:14 | data | semmle.label | data |
|
||||
subpaths
|
||||
#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,86 +1,59 @@
|
||||
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: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: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:40:3:40:5 | num |
|
||||
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:40:3:40:5 | num |
|
||||
| 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:14:15:14:28 | maxConnections |
|
||||
| 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: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: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: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: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
|
||||
| test.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections |
|
||||
| test.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 |
|
||||
| test.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 |
|
||||
nodes
|
||||
| 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:25:22:25:23 | & ... | semmle.label | & ... |
|
||||
| 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: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: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 |
|
||||
| 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: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: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:19:6:19:6 | y | semmle.label | y |
|
||||
| test5.cpp:19:6:19:6 | y | semmle.label | y |
|
||||
| test.c:11:29:11:32 | argv | semmle.label | argv |
|
||||
| test.c:11:29:11:32 | argv | semmle.label | argv |
|
||||
| test.c:10:27:10:30 | argv indirection | semmle.label | argv indirection |
|
||||
| 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: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 |
|
||||
subpaths
|
||||
#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 | & ... | 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: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: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 |
|
||||
| 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: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 | 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 |
|
||||
| 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 | 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: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: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 |
|
||||
| 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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: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: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,9 +1,5 @@
|
||||
edges
|
||||
| test.cpp:4:15:4:33 | call to malloc | test.cpp:5:15:5:22 | ... + ... |
|
||||
| test.cpp:4:15:4:33 | call to malloc | test.cpp:5:15:5:22 | ... + ... |
|
||||
| test.cpp:4:15:4:33 | call to malloc | test.cpp:6:14:6:15 | * ... |
|
||||
| test.cpp:4:15:4:33 | call to malloc | test.cpp:6:14:6:15 | * ... |
|
||||
| test.cpp:4:15:4:33 | call to malloc | test.cpp:8:14:8:21 | * ... |
|
||||
| test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | ... + ... |
|
||||
| test.cpp:5:15:5:22 | ... + ... | test.cpp:6:14:6:15 | * ... |
|
||||
| test.cpp:5:15:5:22 | ... + ... | test.cpp:6:14:6:15 | * ... |
|
||||
@@ -14,10 +10,6 @@ edges
|
||||
| test.cpp:6:14:6:15 | * ... | test.cpp:8:14:8:21 | * ... |
|
||||
| test.cpp:16:15:16:33 | call to malloc | test.cpp:20:14:20:21 | * ... |
|
||||
| test.cpp:28:15:28:37 | call to malloc | test.cpp:29:15:29:28 | ... + ... |
|
||||
| test.cpp:28:15:28:37 | call to malloc | test.cpp:29:15:29:28 | ... + ... |
|
||||
| test.cpp:28:15:28:37 | call to malloc | test.cpp:30:14:30:15 | * ... |
|
||||
| test.cpp:28:15:28:37 | call to malloc | test.cpp:30:14:30:15 | * ... |
|
||||
| test.cpp:28:15:28:37 | call to malloc | test.cpp:32:14:32:21 | * ... |
|
||||
| test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | ... + ... |
|
||||
| test.cpp:29:15:29:28 | ... + ... | test.cpp:30:14:30:15 | * ... |
|
||||
| test.cpp:29:15:29:28 | ... + ... | test.cpp:30:14:30:15 | * ... |
|
||||
@@ -27,29 +19,14 @@ edges
|
||||
| test.cpp:29:15:29:28 | ... + ... | test.cpp:32:14:32:21 | * ... |
|
||||
| test.cpp:30:14:30:15 | * ... | test.cpp:32:14:32:21 | * ... |
|
||||
| test.cpp:51:33:51:35 | end | test.cpp:60:34:60:37 | mk_array output argument |
|
||||
| test.cpp:52:19:52:37 | call to malloc | test.cpp:53:5:53:23 | ... = ... |
|
||||
| test.cpp:52:19:52:37 | call to malloc | test.cpp:53:12:53:23 | ... + ... |
|
||||
| test.cpp:53:5:53:23 | ... = ... | test.cpp:51:33:51:35 | end |
|
||||
| test.cpp:53:12:53:23 | ... + ... | test.cpp:53:5:53:23 | ... = ... |
|
||||
| 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:194:15:194:33 | call to malloc | test.cpp:195:17:195:23 | ... + ... |
|
||||
| test.cpp:194:15:194:33 | call to malloc | test.cpp:195:17:195:23 | ... + ... |
|
||||
| test.cpp:194:15:194:33 | call to malloc | test.cpp:201:5:201:19 | ... = ... |
|
||||
| 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:205:15:205:33 | call to malloc | test.cpp:213:5:213:13 | ... = ... |
|
||||
| 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: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:260:13:260:24 | new[] | test.cpp:264:13:264:14 | * ... |
|
||||
| test.cpp:260:13:260:24 | new[] | test.cpp:264:13:264:14 | * ... |
|
||||
| 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 | * ... |
|
||||
@@ -58,107 +35,48 @@ edges
|
||||
| test.cpp:264:13:264:14 | * ... | test.cpp:264:13:264:14 | * ... |
|
||||
| test.cpp:264:13:264:14 | * ... | test.cpp:264:13:264:14 | * ... |
|
||||
| test.cpp:270:13:270:24 | new[] | test.cpp:271:14:271:21 | ... + ... |
|
||||
| test.cpp:270:13:270:24 | new[] | test.cpp:271:14:271:21 | ... + ... |
|
||||
| test.cpp:270:13:270:24 | new[] | test.cpp:274:5:274:10 | ... = ... |
|
||||
| test.cpp:271:14:271:21 | ... + ... | test.cpp:271:14:271:21 | ... + ... |
|
||||
| test.cpp:271:14:271:21 | ... + ... | test.cpp:274:5:274:10 | ... = ... |
|
||||
| test.cpp:271:14:271:21 | ... + ... | test.cpp:274:5:274:10 | ... = ... |
|
||||
| test.cpp:355:14:355:27 | new[] | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:355:14:355:27 | new[] | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:355:14:355:27 | new[] | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:355:14:355:27 | new[] | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:355:14:355:27 | new[] | test.cpp:358:14:358:26 | end_plus_one indirection |
|
||||
| test.cpp:355:14:355:27 | new[] | test.cpp:359:14:359:32 | ... + ... indirection |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:358:14:358:26 | end_plus_one indirection |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:358:14:358:26 | end_plus_one indirection |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | ... + ... indirection |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | ... + ... indirection |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | end_plus_one indirection |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | end_plus_one indirection |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | ... + ... indirection |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | ... + ... indirection |
|
||||
| test.cpp:377:14:377:27 | new[] | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:377:14:377:27 | new[] | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:377:14:377:27 | new[] | test.cpp:381:5:381:9 | ... ++ |
|
||||
| test.cpp:377:14:377:27 | new[] | test.cpp:381:5:381:9 | ... ++ |
|
||||
| test.cpp:377:14:377:27 | new[] | test.cpp:384:13:384:16 | end indirection |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | end indirection |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | end indirection |
|
||||
| test.cpp:381:5:381:9 | ... ++ | test.cpp:381:5:381:9 | ... ++ |
|
||||
| test.cpp:381:5:381:9 | ... ++ | test.cpp:384:13:384:16 | end indirection |
|
||||
| test.cpp:410:14:410:27 | new[] | test.cpp:411:15:411:23 | & ... |
|
||||
| test.cpp:410:14:410:27 | new[] | test.cpp:411:15:411:23 | & ... |
|
||||
| test.cpp:410:14:410:27 | new[] | test.cpp:413:5:413:8 | ... ++ |
|
||||
| test.cpp:410:14:410:27 | new[] | test.cpp:413:5:413:8 | ... ++ |
|
||||
| test.cpp:410:14:410:27 | new[] | test.cpp:415:7:415:15 | ... = ... |
|
||||
| test.cpp:411:15:411:23 | & ... | test.cpp:411:15:411:23 | & ... |
|
||||
| test.cpp:411:15:411:23 | & ... | test.cpp:415:7:415:15 | ... = ... |
|
||||
| test.cpp:411:15:411:23 | & ... | test.cpp:415:7:415:15 | ... = ... |
|
||||
| test.cpp:413:5:413:8 | ... ++ | test.cpp:413:5:413:8 | ... ++ |
|
||||
| test.cpp:413:5:413:8 | ... ++ | test.cpp:415:7:415:15 | ... = ... |
|
||||
| test.cpp:413:5:413:8 | ... ++ | test.cpp:415:7:415:15 | ... = ... |
|
||||
| test.cpp:421:14:421:27 | new[] | test.cpp:422:15:422:23 | & ... |
|
||||
| test.cpp:421:14:421:27 | new[] | test.cpp:422:15:422:23 | & ... |
|
||||
| test.cpp:421:14:421:27 | new[] | test.cpp:424:5:424:8 | ... ++ |
|
||||
| test.cpp:421:14:421:27 | new[] | test.cpp:424:5:424:8 | ... ++ |
|
||||
| test.cpp:421:14:421:27 | new[] | test.cpp:426:7:426:15 | ... = ... |
|
||||
| test.cpp:422:15:422:23 | & ... | test.cpp:422:15:422:23 | & ... |
|
||||
| test.cpp:422:15:422:23 | & ... | test.cpp:426:7:426:15 | ... = ... |
|
||||
| test.cpp:422:15:422:23 | & ... | test.cpp:426:7:426:15 | ... = ... |
|
||||
| test.cpp:424:5:424:8 | ... ++ | test.cpp:424:5:424:8 | ... ++ |
|
||||
| test.cpp:424:5:424:8 | ... ++ | test.cpp:426:7:426:15 | ... = ... |
|
||||
| test.cpp:424:5:424:8 | ... ++ | test.cpp:426:7:426:15 | ... = ... |
|
||||
| test.cpp:432:14:432:27 | new[] | test.cpp:433:15:433:23 | & ... |
|
||||
| test.cpp:432:14:432:27 | new[] | test.cpp:433:15:433:23 | & ... |
|
||||
| test.cpp:432:14:432:27 | new[] | test.cpp:436:5:436:8 | ... ++ |
|
||||
| test.cpp:432:14:432:27 | new[] | test.cpp:436:5:436:8 | ... ++ |
|
||||
| test.cpp:432:14:432:27 | new[] | test.cpp:438:7:438:15 | ... = ... |
|
||||
| test.cpp:433:15:433:23 | & ... | test.cpp:433:15:433:23 | & ... |
|
||||
| test.cpp:433:15:433:23 | & ... | test.cpp:438:7:438:15 | ... = ... |
|
||||
| test.cpp:433:15:433:23 | & ... | test.cpp:438:7:438:15 | ... = ... |
|
||||
| test.cpp:436:5:436:8 | ... ++ | test.cpp:436:5:436:8 | ... ++ |
|
||||
| test.cpp:436:5:436:8 | ... ++ | test.cpp:438:7:438:15 | ... = ... |
|
||||
| test.cpp:436:5:436:8 | ... ++ | test.cpp:438:7:438:15 | ... = ... |
|
||||
| test.cpp:444:14:444:27 | new[] | test.cpp:445:15:445:23 | & ... |
|
||||
| test.cpp:444:14:444:27 | new[] | test.cpp:445:15:445:23 | & ... |
|
||||
| test.cpp:444:14:444:27 | new[] | test.cpp:448:5:448:8 | ... ++ |
|
||||
| test.cpp:444:14:444:27 | new[] | test.cpp:448:5:448:8 | ... ++ |
|
||||
| test.cpp:444:14:444:27 | new[] | test.cpp:450:7:450:15 | ... = ... |
|
||||
| test.cpp:445:15:445:23 | & ... | test.cpp:445:15:445:23 | & ... |
|
||||
| test.cpp:445:15:445:23 | & ... | test.cpp:450:7:450:15 | ... = ... |
|
||||
| test.cpp:445:15:445:23 | & ... | test.cpp:450:7:450:15 | ... = ... |
|
||||
| test.cpp:448:5:448:8 | ... ++ | test.cpp:448:5:448:8 | ... ++ |
|
||||
| test.cpp:448:5:448:8 | ... ++ | test.cpp:450:7:450:15 | ... = ... |
|
||||
| test.cpp:448:5:448:8 | ... ++ | test.cpp:450:7:450:15 | ... = ... |
|
||||
| test.cpp:480:14:480:27 | new[] | test.cpp:481:15:481:23 | & ... |
|
||||
| test.cpp:480:14:480:27 | new[] | test.cpp:481:15:481:23 | & ... |
|
||||
| test.cpp:480:14:480:27 | new[] | test.cpp:484:5:484:8 | ... ++ |
|
||||
| test.cpp:480:14:480:27 | new[] | test.cpp:484:5:484:8 | ... ++ |
|
||||
| test.cpp:480:14:480:27 | new[] | test.cpp:486:7:486:15 | ... = ... |
|
||||
| test.cpp:481:15:481:23 | & ... | test.cpp:481:15:481:23 | & ... |
|
||||
| test.cpp:481:15:481:23 | & ... | test.cpp:486:7:486:15 | ... = ... |
|
||||
| test.cpp:481:15:481:23 | & ... | test.cpp:486:7:486:15 | ... = ... |
|
||||
| test.cpp:484:5:484:8 | ... ++ | test.cpp:484:5:484:8 | ... ++ |
|
||||
| test.cpp:484:5:484:8 | ... ++ | test.cpp:486:7:486:15 | ... = ... |
|
||||
| test.cpp:484:5:484:8 | ... ++ | test.cpp:486:7:486:15 | ... = ... |
|
||||
| test.cpp:543:14:543:27 | new[] | test.cpp:548:5:548:19 | ... = ... |
|
||||
| test.cpp:554:14:554:27 | new[] | test.cpp:559:5:559:19 | ... = ... |
|
||||
| test.cpp:642:14:642:31 | new[] | test.cpp:647:5:647:19 | ... = ... |
|
||||
| test.cpp:695:13:695:26 | new[] | test.cpp:698:5:698:10 | ... += ... |
|
||||
| test.cpp:695:13:695:26 | new[] | test.cpp:698:5:698:10 | ... += ... |
|
||||
| test.cpp:698:5:698:10 | ... += ... | test.cpp:698:5:698:10 | ... += ... |
|
||||
| test.cpp:698:5:698:10 | ... += ... | test.cpp:701:15:701:16 | p indirection |
|
||||
| test.cpp:705:18:705:18 | q | test.cpp:705:18:705:18 | q |
|
||||
| test.cpp:705:18:705:18 | q | test.cpp:706:12:706:13 | * ... |
|
||||
| test.cpp:705:18:705:18 | q | test.cpp:706:12:706:13 | * ... |
|
||||
| test.cpp:711:13:711:26 | new[] | test.cpp:714:11:714:11 | q |
|
||||
| test.cpp:714:11:714:11 | q | test.cpp:705:18:705:18 | q |
|
||||
| test.cpp:730:12:730:28 | new[] | test.cpp:732:16:732:26 | ... + ... |
|
||||
| test.cpp:730:12:730:28 | new[] | test.cpp:732:16:732:26 | ... + ... |
|
||||
| test.cpp:730:12:730:28 | new[] | test.cpp:733:5:733:12 | ... = ... |
|
||||
| test.cpp:732:16:732:26 | ... + ... | test.cpp:732:16:732:26 | ... + ... |
|
||||
| test.cpp:732:16:732:26 | ... + ... | test.cpp:733:5:733:12 | ... = ... |
|
||||
| test.cpp:732:16:732:26 | ... + ... | test.cpp:733:5:733:12 | ... = ... |
|
||||
@@ -169,10 +87,8 @@ edges
|
||||
| test.cpp:781:14:781:27 | new[] | test.cpp:786:18:786:27 | access to array |
|
||||
| test.cpp:792:60:792:62 | end | test.cpp:800:40:800:43 | mk_array_no_field_flow output argument |
|
||||
| test.cpp:792:60:792:62 | end | test.cpp:832:40:832:43 | mk_array_no_field_flow output argument |
|
||||
| test.cpp:793:14:793:32 | call to malloc | test.cpp:794:5:794:24 | ... = ... |
|
||||
| test.cpp:793:14:793:32 | call to malloc | test.cpp:794:12:794:24 | ... + ... |
|
||||
| test.cpp:794:5:794:24 | ... = ... | test.cpp:792:60:792:62 | end |
|
||||
| test.cpp:794:12:794:24 | ... + ... | test.cpp:794:5:794:24 | ... = ... |
|
||||
| test.cpp:794:12:794:24 | ... + ... | test.cpp:792:60:792:62 | end |
|
||||
| test.cpp:800:40:800:43 | mk_array_no_field_flow output argument | test.cpp:807:7:807:12 | ... = ... |
|
||||
| test.cpp:815:52:815:54 | end | test.cpp:815:52:815:54 | end |
|
||||
| test.cpp:815:52:815:54 | end | test.cpp:821:7:821:12 | ... = ... |
|
||||
@@ -182,8 +98,6 @@ edges
|
||||
| test.cpp:841:18:841:35 | call to malloc | test.cpp:842:3:842:20 | ... = ... |
|
||||
| test.cpp:848:20:848:37 | call to malloc | test.cpp:849:5:849:22 | ... = ... |
|
||||
| test.cpp:856:12:856:35 | call to malloc | test.cpp:857:16:857:29 | ... + ... |
|
||||
| test.cpp:856:12:856:35 | call to malloc | test.cpp:857:16:857:29 | ... + ... |
|
||||
| test.cpp:856:12:856:35 | call to malloc | test.cpp:860:5:860:11 | ... = ... |
|
||||
| test.cpp:857:16:857:29 | ... + ... | test.cpp:857:16:857:29 | ... + ... |
|
||||
| test.cpp:857:16:857:29 | ... + ... | test.cpp:860:5:860:11 | ... = ... |
|
||||
| test.cpp:857:16:857:29 | ... + ... | test.cpp:860:5:860:11 | ... = ... |
|
||||
@@ -204,22 +118,13 @@ nodes
|
||||
| test.cpp:32:14:32:21 | * ... | semmle.label | * ... |
|
||||
| test.cpp:51:33:51:35 | end | semmle.label | end |
|
||||
| test.cpp:52:19:52:37 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:53:5: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: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:206:17:206:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:206:17:206:23 | ... + ... | 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:261:14:261:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
|
||||
@@ -232,45 +137,31 @@ nodes
|
||||
| test.cpp:355:14:355:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:358:14:358:26 | end_plus_one indirection | semmle.label | end_plus_one indirection |
|
||||
| test.cpp:359:14:359:32 | ... + ... indirection | semmle.label | ... + ... indirection |
|
||||
| test.cpp:377:14:377:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:381:5:381:9 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:381:5:381:9 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:384:13:384:16 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:410:14:410:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:411:15:411:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:411:15:411:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:413:5:413:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:413:5:413:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:415:7:415:15 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:421:14:421:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:422:15:422:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:422:15:422:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:424:5:424:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:424:5:424:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:426:7:426:15 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:432:14:432:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:433:15:433:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:433:15:433:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:436:5:436:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:436:5:436:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:438:7:438:15 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:444:14:444:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:445:15:445:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:445:15:445:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:448:5:448:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:448:5:448:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:450:7:450:15 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:480:14:480:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:481:15:481:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:481:15:481:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:484:5:484:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:484:5:484:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:486:7:486:15 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:543:14:543:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:548:5:548:19 | ... = ... | semmle.label | ... = ... |
|
||||
@@ -278,15 +169,6 @@ nodes
|
||||
| test.cpp:559:5:559:19 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:642:14:642:31 | new[] | semmle.label | new[] |
|
||||
| test.cpp:647:5:647:19 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:695:13:695:26 | new[] | semmle.label | new[] |
|
||||
| test.cpp:698:5:698:10 | ... += ... | semmle.label | ... += ... |
|
||||
| test.cpp:698:5:698:10 | ... += ... | semmle.label | ... += ... |
|
||||
| test.cpp:701:15:701:16 | p indirection | semmle.label | p indirection |
|
||||
| test.cpp:705:18:705:18 | q | semmle.label | q |
|
||||
| test.cpp:705:18:705:18 | q | semmle.label | q |
|
||||
| test.cpp:706:12:706:13 | * ... | semmle.label | * ... |
|
||||
| test.cpp:711:13:711:26 | new[] | semmle.label | new[] |
|
||||
| test.cpp:714:11:714:11 | q | semmle.label | q |
|
||||
| test.cpp:730:12:730:28 | new[] | semmle.label | new[] |
|
||||
| test.cpp:732:16:732:26 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:732:16:732:26 | ... + ... | semmle.label | ... + ... |
|
||||
@@ -300,7 +182,6 @@ nodes
|
||||
| test.cpp:786:18:786:27 | access to array | semmle.label | access to array |
|
||||
| test.cpp:792:60:792:62 | end | semmle.label | end |
|
||||
| test.cpp:793:14:793:32 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:794:5:794:24 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:794:12:794:24 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:800:40:800:43 | mk_array_no_field_flow output argument | semmle.label | mk_array_no_field_flow output argument |
|
||||
| test.cpp:807:7:807:12 | ... = ... | semmle.label | ... = ... |
|
||||
@@ -325,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: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: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: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: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 |
|
||||
@@ -342,8 +220,6 @@ subpaths
|
||||
| test.cpp:548:5:548:19 | ... = ... | test.cpp:543:14:543:27 | new[] | test.cpp:548:5:548:19 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:543:14:543:27 | new[] | new[] | test.cpp:548:8:548:14 | src_pos | src_pos |
|
||||
| test.cpp:559:5:559:19 | ... = ... | test.cpp:554:14:554:27 | new[] | test.cpp:559:5:559:19 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:554:14:554:27 | new[] | new[] | test.cpp:559:8:559:14 | src_pos | src_pos |
|
||||
| test.cpp:647:5:647:19 | ... = ... | test.cpp:642:14:642:31 | new[] | test.cpp:647:5:647:19 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:642:14:642:31 | new[] | new[] | test.cpp:647:8:647:14 | src_pos | src_pos |
|
||||
| test.cpp:701:15:701:16 | p indirection | test.cpp:695:13:695:26 | new[] | test.cpp:701:15:701:16 | p indirection | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:695:13:695:26 | new[] | new[] | test.cpp:696:19:696:22 | size | size |
|
||||
| test.cpp:706:12:706:13 | * ... | test.cpp:711:13:711:26 | new[] | test.cpp:706:12:706:13 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:711:13:711:26 | new[] | new[] | test.cpp:712:19:712:22 | size | size |
|
||||
| test.cpp:733:5:733:12 | ... = ... | test.cpp:730:12:730:28 | new[] | test.cpp:733:5:733:12 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:730:12:730:28 | new[] | new[] | test.cpp:732:21:732:25 | ... + ... | ... + ... |
|
||||
| test.cpp:767:16:767:29 | access to array | test.cpp:754:18:754:31 | new[] | test.cpp:767:16:767:29 | access to array | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:754:18:754:31 | new[] | new[] | test.cpp:767:22:767:28 | ... + ... | ... + ... |
|
||||
| test.cpp:767:16:767:29 | access to array | test.cpp:754:18:754:31 | new[] | test.cpp:767:16:767:29 | access to array | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:754:18:754:31 | new[] | new[] | test.cpp:772:22:772:28 | ... + ... | ... + ... |
|
||||
|
||||
@@ -3,9 +3,9 @@ using size_t = decltype(sizeof 0); void* malloc(size_t size);
|
||||
void test1(int size) {
|
||||
char* p = (char*)malloc(size);
|
||||
char* q = p + size; // $ alloc=L4
|
||||
char a = *q; // $ deref=L6 // BAD
|
||||
char a = *q; // $ deref=L5->L6 // BAD
|
||||
char b = *(q - 1); // GOOD
|
||||
char c = *(q + 1); // $ deref=L8+1 // BAD
|
||||
char c = *(q + 1); // $ deref=L5->L8+1 // BAD
|
||||
char d = *(q + size); // BAD [NOT DETECTED]
|
||||
char e = *(q - size); // GOOD
|
||||
char f = *(q + size + 1); // BAD [NOT DETECTED]
|
||||
@@ -17,7 +17,7 @@ void test2(int size) {
|
||||
char* q = p + size - 1; // $ alloc=L16
|
||||
char a = *q; // GOOD
|
||||
char b = *(q - 1); // GOOD
|
||||
char c = *(q + 1); // $ deref=L20 // BAD
|
||||
char c = *(q + 1); // $ deref=L17->L20 // BAD
|
||||
char d = *(q + size); // BAD [NOT DETECTED]
|
||||
char e = *(q - size); // GOOD
|
||||
char f = *(q + size + 1); // BAD [NOT DETECTED]
|
||||
@@ -27,9 +27,9 @@ void test2(int size) {
|
||||
void test3(int size) {
|
||||
char* p = (char*)malloc(size + 1);
|
||||
char* q = p + (size + 1); // $ alloc=L28+1
|
||||
char a = *q; // $ deref=L30 // BAD
|
||||
char a = *q; // $ deref=L29->L30 // BAD
|
||||
char b = *(q - 1); // GOOD
|
||||
char c = *(q + 1); // $ deref=L32+1 // BAD
|
||||
char c = *(q + 1); // $ deref=L29->L32+1 // BAD
|
||||
char d = *(q + size); // BAD [NOT DETECTED]
|
||||
char e = *(q - size); // GOOD
|
||||
char f = *(q + size + 1); // BAD [NOT DETECTED]
|
||||
@@ -198,7 +198,7 @@ void test12(unsigned len, unsigned index) {
|
||||
return;
|
||||
}
|
||||
|
||||
p[index] = '\0'; // $ deref=L201 // BAD
|
||||
p[index] = '\0'; // $ MISSING: deref=L195->L201 // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test13(unsigned len, unsigned index) {
|
||||
@@ -210,7 +210,7 @@ void test13(unsigned len, unsigned index) {
|
||||
return;
|
||||
}
|
||||
|
||||
*q = '\0'; // $ deref=L213 // BAD
|
||||
*q = '\0'; // $ deref=L206->L213 // BAD
|
||||
}
|
||||
|
||||
bool unknown();
|
||||
@@ -229,14 +229,14 @@ void test15(unsigned index) {
|
||||
return;
|
||||
}
|
||||
int* newname = new int[size];
|
||||
newname[index] = 0; // $ alloc=L231 deref=L232 // GOOD [FALSE POSITIVE]
|
||||
newname[index] = 0; // GOOD
|
||||
}
|
||||
|
||||
void test16(unsigned index) {
|
||||
unsigned size = index + 13;
|
||||
if(size >= index) {
|
||||
int* newname = new int[size];
|
||||
newname[index] = 0; // $ alloc=L238 deref=L239 // GOOD [FALSE POSITIVE]
|
||||
newname[index] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ void test17(unsigned len)
|
||||
int *end = xs + len; // $ alloc=L260
|
||||
for (int *x = xs; x <= end; x++)
|
||||
{
|
||||
int i = *x; // $ deref=L264 // BAD
|
||||
int i = *x; // $ deref=L261->L264 // BAD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ void test18(unsigned len)
|
||||
int *end = xs + len; // $ alloc=L270
|
||||
for (int *x = xs; x <= end; x++)
|
||||
{
|
||||
*x = 0; // $ deref=L274 // BAD
|
||||
*x = 0; // $ deref=L271->L274 // BAD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,8 +355,8 @@ void test25(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = xs + size; // $ alloc=L355
|
||||
char *end_plus_one = end + 1;
|
||||
int val1 = *end_plus_one; // $ deref=L358+1 // BAD
|
||||
int val2 = *(end_plus_one + 1); // $ deref=L359+2 // BAD
|
||||
int val1 = *end_plus_one; // $ deref=L356->L358+1 // BAD
|
||||
int val2 = *(end_plus_one + 1); // $ deref=L356->L359+2 // BAD
|
||||
}
|
||||
|
||||
void test26(unsigned size) {
|
||||
@@ -381,7 +381,7 @@ void test27(unsigned size, bool b) {
|
||||
end++;
|
||||
}
|
||||
|
||||
int val = *end; // $ deref=L384+1 // BAD
|
||||
int val = *end; // $ deref=L378->L384+1 // BAD
|
||||
}
|
||||
|
||||
void test28(unsigned size) {
|
||||
@@ -412,7 +412,7 @@ void test28_simple2(unsigned size) {
|
||||
if (xs < end) {
|
||||
xs++;
|
||||
if (xs < end + 1) {
|
||||
xs[0] = 0; // $ deref=L415 // BAD
|
||||
xs[0] = 0; // $ deref=L411->L415 // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -423,7 +423,7 @@ void test28_simple3(unsigned size) {
|
||||
if (xs < end) {
|
||||
xs++;
|
||||
if (xs - 1 < end) {
|
||||
xs[0] = 0; // $ deref=L426 // BAD
|
||||
xs[0] = 0; // $ deref=L422->L426 // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -435,7 +435,7 @@ void test28_simple4(unsigned size) {
|
||||
end++;
|
||||
xs++;
|
||||
if (xs < end) {
|
||||
xs[0] = 0; // $ deref=L438 // BAD
|
||||
xs[0] = 0; // $ deref=L433->L438 // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -447,7 +447,7 @@ void test28_simple5(unsigned size) {
|
||||
if (xs < end) {
|
||||
xs++;
|
||||
if (xs < end) {
|
||||
xs[0] = 0; // $ deref=L450 // BAD
|
||||
xs[0] = 0; // $ deref=L445->L450 // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -483,7 +483,7 @@ void test28_simple8(unsigned size) {
|
||||
if (xs < end) {
|
||||
xs++;
|
||||
if (xs < end - 1) {
|
||||
xs[0] = 0; // $ deref=L486+498 // BAD
|
||||
xs[0] = 0; // $ deref=L481->L486+498 // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -698,12 +698,12 @@ void test34(unsigned size) {
|
||||
p += 1;
|
||||
}
|
||||
if (p + 1 < end) {
|
||||
int val = *p; // $ deref=L698->L700->L701 // GOOD [FALSE POSITIVE]
|
||||
int val = *p; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void deref(char* q) {
|
||||
char x = *q; // $ deref=L714->L705->L706 // BAD
|
||||
char x = *q; // $ MISSING: deref=L714->L705->L706 // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test35(size_t size, char* q)
|
||||
@@ -730,7 +730,7 @@ void test36(unsigned size, unsigned n) {
|
||||
int* p = new int[size + 2];
|
||||
if(n < size + 1) {
|
||||
int* end = p + (n + 2); // $ alloc=L730+2
|
||||
*end = 0; // $ deref=L733 // BAD
|
||||
*end = 0; // $ deref=L732->L733 // BAD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -857,6 +857,6 @@ void test_regression(size_t size) {
|
||||
int* chend = p + (size + 1); // $ alloc=L856+1
|
||||
|
||||
if(p <= chend) {
|
||||
*p = 42; // $ deref=L860 // BAD
|
||||
*p = 42; // $ deref=L857->L860 // BAD
|
||||
}
|
||||
}
|
||||
@@ -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: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: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: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: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 |
|
||||
|
||||
@@ -27,7 +27,7 @@ void test4(bool b) {
|
||||
if (b) {
|
||||
foo = 1;
|
||||
}
|
||||
use(foo); // BAD
|
||||
use(foo); // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test5() {
|
||||
@@ -43,7 +43,7 @@ void test5(int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
foo = i;
|
||||
}
|
||||
use(foo); // BAD
|
||||
use(foo); // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test6(bool b) {
|
||||
@@ -52,7 +52,7 @@ void test6(bool b) {
|
||||
foo = 42;
|
||||
}
|
||||
if (b) {
|
||||
use(foo); // GOOD (REPORTED, FP)
|
||||
use(foo); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ void test7(bool b) {
|
||||
set = true;
|
||||
}
|
||||
if (set) {
|
||||
use(foo); // GOOD (REPORTED, FP)
|
||||
use(foo); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ void test9(int count) {
|
||||
if (!set) {
|
||||
foo = 42;
|
||||
}
|
||||
use(foo); // GOOD (REPORTED, FP)
|
||||
use(foo); // GOOD
|
||||
}
|
||||
|
||||
void test10() {
|
||||
@@ -129,7 +129,7 @@ int absWrong(int i) {
|
||||
} else if (i < 0) {
|
||||
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
|
||||
@@ -326,7 +326,7 @@ int test28() {
|
||||
a = false;
|
||||
c = false;
|
||||
}
|
||||
return val; // GOOD [FALSE POSITIVE]
|
||||
return val; // GOOD
|
||||
}
|
||||
|
||||
int test29() {
|
||||
@@ -472,4 +472,64 @@ void test44() {
|
||||
int y = 1;
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -10,6 +10,7 @@ edges
|
||||
| tests.cpp:131:14:131:35 | call to getenv indirection | tests.cpp:107:30:107:32 | msg indirection |
|
||||
| tests.cpp:132:14:132:35 | call to getenv indirection | tests.cpp:114:30:114:32 | msg indirection |
|
||||
| tests.cpp:133:14:133:35 | call to getenv indirection | tests.cpp:122:30:122:32 | msg indirection |
|
||||
| tests.cpp:139:17:139:22 | call to getenv indirection | tests.cpp:141:15:141:20 | secret indirection |
|
||||
| tests_passwd.cpp:16:8:16:15 | call to getpwnam indirection | tests_passwd.cpp:18:29:18:31 | pwd indirection |
|
||||
| tests_passwd.cpp:16:8:16:15 | call to getpwnam indirection | tests_passwd.cpp:19:26:19:28 | pwd indirection |
|
||||
nodes
|
||||
@@ -37,6 +38,8 @@ nodes
|
||||
| tests.cpp:132:14:132:35 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| tests.cpp:133:14:133:35 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| tests.cpp:133:14:133:35 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| tests.cpp:139:17:139:22 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| tests.cpp:141:15:141:20 | secret indirection | semmle.label | secret indirection |
|
||||
| tests_passwd.cpp:16:8:16:15 | call to getpwnam indirection | semmle.label | call to getpwnam indirection |
|
||||
| tests_passwd.cpp:18:29:18:31 | pwd indirection | semmle.label | pwd indirection |
|
||||
| tests_passwd.cpp:19:26:19:28 | pwd indirection | semmle.label | pwd indirection |
|
||||
@@ -56,5 +59,6 @@ subpaths
|
||||
| tests.cpp:119:7:119:12 | buffer indirection | tests.cpp:132:14:132:35 | call to getenv indirection | tests.cpp:119:7:119:12 | buffer indirection | This operation potentially exposes sensitive system data from $@. | tests.cpp:132:14:132:35 | call to getenv indirection | call to getenv indirection |
|
||||
| tests.cpp:124:15:124:17 | msg indirection | tests.cpp:133:14:133:35 | call to getenv indirection | tests.cpp:124:15:124:17 | msg indirection | This operation potentially exposes sensitive system data from $@. | tests.cpp:133:14:133:35 | call to getenv indirection | call to getenv indirection |
|
||||
| tests.cpp:133:14:133:35 | call to getenv indirection | tests.cpp:133:14:133:35 | call to getenv indirection | tests.cpp:133:14:133:35 | call to getenv indirection | This operation potentially exposes sensitive system data from $@. | tests.cpp:133:14:133:35 | call to getenv indirection | call to getenv indirection |
|
||||
| tests.cpp:141:15:141:20 | secret indirection | tests.cpp:139:17:139:22 | call to getenv indirection | tests.cpp:141:15:141:20 | secret indirection | This operation potentially exposes sensitive system data from $@. | tests.cpp:139:17:139:22 | call to getenv indirection | call to getenv indirection |
|
||||
| tests_passwd.cpp:18:29:18:31 | pwd indirection | tests_passwd.cpp:16:8:16:15 | call to getpwnam indirection | tests_passwd.cpp:18:29:18:31 | pwd indirection | This operation potentially exposes sensitive system data from $@. | tests_passwd.cpp:16:8:16:15 | call to getpwnam indirection | call to getpwnam indirection |
|
||||
| tests_passwd.cpp:19:26:19:28 | pwd indirection | tests_passwd.cpp:16:8:16:15 | call to getpwnam indirection | tests_passwd.cpp:19:26:19:28 | pwd indirection | This operation potentially exposes sensitive system data from $@. | tests_passwd.cpp:16:8:16:15 | call to getpwnam indirection | call to getpwnam indirection |
|
||||
|
||||
@@ -132,3 +132,13 @@ void test5()
|
||||
myOutputFn4(getenv("SECRET_TOKEN")); // BAD: outputs the SECRET_TOKEN environment variable
|
||||
myOutputFn5(getenv("SECRET_TOKEN")); // BAD: outputs the SECRET_TOKEN environment variable
|
||||
}
|
||||
|
||||
void RtlZeroMemory(void* dst, size_t len);
|
||||
|
||||
void test_clear_memory(char *username) {
|
||||
char* secret = getenv("SECRET_TOKEN");
|
||||
|
||||
printf("%s", secret); // BAD
|
||||
RtlZeroMemory(secret, 1024);
|
||||
printf("%s", secret); // GOOD
|
||||
}
|
||||
@@ -22,31 +22,19 @@ edges
|
||||
| tests5.cpp:88:2:88:2 | p indirection | tests5.cpp:89:2:89:2 | p indirection |
|
||||
| tests.cpp:15:23:15:43 | call to XercesDOMParser | tests.cpp:17:2:17:2 | p indirection |
|
||||
| tests.cpp:28:23:28:43 | call to XercesDOMParser | tests.cpp:31:2:31:2 | p indirection |
|
||||
| tests.cpp:35:23:35:43 | call to XercesDOMParser | tests.cpp:37:2:37:2 | (AbstractDOMParser *)... indirection |
|
||||
| tests.cpp:35:23:35:43 | call to XercesDOMParser | tests.cpp:37:2:37:2 | p indirection |
|
||||
| tests.cpp:37:2:37:2 | (AbstractDOMParser *)... indirection | tests.cpp:37:2:37:2 | p indirection |
|
||||
| tests.cpp:37:2:37:2 | p indirection | tests.cpp:37:2:37:2 | p indirection |
|
||||
| tests.cpp:37:2:37:2 | p indirection | tests.cpp:38:2:38:2 | (AbstractDOMParser *)... indirection |
|
||||
| tests.cpp:37:2:37:2 | p indirection | tests.cpp:38:2:38:2 | p indirection |
|
||||
| tests.cpp:38:2:38:2 | (AbstractDOMParser *)... indirection | tests.cpp:38:2:38:2 | p indirection |
|
||||
| tests.cpp:38:2:38:2 | p indirection | tests.cpp:38:2:38:2 | p indirection |
|
||||
| tests.cpp:38:2:38:2 | p indirection | tests.cpp:39:2:39:2 | p indirection |
|
||||
| tests.cpp:51:23:51:43 | call to XercesDOMParser | tests.cpp:53:2:53:2 | (AbstractDOMParser *)... indirection |
|
||||
| tests.cpp:51:23:51:43 | call to XercesDOMParser | tests.cpp:53:2:53:2 | p indirection |
|
||||
| tests.cpp:53:2:53:2 | (AbstractDOMParser *)... indirection | tests.cpp:53:2:53:2 | p indirection |
|
||||
| tests.cpp:53:2:53:2 | p indirection | tests.cpp:53:2:53:2 | p indirection |
|
||||
| tests.cpp:53:2:53:2 | p indirection | tests.cpp:55:2:55:2 | (AbstractDOMParser *)... indirection |
|
||||
| tests.cpp:53:2:53:2 | p indirection | tests.cpp:55:2:55:2 | p indirection |
|
||||
| tests.cpp:55:2:55:2 | (AbstractDOMParser *)... indirection | tests.cpp:55:2:55:2 | p indirection |
|
||||
| tests.cpp:55:2:55:2 | p indirection | tests.cpp:55:2:55:2 | p indirection |
|
||||
| tests.cpp:55:2:55:2 | p indirection | tests.cpp:56:2:56:2 | p indirection |
|
||||
| tests.cpp:55:2:55:2 | p indirection | tests.cpp:57:2:57:2 | (AbstractDOMParser *)... indirection |
|
||||
| tests.cpp:55:2:55:2 | p indirection | tests.cpp:57:2:57:2 | p indirection |
|
||||
| tests.cpp:57:2:57:2 | (AbstractDOMParser *)... indirection | tests.cpp:57:2:57:2 | p indirection |
|
||||
| tests.cpp:57:2:57:2 | p indirection | tests.cpp:57:2:57:2 | p indirection |
|
||||
| tests.cpp:57:2:57:2 | p indirection | tests.cpp:59:2:59:2 | (AbstractDOMParser *)... indirection |
|
||||
| tests.cpp:57:2:57:2 | p indirection | tests.cpp:59:2:59:2 | p indirection |
|
||||
| tests.cpp:59:2:59:2 | (AbstractDOMParser *)... indirection | tests.cpp:59:2:59:2 | p indirection |
|
||||
| tests.cpp:59:2:59:2 | p indirection | tests.cpp:59:2:59:2 | p indirection |
|
||||
| tests.cpp:59:2:59:2 | p indirection | tests.cpp:60:2:60:2 | p indirection |
|
||||
| tests.cpp:66:23:66:43 | call to XercesDOMParser | tests.cpp:69:2:69:2 | p indirection |
|
||||
@@ -104,25 +92,19 @@ nodes
|
||||
| tests.cpp:28:23:28:43 | call to XercesDOMParser | semmle.label | call to XercesDOMParser |
|
||||
| tests.cpp:31:2:31:2 | p indirection | semmle.label | p indirection |
|
||||
| tests.cpp:35:23:35:43 | call to XercesDOMParser | semmle.label | call to XercesDOMParser |
|
||||
| tests.cpp:37:2:37:2 | (AbstractDOMParser *)... indirection | semmle.label | (AbstractDOMParser *)... indirection |
|
||||
| tests.cpp:37:2:37:2 | p indirection | semmle.label | p indirection |
|
||||
| tests.cpp:37:2:37:2 | p indirection | semmle.label | p indirection |
|
||||
| tests.cpp:38:2:38:2 | (AbstractDOMParser *)... indirection | semmle.label | (AbstractDOMParser *)... indirection |
|
||||
| tests.cpp:38:2:38:2 | p indirection | semmle.label | p indirection |
|
||||
| tests.cpp:38:2:38:2 | p indirection | semmle.label | p indirection |
|
||||
| tests.cpp:39:2:39:2 | p indirection | semmle.label | p indirection |
|
||||
| tests.cpp:51:23:51:43 | call to XercesDOMParser | semmle.label | call to XercesDOMParser |
|
||||
| tests.cpp:53:2:53:2 | (AbstractDOMParser *)... indirection | semmle.label | (AbstractDOMParser *)... indirection |
|
||||
| tests.cpp:53:2:53:2 | p indirection | semmle.label | p indirection |
|
||||
| tests.cpp:53:2:53:2 | p indirection | semmle.label | p indirection |
|
||||
| tests.cpp:55:2:55:2 | (AbstractDOMParser *)... indirection | semmle.label | (AbstractDOMParser *)... indirection |
|
||||
| tests.cpp:55:2:55:2 | p indirection | semmle.label | p indirection |
|
||||
| tests.cpp:55:2:55:2 | p indirection | semmle.label | p indirection |
|
||||
| tests.cpp:56:2:56:2 | p indirection | semmle.label | p indirection |
|
||||
| tests.cpp:57:2:57:2 | (AbstractDOMParser *)... indirection | semmle.label | (AbstractDOMParser *)... indirection |
|
||||
| tests.cpp:57:2:57:2 | p indirection | semmle.label | p indirection |
|
||||
| tests.cpp:57:2:57:2 | p indirection | semmle.label | p indirection |
|
||||
| tests.cpp:59:2:59:2 | (AbstractDOMParser *)... indirection | semmle.label | (AbstractDOMParser *)... indirection |
|
||||
| tests.cpp:59:2:59:2 | p indirection | semmle.label | p indirection |
|
||||
| tests.cpp:59:2:59:2 | p indirection | semmle.label | p indirection |
|
||||
| tests.cpp:60:2:60:2 | p indirection | semmle.label | p indirection |
|
||||
|
||||
Reference in New Issue
Block a user