Merge branch 'main' into ts53-ts

This commit is contained in:
erik-krogh
2023-11-20 20:31:00 +01:00
2268 changed files with 94487 additions and 30493 deletions

View File

@@ -145,9 +145,9 @@ namespace Semmle.Autobuild.Cpp.Tests
bool IBuildActions.IsMacOs() => IsMacOs; bool IBuildActions.IsMacOs() => IsMacOs;
public bool IsArm { get; set; } public bool IsRunningOnAppleSilicon { get; set; }
bool IBuildActions.IsArm() => IsArm; bool IBuildActions.IsRunningOnAppleSilicon() => IsRunningOnAppleSilicon;
string IBuildActions.PathCombine(params string[] parts) string IBuildActions.PathCombine(params string[] parts)
{ {

View File

@@ -1,3 +1,17 @@
## 0.12.0
### Breaking Changes
* The expressions `AssignPointerAddExpr` and `AssignPointerSubExpr` are no longer subtypes of `AssignBitwiseOperation`.
### Minor Analysis Improvements
* The "Returning stack-allocated memory" (`cpp/return-stack-allocated-memory`) query now also detects returning stack-allocated memory allocated by calls to `alloca`, `strdupa`, and `strndupa`.
* Added models for `strlcpy` and `strlcat`.
* Added models for the `sprintf` variants from the `StrSafe.h` header.
* Added SQL API models for `ODBC`.
* Added taint models for `realloc` and related functions.
## 0.11.0 ## 0.11.0
### Breaking Changes ### Breaking Changes

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added taint models for `realloc` and related functions.

View File

@@ -1,4 +0,0 @@
---
category: breaking
---
* The expressions `AssignPointerAddExpr` and `AssignPointerSubExpr` are no longer subtypes of `AssignBitwiseOperation`.

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

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 0.11.0 lastReleaseVersion: 0.12.0

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all name: codeql/cpp-all
version: 0.11.1-dev version: 0.12.1-dev
groups: cpp groups: cpp
dbscheme: semmlecode.cpp.dbscheme dbscheme: semmlecode.cpp.dbscheme
extractor: cpp extractor: cpp

View File

@@ -31,6 +31,11 @@ abstract class MustFlowConfiguration extends string {
*/ */
abstract predicate isSink(Operand sink); abstract predicate isSink(Operand sink);
/**
* Holds if data flow through `instr` is prohibited.
*/
predicate isBarrier(Instruction instr) { none() }
/** /**
* Holds if the additional flow step from `node1` to `node2` must be taken * Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis. * into account in the analysis.
@@ -48,18 +53,21 @@ abstract class MustFlowConfiguration extends string {
*/ */
final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) { final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) {
this.isSource(source.getInstruction()) and this.isSource(source.getInstruction()) and
source.getASuccessor+() = sink source.getASuccessor*() = sink
} }
} }
/** Holds if `node` flows from a source. */ /** Holds if `node` flows from a source. */
pragma[nomagic] pragma[nomagic]
private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) { private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) {
config.isSource(node) not config.isBarrier(node) and
or (
exists(Instruction mid | config.isSource(node)
step(mid, node, config) and or
flowsFromSource(mid, pragma[only_bind_into](config)) exists(Instruction mid |
step(mid, node, config) and
flowsFromSource(mid, pragma[only_bind_into](config))
)
) )
} }

View File

@@ -81,6 +81,14 @@ class Node0Impl extends TIRDataFlowNode0 {
/** Gets the operands corresponding to this node, if any. */ /** Gets the operands corresponding to this node, if any. */
Operand asOperand() { result = this.(OperandNode0).getOperand() } Operand asOperand() { result = this.(OperandNode0).getOperand() }
/** Gets the location of this node. */
final Location getLocation() { result = this.getLocationImpl() }
/** INTERNAL: Do not use. */
Location getLocationImpl() {
none() // overridden by subclasses
}
/** INTERNAL: Do not use. */ /** INTERNAL: Do not use. */
string toStringImpl() { string toStringImpl() {
none() // overridden by subclasses none() // overridden by subclasses
@@ -131,9 +139,15 @@ abstract class InstructionNode0 extends Node0Impl {
override DataFlowType getType() { result = getInstructionType(instr, _) } override DataFlowType getType() { result = getInstructionType(instr, _) }
override string toStringImpl() { override string toStringImpl() {
// This predicate is overridden in subclasses. This default implementation if instr.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
// does not use `Instruction.toString` because that's expensive to compute. then result = "this"
result = instr.getOpcode().toString() else result = instr.getAst().toString()
}
override Location getLocationImpl() {
if exists(instr.getAst().getLocation())
then result = instr.getAst().getLocation()
else result instanceof UnknownDefaultLocation
} }
final override predicate isGLValue() { exists(getInstructionType(instr, true)) } final override predicate isGLValue() { exists(getInstructionType(instr, true)) }
@@ -173,7 +187,17 @@ abstract class OperandNode0 extends Node0Impl {
override DataFlowType getType() { result = getOperandType(op, _) } override DataFlowType getType() { result = getOperandType(op, _) }
override string toStringImpl() { result = op.toString() } override string toStringImpl() {
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = op.getDef().getAst().toString()
}
override Location getLocationImpl() {
if exists(op.getDef().getAst().getLocation())
then result = op.getDef().getAst().getLocation()
else result instanceof UnknownDefaultLocation
}
final override predicate isGLValue() { exists(getOperandType(op, true)) } final override predicate isGLValue() { exists(getOperandType(op, true)) }
} }
@@ -621,6 +645,24 @@ class GlobalLikeVariable extends Variable {
} }
} }
/**
* Returns the smallest indirection for the type `t`.
*
* For most types this is `1`, but for `ArrayType`s (which are allocated on
* the stack) this is `0`
*/
int getMinIndirectionsForType(Type t) {
if t.getUnspecifiedType() instanceof Cpp::ArrayType then result = 0 else result = 1
}
private int getMinIndirectionForGlobalUse(Ssa::GlobalUse use) {
result = getMinIndirectionsForType(use.getUnspecifiedType())
}
private int getMinIndirectionForGlobalDef(Ssa::GlobalDef def) {
result = getMinIndirectionsForType(def.getUnspecifiedType())
}
/** /**
* Holds if data can flow from `node1` to `node2` in a way that loses the * Holds if data can flow from `node1` to `node2` in a way that loses the
* calling context. For example, this would happen with flow through a * calling context. For example, this would happen with flow through a
@@ -632,20 +674,20 @@ predicate jumpStep(Node n1, Node n2) {
v = globalUse.getVariable() and v = globalUse.getVariable() and
n1.(FinalGlobalValue).getGlobalUse() = globalUse n1.(FinalGlobalValue).getGlobalUse() = globalUse
| |
globalUse.getIndirectionIndex() = 1 and globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
v = n2.asVariable() v = n2.asVariable()
or or
v = n2.asIndirectVariable(globalUse.getIndirectionIndex()) v = n2.asIndirectVariable(globalUse.getIndirection())
) )
or or
exists(Ssa::GlobalDef globalDef | exists(Ssa::GlobalDef globalDef |
v = globalDef.getVariable() and v = globalDef.getVariable() and
n2.(InitialGlobalValue).getGlobalDef() = globalDef n2.(InitialGlobalValue).getGlobalDef() = globalDef
| |
globalDef.getIndirectionIndex() = 1 and globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
v = n1.asVariable() v = n1.asVariable()
or or
v = n1.asIndirectVariable(globalDef.getIndirectionIndex()) v = n1.asIndirectVariable(globalDef.getIndirection())
) )
) )
} }

View File

@@ -34,7 +34,8 @@ cached
private newtype TIRDataFlowNode = private newtype TIRDataFlowNode =
TNode0(Node0Impl node) { DataFlowImplCommon::forceCachingInSameStage() } or TNode0(Node0Impl node) { DataFlowImplCommon::forceCachingInSameStage() } or
TVariableNode(Variable var, int indirectionIndex) { TVariableNode(Variable var, int indirectionIndex) {
indirectionIndex = [1 .. Ssa::getMaxIndirectionsForType(var.getUnspecifiedType())] indirectionIndex =
[getMinIndirectionsForType(var.getUnspecifiedType()) .. Ssa::getMaxIndirectionsForType(var.getUnspecifiedType())]
} or } or
TPostFieldUpdateNode(FieldAddress operand, int indirectionIndex) { TPostFieldUpdateNode(FieldAddress operand, int indirectionIndex) {
indirectionIndex = indirectionIndex =
@@ -346,7 +347,9 @@ class Node extends TIRDataFlowNode {
* Gets the variable corresponding to this node, if any. This can be used for * Gets the variable corresponding to this node, if any. This can be used for
* modeling flow in and out of global variables. * modeling flow in and out of global variables.
*/ */
Variable asVariable() { this = TVariableNode(result, 1) } Variable asVariable() {
this = TVariableNode(result, getMinIndirectionsForType(result.getUnspecifiedType()))
}
/** /**
* Gets the `indirectionIndex`'th indirection of this node's underlying variable, if any. * Gets the `indirectionIndex`'th indirection of this node's underlying variable, if any.
@@ -354,7 +357,7 @@ class Node extends TIRDataFlowNode {
* This can be used for modeling flow in and out of global variables. * This can be used for modeling flow in and out of global variables.
*/ */
Variable asIndirectVariable(int indirectionIndex) { Variable asIndirectVariable(int indirectionIndex) {
indirectionIndex > 1 and indirectionIndex > getMinIndirectionsForType(result.getUnspecifiedType()) and
this = TVariableNode(result, indirectionIndex) this = TVariableNode(result, indirectionIndex)
} }
@@ -432,6 +435,10 @@ private class Node0 extends Node, TNode0 {
override Declaration getFunction() { result = node.getFunction() } override Declaration getFunction() { result = node.getFunction() }
override Location getLocationImpl() { result = node.getLocation() }
override string toStringImpl() { result = node.toString() }
override DataFlowType getType() { result = node.getType() } override DataFlowType getType() { result = node.getType() }
override predicate isGLValue() { node.isGLValue() } override predicate isGLValue() { node.isGLValue() }
@@ -448,18 +455,6 @@ class InstructionNode extends Node0 {
/** Gets the instruction corresponding to this node. */ /** Gets the instruction corresponding to this node. */
Instruction getInstruction() { result = instr } Instruction getInstruction() { result = instr }
override Location getLocationImpl() {
if exists(instr.getAst().getLocation())
then result = instr.getAst().getLocation()
else result instanceof UnknownDefaultLocation
}
override string toStringImpl() {
if instr.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = instr.getAst().toString()
}
} }
/** /**
@@ -473,18 +468,6 @@ class OperandNode extends Node, Node0 {
/** Gets the operand corresponding to this node. */ /** Gets the operand corresponding to this node. */
Operand getOperand() { result = op } Operand getOperand() { result = op }
override Location getLocationImpl() {
if exists(op.getDef().getAst().getLocation())
then result = op.getDef().getAst().getLocation()
else result instanceof UnknownDefaultLocation
}
override string toStringImpl() {
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = op.getDef().getAst().toString()
}
} }
/** /**
@@ -1293,31 +1276,90 @@ abstract private class IndirectExprNodeBase extends Node {
} }
} }
private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand /** A signature for converting an indirect node to an expression. */
{ private signature module IndirectNodeToIndirectExprSig {
IndirectOperandIndirectExprNode() { /** The indirect node class to be converted to an expression */
exists(Expr e, int n, int indirectionIndex | class IndirectNode;
indirectExprNodeShouldBeIndirectOperand(this, e, n, indirectionIndex) and
not indirectExprNodeShouldBeIndirectOperand(_, e, n + 1, indirectionIndex) /**
) * Holds if the indirect expression at indirection index `indirectionIndex`
* of `node` is `e`. The integer `n` specifies how many conversions has been
* applied to `node`.
*/
predicate indirectNodeHasIndirectExpr(IndirectNode node, Expr e, int n, int indirectionIndex);
}
/**
* A module that implements the logic for deciding whether an indirect node
* should be an `IndirectExprNode`.
*/
private module IndirectNodeToIndirectExpr<IndirectNodeToIndirectExprSig Sig> {
import Sig
/**
* This predicate shifts the indirection index by one when `conv` is a
* `ReferenceDereferenceExpr`.
*
* This is necessary because `ReferenceDereferenceExpr` is a conversion
* in the AST, but appears as a `LoadInstruction` in the IR.
*/
bindingset[e, indirectionIndex]
private predicate adjustForReference(
Expr e, int indirectionIndex, Expr conv, int adjustedIndirectionIndex
) {
conv.(ReferenceDereferenceExpr).getExpr() = e and
adjustedIndirectionIndex = indirectionIndex - 1
or
not conv instanceof ReferenceDereferenceExpr and
conv = e and
adjustedIndirectionIndex = indirectionIndex
} }
final override Expr getConvertedExpr(int n, int index) { /** Holds if `node` should be an `IndirectExprNode`. */
indirectExprNodeShouldBeIndirectOperand(this, result, n, index) predicate charpred(IndirectNode node) {
exists(Expr e, int n, int indirectionIndex |
indirectNodeHasIndirectExpr(node, e, n, indirectionIndex) and
not exists(Expr conv, int adjustedIndirectionIndex |
adjustForReference(e, indirectionIndex, conv, adjustedIndirectionIndex) and
indirectNodeHasIndirectExpr(_, conv, n + 1, adjustedIndirectionIndex)
)
)
} }
} }
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction private module IndirectOperandIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
class IndirectNode = IndirectOperand;
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectOperand/4;
}
module IndirectOperandToIndirectExpr =
IndirectNodeToIndirectExpr<IndirectOperandIndirectExprNodeImpl>;
private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
{ {
IndirectInstructionIndirectExprNode() { IndirectOperandIndirectExprNode() { IndirectOperandToIndirectExpr::charpred(this) }
exists(Expr e, int n, int indirectionIndex |
indirectExprNodeShouldBeIndirectInstruction(this, e, n, indirectionIndex) and
not indirectExprNodeShouldBeIndirectInstruction(_, e, n + 1, indirectionIndex)
)
}
final override Expr getConvertedExpr(int n, int index) { final override Expr getConvertedExpr(int n, int index) {
indirectExprNodeShouldBeIndirectInstruction(this, result, n, index) IndirectOperandToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
}
}
private module IndirectInstructionIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
class IndirectNode = IndirectInstruction;
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectInstruction/4;
}
module IndirectInstructionToIndirectExpr =
IndirectNodeToIndirectExpr<IndirectInstructionIndirectExprNodeImpl>;
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction
{
IndirectInstructionIndirectExprNode() { IndirectInstructionToIndirectExpr::charpred(this) }
final override Expr getConvertedExpr(int n, int index) {
IndirectInstructionToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
} }
} }

View File

@@ -113,22 +113,12 @@ private newtype TDefOrUseImpl =
TGlobalUse(GlobalLikeVariable v, IRFunction f, int indirectionIndex) { TGlobalUse(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
// Represents a final "use" of a global variable to ensure that // Represents a final "use" of a global variable to ensure that
// the assignment to a global variable isn't ruled out as dead. // the assignment to a global variable isn't ruled out as dead.
exists(VariableAddressInstruction vai, int defIndex | isGlobalUse(v, f, _, indirectionIndex)
vai.getEnclosingIRFunction() = f and
vai.getAstVariable() = v and
isDef(_, _, _, vai, _, defIndex) and
indirectionIndex = [0 .. defIndex] + 1
)
} or } or
TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) { TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
// Represents the initial "definition" of a global variable when entering // Represents the initial "definition" of a global variable when entering
// a function body. // a function body.
exists(VariableAddressInstruction vai | isGlobalDefImpl(v, f, _, indirectionIndex)
vai.getEnclosingIRFunction() = f and
vai.getAstVariable() = v and
isUse(_, _, vai, _, indirectionIndex) and
not isDef(_, _, vai.getAUse(), _, _, _)
)
} or } or
TIteratorDef( TIteratorDef(
Operand iteratorDerefAddress, BaseSourceVariableInstruction container, int indirectionIndex Operand iteratorDerefAddress, BaseSourceVariableInstruction container, int indirectionIndex
@@ -150,6 +140,27 @@ private newtype TDefOrUseImpl =
) )
} }
private predicate isGlobalUse(
GlobalLikeVariable v, IRFunction f, int indirection, int indirectionIndex
) {
exists(VariableAddressInstruction vai |
vai.getEnclosingIRFunction() = f and
vai.getAstVariable() = v and
isDef(_, _, _, vai, indirection, indirectionIndex)
)
}
private predicate isGlobalDefImpl(
GlobalLikeVariable v, IRFunction f, int indirection, int indirectionIndex
) {
exists(VariableAddressInstruction vai |
vai.getEnclosingIRFunction() = f and
vai.getAstVariable() = v and
isUse(_, _, vai, indirection, indirectionIndex) and
not isDef(_, _, _, vai, _, indirectionIndex)
)
}
private predicate unspecifiedTypeIsModifiableAt(Type unspecified, int indirectionIndex) { private predicate unspecifiedTypeIsModifiableAt(Type unspecified, int indirectionIndex) {
indirectionIndex = [1 .. getIndirectionForUnspecifiedType(unspecified).getNumberOfIndirections()] and indirectionIndex = [1 .. getIndirectionForUnspecifiedType(unspecified).getNumberOfIndirections()] and
exists(CppType cppType | exists(CppType cppType |
@@ -438,7 +449,7 @@ class GlobalUse extends UseImpl, TGlobalUse {
override FinalGlobalValue getNode() { result.getGlobalUse() = this } override FinalGlobalValue getNode() { result.getGlobalUse() = this }
override int getIndirection() { result = ind + 1 } override int getIndirection() { isGlobalUse(global, f, result, ind) }
/** Gets the global variable associated with this use. */ /** Gets the global variable associated with this use. */
GlobalLikeVariable getVariable() { result = global } GlobalLikeVariable getVariable() { result = global }
@@ -460,7 +471,9 @@ class GlobalUse extends UseImpl, TGlobalUse {
) )
} }
override SourceVariable getSourceVariable() { sourceVariableIsGlobal(result, global, f, ind) } override SourceVariable getSourceVariable() {
sourceVariableIsGlobal(result, global, f, this.getIndirection())
}
final override Cpp::Location getLocation() { result = f.getLocation() } final override Cpp::Location getLocation() { result = f.getLocation() }
@@ -501,16 +514,18 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
/** Gets the global variable associated with this definition. */ /** Gets the global variable associated with this definition. */
override SourceVariable getSourceVariable() { override SourceVariable getSourceVariable() {
sourceVariableIsGlobal(result, global, f, indirectionIndex) sourceVariableIsGlobal(result, global, f, this.getIndirection())
} }
int getIndirection() { result = indirectionIndex }
/** /**
* Gets the type of this use after specifiers have been deeply stripped * Gets the type of this use after specifiers have been deeply stripped
* and typedefs have been resolved. * and typedefs have been resolved.
*/ */
Type getUnspecifiedType() { result = global.getUnspecifiedType() } Type getUnspecifiedType() { result = global.getUnspecifiedType() }
override string toString() { result = "GlobalDef" } override string toString() { result = "Def of " + this.getSourceVariable() }
override Location getLocation() { result = f.getLocation() } override Location getLocation() { result = f.getLocation() }
@@ -980,7 +995,7 @@ class GlobalDef extends TGlobalDef, SsaDefOrUse {
final override Location getLocation() { result = global.getLocation() } final override Location getLocation() { result = global.getLocation() }
/** Gets a textual representation of this definition. */ /** Gets a textual representation of this definition. */
override string toString() { result = "GlobalDef" } override string toString() { result = global.toString() }
/** /**
* Holds if this definition has index `index` in block `block`, and * Holds if this definition has index `index` in block `block`, and
@@ -990,6 +1005,9 @@ class GlobalDef extends TGlobalDef, SsaDefOrUse {
global.hasIndexInBlock(block, index, sv) global.hasIndexInBlock(block, index, sv)
} }
/** Gets the indirection index of this definition. */
int getIndirection() { result = global.getIndirection() }
/** Gets the indirection index of this definition. */ /** Gets the indirection index of this definition. */
int getIndirectionIndex() { result = global.getIndirectionIndex() } int getIndirectionIndex() { result = global.getIndirectionIndex() }

View File

@@ -872,7 +872,7 @@ private module Cached {
upper = countIndirectionsForCppType(type) and upper = countIndirectionsForCppType(type) and
ind = ind0 + [lower .. upper] and ind = ind0 + [lower .. upper] and
indirectionIndex = ind - (ind0 + lower) and indirectionIndex = ind - (ind0 + lower) and
(if type.hasType(any(Cpp::ArrayType arrayType), true) then lower = 0 else lower = 1) lower = getMinIndirectionsForType(any(Type t | type.hasUnspecifiedType(t, _)))
) )
} }

View File

@@ -49,10 +49,11 @@ private class FgetsFunction extends DataFlowFunction, TaintFunction, ArrayFuncti
} }
override predicate hasRemoteFlowSource(FunctionOutput output, string description) { override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
output.isParameterDeref(0) and (
description = "string read by " + this.getName() output.isParameterDeref(0) or
or output.isReturnValue() or
output.isReturnValue() and output.isReturnValueDeref()
) and
description = "string read by " + this.getName() description = "string read by " + this.getName()
} }

View File

@@ -157,7 +157,7 @@ private class Getaddrinfo extends TaintFunction, ArrayFunction, RemoteFlowSource
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam in [0, 1] } override predicate hasArrayWithNullTerminator(int bufParam) { bufParam in [0, 1] }
override predicate hasRemoteFlowSource(FunctionOutput output, string description) { override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
output.isParameterDeref(3) and output.isParameterDeref(3, 2) and
description = "address returned by " + this.getName() description = "address returned by " + this.getName()
} }
} }

View File

@@ -147,19 +147,32 @@ private class SnprintfImpl extends Snprintf {
/** /**
* The Microsoft `StringCchPrintf` function and variants. * The Microsoft `StringCchPrintf` function and variants.
* See: https://learn.microsoft.com/en-us/windows/win32/api/strsafe/
* and
* https://learn.microsoft.com/en-us/previous-versions/windows/embedded/ms860435(v=msdn.10)
*/ */
private class StringCchPrintf extends FormattingFunction { private class StringCchPrintf extends FormattingFunction {
StringCchPrintf() { StringCchPrintf() {
this instanceof TopLevelFunction and this instanceof TopLevelFunction and
this.hasGlobalName([ exists(string baseName |
"StringCchPrintf", "StringCchPrintfEx", "StringCchPrintf_l", "StringCchPrintf_lEx", baseName in [
"StringCbPrintf", "StringCbPrintfEx", "StringCbPrintf_l", "StringCbPrintf_lEx" "StringCchPrintf", //StringCchPrintf(pszDest, cchDest, pszFormat, ...)
]) and "StringCchPrintfEx", //StringCchPrintfEx(pszDest,cchDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, ...)
"StringCchPrintf_l", //StringCchPrintf_l(pszDest, cbDest, pszFormat, locale, ...)
"StringCchPrintf_lEx", //StringCchPrintf_lEx(pszDest, cchDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, locale, ...)
"StringCbPrintf", //StringCbPrintf(pszDest, cbDest, pszFormat, ...)
"StringCbPrintfEx", //StringCbPrintfEx(pszDest, cbDest, ppszDestEnd, pcbRemaining, dwFlags, pszFormat, ...)
"StringCbPrintf_l", //StringCbPrintf_l(pszDest, cbDest, pszFormat, locale, ...)
"StringCbPrintf_lEx" //StringCbPrintf_lEx(pszDest, cbDest, ppszDestEnd, pcbRemaining, dwFlags, pszFormat, locale, ...)
]
|
this.hasGlobalName(baseName + ["", "A", "W"])
) and
not exists(this.getDefinition().getFile().getRelativePath()) not exists(this.getDefinition().getFile().getRelativePath())
} }
override int getFormatParameterIndex() { override int getFormatParameterIndex() {
if this.getName().matches("%Ex") then result = 5 else result = 2 if this.getName().matches("%Ex" + ["", "A", "W"]) then result = 5 else result = 2
} }
override int getOutputParameterIndex(boolean isStream) { result = 0 and isStream = false } override int getOutputParameterIndex(boolean isStream) { result = 0 and isStream = false }

View File

@@ -58,7 +58,7 @@ private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, Rem
override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 } override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 }
override predicate hasRemoteFlowSink(FunctionInput input, string description) { override predicate hasRemoteFlowSink(FunctionInput input, string description) {
input.isParameterDeref(1) and description = "buffer sent by " + this.getName() input.isParameterDeref(1, 1) and description = "buffer sent by " + this.getName()
} }
override predicate hasSocketInput(FunctionInput input) { input.isParameter(0) } override predicate hasSocketInput(FunctionInput input) { input.isParameter(0) }

View File

@@ -10,6 +10,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
/** /**
* The standard function `strcat` and its wide, sized, and Microsoft variants. * The standard function `strcat` and its wide, sized, and Microsoft variants.
*
* Does not include `strlcat`, which is covered by `StrlcatFunction`
*/ */
class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction { class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction {
StrcatFunction() { StrcatFunction() {
@@ -90,3 +92,64 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
buffer = true buffer = true
} }
} }
/**
* The `strlcat` function.
*/
class StrlcatFunction extends TaintFunction, ArrayFunction, SideEffectFunction {
StrlcatFunction() {
this.hasGlobalName("strlcat") // strlcat(dst, src, dst_size)
}
/**
* Gets the index of the parameter that is the size of the copy (in characters).
*/
int getParamSize() { result = 2 }
/**
* Gets the index of the parameter that is the source of the copy.
*/
int getParamSrc() { result = 1 }
/**
* Gets the index of the parameter that is the destination to be appended to.
*/
int getParamDest() { result = 0 }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
(
input.isParameter(2)
or
input.isParameterDeref(0)
or
input.isParameterDeref(1)
) and
output.isParameterDeref(0)
}
override predicate hasArrayInput(int param) {
param = 0 or
param = 1
}
override predicate hasArrayOutput(int param) { param = 0 }
override predicate hasArrayWithNullTerminator(int param) { param = 1 }
override predicate hasArrayWithUnknownSize(int param) { param = 0 }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = 0 and
buffer = true and
mustWrite = false
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
(i = 0 or i = 1) and
buffer = true
}
}

View File

@@ -32,7 +32,8 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
"wcsxfrm_l", // _strxfrm_l(dest, src, max_amount, locale) "wcsxfrm_l", // _strxfrm_l(dest, src, max_amount, locale)
"_mbsnbcpy", // _mbsnbcpy(dest, src, max_amount) "_mbsnbcpy", // _mbsnbcpy(dest, src, max_amount)
"stpcpy", // stpcpy(dest, src) "stpcpy", // stpcpy(dest, src)
"stpncpy" // stpcpy(dest, src, max_amount) "stpncpy", // stpncpy(dest, src, max_amount)
"strlcpy" // strlcpy(dst, src, dst_size)
]) ])
or or
( (
@@ -53,6 +54,11 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
*/ */
private predicate isSVariant() { this.getName().matches("%\\_s") } private predicate isSVariant() { this.getName().matches("%\\_s") }
/**
* Holds if the function returns the total length the string would have had if the size was unlimited.
*/
private predicate returnsTotalLength() { this.getName() = "strlcpy" }
/** /**
* Gets the index of the parameter that is the maximum size of the copy (in characters). * Gets the index of the parameter that is the maximum size of the copy (in characters).
*/ */
@@ -60,7 +66,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
if this.isSVariant() if this.isSVariant()
then result = 1 then result = 1
else ( else (
this.getName().matches(["%ncpy%", "%nbcpy%", "%xfrm%"]) and this.getName().matches(["%ncpy%", "%nbcpy%", "%xfrm%", "strlcpy"]) and
result = 2 result = 2
) )
} }
@@ -100,6 +106,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
input.isParameterDeref(this.getParamSrc()) and input.isParameterDeref(this.getParamSrc()) and
output.isReturnValueDeref() output.isReturnValueDeref()
or or
not this.returnsTotalLength() and
input.isParameter(this.getParamDest()) and input.isParameter(this.getParamDest()) and
output.isReturnValue() output.isReturnValue()
} }
@@ -110,8 +117,9 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
exists(this.getParamSize()) and exists(this.getParamSize()) and
input.isParameterDeref(this.getParamSrc()) and input.isParameterDeref(this.getParamSrc()) and
( (
output.isParameterDeref(this.getParamDest()) or output.isParameterDeref(this.getParamDest())
output.isReturnValueDeref() or
not this.returnsTotalLength() and output.isReturnValueDeref()
) )
} }

View File

@@ -8,7 +8,7 @@ import semmle.code.cpp.Parameter
private newtype TFunctionInput = private newtype TFunctionInput =
TInParameter(ParameterIndex i) or TInParameter(ParameterIndex i) or
TInParameterDeref(ParameterIndex i) or TInParameterDeref(ParameterIndex i, int indirectionIndex) { indirectionIndex = [1, 2] } or
TInQualifierObject() or TInQualifierObject() or
TInQualifierAddress() or TInQualifierAddress() or
TInReturnValueDeref() TInReturnValueDeref()
@@ -245,15 +245,18 @@ class InParameter extends FunctionInput, TInParameter {
*/ */
class InParameterDeref extends FunctionInput, TInParameterDeref { class InParameterDeref extends FunctionInput, TInParameterDeref {
ParameterIndex index; ParameterIndex index;
int indirectionIndex;
InParameterDeref() { this = TInParameterDeref(index) } InParameterDeref() { this = TInParameterDeref(index, indirectionIndex) }
override string toString() { result = "InParameterDeref " + index.toString() } override string toString() { result = "InParameterDeref " + index.toString() }
/** Gets the zero-based index of the parameter. */ /** Gets the zero-based index of the parameter. */
ParameterIndex getIndex() { result = index } ParameterIndex getIndex() { result = index }
override predicate isParameterDeref(ParameterIndex i) { i = index } override predicate isParameterDeref(ParameterIndex i, int indirection) {
i = index and indirectionIndex = indirection
}
} }
/** /**
@@ -321,10 +324,10 @@ class InReturnValueDeref extends FunctionInput, TInReturnValueDeref {
} }
private newtype TFunctionOutput = private newtype TFunctionOutput =
TOutParameterDeref(ParameterIndex i) or TOutParameterDeref(ParameterIndex i, int indirectionIndex) { indirectionIndex = [1, 2] } or
TOutQualifierObject() or TOutQualifierObject() or
TOutReturnValue() or TOutReturnValue() or
TOutReturnValueDeref() TOutReturnValueDeref(int indirections) { indirections = [1, 2] }
/** /**
* An output from a function. This can be: * An output from a function. This can be:
@@ -498,17 +501,16 @@ class FunctionOutput extends TFunctionOutput {
*/ */
class OutParameterDeref extends FunctionOutput, TOutParameterDeref { class OutParameterDeref extends FunctionOutput, TOutParameterDeref {
ParameterIndex index; ParameterIndex index;
int indirectionIndex;
OutParameterDeref() { this = TOutParameterDeref(index) } OutParameterDeref() { this = TOutParameterDeref(index, indirectionIndex) }
override string toString() { result = "OutParameterDeref " + index.toString() } override string toString() { result = "OutParameterDeref " + index.toString() }
ParameterIndex getIndex() { result = index } ParameterIndex getIndex() { result = index }
override predicate isParameterDeref(ParameterIndex i) { i = index }
override predicate isParameterDeref(ParameterIndex i, int ind) { override predicate isParameterDeref(ParameterIndex i, int ind) {
this.isParameterDeref(i) and ind = 1 i = index and ind = indirectionIndex
} }
} }
@@ -572,4 +574,8 @@ class OutReturnValueDeref extends FunctionOutput, TOutReturnValueDeref {
override string toString() { result = "OutReturnValueDeref" } override string toString() { result = "OutReturnValueDeref" }
override predicate isReturnValueDeref() { any() } override predicate isReturnValueDeref() { any() }
override predicate isReturnValueDeref(int indirectionIndex) {
this = TOutReturnValueDeref(indirectionIndex)
}
} }

View File

@@ -17,9 +17,7 @@ private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
* `upper` is true, and can be traced back to a guard represented by `reason`. * `upper` is true, and can be traced back to a guard represented by `reason`.
*/ */
predicate bounded(Expr e, Bound b, float delta, boolean upper, Reason reason) { predicate bounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
exists(SemanticExprConfig::Expr semExpr | exists(SemanticExprConfig::Expr semExpr | semExpr.getUnconvertedResultExpression() = e |
semExpr.getUnconverted().getUnconvertedResultExpression() = e
|
semBounded(semExpr, b, delta, upper, reason) semBounded(semExpr, b, delta, upper, reason)
) )
} }
@@ -30,9 +28,7 @@ predicate bounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
* The `Expr` may be a conversion. * The `Expr` may be a conversion.
*/ */
predicate convertedBounded(Expr e, Bound b, float delta, boolean upper, Reason reason) { predicate convertedBounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
exists(SemanticExprConfig::Expr semExpr | exists(SemanticExprConfig::Expr semExpr | semExpr.getConvertedResultExpression() = e |
semExpr.getConverted().getConvertedResultExpression() = e
|
semBounded(semExpr, b, delta, upper, reason) semBounded(semExpr, b, delta, upper, reason)
) )
} }

View File

@@ -100,7 +100,7 @@ predicate exprMightOverflowNegatively(Expr expr) {
lowerBound(expr) < exprMinVal(expr) lowerBound(expr) < exprMinVal(expr)
or or
exists(SemanticExprConfig::Expr semExpr | exists(SemanticExprConfig::Expr semExpr |
semExpr.getUnconverted().getAst() = expr and semExpr.getAst() = expr and
ConstantStage::potentiallyOverflowingExpr(false, semExpr) and ConstantStage::potentiallyOverflowingExpr(false, semExpr) and
not ConstantStage::initialBounded(semExpr, _, _, false, _, _, _) not ConstantStage::initialBounded(semExpr, _, _, false, _, _, _)
) )
@@ -126,7 +126,7 @@ predicate exprMightOverflowPositively(Expr expr) {
upperBound(expr) > exprMaxVal(expr) upperBound(expr) > exprMaxVal(expr)
or or
exists(SemanticExprConfig::Expr semExpr | exists(SemanticExprConfig::Expr semExpr |
semExpr.getUnconverted().getAst() = expr and semExpr.getAst() = expr and
ConstantStage::potentiallyOverflowingExpr(true, semExpr) and ConstantStage::potentiallyOverflowingExpr(true, semExpr) and
not ConstantStage::initialBounded(semExpr, _, _, true, _, _, _) not ConstantStage::initialBounded(semExpr, _, _, true, _, _, _)
) )

View File

@@ -12,9 +12,6 @@ class SemBasicBlock extends Specific::BasicBlock {
/** Holds if this block (transitively) dominates `otherblock`. */ /** Holds if this block (transitively) dominates `otherblock`. */
final predicate bbDominates(SemBasicBlock otherBlock) { Specific::bbDominates(this, otherBlock) } final predicate bbDominates(SemBasicBlock otherBlock) { Specific::bbDominates(this, otherBlock) }
/** Holds if this block has dominance information. */
final predicate hasDominanceInformation() { Specific::hasDominanceInformation(this) }
/** Gets an expression that is evaluated in this basic block. */ /** Gets an expression that is evaluated in this basic block. */
final SemExpr getAnExpr() { result.getBasicBlock() = this } final SemExpr getAnExpr() { result.getBasicBlock() = this }

View File

@@ -4,6 +4,7 @@
private import Semantic private import Semantic
private import SemanticExprSpecific::SemanticExprConfig as Specific private import SemanticExprSpecific::SemanticExprConfig as Specific
private import SemanticType
/** /**
* An language-neutral expression. * An language-neutral expression.
@@ -241,8 +242,21 @@ class SemConvertExpr extends SemUnaryExpr {
SemConvertExpr() { opcode instanceof Opcode::Convert } SemConvertExpr() { opcode instanceof Opcode::Convert }
} }
private import semmle.code.cpp.ir.IR as IR
/** A conversion instruction which is guaranteed to not overflow. */
private class SafeConversion extends IR::ConvertInstruction {
SafeConversion() {
exists(SemType tFrom, SemType tTo |
tFrom = getSemanticType(super.getUnary().getResultIRType()) and
tTo = getSemanticType(super.getResultIRType()) and
conversionCannotOverflow(tFrom, tTo)
)
}
}
class SemCopyValueExpr extends SemUnaryExpr { class SemCopyValueExpr extends SemUnaryExpr {
SemCopyValueExpr() { opcode instanceof Opcode::CopyValue } SemCopyValueExpr() { opcode instanceof Opcode::CopyValue or this instanceof SafeConversion }
} }
class SemNegateExpr extends SemUnaryExpr { class SemNegateExpr extends SemUnaryExpr {

View File

@@ -12,87 +12,10 @@ private import semmle.code.cpp.ir.ValueNumbering
module SemanticExprConfig { module SemanticExprConfig {
class Location = Cpp::Location; class Location = Cpp::Location;
/** A `ConvertInstruction` or a `CopyValueInstruction`. */
private class Conversion extends IR::UnaryInstruction {
Conversion() {
this instanceof IR::CopyValueInstruction
or
this instanceof IR::ConvertInstruction
}
/** Holds if this instruction converts a value of type `tFrom` to a value of type `tTo`. */
predicate converts(SemType tFrom, SemType tTo) {
tFrom = getSemanticType(this.getUnary().getResultIRType()) and
tTo = getSemanticType(this.getResultIRType())
}
}
/**
* Gets a conversion-like instruction that consumes `op`, and
* which is guaranteed to not overflow.
*/
private IR::Instruction safeConversion(IR::Operand op) {
exists(Conversion conv, SemType tFrom, SemType tTo |
conv.converts(tFrom, tTo) and
conversionCannotOverflow(tFrom, tTo) and
conv.getUnaryOperand() = op and
result = conv
)
}
/** Holds if `i1 = i2` or if `i2` is a safe conversion that consumes `i1`. */
private predicate idOrSafeConversion(IR::Instruction i1, IR::Instruction i2) {
not i1.getResultIRType() instanceof IR::IRVoidType and
(
i1 = i2
or
i2 = safeConversion(i1.getAUse()) and
i1.getBlock() = i2.getBlock()
)
}
module Equiv = QlBuiltins::EquivalenceRelation<IR::Instruction, idOrSafeConversion/2>;
/** /**
* The expressions on which we perform range analysis. * The expressions on which we perform range analysis.
*/ */
class Expr extends Equiv::EquivalenceClass { class Expr = IR::Instruction;
/** Gets the n'th instruction in this equivalence class. */
private IR::Instruction getInstruction(int n) {
result =
rank[n + 1](IR::Instruction instr, int i, IR::IRBlock block |
this = Equiv::getEquivalenceClass(instr) and block.getInstruction(i) = instr
|
instr order by i
)
}
/** Gets a textual representation of this element. */
string toString() { result = this.getUnconverted().toString() }
/** Gets the basic block of this expression. */
IR::IRBlock getBlock() { result = this.getUnconverted().getBlock() }
/** Gets the unconverted instruction associated with this expression. */
IR::Instruction getUnconverted() { result = this.getInstruction(0) }
/**
* Gets the final instruction associated with this expression. This
* represents the result after applying all the safe conversions.
*/
IR::Instruction getConverted() {
exists(int n |
result = this.getInstruction(n) and
not exists(this.getInstruction(n + 1))
)
}
/** Gets the type of the result produced by this instruction. */
IR::IRType getResultIRType() { result = this.getConverted().getResultIRType() }
/** Gets the location of the source code for this expression. */
Location getLocation() { result = this.getUnconverted().getLocation() }
}
SemBasicBlock getExprBasicBlock(Expr e) { result = getSemanticBasicBlock(e.getBlock()) } SemBasicBlock getExprBasicBlock(Expr e) { result = getSemanticBasicBlock(e.getBlock()) }
@@ -139,12 +62,12 @@ module SemanticExprConfig {
predicate stringLiteral(Expr expr, SemType type, string value) { predicate stringLiteral(Expr expr, SemType type, string value) {
anyConstantExpr(expr, type, value) and anyConstantExpr(expr, type, value) and
expr.getUnconverted() instanceof IR::StringConstantInstruction expr instanceof IR::StringConstantInstruction
} }
predicate binaryExpr(Expr expr, Opcode opcode, SemType type, Expr leftOperand, Expr rightOperand) { predicate binaryExpr(Expr expr, Opcode opcode, SemType type, Expr leftOperand, Expr rightOperand) {
exists(IR::BinaryInstruction instr | exists(IR::BinaryInstruction instr |
instr = expr.getUnconverted() and instr = expr and
type = getSemanticType(instr.getResultIRType()) and type = getSemanticType(instr.getResultIRType()) and
leftOperand = getSemanticExpr(instr.getLeft()) and leftOperand = getSemanticExpr(instr.getLeft()) and
rightOperand = getSemanticExpr(instr.getRight()) and rightOperand = getSemanticExpr(instr.getRight()) and
@@ -154,14 +77,14 @@ module SemanticExprConfig {
} }
predicate unaryExpr(Expr expr, Opcode opcode, SemType type, Expr operand) { predicate unaryExpr(Expr expr, Opcode opcode, SemType type, Expr operand) {
exists(IR::UnaryInstruction instr | instr = expr.getUnconverted() | exists(IR::UnaryInstruction instr | instr = expr |
type = getSemanticType(instr.getResultIRType()) and type = getSemanticType(instr.getResultIRType()) and
operand = getSemanticExpr(instr.getUnary()) and operand = getSemanticExpr(instr.getUnary()) and
// REVIEW: Merge the two operand types. // REVIEW: Merge the two operand types.
opcode.toString() = instr.getOpcode().toString() opcode.toString() = instr.getOpcode().toString()
) )
or or
exists(IR::StoreInstruction instr | instr = expr.getUnconverted() | exists(IR::StoreInstruction instr | instr = expr |
type = getSemanticType(instr.getResultIRType()) and type = getSemanticType(instr.getResultIRType()) and
operand = getSemanticExpr(instr.getSourceValue()) and operand = getSemanticExpr(instr.getSourceValue()) and
opcode instanceof Opcode::Store opcode instanceof Opcode::Store
@@ -170,13 +93,13 @@ module SemanticExprConfig {
predicate nullaryExpr(Expr expr, Opcode opcode, SemType type) { predicate nullaryExpr(Expr expr, Opcode opcode, SemType type) {
exists(IR::LoadInstruction load | exists(IR::LoadInstruction load |
load = expr.getUnconverted() and load = expr and
type = getSemanticType(load.getResultIRType()) and type = getSemanticType(load.getResultIRType()) and
opcode instanceof Opcode::Load opcode instanceof Opcode::Load
) )
or or
exists(IR::InitializeParameterInstruction init | exists(IR::InitializeParameterInstruction init |
init = expr.getUnconverted() and init = expr and
type = getSemanticType(init.getResultIRType()) and type = getSemanticType(init.getResultIRType()) and
opcode instanceof Opcode::InitializeParameter opcode instanceof Opcode::InitializeParameter
) )
@@ -199,8 +122,6 @@ module SemanticExprConfig {
dominator.dominates(dominated) dominator.dominates(dominated)
} }
predicate hasDominanceInformation(BasicBlock block) { any() }
private predicate id(Cpp::Locatable x, Cpp::Locatable y) { x = y } private predicate id(Cpp::Locatable x, Cpp::Locatable y) { x = y }
private predicate idOf(Cpp::Locatable x, int y) = equivalenceRelation(id/2)(x, y) private predicate idOf(Cpp::Locatable x, int y) = equivalenceRelation(id/2)(x, y)
@@ -209,17 +130,7 @@ module SemanticExprConfig {
newtype TSsaVariable = newtype TSsaVariable =
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() } or TSsaOperand(IR::PhiInputOperand op) { op.isDefinitionInexact() }
TSsaPointerArithmeticGuard(ValueNumber instr) {
exists(Guard g, IR::Operand use |
use = instr.getAUse() and use.getIRType() instanceof IR::IRAddressType
|
g.comparesLt(use, _, _, _, _) or
g.comparesLt(_, use, _, _, _) or
g.comparesEq(use, _, _, _, _) or
g.comparesEq(_, use, _, _, _)
)
}
class SsaVariable extends TSsaVariable { class SsaVariable extends TSsaVariable {
string toString() { none() } string toString() { none() }
@@ -228,9 +139,7 @@ module SemanticExprConfig {
IR::Instruction asInstruction() { none() } IR::Instruction asInstruction() { none() }
ValueNumber asPointerArithGuard() { none() } IR::PhiInputOperand asOperand() { none() }
IR::Operand asOperand() { none() }
} }
class SsaInstructionVariable extends SsaVariable, TSsaInstruction { class SsaInstructionVariable extends SsaVariable, TSsaInstruction {
@@ -245,20 +154,8 @@ module SemanticExprConfig {
final override IR::Instruction asInstruction() { result = instr } final override IR::Instruction asInstruction() { result = instr }
} }
class SsaPointerArithmeticGuard extends SsaVariable, TSsaPointerArithmeticGuard {
ValueNumber vn;
SsaPointerArithmeticGuard() { this = TSsaPointerArithmeticGuard(vn) }
final override string toString() { result = vn.toString() }
final override Location getLocation() { result = vn.getLocation() }
final override ValueNumber asPointerArithGuard() { result = vn }
}
class SsaOperand extends SsaVariable, TSsaOperand { class SsaOperand extends SsaVariable, TSsaOperand {
IR::Operand op; IR::PhiInputOperand op;
SsaOperand() { this = TSsaOperand(op) } SsaOperand() { this = TSsaOperand(op) }
@@ -266,7 +163,7 @@ module SemanticExprConfig {
final override Location getLocation() { result = op.getLocation() } final override Location getLocation() { result = op.getLocation() }
final override IR::Operand asOperand() { result = op } final override IR::PhiInputOperand asOperand() { result = op }
} }
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) { predicate explicitUpdate(SsaVariable v, Expr sourceExpr) {
@@ -289,97 +186,29 @@ module SemanticExprConfig {
) )
} }
Expr getAUse(SsaVariable v) { Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
result.getUnconverted().(IR::LoadInstruction).getSourceValue() = v.asInstruction()
or
result.getUnconverted() = v.asPointerArithGuard().getAnInstruction()
}
SemType getSsaVariableType(SsaVariable v) { SemType getSsaVariableType(SsaVariable v) {
result = getSemanticType(v.asInstruction().getResultIRType()) result = getSemanticType(v.asInstruction().getResultIRType())
or
result = getSemanticType(v.asOperand().getUse().getResultIRType())
} }
BasicBlock getSsaVariableBasicBlock(SsaVariable v) { BasicBlock getSsaVariableBasicBlock(SsaVariable v) {
result = v.asInstruction().getBlock() result = v.asInstruction().getBlock()
or or
result = v.asOperand().getUse().getBlock() result = v.asOperand().getAnyDef().getBlock()
} }
private newtype TReadPosition = /** Holds if `inp` is an input to the phi node along the edge originating in `bb`. */
TReadPositionBlock(IR::IRBlock block) or predicate phiInputFromBlock(SsaVariable phi, SsaVariable inp, BasicBlock bb) {
TReadPositionPhiInputEdge(IR::IRBlock pred, IR::IRBlock succ) {
exists(IR::PhiInputOperand input |
pred = input.getPredecessorBlock() and
succ = input.getUse().getBlock()
)
}
class SsaReadPosition extends TReadPosition {
string toString() { none() }
Location getLocation() { none() }
predicate hasRead(SsaVariable v) { none() }
}
private class SsaReadPositionBlock extends SsaReadPosition, TReadPositionBlock {
IR::IRBlock block;
SsaReadPositionBlock() { this = TReadPositionBlock(block) }
final override string toString() { result = block.toString() }
final override Location getLocation() { result = block.getLocation() }
final override predicate hasRead(SsaVariable v) {
exists(IR::Operand operand |
operand.getDef() = v.asInstruction() or
operand.getDef() = v.asPointerArithGuard().getAnInstruction()
|
not operand instanceof IR::PhiInputOperand and
operand.getUse().getBlock() = block
)
}
}
private class SsaReadPositionPhiInputEdge extends SsaReadPosition, TReadPositionPhiInputEdge {
IR::IRBlock pred;
IR::IRBlock succ;
SsaReadPositionPhiInputEdge() { this = TReadPositionPhiInputEdge(pred, succ) }
final override string toString() { result = pred.toString() + "->" + succ.toString() }
final override Location getLocation() { result = succ.getLocation() }
final override predicate hasRead(SsaVariable v) {
exists(IR::PhiInputOperand operand |
operand.getDef() = v.asInstruction() or
operand.getDef() = v.asPointerArithGuard().getAnInstruction()
|
operand.getPredecessorBlock() = pred and
operand.getUse().getBlock() = succ
)
}
}
predicate hasReadOfSsaVariable(SsaReadPosition pos, SsaVariable v) { pos.hasRead(v) }
predicate readBlock(SsaReadPosition pos, BasicBlock block) { pos = TReadPositionBlock(block) }
predicate phiInputEdge(SsaReadPosition pos, BasicBlock origBlock, BasicBlock phiBlock) {
pos = TReadPositionPhiInputEdge(origBlock, phiBlock)
}
predicate phiInput(SsaReadPosition pos, SsaVariable phi, SsaVariable input) {
exists(IR::PhiInputOperand operand | exists(IR::PhiInputOperand operand |
pos = TReadPositionPhiInputEdge(operand.getPredecessorBlock(), operand.getUse().getBlock()) bb = operand.getPredecessorBlock() and
|
phi.asInstruction() = operand.getUse() and phi.asInstruction() = operand.getUse() and
( (
input.asInstruction() = operand.getDef() inp.asInstruction() = operand.getDef()
or or
input.asOperand() = operand inp.asOperand() = operand
) )
) )
} }
@@ -433,7 +262,7 @@ module SemanticExprConfig {
} }
/** Gets the expression associated with `instr`. */ /** Gets the expression associated with `instr`. */
SemExpr getSemanticExpr(IR::Instruction instr) { result = Equiv::getEquivalenceClass(instr) } SemExpr getSemanticExpr(IR::Instruction instr) { result = instr }
} }
predicate getSemanticExpr = SemanticExprConfig::getSemanticExpr/1; predicate getSemanticExpr = SemanticExprConfig::getSemanticExpr/1;

View File

@@ -35,32 +35,4 @@ predicate semImplies_v2(SemGuard g1, boolean b1, SemGuard g2, boolean b2) {
Specific::implies_v2(g1, b1, g2, b2) Specific::implies_v2(g1, b1, g2, b2)
} }
/**
* Holds if `guard` directly controls the position `controlled` with the
* value `testIsTrue`.
*/
pragma[nomagic]
predicate semGuardDirectlyControlsSsaRead(
SemGuard guard, SemSsaReadPosition controlled, boolean testIsTrue
) {
guard.directlyControls(controlled.(SemSsaReadPositionBlock).getBlock(), testIsTrue)
or
exists(SemSsaReadPositionPhiInputEdge controlledEdge | controlledEdge = controlled |
guard.directlyControls(controlledEdge.getOrigBlock(), testIsTrue) or
guard.hasBranchEdge(controlledEdge.getOrigBlock(), controlledEdge.getPhiBlock(), testIsTrue)
)
}
/**
* Holds if `guard` controls the position `controlled` with the value `testIsTrue`.
*/
predicate semGuardControlsSsaRead(SemGuard guard, SemSsaReadPosition controlled, boolean testIsTrue) {
semGuardDirectlyControlsSsaRead(guard, controlled, testIsTrue)
or
exists(SemGuard guard0, boolean testIsTrue0 |
semImplies_v2(guard0, testIsTrue0, guard, testIsTrue) and
semGuardControlsSsaRead(guard0, controlled, testIsTrue0)
)
}
SemGuard semGetComparisonGuard(SemRelationalExpr e) { result = Specific::comparisonGuard(e) } SemGuard semGetComparisonGuard(SemRelationalExpr e) { result = Specific::comparisonGuard(e) }

View File

@@ -22,8 +22,6 @@ class SemSsaExplicitUpdate extends SemSsaVariable {
SemSsaExplicitUpdate() { Specific::explicitUpdate(this, sourceExpr) } SemSsaExplicitUpdate() { Specific::explicitUpdate(this, sourceExpr) }
final SemExpr getSourceExpr() { result = sourceExpr }
final SemExpr getDefiningExpr() { result = sourceExpr } final SemExpr getDefiningExpr() { result = sourceExpr }
} }
@@ -31,68 +29,8 @@ class SemSsaPhiNode extends SemSsaVariable {
SemSsaPhiNode() { Specific::phi(this) } SemSsaPhiNode() { Specific::phi(this) }
final SemSsaVariable getAPhiInput() { result = Specific::getAPhiInput(this) } final SemSsaVariable getAPhiInput() { result = Specific::getAPhiInput(this) }
}
final predicate hasInputFromBlock(SemSsaVariable inp, SemBasicBlock bb) {
class SemSsaReadPosition instanceof Specific::SsaReadPosition { Specific::phiInputFromBlock(this, inp, bb)
final string toString() { result = super.toString() } }
final Specific::Location getLocation() { result = super.getLocation() }
final predicate hasReadOfVar(SemSsaVariable var) { Specific::hasReadOfSsaVariable(this, var) }
}
class SemSsaReadPositionPhiInputEdge extends SemSsaReadPosition {
SemBasicBlock origBlock;
SemBasicBlock phiBlock;
SemSsaReadPositionPhiInputEdge() { Specific::phiInputEdge(this, origBlock, phiBlock) }
predicate phiInput(SemSsaPhiNode phi, SemSsaVariable inp) { Specific::phiInput(this, phi, inp) }
SemBasicBlock getOrigBlock() { result = origBlock }
SemBasicBlock getPhiBlock() { result = phiBlock }
}
class SemSsaReadPositionBlock extends SemSsaReadPosition {
SemBasicBlock block;
SemSsaReadPositionBlock() { Specific::readBlock(this, block) }
SemBasicBlock getBlock() { result = block }
SemExpr getAnExpr() { result = this.getBlock().getAnExpr() }
}
/**
* Holds if `inp` is an input to `phi` along a back edge.
*/
predicate semBackEdge(SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge) {
edge.phiInput(phi, inp) and
// Conservatively assume that every edge is a back edge if we don't have dominance information.
(
phi.getBasicBlock().bbDominates(edge.getOrigBlock()) or
irreducibleSccEdge(edge.getOrigBlock(), phi.getBasicBlock()) or
not edge.getOrigBlock().hasDominanceInformation()
)
}
/**
* Holds if the edge from b1 to b2 is part of a multiple-entry cycle in an irreducible control flow
* graph.
*
* An ireducible control flow graph is one where the usual dominance-based back edge detection does
* not work, because there is a cycle with multiple entry points, meaning there are
* mutually-reachable basic blocks where neither dominates the other. For such a graph, we first
* remove all detectable back-edges using the normal condition that the predecessor block is
* dominated by the successor block, then mark all edges in a cycle in the resulting graph as back
* edges.
*/
private predicate irreducibleSccEdge(SemBasicBlock b1, SemBasicBlock b2) {
trimmedEdge(b1, b2) and trimmedEdge+(b2, b1)
}
private predicate trimmedEdge(SemBasicBlock pred, SemBasicBlock succ) {
pred.getASuccessor() = succ and
not succ.bbDominates(pred)
} }

View File

@@ -14,7 +14,7 @@ private predicate constantIntegerExpr(SemExpr e, int val) {
// Copy of another constant // Copy of another constant
exists(SemSsaExplicitUpdate v, SemExpr src | exists(SemSsaExplicitUpdate v, SemExpr src |
e = v.getAUse() and e = v.getAUse() and
src = v.getSourceExpr() and src = v.getDefiningExpr() and
constantIntegerExpr(src, val) constantIntegerExpr(src, val)
) )
or or

View File

@@ -22,30 +22,7 @@ module CppLangImplConstant implements LangSig<Sem, FloatDelta> {
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() } predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
/** /**
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`). * Holds if `e2 >= e1 + delta` (if `upper = false`) or `e2 <= e1 + delta` (if `upper = true`).
*/ */
predicate hasBound(SemExpr e, SemExpr bound, float delta, boolean upper) { none() } predicate additionalBoundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) { none() }
/**
* Holds if the value of `dest` is known to be `src + delta`.
*/
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, float delta) { none() }
/**
* Gets the type that range analysis should use to track the result of the specified expression,
* if a type other than the original type of the expression is to be used.
*
* This predicate is commonly used in languages that support immutable "boxed" types that are
* actually references but whose values can be tracked as the type contained in the box.
*/
SemType getAlternateType(SemExpr e) { none() }
/**
* Gets the type that range analysis should use to track the result of the specified source
* variable, if a type other than the original type of the expression is to be used.
*
* This predicate is commonly used in languages that support immutable "boxed" types that are
* actually references but whose values can be tracked as the type contained in the box.
*/
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
} }

View File

@@ -1,7 +1,6 @@
private import RangeAnalysisConstantSpecific private import RangeAnalysisConstantSpecific
private import RangeAnalysisRelativeSpecific private import RangeAnalysisRelativeSpecific
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
private import RangeUtils
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExpr private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExpr
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticCFG private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticCFG
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticGuard private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticGuard
@@ -72,14 +71,14 @@ module Sem implements Semantic {
class BasicBlock = SemBasicBlock; class BasicBlock = SemBasicBlock;
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
int getBlockId1(BasicBlock bb) { result = bb.getUniqueId() }
class Guard = SemGuard; class Guard = SemGuard;
predicate implies_v2 = semImplies_v2/4; predicate implies_v2 = semImplies_v2/4;
predicate guardDirectlyControlsSsaRead = semGuardDirectlyControlsSsaRead/3;
predicate guardControlsSsaRead = semGuardControlsSsaRead/3;
class Type = SemType; class Type = SemType;
class IntegerType = SemIntegerType; class IntegerType = SemIntegerType;
@@ -88,19 +87,17 @@ module Sem implements Semantic {
class AddressType = SemAddressType; class AddressType = SemAddressType;
SemType getExprType(SemExpr e) { result = e.getSemType() }
SemType getSsaType(SemSsaVariable var) { result = var.getType() }
class SsaVariable = SemSsaVariable; class SsaVariable = SemSsaVariable;
class SsaPhiNode = SemSsaPhiNode; class SsaPhiNode = SemSsaPhiNode;
class SsaExplicitUpdate = SemSsaExplicitUpdate; class SsaExplicitUpdate = SemSsaExplicitUpdate;
class SsaReadPosition = SemSsaReadPosition; predicate additionalValueFlowStep(SemExpr dest, SemExpr src, int delta) { none() }
class SsaReadPositionPhiInputEdge = SemSsaReadPositionPhiInputEdge;
class SsaReadPositionBlock = SemSsaReadPositionBlock;
predicate backEdge = semBackEdge/3;
predicate conversionCannotOverflow(Type fromType, Type toType) { predicate conversionCannotOverflow(Type fromType, Type toType) {
SemanticType::conversionCannotOverflow(fromType, toType) SemanticType::conversionCannotOverflow(fromType, toType)
@@ -109,7 +106,7 @@ module Sem implements Semantic {
module SignAnalysis implements SignAnalysisSig<Sem> { module SignAnalysis implements SignAnalysisSig<Sem> {
private import SignAnalysisCommon as SA private import SignAnalysisCommon as SA
import SA::SignAnalysis<FloatDelta, Util> import SA::SignAnalysis<FloatDelta>
} }
module ConstantBounds implements BoundSig<SemLocation, Sem, FloatDelta> { module ConstantBounds implements BoundSig<SemLocation, Sem, FloatDelta> {
@@ -172,18 +169,16 @@ private module ModulusAnalysisInstantiated implements ModulusAnalysisSig<Sem> {
class ModBound = AllBounds::SemBound; class ModBound = AllBounds::SemBound;
private import codeql.rangeanalysis.ModulusAnalysis as MA private import codeql.rangeanalysis.ModulusAnalysis as MA
import MA::ModulusAnalysis<SemLocation, Sem, FloatDelta, AllBounds, Util> import MA::ModulusAnalysis<SemLocation, Sem, FloatDelta, AllBounds>
} }
module Util = RangeUtil<FloatDelta, CppLangImplConstant>;
module ConstantStage = module ConstantStage =
RangeStage<SemLocation, Sem, FloatDelta, ConstantBounds, FloatOverflow, CppLangImplConstant, RangeStage<SemLocation, Sem, FloatDelta, ConstantBounds, FloatOverflow, CppLangImplConstant,
SignAnalysis, ModulusAnalysisInstantiated, Util>; SignAnalysis, ModulusAnalysisInstantiated>;
module RelativeStage = module RelativeStage =
RangeStage<SemLocation, Sem, FloatDelta, RelativeBounds, FloatOverflow, CppLangImplRelative, RangeStage<SemLocation, Sem, FloatDelta, RelativeBounds, FloatOverflow, CppLangImplRelative,
SignAnalysis, ModulusAnalysisInstantiated, Util>; SignAnalysis, ModulusAnalysisInstantiated>;
private newtype TSemReason = private newtype TSemReason =
TSemNoReason() or TSemNoReason() or

View File

@@ -54,30 +54,7 @@ module CppLangImplRelative implements LangSig<Sem, FloatDelta> {
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() } predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
/** /**
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`). * Holds if `e2 >= e1 + delta` (if `upper = false`) or `e2 <= e1 + delta` (if `upper = true`).
*/ */
predicate hasBound(SemExpr e, SemExpr bound, float delta, boolean upper) { none() } predicate additionalBoundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) { none() }
/**
* Holds if the value of `dest` is known to be `src + delta`.
*/
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, float delta) { none() }
/**
* Gets the type that range analysis should use to track the result of the specified expression,
* if a type other than the original type of the expression is to be used.
*
* This predicate is commonly used in languages that support immutable "boxed" types that are
* actually references but whose values can be tracked as the type contained in the box.
*/
SemType getAlternateType(SemExpr e) { none() }
/**
* Gets the type that range analysis should use to track the result of the specified source
* variable, if a type other than the original type of the expression is to be used.
*
* This predicate is commonly used in languages that support immutable "boxed" types that are
* actually references but whose values can be tracked as the type contained in the box.
*/
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
} }

View File

@@ -1,165 +0,0 @@
/**
* Provides utility predicates for range analysis.
*/
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
private import RangeAnalysisRelativeSpecific
private import codeql.rangeanalysis.RangeAnalysis
private import RangeAnalysisImpl
private import ConstantAnalysis
module RangeUtil<DeltaSig D, LangSig<Sem, D> Lang> implements UtilSig<Sem, D> {
/**
* Gets an expression that equals `v - d`.
*/
private SemExpr semSsaRead(SemSsaVariable v, D::Delta delta) {
// There are various language-specific extension points that can be removed once we no longer
// expect to match the original Java implementation's results exactly.
result = v.getAUse() and delta = D::fromInt(0)
or
exists(D::Delta d1, SemConstantIntegerExpr c |
result.(SemAddExpr).hasOperands(semSsaRead(v, d1), c) and
delta = D::fromFloat(D::toFloat(d1) - c.getIntValue())
)
or
exists(SemSubExpr sub, D::Delta d1, SemConstantIntegerExpr c |
result = sub and
sub.getLeftOperand() = semSsaRead(v, d1) and
sub.getRightOperand() = c and
delta = D::fromFloat(D::toFloat(d1) + c.getIntValue())
)
or
result = v.(SemSsaExplicitUpdate).getSourceExpr() and
delta = D::fromFloat(0)
or
result.(SemCopyValueExpr).getOperand() = semSsaRead(v, delta)
or
result.(SemStoreExpr).getOperand() = semSsaRead(v, delta)
}
/**
* Gets a condition that tests whether `v` equals `e + delta`.
*
* If the condition evaluates to `testIsTrue`:
* - `isEq = true` : `v == e + delta`
* - `isEq = false` : `v != e + delta`
*/
pragma[nomagic]
SemGuard semEqFlowCond(
SemSsaVariable v, SemExpr e, D::Delta delta, boolean isEq, boolean testIsTrue
) {
exists(boolean eqpolarity |
result.isEquality(semSsaRead(v, delta), e, eqpolarity) and
(testIsTrue = true or testIsTrue = false) and
eqpolarity.booleanXor(testIsTrue).booleanNot() = isEq
)
or
exists(boolean testIsTrue0 |
semImplies_v2(result, testIsTrue, semEqFlowCond(v, e, delta, isEq, testIsTrue0), testIsTrue0)
)
}
/**
* Holds if `v` is an `SsaExplicitUpdate` that equals `e + delta`.
*/
predicate semSsaUpdateStep(SemSsaExplicitUpdate v, SemExpr e, D::Delta delta) {
exists(SemExpr defExpr | defExpr = v.getSourceExpr() |
defExpr.(SemCopyValueExpr).getOperand() = e and delta = D::fromFloat(0)
or
defExpr.(SemStoreExpr).getOperand() = e and delta = D::fromFloat(0)
or
defExpr.(SemAddOneExpr).getOperand() = e and delta = D::fromFloat(1)
or
defExpr.(SemSubOneExpr).getOperand() = e and delta = D::fromFloat(-1)
or
e = defExpr and
not (
defExpr instanceof SemCopyValueExpr or
defExpr instanceof SemStoreExpr or
defExpr instanceof SemAddOneExpr or
defExpr instanceof SemSubOneExpr
) and
delta = D::fromFloat(0)
)
}
/**
* Holds if `e1 + delta` equals `e2`.
*/
predicate semValueFlowStep(SemExpr e2, SemExpr e1, D::Delta delta) {
e2.(SemCopyValueExpr).getOperand() = e1 and delta = D::fromFloat(0)
or
e2.(SemStoreExpr).getOperand() = e1 and delta = D::fromFloat(0)
or
e2.(SemAddOneExpr).getOperand() = e1 and delta = D::fromFloat(1)
or
e2.(SemSubOneExpr).getOperand() = e1 and delta = D::fromFloat(-1)
or
Lang::additionalValueFlowStep(e2, e1, delta)
or
exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
D::fromInt(x.(SemConstantIntegerExpr).getIntValue()) = delta
)
or
exists(SemExpr x, SemSubExpr sub |
e2 = sub and
sub.getLeftOperand() = e1 and
sub.getRightOperand() = x
|
D::fromInt(-x.(SemConstantIntegerExpr).getIntValue()) = delta
)
}
/**
* Gets the type used to track the specified expression's range information.
*
* Usually, this just `e.getSemType()`, but the language can override this to track immutable boxed
* primitive types as the underlying primitive type.
*/
SemType getTrackedType(SemExpr e) {
result = Lang::getAlternateType(e)
or
not exists(Lang::getAlternateType(e)) and result = e.getSemType()
}
/**
* Gets the type used to track the specified source variable's range information.
*
* Usually, this just `e.getType()`, but the language can override this to track immutable boxed
* primitive types as the underlying primitive type.
*/
SemType getTrackedTypeForSsaVariable(SemSsaVariable var) {
result = Lang::getAlternateTypeForSsaVariable(var)
or
not exists(Lang::getAlternateTypeForSsaVariable(var)) and result = var.getType()
}
import Ranking
}
import Ranking
module Ranking {
/**
* Holds if `rix` is the number of input edges to `phi`.
*/
predicate maxPhiInputRank(SemSsaPhiNode phi, int rix) {
rix = max(int r | rankedPhiInput(phi, _, _, r))
}
/**
* Holds if `inp` is an input to `phi` along `edge` and this input has index `r`
* in an arbitrary 1-based numbering of the input edges to `phi`.
*/
predicate rankedPhiInput(
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int r
) {
edge.phiInput(phi, inp) and
edge =
rank[r](SemSsaReadPositionPhiInputEdge e |
e.phiInput(phi, _)
|
e order by e.getOrigBlock().getUniqueId()
)
}
}

View File

@@ -11,10 +11,9 @@ private import RangeAnalysisImpl
private import SignAnalysisSpecific as Specific private import SignAnalysisSpecific as Specific
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
private import ConstantAnalysis private import ConstantAnalysis
private import RangeUtils
private import Sign private import Sign
module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> { module SignAnalysis<DeltaSig D> {
private import codeql.rangeanalysis.internal.RangeUtils::MakeUtils<Sem, D> private import codeql.rangeanalysis.internal.RangeUtils::MakeUtils<Sem, D>
/** /**
@@ -39,13 +38,13 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
/** An SSA definition whose sign is determined by the sign of that definitions source expression. */ /** An SSA definition whose sign is determined by the sign of that definitions source expression. */
private class ExplicitSignDef extends FlowSignDef instanceof SemSsaExplicitUpdate { private class ExplicitSignDef extends FlowSignDef instanceof SemSsaExplicitUpdate {
final override Sign getSign() { result = semExprSign(super.getSourceExpr()) } final override Sign getSign() { result = semExprSign(super.getDefiningExpr()) }
} }
/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */ /** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode { private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode {
final override Sign getSign() { final override Sign getSign() {
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge | exists(SemSsaVariable inp, SsaReadPositionPhiInputEdge edge |
edge.phiInput(this, inp) and edge.phiInput(this, inp) and
result = semSsaSign(inp, edge) result = semSsaSign(inp, edge)
) )
@@ -148,7 +147,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
not this instanceof ConstantSignExpr and not this instanceof ConstantSignExpr and
( (
// Only track numeric types. // Only track numeric types.
Utils::getTrackedType(this) instanceof SemNumericType Sem::getExprType(this) instanceof SemNumericType
or or
// Unless the language says to track this expression anyway. // Unless the language says to track this expression anyway.
Specific::trackUnknownNonNumericExpr(this) Specific::trackUnknownNonNumericExpr(this)
@@ -170,11 +169,11 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
override Sign getSignRestriction() { override Sign getSignRestriction() {
// Propagate via SSA // Propagate via SSA
// Propagate the sign from the def of `v`, incorporating any inference from guards. // Propagate the sign from the def of `v`, incorporating any inference from guards.
result = semSsaSign(v, any(SemSsaReadPositionBlock bb | bb.getAnExpr() = this)) result = semSsaSign(v, any(SsaReadPositionBlock bb | bb.getBlock().getAnExpr() = this))
or or
// No block for this read. Just use the sign of the def. // No block for this read. Just use the sign of the def.
// REVIEW: How can this happen? // REVIEW: How can this happen?
not exists(SemSsaReadPositionBlock bb | bb.getAnExpr() = this) and not exists(SsaReadPositionBlock bb | bb.getBlock().getAnExpr() = this) and
result = semSsaDefSign(v) result = semSsaDefSign(v)
} }
} }
@@ -203,7 +202,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
/** An expression of an unsigned type. */ /** An expression of an unsigned type. */
private class UnsignedExpr extends FlowSignExpr { private class UnsignedExpr extends FlowSignExpr {
UnsignedExpr() { Utils::getTrackedType(this) instanceof SemUnsignedIntegerType } UnsignedExpr() { Sem::getExprType(this) instanceof SemUnsignedIntegerType }
override Sign getSignRestriction() { override Sign getSignRestriction() {
result = TPos() or result = TPos() or
@@ -276,7 +275,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
override SemUnboxExpr cast; override SemUnboxExpr cast;
UnboxSignExpr() { UnboxSignExpr() {
exists(SemType fromType | fromType = Utils::getTrackedType(cast.getOperand()) | exists(SemType fromType | fromType = Sem::getExprType(cast.getOperand()) |
// Only numeric source types are handled here. // Only numeric source types are handled here.
fromType instanceof SemNumericType fromType instanceof SemNumericType
) )
@@ -290,11 +289,11 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
* to only include bounds for which we might determine a sign. * to only include bounds for which we might determine a sign.
*/ */
private predicate lowerBound( private predicate lowerBound(
SemExpr lowerbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict SemExpr lowerbound, SemSsaVariable v, SsaReadPosition pos, boolean isStrict
) { ) {
exists(boolean testIsTrue, SemRelationalExpr comp | exists(boolean testIsTrue, SemRelationalExpr comp |
pos.hasReadOfVar(v) and pos.hasReadOfVar(v) and
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and guardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
not unknownSign(lowerbound) not unknownSign(lowerbound)
| |
testIsTrue = true and testIsTrue = true and
@@ -314,11 +313,11 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
* to only include bounds for which we might determine a sign. * to only include bounds for which we might determine a sign.
*/ */
private predicate upperBound( private predicate upperBound(
SemExpr upperbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict SemExpr upperbound, SemSsaVariable v, SsaReadPosition pos, boolean isStrict
) { ) {
exists(boolean testIsTrue, SemRelationalExpr comp | exists(boolean testIsTrue, SemRelationalExpr comp |
pos.hasReadOfVar(v) and pos.hasReadOfVar(v) and
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and guardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
not unknownSign(upperbound) not unknownSign(upperbound)
| |
testIsTrue = true and testIsTrue = true and
@@ -340,10 +339,10 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
* - `isEq = true` : `v = eqbound` * - `isEq = true` : `v = eqbound`
* - `isEq = false` : `v != eqbound` * - `isEq = false` : `v != eqbound`
*/ */
private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isEq) { private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SsaReadPosition pos, boolean isEq) {
exists(SemGuard guard, boolean testIsTrue, boolean polarity, SemExpr e | exists(SemGuard guard, boolean testIsTrue, boolean polarity, SemExpr e |
pos.hasReadOfVar(pragma[only_bind_into](v)) and pos.hasReadOfVar(pragma[only_bind_into](v)) and
semGuardControlsSsaRead(guard, pragma[only_bind_into](pos), testIsTrue) and guardControlsSsaRead(guard, pragma[only_bind_into](pos), testIsTrue) and
e = ssaRead(pragma[only_bind_into](v), D::fromInt(0)) and e = ssaRead(pragma[only_bind_into](v), D::fromInt(0)) and
guard.isEquality(eqbound, e, polarity) and guard.isEquality(eqbound, e, polarity) and
isEq = polarity.booleanXor(testIsTrue).booleanNot() and isEq = polarity.booleanXor(testIsTrue).booleanNot() and
@@ -355,7 +354,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
* Holds if `bound` is a bound for `v` at `pos` that needs to be positive in * Holds if `bound` is a bound for `v` at `pos` that needs to be positive in
* order for `v` to be positive. * order for `v` to be positive.
*/ */
private predicate posBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) { private predicate posBound(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
upperBound(bound, v, pos, _) or upperBound(bound, v, pos, _) or
eqBound(bound, v, pos, true) eqBound(bound, v, pos, true)
} }
@@ -364,7 +363,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
* Holds if `bound` is a bound for `v` at `pos` that needs to be negative in * Holds if `bound` is a bound for `v` at `pos` that needs to be negative in
* order for `v` to be negative. * order for `v` to be negative.
*/ */
private predicate negBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) { private predicate negBound(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
lowerBound(bound, v, pos, _) or lowerBound(bound, v, pos, _) or
eqBound(bound, v, pos, true) eqBound(bound, v, pos, true)
} }
@@ -373,24 +372,24 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
* Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v` * Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v`
* can be zero. * can be zero.
*/ */
private predicate zeroBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) { private predicate zeroBound(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
lowerBound(bound, v, pos, _) or lowerBound(bound, v, pos, _) or
upperBound(bound, v, pos, _) or upperBound(bound, v, pos, _) or
eqBound(bound, v, pos, _) eqBound(bound, v, pos, _)
} }
/** Holds if `bound` allows `v` to be positive at `pos`. */ /** Holds if `bound` allows `v` to be positive at `pos`. */
private predicate posBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) { private predicate posBoundOk(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
posBound(bound, v, pos) and TPos() = semExprSign(bound) posBound(bound, v, pos) and TPos() = semExprSign(bound)
} }
/** Holds if `bound` allows `v` to be negative at `pos`. */ /** Holds if `bound` allows `v` to be negative at `pos`. */
private predicate negBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) { private predicate negBoundOk(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
negBound(bound, v, pos) and TNeg() = semExprSign(bound) negBound(bound, v, pos) and TNeg() = semExprSign(bound)
} }
/** Holds if `bound` allows `v` to be zero at `pos`. */ /** Holds if `bound` allows `v` to be zero at `pos`. */
private predicate zeroBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) { private predicate zeroBoundOk(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
lowerBound(bound, v, pos, _) and TNeg() = semExprSign(bound) lowerBound(bound, v, pos, _) and TNeg() = semExprSign(bound)
or or
lowerBound(bound, v, pos, false) and TZero() = semExprSign(bound) lowerBound(bound, v, pos, false) and TZero() = semExprSign(bound)
@@ -408,7 +407,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
* Holds if there is a bound that might restrict whether `v` has the sign `s` * Holds if there is a bound that might restrict whether `v` has the sign `s`
* at `pos`. * at `pos`.
*/ */
private predicate hasGuard(SemSsaVariable v, SemSsaReadPosition pos, Sign s) { private predicate hasGuard(SemSsaVariable v, SsaReadPosition pos, Sign s) {
s = TPos() and posBound(_, v, pos) s = TPos() and posBound(_, v, pos)
or or
s = TNeg() and negBound(_, v, pos) s = TNeg() and negBound(_, v, pos)
@@ -421,7 +420,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
* might be ruled out by a guard. * might be ruled out by a guard.
*/ */
pragma[noinline] pragma[noinline]
private Sign guardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) { private Sign guardedSsaSign(SemSsaVariable v, SsaReadPosition pos) {
result = semSsaDefSign(v) and result = semSsaDefSign(v) and
pos.hasReadOfVar(v) and pos.hasReadOfVar(v) and
hasGuard(v, pos, result) hasGuard(v, pos, result)
@@ -432,7 +431,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
* can rule it out. * can rule it out.
*/ */
pragma[noinline] pragma[noinline]
private Sign unguardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) { private Sign unguardedSsaSign(SemSsaVariable v, SsaReadPosition pos) {
result = semSsaDefSign(v) and result = semSsaDefSign(v) and
pos.hasReadOfVar(v) and pos.hasReadOfVar(v) and
not hasGuard(v, pos, result) not hasGuard(v, pos, result)
@@ -443,7 +442,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
* ruled out the sign but does not. * ruled out the sign but does not.
* This does not check that the definition of `v` also allows the sign. * This does not check that the definition of `v` also allows the sign.
*/ */
private Sign guardedSsaSignOk(SemSsaVariable v, SemSsaReadPosition pos) { private Sign guardedSsaSignOk(SemSsaVariable v, SsaReadPosition pos) {
result = TPos() and result = TPos() and
forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos)) forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos))
or or
@@ -455,7 +454,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
} }
/** Gets a possible sign for `v` at `pos`. */ /** Gets a possible sign for `v` at `pos`. */
private Sign semSsaSign(SemSsaVariable v, SemSsaReadPosition pos) { private Sign semSsaSign(SemSsaVariable v, SsaReadPosition pos) {
result = unguardedSsaSign(v, pos) result = unguardedSsaSign(v, pos)
or or
result = guardedSsaSign(v, pos) and result = guardedSsaSign(v, pos) and
@@ -471,7 +470,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
Sign semExprSign(SemExpr e) { Sign semExprSign(SemExpr e) {
exists(Sign s | s = e.(SignExpr).getSign() | exists(Sign s | s = e.(SignExpr).getSign() |
if if
Utils::getTrackedType(e) instanceof SemUnsignedIntegerType and Sem::getExprType(e) instanceof SemUnsignedIntegerType and
s = TNeg() and s = TNeg() and
not Specific::ignoreTypeRestrictions(e) not Specific::ignoreTypeRestrictions(e)
then result = TPos() then result = TPos()

View File

@@ -1,3 +1,9 @@
## 0.8.3
### Minor Analysis Improvements
* The `cpp/uninitialized-local` query has been improved to produce fewer false positives.
## 0.8.2 ## 0.8.2
No user-facing changes. No user-facing changes.

View File

@@ -27,16 +27,26 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
ReturnStackAllocatedMemoryConfig() { this = "ReturnStackAllocatedMemoryConfig" } ReturnStackAllocatedMemoryConfig() { this = "ReturnStackAllocatedMemoryConfig" }
override predicate isSource(Instruction source) { override predicate isSource(Instruction source) {
// Holds if `source` is a node that represents the use of a stack variable exists(Function func |
exists(VariableAddressInstruction var, Function func |
var = source and
func = source.getEnclosingFunction() and
var.getAstVariable() instanceof StackVariable and
// Pointer-to-member types aren't properly handled in the dbscheme.
not var.getResultType() instanceof PointerToMemberType and
// Rule out FPs caused by extraction errors. // Rule out FPs caused by extraction errors.
not any(ErrorExpr e).getEnclosingFunction() = func and not any(ErrorExpr e).getEnclosingFunction() = func and
not intentionallyReturnsStackPointer(func) not intentionallyReturnsStackPointer(func) and
func = source.getEnclosingFunction()
|
// `source` is an instruction that represents the use of a stack variable
exists(VariableAddressInstruction var |
var = source and
var.getAstVariable() instanceof StackVariable and
// Pointer-to-member types aren't properly handled in the dbscheme.
not var.getResultType() instanceof PointerToMemberType
)
or
// `source` is an instruction that represents the return value of a
// function that is known to return stack-allocated memory.
exists(Call call |
call.getTarget().hasGlobalName(["alloca", "strdupa", "strndupa", "_alloca", "_malloca"]) and
source.getUnconvertedResultExpression() = call
)
) )
} }
@@ -85,10 +95,10 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
} }
from from
MustFlowPathNode source, MustFlowPathNode sink, VariableAddressInstruction var, MustFlowPathNode source, MustFlowPathNode sink, Instruction instr,
ReturnStackAllocatedMemoryConfig conf ReturnStackAllocatedMemoryConfig conf
where where
conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
source.getInstruction() = var source.getInstruction() = instr
select sink.getInstruction(), source, sink, "May return stack-allocated memory from $@.", select sink.getInstruction(), source, sink, "May return stack-allocated memory from $@.",
var.getAst(), var.getAst().toString() instr.getAst(), instr.getAst().toString()

View File

@@ -13,7 +13,8 @@
*/ */
import cpp import cpp
import semmle.code.cpp.controlflow.StackVariableReachability import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.dataflow.MustFlow
/** /**
* Auxiliary predicate: Types that don't require initialization * Auxiliary predicate: Types that don't require initialization
@@ -33,31 +34,6 @@ predicate allocatedType(Type t) {
allocatedType(t.getUnspecifiedType()) allocatedType(t.getUnspecifiedType())
} }
/**
* A declaration of a local variable that leaves the
* variable uninitialized.
*/
DeclStmt declWithNoInit(LocalVariable v) {
result.getADeclaration() = v and
not exists(v.getInitializer()) and
/* The type of the variable is not stack-allocated. */
exists(Type t | t = v.getType() | not allocatedType(t))
}
class UninitialisedLocalReachability extends StackVariableReachability {
UninitialisedLocalReachability() { this = "UninitialisedLocal" }
override predicate isSource(ControlFlowNode node, StackVariable v) { node = declWithNoInit(v) }
override predicate isSink(ControlFlowNode node, StackVariable v) { useOfVarActual(v, node) }
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
// only report the _first_ possibly uninitialized use
useOfVarActual(v, node) or
definitionBarrier(v, node)
}
}
pragma[noinline] pragma[noinline]
predicate containsInlineAssembly(Function f) { exists(AsmStmt s | s.getEnclosingFunction() = f) } predicate containsInlineAssembly(Function f) { exists(AsmStmt s | s.getEnclosingFunction() = f) }
@@ -82,8 +58,33 @@ VariableAccess commonException() {
containsInlineAssembly(result.getEnclosingFunction()) containsInlineAssembly(result.getEnclosingFunction())
} }
from UninitialisedLocalReachability r, LocalVariable v, VariableAccess va predicate isSinkImpl(Instruction sink, VariableAccess va) {
exists(LoadInstruction load |
va = load.getUnconvertedResultExpression() and
not va = commonException() and
sink = load.getSourceValue()
)
}
class MustFlow extends MustFlowConfiguration {
MustFlow() { this = "MustFlow" }
override predicate isSource(Instruction source) {
source instanceof UninitializedInstruction and
exists(Type t | t = source.getResultType() | not allocatedType(t))
}
override predicate isSink(Operand sink) { isSinkImpl(sink.getDef(), _) }
override predicate allowInterproceduralFlow() { none() }
override predicate isBarrier(Instruction instr) { instr instanceof ChiInstruction }
}
from
VariableAccess va, LocalVariable v, MustFlow conf, MustFlowPathNode source, MustFlowPathNode sink
where where
r.reaches(_, v, va) and conf.hasFlowPath(source, sink) and
not va = commonException() isSinkImpl(sink.getInstruction(), va) and
v = va.getTarget()
select va, "The variable $@ may not be initialized at this access.", v, v.getName() select va, "The variable $@ may not be initialized at this access.", v, v.getName()

View File

@@ -14,25 +14,47 @@
import cpp import cpp
import semmle.code.cpp.security.Security import semmle.code.cpp.security.Security
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl import semmle.code.cpp.security.FlowSources
import TaintedWithPath import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.ir.IR
import Flow::PathGraph
predicate isProcessOperationExplanation(Expr arg, string processOperation) { predicate isProcessOperationExplanation(DataFlow::Node arg, string processOperation) {
exists(int processOperationArg, FunctionCall call | exists(int processOperationArg, FunctionCall call |
isProcessOperationArgument(processOperation, processOperationArg) and isProcessOperationArgument(processOperation, processOperationArg) and
call.getTarget().getName() = processOperation and call.getTarget().getName() = processOperation and
call.getArgument(processOperationArg) = arg call.getArgument(processOperationArg) = [arg.asExpr(), arg.asIndirectExpr()]
) )
} }
class Configuration extends TaintTrackingConfiguration { predicate isSource(FlowSource source, string sourceType) {
override predicate isSink(Element arg) { isProcessOperationExplanation(arg, _) } not source instanceof DataFlow::ExprNode and
sourceType = source.getSourceType()
} }
from string processOperation, Expr arg, Expr source, PathNode sourceNode, PathNode sinkNode module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { isSource(node, _) }
predicate isSink(DataFlow::Node node) { isProcessOperationExplanation(node, _) }
predicate isBarrier(DataFlow::Node node) {
isSink(node) and node.asExpr().getUnspecifiedType() instanceof ArithmeticType
or
node.asInstruction().(StoreInstruction).getResultType() instanceof ArithmeticType
}
}
module Flow = TaintTracking::Global<Config>;
from
string processOperation, string sourceType, DataFlow::Node source, DataFlow::Node sink,
Flow::PathNode sourceNode, Flow::PathNode sinkNode
where where
isProcessOperationExplanation(arg, processOperation) and source = sourceNode.getNode() and
taintedWithPath(source, arg, sourceNode, sinkNode) sink = sinkNode.getNode() and
select arg, sourceNode, sinkNode, isSource(source, sourceType) and
isProcessOperationExplanation(sink, processOperation) and
Flow::flowPath(sourceNode, sinkNode)
select sink, sourceNode, sinkNode,
"The value of this argument may come from $@ and is being passed to " + processOperation + ".", "The value of this argument may come from $@ and is being passed to " + processOperation + ".",
source, source.toString() source, sourceType

View File

@@ -15,9 +15,10 @@
*/ */
import semmle.code.cpp.security.BufferWrite import semmle.code.cpp.security.BufferWrite
import semmle.code.cpp.security.Security import semmle.code.cpp.security.FlowSources as FS
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl import semmle.code.cpp.dataflow.new.TaintTracking
import TaintedWithPath import semmle.code.cpp.controlflow.IRGuards
import Flow::PathGraph
/* /*
* --- Summary of CWE-120 alerts --- * --- Summary of CWE-120 alerts ---
@@ -47,38 +48,54 @@ predicate isUnboundedWrite(BufferWrite bw) {
not exists(bw.getMaxData(_)) // and we can't deduce an upper bound to the amount copied not exists(bw.getMaxData(_)) // and we can't deduce an upper bound to the amount copied
} }
/*
* predicate isMaybeUnboundedWrite(BufferWrite bw)
* {
* not bw.hasExplicitLimit() // has no explicit size limit
* and exists(bw.getMaxData()) // and we can deduce an upper bound to the amount copied
* and (not exists(getBufferSize(bw.getDest(), _))) // but we can't work out the size of the destination to be sure
* }
*/
/** /**
* Holds if `e` is a source buffer going into an unbounded write `bw` or a * Holds if `e` is a source buffer going into an unbounded write `bw` or a
* qualifier of (a qualifier of ...) such a source. * qualifier of (a qualifier of ...) such a source.
*/ */
predicate unboundedWriteSource(Expr e, BufferWrite bw) { predicate unboundedWriteSource(Expr e, BufferWrite bw, boolean qualifier) {
isUnboundedWrite(bw) and e = bw.getASource() isUnboundedWrite(bw) and e = bw.getASource() and qualifier = false
or or
exists(FieldAccess fa | unboundedWriteSource(fa, bw) and e = fa.getQualifier()) exists(FieldAccess fa | unboundedWriteSource(fa, bw, _) and e = fa.getQualifier()) and
qualifier = true
} }
/* predicate isSource(FS::FlowSource source, string sourceType) { source.getSourceType() = sourceType }
* --- user input reach ---
*/
class Configuration extends TaintTrackingConfiguration { predicate isSink(DataFlow::Node sink, BufferWrite bw, boolean qualifier) {
override predicate isSink(Element tainted) { unboundedWriteSource(tainted, _) } unboundedWriteSource(sink.asIndirectExpr(), bw, qualifier)
or
override predicate taintThroughGlobals() { any() } // `gets` and `scanf` reads from stdin so there's no real input.
// The `BufferWrite` library models this as the call itself being
// the source. In this case we mark the output argument as being
// the sink so that we report a path where source = sink (because
// the same output argument is also included in `isSource`).
bw.getASource() = bw and
unboundedWriteSource(sink.asDefiningArgument(), bw, qualifier)
} }
/* predicate lessThanOrEqual(IRGuardCondition g, Expr e, boolean branch) {
* --- put it together --- exists(Operand left |
*/ g.comparesLt(left, _, _, true, branch) or
g.comparesEq(left, _, _, true, branch)
|
left.getDef().getUnconvertedResultExpression() = e
)
}
module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { isSource(source, _) }
predicate isSink(DataFlow::Node sink) { isSink(sink, _, _) }
predicate isBarrierOut(DataFlow::Node node) { isSink(node, _, false) }
predicate isBarrier(DataFlow::Node node) {
// Block flow if the node is guarded by any <, <= or = operations.
node = DataFlow::BarrierGuard<lessThanOrEqual/3>::getABarrierNode()
}
}
module Flow = TaintTracking::Global<Config>;
/* /*
* An unbounded write is, for example `strcpy(..., tainted)`. We're looking * An unbounded write is, for example `strcpy(..., tainted)`. We're looking
@@ -87,17 +104,20 @@ class Configuration extends TaintTrackingConfiguration {
* *
* In the case of `gets` and `scanf`, where the source buffer is implicit, the * In the case of `gets` and `scanf`, where the source buffer is implicit, the
* `BufferWrite` library reports the source buffer to be the same as the * `BufferWrite` library reports the source buffer to be the same as the
* destination buffer. Since those destination-buffer arguments are also * destination buffer. So to report an alert on a pattern like:
* modeled in the taint-tracking library as being _sources_ of taint, they are * ```
* in practice reported as being tainted because the `security.TaintTracking` * char s[32];
* library does not distinguish between taint going into an argument and out of * gets(s);
* an argument. Thus, we get the desired alerts. * ```
* we define the sink as the node corresponding to the output argument of `gets`.
* This gives us a path where the source is equal to the sink.
*/ */
from BufferWrite bw, Expr inputSource, Expr tainted, PathNode sourceNode, PathNode sinkNode from BufferWrite bw, Flow::PathNode source, Flow::PathNode sink, string sourceType
where where
taintedWithPath(inputSource, tainted, sourceNode, sinkNode) and Flow::flowPath(source, sink) and
unboundedWriteSource(tainted, bw) isSource(source.getNode(), sourceType) and
select bw, sourceNode, sinkNode, isSink(sink.getNode(), bw, _)
"This '" + bw.getBWDesc() + "' with input from $@ may overflow the destination.", inputSource, select bw, source, sink,
inputSource.toString() "This '" + bw.getBWDesc() + "' with input from $@ may overflow the destination.",
source.getNode(), sourceType

View File

@@ -1,24 +0,0 @@
#include <stdio.h>
char *copy;
void copyArgv(char **argv) {
copy = argv[1];
}
void printWrapper(char *str) {
printf(str);
}
int main(int argc, char **argv) {
copyArgv(argv);
// This should be avoided
printf(copy);
// This should be avoided too, because it has the same effect
printWrapper(copy);
// This is fine
printf("%s", copy);
}

View File

@@ -1,36 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>The program uses input from the user, propagated via a global variable, as a format string for <code>printf</code> style functions.
This can lead to buffer overflows or data representation problems. An attacker can exploit this weakness to crash the program,
disclose information or even execute arbitrary code.</p>
<p>This rule only identifies inputs from the user that are transferred through global variables before being used in <code>printf</code> style functions.
Analyzing the flow of data through global variables is more prone to errors and so this rule may identify some examples of code where
the input is not really from the user. For example, when a global variable is set in two places, one that comes from the user and one that does not.
In this case we would mark all usages of the global variable as input from the user, but the input from the user may always came after the call to the
<code>printf</code> style functions.</p>
<p>The results of this rule should be considered alongside the related rule "Uncontrolled format string" which tracks the flow of the
values input by a user, excluding global variables, until the values are used as the format argument for a <code>printf</code> like function call.</p>
</overview>
<recommendation>
<p>Use constant expressions as the format strings. If you need to print a value from the user, use <code>printf("%s", value_from_user)</code>.</p>
</recommendation>
<example>
<sample src="UncontrolledFormatStringThroughGlobalVar.c" />
</example>
<references>
<li>CERT C Coding
Standard: <a href="https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings">FIO30-C. Exclude
user input from format strings</a>.</li>
</references>
</qhelp>

View File

@@ -1,40 +0,0 @@
/**
* @name Uncontrolled format string (through global variable)
* @description Using externally-controlled format strings in
* printf-style functions can lead to buffer overflows
* or data representation problems.
* @kind path-problem
* @problem.severity warning
* @security-severity 9.3
* @precision high
* @id cpp/tainted-format-string-through-global
* @tags reliability
* security
* external/cwe/cwe-134
*/
import cpp
import semmle.code.cpp.security.FunctionWithWrappers
import semmle.code.cpp.security.Security
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
import TaintedWithPath
class Configuration extends TaintTrackingConfiguration {
override predicate isSink(Element tainted) {
exists(PrintfLikeFunction printf | printf.outermostWrapperFunctionCall(tainted, _))
}
override predicate taintThroughGlobals() { any() }
}
from
PrintfLikeFunction printf, Expr arg, PathNode sourceNode, PathNode sinkNode,
string printfFunction, Expr userValue, string cause
where
printf.outermostWrapperFunctionCall(arg, printfFunction) and
not taintedWithoutGlobals(arg) and
taintedWithPath(userValue, arg, sourceNode, sinkNode) and
isUserInput(userValue, cause)
select arg, sourceNode, sinkNode,
"The value of this argument may come from $@ and is being used as a formatting argument to " +
printfFunction + ".", userValue, cause

View File

@@ -14,10 +14,13 @@
import cpp import cpp
import semmle.code.cpp.security.Overflow import semmle.code.cpp.security.Overflow
import semmle.code.cpp.security.Security import semmle.code.cpp.dataflow.new.TaintTracking
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl import semmle.code.cpp.dataflow.new.DataFlow
import TaintedWithPath import semmle.code.cpp.ir.IR
import semmle.code.cpp.controlflow.IRGuards as IRGuards
import semmle.code.cpp.security.FlowSources as FS
import Bounded import Bounded
import Flow::PathGraph
bindingset[op] bindingset[op]
predicate missingGuard(Operation op, Expr e, string effect) { predicate missingGuard(Operation op, Expr e, string effect) {
@@ -28,28 +31,90 @@ predicate missingGuard(Operation op, Expr e, string effect) {
not e instanceof VariableAccess and effect = "overflow" not e instanceof VariableAccess and effect = "overflow"
} }
class Configuration extends TaintTrackingConfiguration { predicate isSource(FS::FlowSource source, string sourceType) { sourceType = source.getSourceType() }
override predicate isSink(Element e) {
exists(Operation op |
missingGuard(op, e, _) and
op.getAnOperand() = e
|
op instanceof UnaryArithmeticOperation or
op instanceof BinaryArithmeticOperation or
op instanceof AssignArithmeticOperation
)
}
override predicate isBarrier(Expr e) { predicate isSink(DataFlow::Node sink, Operation op, Expr e) {
super.isBarrier(e) or bounded(e) or e.getUnspecifiedType().(IntegralType).getSize() <= 1 e = sink.asExpr() and
missingGuard(op, e, _) and
op.getAnOperand() = e and
(
op instanceof UnaryArithmeticOperation or
op instanceof BinaryArithmeticOperation or
op instanceof AssignArithmeticOperation
)
}
predicate hasUpperBoundsCheck(Variable var) {
exists(RelationalOperation oper, VariableAccess access |
oper.getAnOperand() = access and
access.getTarget() = var and
// Comparing to 0 is not an upper bound check
not oper.getAnOperand().getValue() = "0"
)
}
predicate constantInstruction(Instruction instr) {
instr instanceof ConstantInstruction or
constantInstruction(instr.(UnaryInstruction).getUnary())
}
predicate readsVariable(LoadInstruction load, Variable var) {
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
}
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
exists(Instruction instr | instr = node.asInstruction() |
readsVariable(instr, checkedVar) and
any(IRGuards::IRGuardCondition guard).ensuresEq(access, _, _, instr.getBlock(), true)
)
}
module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { isSource(source, _) }
predicate isSink(DataFlow::Node sink) { isSink(sink, _, _) }
predicate isBarrier(DataFlow::Node node) {
exists(StoreInstruction store | store = node.asInstruction() |
// Block flow to "likely small expressions"
bounded(store.getSourceValue().getUnconvertedResultExpression())
or
// Block flow to "small types"
store.getResultType().getUnspecifiedType().(IntegralType).getSize() <= 1
)
or
// Block flow if there's an upper bound check of the variable anywhere in the program
exists(Variable checkedVar, Instruction instr | instr = node.asInstruction() |
readsVariable(instr, checkedVar) and
hasUpperBoundsCheck(checkedVar)
)
or
// Block flow if the node is guarded by an equality check
exists(Variable checkedVar, Operand access |
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
readsVariable(access.getDef(), checkedVar)
)
or
// Block flow to any binary instruction whose operands are both non-constants.
exists(BinaryInstruction iTo |
iTo = node.asInstruction() and
not constantInstruction(iTo.getLeft()) and
not constantInstruction(iTo.getRight()) and
// propagate taint from either the pointer or the offset, regardless of constantness
not iTo instanceof PointerArithmeticInstruction
)
} }
} }
from Expr origin, Expr e, string effect, PathNode sourceNode, PathNode sinkNode, Operation op module Flow = TaintTracking::Global<Config>;
from
Expr e, string effect, Flow::PathNode source, Flow::PathNode sink, Operation op, string sourceType
where where
taintedWithPath(origin, e, sourceNode, sinkNode) and Flow::flowPath(source, sink) and
op.getAnOperand() = e and isSource(source.getNode(), sourceType) and
isSink(sink.getNode(), op, e) and
missingGuard(op, e, effect) missingGuard(op, e, effect)
select e, sourceNode, sinkNode, select e, source, sink,
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".", "$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
origin, "User-provided value" source, sourceType

View File

@@ -16,45 +16,30 @@
import cpp import cpp
import semmle.code.cpp.security.Overflow import semmle.code.cpp.security.Overflow
import semmle.code.cpp.security.Security import semmle.code.cpp.dataflow.new.TaintTracking
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl import semmle.code.cpp.ir.IR
import semmle.code.cpp.controlflow.IRGuards as IRGuards
predicate isMaxValue(Expr mie) { predicate isMaxValue(Expr mie) {
exists(MacroInvocation mi | exists(MacroInvocation mi |
mi.getExpr() = mie and mi.getExpr() = mie and
( mi.getMacroName() = ["CHAR_MAX", "LLONG_MAX", "INT_MAX", "SHRT_MAX", "UINT_MAX"]
mi.getMacroName() = "CHAR_MAX" or
mi.getMacroName() = "LLONG_MAX" or
mi.getMacroName() = "INT_MAX" or
mi.getMacroName() = "SHRT_MAX" or
mi.getMacroName() = "UINT_MAX"
)
) )
} }
predicate isMinValue(Expr mie) { predicate isMinValue(Expr mie) {
exists(MacroInvocation mi | exists(MacroInvocation mi |
mi.getExpr() = mie and mi.getExpr() = mie and
( mi.getMacroName() = ["CHAR_MIN", "LLONG_MIN", "INT_MIN", "SHRT_MIN"]
mi.getMacroName() = "CHAR_MIN" or
mi.getMacroName() = "LLONG_MIN" or
mi.getMacroName() = "INT_MIN" or
mi.getMacroName() = "SHRT_MIN"
)
) )
} }
class SecurityOptionsArith extends SecurityOptions { predicate isSource(DataFlow::Node source, string cause) {
override predicate isUserInput(Expr expr, string cause) { exists(Expr expr | expr = source.asExpr() |
isMaxValue(expr) and cause = "max value" isMaxValue(expr) and cause = "max value"
or or
isMinValue(expr) and cause = "min value" isMinValue(expr) and cause = "min value"
} )
}
predicate taintedVarAccess(Expr origin, VariableAccess va, string cause) {
isUserInput(origin, cause) and
tainted(origin, va)
} }
predicate causeEffectCorrespond(string cause, string effect) { predicate causeEffectCorrespond(string cause, string effect) {
@@ -65,16 +50,79 @@ predicate causeEffectCorrespond(string cause, string effect) {
effect = "underflow" effect = "underflow"
} }
from Expr origin, Operation op, VariableAccess va, string cause, string effect predicate isSink(DataFlow::Node sink, VariableAccess va, string effect) {
where exists(Operation op |
taintedVarAccess(origin, va, cause) and sink.asExpr() = va and
op.getAnOperand() = va and op.getAnOperand() = va
( |
missingGuardAgainstUnderflow(op, va) and effect = "underflow" missingGuardAgainstUnderflow(op, va) and effect = "underflow"
or or
missingGuardAgainstOverflow(op, va) and effect = "overflow" missingGuardAgainstOverflow(op, va) and effect = "overflow"
) and )
causeEffectCorrespond(cause, effect) }
predicate hasUpperBoundsCheck(Variable var) {
exists(RelationalOperation oper, VariableAccess access |
oper.getAnOperand() = access and
access.getTarget() = var and
// Comparing to 0 is not an upper bound check
not oper.getAnOperand().getValue() = "0"
)
}
predicate constantInstruction(Instruction instr) {
instr instanceof ConstantInstruction or
constantInstruction(instr.(UnaryInstruction).getUnary())
}
predicate readsVariable(LoadInstruction load, Variable var) {
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
}
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
exists(Instruction instr | instr = node.asInstruction() |
readsVariable(instr, checkedVar) and
any(IRGuards::IRGuardCondition guard).ensuresEq(access, _, _, instr.getBlock(), true)
)
}
module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { isSource(source, _) }
predicate isSink(DataFlow::Node sink) { isSink(sink, _, _) }
predicate isBarrier(DataFlow::Node node) {
// Block flow if there's an upper bound check of the variable anywhere in the program
exists(Variable checkedVar, Instruction instr | instr = node.asInstruction() |
readsVariable(instr, checkedVar) and
hasUpperBoundsCheck(checkedVar)
)
or
// Block flow if the node is guarded by an equality check
exists(Variable checkedVar, Operand access |
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
readsVariable(access.getDef(), checkedVar)
)
or
// Block flow to any binary instruction whose operands are both non-constants.
exists(BinaryInstruction iTo |
iTo = node.asInstruction() and
not constantInstruction(iTo.getLeft()) and
not constantInstruction(iTo.getRight()) and
// propagate taint from either the pointer or the offset, regardless of constantness
not iTo instanceof PointerArithmeticInstruction
)
}
}
module Flow = TaintTracking::Global<Config>;
from DataFlow::Node source, DataFlow::Node sink, VariableAccess va, string cause, string effect
where
Flow::flow(source, sink) and
isSource(source, cause) and
causeEffectCorrespond(cause, effect) and
isSink(sink, va, effect)
select va, select va,
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".", "$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
origin, "Extreme value" source, "Extreme value"

View File

@@ -15,7 +15,11 @@
import cpp import cpp
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl import semmle.code.cpp.dataflow.new.DataFlow
import semmle.code.cpp.security.FlowSources as FS
import semmle.code.cpp.dataflow.new.TaintTracking
import semmle.code.cpp.ir.IR
import semmle.code.cpp.controlflow.IRGuards as IRGuards
/** Holds if `expr` might overflow. */ /** Holds if `expr` might overflow. */
predicate outOfBoundsExpr(Expr expr, string kind) { predicate outOfBoundsExpr(Expr expr, string kind) {
@@ -27,13 +31,76 @@ predicate outOfBoundsExpr(Expr expr, string kind) {
else none() else none()
} }
from Expr use, Expr origin, string kind predicate isSource(FS::FlowSource source, string sourceType) { sourceType = source.getSourceType() }
predicate isSink(DataFlow::Node sink, string kind) {
exists(Expr use |
use = sink.asExpr() and
not use.getUnspecifiedType() instanceof PointerType and
outOfBoundsExpr(use, kind) and
not inSystemMacroExpansion(use)
)
}
predicate hasUpperBoundsCheck(Variable var) {
exists(RelationalOperation oper, VariableAccess access |
oper.getAnOperand() = access and
access.getTarget() = var and
// Comparing to 0 is not an upper bound check
not oper.getAnOperand().getValue() = "0"
)
}
predicate constantInstruction(Instruction instr) {
instr instanceof ConstantInstruction or
constantInstruction(instr.(UnaryInstruction).getUnary())
}
predicate readsVariable(LoadInstruction load, Variable var) {
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
}
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
exists(Instruction instr | instr = node.asInstruction() |
readsVariable(instr, checkedVar) and
any(IRGuards::IRGuardCondition guard).ensuresEq(access, _, _, instr.getBlock(), true)
)
}
module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { isSource(source, _) }
predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
predicate isBarrier(DataFlow::Node node) {
// Block flow if there's an upper bound check of the variable anywhere in the program
exists(Variable checkedVar, Instruction instr | instr = node.asInstruction() |
readsVariable(instr, checkedVar) and
hasUpperBoundsCheck(checkedVar)
)
or
// Block flow if the node is guarded by an equality check
exists(Variable checkedVar, Operand access |
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
readsVariable(access.getDef(), checkedVar)
)
or
// Block flow to any binary instruction whose operands are both non-constants.
exists(BinaryInstruction iTo |
iTo = node.asInstruction() and
not constantInstruction(iTo.getLeft()) and
not constantInstruction(iTo.getRight()) and
// propagate taint from either the pointer or the offset, regardless of constantness
not iTo instanceof PointerArithmeticInstruction
)
}
}
module Flow = TaintTracking::Global<Config>;
from DataFlow::Node source, DataFlow::Node sink, string kind, string sourceType
where where
not use.getUnspecifiedType() instanceof PointerType and Flow::flow(source, sink) and
outOfBoundsExpr(use, kind) and isSource(source, sourceType) and
tainted(origin, use) and isSink(sink, kind)
origin != use and select sink, "$@ flows an expression which might " + kind + ".", source, sourceType
not inSystemMacroExpansion(use) and
// Avoid double-counting: don't include all the conversions of `use`.
not use instanceof Conversion
select use, "$@ flows an expression which might " + kind + ".", origin, "User-provided value"

View File

@@ -4,6 +4,7 @@
* @description The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. For all files that were seen during the build, this query counts the lines of code, excluding whitespace or comments. * @description The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. For all files that were seen during the build, this query counts the lines of code, excluding whitespace or comments.
* @kind metric * @kind metric
* @tags summary * @tags summary
* telemetry
*/ */
import cpp import cpp

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added SQL API models for `ODBC`.

View File

@@ -0,0 +1,4 @@
---
category: breaking
---
* The `cpp/tainted-format-string-through-global` query has been deleted. This does not lead to a loss of relevant alerts, as the query duplicated a subset of the alerts from `cpp/tainted-format-string`.

View File

@@ -0,0 +1,5 @@
## 0.8.3
### Minor Analysis Improvements
* The `cpp/uninitialized-local` query has been improved to produce fewer false positives.

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 0.8.2 lastReleaseVersion: 0.8.3

View File

@@ -4,7 +4,6 @@
* @kind problem * @kind problem
* @id cpp/quantum-readiness/cbom/all-asymmetric-algorithms * @id cpp/quantum-readiness/cbom/all-asymmetric-algorithms
* @problem.severity error * @problem.severity error
* @precision high
* @tags cbom * @tags cbom
* cryptography * cryptography
*/ */

View File

@@ -4,7 +4,6 @@
* @kind problem * @kind problem
* @id cpp/quantum-readiness/cbom/all-cryptographic-algorithms * @id cpp/quantum-readiness/cbom/all-cryptographic-algorithms
* @problem.severity error * @problem.severity error
* @precision high
* @tags cbom * @tags cbom
* cryptography * cryptography
*/ */

View File

@@ -4,7 +4,6 @@
* @kind problem * @kind problem
* @id cpp/quantum-readiness/cbom/all-asymmetric-encryption-algorithms * @id cpp/quantum-readiness/cbom/all-asymmetric-encryption-algorithms
* @problem.severity error * @problem.severity error
* @precision high
* @tags cbom * @tags cbom
* cryptography * cryptography
*/ */

View File

@@ -4,7 +4,6 @@
* @kind problem * @kind problem
* @id cpp/quantum-readiness/cbom/authenticated-encryption-algorithms * @id cpp/quantum-readiness/cbom/authenticated-encryption-algorithms
* @problem.severity error * @problem.severity error
* @precision high
* @tags cbom * @tags cbom
* cryptography * cryptography
*/ */

View File

@@ -4,7 +4,6 @@
* @kind problem * @kind problem
* @id cpp/quantum-readiness/cbom/block-cipher-mode * @id cpp/quantum-readiness/cbom/block-cipher-mode
* @problem.severity error * @problem.severity error
* @precision high
* @tags cbom * @tags cbom
* cryptography * cryptography
*/ */

View File

@@ -4,7 +4,6 @@
* @kind problem * @kind problem
* @id cpp/quantum-readiness/cbom/iv-sources * @id cpp/quantum-readiness/cbom/iv-sources
* @problem.severity error * @problem.severity error
* @precision high
* @tags cbom * @tags cbom
* cryptography * cryptography
*/ */

View File

@@ -4,7 +4,6 @@
* @kind problem * @kind problem
* @id cpp/quantum-readiness/cbom/unkown-iv-sources * @id cpp/quantum-readiness/cbom/unkown-iv-sources
* @problem.severity error * @problem.severity error
* @precision high
* @tags cbom * @tags cbom
* cryptography * cryptography
*/ */

View File

@@ -4,7 +4,6 @@
* @kind problem * @kind problem
* @id cpp/quantum-readiness/cbom/elliptic-curve-key-length * @id cpp/quantum-readiness/cbom/elliptic-curve-key-length
* @problem.severity error * @problem.severity error
* @precision high
* @tags cbom * @tags cbom
* cryptography * cryptography
*/ */

View File

@@ -4,7 +4,6 @@
* @kind problem * @kind problem
* @id cpp/quantum-readiness/cbom/elliptic-curve-algorithms * @id cpp/quantum-readiness/cbom/elliptic-curve-algorithms
* @problem.severity error * @problem.severity error
* @precision high
* @tags cbom * @tags cbom
* cryptography * cryptography
*/ */

View File

@@ -4,7 +4,6 @@
* @kind problem * @kind problem
* @id cpp/quantum-readiness/cbom/hash-algorithms * @id cpp/quantum-readiness/cbom/hash-algorithms
* @problem.severity error * @problem.severity error
* @precision high
* @tags cbom * @tags cbom
* cryptography * cryptography
*/ */

View File

@@ -4,7 +4,6 @@
* @kind problem * @kind problem
* @id cpp/quantum-readiness/cbom/key-exchange * @id cpp/quantum-readiness/cbom/key-exchange
* @problem.severity error * @problem.severity error
* @precision high
* @tags cbom * @tags cbom
* cryptography * cryptography
*/ */

View File

@@ -4,7 +4,6 @@
* @kind problem * @kind problem
* @id cpp/quantum-readiness/cbom/asymmetric-key-generation * @id cpp/quantum-readiness/cbom/asymmetric-key-generation
* @problem.severity error * @problem.severity error
* @precision high
* @tags cbom * @tags cbom
* cryptography * cryptography
*/ */

View File

@@ -4,7 +4,6 @@
* @kind problem * @kind problem
* @id cpp/quantum-readiness/cbom/signing-algorithms * @id cpp/quantum-readiness/cbom/signing-algorithms
* @problem.severity error * @problem.severity error
* @precision high
* @tags cbom * @tags cbom
* cryptography * cryptography
*/ */

View File

@@ -4,7 +4,6 @@
* @kind problem * @kind problem
* @id cpp/quantum-readiness/cbom/symmetric-encryption-algorithms * @id cpp/quantum-readiness/cbom/symmetric-encryption-algorithms
* @problem.severity error * @problem.severity error
* @precision high
* @tags cbom * @tags cbom
* cryptography * cryptography
*/ */

View File

@@ -4,7 +4,6 @@
* @kind problem * @kind problem
* @id cpp/quantum-readiness/cbom/unkwon-asymmetric-key-generation * @id cpp/quantum-readiness/cbom/unkwon-asymmetric-key-generation
* @problem.severity error * @problem.severity error
* @precision high
* @tags cbom * @tags cbom
* cryptography * cryptography
*/ */

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries name: codeql/cpp-queries
version: 0.8.3-dev version: 0.8.4-dev
groups: groups:
- cpp - cpp
- queries - queries

View File

@@ -0,0 +1,111 @@
module AstTest {
import semmle.code.cpp.dataflow.DataFlow
private import semmle.code.cpp.controlflow.Guards
/**
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement
* S in `if (guarded(x)) S`.
*/
// This is tested in `BarrierGuard.cpp`.
predicate testBarrierGuard(GuardCondition g, Expr checked, boolean isTrue) {
g.(FunctionCall).getTarget().getName() = "guarded" and
checked = g.(FunctionCall).getArgument(0) and
isTrue = true
}
/** Common data flow configuration to be used by tests. */
module AstTestAllocationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
or
source.asParameter().getName().matches("source%")
or
source.asExpr().(FunctionCall).getTarget().getName() = "indirect_source"
or
source.(DataFlow::DefinitionByReferenceNode).getParameter().getName().matches("ref_source%")
or
// Track uninitialized variables
exists(source.asUninitialized())
}
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call |
call.getTarget().getName() = ["sink", "indirect_sink"] and
sink.asExpr() = call.getAnArgument()
)
}
predicate isBarrier(DataFlow::Node barrier) {
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier") or
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
}
}
module AstFlow = DataFlow::Global<AstTestAllocationConfig>;
}
module IRTest {
private import cpp
import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.controlflow.IRGuards
/**
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement
* S in `if (guarded(x)) S`.
*/
// This is tested in `BarrierGuard.cpp`.
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean isTrue) {
exists(Call call |
call = g.getUnconvertedResultExpression() and
call.getTarget().hasName("guarded") and
checked = call.getArgument(0) and
isTrue = true
)
}
/** Common data flow configuration to be used by tests. */
module IRTestAllocationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
or
source.asIndirectExpr(1).(FunctionCall).getTarget().getName() = "indirect_source"
or
source.asExpr().(StringLiteral).getValue() = "source"
or
// indirect_source(n) gives the dataflow node representing the indirect node after n dereferences.
exists(int n, string s |
n = s.regexpCapture("indirect_source\\((\\d)\\)", 1).toInt() and
source.asIndirectExpr(n).(StringLiteral).getValue() = s
)
or
source.asParameter().getName().matches("source%")
or
source.(DataFlow::DefinitionByReferenceNode).getParameter().getName().matches("ref_source%")
or
exists(source.asUninitialized())
}
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call, Expr e | e = call.getAnArgument() |
call.getTarget().getName() = "sink" and
sink.asExpr() = e
or
call.getTarget().getName() = "indirect_sink" and
sink.asIndirectExpr() = e
)
}
predicate isBarrier(DataFlow::Node barrier) {
exists(Expr barrierExpr | barrierExpr in [barrier.asExpr(), barrier.asIndirectExpr()] |
barrierExpr.(VariableAccess).getTarget().hasName("barrier")
)
or
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
or
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getAnIndirectBarrierNode()
}
}
module IRFlow = DataFlow::Global<IRTestAllocationConfig>;
}

View File

@@ -1,5 +1,11 @@
uniqueEnclosingCallable uniqueEnclosingCallable
| test.cpp:864:44:864:58 | {...} | Node should have one enclosing callable but has 0. |
| test.cpp:864:47:864:54 | call to source | Node should have one enclosing callable but has 0. |
| test.cpp:872:46:872:51 | call to source | Node should have one enclosing callable but has 0. |
| test.cpp:872:53:872:56 | 1 | Node should have one enclosing callable but has 0. |
uniqueCallEnclosingCallable uniqueCallEnclosingCallable
| test.cpp:864:47:864:54 | call to source | Call should have one enclosing callable but has 0. |
| test.cpp:872:46:872:51 | call to source | Call should have one enclosing callable but has 0. |
uniqueType uniqueType
uniqueNodeLocation uniqueNodeLocation
missingLocation missingLocation
@@ -23,6 +29,8 @@ argHasPostUpdate
| lambdas.cpp:38:2:38:2 | d | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:38:2:38:2 | d | ArgumentNode is missing PostUpdateNode. |
| lambdas.cpp:45:2:45:2 | e | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:45:2:45:2 | e | ArgumentNode is missing PostUpdateNode. |
| test.cpp:67:29:67:35 | source1 | ArgumentNode is missing PostUpdateNode. | | test.cpp:67:29:67:35 | source1 | ArgumentNode is missing PostUpdateNode. |
| test.cpp:813:19:813:35 | * ... | ArgumentNode is missing PostUpdateNode. |
| test.cpp:848:23:848:25 | rpx | ArgumentNode is missing PostUpdateNode. |
postWithInFlow postWithInFlow
| BarrierGuard.cpp:49:6:49:6 | x [post update] | PostUpdateNode should not be the target of local flow. | | BarrierGuard.cpp:49:6:49:6 | x [post update] | PostUpdateNode should not be the target of local flow. |
| BarrierGuard.cpp:60:7:60:7 | x [post update] | PostUpdateNode should not be the target of local flow. | | BarrierGuard.cpp:60:7:60:7 | x [post update] | PostUpdateNode should not be the target of local flow. |
@@ -136,6 +144,9 @@ postWithInFlow
| test.cpp:728:3:728:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. | | test.cpp:728:3:728:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:728:4:728:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. | | test.cpp:728:4:728:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:734:41:734:41 | x [inner post update] | PostUpdateNode should not be the target of local flow. | | test.cpp:734:41:734:41 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:808:5:808:21 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:808:6:808:21 | global_indirect1 [inner post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:832:5:832:17 | global_direct [post update] | PostUpdateNode should not be the target of local flow. |
viableImplInCallContextTooLarge viableImplInCallContextTooLarge
uniqueParameterNodeAtPosition uniqueParameterNodeAtPosition
uniqueParameterNodePosition uniqueParameterNodePosition

View File

@@ -0,0 +1,306 @@
WARNING: Module DataFlow has been deprecated and may be removed in future (test-source-sink.ql:3,25-42)
WARNING: Module DataFlow has been deprecated and may be removed in future (test-source-sink.ql:3,57-74)
astFlow
| BarrierGuard.cpp:5:19:5:24 | source | BarrierGuard.cpp:9:10:9:15 | source |
| BarrierGuard.cpp:13:17:13:22 | source | BarrierGuard.cpp:15:10:15:15 | source |
| BarrierGuard.cpp:21:17:21:22 | source | BarrierGuard.cpp:25:10:25:15 | source |
| BarrierGuard.cpp:29:16:29:21 | source | BarrierGuard.cpp:31:10:31:15 | source |
| BarrierGuard.cpp:29:16:29:21 | source | BarrierGuard.cpp:33:10:33:15 | source |
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:51:13:51:13 | x |
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:53:13:53:13 | x |
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:55:13:55:13 | x |
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:62:14:62:14 | x |
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:64:14:64:14 | x |
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:66:14:66:14 | x |
| acrossLinkTargets.cpp:19:27:19:32 | call to source | acrossLinkTargets.cpp:12:8:12:8 | x |
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:18:8:18:19 | sourceArray1 |
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:22:8:22:20 | & ... |
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:23:17:23:29 | & ... |
| clang.cpp:29:27:29:32 | call to source | clang.cpp:30:27:30:28 | m1 |
| clang.cpp:29:27:29:32 | call to source | clang.cpp:31:27:31:34 | call to getFirst |
| clang.cpp:35:32:35:37 | call to source | clang.cpp:38:10:38:11 | m2 |
| clang.cpp:44:35:44:40 | call to source | clang.cpp:46:17:46:18 | m2 |
| clang.cpp:51:19:51:24 | call to source | clang.cpp:52:8:52:17 | stackArray |
| clang.cpp:51:19:51:24 | call to source | clang.cpp:53:17:53:26 | stackArray |
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:35:16:35:25 | call to notSource1 |
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:43:15:43:24 | call to notSource1 |
| dispatch.cpp:10:37:10:42 | call to source | dispatch.cpp:36:16:36:25 | call to notSource2 |
| dispatch.cpp:10:37:10:42 | call to source | dispatch.cpp:44:15:44:24 | call to notSource2 |
| dispatch.cpp:37:19:37:24 | call to source | dispatch.cpp:11:38:11:38 | x |
| dispatch.cpp:45:18:45:23 | call to source | dispatch.cpp:11:38:11:38 | x |
| globals.cpp:5:17:5:22 | call to source | globals.cpp:6:10:6:14 | local |
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:14:3:14:6 | t |
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:18:8:18:8 | call to operator() |
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:21:3:21:6 | t |
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:29:3:29:6 | t |
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:35:8:35:8 | a |
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:41:8:41:8 | a |
| lambdas.cpp:43:7:43:12 | call to source | lambdas.cpp:46:7:46:7 | w |
| ref.cpp:29:11:29:16 | call to source | ref.cpp:62:10:62:11 | x3 |
| ref.cpp:53:9:53:10 | x1 | ref.cpp:56:10:56:11 | x1 |
| ref.cpp:53:13:53:14 | x2 | ref.cpp:59:10:59:11 | x2 |
| ref.cpp:53:17:53:18 | x3 | ref.cpp:62:10:62:11 | x3 |
| ref.cpp:53:21:53:22 | x4 | ref.cpp:65:10:65:11 | x4 |
| ref.cpp:55:23:55:28 | call to source | ref.cpp:56:10:56:11 | x1 |
| ref.cpp:94:15:94:20 | call to source | ref.cpp:129:13:129:15 | val |
| ref.cpp:109:15:109:20 | call to source | ref.cpp:132:13:132:15 | val |
| ref.cpp:122:23:122:28 | call to source | ref.cpp:123:13:123:15 | val |
| ref.cpp:125:19:125:24 | call to source | ref.cpp:126:13:126:15 | val |
| self-Iterator.cpp:19:23:19:28 | call to source | self-Iterator.cpp:20:10:20:10 | x |
| test.cpp:6:12:6:17 | call to source | test.cpp:7:8:7:9 | t1 |
| test.cpp:6:12:6:17 | call to source | test.cpp:9:8:9:9 | t1 |
| test.cpp:6:12:6:17 | call to source | test.cpp:10:8:10:9 | t2 |
| test.cpp:6:12:6:17 | call to source | test.cpp:15:8:15:9 | t2 |
| test.cpp:6:12:6:17 | call to source | test.cpp:26:8:26:9 | t1 |
| test.cpp:35:10:35:15 | call to source | test.cpp:30:8:30:8 | t |
| test.cpp:36:13:36:18 | call to source | test.cpp:31:8:31:8 | c |
| test.cpp:50:14:50:19 | call to source | test.cpp:58:10:58:10 | t |
| test.cpp:66:30:66:36 | source1 | test.cpp:71:8:71:9 | x4 |
| test.cpp:75:7:75:8 | u1 | test.cpp:76:8:76:9 | u1 |
| test.cpp:83:7:83:8 | u2 | test.cpp:84:8:84:18 | ... ? ... : ... |
| test.cpp:83:7:83:8 | u2 | test.cpp:86:8:86:9 | i1 |
| test.cpp:89:28:89:34 | source1 | test.cpp:90:8:90:14 | source1 |
| test.cpp:100:13:100:18 | call to source | test.cpp:103:10:103:12 | ref |
| test.cpp:138:27:138:32 | call to source | test.cpp:140:8:140:8 | y |
| test.cpp:151:33:151:38 | call to source | test.cpp:144:8:144:8 | s |
| test.cpp:151:33:151:38 | call to source | test.cpp:152:8:152:8 | y |
| test.cpp:164:34:164:39 | call to source | test.cpp:157:8:157:8 | x |
| test.cpp:164:34:164:39 | call to source | test.cpp:165:8:165:8 | y |
| test.cpp:171:11:171:16 | call to source | test.cpp:178:8:178:8 | y |
| test.cpp:245:14:245:19 | call to source | test.cpp:260:12:260:12 | x |
| test.cpp:265:22:265:27 | call to source | test.cpp:266:12:266:12 | x |
| test.cpp:305:17:305:22 | call to source | test.cpp:289:14:289:14 | x |
| test.cpp:314:4:314:9 | call to source | test.cpp:318:7:318:7 | x |
| test.cpp:347:17:347:22 | call to source | test.cpp:349:10:349:18 | globalVar |
| test.cpp:359:13:359:18 | call to source | test.cpp:365:10:365:14 | field |
| test.cpp:373:13:373:18 | call to source | test.cpp:369:10:369:14 | field |
| test.cpp:373:13:373:18 | call to source | test.cpp:375:10:375:14 | field |
| test.cpp:382:48:382:54 | source1 | test.cpp:385:8:385:10 | tmp |
| test.cpp:388:53:388:59 | source1 | test.cpp:392:8:392:10 | tmp |
| test.cpp:388:53:388:59 | source1 | test.cpp:394:10:394:12 | tmp |
| test.cpp:399:7:399:9 | tmp | test.cpp:401:8:401:10 | tmp |
| test.cpp:405:7:405:9 | tmp | test.cpp:408:8:408:10 | tmp |
| test.cpp:416:7:416:11 | local | test.cpp:418:8:418:12 | local |
| test.cpp:417:16:417:20 | ref arg local | test.cpp:418:8:418:12 | local |
| test.cpp:422:7:422:11 | local | test.cpp:424:8:424:12 | local |
| test.cpp:423:20:423:25 | ref arg & ... | test.cpp:424:8:424:12 | local |
| test.cpp:433:7:433:11 | local | test.cpp:435:8:435:12 | local |
| test.cpp:433:7:433:11 | local | test.cpp:436:8:436:13 | * ... |
| test.cpp:434:20:434:24 | ref arg local | test.cpp:435:8:435:12 | local |
| test.cpp:434:20:434:24 | ref arg local | test.cpp:436:8:436:13 | * ... |
| test.cpp:440:7:440:11 | local | test.cpp:442:8:442:12 | local |
| test.cpp:441:18:441:23 | ref arg & ... | test.cpp:442:8:442:12 | local |
| test.cpp:448:7:448:11 | local | test.cpp:450:8:450:12 | local |
| test.cpp:448:7:448:11 | local | test.cpp:451:8:451:13 | * ... |
| test.cpp:449:18:449:22 | ref arg local | test.cpp:450:8:450:12 | local |
| test.cpp:449:18:449:22 | ref arg local | test.cpp:451:8:451:13 | * ... |
| test.cpp:456:26:456:32 | source1 | test.cpp:457:9:457:22 | (statement expression) |
| test.cpp:456:26:456:32 | source1 | test.cpp:468:8:468:12 | local |
| test.cpp:472:8:472:13 | call to source | test.cpp:478:8:478:8 | x |
| test.cpp:506:8:506:13 | call to source | test.cpp:513:8:513:8 | x |
| test.cpp:517:7:517:16 | stackArray | test.cpp:521:8:521:20 | access to array |
| test.cpp:519:19:519:24 | call to source | test.cpp:521:8:521:20 | access to array |
| test.cpp:551:9:551:9 | y | test.cpp:541:10:541:10 | y |
| test.cpp:583:11:583:16 | call to source | test.cpp:590:8:590:8 | x |
| test.cpp:628:20:628:25 | ref arg buffer | test.cpp:629:17:629:22 | buffer |
| test.cpp:633:18:633:23 | call to source | test.cpp:634:8:634:8 | x |
| test.cpp:702:38:702:43 | source | test.cpp:695:8:695:10 | buf |
| test.cpp:726:11:726:16 | call to source | test.cpp:735:8:735:8 | x |
| test.cpp:733:7:733:7 | x | test.cpp:735:8:735:8 | x |
| test.cpp:749:27:749:32 | call to source | test.cpp:740:10:740:10 | x |
| test.cpp:751:27:751:32 | call to source | test.cpp:740:10:740:10 | x |
| test.cpp:753:32:753:37 | call to source | test.cpp:740:10:740:10 | x |
| test.cpp:755:32:755:37 | call to source | test.cpp:740:10:740:10 | x |
| test.cpp:769:27:769:32 | call to source | test.cpp:760:10:760:10 | x |
| test.cpp:771:27:771:32 | call to source | test.cpp:760:10:760:10 | x |
| test.cpp:773:32:773:37 | call to source | test.cpp:760:10:760:10 | x |
| test.cpp:775:32:775:37 | call to source | test.cpp:760:10:760:10 | x |
| test.cpp:788:31:788:36 | call to source | test.cpp:782:12:782:12 | x |
| test.cpp:790:31:790:36 | call to source | test.cpp:782:12:782:12 | x |
| test.cpp:797:22:797:28 | ref arg content | test.cpp:798:19:798:25 | content |
| test.cpp:842:11:842:16 | call to source | test.cpp:844:8:844:8 | y |
| test.cpp:846:13:846:27 | call to indirect_source | test.cpp:848:23:848:25 | rpx |
| test.cpp:860:54:860:59 | call to source | test.cpp:861:10:861:37 | static_local_pointer_dynamic |
| true_upon_entry.cpp:17:11:17:16 | call to source | true_upon_entry.cpp:21:8:21:8 | x |
| true_upon_entry.cpp:27:9:27:14 | call to source | true_upon_entry.cpp:29:8:29:8 | x |
| true_upon_entry.cpp:33:11:33:16 | call to source | true_upon_entry.cpp:39:8:39:8 | x |
| true_upon_entry.cpp:43:11:43:16 | call to source | true_upon_entry.cpp:49:8:49:8 | x |
| true_upon_entry.cpp:54:11:54:16 | call to source | true_upon_entry.cpp:57:8:57:8 | x |
| true_upon_entry.cpp:70:11:70:16 | call to source | true_upon_entry.cpp:78:8:78:8 | x |
| true_upon_entry.cpp:83:11:83:16 | call to source | true_upon_entry.cpp:86:8:86:8 | x |
irFlow
| BarrierGuard.cpp:5:19:5:24 | source | BarrierGuard.cpp:9:10:9:15 | source |
| BarrierGuard.cpp:13:17:13:22 | source | BarrierGuard.cpp:15:10:15:15 | source |
| BarrierGuard.cpp:21:17:21:22 | source | BarrierGuard.cpp:25:10:25:15 | source |
| BarrierGuard.cpp:29:16:29:21 | source | BarrierGuard.cpp:31:10:31:15 | source |
| BarrierGuard.cpp:29:16:29:21 | source | BarrierGuard.cpp:33:10:33:15 | source |
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:53:13:53:13 | x |
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:55:13:55:13 | x |
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:64:14:64:14 | x |
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:66:14:66:14 | x |
| acrossLinkTargets.cpp:19:27:19:32 | call to source | acrossLinkTargets.cpp:12:8:12:8 | x |
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:18:8:18:19 | sourceArray1 |
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:23:17:23:29 | & ... indirection |
| clang.cpp:29:27:29:32 | call to source | clang.cpp:30:27:30:28 | m1 |
| clang.cpp:29:27:29:32 | call to source | clang.cpp:31:27:31:34 | call to getFirst |
| clang.cpp:35:32:35:37 | call to source | clang.cpp:38:10:38:11 | m2 |
| clang.cpp:40:42:40:47 | call to source | clang.cpp:42:18:42:19 | m2 |
| clang.cpp:44:35:44:40 | call to source | clang.cpp:46:17:46:18 | m2 |
| clang.cpp:50:7:50:16 | definition of stackArray | clang.cpp:52:8:52:17 | stackArray |
| clang.cpp:50:25:50:30 | call to source | clang.cpp:53:17:53:26 | stackArray indirection |
| clang.cpp:50:35:50:40 | call to source | clang.cpp:53:17:53:26 | stackArray indirection |
| clang.cpp:51:19:51:24 | call to source | clang.cpp:53:17:53:26 | stackArray indirection |
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:35:16:35:25 | call to notSource1 |
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:43:15:43:24 | call to notSource1 |
| dispatch.cpp:10:37:10:42 | call to source | dispatch.cpp:36:16:36:25 | call to notSource2 |
| dispatch.cpp:10:37:10:42 | call to source | dispatch.cpp:44:15:44:24 | call to notSource2 |
| dispatch.cpp:16:37:16:42 | call to source | dispatch.cpp:32:16:32:24 | call to isSource2 |
| dispatch.cpp:16:37:16:42 | call to source | dispatch.cpp:40:15:40:23 | call to isSource2 |
| dispatch.cpp:22:37:22:42 | call to source | dispatch.cpp:31:16:31:24 | call to isSource1 |
| dispatch.cpp:22:37:22:42 | call to source | dispatch.cpp:39:15:39:23 | call to isSource1 |
| dispatch.cpp:22:37:22:42 | call to source | dispatch.cpp:55:22:55:30 | call to isSource1 |
| dispatch.cpp:22:37:22:42 | call to source | dispatch.cpp:58:28:58:36 | call to isSource1 |
| dispatch.cpp:33:18:33:23 | call to source | dispatch.cpp:23:38:23:38 | x |
| dispatch.cpp:37:19:37:24 | call to source | dispatch.cpp:11:38:11:38 | x |
| dispatch.cpp:41:17:41:22 | call to source | dispatch.cpp:23:38:23:38 | x |
| dispatch.cpp:45:18:45:23 | call to source | dispatch.cpp:11:38:11:38 | x |
| dispatch.cpp:69:15:69:20 | call to source | dispatch.cpp:23:38:23:38 | x |
| dispatch.cpp:73:14:73:19 | call to source | dispatch.cpp:23:38:23:38 | x |
| dispatch.cpp:81:13:81:18 | call to source | dispatch.cpp:23:38:23:38 | x |
| dispatch.cpp:107:17:107:22 | call to source | dispatch.cpp:96:8:96:8 | x |
| dispatch.cpp:140:8:140:13 | call to source | dispatch.cpp:96:8:96:8 | x |
| dispatch.cpp:144:8:144:13 | call to source | dispatch.cpp:96:8:96:8 | x |
| flowOut.cpp:5:16:5:21 | call to source | flowOut.cpp:19:9:19:9 | x |
| globals.cpp:5:17:5:22 | call to source | globals.cpp:6:10:6:14 | local |
| globals.cpp:13:23:13:28 | call to source | globals.cpp:12:10:12:24 | flowTestGlobal1 |
| globals.cpp:23:23:23:28 | call to source | globals.cpp:19:10:19:24 | flowTestGlobal2 |
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:14:8:14:8 | t |
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:18:8:18:8 | call to operator() |
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:21:8:21:8 | t |
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:29:8:29:8 | t |
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:35:8:35:8 | a |
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:41:8:41:8 | a |
| lambdas.cpp:43:7:43:12 | call to source | lambdas.cpp:46:7:46:7 | w |
| ref.cpp:29:11:29:16 | call to source | ref.cpp:62:10:62:11 | x3 |
| ref.cpp:53:9:53:10 | definition of x1 | ref.cpp:56:10:56:11 | x1 |
| ref.cpp:53:13:53:14 | definition of x2 | ref.cpp:59:10:59:11 | x2 |
| ref.cpp:53:17:53:18 | definition of x3 | ref.cpp:62:10:62:11 | x3 |
| ref.cpp:53:21:53:22 | definition of x4 | ref.cpp:65:10:65:11 | x4 |
| ref.cpp:55:23:55:28 | call to source | ref.cpp:56:10:56:11 | x1 |
| ref.cpp:94:15:94:20 | call to source | ref.cpp:129:13:129:15 | val |
| ref.cpp:109:15:109:20 | call to source | ref.cpp:132:13:132:15 | val |
| ref.cpp:122:23:122:28 | call to source | ref.cpp:123:13:123:15 | val |
| ref.cpp:125:19:125:24 | call to source | ref.cpp:126:13:126:15 | val |
| self-Iterator.cpp:19:23:19:30 | call to source | self-Iterator.cpp:20:10:20:10 | x |
| test.cpp:6:12:6:17 | call to source | test.cpp:7:8:7:9 | t1 |
| test.cpp:6:12:6:17 | call to source | test.cpp:9:8:9:9 | t1 |
| test.cpp:6:12:6:17 | call to source | test.cpp:10:8:10:9 | t2 |
| test.cpp:6:12:6:17 | call to source | test.cpp:15:8:15:9 | t2 |
| test.cpp:6:12:6:17 | call to source | test.cpp:26:8:26:9 | t1 |
| test.cpp:35:10:35:15 | call to source | test.cpp:30:8:30:8 | t |
| test.cpp:36:13:36:18 | call to source | test.cpp:31:8:31:8 | c |
| test.cpp:50:14:50:19 | call to source | test.cpp:58:10:58:10 | t |
| test.cpp:66:30:66:36 | source1 | test.cpp:71:8:71:9 | x4 |
| test.cpp:75:7:75:8 | definition of u1 | test.cpp:76:8:76:9 | u1 |
| test.cpp:83:7:83:8 | definition of u2 | test.cpp:84:8:84:18 | ... ? ... : ... |
| test.cpp:83:7:83:8 | definition of u2 | test.cpp:86:8:86:9 | i1 |
| test.cpp:89:28:89:34 | source1 indirection | test.cpp:90:8:90:14 | source1 |
| test.cpp:100:13:100:18 | call to source | test.cpp:103:10:103:12 | ref |
| test.cpp:138:27:138:32 | call to source | test.cpp:140:8:140:8 | y |
| test.cpp:151:33:151:38 | call to source | test.cpp:144:8:144:8 | s |
| test.cpp:151:33:151:38 | call to source | test.cpp:152:8:152:8 | y |
| test.cpp:164:34:164:39 | call to source | test.cpp:157:8:157:8 | x |
| test.cpp:164:34:164:39 | call to source | test.cpp:165:8:165:8 | y |
| test.cpp:171:11:171:16 | call to source | test.cpp:178:8:178:8 | y |
| test.cpp:245:14:245:19 | call to source | test.cpp:260:12:260:12 | x |
| test.cpp:265:22:265:27 | call to source | test.cpp:266:12:266:12 | x |
| test.cpp:305:17:305:22 | call to source | test.cpp:289:14:289:14 | x |
| test.cpp:314:4:314:9 | call to source | test.cpp:318:7:318:7 | x |
| test.cpp:333:17:333:22 | call to source | test.cpp:337:10:337:18 | globalVar |
| test.cpp:333:17:333:22 | call to source | test.cpp:339:10:339:18 | globalVar |
| test.cpp:333:17:333:22 | call to source | test.cpp:343:10:343:18 | globalVar |
| test.cpp:333:17:333:22 | call to source | test.cpp:349:10:349:18 | globalVar |
| test.cpp:347:17:347:22 | call to source | test.cpp:337:10:337:18 | globalVar |
| test.cpp:347:17:347:22 | call to source | test.cpp:339:10:339:18 | globalVar |
| test.cpp:347:17:347:22 | call to source | test.cpp:343:10:343:18 | globalVar |
| test.cpp:347:17:347:22 | call to source | test.cpp:349:10:349:18 | globalVar |
| test.cpp:359:13:359:18 | call to source | test.cpp:365:10:365:14 | field |
| test.cpp:373:13:373:18 | call to source | test.cpp:369:10:369:14 | field |
| test.cpp:373:13:373:18 | call to source | test.cpp:375:10:375:14 | field |
| test.cpp:382:48:382:54 | source1 | test.cpp:385:8:385:10 | tmp |
| test.cpp:388:53:388:59 | source1 | test.cpp:392:8:392:10 | tmp |
| test.cpp:388:53:388:59 | source1 | test.cpp:394:10:394:12 | tmp |
| test.cpp:399:7:399:9 | definition of tmp | test.cpp:401:8:401:10 | tmp |
| test.cpp:405:7:405:9 | definition of tmp | test.cpp:408:8:408:10 | tmp |
| test.cpp:416:7:416:11 | definition of local | test.cpp:418:8:418:12 | local |
| test.cpp:417:16:417:20 | intRefSource output argument | test.cpp:418:8:418:12 | local |
| test.cpp:422:7:422:11 | definition of local | test.cpp:424:8:424:12 | local |
| test.cpp:423:20:423:25 | intPointerSource output argument | test.cpp:424:8:424:12 | local |
| test.cpp:433:7:433:11 | definition of local | test.cpp:435:8:435:12 | local |
| test.cpp:434:20:434:24 | intPointerSource output argument | test.cpp:436:8:436:13 | * ... |
| test.cpp:440:7:440:11 | definition of local | test.cpp:442:8:442:12 | local |
| test.cpp:441:18:441:23 | intArraySource output argument | test.cpp:442:8:442:12 | local |
| test.cpp:448:7:448:11 | definition of local | test.cpp:450:8:450:12 | local |
| test.cpp:449:18:449:22 | intArraySource output argument | test.cpp:451:8:451:13 | * ... |
| test.cpp:456:26:456:32 | source1 | test.cpp:457:9:457:22 | (statement expression) |
| test.cpp:456:26:456:32 | source1 | test.cpp:468:8:468:12 | local |
| test.cpp:472:8:472:13 | call to source | test.cpp:478:8:478:8 | x |
| test.cpp:506:8:506:13 | call to source | test.cpp:513:8:513:8 | x |
| test.cpp:519:19:519:24 | call to source | test.cpp:521:8:521:20 | access to array |
| test.cpp:531:29:531:34 | call to source | test.cpp:532:8:532:9 | * ... |
| test.cpp:547:9:547:9 | definition of x | test.cpp:536:10:536:11 | * ... |
| test.cpp:551:9:551:9 | definition of y | test.cpp:541:10:541:10 | y |
| test.cpp:562:17:562:31 | call to indirect_source indirection | test.cpp:566:10:566:19 | * ... |
| test.cpp:562:17:562:31 | call to indirect_source indirection | test.cpp:568:10:568:19 | * ... |
| test.cpp:562:17:562:31 | call to indirect_source indirection | test.cpp:572:10:572:19 | * ... |
| test.cpp:562:17:562:31 | call to indirect_source indirection | test.cpp:578:10:578:19 | * ... |
| test.cpp:576:17:576:31 | call to indirect_source indirection | test.cpp:566:10:566:19 | * ... |
| test.cpp:576:17:576:31 | call to indirect_source indirection | test.cpp:568:10:568:19 | * ... |
| test.cpp:576:17:576:31 | call to indirect_source indirection | test.cpp:572:10:572:19 | * ... |
| test.cpp:576:17:576:31 | call to indirect_source indirection | test.cpp:578:10:578:19 | * ... |
| test.cpp:594:12:594:26 | call to indirect_source indirection | test.cpp:597:8:597:13 | * ... |
| test.cpp:601:20:601:20 | intPointerSource output argument | test.cpp:603:8:603:9 | * ... |
| test.cpp:607:20:607:20 | intPointerSource output argument | test.cpp:609:8:609:9 | * ... |
| test.cpp:614:20:614:20 | intPointerSource output argument | test.cpp:616:8:616:17 | * ... |
| test.cpp:628:20:628:25 | intPointerSource output argument | test.cpp:629:17:629:22 | buffer indirection |
| test.cpp:633:18:633:23 | call to source | test.cpp:634:8:634:8 | x |
| test.cpp:646:7:646:12 | call to source | test.cpp:645:8:645:8 | x |
| test.cpp:660:7:660:12 | call to source | test.cpp:658:8:658:8 | x |
| test.cpp:664:18:664:23 | call to source | test.cpp:666:8:666:16 | * ... |
| test.cpp:681:7:681:12 | call to source | test.cpp:679:8:679:16 | * ... |
| test.cpp:733:7:733:7 | definition of x | test.cpp:735:8:735:8 | x |
| test.cpp:751:27:751:32 | call to source | test.cpp:740:10:740:10 | x |
| test.cpp:753:32:753:37 | call to source | test.cpp:740:10:740:10 | x |
| test.cpp:755:32:755:37 | call to source | test.cpp:740:10:740:10 | x |
| test.cpp:771:27:771:32 | call to source | test.cpp:760:10:760:10 | x |
| test.cpp:773:32:773:37 | call to source | test.cpp:760:10:760:10 | x |
| test.cpp:775:32:775:37 | call to source | test.cpp:760:10:760:10 | x |
| test.cpp:788:31:788:36 | call to source | test.cpp:782:12:782:12 | x |
| test.cpp:790:31:790:36 | call to source | test.cpp:782:12:782:12 | x |
| test.cpp:797:22:797:28 | intPointerSource output argument | test.cpp:798:19:798:25 | content indirection |
| test.cpp:808:25:808:39 | call to indirect_source indirection | test.cpp:813:19:813:35 | * ... indirection |
| test.cpp:818:26:818:31 | call to source | test.cpp:823:10:823:27 | * ... |
| test.cpp:832:21:832:26 | call to source | test.cpp:836:10:836:22 | global_direct |
| test.cpp:842:11:842:16 | call to source | test.cpp:844:8:844:8 | y |
| test.cpp:846:13:846:27 | call to indirect_source indirection | test.cpp:848:17:848:25 | rpx indirection |
| test.cpp:853:55:853:62 | call to source | test.cpp:854:10:854:36 | * ... |
| test.cpp:860:54:860:59 | call to source | test.cpp:861:10:861:37 | static_local_pointer_dynamic |
| test.cpp:872:46:872:51 | call to source | test.cpp:875:10:875:31 | global_pointer_dynamic |
| test.cpp:880:64:880:83 | indirect_source(1) indirection | test.cpp:883:10:883:45 | static_local_array_static_indirect_1 |
| test.cpp:881:64:881:83 | indirect_source(2) indirection | test.cpp:886:19:886:54 | static_local_array_static_indirect_2 indirection |
| test.cpp:890:54:890:61 | source | test.cpp:893:10:893:36 | static_local_pointer_static |
| test.cpp:891:65:891:84 | indirect_source(1) indirection | test.cpp:895:19:895:56 | static_local_pointer_static_indirect_1 indirection |
| test.cpp:901:56:901:75 | indirect_source(1) indirection | test.cpp:907:10:907:39 | global_array_static_indirect_1 |
| test.cpp:902:56:902:75 | indirect_source(2) indirection | test.cpp:911:19:911:48 | global_array_static_indirect_2 indirection |
| test.cpp:914:46:914:53 | source | test.cpp:919:10:919:30 | global_pointer_static |
| test.cpp:915:57:915:76 | indirect_source(1) indirection | test.cpp:921:19:921:50 | global_pointer_static_indirect_1 indirection |
| true_upon_entry.cpp:9:11:9:16 | call to source | true_upon_entry.cpp:13:8:13:8 | x |
| true_upon_entry.cpp:17:11:17:16 | call to source | true_upon_entry.cpp:21:8:21:8 | x |
| true_upon_entry.cpp:27:9:27:14 | call to source | true_upon_entry.cpp:29:8:29:8 | x |
| true_upon_entry.cpp:33:11:33:16 | call to source | true_upon_entry.cpp:39:8:39:8 | x |
| true_upon_entry.cpp:43:11:43:16 | call to source | true_upon_entry.cpp:49:8:49:8 | x |
| true_upon_entry.cpp:54:11:54:16 | call to source | true_upon_entry.cpp:57:8:57:8 | x |
| true_upon_entry.cpp:62:11:62:16 | call to source | true_upon_entry.cpp:66:8:66:8 | x |
| true_upon_entry.cpp:70:11:70:16 | call to source | true_upon_entry.cpp:78:8:78:8 | x |
| true_upon_entry.cpp:83:11:83:16 | call to source | true_upon_entry.cpp:86:8:86:8 | x |
| true_upon_entry.cpp:98:11:98:16 | call to source | true_upon_entry.cpp:105:8:105:8 | x |

View File

@@ -0,0 +1,9 @@
import TestBase
query predicate astFlow(AstTest::DataFlow::Node source, AstTest::DataFlow::Node sink) {
AstTest::AstFlow::flow(source, sink)
}
query predicate irFlow(IRTest::DataFlow::Node source, IRTest::DataFlow::Node sink) {
IRTest::IRFlow::flow(source, sink)
}

View File

@@ -1,5 +1,5 @@
int source(); int source();
void sink(int); void sink(const int *); void sink(int **); void indirect_sink(...); void sink(...); void indirect_sink(...);
void intraprocedural_with_local_flow() { void intraprocedural_with_local_flow() {
int t2; int t2;
@@ -796,4 +796,130 @@ void test() {
MyStruct a; MyStruct a;
intPointerSource(a.content, a.content); intPointerSource(a.content, a.content);
indirect_sink(a.content); // $ ast ir indirect_sink(a.content); // $ ast ir
}
namespace MoreGlobalTests {
int **global_indirect1;
int **global_indirect2;
int **global_direct;
void set_indirect1()
{
*global_indirect1 = indirect_source();
}
void read_indirect1() {
sink(global_indirect1); // clean
indirect_sink(*global_indirect1); // $ ir MISSING: ast
}
void set_indirect2()
{
**global_indirect2 = source();
}
void read_indirect2() {
sink(global_indirect2); // clean
sink(**global_indirect2); // $ ir MISSING: ast
}
// overload source with a boolean parameter so
// that we can define a variant that return an int**.
int** source(bool);
void set_direct()
{
global_direct = source(true);
}
void read_direct() {
sink(global_direct); // $ ir MISSING: ast
indirect_sink(global_direct); // clean
}
}
void test_references() {
int x = source();
int &y = x;
sink(y); // $ ast,ir
int* px = indirect_source();
int*& rpx = px;
indirect_sink((int*)rpx); // $ ast,ir
}
namespace GlobalArrays {
void test1() {
static const int static_local_array_dynamic[] = { ::source() };
sink(*static_local_array_dynamic); // $ ir MISSING: ast
}
const int* source(bool);
void test2() {
static const int* static_local_pointer_dynamic = source(true);
sink(static_local_pointer_dynamic); // $ ast,ir
}
static const int global_array_dynamic[] = { ::source() };
void test3() {
sink(*global_array_dynamic); // $ MISSING: ir,ast // Missing in IR because no 'IRFunction' for global_array is generated because the type of global_array_dynamic is "deeply const".
}
const int* source(bool);
static const int* global_pointer_dynamic = source(true);
void test4() {
sink(global_pointer_dynamic); // $ ir MISSING: ast
}
void test5() {
static const char static_local_array_static[] = "source";
static const char static_local_array_static_indirect_1[] = "indirect_source(1)";
static const char static_local_array_static_indirect_2[] = "indirect_source(2)";
sink(static_local_array_static); // clean
sink(static_local_array_static_indirect_1); // $ ir MISSING: ast
indirect_sink(static_local_array_static_indirect_1); // clean
sink(static_local_array_static_indirect_2); // clean
indirect_sink(static_local_array_static_indirect_2); // $ ir MISSING: ast
}
void test6() {
static const char* static_local_pointer_static = "source";
static const char* static_local_pointer_static_indirect_1 = "indirect_source(1)";
static const char* static_local_pointer_static_indirect_2 = "indirect_source(2)";
sink(static_local_pointer_static); // $ ir MISSING: ast
sink(static_local_pointer_static_indirect_1); // clean
indirect_sink(static_local_pointer_static_indirect_1); // $ ir MISSING: ast
sink(static_local_pointer_static_indirect_2); // clean: static_local_pointer_static_indirect_2 does not have 2 indirections
indirect_sink(static_local_pointer_static_indirect_2); // clean: static_local_pointer_static_indirect_2 does not have 2 indirections
}
static const char global_array_static[] = "source";
static const char global_array_static_indirect_1[] = "indirect_source(1)";
static const char global_array_static_indirect_2[] = "indirect_source(2)";
void test7() {
sink(global_array_static); // clean
sink(*global_array_static); // clean
sink(global_array_static_indirect_1); // $ ir MISSING: ast
sink(*global_array_static_indirect_1); // clean
indirect_sink(global_array_static); // clean
indirect_sink(global_array_static_indirect_1); // clean
indirect_sink(global_array_static_indirect_2); // $ ir MISSING: ast
}
static const char* global_pointer_static = "source";
static const char* global_pointer_static_indirect_1 = "indirect_source(1)";
static const char* global_pointer_static_indirect_2 = "indirect_source(2)";
void test8() {
sink(global_pointer_static); // $ ir MISSING: ast
sink(global_pointer_static_indirect_1); // clean
indirect_sink(global_pointer_static_indirect_1); // $ ir MISSING: ast
sink(global_pointer_static_indirect_2); // clean: global_pointer_static_indirect_2 does not have 2 indirections
indirect_sink(global_pointer_static_indirect_2); // clean: global_pointer_static_indirect_2 does not have 2 indirections
}
} }

View File

@@ -1,9 +1,2 @@
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:19,45-53)
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:20,24-32)
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:27,15-23)
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:33,22-30)
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:40,25-33)
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:42,17-25)
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:46,20-28)
testFailures testFailures
failures failures

View File

@@ -1,107 +1,3 @@
import TestBase
import TestUtilities.dataflow.FlowTestCommon import TestUtilities.dataflow.FlowTestCommon
module AstTest {
private import semmle.code.cpp.dataflow.DataFlow
private import semmle.code.cpp.controlflow.Guards
/**
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement
* S in `if (guarded(x)) S`.
*/
// This is tested in `BarrierGuard.cpp`.
predicate testBarrierGuard(GuardCondition g, Expr checked, boolean isTrue) {
g.(FunctionCall).getTarget().getName() = "guarded" and
checked = g.(FunctionCall).getArgument(0) and
isTrue = true
}
/** Common data flow configuration to be used by tests. */
module AstTestAllocationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
or
source.asParameter().getName().matches("source%")
or
source.asExpr().(FunctionCall).getTarget().getName() = "indirect_source"
or
source.(DataFlow::DefinitionByReferenceNode).getParameter().getName().matches("ref_source%")
or
// Track uninitialized variables
exists(source.asUninitialized())
}
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call |
call.getTarget().getName() = ["sink", "indirect_sink"] and
sink.asExpr() = call.getAnArgument()
)
}
predicate isBarrier(DataFlow::Node barrier) {
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier") or
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
}
}
module AstFlow = DataFlow::Global<AstTestAllocationConfig>;
}
module IRTest {
private import cpp
private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.controlflow.IRGuards
/**
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement
* S in `if (guarded(x)) S`.
*/
// This is tested in `BarrierGuard.cpp`.
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean isTrue) {
exists(Call call |
call = g.getUnconvertedResultExpression() and
call.getTarget().hasName("guarded") and
checked = call.getArgument(0) and
isTrue = true
)
}
/** Common data flow configuration to be used by tests. */
module IRTestAllocationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
or
source.asIndirectExpr(1).(FunctionCall).getTarget().getName() = "indirect_source"
or
source.asParameter().getName().matches("source%")
or
source.(DataFlow::DefinitionByReferenceNode).getParameter().getName().matches("ref_source%")
or
exists(source.asUninitialized())
}
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call, Expr e | e = call.getAnArgument() |
call.getTarget().getName() = "sink" and
sink.asExpr() = e
or
call.getTarget().getName() = "indirect_sink" and
sink.asIndirectExpr() = e
)
}
predicate isBarrier(DataFlow::Node barrier) {
exists(Expr barrierExpr | barrierExpr in [barrier.asExpr(), barrier.asIndirectExpr()] |
barrierExpr.(VariableAccess).getTarget().hasName("barrier")
)
or
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
or
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getAnIndirectBarrierNode()
}
}
module IRFlow = DataFlow::Global<IRTestAllocationConfig>;
}
import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>> import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>>

View File

@@ -1,2 +1,2 @@
failures
testFailures testFailures
failures

View File

@@ -6646,6 +6646,17 @@ WARNING: Module TaintTracking has been deprecated and may be removed in future (
| taint.cpp:738:17:738:31 | call to indirect_source | taint.cpp:739:30:739:35 | source | | | taint.cpp:738:17:738:31 | call to indirect_source | taint.cpp:739:30:739:35 | source | |
| taint.cpp:739:22:739:28 | call to realloc | taint.cpp:740:7:740:10 | dest | | | taint.cpp:739:22:739:28 | call to realloc | taint.cpp:740:7:740:10 | dest | |
| taint.cpp:739:30:739:35 | source | taint.cpp:739:22:739:28 | call to realloc | TAINT | | taint.cpp:739:30:739:35 | source | taint.cpp:739:22:739:28 | call to realloc | TAINT |
| taint.cpp:743:40:743:45 | buffer | taint.cpp:744:5:744:10 | buffer | |
| taint.cpp:743:40:743:45 | buffer | taint.cpp:745:27:745:32 | buffer | |
| taint.cpp:744:4:744:10 | * ... | taint.cpp:744:3:744:10 | * ... | TAINT |
| taint.cpp:744:5:744:10 | buffer | taint.cpp:744:4:744:10 | * ... | TAINT |
| taint.cpp:744:14:744:19 | call to source | taint.cpp:744:3:744:21 | ... = ... | |
| taint.cpp:745:19:745:25 | call to realloc | taint.cpp:743:40:743:45 | buffer | |
| taint.cpp:745:19:745:25 | call to realloc | taint.cpp:745:3:745:37 | ... = ... | |
| taint.cpp:745:19:745:25 | call to realloc | taint.cpp:746:10:746:15 | buffer | |
| taint.cpp:745:27:745:32 | buffer | taint.cpp:745:19:745:25 | call to realloc | TAINT |
| taint.cpp:746:9:746:15 | * ... | taint.cpp:746:8:746:15 | * ... | TAINT |
| taint.cpp:746:10:746:15 | buffer | taint.cpp:746:9:746:15 | * ... | TAINT |
| vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | | | vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | |
| vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | | | vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | |
| vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | | | vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | |

View File

@@ -738,4 +738,10 @@ void test_realloc() {
char *source = indirect_source(); char *source = indirect_source();
char *dest = (char*)realloc(source, 16); char *dest = (char*)realloc(source, 16);
sink(dest); // $ ir MISSING: ast sink(dest); // $ ir MISSING: ast
}
void test_realloc_2_indirections(int **buffer) {
**buffer = source();
buffer = (int**)realloc(buffer, 16);
sink(**buffer); // $ ir MISSING: ast
} }

View File

@@ -2,7 +2,6 @@ import cpp
import codeql.rangeanalysis.ModulusAnalysis import codeql.rangeanalysis.ModulusAnalysis
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticLocation import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticLocation
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisImpl import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisImpl
@@ -10,9 +9,7 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import semmle.code.cpp.ir.IR as IR import semmle.code.cpp.ir.IR as IR
import TestUtilities.InlineExpectationsTest import TestUtilities.InlineExpectationsTest
module ModulusAnalysisInstantiated = module ModulusAnalysisInstantiated = ModulusAnalysis<SemLocation, Sem, FloatDelta, ConstantBounds>;
ModulusAnalysis<SemLocation, Sem, FloatDelta, ConstantBounds,
RangeUtil<FloatDelta, CppLangImplRelative>>;
module ModulusAnalysisTest implements TestSig { module ModulusAnalysisTest implements TestSig {
string getARelevantTag() { result = "mod" } string getARelevantTag() { result = "mod" }

View File

@@ -18,7 +18,7 @@ int test2(struct List* p) {
int count = 0; int count = 0;
for (; p; p = p->next) { for (; p; p = p->next) {
count = (count+1) % 10; count = (count+1) % 10;
range(count); // $ range=<=9 range=>=-9 range="<=Phi: p | Store: count+1" range(count); // $ range=<=9 range=>=-9
} }
range(count); // $ range=>=-9 range=<=9 range(count); // $ range=>=-9 range=<=9
return count; return count;
@@ -29,7 +29,7 @@ int test3(struct List* p) {
for (; p; p = p->next) { for (; p; p = p->next) {
range(count++); // $ range=>=-9 range=<=9 range(count++); // $ range=>=-9 range=<=9
count = count % 10; count = count % 10;
range(count); // $ range=<=9 range=>=-9 range="<=Store: ... +++0" range="<=Phi: p | Store: count+1" range(count); // $ range=<=9 range=>=-9
} }
range(count); // $ range=>=-9 range=<=9 range(count); // $ range=>=-9 range=<=9
return count; return count;
@@ -317,7 +317,7 @@ int test_mult01(int a, int b) {
range(b); // $ range=<=23 range=>=-13 range(b); // $ range=<=23 range=>=-13
int r = a*b; // $ overflow=+- -143 .. 253 int r = a*b; // $ overflow=+- -143 .. 253
range(r); range(r);
total += r; // $ overflow=+ total += r; // $ overflow=+-
range(total); // $ MISSING: range=">=... * ...+0" range(total); // $ MISSING: range=">=... * ...+0"
} }
if (3 <= a && a <= 11 && -13 <= b && b <= 0) { if (3 <= a && a <= 11 && -13 <= b && b <= 0) {
@@ -365,7 +365,7 @@ int test_mult02(int a, int b) {
range(b); // $ range=<=23 range=>=-13 range(b); // $ range=<=23 range=>=-13
int r = a*b; // $ overflow=+- -143 .. 253 int r = a*b; // $ overflow=+- -143 .. 253
range(r); range(r);
total += r; // $ overflow=+ total += r; // $ overflow=+-
range(total); // $ MISSING: range=">=... * ...+0" range(total); // $ MISSING: range=">=... * ...+0"
} }
if (0 <= a && a <= 11 && -13 <= b && b <= 0) { if (0 <= a && a <= 11 && -13 <= b && b <= 0) {
@@ -460,7 +460,7 @@ int test_mult04(int a, int b) {
range(b); // $ range=<=23 range=>=-13 range(b); // $ range=<=23 range=>=-13
int r = a*b; // $ overflow=+- -391 .. 221 int r = a*b; // $ overflow=+- -391 .. 221
range(r); range(r);
total += r; // $ overflow=- total += r; // $ overflow=+-
range(total); // $ MISSING: range="<=... * ...+0" range(total); // $ MISSING: range="<=... * ...+0"
} }
if (-17 <= a && a <= 0 && -13 <= b && b <= 0) { if (-17 <= a && a <= 0 && -13 <= b && b <= 0) {
@@ -508,7 +508,7 @@ int test_mult05(int a, int b) {
range(b); // $ range=<=23 range=>=-13 range(b); // $ range=<=23 range=>=-13
int r = a*b; // $ overflow=+- -391 .. 221 int r = a*b; // $ overflow=+- -391 .. 221
range(r); range(r);
total += r; // $ overflow=- total += r; // $ overflow=+-
range(total); // $ MISSING: range="<=... * ...+0" range(total); // $ MISSING: range="<=... * ...+0"
} }
if (-17 <= a && a <= -2 && -13 <= b && b <= 0) { if (-17 <= a && a <= -2 && -13 <= b && b <= 0) {
@@ -974,7 +974,7 @@ void test_mod_neg(int s) {
void test_mod_ternary(int s, bool b) { void test_mod_ternary(int s, bool b) {
int s2 = s % (b ? 5 : 500); int s2 = s % (b ? 5 : 500);
range(s2); // $ range=>=-499 range=<=499 range="<=Phi: ... ? ... : ...-1" range(s2); // $ range=>=-499 range=<=499
} }
void test_mod_ternary2(int s, bool b1, bool b2) { void test_mod_ternary2(int s, bool b1, bool b2) {

View File

@@ -130,3 +130,19 @@ void test_div(int x) {
range(x >> 2); // $ range=>=0 range=<=2 range(x >> 2); // $ range=>=0 range=<=2
} }
} }
struct X { int n; };
void read_argument(const X *);
// This test exists purely to ensure that modulus analysis terminates in the
// presence of inexact phi operands. The LoadInstruction on `while(x->n) { ... }`
// reads from a PhiInstruction with two input operands: an exact operand defined
// by the StoreInstruction generated by `x->n--` and an inexact operand coming
// from the WriteSideEffect generated by `read_argument(x)`. If we don't consider
// the inexact operand modulus analysis fails to terminate.
void nonterminating_without_operands_as_ssa(X *x) {
read_argument(x);
while (x->n) {
x->n--;
}
}

View File

@@ -1,15 +1,13 @@
import cpp import cpp
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.SignAnalysisCommon import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.SignAnalysisCommon
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import semmle.code.cpp.ir.IR as IR import semmle.code.cpp.ir.IR as IR
import TestUtilities.InlineExpectationsTest import TestUtilities.InlineExpectationsTest
module SignAnalysisInstantiated = module SignAnalysisInstantiated = SignAnalysis<FloatDelta>;
SignAnalysis<FloatDelta, RangeUtil<FloatDelta, CppLangImplRelative>>;
module SignAnalysisTest implements TestSig { module SignAnalysisTest implements TestSig {
string getARelevantTag() { result = "sign" } string getARelevantTag() { result = "sign" }

View File

@@ -4,7 +4,12 @@ uniqueType
uniqueNodeLocation uniqueNodeLocation
missingLocation missingLocation
uniqueNodeToString uniqueNodeToString
| cpp11.cpp:50:15:50:16 | (no string representation) | Node should have one toString but has 0. | | builtin.c:5:5:5:11 | (no string representation) | Node should have one toString but has 0. |
| misc.c:227:7:227:28 | (no string representation) | Node should have one toString but has 0. |
| static_init_templates.cpp:80:18:80:23 | (no string representation) | Node should have one toString but has 0. |
| static_init_templates.cpp:80:18:80:23 | (no string representation) | Node should have one toString but has 0. |
| static_init_templates.cpp:89:18:89:23 | (no string representation) | Node should have one toString but has 0. |
| static_init_templates.cpp:89:18:89:23 | (no string representation) | Node should have one toString but has 0. |
parameterCallable parameterCallable
localFlowIsLocal localFlowIsLocal
readStepIsLocal readStepIsLocal

View File

@@ -43,6 +43,11 @@ edges
| test.cpp:189:16:189:16 | p | test.cpp:189:16:189:16 | (reference to) | | test.cpp:189:16:189:16 | p | test.cpp:189:16:189:16 | (reference to) |
| test.cpp:190:10:190:13 | (reference dereference) | test.cpp:190:10:190:13 | (reference to) | | test.cpp:190:10:190:13 | (reference dereference) | test.cpp:190:10:190:13 | (reference to) |
| test.cpp:190:10:190:13 | pRef | test.cpp:190:10:190:13 | (reference dereference) | | test.cpp:190:10:190:13 | pRef | test.cpp:190:10:190:13 | (reference dereference) |
| test.cpp:237:12:237:17 | call to alloca | test.cpp:237:12:237:17 | call to alloca |
| test.cpp:237:12:237:17 | call to alloca | test.cpp:238:9:238:9 | p |
| test.cpp:249:13:249:20 | call to strndupa | test.cpp:249:13:249:20 | call to strndupa |
| test.cpp:249:13:249:20 | call to strndupa | test.cpp:250:9:250:10 | s2 |
| test.cpp:250:9:250:10 | s2 | test.cpp:250:9:250:10 | (void *)... |
nodes nodes
| test.cpp:17:9:17:11 | & ... | semmle.label | & ... | | test.cpp:17:9:17:11 | & ... | semmle.label | & ... |
| test.cpp:17:10:17:11 | mc | semmle.label | mc | | test.cpp:17:10:17:11 | mc | semmle.label | mc |
@@ -101,6 +106,14 @@ nodes
| test.cpp:190:10:190:13 | (reference dereference) | semmle.label | (reference dereference) | | test.cpp:190:10:190:13 | (reference dereference) | semmle.label | (reference dereference) |
| test.cpp:190:10:190:13 | (reference to) | semmle.label | (reference to) | | test.cpp:190:10:190:13 | (reference to) | semmle.label | (reference to) |
| test.cpp:190:10:190:13 | pRef | semmle.label | pRef | | test.cpp:190:10:190:13 | pRef | semmle.label | pRef |
| test.cpp:237:12:237:17 | call to alloca | semmle.label | call to alloca |
| test.cpp:237:12:237:17 | call to alloca | semmle.label | call to alloca |
| test.cpp:238:9:238:9 | p | semmle.label | p |
| test.cpp:245:9:245:15 | call to strdupa | semmle.label | call to strdupa |
| test.cpp:249:13:249:20 | call to strndupa | semmle.label | call to strndupa |
| test.cpp:249:13:249:20 | call to strndupa | semmle.label | call to strndupa |
| test.cpp:250:9:250:10 | (void *)... | semmle.label | (void *)... |
| test.cpp:250:9:250:10 | s2 | semmle.label | s2 |
#select #select
| test.cpp:17:9:17:11 | CopyValue: & ... | test.cpp:17:10:17:11 | mc | test.cpp:17:9:17:11 | & ... | May return stack-allocated memory from $@. | test.cpp:17:10:17:11 | mc | mc | | test.cpp:17:9:17:11 | CopyValue: & ... | test.cpp:17:10:17:11 | mc | test.cpp:17:9:17:11 | & ... | May return stack-allocated memory from $@. | test.cpp:17:10:17:11 | mc | mc |
| test.cpp:25:9:25:11 | Load: ptr | test.cpp:23:18:23:19 | mc | test.cpp:25:9:25:11 | ptr | May return stack-allocated memory from $@. | test.cpp:23:18:23:19 | mc | mc | | test.cpp:25:9:25:11 | Load: ptr | test.cpp:23:18:23:19 | mc | test.cpp:25:9:25:11 | ptr | May return stack-allocated memory from $@. | test.cpp:23:18:23:19 | mc | mc |
@@ -115,3 +128,6 @@ nodes
| test.cpp:177:10:177:23 | Convert: (void *)... | test.cpp:176:25:176:34 | localArray | test.cpp:177:10:177:23 | (void *)... | May return stack-allocated memory from $@. | test.cpp:176:25:176:34 | localArray | localArray | | test.cpp:177:10:177:23 | Convert: (void *)... | test.cpp:176:25:176:34 | localArray | test.cpp:177:10:177:23 | (void *)... | May return stack-allocated memory from $@. | test.cpp:176:25:176:34 | localArray | localArray |
| test.cpp:183:10:183:19 | CopyValue: (reference to) | test.cpp:182:21:182:27 | myLocal | test.cpp:183:10:183:19 | (reference to) | May return stack-allocated memory from $@. | test.cpp:182:21:182:27 | myLocal | myLocal | | test.cpp:183:10:183:19 | CopyValue: (reference to) | test.cpp:182:21:182:27 | myLocal | test.cpp:183:10:183:19 | (reference to) | May return stack-allocated memory from $@. | test.cpp:182:21:182:27 | myLocal | myLocal |
| test.cpp:190:10:190:13 | CopyValue: (reference to) | test.cpp:189:16:189:16 | p | test.cpp:190:10:190:13 | (reference to) | May return stack-allocated memory from $@. | test.cpp:189:16:189:16 | p | p | | test.cpp:190:10:190:13 | CopyValue: (reference to) | test.cpp:189:16:189:16 | p | test.cpp:190:10:190:13 | (reference to) | May return stack-allocated memory from $@. | test.cpp:189:16:189:16 | p | p |
| test.cpp:238:9:238:9 | Load: p | test.cpp:237:12:237:17 | call to alloca | test.cpp:238:9:238:9 | p | May return stack-allocated memory from $@. | test.cpp:237:12:237:17 | call to alloca | call to alloca |
| test.cpp:245:9:245:15 | Call: call to strdupa | test.cpp:245:9:245:15 | call to strdupa | test.cpp:245:9:245:15 | call to strdupa | May return stack-allocated memory from $@. | test.cpp:245:9:245:15 | call to strdupa | call to strdupa |
| test.cpp:250:9:250:10 | Convert: (void *)... | test.cpp:249:13:249:20 | call to strndupa | test.cpp:250:9:250:10 | (void *)... | May return stack-allocated memory from $@. | test.cpp:249:13:249:20 | call to strndupa | call to strndupa |

View File

@@ -229,4 +229,23 @@ int* id(int* px) {
void f() { void f() {
int x; int x;
int* px = id(&x); // GOOD int* px = id(&x); // GOOD
}
void *alloca(size_t);
void* test_alloca() {
void* p = alloca(10);
return p; // BAD
}
char *strdupa(const char *);
char *strndupa(const char *, size_t);
char* test_strdupa(const char* s) {
return strdupa(s); // BAD
}
void* test_strndupa(const char* s, size_t size) {
char* s2 = strndupa(s, size);
return s2; // BAD
} }

View File

@@ -1,23 +1,12 @@
edges edges
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data | | test.cpp:37:73:37:76 | data indirection | test.cpp:43:32:43:35 | data indirection |
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data | | test.cpp:64:30:64:35 | call to getenv indirection | test.cpp:73:24:73:27 | data indirection |
| test.cpp:37:73:37:76 | data indirection | test.cpp:43:32:43:35 | data |
| test.cpp:37:73:37:76 | data indirection | test.cpp:43:32:43:35 | data |
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data |
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data |
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data indirection |
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data indirection |
| test.cpp:73:24:73:27 | data | test.cpp:37:73:37:76 | data |
| test.cpp:73:24:73:27 | data indirection | test.cpp:37:73:37:76 | data indirection | | test.cpp:73:24:73:27 | data indirection | test.cpp:37:73:37:76 | data indirection |
subpaths
nodes nodes
| test.cpp:37:73:37:76 | data | semmle.label | data |
| test.cpp:37:73:37:76 | data indirection | semmle.label | data indirection | | test.cpp:37:73:37:76 | data indirection | semmle.label | data indirection |
| test.cpp:43:32:43:35 | data | semmle.label | data | | test.cpp:43:32:43:35 | data indirection | semmle.label | data indirection |
| test.cpp:43:32:43:35 | data | semmle.label | data | | test.cpp:64:30:64:35 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv |
| test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv |
| test.cpp:73:24:73:27 | data | semmle.label | data |
| test.cpp:73:24:73:27 | data indirection | semmle.label | data indirection | | test.cpp:73:24:73:27 | data indirection | semmle.label | data indirection |
subpaths
#select #select
| test.cpp:43:32:43:35 | data | test.cpp:64:30:64:35 | call to getenv | test.cpp:43:32:43:35 | data | The value of this argument may come from $@ and is being passed to LoadLibraryA. | test.cpp:64:30:64:35 | call to getenv | call to getenv | | test.cpp:43:32:43:35 | data indirection | test.cpp:64:30:64:35 | call to getenv indirection | test.cpp:43:32:43:35 | data indirection | The value of this argument may come from $@ and is being passed to LoadLibraryA. | test.cpp:64:30:64:35 | call to getenv indirection | an environment variable |

View File

@@ -1,103 +1,45 @@
edges edges
| test.cpp:24:30:24:36 | command | test.cpp:26:10:26:16 | command | | test.cpp:24:30:24:36 | command indirection | test.cpp:26:10:26:16 | command indirection |
| test.cpp:24:30:24:36 | command | test.cpp:26:10:26:16 | command | | test.cpp:29:30:29:36 | command indirection | test.cpp:31:10:31:16 | command indirection |
| test.cpp:29:30:29:36 | command | test.cpp:31:10:31:16 | command | | test.cpp:42:18:42:34 | call to getenv indirection | test.cpp:24:30:24:36 | command indirection |
| test.cpp:29:30:29:36 | command | test.cpp:31:10:31:16 | command | | test.cpp:43:18:43:34 | call to getenv indirection | test.cpp:29:30:29:36 | command indirection |
| test.cpp:42:18:42:23 | call to getenv | test.cpp:24:30:24:36 | command | | test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer indirection |
| test.cpp:42:18:42:34 | call to getenv | test.cpp:24:30:24:36 | command | | test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data indirection |
| test.cpp:43:18:43:23 | call to getenv | test.cpp:29:30:29:36 | command | | test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | dataref indirection |
| test.cpp:43:18:43:34 | call to getenv | test.cpp:29:30:29:36 | command | | test.cpp:56:12:56:17 | fgets output argument | test.cpp:65:10:65:14 | data2 indirection |
| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer | | test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer indirection |
| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer | | test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer indirection |
| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer | | test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer indirection |
| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer | | test.cpp:113:8:113:12 | call to fgets indirection | test.cpp:114:9:114:11 | ptr indirection |
| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data |
| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data |
| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data |
| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data |
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
| test.cpp:56:12:56:17 | buffer | test.cpp:65:10:65:14 | data2 |
| test.cpp:56:12:56:17 | buffer | test.cpp:65:10:65:14 | data2 |
| test.cpp:56:12:56:17 | buffer | test.cpp:65:10:65:14 | data2 |
| test.cpp:56:12:56:17 | buffer | test.cpp:65:10:65:14 | data2 |
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer |
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer |
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data |
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data |
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | dataref |
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | dataref |
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | dataref |
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:65:10:65:14 | data2 |
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:65:10:65:14 | data2 |
| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer |
| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer |
| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer |
| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer |
| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer |
| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer |
| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer |
| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer |
| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer |
| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer |
| test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer |
| test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer |
| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer |
| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer |
| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer |
| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer |
| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer |
| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer |
subpaths
nodes nodes
| test.cpp:24:30:24:36 | command | semmle.label | command | | test.cpp:24:30:24:36 | command indirection | semmle.label | command indirection |
| test.cpp:26:10:26:16 | command | semmle.label | command | | test.cpp:26:10:26:16 | command indirection | semmle.label | command indirection |
| test.cpp:26:10:26:16 | command | semmle.label | command | | test.cpp:29:30:29:36 | command indirection | semmle.label | command indirection |
| test.cpp:29:30:29:36 | command | semmle.label | command | | test.cpp:31:10:31:16 | command indirection | semmle.label | command indirection |
| test.cpp:31:10:31:16 | command | semmle.label | command | | test.cpp:42:18:42:34 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:31:10:31:16 | command | semmle.label | command | | test.cpp:43:18:43:34 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:42:18:42:23 | call to getenv | semmle.label | call to getenv |
| test.cpp:42:18:42:34 | call to getenv | semmle.label | call to getenv |
| test.cpp:43:18:43:23 | call to getenv | semmle.label | call to getenv |
| test.cpp:43:18:43:34 | call to getenv | semmle.label | call to getenv |
| test.cpp:56:12:56:17 | buffer | semmle.label | buffer |
| test.cpp:56:12:56:17 | buffer | semmle.label | buffer |
| test.cpp:56:12:56:17 | fgets output argument | semmle.label | fgets output argument | | test.cpp:56:12:56:17 | fgets output argument | semmle.label | fgets output argument |
| test.cpp:62:10:62:15 | buffer | semmle.label | buffer | | test.cpp:62:10:62:15 | buffer indirection | semmle.label | buffer indirection |
| test.cpp:62:10:62:15 | buffer | semmle.label | buffer | | test.cpp:63:10:63:13 | data indirection | semmle.label | data indirection |
| test.cpp:63:10:63:13 | data | semmle.label | data | | test.cpp:64:10:64:16 | dataref indirection | semmle.label | dataref indirection |
| test.cpp:63:10:63:13 | data | semmle.label | data | | test.cpp:65:10:65:14 | data2 indirection | semmle.label | data2 indirection |
| test.cpp:64:10:64:16 | dataref | semmle.label | dataref |
| test.cpp:64:10:64:16 | dataref | semmle.label | dataref |
| test.cpp:64:10:64:16 | dataref | semmle.label | dataref |
| test.cpp:65:10:65:14 | data2 | semmle.label | data2 |
| test.cpp:65:10:65:14 | data2 | semmle.label | data2 |
| test.cpp:76:12:76:17 | buffer | semmle.label | buffer |
| test.cpp:76:12:76:17 | buffer | semmle.label | buffer |
| test.cpp:76:12:76:17 | fgets output argument | semmle.label | fgets output argument | | test.cpp:76:12:76:17 | fgets output argument | semmle.label | fgets output argument |
| test.cpp:78:10:78:15 | buffer | semmle.label | buffer | | test.cpp:78:10:78:15 | buffer indirection | semmle.label | buffer indirection |
| test.cpp:78:10:78:15 | buffer | semmle.label | buffer |
| test.cpp:98:17:98:22 | buffer | semmle.label | buffer |
| test.cpp:98:17:98:22 | buffer | semmle.label | buffer |
| test.cpp:98:17:98:22 | recv output argument | semmle.label | recv output argument | | test.cpp:98:17:98:22 | recv output argument | semmle.label | recv output argument |
| test.cpp:99:15:99:20 | buffer | semmle.label | buffer | | test.cpp:99:15:99:20 | buffer indirection | semmle.label | buffer indirection |
| test.cpp:99:15:99:20 | buffer | semmle.label | buffer |
| test.cpp:106:17:106:22 | buffer | semmle.label | buffer |
| test.cpp:106:17:106:22 | buffer | semmle.label | buffer |
| test.cpp:106:17:106:22 | recv output argument | semmle.label | recv output argument | | test.cpp:106:17:106:22 | recv output argument | semmle.label | recv output argument |
| test.cpp:107:15:107:20 | buffer | semmle.label | buffer | | test.cpp:107:15:107:20 | buffer indirection | semmle.label | buffer indirection |
| test.cpp:107:15:107:20 | buffer | semmle.label | buffer | | test.cpp:113:8:113:12 | call to fgets indirection | semmle.label | call to fgets indirection |
| test.cpp:114:9:114:11 | ptr indirection | semmle.label | ptr indirection |
subpaths
#select #select
| test.cpp:26:10:26:16 | command | test.cpp:42:18:42:23 | call to getenv | test.cpp:26:10:26:16 | command | The value of this argument may come from $@ and is being passed to system. | test.cpp:42:18:42:23 | call to getenv | call to getenv | | test.cpp:26:10:26:16 | command indirection | test.cpp:42:18:42:34 | call to getenv indirection | test.cpp:26:10:26:16 | command indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:42:18:42:34 | call to getenv indirection | an environment variable |
| test.cpp:31:10:31:16 | command | test.cpp:43:18:43:23 | call to getenv | test.cpp:31:10:31:16 | command | The value of this argument may come from $@ and is being passed to system. | test.cpp:43:18:43:23 | call to getenv | call to getenv | | test.cpp:31:10:31:16 | command indirection | test.cpp:43:18:43:34 | call to getenv indirection | test.cpp:31:10:31:16 | command indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:43:18:43:34 | call to getenv indirection | an environment variable |
| test.cpp:62:10:62:15 | buffer | test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | buffer | buffer | | test.cpp:62:10:62:15 | buffer indirection | test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | fgets output argument | string read by fgets |
| test.cpp:63:10:63:13 | data | test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | buffer | buffer | | test.cpp:63:10:63:13 | data indirection | test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | fgets output argument | string read by fgets |
| test.cpp:64:10:64:16 | dataref | test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | buffer | buffer | | test.cpp:64:10:64:16 | dataref indirection | test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | dataref indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | fgets output argument | string read by fgets |
| test.cpp:65:10:65:14 | data2 | test.cpp:56:12:56:17 | buffer | test.cpp:65:10:65:14 | data2 | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | buffer | buffer | | test.cpp:65:10:65:14 | data2 indirection | test.cpp:56:12:56:17 | fgets output argument | test.cpp:65:10:65:14 | data2 indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | fgets output argument | string read by fgets |
| test.cpp:78:10:78:15 | buffer | test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer | The value of this argument may come from $@ and is being passed to system. | test.cpp:76:12:76:17 | buffer | buffer | | test.cpp:78:10:78:15 | buffer indirection | test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:76:12:76:17 | fgets output argument | string read by fgets |
| test.cpp:99:15:99:20 | buffer | test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer | The value of this argument may come from $@ and is being passed to LoadLibrary. | test.cpp:98:17:98:22 | buffer | buffer | | test.cpp:99:15:99:20 | buffer indirection | test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer indirection | The value of this argument may come from $@ and is being passed to LoadLibrary. | test.cpp:98:17:98:22 | recv output argument | buffer read by recv |
| test.cpp:107:15:107:20 | buffer | test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer | The value of this argument may come from $@ and is being passed to LoadLibrary. | test.cpp:106:17:106:22 | buffer | buffer | | test.cpp:107:15:107:20 | buffer indirection | test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer indirection | The value of this argument may come from $@ and is being passed to LoadLibrary. | test.cpp:106:17:106:22 | recv output argument | buffer read by recv |
| test.cpp:114:9:114:11 | ptr indirection | test.cpp:113:8:113:12 | call to fgets indirection | test.cpp:114:9:114:11 | ptr indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:113:8:113:12 | call to fgets indirection | string read by fgets |

View File

@@ -107,3 +107,9 @@ void testAcceptRecv(int socket1, int socket2)
LoadLibrary(buffer); // BAD: using data from recv LoadLibrary(buffer); // BAD: using data from recv
} }
} }
void argumentUse(char *ptr, FILE *stream) {
char buffer[80];
ptr = fgets(buffer, sizeof(buffer), stream);
system(ptr); // BAD
}

View File

@@ -1,4 +1,32 @@
edges edges
subpaths | main.cpp:6:27:6:30 | argv indirection | main.cpp:10:20:10:23 | argv indirection |
| main.cpp:10:20:10:23 | argv indirection | tests.cpp:631:32:631:35 | argv indirection |
| tests.cpp:613:19:613:24 | source indirection | tests.cpp:615:17:615:22 | source indirection |
| tests.cpp:622:19:622:24 | source indirection | tests.cpp:625:2:625:16 | ... = ... indirection |
| tests.cpp:625:2:625:16 | ... = ... indirection | tests.cpp:625:4:625:7 | s indirection [post update] [home indirection] |
| tests.cpp:625:4:625:7 | s indirection [post update] [home indirection] | tests.cpp:628:14:628:14 | s indirection [home indirection] |
| tests.cpp:628:14:628:14 | s indirection [home indirection] | tests.cpp:628:14:628:19 | home indirection |
| tests.cpp:628:14:628:14 | s indirection [home indirection] | tests.cpp:628:16:628:19 | home indirection |
| tests.cpp:628:16:628:19 | home indirection | tests.cpp:628:14:628:19 | home indirection |
| tests.cpp:631:32:631:35 | argv indirection | tests.cpp:656:9:656:15 | access to array indirection |
| tests.cpp:631:32:631:35 | argv indirection | tests.cpp:657:9:657:15 | access to array indirection |
| tests.cpp:656:9:656:15 | access to array indirection | tests.cpp:613:19:613:24 | source indirection |
| tests.cpp:657:9:657:15 | access to array indirection | tests.cpp:622:19:622:24 | source indirection |
nodes nodes
| main.cpp:6:27:6:30 | argv indirection | semmle.label | argv indirection |
| main.cpp:10:20:10:23 | argv indirection | semmle.label | argv indirection |
| tests.cpp:613:19:613:24 | source indirection | semmle.label | source indirection |
| tests.cpp:615:17:615:22 | source indirection | semmle.label | source indirection |
| tests.cpp:622:19:622:24 | source indirection | semmle.label | source indirection |
| tests.cpp:625:2:625:16 | ... = ... indirection | semmle.label | ... = ... indirection |
| tests.cpp:625:4:625:7 | s indirection [post update] [home indirection] | semmle.label | s indirection [post update] [home indirection] |
| tests.cpp:628:14:628:14 | s indirection [home indirection] | semmle.label | s indirection [home indirection] |
| tests.cpp:628:14:628:19 | home indirection | semmle.label | home indirection |
| tests.cpp:628:16:628:19 | home indirection | semmle.label | home indirection |
| tests.cpp:631:32:631:35 | argv indirection | semmle.label | argv indirection |
| tests.cpp:656:9:656:15 | access to array indirection | semmle.label | access to array indirection |
| tests.cpp:657:9:657:15 | access to array indirection | semmle.label | access to array indirection |
subpaths
#select #select
| tests.cpp:615:2:615:7 | call to strcpy | main.cpp:6:27:6:30 | argv indirection | tests.cpp:615:17:615:22 | source indirection | This 'call to strcpy' with input from $@ may overflow the destination. | main.cpp:6:27:6:30 | argv indirection | a command-line argument |
| tests.cpp:628:2:628:7 | call to strcpy | main.cpp:6:27:6:30 | argv indirection | tests.cpp:628:14:628:19 | home indirection | This 'call to strcpy' with input from $@ may overflow the destination. | main.cpp:6:27:6:30 | argv indirection | a command-line argument |

View File

@@ -407,7 +407,7 @@ void test15()
{ {
if (ptr[5] == ' ') // GOOD if (ptr[5] == ' ') // GOOD
{ {
// ... break;
} }
} }
} }
@@ -608,6 +608,26 @@ int test23() {
return sizeof(buffer) / sizeof(buffer[101]); // GOOD return sizeof(buffer) / sizeof(buffer[101]); // GOOD
} }
char* strcpy(char *, const char *);
void test24(char* source) {
char buffer[100];
strcpy(buffer, source); // BAD
}
struct my_struct {
char* home;
};
void test25(char* source) {
my_struct s;
s.home = source;
char buf[100];
strcpy(buf, s.home); // BAD
}
int tests_main(int argc, char *argv[]) int tests_main(int argc, char *argv[])
{ {
long long arr17[19]; long long arr17[19];
@@ -633,6 +653,8 @@ int tests_main(int argc, char *argv[])
test21(argc == 0); test21(argc == 0);
test22(argc == 0, argv[0]); test22(argc == 0, argv[0]);
test23(); test23();
test24(argv[0]);
test25(argv[0]);
return 0; return 0;
} }

View File

@@ -1,37 +1,18 @@
edges edges
| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | | tests.c:16:26:16:29 | argv indirection | tests.c:28:22:28:28 | access to array indirection |
| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | | tests.c:16:26:16:29 | argv indirection | tests.c:29:28:29:34 | access to array indirection |
| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | | tests.c:16:26:16:29 | argv indirection | tests.c:34:10:34:16 | access to array indirection |
| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array |
| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array |
| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array |
| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array |
| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array |
| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array |
| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array |
| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array |
| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array |
subpaths
nodes nodes
| tests.c:28:22:28:25 | argv | semmle.label | argv | | tests.c:16:26:16:29 | argv indirection | semmle.label | argv indirection |
| tests.c:28:22:28:25 | argv | semmle.label | argv | | tests.c:28:22:28:28 | access to array indirection | semmle.label | access to array indirection |
| tests.c:28:22:28:28 | access to array | semmle.label | access to array | | tests.c:29:28:29:34 | access to array indirection | semmle.label | access to array indirection |
| tests.c:28:22:28:28 | access to array | semmle.label | access to array | | tests.c:31:15:31:23 | scanf output argument | semmle.label | scanf output argument |
| tests.c:29:28:29:31 | argv | semmle.label | argv | | tests.c:33:21:33:29 | scanf output argument | semmle.label | scanf output argument |
| tests.c:29:28:29:31 | argv | semmle.label | argv | | tests.c:34:10:34:16 | access to array indirection | semmle.label | access to array indirection |
| tests.c:29:28:29:34 | access to array | semmle.label | access to array | subpaths
| tests.c:29:28:29:34 | access to array | semmle.label | access to array |
| tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 |
| tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 |
| tests.c:33:21:33:29 | buffer100 | semmle.label | buffer100 |
| tests.c:33:21:33:29 | buffer100 | semmle.label | buffer100 |
| tests.c:34:10:34:13 | argv | semmle.label | argv |
| tests.c:34:10:34:13 | argv | semmle.label | argv |
| tests.c:34:10:34:16 | access to array | semmle.label | access to array |
| tests.c:34:10:34:16 | access to array | semmle.label | access to array |
#select #select
| tests.c:28:3:28:9 | call to sprintf | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv | | tests.c:28:3:28:9 | call to sprintf | tests.c:16:26:16:29 | argv indirection | tests.c:28:22:28:28 | access to array indirection | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:16:26:16:29 | argv indirection | a command-line argument |
| tests.c:29:3:29:9 | call to sprintf | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:29:28:29:31 | argv | argv | | tests.c:29:3:29:9 | call to sprintf | tests.c:16:26:16:29 | argv indirection | tests.c:29:28:29:34 | access to array indirection | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:16:26:16:29 | argv indirection | a command-line argument |
| tests.c:31:15:31:23 | buffer100 | tests.c:31:15:31:23 | buffer100 | tests.c:31:15:31:23 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:31:15:31:23 | buffer100 | buffer100 | | tests.c:31:15:31:23 | buffer100 | tests.c:31:15:31:23 | scanf output argument | tests.c:31:15:31:23 | scanf output argument | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:31:15:31:23 | scanf output argument | value read by scanf |
| tests.c:33:21:33:29 | buffer100 | tests.c:33:21:33:29 | buffer100 | tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:33:21:33:29 | buffer100 | buffer100 | | tests.c:33:21:33:29 | buffer100 | tests.c:33:21:33:29 | scanf output argument | tests.c:33:21:33:29 | scanf output argument | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:33:21:33:29 | scanf output argument | value read by scanf |
| tests.c:34:25:34:33 | buffer100 | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | This 'sscanf string argument' with input from $@ may overflow the destination. | tests.c:34:10:34:13 | argv | argv | | tests.c:34:25:34:33 | buffer100 | tests.c:16:26:16:29 | argv indirection | tests.c:34:10:34:16 | access to array indirection | This 'sscanf string argument' with input from $@ may overflow the destination. | tests.c:16:26:16:29 | argv indirection | a command-line argument |

View File

@@ -1,69 +0,0 @@
edges
| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy |
| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy |
| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy |
| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy |
| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy |
| globalVars.c:8:7:8:10 | copy | globalVars.c:33:15:33:18 | copy |
| globalVars.c:8:7:8:10 | copy | globalVars.c:35:11:35:14 | copy |
| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 |
| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 |
| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 |
| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 |
| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 |
| globalVars.c:9:7:9:11 | copy2 | globalVars.c:44:15:44:19 | copy2 |
| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 |
| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 |
| globalVars.c:11:22:11:25 | argv | globalVars.c:8:7:8:10 | copy |
| globalVars.c:11:22:11:25 | argv | globalVars.c:12:2:12:15 | ... = ... |
| globalVars.c:12:2:12:15 | ... = ... | globalVars.c:8:7:8:10 | copy |
| globalVars.c:15:21:15:23 | val | globalVars.c:9:7:9:11 | copy2 |
| globalVars.c:15:21:15:23 | val | globalVars.c:16:2:16:12 | ... = ... |
| globalVars.c:16:2:16:12 | ... = ... | globalVars.c:9:7:9:11 | copy2 |
| globalVars.c:24:11:24:14 | argv | globalVars.c:11:22:11:25 | argv |
| globalVars.c:24:11:24:14 | argv | globalVars.c:11:22:11:25 | argv |
| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy |
| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy |
| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy |
| globalVars.c:30:15:30:18 | copy | globalVars.c:35:11:35:14 | copy |
| globalVars.c:33:15:33:18 | copy | globalVars.c:35:11:35:14 | copy |
| globalVars.c:35:11:35:14 | copy | globalVars.c:15:21:15:23 | val |
| globalVars.c:35:11:35:14 | copy | globalVars.c:35:11:35:14 | copy |
| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 |
| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 |
| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 |
| globalVars.c:41:15:41:19 | copy2 | globalVars.c:50:9:50:13 | copy2 |
| globalVars.c:41:15:41:19 | copy2 | globalVars.c:50:9:50:13 | copy2 |
| globalVars.c:44:15:44:19 | copy2 | globalVars.c:50:9:50:13 | copy2 |
| globalVars.c:44:15:44:19 | copy2 | globalVars.c:50:9:50:13 | copy2 |
subpaths
nodes
| globalVars.c:8:7:8:10 | copy | semmle.label | copy |
| globalVars.c:9:7:9:11 | copy2 | semmle.label | copy2 |
| globalVars.c:11:22:11:25 | argv | semmle.label | argv |
| globalVars.c:12:2:12:15 | ... = ... | semmle.label | ... = ... |
| globalVars.c:15:21:15:23 | val | semmle.label | val |
| globalVars.c:16:2:16:12 | ... = ... | semmle.label | ... = ... |
| globalVars.c:24:11:24:14 | argv | semmle.label | argv |
| globalVars.c:24:11:24:14 | argv | semmle.label | argv |
| globalVars.c:27:9:27:12 | copy | semmle.label | copy |
| globalVars.c:27:9:27:12 | copy | semmle.label | copy |
| globalVars.c:30:15:30:18 | copy | semmle.label | copy |
| globalVars.c:30:15:30:18 | copy | semmle.label | copy |
| globalVars.c:30:15:30:18 | copy | semmle.label | copy |
| globalVars.c:33:15:33:18 | copy | semmle.label | copy |
| globalVars.c:35:11:35:14 | copy | semmle.label | copy |
| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 |
| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 |
| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 |
| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 |
| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 |
| globalVars.c:44:15:44:19 | copy2 | semmle.label | copy2 |
| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 |
| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 |
#select
| globalVars.c:27:9:27:12 | copy | globalVars.c:24:11:24:14 | argv | globalVars.c:27:9:27:12 | copy | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | globalVars.c:24:11:24:14 | argv | argv |
| globalVars.c:30:15:30:18 | copy | globalVars.c:24:11:24:14 | argv | globalVars.c:30:15:30:18 | copy | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(str), which calls printf(format). | globalVars.c:24:11:24:14 | argv | argv |
| globalVars.c:38:9:38:13 | copy2 | globalVars.c:24:11:24:14 | argv | globalVars.c:38:9:38:13 | copy2 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | globalVars.c:24:11:24:14 | argv | argv |
| globalVars.c:41:15:41:19 | copy2 | globalVars.c:24:11:24:14 | argv | globalVars.c:41:15:41:19 | copy2 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(str), which calls printf(format). | globalVars.c:24:11:24:14 | argv | argv |
| globalVars.c:50:9:50:13 | copy2 | globalVars.c:24:11:24:14 | argv | globalVars.c:50:9:50:13 | copy2 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | globalVars.c:24:11:24:14 | argv | argv |

View File

@@ -1 +0,0 @@
Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql

View File

@@ -1,13 +1,8 @@
edges edges
| examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data |
| examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data |
| examples.cpp:63:26:63:30 | fscanf output argument | examples.cpp:66:11:66:14 | data | | examples.cpp:63:26:63:30 | fscanf output argument | examples.cpp:66:11:66:14 | data |
| examples.cpp:63:26:63:30 | fscanf output argument | examples.cpp:66:11:66:14 | data |
subpaths
nodes nodes
| examples.cpp:63:26:63:30 | & ... | semmle.label | & ... |
| examples.cpp:63:26:63:30 | fscanf output argument | semmle.label | fscanf output argument | | examples.cpp:63:26:63:30 | fscanf output argument | semmle.label | fscanf output argument |
| examples.cpp:66:11:66:14 | data | semmle.label | data | | examples.cpp:66:11:66:14 | data | semmle.label | data |
| examples.cpp:66:11:66:14 | data | semmle.label | data | subpaths
#select #select
| examples.cpp:66:11:66:14 | data | examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | examples.cpp:63:26:63:30 | & ... | User-provided value | | examples.cpp:66:11:66:14 | data | examples.cpp:63:26:63:30 | fscanf output argument | examples.cpp:66:11:66:14 | data | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | examples.cpp:63:26:63:30 | fscanf output argument | value read by fscanf |

View File

@@ -1 +1 @@
| examples.cpp:66:9:66:14 | -- ... | $@ flows an expression which might overflow negatively. | examples.cpp:63:26:63:30 | & ... | User-provided value | | examples.cpp:66:9:66:14 | -- ... | $@ flows an expression which might overflow negatively. | examples.cpp:63:26:63:30 | fscanf output argument | value read by fscanf |

View File

@@ -1,86 +1,59 @@
edges edges
| test2.cpp:12:21:12:21 | v | test2.cpp:14:11:14:11 | v | | test2.cpp:12:21:12:21 | v | test2.cpp:14:11:14:11 | v |
| test2.cpp:12:21:12:21 | v | test2.cpp:14:11:14:11 | v |
| test2.cpp:25:22:25:23 | & ... | test2.cpp:27:13:27:13 | v |
| test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:27:13:27:13 | v | | test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:27:13:27:13 | v |
| test2.cpp:27:13:27:13 | v | test2.cpp:12:21:12:21 | v | | test2.cpp:27:13:27:13 | v | test2.cpp:12:21:12:21 | v |
| test2.cpp:36:9:36:14 | buffer | test2.cpp:39:9:39:11 | num |
| test2.cpp:36:9:36:14 | buffer | test2.cpp:39:9:39:11 | num |
| test2.cpp:36:9:36:14 | buffer | test2.cpp:39:9:39:11 | num |
| test2.cpp:36:9:36:14 | buffer | test2.cpp:39:9:39:11 | num |
| test2.cpp:36:9:36:14 | buffer | test2.cpp:40:3:40:5 | num |
| test2.cpp:36:9:36:14 | buffer | test2.cpp:40:3:40:5 | num |
| test2.cpp:36:9:36:14 | buffer | test2.cpp:40:3:40:5 | num |
| test2.cpp:36:9:36:14 | buffer | test2.cpp:40:3:40:5 | num |
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:39:9:39:11 | num |
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:39:9:39:11 | num | | test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:39:9:39:11 | num |
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:40:3:40:5 | num | | test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:40:3:40:5 | num |
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:40:3:40:5 | num | | test3.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections |
| test5.cpp:5:5:5:17 | getTaintedInt indirection | test5.cpp:17:6:17:18 | call to getTaintedInt | | test3.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 |
| test3.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 |
| test5.cpp:5:5:5:17 | getTaintedInt indirection | test5.cpp:17:6:17:18 | call to getTaintedInt | | test5.cpp:5:5:5:17 | getTaintedInt indirection | test5.cpp:17:6:17:18 | call to getTaintedInt |
| test5.cpp:5:5:5:17 | getTaintedInt indirection | test5.cpp:18:6:18:18 | call to getTaintedInt | | test5.cpp:5:5:5:17 | getTaintedInt indirection | test5.cpp:18:6:18:18 | call to getTaintedInt |
| test5.cpp:9:7:9:9 | buf | test5.cpp:5:5:5:17 | getTaintedInt indirection |
| test5.cpp:9:7:9:9 | buf | test5.cpp:5:5:5:17 | getTaintedInt indirection |
| test5.cpp:9:7:9:9 | gets output argument | test5.cpp:5:5:5:17 | getTaintedInt indirection | | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:5:5:5:17 | getTaintedInt indirection |
| test5.cpp:18:6:18:18 | call to getTaintedInt | test5.cpp:19:6:19:6 | y | | test5.cpp:18:6:18:18 | call to getTaintedInt | test5.cpp:19:6:19:6 | y |
| test5.cpp:18:6:18:18 | call to getTaintedInt | test5.cpp:19:6:19:6 | y | | test.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections |
| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections | | test.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 |
| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections | | test.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 |
| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
subpaths
nodes nodes
| test2.cpp:12:21:12:21 | v | semmle.label | v | | test2.cpp:12:21:12:21 | v | semmle.label | v |
| test2.cpp:14:11:14:11 | v | semmle.label | v | | test2.cpp:14:11:14:11 | v | semmle.label | v |
| test2.cpp:14:11:14:11 | v | semmle.label | v |
| test2.cpp:25:22:25:23 | & ... | semmle.label | & ... |
| test2.cpp:25:22:25:23 | fscanf output argument | semmle.label | fscanf output argument | | test2.cpp:25:22:25:23 | fscanf output argument | semmle.label | fscanf output argument |
| test2.cpp:27:13:27:13 | v | semmle.label | v | | test2.cpp:27:13:27:13 | v | semmle.label | v |
| test2.cpp:36:9:36:14 | buffer | semmle.label | buffer |
| test2.cpp:36:9:36:14 | buffer | semmle.label | buffer |
| test2.cpp:36:9:36:14 | fgets output argument | semmle.label | fgets output argument | | test2.cpp:36:9:36:14 | fgets output argument | semmle.label | fgets output argument |
| test2.cpp:39:9:39:11 | num | semmle.label | num | | test2.cpp:39:9:39:11 | num | semmle.label | num |
| test2.cpp:39:9:39:11 | num | semmle.label | num |
| test2.cpp:40:3:40:5 | num | semmle.label | num |
| test2.cpp:40:3:40:5 | num | semmle.label | num | | test2.cpp:40:3:40:5 | num | semmle.label | num |
| test3.c:10:27:10:30 | argv indirection | semmle.label | argv indirection |
| test5.cpp:5:5:5:17 | getTaintedInt indirection | semmle.label | getTaintedInt indirection | | test5.cpp:5:5:5:17 | getTaintedInt indirection | semmle.label | getTaintedInt indirection |
| test5.cpp:9:7:9:9 | buf | semmle.label | buf |
| test5.cpp:9:7:9:9 | buf | semmle.label | buf |
| test5.cpp:9:7:9:9 | gets output argument | semmle.label | gets output argument | | test5.cpp:9:7:9:9 | gets output argument | semmle.label | gets output argument |
| test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt | | test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
| test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
| test5.cpp:18:6:18:18 | call to getTaintedInt | semmle.label | call to getTaintedInt | | test5.cpp:18:6:18:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
| test5.cpp:19:6:19:6 | y | semmle.label | y | | test5.cpp:19:6:19:6 | y | semmle.label | y |
| test5.cpp:19:6:19:6 | y | semmle.label | y | | test.c:10:27:10:30 | argv indirection | semmle.label | argv indirection |
| test.c:11:29:11:32 | argv | semmle.label | argv |
| test.c:11:29:11:32 | argv | semmle.label | argv |
| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections | | test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
| test.c:41:17:41:20 | argv | semmle.label | argv |
| test.c:41:17:41:20 | argv | semmle.label | argv |
| test.c:44:7:44:10 | len2 | semmle.label | len2 | | test.c:44:7:44:10 | len2 | semmle.label | len2 |
| test.c:44:7:44:10 | len2 | semmle.label | len2 |
| test.c:51:17:51:20 | argv | semmle.label | argv |
| test.c:51:17:51:20 | argv | semmle.label | argv |
| test.c:54:7:54:10 | len3 | semmle.label | len3 |
| test.c:54:7:54:10 | len3 | semmle.label | len3 | | test.c:54:7:54:10 | len3 | semmle.label | len3 |
subpaths
#select #select
| test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | & ... | test2.cpp:14:11:14:11 | v | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value | | test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:14:11:14:11 | v | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf |
| test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | & ... | test2.cpp:14:11:14:11 | v | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test2.cpp:25:22:25:23 | & ... | User-provided value | | test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:14:11:14:11 | v | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf |
| test2.cpp:39:9:39:11 | num | test2.cpp:36:9:36:14 | buffer | test2.cpp:39:9:39:11 | num | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:36:9:36:14 | buffer | User-provided value | | test2.cpp:39:9:39:11 | num | test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:39:9:39:11 | num | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:36:9:36:14 | fgets output argument | string read by fgets |
| test2.cpp:40:3:40:5 | num | test2.cpp:36:9:36:14 | buffer | test2.cpp:40:3:40:5 | num | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:36:9:36:14 | buffer | User-provided value | | test2.cpp:40:3:40:5 | num | test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:40:3:40:5 | num | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:36:9:36:14 | fgets output argument | string read by fgets |
| test5.cpp:17:6:17:18 | call to getTaintedInt | test5.cpp:9:7:9:9 | buf | test5.cpp:17:6:17:18 | call to getTaintedInt | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | buf | User-provided value | | test5.cpp:17:6:17:18 | call to getTaintedInt | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:17:6:17:18 | call to getTaintedInt | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | buf | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | buf | User-provided value | | test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | buf | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test5.cpp:9:7:9:9 | buf | User-provided value | | test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
| test.c:14:15:14:28 | maxConnections | test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test.c:11:29:11:32 | argv | User-provided value | | test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:14:15:14:28 | maxConnections | test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:11:29:11:32 | argv | User-provided value | | test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:44:7:44:10 | len2 | test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:41:17:41:20 | argv | User-provided value | | test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:54:7:54:10 | len3 | test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:51:17:51:20 | argv | User-provided value | | test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:44:7:44:10 | len2 | test3.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:44:7:44:10 | len2 | test3.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:44:7:44:10 | len2 | test.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:44:7:44:10 | len2 | test.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:54:7:54:10 | len3 | test3.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:54:7:54:10 | len3 | test3.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:54:7:54:10 | len3 | test.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:54:7:54:10 | len3 | test.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |

View File

@@ -1,18 +1,23 @@
| test2.cpp:14:11:14:15 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value | | test2.cpp:14:11:14:15 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf |
| test2.cpp:15:11:15:19 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value | | test2.cpp:15:11:15:19 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf |
| test2.cpp:16:11:16:21 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value | | test2.cpp:16:11:16:21 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf |
| test2.cpp:17:11:17:22 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value | | test2.cpp:17:11:17:22 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf |
| test2.cpp:39:9:39:18 | ... + ... | $@ flows an expression which might overflow. | test2.cpp:36:9:36:14 | buffer | User-provided value | | test2.cpp:39:9:39:18 | ... + ... | $@ flows an expression which might overflow. | test2.cpp:36:9:36:14 | fgets output argument | string read by fgets |
| test2.cpp:40:3:40:13 | ... += ... | $@ flows an expression which might overflow. | test2.cpp:36:9:36:14 | buffer | User-provided value | | test2.cpp:40:3:40:13 | ... += ... | $@ flows an expression which might overflow. | test2.cpp:36:9:36:14 | fgets output argument | string read by fgets |
| test3.c:12:31:12:34 | * ... | $@ flows an expression which might overflow negatively. | test3.c:11:15:11:18 | argv | User-provided value | | test3.c:12:11:12:34 | * ... | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
| test3.c:13:16:13:19 | * ... | $@ flows an expression which might overflow negatively. | test3.c:11:15:11:18 | argv | User-provided value | | test3.c:12:11:12:34 | * ... | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | argv indirection | a command-line argument |
| test4.cpp:13:17:13:20 | access to array | $@ flows an expression which might overflow negatively. | test4.cpp:9:13:9:16 | argv | User-provided value | | test3.c:13:11:13:20 | * ... | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
| test5.cpp:10:9:10:15 | call to strtoul | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | buf | User-provided value | | test3.c:13:11:13:20 | * ... | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | argv indirection | a command-line argument |
| test5.cpp:17:6:17:27 | ... * ... | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | buf | User-provided value | | test4.cpp:13:7:13:20 | access to array | $@ flows an expression which might overflow negatively. | test4.cpp:8:27:8:30 | argv indirection | a command-line argument |
| test5.cpp:19:6:19:13 | ... * ... | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | buf | User-provided value | | test5.cpp:10:9:10:27 | call to strtoul | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
| test6.cpp:11:15:11:15 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | & ... | User-provided value | | test5.cpp:17:6:17:27 | ... * ... | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
| test6.cpp:16:15:16:15 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | & ... | User-provided value | | test5.cpp:19:6:19:13 | ... * ... | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
| test6.cpp:30:16:30:16 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | & ... | User-provided value | | test6.cpp:11:10:11:15 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | fscanf output argument | value read by fscanf |
| test.c:14:15:14:35 | ... * ... | $@ flows an expression which might overflow. | test.c:11:29:11:32 | argv | User-provided value | | test6.cpp:16:10:16:15 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | fscanf output argument | value read by fscanf |
| test.c:44:7:44:12 | ... -- | $@ flows an expression which might overflow negatively. | test.c:41:17:41:20 | argv | User-provided value | | test6.cpp:30:11:30:16 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | fscanf output argument | value read by fscanf |
| test.c:54:7:54:12 | ... -- | $@ flows an expression which might overflow negatively. | test.c:51:17:51:20 | argv | User-provided value | | test.c:14:15:14:35 | ... * ... | $@ flows an expression which might overflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:14:15:14:35 | ... * ... | $@ flows an expression which might overflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:44:7:44:12 | ... -- | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:44:7:44:12 | ... -- | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:54:7:54:12 | ... -- | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
| test.c:54:7:54:12 | ... -- | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | argv indirection | a command-line argument |

View File

@@ -22,16 +22,10 @@ edges
| test.cpp:52:19:52:37 | call to malloc | test.cpp:53:12:53:23 | ... + ... | | test.cpp:52:19:52:37 | call to malloc | test.cpp:53:12:53:23 | ... + ... |
| test.cpp:53:12:53:23 | ... + ... | test.cpp:51:33:51:35 | end | | test.cpp:53:12:53:23 | ... + ... | test.cpp:51:33:51:35 | end |
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:67:9:67:14 | ... = ... | | test.cpp:60:34:60:37 | mk_array output argument | test.cpp:67:9:67:14 | ... = ... |
| test.cpp:194:15:194:33 | call to malloc | test.cpp:195:17:195:23 | ... + ... |
| test.cpp:195:17:195:23 | ... + ... | test.cpp:195:17:195:23 | ... + ... |
| test.cpp:195:17:195:23 | ... + ... | test.cpp:201:5:201:19 | ... = ... |
| test.cpp:195:17:195:23 | ... + ... | test.cpp:201:5:201:19 | ... = ... |
| test.cpp:205:15:205:33 | call to malloc | test.cpp:206:17:206:23 | ... + ... | | test.cpp:205:15:205:33 | call to malloc | test.cpp:206:17:206:23 | ... + ... |
| test.cpp:206:17:206:23 | ... + ... | test.cpp:206:17:206:23 | ... + ... | | test.cpp:206:17:206:23 | ... + ... | test.cpp:206:17:206:23 | ... + ... |
| test.cpp:206:17:206:23 | ... + ... | test.cpp:213:5:213:13 | ... = ... | | test.cpp:206:17:206:23 | ... + ... | test.cpp:213:5:213:13 | ... = ... |
| test.cpp:206:17:206:23 | ... + ... | test.cpp:213:5:213:13 | ... = ... | | test.cpp:206:17:206:23 | ... + ... | test.cpp:213:5:213:13 | ... = ... |
| test.cpp:231:18:231:30 | new[] | test.cpp:232:3:232:20 | ... = ... |
| test.cpp:238:20:238:32 | new[] | test.cpp:239:5:239:22 | ... = ... |
| test.cpp:260:13:260:24 | new[] | test.cpp:261:14:261:21 | ... + ... | | test.cpp:260:13:260:24 | new[] | test.cpp:261:14:261:21 | ... + ... |
| test.cpp:261:14:261:21 | ... + ... | test.cpp:261:14:261:21 | ... + ... | | test.cpp:261:14:261:21 | ... + ... | test.cpp:261:14:261:21 | ... + ... |
| test.cpp:261:14:261:21 | ... + ... | test.cpp:264:13:264:14 | * ... | | test.cpp:261:14:261:21 | ... + ... | test.cpp:264:13:264:14 | * ... |
@@ -127,18 +121,10 @@ nodes
| test.cpp:53:12:53:23 | ... + ... | semmle.label | ... + ... | | test.cpp:53:12:53:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:60:34:60:37 | mk_array output argument | semmle.label | mk_array output argument | | test.cpp:60:34:60:37 | mk_array output argument | semmle.label | mk_array output argument |
| test.cpp:67:9:67:14 | ... = ... | semmle.label | ... = ... | | test.cpp:67:9:67:14 | ... = ... | semmle.label | ... = ... |
| test.cpp:194:15:194:33 | call to malloc | semmle.label | call to malloc |
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:201:5:201:19 | ... = ... | semmle.label | ... = ... |
| test.cpp:205:15:205:33 | call to malloc | semmle.label | call to malloc | | test.cpp:205:15:205:33 | call to malloc | semmle.label | call to malloc |
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... | | test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... | | test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:213:5:213:13 | ... = ... | semmle.label | ... = ... | | test.cpp:213:5:213:13 | ... = ... | semmle.label | ... = ... |
| test.cpp:231:18:231:30 | new[] | semmle.label | new[] |
| test.cpp:232:3:232:20 | ... = ... | semmle.label | ... = ... |
| test.cpp:238:20:238:32 | new[] | semmle.label | new[] |
| test.cpp:239:5:239:22 | ... = ... | semmle.label | ... = ... |
| test.cpp:260:13:260:24 | new[] | semmle.label | new[] | | test.cpp:260:13:260:24 | new[] | semmle.label | new[] |
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... | | test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... | | test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
@@ -220,10 +206,7 @@ subpaths
| test.cpp:30:14:30:15 | * ... | test.cpp:28:15:28:37 | call to malloc | test.cpp:30:14:30:15 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:28:15:28:37 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... | | test.cpp:30:14:30:15 | * ... | test.cpp:28:15:28:37 | call to malloc | test.cpp:30:14:30:15 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:28:15:28:37 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
| test.cpp:32:14:32:21 | * ... | test.cpp:28:15:28:37 | call to malloc | test.cpp:32:14:32:21 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:28:15:28:37 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... | | test.cpp:32:14:32:21 | * ... | test.cpp:28:15:28:37 | call to malloc | test.cpp:32:14:32:21 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:28:15:28:37 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
| test.cpp:67:9:67:14 | ... = ... | test.cpp:52:19:52:37 | call to malloc | test.cpp:67:9:67:14 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:52:19:52:37 | call to malloc | call to malloc | test.cpp:53:20:53:23 | size | size | | test.cpp:67:9:67:14 | ... = ... | test.cpp:52:19:52:37 | call to malloc | test.cpp:67:9:67:14 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:52:19:52:37 | call to malloc | call to malloc | test.cpp:53:20:53:23 | size | size |
| test.cpp:201:5:201:19 | ... = ... | test.cpp:194:15:194:33 | call to malloc | test.cpp:201:5:201:19 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:194:15:194:33 | call to malloc | call to malloc | test.cpp:195:21:195:23 | len | len |
| test.cpp:213:5:213:13 | ... = ... | test.cpp:205:15:205:33 | call to malloc | test.cpp:213:5:213:13 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:205:15:205:33 | call to malloc | call to malloc | test.cpp:206:21:206:23 | len | len | | test.cpp:213:5:213:13 | ... = ... | test.cpp:205:15:205:33 | call to malloc | test.cpp:213:5:213:13 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:205:15:205:33 | call to malloc | call to malloc | test.cpp:206:21:206:23 | len | len |
| test.cpp:232:3:232:20 | ... = ... | test.cpp:231:18:231:30 | new[] | test.cpp:232:3:232:20 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:231:18:231:30 | new[] | new[] | test.cpp:232:11:232:15 | index | index |
| test.cpp:239:5:239:22 | ... = ... | test.cpp:238:20:238:32 | new[] | test.cpp:239:5:239:22 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:238:20:238:32 | new[] | new[] | test.cpp:239:13:239:17 | index | index |
| test.cpp:264:13:264:14 | * ... | test.cpp:260:13:260:24 | new[] | test.cpp:264:13:264:14 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:260:13:260:24 | new[] | new[] | test.cpp:261:19:261:21 | len | len | | test.cpp:264:13:264:14 | * ... | test.cpp:260:13:260:24 | new[] | test.cpp:264:13:264:14 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:260:13:260:24 | new[] | new[] | test.cpp:261:19:261:21 | len | len |
| test.cpp:274:5:274:10 | ... = ... | test.cpp:270:13:270:24 | new[] | test.cpp:274:5:274:10 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:270:13:270:24 | new[] | new[] | test.cpp:271:19:271:21 | len | len | | test.cpp:274:5:274:10 | ... = ... | test.cpp:270:13:270:24 | new[] | test.cpp:274:5:274:10 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:270:13:270:24 | new[] | new[] | test.cpp:271:19:271:21 | len | len |
| test.cpp:358:14:358:26 | end_plus_one indirection | test.cpp:355:14:355:27 | new[] | test.cpp:358:14:358:26 | end_plus_one indirection | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size | | test.cpp:358:14:358:26 | end_plus_one indirection | test.cpp:355:14:355:27 | new[] | test.cpp:358:14:358:26 | end_plus_one indirection | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size |

View File

@@ -198,7 +198,7 @@ void test12(unsigned len, unsigned index) {
return; return;
} }
p[index] = '\0'; // $ deref=L195->L201 // BAD p[index] = '\0'; // $ MISSING: deref=L195->L201 // BAD [NOT DETECTED]
} }
void test13(unsigned len, unsigned index) { void test13(unsigned len, unsigned index) {
@@ -229,14 +229,14 @@ void test15(unsigned index) {
return; return;
} }
int* newname = new int[size]; int* newname = new int[size];
newname[index] = 0; // $ alloc=L231 deref=L232 // GOOD [FALSE POSITIVE] newname[index] = 0; // GOOD
} }
void test16(unsigned index) { void test16(unsigned index) {
unsigned size = index + 13; unsigned size = index + 13;
if(size >= index) { if(size >= index) {
int* newname = new int[size]; int* newname = new int[size];
newname[index] = 0; // $ alloc=L238 deref=L239 // GOOD [FALSE POSITIVE] newname[index] = 0; // GOOD
} }
} }

View File

@@ -1 +1 @@
| tests.cpp:38:31:38:34 | data | $@ flows an expression which might overflow. | tests.cpp:57:27:57:31 | & ... | User-provided value | | tests.cpp:38:25:38:34 | data | $@ flows an expression which might overflow. | tests.cpp:57:27:57:31 | fscanf output argument | value read by fscanf |

View File

@@ -1,14 +1,7 @@
| test.cpp:12:6:12:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:11:6:11:8 | foo | foo | | test.cpp:12:6:12:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:11:6:11:8 | foo | foo |
| test.cpp:30:6:30:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:26:6:26:8 | foo | foo |
| test.cpp:46:6:46:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:42:6:42:8 | foo | foo |
| test.cpp:55:7:55:9 | foo | The variable $@ may not be initialized at this access. | test.cpp:50:6:50:8 | foo | foo |
| test.cpp:67:7:67:9 | foo | The variable $@ may not be initialized at this access. | test.cpp:61:6:61:8 | foo | foo |
| test.cpp:92:6:92:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:82:6:82:8 | foo | foo |
| test.cpp:113:6:113:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:111:6:111:8 | foo | foo | | test.cpp:113:6:113:8 | foo | The variable $@ may not be initialized at this access. | test.cpp:111:6:111:8 | foo | foo |
| test.cpp:132:9:132:9 | j | The variable $@ may not be initialized at this access. | test.cpp:126:6:126:6 | j | j |
| test.cpp:219:3:219:3 | x | The variable $@ may not be initialized at this access. | test.cpp:218:7:218:7 | x | x | | test.cpp:219:3:219:3 | x | The variable $@ may not be initialized at this access. | test.cpp:218:7:218:7 | x | x |
| test.cpp:243:13:243:13 | i | The variable $@ may not be initialized at this access. | test.cpp:241:6:241:6 | i | i | | test.cpp:243:13:243:13 | i | The variable $@ may not be initialized at this access. | test.cpp:241:6:241:6 | i | i |
| test.cpp:329:9:329:11 | val | The variable $@ may not be initialized at this access. | test.cpp:321:6:321:8 | val | val |
| test.cpp:336:10:336:10 | a | The variable $@ may not be initialized at this access. | test.cpp:333:7:333:7 | a | a | | test.cpp:336:10:336:10 | a | The variable $@ may not be initialized at this access. | test.cpp:333:7:333:7 | a | a |
| test.cpp:369:10:369:10 | a | The variable $@ may not be initialized at this access. | test.cpp:358:7:358:7 | a | a | | test.cpp:369:10:369:10 | a | The variable $@ may not be initialized at this access. | test.cpp:358:7:358:7 | a | a |
| test.cpp:378:9:378:11 | val | The variable $@ may not be initialized at this access. | test.cpp:359:6:359:8 | val | val | | test.cpp:378:9:378:11 | val | The variable $@ may not be initialized at this access. | test.cpp:359:6:359:8 | val | val |

View File

@@ -27,7 +27,7 @@ void test4(bool b) {
if (b) { if (b) {
foo = 1; foo = 1;
} }
use(foo); // BAD use(foo); // BAD [NOT DETECTED]
} }
void test5() { void test5() {
@@ -43,7 +43,7 @@ void test5(int count) {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
foo = i; foo = i;
} }
use(foo); // BAD use(foo); // BAD [NOT DETECTED]
} }
void test6(bool b) { void test6(bool b) {
@@ -52,7 +52,7 @@ void test6(bool b) {
foo = 42; foo = 42;
} }
if (b) { if (b) {
use(foo); // GOOD (REPORTED, FP) use(foo); // GOOD
} }
} }
@@ -64,7 +64,7 @@ void test7(bool b) {
set = true; set = true;
} }
if (set) { if (set) {
use(foo); // GOOD (REPORTED, FP) use(foo); // GOOD
} }
} }
@@ -89,7 +89,7 @@ void test9(int count) {
if (!set) { if (!set) {
foo = 42; foo = 42;
} }
use(foo); // GOOD (REPORTED, FP) use(foo); // GOOD
} }
void test10() { void test10() {
@@ -129,7 +129,7 @@ int absWrong(int i) {
} else if (i < 0) { } else if (i < 0) {
j = -i; j = -i;
} }
return j; // wrong: j may not be initialized before use return j; // wrong: j may not be initialized before use [NOT DETECTED]
} }
// Example from qhelp // Example from qhelp
@@ -326,7 +326,7 @@ int test28() {
a = false; a = false;
c = false; c = false;
} }
return val; // GOOD [FALSE POSITIVE] return val; // GOOD
} }
int test29() { int test29() {
@@ -472,4 +472,64 @@ void test44() {
int y = 1; int y = 1;
void(x + y); // BAD void(x + y); // BAD
}
enum class State { StateA, StateB, StateC };
int exhaustive_switch(State s) {
int y;
switch(s) {
case State::StateA:
y = 1;
break;
case State::StateB:
y = 2;
break;
case State::StateC:
y = 3;
break;
}
return y; // GOOD (y is always initialized)
}
int exhaustive_switch_2(State s) {
int y;
switch(s) {
case State::StateA:
y = 1;
break;
default:
y = 2;
break;
}
return y; // GOOD (y is always initialized)
}
int non_exhaustive_switch(State s) {
int y;
switch(s) {
case State::StateA:
y = 1;
break;
case State::StateB:
y = 2;
break;
}
return y; // BAD [NOT DETECTED] (y is not initialized when s = StateC)
}
int non_exhaustive_switch_2(State s) {
int y;
switch(s) {
case State::StateA:
y = 1;
break;
case State::StateB:
y = 2;
break;
}
if(s != State::StateC) {
return y; // GOOD (y is not initialized when s = StateC, but if s = StateC we won't reach this point)
}
return 0;
} }

View File

@@ -159,9 +159,9 @@ namespace Semmle.Autobuild.CSharp.Tests
bool IBuildActions.IsMacOs() => IsMacOs; bool IBuildActions.IsMacOs() => IsMacOs;
public bool IsArm { get; set; } public bool IsRunningOnAppleSilicon { get; set; }
bool IBuildActions.IsArm() => IsArm; bool IBuildActions.IsRunningOnAppleSilicon() => IsRunningOnAppleSilicon;
public string PathCombine(params string[] parts) public string PathCombine(params string[] parts)
{ {

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Xml; using System.Xml;
using Semmle.Util; using Semmle.Util;
@@ -119,10 +120,10 @@ namespace Semmle.Autobuild.Shared
bool IsMacOs(); bool IsMacOs();
/// <summary> /// <summary>
/// Gets a value indicating whether we are running on arm. /// Gets a value indicating whether we are running on Apple Silicon.
/// </summary> /// </summary>
/// <returns>True if we are running on arm.</returns> /// <returns>True if we are running on Apple Silicon.</returns>
bool IsArm(); bool IsRunningOnAppleSilicon();
/// <summary> /// <summary>
/// Combine path segments, Path.Combine(). /// Combine path segments, Path.Combine().
@@ -240,9 +241,25 @@ namespace Semmle.Autobuild.Shared
bool IBuildActions.IsMacOs() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX); bool IBuildActions.IsMacOs() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
bool IBuildActions.IsArm() => bool IBuildActions.IsRunningOnAppleSilicon()
RuntimeInformation.ProcessArchitecture == Architecture.Arm64 || {
RuntimeInformation.ProcessArchitecture == Architecture.Arm; var thisBuildActions = (IBuildActions)this;
if (!thisBuildActions.IsMacOs())
{
return false;
}
try
{
thisBuildActions.RunProcess("sysctl", "machdep.cpu.brand_string", workingDirectory: null, env: null, out var stdOut);
return stdOut?.Any(s => s?.ToLowerInvariant().Contains("apple") == true) ?? false;
}
catch (Exception)
{
return false;
}
}
string IBuildActions.PathCombine(params string[] parts) => Path.Combine(parts); string IBuildActions.PathCombine(params string[] parts) => Path.Combine(parts);

Some files were not shown because too many files have changed in this diff Show More