Merge branch 'main' into rdmarsh2/cpp/output-iterators-1

Fix merge conflict in test expectations
This commit is contained in:
Robert Marsh
2020-09-16 13:52:59 -07:00
425 changed files with 20307 additions and 4107 deletions

49
.github/workflows/query-list.yml vendored Normal file
View File

@@ -0,0 +1,49 @@
name: Build code scanning query list
on:
push:
branches:
- main
- 'rc/**'
pull_request:
paths:
- '.github/workflows/query-list.yml'
- 'misc/scripts/generate-code-scanning-query-list.py'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Clone self (github/codeql)
uses: actions/checkout@v2
with:
path: codeql
- name: Clone github/codeql-go
uses: actions/checkout@v2
with:
repository: 'github/codeql-go'
path: codeql-go
- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Download CodeQL CLI
uses: dsaltares/fetch-gh-release-asset@aa37ae5c44d3c9820bc12fe675e8670ecd93bd1c
with:
repo: "github/codeql-cli-binaries"
version: "latest"
file: "codeql-linux64.zip"
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unzip CodeQL CLI
run: unzip -d codeql-cli codeql-linux64.zip
- name: Build code scanning query list
run: |
PATH="$PATH:codeql-cli/codeql" python codeql/misc/scripts/generate-code-scanning-query-list.py > code-scanning-query-list.csv
- name: Upload code scanning query list
uses: actions/upload-artifact@v2
with:
name: code-scanning-query-list
path: code-scanning-query-list.csv

View File

@@ -20,7 +20,10 @@ The following changes in version 1.26 affect C/C++ analysis in all applications.
## Changes to libraries
* The QL class `Block`, denoting the `{ ... }` statement, is renamed to `BlockStmt`.
* The models library now models many taint flows through `std::array`, `std::vector`, `std::deque`, `std::list` and `std::forward_list`.
* The models library now models many more taint flows through `std::string`.
* The models library now models some taint flows through `std::ostream`.
* The models library now models some taint flows through `std::shared_ptr`, `std::unique_ptr`, `std::make_shared` and `std::make_unique`.
* The `SimpleRangeAnalysis` library now supports multiplications of the form
`e1 * e2` and `x *= e2` when `e1` and `e2` are unsigned or constant.

View File

@@ -0,0 +1,21 @@
# Improvements to Java analysis
The following changes in version 1.26 affect Java analysis in all applications.
## General improvements
## New queries
| **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------|
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|------------------------------|------------------------|-----------------------------------|
## Changes to libraries
* The QL class `Block`, denoting the `{ ... }` statement, is renamed to `BlockStmt`.

View File

@@ -3,6 +3,7 @@
## General improvements
* Support for the following frameworks and libraries has been improved:
- [bluebird](https://www.npmjs.com/package/bluebird)
- [fast-json-stable-stringify](https://www.npmjs.com/package/fast-json-stable-stringify)
- [fast-safe-stringify](https://www.npmjs.com/package/fast-safe-stringify)
- [javascript-stringify](https://www.npmjs.com/package/javascript-stringify)
@@ -10,9 +11,11 @@
- [json-stable-stringify](https://www.npmjs.com/package/json-stable-stringify)
- [json-stringify-safe](https://www.npmjs.com/package/json-stringify-safe)
- [json3](https://www.npmjs.com/package/json3)
- [lodash](https://www.npmjs.com/package/lodash)
- [object-inspect](https://www.npmjs.com/package/object-inspect)
- [pretty-format](https://www.npmjs.com/package/pretty-format)
- [stringify-object](https://www.npmjs.com/package/stringify-object)
- [underscore](https://www.npmjs.com/package/underscore)
* Analyzing files with the ".cjs" extension is now supported.
@@ -30,7 +33,9 @@
| Incomplete URL substring sanitization (`js/incomplete-url-substring-sanitization`) | More results | This query now recognizes additional URLs when the substring check is an inclusion check. |
| Ambiguous HTML id attribute (`js/duplicate-html-id`) | Results no longer shown | Precision tag reduced to "low". The query is no longer run by default. |
| Unused loop iteration variable (`js/unused-loop-variable`) | Fewer results | This query no longer flags variables in a destructuring array assignment that are not the last variable in the destructed array. |
| Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | More results | This query now recognizes more commands where colon, dash, and underscore are used. |
| Unsafe jQuery plugin (`js/unsafe-jquery-plugin`) | More results | This query now detects more unsafe uses of nested option properties. |
| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | More results | This query now recognizes some unsafe uses of `importScripts()` inside WebWorkers. |
## Changes to libraries

View File

@@ -9,6 +9,6 @@
import cpp
from Block blk
from BlockStmt blk
where blk.getNumStmt() = 0
select blk

View File

@@ -13,5 +13,5 @@
import cpp
from IfStmt i
where i.getThen().(Block).getNumStmt() = 0
where i.getThen().(BlockStmt).getNumStmt() = 0
select i

View File

@@ -8,6 +8,6 @@
import cpp
from Block b
from BlockStmt b
where b.getNumStmt() = 1
select b

View File

@@ -14,7 +14,7 @@ import cpp
class ComplexStmt extends Stmt {
ComplexStmt() {
exists(Block body |
exists(BlockStmt body |
body = this.(Loop).getStmt() or
body = this.(SwitchStmt).getStmt()
|
@@ -24,7 +24,7 @@ class ComplexStmt extends Stmt {
}
}
from Block b, int n, ComplexStmt complexStmt
from BlockStmt b, int n, ComplexStmt complexStmt
where
n = strictcount(ComplexStmt s | s = b.getAStmt()) and
n > 3 and

View File

@@ -17,7 +17,7 @@ where
shadowing(lv1, lv2) and
not lv1.isCompilerGenerated() and
not lv2.isCompilerGenerated() and
not lv1.getParentScope().(Block).isInMacroExpansion() and
not lv2.getParentScope().(Block).isInMacroExpansion()
not lv1.getParentScope().(BlockStmt).isInMacroExpansion() and
not lv2.getParentScope().(BlockStmt).isInMacroExpansion()
select lv1, "Variable " + lv1.getName() + " hides another variable of the same name (on $@).", lv2,
"line " + lv2.getLocation().getStartLine().toString()

View File

@@ -14,7 +14,7 @@
import cpp
predicate emptyBlock(ControlStructure s, Block b) {
predicate emptyBlock(ControlStructure s, BlockStmt b) {
b = s.getAChild() and
not exists(b.getAChild()) and
not b.isInMacroExpansion() and
@@ -23,7 +23,7 @@ predicate emptyBlock(ControlStructure s, Block b) {
class AffectedFile extends File {
AffectedFile() {
exists(Block b |
exists(BlockStmt b |
emptyBlock(_, b) and
this = b.getFile()
)
@@ -37,7 +37,7 @@ class AffectedFile extends File {
class BlockOrNonChild extends Element {
BlockOrNonChild() {
(
this instanceof Block
this instanceof BlockStmt
or
this instanceof Comment
or
@@ -78,7 +78,7 @@ class BlockOrNonChild extends Element {
/**
* A block that contains a non-child element.
*/
predicate emptyBlockContainsNonchild(Block b) {
predicate emptyBlockContainsNonchild(BlockStmt b) {
emptyBlock(_, b) and
exists(BlockOrNonChild c, AffectedFile file |
c.(BlockOrNonChild).getStartRankIn(file) = 1 + b.(BlockOrNonChild).getStartRankIn(file) and
@@ -91,7 +91,7 @@ predicate emptyBlockContainsNonchild(Block b) {
* A block that is entirely on one line, which also contains a comment. Chances
* are the comment is intended to refer to the block.
*/
predicate lineComment(Block b) {
predicate lineComment(BlockStmt b) {
emptyBlock(_, b) and
exists(Location bLocation, File f, int line |
bLocation = b.getLocation() and
@@ -106,7 +106,7 @@ predicate lineComment(Block b) {
)
}
from ControlStructure s, Block eb
from ControlStructure s, BlockStmt eb
where
emptyBlock(s, eb) and
not emptyBlockContainsNonchild(eb) and

View File

@@ -12,7 +12,7 @@
import cpp
import semmle.code.cpp.commons.Exclusions
Stmt getNextRealStmt(Block b, int i) {
Stmt getNextRealStmt(BlockStmt b, int i) {
result = b.getStmt(i + 1) and
not result instanceof EmptyStmt
or
@@ -20,7 +20,7 @@ Stmt getNextRealStmt(Block b, int i) {
result = getNextRealStmt(b, i + 1)
}
from JumpStmt js, Block b, int i, Stmt s
from JumpStmt js, BlockStmt b, int i, Stmt s
where
b.getStmt(i) = js and
s = getNextRealStmt(b, i) and

View File

@@ -12,7 +12,7 @@
import cpp
int lineInBlock(File f) {
exists(Block block, Location blockLocation |
exists(BlockStmt block, Location blockLocation |
block.getFile() = f and blockLocation = block.getLocation()
|
result in [blockLocation.getStartLine() .. blockLocation.getEndLine()]

View File

@@ -27,11 +27,11 @@ predicate macroUseLocation(File f, int start, int end) {
}
pragma[noopt]
predicate emptyIf(IfStmt s, Block b, File f, int start, int end) {
predicate emptyIf(IfStmt s, BlockStmt b, File f, int start, int end) {
s instanceof IfStmt and
not exists(s.getElse()) and
b = s.getThen() and
b instanceof Block and
b instanceof BlockStmt and
not exists(b.getAChild()) and
f = b.getFile() and
exists(Location l |
@@ -42,7 +42,7 @@ predicate emptyIf(IfStmt s, Block b, File f, int start, int end) {
}
pragma[noopt]
predicate query(IfStmt s, Block b) {
predicate query(IfStmt s, BlockStmt b) {
exists(File f, int blockStart, int blockEnd |
emptyIf(s, b, f, blockStart, blockEnd) and
not exists(int macroStart, int macroEnd |
@@ -53,7 +53,7 @@ predicate query(IfStmt s, Block b) {
)
}
from IfStmt s, Block b
from IfStmt s, BlockStmt b
where
query(s, b) and
not b.isInMacroExpansion()

View File

@@ -27,7 +27,7 @@ int logicalLength(FunctionDeclarationEntry f) {
count(Stmt s |
s.getEnclosingFunction() = f.getFunction() and
s.getFile() = f.getFile() and
not s instanceof Block and
not s instanceof BlockStmt and
not s instanceof EmptyStmt and
not exists(ForStmt for | s = for.getInitialization()) and
not s.isAffectedByMacro()

View File

@@ -14,7 +14,7 @@ import cpp
class OneLineStmt extends Stmt {
OneLineStmt() {
this.getLocation().getStartLine() = this.getLocation().getEndLine() and
not this instanceof Block and
not this instanceof BlockStmt and
not exists(ForStmt for | this = for.getInitialization()) and
(
// Either this statement is not touched by a macro at all...

View File

@@ -27,7 +27,7 @@ int logicalLength(FunctionDeclarationEntry f) {
count(Stmt s |
s.getEnclosingFunction() = f.getFunction() and
s.getFile() = f.getFile() and
not s instanceof Block and
not s instanceof BlockStmt and
not s instanceof EmptyStmt and
not exists(ForStmt for | s = for.getInitialization()) and
not s.isAffectedByMacro()

View File

@@ -13,7 +13,7 @@
import cpp
predicate blockDominates(Block check, Block access) {
predicate blockDominates(BlockStmt check, BlockStmt access) {
check.getLocation().getStartLine() <= access.getLocation().getStartLine() and
check.getLocation().getEndLine() >= access.getLocation().getEndLine()
}

View File

@@ -117,7 +117,7 @@ private predicate blockCoversStatement(int equivClass, int first, int last, Stmt
private Stmt statementInMethod(FunctionDeclarationEntry m) {
result.getParent+() = m.getBlock() and
not result.getLocation() instanceof UnknownStmtLocation and
not result instanceof Block
not result instanceof BlockStmt
}
private predicate duplicateStatement(

View File

@@ -18,6 +18,7 @@ from Include i, File f, string extension
where
f = i.getIncludedFile() and
extension = f.getExtension().toLowerCase() and
extension != "inc" and
extension != "inl" and
extension != "tcc" and
extension != "tpp" and

View File

@@ -13,7 +13,7 @@ import cpp
from Stmt parent, Stmt child
where
not child instanceof Block and
not child instanceof BlockStmt and
(
child = parent.(IfStmt).getThen()
or

View File

@@ -28,7 +28,7 @@ predicate oppositeOperators(string op1, string op2) {
* `!op2(_, _)`.
*/
predicate implementedAsNegationOf(Operator op1, Operator op2) {
exists(Block b, ReturnStmt r, NotExpr n, Expr o |
exists(BlockStmt b, ReturnStmt r, NotExpr n, Expr o |
b = op1.getBlock() and
b.getNumStmt() = 1 and
r = b.getStmt(0) and

View File

@@ -29,7 +29,7 @@ predicate localShadowsParameter(LocalVariable lv, Parameter p) {
from Variable v, Variable shadowed
where
not v.getParentScope().(Block).isInMacroExpansion() and
not v.getParentScope().(BlockStmt).isInMacroExpansion() and
(
v.(LocalVariableOrParameter).shadowsGlobal(shadowed.(GlobalVariable)) or
localShadowsParameter(v, shadowed) or

View File

@@ -38,7 +38,7 @@ predicate noDefUsePath(LocalVariable lv, ControlFlowNode n) {
}
predicate neighbouringStmts(Stmt s1, Stmt s2) {
exists(Block b, int i |
exists(BlockStmt b, int i |
i in [0 .. b.getNumStmt() - 2] and
s1 = b.getStmt(i) and
s2 = b.getStmt(i + 1)

View File

@@ -22,6 +22,6 @@ where
not s instanceof ControlStructure and
// Exclude blocks; if a child of the block violates the rule that will still
// be picked up so there is no point in blaming the block as well
not s instanceof Block and
not s instanceof BlockStmt and
s.isPure()
select s, "AV Rule 187: All non-null statements shall potentially have a side-effect."

View File

@@ -18,7 +18,7 @@ import cpp
// whether t is the last statement of s, possibly peeling off blocks
predicate isTerminatingStmt(Stmt s, Stmt t) {
s = t or isTerminatingStmt(s.(Block).getLastStmt(), t)
s = t or isTerminatingStmt(s.(BlockStmt).getLastStmt(), t)
}
from BreakStmt s

View File

@@ -128,7 +128,7 @@ class Element extends ElementBase {
/**
* Gets the parent scope of this `Element`, if any.
* A scope is a `Type` (`Class` / `Enum`), a `Namespace`, a `Block`, a `Function`,
* A scope is a `Type` (`Class` / `Enum`), a `Namespace`, a `BlockStmt`, a `Function`,
* or certain kinds of `Statement`.
*/
Element getParentScope() {
@@ -161,7 +161,7 @@ class Element extends ElementBase {
exists(EnumConstant e | this = e and result = e.getDeclaringEnum())
or
// result instanceof block|function
exists(Block b | this = b and blockscope(unresolveElement(b), unresolveElement(result)))
exists(BlockStmt b | this = b and blockscope(unresolveElement(b), unresolveElement(result)))
or
exists(TemplateFunction tf | this = tf.getATemplateArgument() and result = tf)
or

View File

@@ -268,7 +268,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
* block, this gives the block guarded by the try statement. See
* `FunctionTryStmt` for further information.
*/
Block getBlock() { result.getParentScope() = this }
BlockStmt getBlock() { result.getParentScope() = this }
/** Holds if this function has an entry point. */
predicate hasEntryPoint() { exists(getEntryPoint()) }
@@ -276,7 +276,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
/**
* Gets the first node in this function's control flow graph.
*
* For most functions, this first node will be the `Block` returned by
* For most functions, this first node will be the `BlockStmt` returned by
* `getBlock`. However in C++, the first node can also be a
* `FunctionTryStmt`.
*/
@@ -564,7 +564,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
* If this is a function definition, get the block containing the
* function body.
*/
Block getBlock() {
BlockStmt getBlock() {
this.isDefinition() and
result = getFunction().getBlock() and
result.getFile() = this.getFile()
@@ -576,7 +576,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
*/
pragma[noopt]
int getNumberOfLines() {
exists(Block b, Location l, int start, int end, int diff | b = getBlock() |
exists(BlockStmt b, Location l, int start, int end, int diff | b = getBlock() |
l = b.getLocation() and
start = l.getStartLine() and
end = l.getEndLine() and

View File

@@ -105,16 +105,23 @@ class Location extends @location {
}
/**
* DEPRECATED: Use `Location` instead.
* A location of an element. Not used for expressions or statements, which
* instead use LocationExpr and LocationStmt respectively.
*/
library class LocationDefault extends Location, @location_default { }
deprecated library class LocationDefault extends Location, @location_default { }
/** A location of a statement. */
library class LocationStmt extends Location, @location_stmt { }
/**
* DEPRECATED: Use `Location` instead.
* A location of a statement.
*/
deprecated library class LocationStmt extends Location, @location_stmt { }
/** A location of an expression. */
library class LocationExpr extends Location, @location_expr { }
/**
* DEPRECATED: Use `Location` instead.
* A location of an expression.
*/
deprecated library class LocationExpr extends Location, @location_expr { }
/**
* Gets the length of the longest line in file `f`.

View File

@@ -136,7 +136,7 @@ deprecated class ObjcTryStmt extends TryStmt {
* DEPRECATED: Objective-C is no longer supported.
* An Objective C `@finally` block.
*/
deprecated class FinallyBlock extends Block {
deprecated class FinallyBlock extends BlockStmt {
FinallyBlock() { none() }
/** Gets the try statement corresponding to this finally block. */

View File

@@ -98,7 +98,7 @@ class Parameter extends LocalScopeVariable, @parameter {
* DEPRECATED: this method was used in a previous implementation of
* getName, but is no longer in use.
*/
deprecated string getNameInBlock(Block b) {
deprecated string getNameInBlock(BlockStmt b) {
exists(ParameterDeclarationEntry pde |
pde.getFunctionDeclarationEntry().getBlock() = b and
this.getFunction().getBlock() = b and
@@ -127,7 +127,7 @@ class Parameter extends LocalScopeVariable, @parameter {
* Gets the catch block to which this parameter belongs, if it is a catch
* block parameter.
*/
Block getCatchBlock() { params(underlyingElement(this), unresolveElement(result), _, _) }
BlockStmt getCatchBlock() { params(underlyingElement(this), unresolveElement(result), _, _) }
/**
* Gets the zero-based index of this parameter.

View File

@@ -25,7 +25,7 @@ private predicate exprInVoidContext(Expr e) {
(
exists(ExprStmt s |
s = e.getParent() and
not exists(StmtExpr se | s = se.getStmt().(Block).getLastStmt())
not exists(StmtExpr se | s = se.getStmt().(BlockStmt).getLastStmt())
)
or
exists(ConditionalExpr c | c.getThen() = e and c instanceof ExprInVoidContext)

View File

@@ -118,7 +118,7 @@ private predicate excludeNodeAndNodesBelow(Expr e) {
or
// Constructor init lists should be evaluated, and we can change this in
// the future, but it would mean that a `Function` entry point is not
// always a `Block` or `FunctionTryStmt`.
// always a `BlockStmt` or `FunctionTryStmt`.
e instanceof ConstructorInit
or
// Destructor field destructions should also be hooked into the CFG
@@ -408,10 +408,10 @@ private Node getControlOrderChildSparse(Node n, int i) {
// in-line in the block containing their corresponding DeclStmt but should
// not be evaluated in the order implied by their position in the block. We
// do the following.
// - Block skips all the VlaDeclStmt and VlaDimensionStmt children.
// - BlockStmt skips all the VlaDeclStmt and VlaDimensionStmt children.
// - VlaDeclStmt is inserted as a child of DeclStmt
// - VlaDimensionStmt is inserted as a child of VlaDeclStmt
result = n.(Block).getChild(i) and
result = n.(BlockStmt).getChild(i) and
not result instanceof VlaDeclStmt and
not result instanceof VlaDimensionStmt
or
@@ -557,7 +557,7 @@ private class Spec extends Pos {
*/
private predicate straightLineSparse(Node scope, int i, Node ni, Spec spec) {
scope =
any(Block b |
any(BlockStmt b |
i = -1 and ni = b and spec.isAt()
or
if exists(getLastControlOrderChild(b))
@@ -734,7 +734,7 @@ private predicate straightLineSparse(Node scope, int i, Node ni, Spec spec) {
or
// If the switch body is not a block then this step is skipped, and the
// expression jumps directly to the cases.
i = 1 and ni = s.getStmt().(Block) and spec.isAt()
i = 1 and ni = s.getStmt().(BlockStmt) and spec.isAt()
or
i = 2 and ni = s.getASwitchCase() and spec.isBefore()
or
@@ -1010,7 +1010,7 @@ private predicate subEdgeIncludingDestructors(Pos p1, Node n1, Node n2, Pos p2)
* The exact placement of that call in the CFG depends on the type of
* `node` as follows:
*
* - `Block`: after ordinary control flow falls off the end of the block
* - `BlockStmt`: after ordinary control flow falls off the end of the block
* without jumps or exceptions.
* - `ReturnStmt`: After the statement itself or after its operand (if
* present).

View File

@@ -182,7 +182,7 @@ private int switchCaseRangeEnd(SwitchCase sc) {
* body `switchBlock`. There may be several such expressions: for example, if
* the condition is `(x ? y : z)` then the result is {`y`, `z`}.
*/
private Node getASwitchExpr(SwitchStmt switch, Block switchBlock) {
private Node getASwitchExpr(SwitchStmt switch, BlockStmt switchBlock) {
switch.getStmt() = switchBlock and
successors_extended(result, switchBlock)
}
@@ -192,7 +192,7 @@ private Node getASwitchExpr(SwitchStmt switch, Block switchBlock) {
* from `switchBlock` to `sc` is impossible. This considers only non-`default`
* switch cases.
*/
private predicate impossibleSwitchEdge(Block switchBlock, SwitchCase sc) {
private predicate impossibleSwitchEdge(BlockStmt switchBlock, SwitchCase sc) {
not sc instanceof DefaultCase and
exists(SwitchStmt switch |
switch = sc.getSwitchStmt() and
@@ -215,7 +215,7 @@ private predicate impossibleSwitchEdge(Block switchBlock, SwitchCase sc) {
* If a switch provably always chooses a non-default case, then the edge to
* the default case is impossible.
*/
private predicate impossibleDefaultSwitchEdge(Block switchBlock, DefaultCase dc) {
private predicate impossibleDefaultSwitchEdge(BlockStmt switchBlock, DefaultCase dc) {
exists(SwitchStmt switch |
switch = dc.getSwitchStmt() and
switch.getStmt() = switchBlock and

View File

@@ -29,7 +29,7 @@ private predicate stdIdentityFunction(Function f) { f.hasQualifiedName("std", ["
*/
private predicate stdAddressOf(Function f) { f.hasQualifiedName("std", "addressof") }
private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) {
private predicate lvalueToLvalueStepPure(Expr lvalueIn, Expr lvalueOut) {
lvalueIn.getConversion() = lvalueOut.(ParenthesisExpr)
or
// When an object is implicitly converted to a reference to one of its base
@@ -42,6 +42,10 @@ private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) {
// such casts.
lvalueIn.getConversion() = lvalueOut and
lvalueOut.(CStyleCast).isImplicit()
}
private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) {
lvalueToLvalueStepPure(lvalueIn, lvalueOut)
or
// C++ only
lvalueIn = lvalueOut.(PrefixCrementOperation).getOperand().getFullyConverted()
@@ -214,6 +218,69 @@ private predicate referenceToUpdate(Expr reference, Expr outer, ControlFlowNode
)
}
private predicate lvalueFromVariableAccess(VariableAccess va, Expr lvalue) {
// Base case for non-reference types.
lvalue = va and
not va.getConversion() instanceof ReferenceDereferenceExpr
or
// Base case for reference types where we pretend that they are
// non-reference types. The type of the target of `va` can be `ReferenceType`
// or `FunctionReferenceType`.
lvalue = va.getConversion().(ReferenceDereferenceExpr)
or
// lvalue -> lvalue
exists(Expr prev |
lvalueFromVariableAccess(va, prev) and
lvalueToLvalueStep(prev, lvalue)
)
or
// pointer -> lvalue
exists(Expr prev |
pointerFromVariableAccess(va, prev) and
pointerToLvalueStep(prev, lvalue)
)
or
// reference -> lvalue
exists(Expr prev |
referenceFromVariableAccess(va, prev) and
referenceToLvalueStep(prev, lvalue)
)
}
private predicate pointerFromVariableAccess(VariableAccess va, Expr pointer) {
// pointer -> pointer
exists(Expr prev |
pointerFromVariableAccess(va, prev) and
pointerToPointerStep(prev, pointer)
)
or
// reference -> pointer
exists(Expr prev |
referenceFromVariableAccess(va, prev) and
referenceToPointerStep(prev, pointer)
)
or
// lvalue -> pointer
exists(Expr prev |
lvalueFromVariableAccess(va, prev) and
lvalueToPointerStep(prev, pointer)
)
}
private predicate referenceFromVariableAccess(VariableAccess va, Expr reference) {
// reference -> reference
exists(Expr prev |
referenceFromVariableAccess(va, prev) and
referenceToReferenceStep(prev, reference)
)
or
// lvalue -> reference
exists(Expr prev |
lvalueFromVariableAccess(va, prev) and
lvalueToReferenceStep(prev, reference)
)
}
/**
* Holds if `node` is a control-flow node that may modify `inner` (or what it
* points to) through `outer`. The two expressions may be `Conversion`s. Plain
@@ -236,7 +303,7 @@ predicate valueToUpdate(Expr inner, Expr outer, ControlFlowNode node) {
(
inner instanceof VariableAccess and
// Don't track non-field assignments
(assignmentTo(outer, _) implies inner instanceof FieldAccess)
not (assignmentTo(outer, _) and outer.(VariableAccess).getTarget() instanceof StackVariable)
or
inner instanceof ThisExpr
or
@@ -245,3 +312,27 @@ predicate valueToUpdate(Expr inner, Expr outer, ControlFlowNode node) {
// can't do anything useful with those at the moment.
)
}
/**
* Holds if `e` is a fully-converted expression that evaluates to an lvalue
* derived from `va` and is used for reading from or assigning to. This is in
* contrast with a variable access that is used for taking an address (`&x`)
* or simply discarding its value (`x;`).
*
* This analysis does not propagate across assignments or calls, and unlike
* `variableAccessedAsValue` in `semmle.code.cpp.dataflow.EscapesTree` it
* propagates through array accesses but not field accesses. The analysis is
* also not concerned with whether the lvalue `e` is converted to an rvalue --
* to examine that, use the relevant member predicates on `Expr`.
*
* If `va` has reference type, the analysis concerns the value pointed to by
* the reference rather than the reference itself. The expression `e` may be a
* `Conversion`.
*/
predicate variablePartiallyAccessed(VariableAccess va, Expr e) {
lvalueFromVariableAccess(va, e) and
not lvalueToLvalueStepPure(e, _) and
not lvalueToPointerStep(e, _) and
not lvalueToReferenceStep(e, _) and
not e = any(ExprInVoidContext eivc | e = eivc.getConversion*())
}

View File

@@ -6,6 +6,7 @@ private import cpp
private import semmle.code.cpp.dataflow.internal.FlowVar
private import semmle.code.cpp.models.interfaces.DataFlow
private import semmle.code.cpp.controlflow.Guards
private import semmle.code.cpp.dataflow.internal.AddressFlow
cached
private newtype TNode =
@@ -622,6 +623,15 @@ private predicate exprToExprStep_nocfg(Expr fromExpr, Expr toExpr) {
or
toExpr.(AddressOfExpr).getOperand() = fromExpr
or
// This rule enables flow from an array to its elements. Example: `a` to
// `a[i]` or `*a`, where `a` is an array type. It does not enable flow from a
// pointer to its indirection as in `p[i]` where `p` is a pointer type.
exists(Expr toConverted |
variablePartiallyAccessed(fromExpr, toConverted) and
toExpr = toConverted.getUnconverted() and
not toExpr = fromExpr
)
or
toExpr.(BuiltInOperationBuiltInAddressOf).getOperand() = fromExpr
or
// The following case is needed to track the qualifier object for flow
@@ -641,14 +651,25 @@ private predicate exprToExprStep_nocfg(Expr fromExpr, Expr toExpr) {
// `ClassAggregateLiteral` (`{ capture1, ..., captureN }`).
toExpr.(LambdaExpression).getInitializer() = fromExpr
or
// Data flow through a function model.
toExpr =
any(Call call |
exists(DataFlowFunction f, FunctionInput inModel, FunctionOutput outModel, int iIn |
call.getTarget() = f and
exists(DataFlowFunction f, FunctionInput inModel, FunctionOutput outModel |
f.hasDataFlow(inModel, outModel) and
outModel.isReturnValue() and
inModel.isParameter(iIn) and
fromExpr = call.getArgument(iIn)
(
exists(int iIn |
inModel.isParameter(iIn) and
fromExpr = call.getArgument(iIn)
)
or
inModel.isQualifierObject() and
fromExpr = call.getQualifier()
or
inModel.isQualifierAddress() and
fromExpr = call.getQualifier()
) and
call.getTarget() = f and
outModel.isReturnValue()
)
)
}

View File

@@ -39,10 +39,10 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
}
/**
* Holds if `node` should be a barrier in all global taint flow configurations
* Holds if `node` should be a sanitizer in all global taint flow configurations
* but not in local taint.
*/
predicate defaultTaintBarrier(DataFlow::Node node) { none() }
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
/**
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
@@ -96,10 +96,17 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
exists(TaintFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
call.getTarget() = f and
inModel.isReturnValueDeref() and
outModel.isQualifierObject() and
f.hasTaintFlow(inModel, outModel) and
nodeFrom.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = call and
nodeTo.asDefiningArgument() = call.getQualifier()
f.hasTaintFlow(inModel, outModel) and
(
outModel.isQualifierObject() and
nodeTo.asDefiningArgument() = call.getQualifier()
or
exists(int argOutIndex |
outModel.isParameterDeref(argOutIndex) and
nodeTo.asDefiningArgument() = call.getArgument(argOutIndex)
)
)
)
}

View File

@@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrier(DataFlow::Node node) {
isSanitizer(node) or
defaultTaintBarrier(node)
defaultTaintSanitizer(node)
}
/** Holds if data flow into `node` is prohibited. */
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
/** Holds if data flow out of `node` is prohibited. */
/** Holds if taint propagation out of `node` is prohibited. */
predicate isSanitizerOut(DataFlow::Node node) { none() }
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }

View File

@@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrier(DataFlow::Node node) {
isSanitizer(node) or
defaultTaintBarrier(node)
defaultTaintSanitizer(node)
}
/** Holds if data flow into `node` is prohibited. */
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
/** Holds if data flow out of `node` is prohibited. */
/** Holds if taint propagation out of `node` is prohibited. */
predicate isSanitizerOut(DataFlow::Node node) { none() }
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }

View File

@@ -27,7 +27,7 @@ class Expr extends StmtParent, @expr {
Function getEnclosingFunction() { result = exprEnclosingElement(this) }
/** Gets the nearest enclosing set of curly braces around this expression in the source, if any. */
Block getEnclosingBlock() { result = getEnclosingStmt().getEnclosingBlock() }
BlockStmt getEnclosingBlock() { result = getEnclosingStmt().getEnclosingBlock() }
override Stmt getEnclosingStmt() {
result = this.getParent().(Expr).getEnclosingStmt()
@@ -402,7 +402,7 @@ class Expr extends StmtParent, @expr {
*/
predicate hasImplicitConversion() {
exists(Expr e |
exprconv(underlyingElement(this), unresolveElement(e)) and e.(Cast).isImplicit()
exprconv(underlyingElement(this), unresolveElement(e)) and e.(Conversion).isImplicit()
)
}
@@ -414,7 +414,7 @@ class Expr extends StmtParent, @expr {
*/
predicate hasExplicitConversion() {
exists(Expr e |
exprconv(underlyingElement(this), unresolveElement(e)) and not e.(Cast).isImplicit()
exprconv(underlyingElement(this), unresolveElement(e)) and not e.(Conversion).isImplicit()
)
}
@@ -453,12 +453,14 @@ class Expr extends StmtParent, @expr {
* cast from B to C. Only (1) and (2) would be included.
*/
Expr getExplicitlyConverted() {
// result is this or one of its conversions
result = this.getConversion*() and
// result is not an implicit conversion - it's either the expr or an explicit cast
(result = this or not result.(Cast).isImplicit()) and
// there is no further explicit conversion after result
not exists(Cast other | other = result.getConversion+() and not other.isImplicit())
// For performance, we avoid a full transitive closure over `getConversion`.
// Since there can be several implicit conversions before and after an
// explicit conversion, use `getImplicitlyConverted` to step over them
// cheaply. Then, if there is an explicit conversion following the implict
// conversion sequence, recurse to handle multiple explicit conversions.
if this.getImplicitlyConverted().hasExplicitConversion()
then result = this.getImplicitlyConverted().getConversion().getExplicitlyConverted()
else result = this
}
/**
@@ -1109,7 +1111,7 @@ class StmtExpr extends Expr, @expr_stmt {
/** Get the result expression of a statement. (Helper function for StmtExpr.) */
private Expr getStmtResultExpr(Stmt stmt) {
result = stmt.(ExprStmt).getExpr() or
result = getStmtResultExpr(stmt.(Block).getLastStmt())
result = getStmtResultExpr(stmt.(BlockStmt).getLastStmt())
}
/**

View File

@@ -144,8 +144,23 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
*/
predicate jumpStep(Node n1, Node n2) { none() }
/**
* Gets a field corresponding to the bit range `[startBit..endBit)` of class `c`, if any.
*/
private Field getAField(Class c, int startBit, int endBit) {
result.getDeclaringType() = c and
startBit = 8 * result.getByteOffset() and
endBit = 8 * result.getType().getSize() + startBit
or
exists(Field f, Class cInner |
f = c.getAField() and
cInner = f.getUnderlyingType() and
result = getAField(cInner, startBit - 8 * f.getByteOffset(), endBit - 8 * f.getByteOffset())
)
}
private newtype TContent =
TFieldContent(Field f) or
TFieldContent(Class c, int startBit, int endBit) { exists(getAField(c, startBit, endBit)) } or
TCollectionContent() or
TArrayContent()
@@ -163,17 +178,18 @@ class Content extends TContent {
}
private class FieldContent extends Content, TFieldContent {
Field f;
Class c;
int startBit;
int endBit;
FieldContent() { this = TFieldContent(f) }
FieldContent() { this = TFieldContent(c, startBit, endBit) }
Field getField() { result = f }
// Ensure that there's just 1 result for `toString`.
override string toString() { result = min(Field f | f = getAField() | f.toString()) }
override string toString() { result = f.toString() }
predicate hasOffset(Class cl, int start, int end) { cl = c and start = startBit and end = endBit }
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
f.getLocation().hasLocationInfo(path, sl, sc, el, ec)
}
Field getAField() { result = getAField(c, startBit, endBit) }
}
private class CollectionContent extends Content, TCollectionContent {
@@ -185,20 +201,38 @@ private class ArrayContent extends Content, TArrayContent {
}
private predicate storeStepNoChi(Node node1, Content f, PostUpdateNode node2) {
exists(FieldAddressInstruction fa, StoreInstruction store |
exists(StoreInstruction store, Class c |
store = node2.asInstruction() and
store.getDestinationAddress() = fa and
store.getSourceValue() = node1.asInstruction() and
f.(FieldContent).getField() = fa.getField()
getWrittenField(store, f.(FieldContent).getAField(), c) and
f.(FieldContent).hasOffset(c, _, _)
)
}
pragma[noinline]
private predicate getWrittenField(StoreInstruction store, Field f, Class c) {
exists(FieldAddressInstruction fa |
fa = store.getDestinationAddress() and
f = fa.getField() and
c = f.getDeclaringType()
)
}
private predicate storeStepChi(Node node1, Content f, PostUpdateNode node2) {
exists(FieldAddressInstruction fa, StoreInstruction store |
exists(StoreInstruction store, ChiInstruction chi |
node1.asInstruction() = store and
store.getDestinationAddress() = fa and
node2.asInstruction().(ChiInstruction).getPartial() = store and
f.(FieldContent).getField() = fa.getField()
node2.asInstruction() = chi and
chi.getPartial() = store and
exists(Class c |
c = chi.getResultType() and
exists(int startBit, int endBit |
chi.getUpdatedInterval(startBit, endBit) and
f.(FieldContent).hasOffset(c, startBit, endBit)
)
or
getWrittenField(store, f.(FieldContent).getAField(), c) and
f.(FieldContent).hasOffset(c, _, _)
)
)
}
@@ -212,17 +246,37 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
storeStepChi(node1, f, node2)
}
bindingset[result, i]
private int unbindInt(int i) { i <= result and i >= result }
pragma[noinline]
private predicate getLoadedField(LoadInstruction load, Field f, Class c) {
exists(FieldAddressInstruction fa |
fa = load.getSourceAddress() and
f = fa.getField() and
c = f.getDeclaringType()
)
}
/**
* Holds if data can flow from `node1` to `node2` via a read of `f`.
* Thus, `node1` references an object with a field `f` whose value ends up in
* `node2`.
*/
predicate readStep(Node node1, Content f, Node node2) {
exists(FieldAddressInstruction fa, LoadInstruction load |
load.getSourceAddress() = fa and
exists(LoadInstruction load |
node2.asInstruction() = load and
node1.asInstruction() = load.getSourceValueOperand().getAnyDef() and
fa.getField() = f.(FieldContent).getField() and
load = node2.asInstruction()
exists(Class c |
c = load.getSourceValueOperand().getAnyDef().getResultType() and
exists(int startBit, int endBit |
load.getSourceValueOperand().getUsedInterval(unbindInt(startBit), unbindInt(endBit)) and
f.(FieldContent).hasOffset(c, startBit, endBit)
)
or
getLoadedField(load, f.(FieldContent).getAField(), c) and
f.(FieldContent).hasOffset(c, _, _)
)
)
}

View File

@@ -335,12 +335,14 @@ abstract private class PartialDefinitionNode extends PostUpdateNode {
private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
override ChiInstruction instr;
FieldAddressInstruction field;
StoreInstruction store;
ExplicitFieldStoreQualifierNode() {
not instr.isResultConflated() and
exists(StoreInstruction store |
instr.getPartial() = store and field = store.getDestinationAddress()
instr.getPartial() = store and
(
instr.getUpdatedInterval(_, _) or
store.getDestinationAddress() instanceof FieldAddressInstruction
)
}
@@ -351,7 +353,12 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() }
override Expr getDefinedExpr() {
result = field.getObjectAddress().getUnconvertedResultExpression()
result =
store
.getDestinationAddress()
.(FieldAddressInstruction)
.getObjectAddress()
.getUnconvertedResultExpression()
}
}
@@ -363,17 +370,22 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
*/
private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode {
override StoreInstruction instr;
FieldAddressInstruction field;
ExplicitSingleFieldStoreQualifierNode() {
field = instr.getDestinationAddress() and
not exists(ChiInstruction chi | chi.getPartial() = instr)
not exists(ChiInstruction chi | chi.getPartial() = instr) and
// Without this condition any store would create a `PostUpdateNode`.
instr.getDestinationAddress() instanceof FieldAddressInstruction
}
override Node getPreUpdateNode() { none() }
override Expr getDefinedExpr() {
result = field.getObjectAddress().getUnconvertedResultExpression()
result =
instr
.getDestinationAddress()
.(FieldAddressInstruction)
.getObjectAddress()
.getUnconvertedResultExpression()
}
}
@@ -545,7 +557,7 @@ pragma[noinline]
private predicate getFieldSizeOfClass(Class c, Type type, int size) {
exists(Field f |
f.getDeclaringType() = c and
f.getType() = type and
f.getUnderlyingType() = type and
type.getSize() = size
)
}
@@ -589,7 +601,7 @@ private predicate simpleOperandLocalFlowStep(Instruction iFrom, Operand opTo) {
exists(LoadInstruction load |
load.getSourceValueOperand() = opTo and
opTo.getAnyDef() = iFrom and
isSingleFieldClass(iFrom.getResultType(), opTo.getType())
isSingleFieldClass(iFrom.getResultType(), opTo.getType().getUnderlyingType())
)
}

View File

@@ -100,10 +100,10 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
}
/**
* Holds if `node` should be a barrier in all global taint flow configurations
* Holds if `node` should be a sanitizer in all global taint flow configurations
* but not in local taint.
*/
predicate defaultTaintBarrier(DataFlow::Node node) { none() }
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
/**
* Holds if taint can flow from `instrIn` to `instrOut` through a call to a

View File

@@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrier(DataFlow::Node node) {
isSanitizer(node) or
defaultTaintBarrier(node)
defaultTaintSanitizer(node)
}
/** Holds if data flow into `node` is prohibited. */
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
/** Holds if data flow out of `node` is prohibited. */
/** Holds if taint propagation out of `node` is prohibited. */
predicate isSanitizerOut(DataFlow::Node node) { none() }
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }

View File

@@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrier(DataFlow::Node node) {
isSanitizer(node) or
defaultTaintBarrier(node)
defaultTaintSanitizer(node)
}
/** Holds if data flow into `node` is prohibited. */
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
/** Holds if data flow out of `node` is prohibited. */
/** Holds if taint propagation out of `node` is prohibited. */
predicate isSanitizerOut(DataFlow::Node node) { none() }
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }

View File

@@ -1962,6 +1962,13 @@ class ChiInstruction extends Instruction {
* Gets the operand that represents the new value written by the memory write.
*/
final Instruction getPartial() { result = getPartialOperand().getDef() }
/**
* Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand.
*/
final predicate getUpdatedInterval(int startBit, int endBit) {
Construction::getIntervalUpdatedByChi(this, startBit, endBit)
}
}
/**

View File

@@ -328,6 +328,14 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper
not Construction::isInCycle(useInstr) and
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
}
/**
* Holds if the operand totally overlaps with its definition and consumes the
* bit range `[startBitOffset, endBitOffset)` relative to the start address of the definition.
*/
predicate getUsedInterval(int startBitOffset, int endBitOffset) {
Construction::getUsedInterval(this, startBitOffset, endBitOffset)
}
}
/**

View File

@@ -617,3 +617,9 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
)
)
}
/** Gets the start bit offset of a `MemoryLocation`, if any. */
int getStartBitOffset(VariableMemoryLocation location) { result = location.getStartBitOffset() }
/** Gets the end bit offset of a `MemoryLocation`, if any. */
int getEndBitOffset(VariableMemoryLocation location) { result = location.getEndBitOffset() }

View File

@@ -149,6 +149,34 @@ private module Cached {
)
}
/**
* Holds if the partial operand of this `ChiInstruction` updates the bit range
* `[startBitOffset, endBitOffset)` of the total operand.
*/
cached
predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBitOffset, int endBitOffset) {
exists(Alias::MemoryLocation location, OldInstruction oldInstruction |
oldInstruction = getOldInstruction(chi.getPartial()) and
location = Alias::getResultMemoryLocation(oldInstruction) and
startBitOffset = Alias::getStartBitOffset(location) and
endBitOffset = Alias::getEndBitOffset(location)
)
}
/**
* Holds if `operand` totally overlaps with its definition and consumes the bit range
* `[startBitOffset, endBitOffset)`.
*/
cached
predicate getUsedInterval(NonPhiMemoryOperand operand, int startBitOffset, int endBitOffset) {
exists(Alias::MemoryLocation location, OldIR::NonPhiMemoryOperand oldOperand |
oldOperand = operand.getUse().(OldInstruction).getAnOperand() and
location = Alias::getOperandMemoryLocation(oldOperand) and
startBitOffset = Alias::getStartBitOffset(location) and
endBitOffset = Alias::getEndBitOffset(location)
)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.

View File

@@ -1962,6 +1962,13 @@ class ChiInstruction extends Instruction {
* Gets the operand that represents the new value written by the memory write.
*/
final Instruction getPartial() { result = getPartialOperand().getDef() }
/**
* Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand.
*/
final predicate getUpdatedInterval(int startBit, int endBit) {
Construction::getIntervalUpdatedByChi(this, startBit, endBit)
}
}
/**

View File

@@ -328,6 +328,14 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper
not Construction::isInCycle(useInstr) and
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
}
/**
* Holds if the operand totally overlaps with its definition and consumes the
* bit range `[startBitOffset, endBitOffset)` relative to the start address of the definition.
*/
predicate getUsedInterval(int startBitOffset, int endBitOffset) {
Construction::getUsedInterval(this, startBitOffset, endBitOffset)
}
}
/**

View File

@@ -182,6 +182,18 @@ Instruction getMemoryOperandDefinition(
none()
}
/**
* Holds if the partial operand of this `ChiInstruction` updates the bit range
* `[startBitOffset, endBitOffset)` of the total operand.
*/
predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBit, int endBit) { none() }
/**
* Holds if the operand totally overlaps with its definition and consumes the
* bit range `[startBitOffset, endBitOffset)`.
*/
predicate getUsedInterval(Operand operand, int startBit, int endBit) { none() }
/** Gets a non-phi instruction that defines an operand of `instr`. */
private Instruction getNonPhiOperandDef(Instruction instr) {
result = getRegisterOperandDefinition(instr, _)

View File

@@ -2905,7 +2905,7 @@ predicate exprNeedsCopyIfNotLoaded(Expr expr) {
private predicate exprImmediatelyDiscarded(Expr expr) {
exists(ExprStmt s |
s = expr.getParent() and
not exists(StmtExpr se | s = se.getStmt().(Block).getLastStmt())
not exists(StmtExpr se | s = se.getStmt().(BlockStmt).getLastStmt())
)
or
exists(CommaExpr c | c.getLeftOperand() = expr)

View File

@@ -290,7 +290,7 @@ class TranslatedTryStmt extends TranslatedStmt {
}
class TranslatedBlock extends TranslatedStmt {
override Block stmt;
override BlockStmt stmt;
override TranslatedElement getChild(int id) { result = getStmt(id) }

View File

@@ -1962,6 +1962,13 @@ class ChiInstruction extends Instruction {
* Gets the operand that represents the new value written by the memory write.
*/
final Instruction getPartial() { result = getPartialOperand().getDef() }
/**
* Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand.
*/
final predicate getUpdatedInterval(int startBit, int endBit) {
Construction::getIntervalUpdatedByChi(this, startBit, endBit)
}
}
/**

View File

@@ -328,6 +328,14 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper
not Construction::isInCycle(useInstr) and
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
}
/**
* Holds if the operand totally overlaps with its definition and consumes the
* bit range `[startBitOffset, endBitOffset)` relative to the start address of the definition.
*/
predicate getUsedInterval(int startBitOffset, int endBitOffset) {
Construction::getUsedInterval(this, startBitOffset, endBitOffset)
}
}
/**

View File

@@ -149,6 +149,34 @@ private module Cached {
)
}
/**
* Holds if the partial operand of this `ChiInstruction` updates the bit range
* `[startBitOffset, endBitOffset)` of the total operand.
*/
cached
predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBitOffset, int endBitOffset) {
exists(Alias::MemoryLocation location, OldInstruction oldInstruction |
oldInstruction = getOldInstruction(chi.getPartial()) and
location = Alias::getResultMemoryLocation(oldInstruction) and
startBitOffset = Alias::getStartBitOffset(location) and
endBitOffset = Alias::getEndBitOffset(location)
)
}
/**
* Holds if `operand` totally overlaps with its definition and consumes the bit range
* `[startBitOffset, endBitOffset)`.
*/
cached
predicate getUsedInterval(NonPhiMemoryOperand operand, int startBitOffset, int endBitOffset) {
exists(Alias::MemoryLocation location, OldIR::NonPhiMemoryOperand oldOperand |
oldOperand = operand.getUse().(OldInstruction).getAnOperand() and
location = Alias::getOperandMemoryLocation(oldOperand) and
startBitOffset = Alias::getStartBitOffset(location) and
endBitOffset = Alias::getEndBitOffset(location)
)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.

View File

@@ -79,3 +79,9 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
result = getMemoryLocation(getAddressOperandAllocation(operand.getAddressOperand()))
}
/** Gets the start bit offset of a `MemoryLocation`, if any. */
int getStartBitOffset(MemoryLocation location) { none() }
/** Gets the end bit offset of a `MemoryLocation`, if any. */
int getEndBitOffset(MemoryLocation location) { none() }

View File

@@ -334,7 +334,7 @@ private predicate branchingExpr(Expr expr) {
* Gets the number of branching statements and expressions in a block. This is
* for computing cyclomatic complexity.
*/
int cyclomaticComplexityBranches(Block b) {
int cyclomaticComplexityBranches(BlockStmt b) {
result =
count(Stmt stmt |
branchingStmt(stmt) and
@@ -373,7 +373,7 @@ private predicate skipParent(Stmt s) {
exists(Stmt parent | parent = s.getParentStmt() |
s instanceof IfStmt and parent.(IfStmt).getElse() = s
or
parent instanceof Block
parent instanceof BlockStmt
or
exists(File f, int startLine, int startCol |
startsAt(s, f, startLine, startCol) and

View File

@@ -18,3 +18,4 @@ private import implementations.StdContainer
private import implementations.StdString
private import implementations.Swap
private import implementations.GetDelim
private import implementations.SmartPointer

View File

@@ -0,0 +1,61 @@
import semmle.code.cpp.models.interfaces.Taint
/**
* The `std::shared_ptr` and `std::unique_ptr` template classes.
*/
class UniqueOrSharedPtr extends Class {
UniqueOrSharedPtr() { this.hasQualifiedName("std", ["shared_ptr", "unique_ptr"]) }
}
/**
* The `std::make_shared` and `std::make_unique` template functions.
*/
class MakeUniqueOrShared extends TaintFunction {
MakeUniqueOrShared() { this.hasQualifiedName("std", ["make_shared", "make_unique"]) }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// Exclude the specializations of `std::make_shared` and `std::make_unique` that allocate arrays
// since these just take a size argument, which we don't want to propagate taint through.
not this.isArray() and
input.isParameter(_) and
output.isReturnValue()
}
/**
* Holds if the function returns a `shared_ptr<T>` (or `unique_ptr<T>`) where `T` is an
* array type (i.e., `U[]` for some type `U`).
*/
predicate isArray() {
this.getTemplateArgument(0).(Type).getUnderlyingType() instanceof ArrayType
}
}
/**
* A prefix `operator*` member function for a `shared_ptr` or `unique_ptr` type.
*/
class UniqueOrSharedDereferenceMemberOperator extends MemberFunction, TaintFunction {
UniqueOrSharedDereferenceMemberOperator() {
this.hasName("operator*") and
this.getDeclaringType() instanceof UniqueOrSharedPtr
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isQualifierObject() and
output.isReturnValueDeref()
}
}
/**
* The `std::shared_ptr` or `std::unique_ptr` function `get`.
*/
class UniqueOrSharedGet extends TaintFunction {
UniqueOrSharedGet() {
this.hasName("get") and
this.getDeclaringType() instanceof UniqueOrSharedPtr
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isQualifierObject() and
output.isReturnValue()
}
}

View File

@@ -1,7 +1,7 @@
/**
* Provides implementation classes modeling `std::string` and other
* instantiations of `std::basic_string`. See `semmle.code.cpp.models.Models`
* for usage information.
* Provides implementation classes modeling `std::string` (and other
* instantiations of `std::basic_string`) and `std::ostream`. See
* `semmle.code.cpp.models.Models` for usage information.
*/
import semmle.code.cpp.models.interfaces.Taint
@@ -270,3 +270,115 @@ class StdStringAt extends TaintFunction {
output.isQualifierObject()
}
}
/**
* The `std::basic_ostream` template class.
*/
class StdBasicOStream extends TemplateClass {
StdBasicOStream() { this.hasQualifiedName("std", "basic_ostream") }
}
/**
* The `std::ostream` functions `operator<<` (defined as a member function),
* `put` and `write`.
*/
class StdOStreamOut extends DataFlowFunction, TaintFunction {
StdOStreamOut() { this.hasQualifiedName("std", "basic_ostream", ["operator<<", "put", "write"]) }
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
// flow from qualifier to return value
input.isQualifierAddress() and
output.isReturnValue()
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from first parameter (value or pointer) to qualifier
input.isParameter(0) and
output.isQualifierObject()
or
input.isParameterDeref(0) and
output.isQualifierObject()
or
// flow from first parameter (value or pointer) to return value
input.isParameter(0) and
output.isReturnValueDeref()
or
input.isParameterDeref(0) and
output.isReturnValueDeref()
or
// reverse flow from returned reference to the qualifier
input.isReturnValueDeref() and
output.isQualifierObject()
}
}
/**
* The `std::ostream` function `operator<<` (defined as a non-member function).
*/
class StdOStreamOutNonMember extends DataFlowFunction, TaintFunction {
StdOStreamOutNonMember() {
this.hasQualifiedName("std", "operator<<") and
this.getUnspecifiedType().(ReferenceType).getBaseType() =
any(StdBasicOStream s).getAnInstantiation()
}
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
// flow from first parameter to return value
input.isParameter(0) and
output.isReturnValue()
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from second parameter to first parameter
input.isParameter(1) and
output.isParameterDeref(0)
or
// flow from second parameter to return value
input.isParameter(1) and
output.isReturnValueDeref()
or
// reverse flow from returned reference to the first parameter
input.isReturnValueDeref() and
output.isParameterDeref(0)
}
}
/**
* Additional model for `std::stringstream` constructors that take a string
* input parameter.
*/
class StdStringStreamConstructor extends Constructor, TaintFunction {
StdStringStreamConstructor() {
this.getDeclaringType().hasQualifiedName("std", "basic_stringstream")
}
/**
* Gets the index of a parameter to this function that is a string.
*/
int getAStringParameterIndex() {
getParameter(result).getType() instanceof ReferenceType // `const std::basic_string &`
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// taint flow from any parameter of string type to the returned object
input.isParameterDeref(getAStringParameterIndex()) and
output.isReturnValue() // TODO: this should be `isQualifierObject` by our current definitions, but that flow is not yet supported.
}
}
/**
* The `std::stringstream` function `str`.
*/
class StdStringStreamStr extends TaintFunction {
StdStringStreamStr() { this.hasQualifiedName("std", "basic_stringstream", "str") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from qualifier to return value (if any)
input.isQualifierObject() and
output.isReturnValue()
or
// flow from first parameter (if any) to qualifier
input.isParameterDeref(0) and
output.isQualifierObject()
}
}

View File

@@ -171,6 +171,65 @@ predicate eqOpWithSwapAndNegate(EqualityOperation cmp, Expr a, Expr b, boolean i
eqOpWithSwap(cmp, a, b, branch.booleanNot()) and isEQ = false
}
/**
* Holds if `cmp` is an unconverted conversion of `a` to a Boolean that
* evalutes to `isEQ` iff `a` is 0.
*
* Note that `a` can be `cmp` itself or a conversion thereof.
*/
private predicate eqZero(Expr cmp, Expr a, boolean isEQ) {
// The `!a` expression tests `a` equal to zero when `a` is a number converted
// to a Boolean.
isEQ = true and
exists(Expr notOperand | notOperand = cmp.(NotExpr).getOperand().getFullyConverted() |
// In C++ code there will be a BoolConversion in `!myInt`
a = notOperand.(BoolConversion).getExpr()
or
// In C code there is no conversion since there was no bool type before C99
a = notOperand and
not a instanceof BoolConversion // avoid overlap with the case above
)
or
// The `(bool)a` expression tests `a` NOT equal to zero when `a` is a number
// converted to a Boolean. To avoid overlap with the case above, this case
// excludes conversions that are right below a `!`.
isEQ = false and
linearAccess(cmp, _, _, _) and
// This test for `isCondition` implies that `cmp` is unconverted and that the
// parent of `cfg` is not a `NotExpr` -- the CFG doesn't do branching from
// inside `NotExpr`.
cmp.isCondition() and
// The GNU two-operand conditional expression is not supported for the
// purpose of guards, but the value of the conditional expression itself is
// modeled in the range analysis.
not exists(ConditionalExpr cond | cmp = cond.getCondition() and cond.isTwoOperand()) and
(
// In C++ code there will be a BoolConversion in `if (myInt)`
a = cmp.getFullyConverted().(BoolConversion).getExpr()
or
// In C code there is no conversion since there was no bool type before C99
a = cmp.getFullyConverted() and
not a instanceof BoolConversion // avoid overlap with the case above
)
}
/**
* Holds if `branch` of `cmp` is taken when `a` compares `isEQ` to zero.
*
* Note that `a` can be `cmp` itself or a conversion thereof.
*/
predicate eqZeroWithNegate(Expr cmp, Expr a, boolean isEQ, boolean branch) {
// The comparison for _equality_ to zero is on the `true` branch when `cmp`
// compares equal to zero and on the `false` branch when `cmp` compares not
// equal to zero.
eqZero(cmp, a, branch) and isEQ = true
or
// The comparison for _inequality_ to zero is on the `false` branch when
// `cmp` compares equal to zero and on the `true` branch when `cmp` compares
// not equal to zero.
eqZero(cmp, a, branch.booleanNot()) and isEQ = false
}
/**
* Holds if `expr` is equivalent to `p*v + q`, where `p` is a non-zero
* number. This takes into account the associativity, commutativity and

View File

@@ -40,21 +40,20 @@ library class RangeSSA extends SSAHelper {
}
}
private predicate guard_defn(
VariableAccess v, ComparisonOperation guard, BasicBlock b, boolean branch
) {
private predicate guard_defn(VariableAccess v, Expr guard, BasicBlock b, boolean branch) {
guardCondition(guard, v, branch) and
guardSuccessor(guard, branch, b)
}
private predicate guardCondition(ComparisonOperation guard, VariableAccess v, boolean branch) {
private predicate guardCondition(Expr guard, VariableAccess v, boolean branch) {
exists(Expr lhs | linearAccess(lhs, v, _, _) |
relOpWithSwapAndNegate(guard, lhs, _, _, _, branch) or
eqOpWithSwapAndNegate(guard, lhs, _, _, branch)
eqOpWithSwapAndNegate(guard, lhs, _, _, branch) or
eqZeroWithNegate(guard, lhs, _, branch)
)
}
private predicate guardSuccessor(ComparisonOperation guard, boolean branch, BasicBlock succ) {
private predicate guardSuccessor(Expr guard, boolean branch, BasicBlock succ) {
branch = true and succ = guard.getATrueSuccessor()
or
branch = false and succ = guard.getAFalseSuccessor()
@@ -98,7 +97,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
* If this definition is a phi node corresponding to a guard,
* then return the variable and the guard.
*/
predicate isGuardPhi(VariableAccess v, ComparisonOperation guard, boolean branch) {
predicate isGuardPhi(VariableAccess v, Expr guard, boolean branch) {
guard_defn(v, guard, this, branch)
}

View File

@@ -427,11 +427,11 @@ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVaria
private predicate phiDependsOnDef(
RangeSsaDefinition phi, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar
) {
exists(VariableAccess access, ComparisonOperation guard |
exists(VariableAccess access, Expr guard |
access = v.getAnAccess() and
phi.isGuardPhi(access, guard, _)
|
exprDependsOnDef(guard.getAnOperand(), srcDef, srcVar) or
exprDependsOnDef(guard.(ComparisonOperation).getAnOperand(), srcDef, srcVar) or
exprDependsOnDef(access, srcDef, srcVar)
)
or
@@ -570,7 +570,7 @@ private float getTruncatedLowerBounds(Expr expr) {
else (
// Some of the bounds computed by getLowerBoundsImpl might
// overflow, so we replace invalid bounds with exprMinVal.
exists(float newLB | newLB = getLowerBoundsImpl(expr) |
exists(float newLB | newLB = normalizeFloatUp(getLowerBoundsImpl(expr)) |
if exprMinVal(expr) <= newLB and newLB <= exprMaxVal(expr)
then result = newLB
else result = exprMinVal(expr)
@@ -617,7 +617,7 @@ private float getTruncatedUpperBounds(Expr expr) {
// Some of the bounds computed by `getUpperBoundsImpl`
// might overflow, so we replace invalid bounds with
// `exprMaxVal`.
exists(float newUB | newUB = getUpperBoundsImpl(expr) |
exists(float newUB | newUB = normalizeFloatUp(getUpperBoundsImpl(expr)) |
if exprMinVal(expr) <= newUB and newUB <= exprMaxVal(expr)
then result = newUB
else result = exprMaxVal(expr)
@@ -1132,9 +1132,7 @@ private float boolConversionUpperBound(Expr expr) {
* use the guard to deduce that the lower bound is 2 inside the block.
*/
private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) {
exists(
VariableAccess access, ComparisonOperation guard, boolean branch, float defLB, float guardLB
|
exists(VariableAccess access, Expr guard, boolean branch, float defLB, float guardLB |
access = v.getAnAccess() and
phi.isGuardPhi(access, guard, branch) and
lowerBoundFromGuard(guard, access, guardLB, branch) and
@@ -1146,13 +1144,13 @@ private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) {
or
exists(VariableAccess access, float neConstant, float lower |
isNEPhi(v, phi, access, neConstant) and
lower = getFullyConvertedLowerBounds(access) and
lower = getTruncatedLowerBounds(access) and
if lower = neConstant then result = lower + 1 else result = lower
)
or
exists(VariableAccess access |
isUnsupportedGuardPhi(v, phi, access) and
result = getFullyConvertedLowerBounds(access)
result = getTruncatedLowerBounds(access)
)
or
result = getDefLowerBounds(phi.getAPhiInput(v), v)
@@ -1160,9 +1158,7 @@ private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) {
/** See comment for `getPhiLowerBounds`, above. */
private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) {
exists(
VariableAccess access, ComparisonOperation guard, boolean branch, float defUB, float guardUB
|
exists(VariableAccess access, Expr guard, boolean branch, float defUB, float guardUB |
access = v.getAnAccess() and
phi.isGuardPhi(access, guard, branch) and
upperBoundFromGuard(guard, access, guardUB, branch) and
@@ -1174,13 +1170,13 @@ private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) {
or
exists(VariableAccess access, float neConstant, float upper |
isNEPhi(v, phi, access, neConstant) and
upper = getFullyConvertedUpperBounds(access) and
upper = getTruncatedUpperBounds(access) and
if upper = neConstant then result = upper - 1 else result = upper
)
or
exists(VariableAccess access |
isUnsupportedGuardPhi(v, phi, access) and
result = getFullyConvertedUpperBounds(access)
result = getTruncatedUpperBounds(access)
)
or
result = getDefUpperBounds(phi.getAPhiInput(v), v)
@@ -1252,70 +1248,6 @@ private float getDefUpperBoundsImpl(RangeSsaDefinition def, StackVariable v) {
unanalyzableDefBounds(def, v, _, result)
}
/**
* Get the lower bounds for a `RangeSsaDefinition`. Most of the work is
* done by `getDefLowerBoundsImpl`, but this is where widening is applied
* to prevent the analysis from exploding due to a recursive definition.
*/
private float getDefLowerBounds(RangeSsaDefinition def, StackVariable v) {
exists(float newLB, float truncatedLB |
newLB = getDefLowerBoundsImpl(def, v) and
if varMinVal(v) <= newLB and newLB <= varMaxVal(v)
then truncatedLB = newLB
else truncatedLB = varMinVal(v)
|
// Widening: check whether the new lower bound is from a source which
// depends recursively on the current definition.
if isRecursiveDef(def, v)
then
// The new lower bound is from a recursive source, so we round
// down to one of a limited set of values to prevent the
// recursion from exploding.
result =
max(float widenLB |
widenLB = wideningLowerBounds(getVariableRangeType(v)) and
not widenLB > truncatedLB
|
widenLB
)
else result = truncatedLB
)
or
// The definition might overflow positively and wrap. If so, the lower
// bound is `typeLowerBound`.
defMightOverflowPositively(def, v) and result = varMinVal(v)
}
/** See comment for `getDefLowerBounds`, above. */
private float getDefUpperBounds(RangeSsaDefinition def, StackVariable v) {
exists(float newUB, float truncatedUB |
newUB = getDefUpperBoundsImpl(def, v) and
if varMinVal(v) <= newUB and newUB <= varMaxVal(v)
then truncatedUB = newUB
else truncatedUB = varMaxVal(v)
|
// Widening: check whether the new upper bound is from a source which
// depends recursively on the current definition.
if isRecursiveDef(def, v)
then
// The new upper bound is from a recursive source, so we round
// up to one of a fixed set of values to prevent the recursion
// from exploding.
result =
min(float widenUB |
widenUB = wideningUpperBounds(getVariableRangeType(v)) and
not widenUB < truncatedUB
|
widenUB
)
else result = truncatedUB
)
or
// The definition might overflow negatively and wrap. If so, the upper
// bound is `typeUpperBound`.
defMightOverflowNegatively(def, v) and result = varMaxVal(v)
}
/**
* Helper for `getDefLowerBounds` and `getDefUpperBounds`. Find the set of
* unanalyzable definitions (such as function parameters) and make their
@@ -1334,7 +1266,7 @@ private predicate unanalyzableDefBounds(RangeSsaDefinition def, StackVariable v,
* inferences about `v`.
*/
bindingset[guard, v, branch]
predicate nonNanGuardedVariable(ComparisonOperation guard, VariableAccess v, boolean branch) {
predicate nonNanGuardedVariable(Expr guard, VariableAccess v, boolean branch) {
getVariableRangeType(v.getTarget()) instanceof IntegralType
or
getVariableRangeType(v.getTarget()) instanceof FloatingPointType and
@@ -1353,9 +1285,7 @@ predicate nonNanGuardedVariable(ComparisonOperation guard, VariableAccess v, boo
* predicate uses the bounds information for `r` to compute a lower bound
* for `v`.
*/
private predicate lowerBoundFromGuard(
ComparisonOperation guard, VariableAccess v, float lb, boolean branch
) {
private predicate lowerBoundFromGuard(Expr guard, VariableAccess v, float lb, boolean branch) {
exists(float childLB, RelationStrictness strictness |
boundFromGuard(guard, v, childLB, true, strictness, branch)
|
@@ -1375,9 +1305,7 @@ private predicate lowerBoundFromGuard(
* predicate uses the bounds information for `r` to compute a upper bound
* for `v`.
*/
private predicate upperBoundFromGuard(
ComparisonOperation guard, VariableAccess v, float ub, boolean branch
) {
private predicate upperBoundFromGuard(Expr guard, VariableAccess v, float ub, boolean branch) {
exists(float childUB, RelationStrictness strictness |
boundFromGuard(guard, v, childUB, false, strictness, branch)
|
@@ -1397,7 +1325,7 @@ private predicate upperBoundFromGuard(
* `linearBoundFromGuard`.
*/
private predicate boundFromGuard(
ComparisonOperation guard, VariableAccess v, float boundValue, boolean isLowerBound,
Expr guard, VariableAccess v, float boundValue, boolean isLowerBound,
RelationStrictness strictness, boolean branch
) {
exists(float p, float q, float r, boolean isLB |
@@ -1410,6 +1338,15 @@ private predicate boundFromGuard(
or
p < 0 and isLowerBound = isLB.booleanNot()
)
or
// When `!e` is true, we know that `0 <= e <= 0`
exists(float p, float q, Expr e |
linearAccess(e, v, p, q) and
eqZeroWithNegate(guard, e, true, branch) and
boundValue = (0.0 - q) / p and
isLowerBound = [false, true] and
strictness = Nonstrict()
)
}
/**
@@ -1487,6 +1424,15 @@ private predicate isNEPhi(
linearAccess(linearExpr, access, p, q) and
neConstant = (r - q) / p
)
or
exists(Expr op, boolean branch, Expr linearExpr, float p, float q |
access.getTarget() = v and
phi.isGuardPhi(access, op, branch) and
eqZeroWithNegate(op, linearExpr, false, branch) and
v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!` is too imprecise
linearAccess(linearExpr, access, p, q) and
neConstant = (0.0 - q) / p
)
}
/**
@@ -1496,10 +1442,13 @@ private predicate isNEPhi(
* compile-time constant.
*/
private predicate isUnsupportedGuardPhi(Variable v, RangeSsaDefinition phi, VariableAccess access) {
exists(ComparisonOperation cmp, boolean branch |
exists(Expr cmp, boolean branch |
eqOpWithSwapAndNegate(cmp, _, _, false, branch)
or
eqZeroWithNegate(cmp, _, false, branch)
|
access.getTarget() = v and
phi.isGuardPhi(access, cmp, branch) and
eqOpWithSwapAndNegate(cmp, _, _, false, branch) and
not isNEPhi(v, phi, access, _)
)
}
@@ -1675,6 +1624,70 @@ module SimpleRangeAnalysisInternal {
float getFullyConvertedUpperBounds(Expr expr) {
result = getTruncatedUpperBounds(expr.getFullyConverted())
}
/**
* Get the lower bounds for a `RangeSsaDefinition`. Most of the work is
* done by `getDefLowerBoundsImpl`, but this is where widening is applied
* to prevent the analysis from exploding due to a recursive definition.
*/
float getDefLowerBounds(RangeSsaDefinition def, StackVariable v) {
exists(float newLB, float truncatedLB |
newLB = getDefLowerBoundsImpl(def, v) and
if varMinVal(v) <= newLB and newLB <= varMaxVal(v)
then truncatedLB = newLB
else truncatedLB = varMinVal(v)
|
// Widening: check whether the new lower bound is from a source which
// depends recursively on the current definition.
if isRecursiveDef(def, v)
then
// The new lower bound is from a recursive source, so we round
// down to one of a limited set of values to prevent the
// recursion from exploding.
result =
max(float widenLB |
widenLB = wideningLowerBounds(getVariableRangeType(v)) and
not widenLB > truncatedLB
|
widenLB
)
else result = truncatedLB
)
or
// The definition might overflow positively and wrap. If so, the lower
// bound is `typeLowerBound`.
defMightOverflowPositively(def, v) and result = varMinVal(v)
}
/** See comment for `getDefLowerBounds`, above. */
float getDefUpperBounds(RangeSsaDefinition def, StackVariable v) {
exists(float newUB, float truncatedUB |
newUB = getDefUpperBoundsImpl(def, v) and
if varMinVal(v) <= newUB and newUB <= varMaxVal(v)
then truncatedUB = newUB
else truncatedUB = varMaxVal(v)
|
// Widening: check whether the new upper bound is from a source which
// depends recursively on the current definition.
if isRecursiveDef(def, v)
then
// The new upper bound is from a recursive source, so we round
// up to one of a fixed set of values to prevent the recursion
// from exploding.
result =
min(float widenUB |
widenUB = wideningUpperBounds(getVariableRangeType(v)) and
not widenUB < truncatedUB
|
widenUB
)
else result = truncatedUB
)
or
// The definition might overflow negatively and wrap. If so, the upper
// bound is `typeUpperBound`.
defMightOverflowNegatively(def, v) and result = varMaxVal(v)
}
}
private import SimpleRangeAnalysisInternal

View File

@@ -17,8 +17,8 @@ import semmle.code.cpp.stmts.Stmt
* }
* ```
*/
class Block extends Stmt, @stmt_block {
override string getAPrimaryQlClass() { result = "Block" }
class BlockStmt extends Stmt, @stmt_block {
override string getAPrimaryQlClass() { result = "BlockStmt" }
/**
* Gets a child declaration of this block.
@@ -76,8 +76,8 @@ class Block extends Stmt, @stmt_block {
* the result is the expression statement `a = b`.
*/
Stmt getLastStmtIn() {
if getLastStmt() instanceof Block
then result = getLastStmt().(Block).getLastStmtIn()
if getLastStmt() instanceof BlockStmt
then result = getLastStmt().(BlockStmt).getLastStmtIn()
else result = getLastStmt()
}
@@ -126,3 +126,9 @@ class Block extends Stmt, @stmt_block {
override predicate mayBeGloballyImpure() { this.getAStmt().mayBeGloballyImpure() }
}
/**
* DEPRECATED: This is now called `BlockStmt` to avoid confusion with
* `BasicBlock`.
*/
deprecated class Block = BlockStmt;

View File

@@ -25,10 +25,10 @@ class Stmt extends StmtParent, @stmt {
/**
* Gets the nearest enclosing block of this statement in the source, if any.
*/
Block getEnclosingBlock() {
BlockStmt getEnclosingBlock() {
if
getParentStmt() instanceof Block and
not getParentStmt().(Block).getLocation() instanceof UnknownLocation
getParentStmt() instanceof BlockStmt and
not getParentStmt().(BlockStmt).getLocation() instanceof UnknownLocation
then result = getParentStmt()
else result = getParentStmt().getEnclosingBlock()
}
@@ -53,7 +53,7 @@ class Stmt extends StmtParent, @stmt {
* to trace the flow of control instead.
*/
Stmt getFollowingStmt() {
exists(Block b, int i |
exists(BlockStmt b, int i |
this = b.getStmt(i) and
result = b.getStmt(i + 1)
)
@@ -240,7 +240,7 @@ class IfStmt extends ConditionalStmt, @stmt_if {
* ```
* if (b) { x = 1; }
* ```
* the result is the `Block` `{ x = 1; }`.
* the result is the `BlockStmt` `{ x = 1; }`.
*/
Stmt getThen() { if_then(underlyingElement(this), unresolveElement(result)) }
@@ -251,7 +251,7 @@ class IfStmt extends ConditionalStmt, @stmt_if {
* ```
* if (b) { x = 1; } else { x = 2; }
* ```
* the result is the `Block` `{ x = 2; }`, and for
* the result is the `BlockStmt` `{ x = 2; }`, and for
* ```
* if (b) { x = 1; }
* ```
@@ -326,7 +326,7 @@ class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if {
* ```
* if constexpr (b) { x = 1; }
* ```
* the result is the `Block` `{ x = 1; }`.
* the result is the `BlockStmt` `{ x = 1; }`.
*/
Stmt getThen() { constexpr_if_then(underlyingElement(this), unresolveElement(result)) }
@@ -337,7 +337,7 @@ class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if {
* ```
* if constexpr (b) { x = 1; } else { x = 2; }
* ```
* the result is the `Block` `{ x = 2; }`, and for
* the result is the `BlockStmt` `{ x = 2; }`, and for
* ```
* if constexpr (b) { x = 1; }
* ```
@@ -842,7 +842,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for {
* ```
* for (int x : xs) { y += x; }
* ```
* the result is the `Block` `{ y += x; }`.
* the result is the `BlockStmt` `{ y += x; }`.
*/
override Stmt getStmt() { result = this.getChild(5) }
@@ -1229,7 +1229,7 @@ class SwitchCase extends Stmt, @stmt_switch_case {
* DEPRECATED: use `SwitchCase.getAStmt` or `ControlFlowNode.getASuccessor`
* rather than this predicate.
*
* Gets the `Block` statement immediately following this 'switch case'
* Gets the `BlockStmt` statement immediately following this 'switch case'
* statement, if any.
*
* For example, for
@@ -1250,7 +1250,7 @@ class SwitchCase extends Stmt, @stmt_switch_case {
* the `case 7:` has result `{ x = 2; break; }`, `default:` has result
* `{ x = 3; }`, and the others have no result.
*/
deprecated Block getLabelledStmt() {
deprecated BlockStmt getLabelledStmt() {
exists(int i, Stmt parent |
this = parent.getChild(i) and
result = parent.getChild(i + 1)
@@ -1331,7 +1331,7 @@ class SwitchCase extends Stmt, @stmt_switch_case {
* `default:` has results `{ x = 3; }, `x = 4;` and `break;`.
*/
Stmt getAStmt() {
exists(Block b, int i, int j |
exists(BlockStmt b, int i, int j |
b.getStmt(i) = this and
b.getStmt(j) = result and
i < j and
@@ -1370,8 +1370,8 @@ class SwitchCase extends Stmt, @stmt_switch_case {
exists(Stmt lastStmt |
lastStmt = this.getAStmt() and
not lastStmt.getFollowingStmt() = this.getAStmt() and
if lastStmt instanceof Block
then result = lastStmt.(Block).getLastStmtIn()
if lastStmt instanceof BlockStmt
then result = lastStmt.(BlockStmt).getLastStmtIn()
else result = lastStmt
)
}
@@ -1528,7 +1528,7 @@ class SwitchStmt extends ConditionalStmt, @stmt_switch {
/**
* Gets the body statement of this 'switch' statement.
*
* In almost all cases the result will be a `Block`, but there are
* In almost all cases the result will be a `BlockStmt`, but there are
* other syntactically valid constructions.
*
* For example, for
@@ -1859,7 +1859,7 @@ class FunctionTryStmt extends TryStmt {
* }
* ```
*/
class CatchBlock extends Block {
class CatchBlock extends BlockStmt {
override string getAPrimaryQlClass() { result = "CatchBlock" }
CatchBlock() { ishandler(underlyingElement(this)) }
@@ -1925,7 +1925,7 @@ class MicrosoftTryExceptStmt extends MicrosoftTryStmt {
/** Gets the expression guarding the `__except` statement. */
Expr getCondition() { result = getChild(1) }
/** Gets the `__except` statement (usually a `Block`). */
/** Gets the `__except` statement (usually a `BlockStmt`). */
Stmt getExcept() { result = getChild(2) }
override string getAPrimaryQlClass() { result = "MicrosoftTryExceptStmt" }
@@ -1949,7 +1949,7 @@ class MicrosoftTryFinallyStmt extends MicrosoftTryStmt {
override string toString() { result = "__try { ... } __finally { ... }" }
/** Gets the `__finally` statement (usually a `Block`). */
/** Gets the `__finally` statement (usually a `BlockStmt`). */
Stmt getFinally() { result = getChild(1) }
override string getAPrimaryQlClass() { result = "MicrosoftTryFinallyStmt" }
@@ -2108,7 +2108,7 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl {
* declaration statement.
*/
int getNumberOfVlaDimensionStmts() {
exists(Block b, int j |
exists(BlockStmt b, int j |
this = b.getStmt(j) and
result =
j - 1 -
@@ -2125,7 +2125,7 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl {
*/
VlaDimensionStmt getVlaDimensionStmt(int i) {
i in [0 .. this.getNumberOfVlaDimensionStmts() - 1] and
exists(Block b, int j |
exists(BlockStmt b, int j |
this = b.getStmt(j) and
result = b.getStmt(j - this.getNumberOfVlaDimensionStmts() + i)
)

View File

@@ -414,6 +414,28 @@ function_entry_point(int id: @function ref, unique int entry_point: @stmt ref);
function_return_type(int id: @function ref, int return_type: @type ref);
/** If `function` is a coroutine, then this gives the
std::experimental::resumable_traits instance associated with it,
and the variables representing the `handle` and `promise` for it. */
coroutine(
unique int function: @function ref,
int traits: @type ref,
int handle: @variable ref,
int promise: @variable ref
);
/** The `new` function used for allocating the coroutine state, if any. */
coroutine_new(
unique int function: @function ref,
int new: @function ref
);
/** The `delete` function used for deallocating the coroutine state, if any. */
coroutine_delete(
unique int function: @function ref,
int delete: @function ref
);
purefunctions(unique int id: @function ref);
function_deleted(unique int id: @function ref);

View File

@@ -1536,7 +1536,7 @@
</e>
<e>
<k>seconds</k>
<v>11965</v>
<v>12700</v>
</e>
</columnsizes>
<dependencies>
@@ -1580,14 +1580,19 @@
<budget>12</budget>
<bs>
<b>
<a>2</a>
<b>3</b>
<v>21</v>
</b>
<b>
<a>3</a>
<b>4</b>
<v>2719</v>
<v>2599</v>
</b>
<b>
<a>4</a>
<b>5</b>
<v>6810</v>
<v>6909</v>
</b>
</bs>
</hist>
@@ -1633,8 +1638,8 @@
<budget>12</budget>
<bs>
<b>
<a>1091</a>
<b>1092</b>
<a>1158</a>
<b>1159</b>
<v>10</v>
</b>
</bs>
@@ -1691,13 +1696,13 @@
<v>10</v>
</b>
<b>
<a>572</a>
<b>573</b>
<a>590</a>
<b>591</b>
<v>10</v>
</b>
<b>
<a>666</a>
<b>667</b>
<a>694</a>
<b>695</b>
<v>10</v>
</b>
</bs>
@@ -1714,22 +1719,22 @@
<b>
<a>1</a>
<b>2</b>
<v>7863</v>
<v>8653</v>
</b>
<b>
<a>2</a>
<b>3</b>
<v>2237</v>
<v>2588</v>
</b>
<b>
<a>3</a>
<b>4</b>
<v>1107</v>
<b>5</b>
<v>1074</v>
</b>
<b>
<a>4</a>
<b>641</b>
<v>756</v>
<a>5</a>
<b>629</b>
<v>383</v>
</b>
</bs>
</hist>
@@ -1745,7 +1750,7 @@
<b>
<a>1</a>
<b>2</b>
<v>11965</v>
<v>12700</v>
</b>
</bs>
</hist>
@@ -1761,17 +1766,17 @@
<b>
<a>1</a>
<b>2</b>
<v>10144</v>
<v>11131</v>
</b>
<b>
<a>2</a>
<b>3</b>
<v>1809</v>
<v>1535</v>
</b>
<b>
<a>3</a>
<b>4</b>
<v>10</v>
<v>32</v>
</b>
</bs>
</hist>
@@ -2150,11 +2155,11 @@
</e>
<e>
<k>cpu_seconds</k>
<v>8159</v>
<v>8093</v>
</e>
<e>
<k>elapsed_seconds</k>
<v>197</v>
<v>219</v>
</e>
</columnsizes>
<dependencies>
@@ -2200,17 +2205,17 @@
<b>
<a>1</a>
<b>2</b>
<v>7106</v>
<v>6931</v>
</b>
<b>
<a>2</a>
<b>3</b>
<v>833</v>
<v>954</v>
</b>
<b>
<a>3</a>
<b>7</b>
<v>219</v>
<v>208</v>
</b>
</bs>
</hist>
@@ -2226,12 +2231,12 @@
<b>
<a>1</a>
<b>2</b>
<v>7677</v>
<v>7764</v>
</b>
<b>
<a>2</a>
<b>3</b>
<v>482</v>
<v>329</v>
</b>
</bs>
</hist>
@@ -2247,7 +2252,7 @@
<b>
<a>1</a>
<b>2</b>
<v>43</v>
<v>54</v>
</b>
<b>
<a>2</a>
@@ -2255,13 +2260,18 @@
<v>21</v>
</b>
<b>
<a>4</a>
<b>5</b>
<a>3</a>
<b>4</b>
<v>10</v>
</b>
<b>
<a>6</a>
<b>7</b>
<a>5</a>
<b>6</b>
<v>10</v>
</b>
<b>
<a>7</a>
<b>8</b>
<v>10</v>
</b>
<b>
@@ -2270,48 +2280,48 @@
<v>10</v>
</b>
<b>
<a>12</a>
<b>13</b>
<a>11</a>
<b>12</b>
<v>10</v>
</b>
<b>
<a>13</a>
<b>14</b>
<a>17</a>
<b>18</b>
<v>10</v>
</b>
<b>
<a>31</a>
<b>32</b>
<a>41</a>
<b>42</b>
<v>10</v>
</b>
<b>
<a>32</a>
<b>33</b>
<a>46</a>
<b>47</b>
<v>10</v>
</b>
<b>
<a>99</a>
<b>100</b>
<a>47</a>
<b>48</b>
<v>10</v>
</b>
<b>
<a>106</a>
<b>107</b>
<a>86</a>
<b>87</b>
<v>10</v>
</b>
<b>
<a>149</a>
<b>150</b>
<a>157</a>
<b>158</b>
<v>10</v>
</b>
<b>
<a>191</a>
<b>192</b>
<a>183</a>
<b>184</b>
<v>10</v>
</b>
<b>
<a>211</a>
<b>212</b>
<a>250</a>
<b>251</b>
<v>10</v>
</b>
</bs>
@@ -2328,7 +2338,7 @@
<b>
<a>1</a>
<b>2</b>
<v>43</v>
<v>54</v>
</b>
<b>
<a>2</a>
@@ -2336,13 +2346,18 @@
<v>21</v>
</b>
<b>
<a>4</a>
<b>5</b>
<a>3</a>
<b>4</b>
<v>10</v>
</b>
<b>
<a>6</a>
<b>7</b>
<a>5</a>
<b>6</b>
<v>10</v>
</b>
<b>
<a>7</a>
<b>8</b>
<v>10</v>
</b>
<b>
@@ -2351,48 +2366,48 @@
<v>10</v>
</b>
<b>
<a>12</a>
<b>13</b>
<a>11</a>
<b>12</b>
<v>10</v>
</b>
<b>
<a>13</a>
<b>14</b>
<a>17</a>
<b>18</b>
<v>10</v>
</b>
<b>
<a>31</a>
<b>32</b>
<a>40</a>
<b>41</b>
<v>10</v>
</b>
<b>
<a>32</a>
<b>33</b>
<a>44</a>
<b>45</b>
<v>10</v>
</b>
<b>
<a>87</a>
<b>88</b>
<a>46</a>
<b>47</b>
<v>10</v>
</b>
<b>
<a>90</a>
<b>91</b>
<a>73</a>
<b>74</b>
<v>10</v>
</b>
<b>
<a>138</a>
<b>139</b>
<a>150</a>
<b>151</b>
<v>10</v>
</b>
<b>
<a>178</a>
<b>179</b>
<a>164</a>
<b>165</b>
<v>10</v>
</b>
<b>
<a>180</a>
<b>181</b>
<a>190</a>
<b>191</b>
<v>10</v>
</b>
</bs>
@@ -15740,6 +15755,318 @@
</dependencies>
</relation>
<relation>
<name>coroutine</name>
<cardinality>2</cardinality>
<columnsizes>
<e>
<k>function</k>
<v>2</v>
</e>
<e>
<k>traits</k>
<v>2</v>
</e>
<e>
<k>handle</k>
<v>2</v>
</e>
<e>
<k>promise</k>
<v>2</v>
</e>
</columnsizes>
<dependencies>
<dep>
<src>function</src>
<trg>traits</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>2</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>function</src>
<trg>handle</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>2</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>function</src>
<trg>promise</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>2</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>traits</src>
<trg>function</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>2</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>traits</src>
<trg>handle</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>2</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>traits</src>
<trg>promise</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>2</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>handle</src>
<trg>function</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>2</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>handle</src>
<trg>traits</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>2</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>handle</src>
<trg>promise</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>2</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>promise</src>
<trg>function</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>2</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>promise</src>
<trg>traits</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>2</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>promise</src>
<trg>handle</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>2</v>
</b>
</bs>
</hist>
</val>
</dep>
</dependencies>
</relation>
<relation>
<name>coroutine_new</name>
<cardinality>2</cardinality>
<columnsizes>
<e>
<k>function</k>
<v>2</v>
</e>
<e>
<k>new</k>
<v>1</v>
</e>
</columnsizes>
<dependencies>
<dep>
<src>function</src>
<trg>new</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>2</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>new</src>
<trg>function</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>2</a>
<b>3</b>
<v>1</v>
</b>
</bs>
</hist>
</val>
</dep>
</dependencies>
</relation>
<relation>
<name>coroutine_delete</name>
<cardinality>2</cardinality>
<columnsizes>
<e>
<k>function</k>
<v>2</v>
</e>
<e>
<k>delete</k>
<v>1</v>
</e>
</columnsizes>
<dependencies>
<dep>
<src>function</src>
<trg>delete</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>2</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>delete</src>
<trg>function</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>2</a>
<b>3</b>
<v>1</v>
</b>
</bs>
</hist>
</val>
</dep>
</dependencies>
</relation>
<relation>
<name>purefunctions</name>
<cardinality>20748</cardinality>
<columnsizes>
@@ -32948,11 +33275,11 @@
</e>
<e>
<k>kind</k>
<v>598</v>
<v>1096</v>
</e>
<e>
<k>location</k>
<v>5472231</v>
<v>3623249</v>
</e>
</columnsizes>
<dependencies>
@@ -32996,69 +33323,69 @@
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>8</b>
<v>52</v>
<a>2</a>
<b>14</b>
<v>87</v>
</b>
<b>
<a>8</a>
<b>18</b>
<v>52</v>
<a>15</a>
<b>50</b>
<v>87</v>
</b>
<b>
<a>21</a>
<b>62</b>
<v>45</v>
<a>50</a>
<b>90</b>
<v>87</v>
</b>
<b>
<a>100</a>
<b>150</b>
<v>45</v>
<a>90</a>
<b>223</b>
<v>87</v>
</b>
<b>
<a>213</a>
<b>506</b>
<v>45</v>
<a>306</a>
<b>471</b>
<v>87</v>
</b>
<b>
<a>531</a>
<b>815</b>
<v>45</v>
<a>484</a>
<b>715</b>
<v>87</v>
</b>
<b>
<a>835</a>
<b>2006</b>
<v>45</v>
<a>866</a>
<b>2036</b>
<v>87</v>
</b>
<b>
<a>2338</a>
<b>3023</b>
<v>45</v>
<a>2167</a>
<b>2960</b>
<v>87</v>
</b>
<b>
<a>3116</a>
<b>5545</b>
<v>45</v>
<a>3202</a>
<b>4443</b>
<v>87</v>
</b>
<b>
<a>5585</a>
<b>10844</b>
<v>45</v>
<a>4717</a>
<b>6425</b>
<v>87</v>
</b>
<b>
<a>13459</a>
<b>19466</b>
<v>45</v>
<a>6722</a>
<b>13439</b>
<v>87</v>
</b>
<b>
<a>20677</a>
<b>67545</b>
<v>45</v>
<a>17876</a>
<b>114329</b>
<v>87</v>
</b>
<b>
<a>150195</a>
<b>817400</b>
<v>39</v>
<a>192871</a>
<b>428312</b>
<v>43</v>
</b>
</bs>
</hist>
@@ -33074,72 +33401,67 @@
<b>
<a>1</a>
<b>4</b>
<v>45</v>
<v>98</v>
</b>
<b>
<a>4</a>
<b>9</b>
<v>45</v>
<b>14</b>
<v>98</v>
</b>
<b>
<a>12</a>
<b>21</b>
<v>45</v>
<a>14</a>
<b>24</b>
<v>87</v>
</b>
<b>
<a>21</a>
<b>85</b>
<v>45</v>
<a>24</a>
<b>38</b>
<v>87</v>
</b>
<b>
<a>86</a>
<b>186</b>
<v>45</v>
<a>38</a>
<b>134</b>
<v>87</v>
</b>
<b>
<a>191</a>
<b>309</b>
<v>45</v>
<a>144</a>
<b>259</b>
<v>87</v>
</b>
<b>
<a>419</a>
<b>726</b>
<v>45</v>
<a>270</a>
<b>481</b>
<v>87</v>
</b>
<b>
<a>740</a>
<b>1250</b>
<v>45</v>
<a>481</a>
<b>1076</b>
<v>87</v>
</b>
<b>
<a>1517</a>
<b>2150</b>
<v>45</v>
<a>1099</a>
<b>1408</b>
<v>87</v>
</b>
<b>
<a>2341</a>
<b>3754</b>
<v>45</v>
<a>1427</a>
<b>2051</b>
<v>87</v>
</b>
<b>
<a>3790</a>
<b>7357</b>
<v>45</v>
<a>2060</a>
<b>4561</b>
<v>87</v>
</b>
<b>
<a>7374</a>
<b>16657</b>
<v>45</v>
<a>5889</a>
<b>60114</b>
<v>87</v>
</b>
<b>
<a>18659</a>
<b>177300</b>
<v>45</v>
</b>
<b>
<a>374826</a>
<b>374827</b>
<v>6</v>
<a>72772</a>
<b>118610</b>
<v>21</v>
</b>
</bs>
</hist>
@@ -33155,22 +33477,37 @@
<b>
<a>1</a>
<b>2</b>
<v>3700703</v>
<v>1680483</v>
</b>
<b>
<a>2</a>
<b>3</b>
<v>1002541</v>
<v>738624</v>
</b>
<b>
<a>3</a>
<b>4</b>
<v>319926</v>
</b>
<b>
<a>4</a>
<b>5</b>
<v>434500</v>
<v>276890</v>
</b>
<b>
<a>5</a>
<b>306832</b>
<v>334486</v>
<b>9</b>
<v>301720</v>
</b>
<b>
<a>9</a>
<b>53</b>
<v>272120</v>
</b>
<b>
<a>53</a>
<b>144478</b>
<v>33483</v>
</b>
</bs>
</hist>
@@ -33186,17 +33523,17 @@
<b>
<a>1</a>
<b>2</b>
<v>4305765</v>
<v>2586676</v>
</b>
<b>
<a>2</a>
<b>3</b>
<v>882917</v>
<v>807411</v>
</b>
<b>
<a>3</a>
<b>20</b>
<v>283548</v>
<b>30</b>
<v>229161</v>
</b>
</bs>
</hist>

View File

@@ -19,7 +19,7 @@ AddressOf.c:
# 1| params:
# 1| 0: [Parameter] i
# 1| Type = [IntType] int
# 1| body: [Block] { ... }
# 1| body: [BlockStmt] { ... }
# 2| 0: [DeclStmt] declaration
# 2| 0: [VariableDeclarationEntry] definition of j
# 2| Type = [IntPointerType] int *
@@ -34,7 +34,7 @@ AddressOf.c:
ArrayToPointer.c:
# 5| [TopLevelFunction] void ArrayToPointer()
# 5| params:
# 6| body: [Block] { ... }
# 6| body: [BlockStmt] { ... }
# 7| 0: [DeclStmt] declaration
# 7| 0: [VariableDeclarationEntry] definition of c
# 7| Type = [ArrayType] char[]
@@ -70,7 +70,7 @@ Cast.c:
# 1| Type = [CharPointerType] char *
# 1| 1: [Parameter] v
# 1| Type = [VoidPointerType] void *
# 1| body: [Block] { ... }
# 1| body: [BlockStmt] { ... }
# 2| 0: [ExprStmt] ExprStmt
# 2| 0: [AssignExpr] ... = ...
# 2| Type = [CharPointerType] char *
@@ -89,7 +89,7 @@ Cast.c:
ConditionDecl.cpp:
# 1| [TopLevelFunction] void ConditionDecl()
# 1| params:
# 1| body: [Block] { ... }
# 1| body: [BlockStmt] { ... }
# 2| 0: [DeclStmt] declaration
# 2| 0: [VariableDeclarationEntry] definition of j
# 2| Type = [IntType] int
@@ -109,7 +109,7 @@ ConditionDecl.cpp:
# 3| expr: [VariableAccess] k
# 3| Type = [IntType] int
# 3| ValueCategory = prvalue(load)
# 3| 1: [Block] { ... }
# 3| 1: [BlockStmt] { ... }
# 5| 2: [ReturnStmt] return ...
ConstructorCall.cpp:
# 1| [CopyAssignmentOperator] C& C::operator=(C const&)
@@ -133,7 +133,7 @@ ConstructorCall.cpp:
# 3| 0: [Parameter] i
# 3| Type = [IntType] int
# 3| initializations:
# 3| body: [Block] { ... }
# 3| body: [BlockStmt] { ... }
# 4| 0: [ReturnStmt] return ...
# 7| [CopyAssignmentOperator] D& D::operator=(D const&)
# 7| params:
@@ -154,7 +154,7 @@ ConstructorCall.cpp:
# 9| [Constructor] void D::D()
# 9| params:
# 9| initializations:
# 9| body: [Block] { ... }
# 9| body: [BlockStmt] { ... }
# 10| 0: [ReturnStmt] return ...
# 13| [CopyAssignmentOperator] E& E::operator=(E const&)
# 13| params:
@@ -172,7 +172,7 @@ ConstructorCall.cpp:
# 17| Type = [PointerType] D *
# 17| 2: [Parameter] e
# 17| Type = [PointerType] E *
# 17| body: [Block] { ... }
# 17| body: [BlockStmt] { ... }
# 18| 0: [ExprStmt] ExprStmt
# 18| 0: [AssignExpr] ... = ...
# 18| Type = [PointerType] C *
@@ -221,7 +221,7 @@ ConstructorCall.cpp:
Conversion1.c:
# 1| [TopLevelFunction] void Conversion1()
# 1| params:
# 1| body: [Block] { ... }
# 1| body: [BlockStmt] { ... }
# 2| 0: [DeclStmt] declaration
# 2| 0: [VariableDeclarationEntry] definition of i
# 2| Type = [IntType] int
@@ -241,7 +241,7 @@ Conversion2.c:
# 1| params:
# 1| 0: [Parameter] x
# 1| Type = [IntType] int
# 1| body: [Block] { ... }
# 1| body: [BlockStmt] { ... }
# 2| 0: [ExprStmt] ExprStmt
# 2| 0: [AssignExpr] ... = ...
# 2| Type = [IntType] int
@@ -277,7 +277,7 @@ Conversion3.cpp:
# 1| params:
# 1| 0: [Parameter] x
# 1| Type = [IntType] int
# 1| body: [Block] { ... }
# 1| body: [BlockStmt] { ... }
# 2| 0: [ExprStmt] ExprStmt
# 2| 0: [AssignExpr] ... = ...
# 2| Type = [IntType] int
@@ -327,7 +327,7 @@ Conversion4.c:
# 1| params:
# 1| 0: [Parameter] x
# 1| Type = [IntType] int
# 1| body: [Block] { ... }
# 1| body: [BlockStmt] { ... }
# 2| 0: [ExprStmt] ExprStmt
# 2| 0: [AssignExpr] ... = ...
# 2| Type = [IntType] int
@@ -350,9 +350,11 @@ Conversion4.c:
# 2| ValueCategory = prvalue
# 3| 1: [ReturnStmt] return ...
DestructorCall.cpp:
# 1| [Constructor] void C::C()
# 1| params:
# 3| [Destructor] void C::~C()
# 3| params:
# 3| body: [Block] { ... }
# 3| body: [BlockStmt] { ... }
# 4| 0: [ReturnStmt] return ...
# 3| destructions:
# 11| [TopLevelFunction] void DestructorCall(C*, D*)
@@ -361,7 +363,7 @@ DestructorCall.cpp:
# 11| Type = [PointerType] C *
# 11| 1: [Parameter] d
# 11| Type = [PointerType] D *
# 11| body: [Block] { ... }
# 11| body: [BlockStmt] { ... }
# 12| 0: [ExprStmt] ExprStmt
# 12| 0: [DeleteExpr] delete
# 12| Type = [VoidType] void
@@ -385,7 +387,7 @@ DynamicCast.cpp:
# 1| params:
#-----| 0: [Parameter] p#0
#-----| Type = [LValueReferenceType] const Base &
#-----| body: [Block] { ... }
#-----| body: [BlockStmt] { ... }
#-----| 0: [ReturnStmt] return ...
#-----| 0: [ReferenceToExpr] (reference to)
#-----| Type = [LValueReferenceType] Base &
@@ -412,13 +414,13 @@ DynamicCast.cpp:
#-----| Type = [RValueReferenceType] Base &&
# 2| [VirtualFunction] void Base::f()
# 2| params:
# 2| body: [Block] { ... }
# 2| body: [BlockStmt] { ... }
# 2| 0: [ReturnStmt] return ...
# 4| [CopyAssignmentOperator] Derived& Derived::operator=(Derived const&)
# 4| params:
#-----| 0: [Parameter] p#0
#-----| Type = [LValueReferenceType] const Derived &
#-----| body: [Block] { ... }
#-----| body: [BlockStmt] { ... }
#-----| 0: [ExprStmt] ExprStmt
#-----| 0: [ReferenceDereferenceExpr] (reference dereference)
#-----| Type = [Class] Base
@@ -478,7 +480,7 @@ DynamicCast.cpp:
#-----| Type = [RValueReferenceType] Derived &&
# 5| [VirtualFunction] void Derived::f()
# 5| params:
# 5| body: [Block] { ... }
# 5| body: [BlockStmt] { ... }
# 5| 0: [ReturnStmt] return ...
# 8| [TopLevelFunction] void DynamicCast(Base*, Derived*)
# 8| params:
@@ -486,7 +488,7 @@ DynamicCast.cpp:
# 8| Type = [PointerType] Base *
# 8| 1: [Parameter] d
# 8| Type = [PointerType] Derived *
# 8| body: [Block] { ... }
# 8| body: [BlockStmt] { ... }
# 9| 0: [ExprStmt] ExprStmt
# 9| 0: [AssignExpr] ... = ...
# 9| Type = [PointerType] Derived *
@@ -508,7 +510,7 @@ DynamicCast.cpp:
# 12| Type = [LValueReferenceType] Base &
# 12| 1: [Parameter] d
# 12| Type = [LValueReferenceType] Derived &
# 12| body: [Block] { ... }
# 12| body: [BlockStmt] { ... }
# 13| 0: [ExprStmt] ExprStmt
# 13| 0: [ReferenceDereferenceExpr] (reference dereference)
# 13| Type = [Class] Derived
@@ -545,7 +547,7 @@ Parenthesis.c:
# 1| params:
# 1| 0: [Parameter] i
# 1| Type = [IntType] int
# 1| body: [Block] { ... }
# 1| body: [BlockStmt] { ... }
# 2| 0: [ExprStmt] ExprStmt
# 2| 0: [AssignExpr] ... = ...
# 2| Type = [IntType] int
@@ -581,7 +583,7 @@ PointerDereference.c:
# 1| Type = [IntPointerType] int *
# 1| 1: [Parameter] j
# 1| Type = [IntType] int
# 1| body: [Block] { ... }
# 1| body: [BlockStmt] { ... }
# 2| 0: [ExprStmt] ExprStmt
# 2| 0: [AssignExpr] ... = ...
# 2| Type = [IntType] int
@@ -603,7 +605,7 @@ ReferenceDereference.cpp:
# 4| Type = [LValueReferenceType] int &
# 4| 1: [Parameter] j
# 4| Type = [IntType] int
# 4| body: [Block] { ... }
# 4| body: [BlockStmt] { ... }
# 5| 0: [ExprStmt] ExprStmt
# 5| 0: [AssignExpr] ... = ...
# 5| Type = [IntType] int
@@ -623,7 +625,7 @@ ReferenceTo.cpp:
# 1| params:
# 1| 0: [Parameter] i
# 1| Type = [IntPointerType] int *
# 1| body: [Block] { ... }
# 1| body: [BlockStmt] { ... }
# 2| 0: [ReturnStmt] return ...
# 2| 0: [ReferenceToExpr] (reference to)
# 2| Type = [LValueReferenceType] int &
@@ -639,7 +641,7 @@ Sizeof.c:
# 1| params:
# 1| 0: [Parameter] array
# 1| Type = [ArrayType] int[]
# 1| body: [Block] { ... }
# 1| body: [BlockStmt] { ... }
# 2| 0: [DeclStmt] declaration
# 2| 0: [VariableDeclarationEntry] definition of i
# 2| Type = [IntType] int
@@ -676,7 +678,7 @@ Sizeof.c:
StatementExpr.c:
# 1| [TopLevelFunction] void StatementExpr()
# 1| params:
# 1| body: [Block] { ... }
# 1| body: [BlockStmt] { ... }
# 2| 0: [DeclStmt] declaration
# 2| 0: [VariableDeclarationEntry] definition of j
# 2| Type = [IntType] int
@@ -700,7 +702,7 @@ StaticMemberAccess.cpp:
# 5| Type = [IntType] int
# 5| 1: [Parameter] xref
# 5| Type = [LValueReferenceType] X &
# 5| body: [Block] { ... }
# 5| body: [BlockStmt] { ... }
# 7| 0: [ExprStmt] ExprStmt
# 7| 0: [AssignExpr] ... = ...
# 7| Type = [IntType] int
@@ -725,7 +727,7 @@ Subscript.c:
# 1| Type = [ArrayType] int[]
# 1| 1: [Parameter] j
# 1| Type = [IntType] int
# 1| body: [Block] { ... }
# 1| body: [BlockStmt] { ... }
# 2| 0: [ExprStmt] ExprStmt
# 2| 0: [AssignExpr] ... = ...
# 2| Type = [IntType] int
@@ -762,20 +764,20 @@ Throw.cpp:
#-----| 0: [Parameter] p#0
#-----| Type = [RValueReferenceType] F &&
# 2| initializations:
# 2| body: [Block] { ... }
# 2| body: [BlockStmt] { ... }
# 2| 0: [ReturnStmt] return ...
# 4| [Constructor] void F::F()
# 4| params:
# 4| initializations:
# 4| body: [Block] { ... }
# 4| body: [BlockStmt] { ... }
# 4| 0: [ReturnStmt] return ...
# 6| [TopLevelFunction] void Throw(int)
# 6| params:
# 6| 0: [Parameter] i
# 6| Type = [IntType] int
# 6| body: [Block] { ... }
# 6| body: [BlockStmt] { ... }
# 7| 0: [TryStmt] try { ... }
# 7| 0: [Block] { ... }
# 7| 0: [BlockStmt] { ... }
# 8| 0: [IfStmt] if (...) ...
# 8| 0: [CStyleCast] (bool)...
# 8| Conversion = [BoolConversion] conversion to bool
@@ -818,13 +820,13 @@ Typeid.cpp:
# 7| params:
# 13| [VirtualFunction] void Base::v()
# 13| params:
# 13| body: [Block] { ... }
# 13| body: [BlockStmt] { ... }
# 13| 0: [ReturnStmt] return ...
# 18| [TopLevelFunction] void TypeId(Base*)
# 18| params:
# 18| 0: [Parameter] bp
# 18| Type = [PointerType] Base *
# 18| body: [Block] { ... }
# 18| body: [BlockStmt] { ... }
# 19| 0: [DeclStmt] declaration
# 19| 0: [VariableDeclarationEntry] definition of name
# 19| Type = [PointerType] const char *
@@ -846,7 +848,7 @@ VacuousDestructorCall.cpp:
# 2| Type = [TemplateParameter] T
# 2| 1: [Parameter] y
# 2| Type = [PointerType] T *
# 2| body: [Block] { ... }
# 2| body: [BlockStmt] { ... }
# 3| 0: [ExprStmt] ExprStmt
# 3| 0: [ExprCall] call to expression
# 3| Type = [UnknownType] unknown
@@ -874,7 +876,7 @@ VacuousDestructorCall.cpp:
# 2| Type = [IntType] int
# 2| 1: [Parameter] y
# 2| Type = [IntPointerType] int *
# 2| body: [Block] { ... }
# 2| body: [BlockStmt] { ... }
# 3| 0: [ExprStmt] ExprStmt
# 3| 0: [VacuousDestructorCall] (vacuous destructor call)
# 3| Type = [VoidType] void
@@ -894,7 +896,7 @@ VacuousDestructorCall.cpp:
# 7| params:
# 7| 0: [Parameter] i
# 7| Type = [IntType] int
# 7| body: [Block] { ... }
# 7| body: [BlockStmt] { ... }
# 10| 0: [ExprStmt] ExprStmt
# 10| 0: [FunctionCall] call to CallDestructor
# 10| Type = [VoidType] void
@@ -914,7 +916,7 @@ Varargs.c:
# 8| params:
# 8| 0: [Parameter] text
# 8| Type = [PointerType] const char *
# 8| body: [Block] { ... }
# 8| body: [BlockStmt] { ... }
# 9| 0: [DeclStmt] declaration
# 9| 0: [VariableDeclarationEntry] definition of args
# 9| Type = [CTypedefType] va_list
@@ -947,7 +949,7 @@ macro_etc.c:
# 3| params:
# 3| 0: [Parameter] i
# 3| Type = [IntType] int
# 3| body: [Block] { ... }
# 3| body: [BlockStmt] { ... }
# 4| 0: [DeclStmt] declaration
# 4| 0: [TypeDeclarationEntry] definition of u
# 4| Type = [LocalUnion] u
@@ -997,7 +999,7 @@ macro_etc.c:
# 10| ValueCategory = prvalue
# 22| [TopLevelFunction] int foo()
# 22| params:
# 22| body: [Block] { ... }
# 22| body: [BlockStmt] { ... }
# 23| 0: [DeclStmt] declaration
# 23| 0: [VariableDeclarationEntry] definition of t
# 23| Type = [IntType] int
@@ -1059,7 +1061,7 @@ macro_etc.c:
# 27| 0: [VariableAccess] i
# 27| Type = [PlainCharType] char
# 27| ValueCategory = lvalue
# 27| 3: [Block] { ... }
# 27| 3: [BlockStmt] { ... }
# 27| 0: [ExprStmt] ExprStmt
# 27| 0: [AssignAddExpr] ... += ...
# 27| Type = [IntType] int
@@ -1111,7 +1113,7 @@ macro_etc.c:
# 28| 0: [VariableAccess] i
# 28| Type = [PlainCharType] char
# 28| ValueCategory = lvalue
# 28| 3: [Block] { ... }
# 28| 3: [BlockStmt] { ... }
# 28| 0: [ExprStmt] ExprStmt
# 28| 0: [AssignAddExpr] ... += ...
# 28| Type = [IntType] int
@@ -1210,7 +1212,7 @@ union_etc.cpp:
# 2| [Constructor] void S::S()
# 2| params:
# 2| initializations:
# 2| body: [Block] { ... }
# 2| body: [BlockStmt] { ... }
# 2| 0: [ReturnStmt] return ...
# 2| [CopyConstructor] void S::S(S const&)
# 2| params:
@@ -1240,7 +1242,7 @@ union_etc.cpp:
# 6| params:
# 6| 0: [Parameter] val
# 6| Type = [IntType] int
# 6| body: [Block] { ... }
# 6| body: [BlockStmt] { ... }
# 6| 0: [ExprStmt] ExprStmt
# 6| 0: [AssignExpr] ... = ...
# 6| Type = [IntType] int
@@ -1305,7 +1307,7 @@ union_etc.cpp:
#-----| Type = [RValueReferenceType] C &&
# 22| [TopLevelFunction] int foo()
# 22| params:
# 22| body: [Block] { ... }
# 22| body: [BlockStmt] { ... }
# 23| 0: [DeclStmt] declaration
# 23| 0: [VariableDeclarationEntry] definition of s
# 23| Type = [Struct] S
@@ -1423,7 +1425,7 @@ union_etc.cpp:
# 33| params:
# 33| 0: [Parameter] val
# 33| Type = [IntType] int
# 33| body: [Block] { ... }
# 33| body: [BlockStmt] { ... }
# 33| 0: [ExprStmt] ExprStmt
# 33| 0: [AssignExpr] ... = ...
# 33| Type = [IntType] int
@@ -1440,7 +1442,7 @@ union_etc.cpp:
# 33| 1: [ReturnStmt] return ...
# 36| [TopLevelFunction] int bar()
# 36| params:
# 36| body: [Block] { ... }
# 36| body: [BlockStmt] { ... }
# 37| 0: [DeclStmt] declaration
# 37| 0: [VariableDeclarationEntry] definition of s
# 37| Type = [PointerType] const T *

View File

@@ -7,6 +7,8 @@
| foo.h:1:13:1:15 | foo | Function | 1 | <none> |
| foo.h:1:13:1:15 | foo | MemberFunction | 1 | C |
| foo.h:1:13:1:15 | foo | MemberFunction | 1 | C |
| main2.cpp:7:7:7:7 | C | MemberFunction | 0 | C |
| main2.cpp:7:7:7:7 | C | MemberFunction | 0 | C |
| main2.cpp:7:7:7:7 | operator= | MemberFunction | 0 | C |
| main2.cpp:7:7:7:7 | operator= | MemberFunction | 0 | C |
| main2.cpp:7:7:7:7 | operator= | MemberFunction | 0 | C |

View File

@@ -8,89 +8,143 @@
| direct_friend::D::f | Can access D::f |
| direct_friend::D::f | Can access D::operator= |
| direct_friend::D::f | Can access D::x |
| field_and_base::P::f | Can access B::B |
| field_and_base::P::f | Can access B::operator= |
| field_and_base::P::f | Can access P::B |
| field_and_base::P::f | Can access P::P |
| field_and_base::P::f | Can access P::f |
| field_and_base::P::f | Can access P::fieldB |
| field_and_base::P::f | Can access P::m |
| field_and_base::P::f | Can access P::m_static |
| field_and_base::P::f | Can access P::operator= |
| friend_class::B::fun | Can access B::B |
| friend_class::B::fun | Can access B::a |
| friend_class::B::fun | Can access B::b |
| friend_class::B::fun | Can access B::fun |
| friend_class::B::fun | Can access B::operator= |
| friend_class::B::fun | Can access C::C |
| friend_class::B::fun | Can access C::operator= |
| friend_class::B::fun | Can access D1::D1 |
| friend_class::B::fun | Can access D1::operator= |
| friend_class::B::fun | Can access D2::D2 |
| friend_class::B::fun | Can access D2::operator= |
| friend_class::C::fun | Can access B::B |
| friend_class::C::fun | Can access B::operator= |
| friend_class::C::fun | Can access C::B |
| friend_class::C::fun | Can access C::C |
| friend_class::C::fun | Can access C::fun |
| friend_class::C::fun | Can access C::operator= |
| friend_class::C::fun | Can access C::x |
| friend_class::C::fun | Can access C::y |
| friend_class::C::fun | Can access D1::D1 |
| friend_class::C::fun | Can access D1::operator= |
| friend_class::C::fun | Can access D2::D2 |
| friend_class::C::fun | Can access D2::operator= |
| friend_class::D1::fun | Can access B::B |
| friend_class::D1::fun | Can access B::a |
| friend_class::D1::fun | Can access B::b |
| friend_class::D1::fun | Can access B::fun |
| friend_class::D1::fun | Can access B::operator= |
| friend_class::D1::fun | Can access C::C |
| friend_class::D1::fun | Can access C::operator= |
| friend_class::D1::fun | Can access D1::C |
| friend_class::D1::fun | Can access D1::D1 |
| friend_class::D1::fun | Can access D1::fun |
| friend_class::D1::fun | Can access D1::operator= |
| friend_class::D1::fun | Can access D2::D2 |
| friend_class::D1::fun | Can access D2::operator= |
| friend_class::D2::fun | Can access B::B |
| friend_class::D2::fun | Can access B::a |
| friend_class::D2::fun | Can access B::b |
| friend_class::D2::fun | Can access B::fun |
| friend_class::D2::fun | Can access B::operator= |
| friend_class::D2::fun | Can access C::C |
| friend_class::D2::fun | Can access C::operator= |
| friend_class::D2::fun | Can access D1::D1 |
| friend_class::D2::fun | Can access D1::operator= |
| friend_class::D2::fun | Can access D2::B |
| friend_class::D2::fun | Can access D2::D2 |
| friend_class::D2::fun | Can access D2::a |
| friend_class::D2::fun | Can access D2::b |
| friend_class::D2::fun | Can access D2::fun |
| friend_class::D2::fun | Can access D2::operator= |
| friend_fun::fun1 | Can access A::operator= |
| friend_fun::fun1 | Can access B::B |
| friend_fun::fun1 | Can access B::operator= |
| friend_fun::fun2 | Can access A::operator= |
| friend_fun::fun2 | Can access B::B |
| friend_fun::fun2 | Can access B::operator= |
| friend_fun::fun2 | Can access B::x |
| friend_fun::fun2 | Can access B::y |
| mixed::B::fun | Can access A::A |
| mixed::B::fun | Can access A::operator= |
| mixed::B::fun | Can access B::A |
| mixed::B::fun | Can access B::B |
| mixed::B::fun | Can access B::fun |
| mixed::B::fun | Can access B::operator= |
| mixed::B::fun | Can access C::C |
| mixed::B::fun | Can access C::operator= |
| mixed::B::fun | Can access D::C |
| mixed::B::fun | Can access D::D |
| mixed::B::fun | Can access D::operator= |
| mixed::C::fun | Can access A::A |
| mixed::C::fun | Can access A::operator= |
| mixed::C::fun | Can access B::B |
| mixed::C::fun | Can access B::operator= |
| mixed::C::fun | Can access C::B |
| mixed::C::fun | Can access C::C |
| mixed::C::fun | Can access C::fun |
| mixed::C::fun | Can access C::operator= |
| mixed::C::fun | Can access D::B |
| mixed::C::fun | Can access D::C |
| mixed::C::fun | Can access D::D |
| mixed::C::fun | Can access D::fun |
| mixed::C::fun | Can access D::operator= |
| mixed::D::fun | Can access A::A |
| mixed::D::fun | Can access A::operator= |
| mixed::D::fun | Can access B::B |
| mixed::D::fun | Can access B::operator= |
| mixed::D::fun | Can access C::B |
| mixed::D::fun | Can access C::C |
| mixed::D::fun | Can access C::operator= |
| mixed::D::fun | Can access D::B |
| mixed::D::fun | Can access D::C |
| mixed::D::fun | Can access D::D |
| mixed::D::fun | Can access D::fun |
| mixed::D::fun | Can access D::operator= |
| protected_derived::BP::f | Can access B::m |
| protected_derived::BP::f | Can access B::operator= |
| protected_derived::BP::f | Can access BN::BN |
| protected_derived::BP::f | Can access BN::operator= |
| protected_derived::BP::f | Can access BP::BP |
| protected_derived::BP::f | Can access BP::f |
| protected_derived::BP::f | Can access BP::m |
| protected_derived::BP::f | Can access BP::operator= |
| protected_derived::BP::f | Can access BPNprot::BPNprot |
| protected_derived::BP::f | Can access BPNprot::operator= |
| protected_derived::BP::f | Can access BPNpub::BP |
| protected_derived::BP::f | Can access BPNpub::BPNpub |
| protected_derived::BP::f | Can access BPNpub::f |
| protected_derived::BP::f | Can access BPNpub::m |
| protected_derived::BP::f | Can access BPNpub::operator= |
| protected_virtual::P::f | Can access B::B |
| protected_virtual::P::f | Can access B::operator= |
| protected_virtual::P::f | Can access Nprot::Nprot |
| protected_virtual::P::f | Can access Nprot::operator= |
| protected_virtual::P::f | Can access Npub::B |
| protected_virtual::P::f | Can access Npub::Npub |
| protected_virtual::P::f | Can access Npub::m |
| protected_virtual::P::f | Can access Npub::operator= |
| protected_virtual::P::f | Can access P::B |
| protected_virtual::P::f | Can access P::P |
| protected_virtual::P::f | Can access P::f |
| protected_virtual::P::f | Can access P::m |
| protected_virtual::P::f | Can access P::operator= |
| simple::Derived::castme | Can access Base::operator= |
| simple::Derived::castme | Can access Derived::Derived |
| simple::Derived::castme | Can access Derived::castme |
| simple::Derived::castme | Can access Derived::operator= |
| simple::top | Can access Base::operator= |
| simple::top | Can access Derived::Derived |
| simple::top | Can access Derived::castme |
| simple::top | Can access Derived::operator= |

View File

@@ -88,14 +88,14 @@ void test_stringstream()
ss5 << t;
sink(ss1);
sink(ss2); // tainted [NOT DETECTED]
sink(ss2); // tainted
sink(ss3); // tainted [NOT DETECTED]
sink(ss4); // tainted [NOT DETECTED]
sink(ss4); // tainted
sink(ss5); // tainted [NOT DETECTED]
sink(ss1.str());
sink(ss2.str()); // tainted [NOT DETECTED]
sink(ss2.str()); // tainted
sink(ss3.str()); // tainted [NOT DETECTED]
sink(ss4.str()); // tainted [NOT DETECTED]
sink(ss4.str()); // tainted
sink(ss5.str()); // tainted [NOT DETECTED]
}

View File

@@ -197,8 +197,10 @@
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:15:23:20 | call to getenv |
| stl.cpp:62:25:62:30 | call to getenv | shared.h:5:23:5:31 | sinkparam |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:21:29:21:29 | s |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:78:43:104 | p#0 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:114:43:118 | p#1 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:25:62:30 | call to getenv |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:64:36:64:36 | s |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:8:68:8 | a |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:12:68:17 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:21 | call to source |
@@ -209,12 +211,31 @@
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:21 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:23 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:6 | call to operator<< |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:17 | (reference dereference) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:9:85:14 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:9:85:16 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:15 | call to operator<< |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:26 | (reference dereference) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:18:86:23 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:18:86:25 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:6 | call to operator<< |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference dereference) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference to) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:14 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:18 | call to operator<< |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:26 | (reference dereference) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (const stringstream)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (reference to) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | ss2 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (const stringstream)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (reference to) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | ss4 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | (const basic_stringstream<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | ss2 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | (const basic_stringstream<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | ss4 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:118:10:118:15 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:26 | call to user_input |

View File

@@ -61,10 +61,31 @@
| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:210:8:210:23 | ... + ... | IR only |
| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:5:13:11 | global1 | AST only |
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:5:23:11 | global2 | AST only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:78:43:104 | p#0 | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:7:62:12 | source | AST only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:64:36:64:36 | s | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:24 | call to basic_string | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:6 | call to operator<< | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:17 | (reference dereference) | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:15 | call to operator<< | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:26 | (reference dereference) | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:6 | call to operator<< | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference dereference) | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference to) | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:18 | call to operator<< | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:26 | (reference dereference) | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (const stringstream)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (reference to) | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | ss2 | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (const stringstream)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (reference to) | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | ss4 | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | (const basic_stringstream<char, char_traits<char>, allocator<char>>)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | ss2 | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | (const basic_stringstream<char, char_traits<char>, allocator<char>>)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | ss4 | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:117:7:117:16 | user_input | AST only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:128:9:128:13 | path2 | IR only |

View File

@@ -48,6 +48,6 @@ void following_pointers(
int stackArray[2] = { source(), source() };
stackArray[0] = source();
sink(stackArray); // no flow
sink(stackArray); // flow
}

View File

@@ -13,6 +13,7 @@
| example.c:24:13:24:18 | coords [post update] | example.c:26:19:26:24 | coords |
| example.c:24:13:24:30 | ... = ... | example.c:24:2:24:30 | ... = ... |
| example.c:24:13:24:30 | ... = ... | example.c:24:20:24:20 | y [post update] |
| example.c:24:20:24:20 | y | example.c:24:13:24:30 | ... = ... |
| example.c:24:24:24:30 | ... + ... | example.c:24:13:24:30 | ... = ... |
| example.c:26:2:26:25 | ... = ... | example.c:26:9:26:9 | x [post update] |
| example.c:26:13:26:16 | call to getX | example.c:26:2:26:25 | ... = ... |

View File

@@ -428,7 +428,7 @@ void intPointerSourceCaller2() {
int local[1];
intPointerSource(local);
sink(local); // tainted
sink(*local); // clean
sink(*local); // tainted
}
void intArraySourceCaller() {
@@ -441,7 +441,7 @@ void intArraySourceCaller2() {
int local[2];
intArraySource(local, 2);
sink(local); // tainted
sink(*local); // clean
sink(*local); // tainted
}
///////////////////////////////////////////////////////////////////////////////
@@ -468,5 +468,5 @@ void intOutparamSource(int *p) {
void viaOutparam() {
int x = 0;
intOutparamSource(&x);
sink(x); // tainted [FALSE NEGATIVE]
sink(x); // tainted
}

View File

@@ -16,6 +16,7 @@
| clang.cpp:30:27:30:34 | call to getFirst | clang.cpp:28:27:28:32 | call to source |
| clang.cpp:37:10:37:11 | m2 | clang.cpp:34:32:34:37 | call to source |
| clang.cpp:45:17:45:18 | m2 | clang.cpp:43:35:43:40 | call to source |
| clang.cpp:51:8:51:17 | stackArray | clang.cpp:50:19:50:24 | call to source |
| dispatch.cpp:11:38:11:38 | x | 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:35:16:35:25 | call to notSource1 | dispatch.cpp:9:37:9:42 | call to source |
@@ -79,12 +80,17 @@
| test.cpp:424:8:424:12 | local | test.cpp:423:20:423:25 | ref arg & ... |
| test.cpp:430:8:430:12 | local | test.cpp:428:7:428:11 | local |
| test.cpp:430:8:430:12 | local | test.cpp:429:20:429:24 | ref arg local |
| test.cpp:431:8:431:13 | * ... | test.cpp:428:7:428:11 | local |
| test.cpp:431:8:431:13 | * ... | test.cpp:429:20:429:24 | ref arg local |
| test.cpp:437:8:437:12 | local | test.cpp:435:7:435:11 | local |
| test.cpp:437:8:437:12 | local | test.cpp:436:18:436:23 | ref arg & ... |
| test.cpp:443:8:443:12 | local | test.cpp:441:7:441:11 | local |
| test.cpp:443:8:443:12 | local | test.cpp:442:18:442:22 | ref arg local |
| test.cpp:444:8:444:13 | * ... | test.cpp:441:7:441:11 | local |
| test.cpp:444:8:444:13 | * ... | test.cpp:442:18:442:22 | ref arg local |
| test.cpp:450:9:450:22 | (statement expression) | test.cpp:449:26:449:32 | source1 |
| test.cpp:461:8:461:12 | local | test.cpp:449:26:449:32 | source1 |
| test.cpp:471:8:471:8 | x | test.cpp:465:8:465:13 | call to source |
| true_upon_entry.cpp:21:8:21:8 | x | true_upon_entry.cpp:17:11:17:16 | call to source |
| true_upon_entry.cpp:29:8:29:8 | x | true_upon_entry.cpp:27:9:27:14 | call to source |
| true_upon_entry.cpp:39:8:39:8 | x | true_upon_entry.cpp:33:11:33:16 | call to source |

View File

@@ -2,6 +2,7 @@
| BarrierGuard.cpp:60:11:60:16 | BarrierGuard.cpp:62:14:62:14 | AST only |
| clang.cpp:12:9:12:20 | clang.cpp:22:8:22:20 | AST only |
| clang.cpp:39:42:39:47 | clang.cpp:41:18:41:19 | IR only |
| clang.cpp:50:19:50:24 | clang.cpp:51:8:51:17 | AST only |
| dispatch.cpp:16:37:16:42 | dispatch.cpp:32:16:32:24 | IR only |
| dispatch.cpp:16:37:16:42 | dispatch.cpp:40:15:40:23 | IR only |
| dispatch.cpp:22:37:22:42 | dispatch.cpp:31:16:31:24 | IR only |
@@ -41,11 +42,16 @@
| test.cpp:422:7:422:11 | test.cpp:424:8:424:12 | AST only |
| test.cpp:423:20:423:25 | test.cpp:424:8:424:12 | AST only |
| test.cpp:428:7:428:11 | test.cpp:430:8:430:12 | AST only |
| test.cpp:428:7:428:11 | test.cpp:431:8:431:13 | AST only |
| test.cpp:429:20:429:24 | test.cpp:430:8:430:12 | AST only |
| test.cpp:429:20:429:24 | test.cpp:431:8:431:13 | AST only |
| test.cpp:435:7:435:11 | test.cpp:437:8:437:12 | AST only |
| test.cpp:436:18:436:23 | test.cpp:437:8:437:12 | AST only |
| test.cpp:441:7:441:11 | test.cpp:443:8:443:12 | AST only |
| test.cpp:441:7:441:11 | test.cpp:444:8:444:13 | AST only |
| test.cpp:442:18:442:22 | test.cpp:443:8:443:12 | AST only |
| test.cpp:442:18:442:22 | test.cpp:444:8:444:13 | AST only |
| test.cpp:465:8:465:13 | test.cpp:471:8:471:8 | AST only |
| true_upon_entry.cpp:9:11:9:16 | true_upon_entry.cpp:13:8:13:8 | IR only |
| true_upon_entry.cpp:62:11:62:16 | true_upon_entry.cpp:66:8:66:8 | IR only |
| true_upon_entry.cpp:98:11:98:16 | true_upon_entry.cpp:105:8:105:8 | IR only |

View File

@@ -104,7 +104,7 @@ public:
{
if (C1 *c1 = dynamic_cast<C1 *>(c))
{
sink(c1->a); // $ast $ir
sink(c1->a); // $ast,ir
}
C *cc;
if (C2 *c2 = dynamic_cast<C2 *>(c))

View File

@@ -92,3 +92,12 @@ void nestedAssign() {
w.s.m1 = user_input();
sink(w.s.m1); // $ast,ir
}
void addressOfField() {
S s;
s.m1 = user_input();
S s_copy = s;
int* px = &s_copy.m1;
sink(*px); // $f-:ast $ir
}

View File

@@ -0,0 +1,51 @@
void sink(void *o);
void *user_input(void);
void local_array() {
void *arr[10] = { 0 };
arr[0] = user_input();
sink(arr[0]); // $ast,ir
sink(arr[1]); // $f+:ast
sink(*arr); // $ast,ir
sink(*&arr[0]); // $ast,ir
}
void local_array_convoluted_assign() {
void *arr[10] = { 0 };
*&arr[0] = user_input();
sink(arr[0]); // $ast,ir
sink(arr[1]); // $f+:ast
}
struct inner {
void *data;
int unrelated;
};
struct middle {
inner arr[10];
inner *ptr;
};
struct outer {
middle nested;
middle *indirect;
};
void nested_array_1(outer o) {
o.nested.arr[1].data = user_input();
sink(o.nested.arr[1].data); // $ast,ir
sink(o.nested.arr[0].data); // $f+:ast
}
void nested_array_2(outer o) {
o.indirect->arr[1].data = user_input();
sink(o.indirect->arr[1].data); // $ast $f-:ir
sink(o.indirect->arr[0].data); // $f+:ast
}
void nested_array_3(outer o) {
o.indirect->ptr[1].data = user_input();
sink(o.indirect->ptr[1].data); // $f-:ast,ir
sink(o.indirect->ptr[0].data);
}

View File

@@ -109,11 +109,11 @@ void test_outer_with_ptr(Outer *pouter) {
sink(outer.inner_nested.a); // $ast,ir
sink(outer.inner_ptr->a); // $ast $f-:ir
sink(outer.a); // $f-:ast $f-:ir
sink(outer.a); // $ast $f-:ir
sink(pouter->inner_nested.a); // $ast,ir
sink(pouter->inner_ptr->a); // $ast $f-:ir
sink(pouter->a); // $f-:ast $f-:ir
sink(pouter->a); // $ast $f-:ir
}
void test_outer_with_ref(Outer *pouter) {

View File

@@ -30,6 +30,12 @@ argHasPostUpdate
| D.cpp:43:24:43:40 | new | ArgumentNode is missing PostUpdateNode. |
| D.cpp:50:24:50:40 | new | ArgumentNode is missing PostUpdateNode. |
| D.cpp:57:25:57:41 | new | ArgumentNode is missing PostUpdateNode. |
| arrays.cpp:7:8:7:13 | access to array | ArgumentNode is missing PostUpdateNode. |
| arrays.cpp:8:8:8:13 | access to array | ArgumentNode is missing PostUpdateNode. |
| arrays.cpp:9:8:9:11 | * ... | ArgumentNode is missing PostUpdateNode. |
| arrays.cpp:10:8:10:15 | * ... | ArgumentNode is missing PostUpdateNode. |
| arrays.cpp:16:8:16:13 | access to array | ArgumentNode is missing PostUpdateNode. |
| arrays.cpp:17:8:17:13 | access to array | ArgumentNode is missing PostUpdateNode. |
| by_reference.cpp:51:8:51:8 | s | ArgumentNode is missing PostUpdateNode. |
| by_reference.cpp:57:8:57:8 | s | ArgumentNode is missing PostUpdateNode. |
| by_reference.cpp:63:8:63:8 | s | ArgumentNode is missing PostUpdateNode. |

View File

@@ -1,13 +1,10 @@
uniqueEnclosingCallable
uniqueType
uniqueNodeLocation
| D.cpp:1:17:1:17 | o | Node should have one location but has 3. |
| by_reference.cpp:1:17:1:17 | o | Node should have one location but has 3. |
| file://:0:0:0:0 | p#0 | Node should have one location but has 0. |
| file://:0:0:0:0 | p#0 | Node should have one location but has 0. |
| file://:0:0:0:0 | p#0 | Node should have one location but has 0. |
| file://:0:0:0:0 | p#0 | Node should have one location but has 0. |
| qualifiers.cpp:1:17:1:17 | o | Node should have one location but has 3. |
missingLocation
| Nodes without location: 4 |
uniqueNodeToString
@@ -20,6 +17,7 @@ localCallNodes
postIsNotPre
postHasUniquePre
| simple.cpp:65:5:65:22 | Store | PostUpdateNode should have one pre-update node but has 0. |
| simple.cpp:92:5:92:22 | Store | PostUpdateNode should have one pre-update node but has 0. |
uniquePostUpdate
postIsInSameCallable
reverseRead

View File

@@ -20,10 +20,18 @@
| aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | IR only |
| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | IR only |
| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | IR only |
| aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:102:8:102:10 | * ... | IR only |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:8:8:8:13 | access to array | AST only |
| arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:17:8:17:13 | access to array | AST only |
| arrays.cpp:36:26:36:35 | call to user_input | arrays.cpp:38:24:38:27 | data | AST only |
| arrays.cpp:42:29:42:38 | call to user_input | arrays.cpp:43:27:43:30 | data | AST only |
| arrays.cpp:42:29:42:38 | call to user_input | arrays.cpp:44:27:44:30 | data | AST only |
| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:111:25:111:25 | a | AST only |
| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:115:27:115:27 | a | AST only |
| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:131:25:131:25 | a | AST only |
| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | AST only |
| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:112:14:112:14 | a | AST only |
| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:116:16:116:16 | a | AST only |
| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | AST only |
| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | AST only |
| complex.cpp:62:19:62:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | AST only |
@@ -36,5 +44,6 @@
| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:38:23:38:23 | a | AST only |
| qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:43:23:43:23 | a | AST only |
| qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:48:23:48:23 | a | AST only |
| realistic.cpp:53:55:53:64 | call to user_input | realistic.cpp:61:47:61:55 | bufferLen | AST only |
| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:33:25:33:25 | a | AST only |
| struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | AST only |

View File

@@ -60,6 +60,15 @@ edges
| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 |
| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 |
| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 |
| aliasing.cpp:98:3:98:21 | Chi [m1] | aliasing.cpp:100:14:100:14 | Store [m1] |
| aliasing.cpp:98:3:98:21 | Store | aliasing.cpp:98:3:98:21 | Chi [m1] |
| aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:98:3:98:21 | Store |
| aliasing.cpp:100:14:100:14 | Store [m1] | aliasing.cpp:102:8:102:10 | * ... |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... |
| arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:16:8:16:13 | access to array |
| arrays.cpp:36:26:36:35 | call to user_input | arrays.cpp:37:24:37:27 | data |
| by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | by_reference.cpp:51:8:51:8 | Argument -1 indirection [a] |
| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | setDirectly output argument [a] |
| by_reference.cpp:51:8:51:8 | Argument -1 indirection [a] | by_reference.cpp:51:10:51:20 | call to getDirectly |
@@ -158,6 +167,9 @@ edges
| simple.cpp:83:9:83:28 | Store | simple.cpp:83:9:83:28 | Chi [f1] |
| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Store |
| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | simple.cpp:84:14:84:20 | call to getf2f1 |
| simple.cpp:92:5:92:22 | Store [i] | simple.cpp:93:20:93:20 | Store [i] |
| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | Store [i] |
| simple.cpp:93:20:93:20 | Store [i] | simple.cpp:94:13:94:13 | i |
| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a |
| struct_init.c:20:20:20:29 | Chi [a] | struct_init.c:24:10:24:12 | Argument 0 indirection [a] |
| struct_init.c:20:20:20:29 | Store | struct_init.c:20:20:20:29 | Chi [a] |
@@ -247,6 +259,19 @@ nodes
| aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 |
| aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 |
| aliasing.cpp:98:3:98:21 | Chi [m1] | semmle.label | Chi [m1] |
| aliasing.cpp:98:3:98:21 | Store | semmle.label | Store |
| aliasing.cpp:98:10:98:19 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:100:14:100:14 | Store [m1] | semmle.label | Store [m1] |
| aliasing.cpp:102:8:102:10 | * ... | semmle.label | * ... |
| arrays.cpp:6:12:6:21 | call to user_input | semmle.label | call to user_input |
| arrays.cpp:7:8:7:13 | access to array | semmle.label | access to array |
| arrays.cpp:9:8:9:11 | * ... | semmle.label | * ... |
| arrays.cpp:10:8:10:15 | * ... | semmle.label | * ... |
| arrays.cpp:15:14:15:23 | call to user_input | semmle.label | call to user_input |
| arrays.cpp:16:8:16:13 | access to array | semmle.label | access to array |
| arrays.cpp:36:26:36:35 | call to user_input | semmle.label | call to user_input |
| arrays.cpp:37:24:37:27 | data | semmle.label | data |
| by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | semmle.label | setDirectly output argument [a] |
| by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:51:8:51:8 | Argument -1 indirection [a] | semmle.label | Argument -1 indirection [a] |
@@ -354,6 +379,10 @@ nodes
| simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input |
| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | semmle.label | Argument -1 indirection [f1] |
| simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 |
| simple.cpp:92:5:92:22 | Store [i] | semmle.label | Store [i] |
| simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input |
| simple.cpp:93:20:93:20 | Store [i] | semmle.label | Store [i] |
| simple.cpp:94:13:94:13 | i | semmle.label | i |
| struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] |
| struct_init.c:15:12:15:12 | a | semmle.label | a |
| struct_init.c:20:20:20:29 | Chi [a] | semmle.label | Chi [a] |
@@ -385,6 +414,12 @@ nodes
| aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input | call to user_input |
| aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input | call to user_input |
| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input |
| aliasing.cpp:102:8:102:10 | * ... | aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:102:8:102:10 | * ... | * ... flows from $@ | aliasing.cpp:98:10:98:19 | call to user_input | call to user_input |
| arrays.cpp:7:8:7:13 | access to array | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array | access to array flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input |
| arrays.cpp:9:8:9:11 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input |
| arrays.cpp:10:8:10:15 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input |
| arrays.cpp:16:8:16:13 | access to array | arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:16:8:16:13 | access to array | access to array flows from $@ | arrays.cpp:15:14:15:23 | call to user_input | call to user_input |
| arrays.cpp:37:24:37:27 | data | arrays.cpp:36:26:36:35 | call to user_input | arrays.cpp:37:24:37:27 | data | data flows from $@ | arrays.cpp:36:26:36:35 | call to user_input | call to user_input |
| by_reference.cpp:51:10:51:20 | call to getDirectly | by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:51:10:51:20 | call to getDirectly | call to getDirectly flows from $@ | by_reference.cpp:50:17:50:26 | call to user_input | call to user_input |
| by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input |
| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input |
@@ -407,6 +442,7 @@ nodes
| simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input |
| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input |
| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input |
| simple.cpp:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input |
| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input |
| struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |

View File

@@ -157,6 +157,44 @@
| aliasing.cpp:86:5:86:6 | m1 | AST only |
| aliasing.cpp:92:3:92:3 | w | AST only |
| aliasing.cpp:92:7:92:8 | m1 | AST only |
| aliasing.cpp:98:5:98:6 | m1 | AST only |
| arrays.cpp:6:3:6:8 | access to array | AST only |
| arrays.cpp:15:3:15:10 | * ... | AST only |
| arrays.cpp:36:3:36:3 | o | AST only |
| arrays.cpp:36:5:36:10 | nested | AST only |
| arrays.cpp:36:19:36:22 | data | AST only |
| arrays.cpp:37:8:37:8 | o | AST only |
| arrays.cpp:37:8:37:22 | access to array | AST only |
| arrays.cpp:37:10:37:15 | nested | AST only |
| arrays.cpp:37:24:37:27 | data | AST only |
| arrays.cpp:38:8:38:8 | o | AST only |
| arrays.cpp:38:8:38:22 | access to array | AST only |
| arrays.cpp:38:10:38:15 | nested | AST only |
| arrays.cpp:38:24:38:27 | data | AST only |
| arrays.cpp:42:3:42:3 | o | AST only |
| arrays.cpp:42:3:42:20 | access to array | AST only |
| arrays.cpp:42:5:42:12 | indirect | AST only |
| arrays.cpp:42:22:42:25 | data | AST only |
| arrays.cpp:43:8:43:8 | o | AST only |
| arrays.cpp:43:8:43:25 | access to array | AST only |
| arrays.cpp:43:10:43:17 | indirect | AST only |
| arrays.cpp:43:27:43:30 | data | AST only |
| arrays.cpp:44:8:44:8 | o | AST only |
| arrays.cpp:44:8:44:25 | access to array | AST only |
| arrays.cpp:44:10:44:17 | indirect | AST only |
| arrays.cpp:44:27:44:30 | data | AST only |
| arrays.cpp:48:3:48:3 | o | AST only |
| arrays.cpp:48:3:48:20 | access to array | AST only |
| arrays.cpp:48:5:48:12 | indirect | AST only |
| arrays.cpp:48:22:48:25 | data | AST only |
| arrays.cpp:49:8:49:8 | o | AST only |
| arrays.cpp:49:8:49:25 | access to array | AST only |
| arrays.cpp:49:10:49:17 | indirect | AST only |
| arrays.cpp:49:27:49:30 | data | AST only |
| arrays.cpp:50:8:50:8 | o | AST only |
| arrays.cpp:50:8:50:25 | access to array | AST only |
| arrays.cpp:50:10:50:17 | indirect | AST only |
| arrays.cpp:50:27:50:30 | data | AST only |
| by_reference.cpp:12:8:12:8 | a | AST only |
| by_reference.cpp:16:11:16:11 | a | AST only |
| by_reference.cpp:20:5:20:8 | this | AST only |
@@ -177,6 +215,8 @@
| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | AST only |
| by_reference.cpp:84:10:84:10 | a | AST only |
| by_reference.cpp:88:9:88:9 | a | AST only |
| by_reference.cpp:92:3:92:5 | * ... | AST only |
| by_reference.cpp:96:3:96:4 | pa | AST only |
| by_reference.cpp:102:21:102:39 | & ... | AST only |
| by_reference.cpp:102:22:102:26 | outer | AST only |
| by_reference.cpp:103:21:103:25 | outer | AST only |
@@ -304,6 +344,32 @@
| qualifiers.cpp:48:10:48:14 | outer | AST only |
| qualifiers.cpp:48:16:48:20 | inner | AST only |
| qualifiers.cpp:48:23:48:23 | a | AST only |
| realistic.cpp:26:5:26:10 | offset | AST only |
| realistic.cpp:42:20:42:20 | o | AST only |
| realistic.cpp:49:9:49:11 | foo | AST only |
| realistic.cpp:49:20:49:22 | baz | AST only |
| realistic.cpp:53:9:53:11 | foo | AST only |
| realistic.cpp:53:9:53:18 | access to array | AST only |
| realistic.cpp:53:20:53:22 | baz | AST only |
| realistic.cpp:53:25:53:33 | userInput | AST only |
| realistic.cpp:53:35:53:43 | bufferLen | AST only |
| realistic.cpp:54:16:54:18 | foo | AST only |
| realistic.cpp:54:16:54:25 | access to array | AST only |
| realistic.cpp:54:27:54:29 | baz | AST only |
| realistic.cpp:54:32:54:40 | userInput | AST only |
| realistic.cpp:54:42:54:47 | buffer | AST only |
| realistic.cpp:60:16:60:18 | dst | AST only |
| realistic.cpp:61:21:61:23 | foo | AST only |
| realistic.cpp:61:21:61:30 | access to array | AST only |
| realistic.cpp:61:32:61:34 | baz | AST only |
| realistic.cpp:61:37:61:45 | userInput | AST only |
| realistic.cpp:61:47:61:55 | bufferLen | AST only |
| realistic.cpp:65:21:65:23 | foo | AST only |
| realistic.cpp:65:21:65:30 | access to array | AST only |
| realistic.cpp:65:32:65:34 | baz | AST only |
| realistic.cpp:65:37:65:45 | userInput | AST only |
| realistic.cpp:65:47:65:52 | buffer | AST only |
| realistic.cpp:66:21:66:23 | dst | AST only |
| simple.cpp:20:24:20:25 | a_ | AST only |
| simple.cpp:21:24:21:25 | b_ | AST only |
| simple.cpp:28:10:28:10 | f | AST only |
@@ -320,6 +386,7 @@
| simple.cpp:83:9:83:10 | this | AST only |
| simple.cpp:83:12:83:13 | f1 | AST only |
| simple.cpp:84:14:84:20 | this | AST only |
| simple.cpp:92:7:92:7 | i | AST only |
| struct_init.c:15:8:15:9 | ab | AST only |
| struct_init.c:15:12:15:12 | a | AST only |
| struct_init.c:16:8:16:9 | ab | AST only |

View File

@@ -26,6 +26,8 @@
| aliasing.cpp:79:3:79:3 | s |
| aliasing.cpp:86:3:86:3 | s |
| aliasing.cpp:92:5:92:5 | s |
| aliasing.cpp:98:3:98:3 | s |
| arrays.cpp:36:3:36:17 | access to array |
| by_reference.cpp:12:5:12:5 | s |
| by_reference.cpp:16:5:16:8 | this |
| by_reference.cpp:84:3:84:7 | inner |
@@ -37,7 +39,9 @@
| qualifiers.cpp:9:30:9:33 | this |
| qualifiers.cpp:12:49:12:53 | inner |
| qualifiers.cpp:13:51:13:55 | inner |
| realistic.cpp:49:9:49:18 | access to array |
| simple.cpp:20:24:20:25 | this |
| simple.cpp:21:24:21:25 | this |
| simple.cpp:65:5:65:5 | a |
| simple.cpp:83:9:83:10 | f2 |
| simple.cpp:92:5:92:5 | a |

View File

@@ -185,6 +185,46 @@
| aliasing.cpp:92:3:92:3 | w |
| aliasing.cpp:92:5:92:5 | s |
| aliasing.cpp:92:7:92:8 | m1 |
| aliasing.cpp:98:3:98:3 | s |
| aliasing.cpp:98:5:98:6 | m1 |
| arrays.cpp:6:3:6:8 | access to array |
| arrays.cpp:15:3:15:10 | * ... |
| arrays.cpp:36:3:36:3 | o |
| arrays.cpp:36:3:36:17 | access to array |
| arrays.cpp:36:5:36:10 | nested |
| arrays.cpp:36:19:36:22 | data |
| arrays.cpp:37:8:37:8 | o |
| arrays.cpp:37:8:37:22 | access to array |
| arrays.cpp:37:10:37:15 | nested |
| arrays.cpp:37:24:37:27 | data |
| arrays.cpp:38:8:38:8 | o |
| arrays.cpp:38:8:38:22 | access to array |
| arrays.cpp:38:10:38:15 | nested |
| arrays.cpp:38:24:38:27 | data |
| arrays.cpp:42:3:42:3 | o |
| arrays.cpp:42:3:42:20 | access to array |
| arrays.cpp:42:5:42:12 | indirect |
| arrays.cpp:42:22:42:25 | data |
| arrays.cpp:43:8:43:8 | o |
| arrays.cpp:43:8:43:25 | access to array |
| arrays.cpp:43:10:43:17 | indirect |
| arrays.cpp:43:27:43:30 | data |
| arrays.cpp:44:8:44:8 | o |
| arrays.cpp:44:8:44:25 | access to array |
| arrays.cpp:44:10:44:17 | indirect |
| arrays.cpp:44:27:44:30 | data |
| arrays.cpp:48:3:48:3 | o |
| arrays.cpp:48:3:48:20 | access to array |
| arrays.cpp:48:5:48:12 | indirect |
| arrays.cpp:48:22:48:25 | data |
| arrays.cpp:49:8:49:8 | o |
| arrays.cpp:49:8:49:25 | access to array |
| arrays.cpp:49:10:49:17 | indirect |
| arrays.cpp:49:27:49:30 | data |
| arrays.cpp:50:8:50:8 | o |
| arrays.cpp:50:8:50:25 | access to array |
| arrays.cpp:50:10:50:17 | indirect |
| arrays.cpp:50:27:50:30 | data |
| by_reference.cpp:12:5:12:5 | s |
| by_reference.cpp:12:8:12:8 | a |
| by_reference.cpp:16:5:16:8 | this |
@@ -209,6 +249,8 @@
| by_reference.cpp:84:10:84:10 | a |
| by_reference.cpp:88:3:88:7 | inner |
| by_reference.cpp:88:9:88:9 | a |
| by_reference.cpp:92:3:92:5 | * ... |
| by_reference.cpp:96:3:96:4 | pa |
| by_reference.cpp:102:21:102:39 | & ... |
| by_reference.cpp:102:22:102:26 | outer |
| by_reference.cpp:103:21:103:25 | outer |
@@ -343,6 +385,33 @@
| qualifiers.cpp:48:10:48:14 | outer |
| qualifiers.cpp:48:16:48:20 | inner |
| qualifiers.cpp:48:23:48:23 | a |
| realistic.cpp:26:5:26:10 | offset |
| realistic.cpp:42:20:42:20 | o |
| realistic.cpp:49:9:49:11 | foo |
| realistic.cpp:49:9:49:18 | access to array |
| realistic.cpp:49:20:49:22 | baz |
| realistic.cpp:53:9:53:11 | foo |
| realistic.cpp:53:9:53:18 | access to array |
| realistic.cpp:53:20:53:22 | baz |
| realistic.cpp:53:25:53:33 | userInput |
| realistic.cpp:53:35:53:43 | bufferLen |
| realistic.cpp:54:16:54:18 | foo |
| realistic.cpp:54:16:54:25 | access to array |
| realistic.cpp:54:27:54:29 | baz |
| realistic.cpp:54:32:54:40 | userInput |
| realistic.cpp:54:42:54:47 | buffer |
| realistic.cpp:60:16:60:18 | dst |
| realistic.cpp:61:21:61:23 | foo |
| realistic.cpp:61:21:61:30 | access to array |
| realistic.cpp:61:32:61:34 | baz |
| realistic.cpp:61:37:61:45 | userInput |
| realistic.cpp:61:47:61:55 | bufferLen |
| realistic.cpp:65:21:65:23 | foo |
| realistic.cpp:65:21:65:30 | access to array |
| realistic.cpp:65:32:65:34 | baz |
| realistic.cpp:65:37:65:45 | userInput |
| realistic.cpp:65:47:65:52 | buffer |
| realistic.cpp:66:21:66:23 | dst |
| simple.cpp:20:24:20:25 | a_ |
| simple.cpp:20:24:20:25 | this |
| simple.cpp:21:24:21:25 | b_ |
@@ -363,6 +432,8 @@
| simple.cpp:83:9:83:10 | this |
| simple.cpp:83:12:83:13 | f1 |
| simple.cpp:84:14:84:20 | this |
| simple.cpp:92:5:92:5 | a |
| simple.cpp:92:7:92:7 | i |
| struct_init.c:15:8:15:9 | ab |
| struct_init.c:15:12:15:12 | a |
| struct_init.c:16:8:16:9 | ab |

View File

@@ -155,6 +155,42 @@ edges
| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:92:3:92:23 | ... = ... |
| aliasing.cpp:93:8:93:8 | w [s, m1] | aliasing.cpp:93:10:93:10 | s [m1] |
| aliasing.cpp:93:10:93:10 | s [m1] | aliasing.cpp:93:12:93:13 | m1 |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:8:8:8:13 | access to array |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... |
| arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:16:8:16:13 | access to array |
| arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:17:8:17:13 | access to array |
| arrays.cpp:36:3:36:3 | o [post update] [nested, arr, ... (3)] | arrays.cpp:37:8:37:8 | o [nested, arr, ... (3)] |
| arrays.cpp:36:3:36:3 | o [post update] [nested, arr, ... (3)] | arrays.cpp:38:8:38:8 | o [nested, arr, ... (3)] |
| arrays.cpp:36:3:36:17 | access to array [post update] [data] | arrays.cpp:36:12:36:14 | arr [inner post update] [data] |
| arrays.cpp:36:3:36:37 | ... = ... | arrays.cpp:36:3:36:17 | access to array [post update] [data] |
| arrays.cpp:36:5:36:10 | nested [post update] [arr, data] | arrays.cpp:36:3:36:3 | o [post update] [nested, arr, ... (3)] |
| arrays.cpp:36:12:36:14 | arr [inner post update] [data] | arrays.cpp:36:5:36:10 | nested [post update] [arr, data] |
| arrays.cpp:36:26:36:35 | call to user_input | arrays.cpp:36:3:36:37 | ... = ... |
| arrays.cpp:37:8:37:8 | o [nested, arr, ... (3)] | arrays.cpp:37:10:37:15 | nested [arr, data] |
| arrays.cpp:37:8:37:22 | access to array [data] | arrays.cpp:37:24:37:27 | data |
| arrays.cpp:37:10:37:15 | nested [arr, data] | arrays.cpp:37:17:37:19 | arr [data] |
| arrays.cpp:37:17:37:19 | arr [data] | arrays.cpp:37:8:37:22 | access to array [data] |
| arrays.cpp:38:8:38:8 | o [nested, arr, ... (3)] | arrays.cpp:38:10:38:15 | nested [arr, data] |
| arrays.cpp:38:8:38:22 | access to array [data] | arrays.cpp:38:24:38:27 | data |
| arrays.cpp:38:10:38:15 | nested [arr, data] | arrays.cpp:38:17:38:19 | arr [data] |
| arrays.cpp:38:17:38:19 | arr [data] | arrays.cpp:38:8:38:22 | access to array [data] |
| arrays.cpp:42:3:42:3 | o [post update] [indirect, arr, ... (3)] | arrays.cpp:43:8:43:8 | o [indirect, arr, ... (3)] |
| arrays.cpp:42:3:42:3 | o [post update] [indirect, arr, ... (3)] | arrays.cpp:44:8:44:8 | o [indirect, arr, ... (3)] |
| arrays.cpp:42:3:42:20 | access to array [post update] [data] | arrays.cpp:42:15:42:17 | arr [inner post update] [data] |
| arrays.cpp:42:3:42:40 | ... = ... | arrays.cpp:42:3:42:20 | access to array [post update] [data] |
| arrays.cpp:42:5:42:12 | indirect [post update] [arr, data] | arrays.cpp:42:3:42:3 | o [post update] [indirect, arr, ... (3)] |
| arrays.cpp:42:15:42:17 | arr [inner post update] [data] | arrays.cpp:42:5:42:12 | indirect [post update] [arr, data] |
| arrays.cpp:42:29:42:38 | call to user_input | arrays.cpp:42:3:42:40 | ... = ... |
| arrays.cpp:43:8:43:8 | o [indirect, arr, ... (3)] | arrays.cpp:43:10:43:17 | indirect [arr, data] |
| arrays.cpp:43:8:43:25 | access to array [data] | arrays.cpp:43:27:43:30 | data |
| arrays.cpp:43:10:43:17 | indirect [arr, data] | arrays.cpp:43:20:43:22 | arr [data] |
| arrays.cpp:43:20:43:22 | arr [data] | arrays.cpp:43:8:43:25 | access to array [data] |
| arrays.cpp:44:8:44:8 | o [indirect, arr, ... (3)] | arrays.cpp:44:10:44:17 | indirect [arr, data] |
| arrays.cpp:44:8:44:25 | access to array [data] | arrays.cpp:44:27:44:30 | data |
| arrays.cpp:44:10:44:17 | indirect [arr, data] | arrays.cpp:44:20:44:22 | arr [data] |
| arrays.cpp:44:20:44:22 | arr [data] | arrays.cpp:44:8:44:25 | access to array [data] |
| by_reference.cpp:50:3:50:3 | ref arg s [a] | by_reference.cpp:51:8:51:8 | s [a] |
| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | ref arg s [a] |
| by_reference.cpp:51:8:51:8 | s [a] | by_reference.cpp:51:10:51:20 | call to getDirectly |
@@ -184,6 +220,9 @@ edges
| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:127:21:127:38 | ref arg * ... [a] |
| by_reference.cpp:88:3:88:24 | ... = ... | by_reference.cpp:88:3:88:7 | inner [post update] [a] |
| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | ... = ... |
| by_reference.cpp:92:4:92:5 | pa [inner post update] | by_reference.cpp:104:15:104:22 | ref arg & ... |
| by_reference.cpp:92:4:92:5 | pa [inner post update] | by_reference.cpp:108:15:108:24 | ref arg & ... |
| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:92:4:92:5 | pa [inner post update] |
| by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:124:21:124:21 | ref arg a |
| by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:128:23:128:23 | ref arg a |
| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:95:25:95:26 | pa |
@@ -192,19 +231,27 @@ edges
| by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] |
| by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] |
| by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] |
| by_reference.cpp:104:15:104:22 | ref arg & ... | by_reference.cpp:104:22:104:22 | a [inner post update] |
| by_reference.cpp:104:16:104:20 | outer [post update] [a] | by_reference.cpp:112:8:112:12 | outer [a] |
| by_reference.cpp:104:22:104:22 | a [inner post update] | by_reference.cpp:104:16:104:20 | outer [post update] [a] |
| by_reference.cpp:106:21:106:41 | ref arg & ... [a] | by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] |
| by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] |
| by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] |
| by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] |
| by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] |
| by_reference.cpp:108:15:108:24 | ref arg & ... | by_reference.cpp:108:24:108:24 | a [inner post update] |
| by_reference.cpp:108:16:108:21 | pouter [post update] [a] | by_reference.cpp:116:8:116:13 | pouter [a] |
| by_reference.cpp:108:24:108:24 | a [inner post update] | by_reference.cpp:108:16:108:21 | pouter [post update] [a] |
| by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | by_reference.cpp:110:14:110:25 | inner_nested [a] |
| by_reference.cpp:110:14:110:25 | inner_nested [a] | by_reference.cpp:110:27:110:27 | a |
| by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | by_reference.cpp:111:14:111:22 | inner_ptr [a] |
| by_reference.cpp:111:14:111:22 | inner_ptr [a] | by_reference.cpp:111:25:111:25 | a |
| by_reference.cpp:112:8:112:12 | outer [a] | by_reference.cpp:112:14:112:14 | a |
| by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | by_reference.cpp:114:16:114:27 | inner_nested [a] |
| by_reference.cpp:114:16:114:27 | inner_nested [a] | by_reference.cpp:114:29:114:29 | a |
| by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | by_reference.cpp:115:16:115:24 | inner_ptr [a] |
| by_reference.cpp:115:16:115:24 | inner_ptr [a] | by_reference.cpp:115:27:115:27 | a |
| by_reference.cpp:116:8:116:13 | pouter [a] | by_reference.cpp:116:16:116:16 | a |
| by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | by_reference.cpp:130:8:130:12 | outer [inner_nested, a] |
| by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] |
| by_reference.cpp:123:21:123:36 | ref arg * ... [a] | by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] |
@@ -307,6 +354,18 @@ edges
| qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:47:5:47:42 | ... = ... |
| qualifiers.cpp:48:10:48:14 | outer [inner, a] | qualifiers.cpp:48:16:48:20 | inner [a] |
| qualifiers.cpp:48:16:48:20 | inner [a] | qualifiers.cpp:48:23:48:23 | a |
| realistic.cpp:53:9:53:11 | foo [post update] [bar, baz, ... (4)] | realistic.cpp:61:21:61:23 | foo [bar, baz, ... (4)] |
| realistic.cpp:53:9:53:18 | access to array [post update] [baz, userInput, ... (3)] | realistic.cpp:53:13:53:15 | bar [inner post update] [baz, userInput, ... (3)] |
| realistic.cpp:53:9:53:66 | ... = ... | realistic.cpp:53:25:53:33 | userInput [post update] [bufferLen] |
| realistic.cpp:53:13:53:15 | bar [inner post update] [baz, userInput, ... (3)] | realistic.cpp:53:9:53:11 | foo [post update] [bar, baz, ... (4)] |
| realistic.cpp:53:20:53:22 | baz [post update] [userInput, bufferLen] | realistic.cpp:53:9:53:18 | access to array [post update] [baz, userInput, ... (3)] |
| realistic.cpp:53:25:53:33 | userInput [post update] [bufferLen] | realistic.cpp:53:20:53:22 | baz [post update] [userInput, bufferLen] |
| realistic.cpp:53:55:53:64 | call to user_input | realistic.cpp:53:9:53:66 | ... = ... |
| realistic.cpp:61:21:61:23 | foo [bar, baz, ... (4)] | realistic.cpp:61:25:61:27 | bar [baz, userInput, ... (3)] |
| realistic.cpp:61:21:61:30 | access to array [baz, userInput, ... (3)] | realistic.cpp:61:32:61:34 | baz [userInput, bufferLen] |
| realistic.cpp:61:25:61:27 | bar [baz, userInput, ... (3)] | realistic.cpp:61:21:61:30 | access to array [baz, userInput, ... (3)] |
| realistic.cpp:61:32:61:34 | baz [userInput, bufferLen] | realistic.cpp:61:37:61:45 | userInput [bufferLen] |
| realistic.cpp:61:37:61:45 | userInput [bufferLen] | realistic.cpp:61:47:61:55 | bufferLen |
| simple.cpp:26:15:26:15 | f [a_] | simple.cpp:28:10:28:10 | f [a_] |
| simple.cpp:26:15:26:15 | f [b_] | simple.cpp:29:10:29:10 | f [b_] |
| simple.cpp:28:10:28:10 | f [a_] | simple.cpp:28:12:28:12 | call to a |
@@ -332,6 +391,10 @@ edges
| simple.cpp:83:9:83:28 | ... = ... | simple.cpp:83:9:83:10 | f2 [post update] [f1] |
| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | ... = ... |
| simple.cpp:84:14:84:20 | this [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 |
| simple.cpp:92:5:92:5 | a [post update] [i] | simple.cpp:94:10:94:11 | a2 [i] |
| simple.cpp:92:5:92:22 | ... = ... | simple.cpp:92:5:92:5 | a [post update] [i] |
| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | ... = ... |
| simple.cpp:94:10:94:11 | a2 [i] | simple.cpp:94:13:94:13 | i |
| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] |
| struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a |
| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] |
@@ -539,6 +602,46 @@ nodes
| aliasing.cpp:93:8:93:8 | w [s, m1] | semmle.label | w [s, m1] |
| aliasing.cpp:93:10:93:10 | s [m1] | semmle.label | s [m1] |
| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 |
| arrays.cpp:6:12:6:21 | call to user_input | semmle.label | call to user_input |
| arrays.cpp:7:8:7:13 | access to array | semmle.label | access to array |
| arrays.cpp:8:8:8:13 | access to array | semmle.label | access to array |
| arrays.cpp:9:8:9:11 | * ... | semmle.label | * ... |
| arrays.cpp:10:8:10:15 | * ... | semmle.label | * ... |
| arrays.cpp:15:14:15:23 | call to user_input | semmle.label | call to user_input |
| arrays.cpp:16:8:16:13 | access to array | semmle.label | access to array |
| arrays.cpp:17:8:17:13 | access to array | semmle.label | access to array |
| arrays.cpp:36:3:36:3 | o [post update] [nested, arr, ... (3)] | semmle.label | o [post update] [nested, arr, ... (3)] |
| arrays.cpp:36:3:36:17 | access to array [post update] [data] | semmle.label | access to array [post update] [data] |
| arrays.cpp:36:3:36:37 | ... = ... | semmle.label | ... = ... |
| arrays.cpp:36:5:36:10 | nested [post update] [arr, data] | semmle.label | nested [post update] [arr, data] |
| arrays.cpp:36:12:36:14 | arr [inner post update] [data] | semmle.label | arr [inner post update] [data] |
| arrays.cpp:36:26:36:35 | call to user_input | semmle.label | call to user_input |
| arrays.cpp:37:8:37:8 | o [nested, arr, ... (3)] | semmle.label | o [nested, arr, ... (3)] |
| arrays.cpp:37:8:37:22 | access to array [data] | semmle.label | access to array [data] |
| arrays.cpp:37:10:37:15 | nested [arr, data] | semmle.label | nested [arr, data] |
| arrays.cpp:37:17:37:19 | arr [data] | semmle.label | arr [data] |
| arrays.cpp:37:24:37:27 | data | semmle.label | data |
| arrays.cpp:38:8:38:8 | o [nested, arr, ... (3)] | semmle.label | o [nested, arr, ... (3)] |
| arrays.cpp:38:8:38:22 | access to array [data] | semmle.label | access to array [data] |
| arrays.cpp:38:10:38:15 | nested [arr, data] | semmle.label | nested [arr, data] |
| arrays.cpp:38:17:38:19 | arr [data] | semmle.label | arr [data] |
| arrays.cpp:38:24:38:27 | data | semmle.label | data |
| arrays.cpp:42:3:42:3 | o [post update] [indirect, arr, ... (3)] | semmle.label | o [post update] [indirect, arr, ... (3)] |
| arrays.cpp:42:3:42:20 | access to array [post update] [data] | semmle.label | access to array [post update] [data] |
| arrays.cpp:42:3:42:40 | ... = ... | semmle.label | ... = ... |
| arrays.cpp:42:5:42:12 | indirect [post update] [arr, data] | semmle.label | indirect [post update] [arr, data] |
| arrays.cpp:42:15:42:17 | arr [inner post update] [data] | semmle.label | arr [inner post update] [data] |
| arrays.cpp:42:29:42:38 | call to user_input | semmle.label | call to user_input |
| arrays.cpp:43:8:43:8 | o [indirect, arr, ... (3)] | semmle.label | o [indirect, arr, ... (3)] |
| arrays.cpp:43:8:43:25 | access to array [data] | semmle.label | access to array [data] |
| arrays.cpp:43:10:43:17 | indirect [arr, data] | semmle.label | indirect [arr, data] |
| arrays.cpp:43:20:43:22 | arr [data] | semmle.label | arr [data] |
| arrays.cpp:43:27:43:30 | data | semmle.label | data |
| arrays.cpp:44:8:44:8 | o [indirect, arr, ... (3)] | semmle.label | o [indirect, arr, ... (3)] |
| arrays.cpp:44:8:44:25 | access to array [data] | semmle.label | access to array [data] |
| arrays.cpp:44:10:44:17 | indirect [arr, data] | semmle.label | indirect [arr, data] |
| arrays.cpp:44:20:44:22 | arr [data] | semmle.label | arr [data] |
| arrays.cpp:44:27:44:30 | data | semmle.label | data |
| by_reference.cpp:50:3:50:3 | ref arg s [a] | semmle.label | ref arg s [a] |
| by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:51:8:51:8 | s [a] | semmle.label | s [a] |
@@ -562,6 +665,8 @@ nodes
| by_reference.cpp:88:3:88:7 | inner [post update] [a] | semmle.label | inner [post update] [a] |
| by_reference.cpp:88:3:88:24 | ... = ... | semmle.label | ... = ... |
| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:92:4:92:5 | pa [inner post update] | semmle.label | pa [inner post update] |
| by_reference.cpp:92:9:92:18 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:95:25:95:26 | pa | semmle.label | pa |
| by_reference.cpp:96:8:96:17 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:102:21:102:39 | ref arg & ... [a] | semmle.label | ref arg & ... [a] |
@@ -569,23 +674,33 @@ nodes
| by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | semmle.label | inner_nested [inner post update] [a] |
| by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | semmle.label | outer [post update] [inner_ptr, a] |
| by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] |
| by_reference.cpp:104:15:104:22 | ref arg & ... | semmle.label | ref arg & ... |
| by_reference.cpp:104:16:104:20 | outer [post update] [a] | semmle.label | outer [post update] [a] |
| by_reference.cpp:104:22:104:22 | a [inner post update] | semmle.label | a [inner post update] |
| by_reference.cpp:106:21:106:41 | ref arg & ... [a] | semmle.label | ref arg & ... [a] |
| by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | semmle.label | pouter [post update] [inner_nested, a] |
| by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | semmle.label | inner_nested [inner post update] [a] |
| by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | semmle.label | pouter [post update] [inner_ptr, a] |
| by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] |
| by_reference.cpp:108:15:108:24 | ref arg & ... | semmle.label | ref arg & ... |
| by_reference.cpp:108:16:108:21 | pouter [post update] [a] | semmle.label | pouter [post update] [a] |
| by_reference.cpp:108:24:108:24 | a [inner post update] | semmle.label | a [inner post update] |
| by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | semmle.label | outer [inner_nested, a] |
| by_reference.cpp:110:14:110:25 | inner_nested [a] | semmle.label | inner_nested [a] |
| by_reference.cpp:110:27:110:27 | a | semmle.label | a |
| by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | semmle.label | outer [inner_ptr, a] |
| by_reference.cpp:111:14:111:22 | inner_ptr [a] | semmle.label | inner_ptr [a] |
| by_reference.cpp:111:25:111:25 | a | semmle.label | a |
| by_reference.cpp:112:8:112:12 | outer [a] | semmle.label | outer [a] |
| by_reference.cpp:112:14:112:14 | a | semmle.label | a |
| by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | semmle.label | pouter [inner_nested, a] |
| by_reference.cpp:114:16:114:27 | inner_nested [a] | semmle.label | inner_nested [a] |
| by_reference.cpp:114:29:114:29 | a | semmle.label | a |
| by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | semmle.label | pouter [inner_ptr, a] |
| by_reference.cpp:115:16:115:24 | inner_ptr [a] | semmle.label | inner_ptr [a] |
| by_reference.cpp:115:27:115:27 | a | semmle.label | a |
| by_reference.cpp:116:8:116:13 | pouter [a] | semmle.label | pouter [a] |
| by_reference.cpp:116:16:116:16 | a | semmle.label | a |
| by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | semmle.label | outer [post update] [inner_nested, a] |
| by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] |
| by_reference.cpp:123:21:123:36 | ref arg * ... [a] | semmle.label | ref arg * ... [a] |
@@ -703,6 +818,19 @@ nodes
| qualifiers.cpp:48:10:48:14 | outer [inner, a] | semmle.label | outer [inner, a] |
| qualifiers.cpp:48:16:48:20 | inner [a] | semmle.label | inner [a] |
| qualifiers.cpp:48:23:48:23 | a | semmle.label | a |
| realistic.cpp:53:9:53:11 | foo [post update] [bar, baz, ... (4)] | semmle.label | foo [post update] [bar, baz, ... (4)] |
| realistic.cpp:53:9:53:18 | access to array [post update] [baz, userInput, ... (3)] | semmle.label | access to array [post update] [baz, userInput, ... (3)] |
| realistic.cpp:53:9:53:66 | ... = ... | semmle.label | ... = ... |
| realistic.cpp:53:13:53:15 | bar [inner post update] [baz, userInput, ... (3)] | semmle.label | bar [inner post update] [baz, userInput, ... (3)] |
| realistic.cpp:53:20:53:22 | baz [post update] [userInput, bufferLen] | semmle.label | baz [post update] [userInput, bufferLen] |
| realistic.cpp:53:25:53:33 | userInput [post update] [bufferLen] | semmle.label | userInput [post update] [bufferLen] |
| realistic.cpp:53:55:53:64 | call to user_input | semmle.label | call to user_input |
| realistic.cpp:61:21:61:23 | foo [bar, baz, ... (4)] | semmle.label | foo [bar, baz, ... (4)] |
| realistic.cpp:61:21:61:30 | access to array [baz, userInput, ... (3)] | semmle.label | access to array [baz, userInput, ... (3)] |
| realistic.cpp:61:25:61:27 | bar [baz, userInput, ... (3)] | semmle.label | bar [baz, userInput, ... (3)] |
| realistic.cpp:61:32:61:34 | baz [userInput, bufferLen] | semmle.label | baz [userInput, bufferLen] |
| realistic.cpp:61:37:61:45 | userInput [bufferLen] | semmle.label | userInput [bufferLen] |
| realistic.cpp:61:47:61:55 | bufferLen | semmle.label | bufferLen |
| simple.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] |
| simple.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] |
| simple.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] |
@@ -732,6 +860,11 @@ nodes
| simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input |
| simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 |
| simple.cpp:84:14:84:20 | this [f2, f1] | semmle.label | this [f2, f1] |
| simple.cpp:92:5:92:5 | a [post update] [i] | semmle.label | a [post update] [i] |
| simple.cpp:92:5:92:22 | ... = ... | semmle.label | ... = ... |
| simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input |
| simple.cpp:94:10:94:11 | a2 [i] | semmle.label | a2 [i] |
| simple.cpp:94:13:94:13 | i | semmle.label | i |
| struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] |
| struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] |
| struct_init.c:15:12:15:12 | a | semmle.label | a |
@@ -792,14 +925,26 @@ nodes
| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input |
| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input |
| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input |
| arrays.cpp:7:8:7:13 | access to array | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array | access to array flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input |
| arrays.cpp:8:8:8:13 | access to array | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:8:8:8:13 | access to array | access to array flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input |
| arrays.cpp:9:8:9:11 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input |
| arrays.cpp:10:8:10:15 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input |
| arrays.cpp:16:8:16:13 | access to array | arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:16:8:16:13 | access to array | access to array flows from $@ | arrays.cpp:15:14:15:23 | call to user_input | call to user_input |
| arrays.cpp:17:8:17:13 | access to array | arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:17:8:17:13 | access to array | access to array flows from $@ | arrays.cpp:15:14:15:23 | call to user_input | call to user_input |
| arrays.cpp:37:24:37:27 | data | arrays.cpp:36:26:36:35 | call to user_input | arrays.cpp:37:24:37:27 | data | data flows from $@ | arrays.cpp:36:26:36:35 | call to user_input | call to user_input |
| arrays.cpp:38:24:38:27 | data | arrays.cpp:36:26:36:35 | call to user_input | arrays.cpp:38:24:38:27 | data | data flows from $@ | arrays.cpp:36:26:36:35 | call to user_input | call to user_input |
| arrays.cpp:43:27:43:30 | data | arrays.cpp:42:29:42:38 | call to user_input | arrays.cpp:43:27:43:30 | data | data flows from $@ | arrays.cpp:42:29:42:38 | call to user_input | call to user_input |
| arrays.cpp:44:27:44:30 | data | arrays.cpp:42:29:42:38 | call to user_input | arrays.cpp:44:27:44:30 | data | data flows from $@ | arrays.cpp:42:29:42:38 | call to user_input | call to user_input |
| by_reference.cpp:51:10:51:20 | call to getDirectly | by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:51:10:51:20 | call to getDirectly | call to getDirectly flows from $@ | by_reference.cpp:50:17:50:26 | call to user_input | call to user_input |
| by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input |
| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input |
| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | call to nonMemberGetA flows from $@ | by_reference.cpp:68:21:68:30 | call to user_input | call to user_input |
| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:110:27:110:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input |
| by_reference.cpp:111:25:111:25 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:111:25:111:25 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input |
| by_reference.cpp:112:14:112:14 | a | by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:112:14:112:14 | a | a flows from $@ | by_reference.cpp:92:9:92:18 | call to user_input | call to user_input |
| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:114:29:114:29 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input |
| by_reference.cpp:115:27:115:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:115:27:115:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input |
| by_reference.cpp:116:16:116:16 | a | by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:116:16:116:16 | a | a flows from $@ | by_reference.cpp:92:9:92:18 | call to user_input | call to user_input |
| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input |
| by_reference.cpp:131:25:131:25 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:131:25:131:25 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input |
| by_reference.cpp:132:14:132:14 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input |
@@ -824,12 +969,14 @@ nodes
| qualifiers.cpp:38:23:38:23 | a | qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:38:23:38:23 | a | a flows from $@ | qualifiers.cpp:37:38:37:47 | call to user_input | call to user_input |
| qualifiers.cpp:43:23:43:23 | a | qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:43:23:43:23 | a | a flows from $@ | qualifiers.cpp:42:29:42:38 | call to user_input | call to user_input |
| qualifiers.cpp:48:23:48:23 | a | qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:48:23:48:23 | a | a flows from $@ | qualifiers.cpp:47:31:47:40 | call to user_input | call to user_input |
| realistic.cpp:61:47:61:55 | bufferLen | realistic.cpp:53:55:53:64 | call to user_input | realistic.cpp:61:47:61:55 | bufferLen | bufferLen flows from $@ | realistic.cpp:53:55:53:64 | call to user_input | call to user_input |
| simple.cpp:28:12:28:12 | call to a | simple.cpp:39:12:39:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:39:12:39:21 | call to user_input | call to user_input |
| simple.cpp:28:12:28:12 | call to a | simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:41:12:41:21 | call to user_input | call to user_input |
| simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input |
| simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input |
| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input |
| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input |
| simple.cpp:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input |
| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input |
| struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input |

View File

@@ -0,0 +1,70 @@
typedef unsigned char u8;
typedef unsigned long size_t;
struct UserInput {
size_t bufferLen;
u8 buffer[256];
};
struct Baz {
int foo;
struct UserInput userInput;
};
struct Bar {
u8* foo;
struct Baz * baz;
};
struct Foo {
struct Bar bar[128];
};
void printf(const char *fmt, ...) {
return;
}
void * malloc(size_t size) {
static unsigned char buffer[0x1000];
static unsigned int offset;
if (size + offset >= sizeof(buffer)) return nullptr;
void* m = (void*)&buffer[offset];
offset += size;
return m;
}
void * memcpy ( void * destination, const void * source, size_t num ) {
u8* d = (u8*)destination;
u8* s = (u8*)source;
u8* e = d + num;
while(d != e) {
*d++ = *s++;
}
return destination;
}
void *user_input(void) {
return (void*)"\x0a\x00\x00\x00\x00\x00\x00\x00The quick brown fox jumps over the lazy dog";
}
void sink(void *o) {
printf("%p\n", o);
}
#define MAX_BAZ 3
int main(int argc, char** argv) {
char dst[256];
struct Foo foo;
for (int i = 0; i < MAX_BAZ; i++) {
foo.bar[i].baz = (struct Baz*)malloc(sizeof(struct Baz));
}
int i = 0;
while(i < MAX_BAZ) {
foo.bar[i].baz->userInput.bufferLen = (size_t)user_input();
memcpy(foo.bar[i].baz->userInput.buffer, user_input(), sizeof(foo.bar[i].baz->userInput.buffer));
if(foo.bar[i].baz->userInput.bufferLen > sizeof(foo.bar[i].baz->userInput.buffer))
{
printf("The user-supplied input 0x%lx is larger than the buffer 0x%lx!\n", foo.bar[i].baz->userInput.bufferLen, sizeof(foo.bar[i].baz->userInput.buffer));
return -1;
}
memcpy(dst, foo.bar[i].baz->userInput.buffer, foo.bar[i].baz->userInput.bufferLen);
sink((void*)foo.bar[i].baz->userInput.bufferLen); // $ast $f-:ir
// There is no flow to the following two `sink` calls because the
// source is the _pointer_ returned by `user_input` rather than the
// _data_ to which it points.
sink((void*)foo.bar[i].baz->userInput.buffer); // $f-:ast,ir
sink((void*)dst); // $f-:ast,ir
i++;
}
return 0;
}

View File

@@ -85,4 +85,13 @@ struct C2
}
};
typedef A A_typedef;
void single_field_test_typedef(A_typedef a)
{
a.i = user_input();
A_typedef a2 = a;
sink(a2.i); //$ast,ir
}
} // namespace Simple

View File

@@ -14,7 +14,7 @@ void test_pointer_deref_assignment()
*p_x = source();
sink(x); // tainted [DETECTED BY IR ONLY]
sink(*p_x); // tainted [DETECTED BY IR ONLY]
sink(*p_x); // tainted
sink(*p2_x); // tainted [DETECTED BY IR ONLY]
sink(r_x); // tainted [DETECTED BY IR ONLY]
}
@@ -137,11 +137,11 @@ void test_array_reference_assignment()
ptr2 = &(arr2[5]);
*ptr2 = source();
sink(*ptr2); // tainted [DETECTED BY IR ONLY]
sink(*ptr2); // tainted
sink(arr2[5]); // tainted [DETECTED BY IR ONLY]
ptr3 = arr3;
ptr3[5] = source();
sink(ptr3[5]); // tainted [DETECTED BY IR ONLY]
sink(ptr3[5]); // tainted
sink(arr3[5]); // tainted [DETECTED BY IR ONLY]
}

View File

@@ -0,0 +1,68 @@
#include "stl.h"
int source();
void sink(int);
void sink(int*);
template<typename T> void sink(std::shared_ptr<T>&);
template<typename T> void sink(std::unique_ptr<T>&);
void test_make_shared() {
std::shared_ptr<int> p = std::make_shared<int>(source());
sink(*p); // tainted
sink(p); // tainted
}
void test_make_shared_array() {
std::shared_ptr<int[]> p = std::make_shared<int[]>(source());
sink(*p); // not tainted
sink(p); // not tainted
}
void test_make_unique() {
std::unique_ptr<int> p = std::make_unique<int>(source());
sink(*p); // tainted
sink(p); // tainted
}
void test_make_unique_array() {
std::unique_ptr<int[]> p = std::make_unique<int[]>(source());
sink(*p); // not tainted
sink(p); // not tainted
}
void test_reverse_taint_shared() {
std::shared_ptr<int> p = std::make_shared<int>();
*p = source();
sink(p); // tainted [NOT DETECTED]
sink(*p); // tainted [NOT DETECTED]
}
void test_reverse_taint_unique() {
std::unique_ptr<int> p = std::unique_ptr<int>();
*p = source();
sink(p); // tainted [NOT DETECTED]
sink(*p); // tainted [NOT DETECTED]
}
void test_shared_get() {
std::shared_ptr<int> p = std::make_shared<int>(source());
sink(p.get()); // tainted
}
void test_unique_get() {
std::unique_ptr<int> p = std::make_unique<int>(source());
sink(p.get()); // tainted
}
struct A {
int x, y;
};
void test_shared_field_member() {
std::unique_ptr<A> p = std::make_unique<A>(source(), 0);
sink(p->x); // tainted [NOT DETECTED]
sink(p->y); // not tainted
}

View File

@@ -132,16 +132,33 @@ namespace std
template <class charT, class traits = char_traits<charT> >
class basic_istream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
public:
basic_istream<charT,traits>& operator>>(int& n);
using char_type = charT;
using int_type = int; //typename traits::int_type;
basic_istream<charT, traits>& operator>>(int& n);
int_type get();
basic_istream<charT, traits>& get(char_type& c);
basic_istream<charT, traits>& get(char_type* s, streamsize n);
int_type peek();
basic_istream<charT, traits>& read (char_type* s, streamsize n);
streamsize readsome(char_type* s, streamsize n);
basic_istream<charT, traits>& putback(char_type c);
};
template<class charT, class traits> basic_istream<charT, traits>& operator>>(basic_istream<charT, traits>&, charT*);
template<class charT, class traits, class Allocator> basic_istream<charT, traits>& operator>>(basic_istream<charT, traits>& is, basic_string<charT, traits, Allocator>& str);
template <class charT, class traits = char_traits<charT> >
class basic_ostream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
public:
typedef charT char_type;
basic_ostream<charT,traits>& write(const char_type* s, streamsize n);
basic_ostream<charT, traits>& operator<<(int n);
basic_ostream<charT, traits>& put(char_type c);
basic_ostream<charT, traits>& write(const char_type* s, streamsize n);
};
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
@@ -156,8 +173,16 @@ namespace std
class basic_stringstream : public basic_iostream<charT, traits> {
public:
explicit basic_stringstream(/*ios_base::openmode which = ios_base::out|ios_base::in - not needed for this test*/);
explicit basic_stringstream( const basic_string<charT, traits, Allocator>& str/*, ios_base::openmode which = ios_base::out | ios_base::in*/);
basic_stringstream(const basic_stringstream& rhs) = delete;
basic_stringstream(basic_stringstream&& rhs);
basic_stringstream& operator=(const basic_stringstream& rhs) = delete;
basic_stringstream& operator=(basic_stringstream&& rhs);
void swap(basic_stringstream& rhs);
basic_string<charT, traits, Allocator> str() const;
void str(const basic_string<charT, traits, Allocator>& str);
};
using stringstream = basic_stringstream<char>;
@@ -224,3 +249,43 @@ namespace std {
void clear() noexcept;
};
}
// --- make_shared / make_unique ---
namespace std {
template<typename T>
class shared_ptr {
public:
shared_ptr() noexcept;
explicit shared_ptr(T*);
template<class U> shared_ptr(const shared_ptr<U>&) noexcept;
template<class U> shared_ptr(shared_ptr<U>&&) noexcept;
shared_ptr<T>& operator=(const shared_ptr<T>&) noexcept;
shared_ptr<T>& operator=(shared_ptr<T>&&) noexcept;
T& operator*() const noexcept;
T* operator->() const noexcept;
T* get() const noexcept;
};
template<typename T>
class unique_ptr {
public:
constexpr unique_ptr() noexcept;
explicit unique_ptr(T*) noexcept;
unique_ptr(unique_ptr<T>&&) noexcept;
unique_ptr<T>& operator=(unique_ptr<T>&&) noexcept;
T& operator*() const;
T* operator->() const noexcept;
T* get() const noexcept;
};
template<typename T, class... Args> unique_ptr<T> make_unique(Args&&...);
template<typename T, class... Args> shared_ptr<T> make_shared(Args&&...);
}

View File

@@ -5,41 +5,194 @@ using namespace std;
char *source();
void sink(const std::string &s) {};
void sink(const std::stringstream &s) {};
void test_stringstream()
namespace ns_char
{
std::stringstream ss1, ss2, ss3, ss4, ss5;
char source();
}
void sink(int i) {};
void sink(const std::string &s) {};
template<class charT>
void sink(const std::basic_ostream<charT> &s) {};
template<class charT>
void sink(const std::basic_istream<charT> &s) {};
template<class charT>
void sink(const std::basic_iostream<charT> &s) {};
void test_stringstream_string(int amount)
{
std::stringstream ss1, ss2, ss3, ss4, ss5, ss6, ss7, ss8, ss9, ss10, ss11, ss12, ss13;
std::string t(source());
ss1 << "1234";
ss2 << source();
ss3 << "123" << source();
ss4 << source() << "456";
ss5 << t;
sink(ss1 << "1234");
sink(ss2 << source()); // tainted
sink(ss3 << "123" << source()); // tainted
sink(ss4 << source() << "456"); // tainted
sink(ss5 << t); // tainted
sink(ss1);
sink(ss2); // tainted [NOT DETECTED]
sink(ss3); // tainted [NOT DETECTED]
sink(ss4); // tainted [NOT DETECTED]
sink(ss5); // tainted [NOT DETECTED]
sink(ss2); // tainted
sink(ss3); // tainted
sink(ss4); // tainted
sink(ss5); // tainted
sink(ss1.str());
sink(ss2.str()); // tainted [NOT DETECTED]
sink(ss3.str()); // tainted [NOT DETECTED]
sink(ss4.str()); // tainted [NOT DETECTED]
sink(ss5.str()); // tainted [NOT DETECTED]
sink(ss2.str()); // tainted
sink(ss3.str()); // tainted
sink(ss4.str()); // tainted
sink(ss5.str()); // tainted
ss6.str("abc");
ss6.str(source()); // (overwrites)
ss7.str(source());
ss7.str("abc"); // (overwrites)
sink(ss6); // tainted
sink(ss7); // [FALSE POSITIVE]
sink(ss8.put('a'));
sink(ss9.put(ns_char::source())); // tainted
sink(ss10.put('a').put(ns_char::source()).put('z')); // tainted
sink(ss8);
sink(ss9); // tainted
sink(ss10); // tainted
sink(ss11.write("begin", 5));
sink(ss12.write(source(), 5)); // tainted
sink(ss13.write("begin", 5).write(source(), amount).write("end", 3)); // tainted
sink(ss11);
sink(ss12); // tainted
sink(ss13); // tainted
}
void test_stringstream_int(int source)
{
std::stringstream ss1, ss2;
int v1 = 0, v2 = 0;
ss1 << 1234;
ss2 << source;
sink(ss1 << 1234);
sink(ss2 << source); // tainted
sink(ss1 >> v1);
sink(ss2 >> v2); // tainted [NOT DETECTED]
sink(ss1);
sink(ss2); // tainted [NOT DETECTED]
sink(ss2); // tainted
sink(ss1.str());
sink(ss2.str()); // tainted [NOT DETECTED]
sink(ss2.str()); // tainted
sink(v1);
sink(v2); // tainted [NOT DETECTED]
}
void test_stringstream_constructors()
{
std::string s1 = "abc";
std::string s2 = source();
std::stringstream ss1(s1);
std::stringstream ss2(s2);
std::stringstream ss3 = std::stringstream("abc");
std::stringstream ss4 = std::stringstream(source());
std::stringstream ss5;
std::stringstream ss6;
sink(ss5 = std::stringstream("abc"));
sink(ss6 = std::stringstream(source())); // tainted
sink(ss1);
sink(ss2); // tainted
sink(ss3);
sink(ss4); // tainted
sink(ss5);
sink(ss6); // tainted
}
void test_stringstream_swap()
{
std::stringstream ss1("abc");
std::stringstream ss2(source());
std::stringstream ss3("abc");
std::stringstream ss4(source());
ss1.swap(ss2);
ss4.swap(ss3);
sink(ss1); // tainted [NOT DETECTED]
sink(ss2); // [FALSE POSITIVE]
sink(ss3); // tainted [NOT DETECTED]
sink(ss4); // [FALSE POSITIVE]
}
void test_stringstream_in()
{
std::stringstream ss1, ss2;
std::string s1, s2, s3, s4;
char b1[100] = {0};
char b2[100] = {0};
char b3[100] = {0};
char b4[100] = {0};
char b5[100] = {0};
char b6[100] = {0};
char b7[100] = {0};
char b8[100] = {0};
char b9[100] = {0};
char b10[100] = {0};
char c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0, c6 = 0;
sink(ss1 << "abc");
sink(ss2 << source()); // tainted
sink(ss1 >> s1);
sink(ss2 >> s2); // tainted [NOT DETECTED]
sink(ss2 >> s3 >> s4); // tainted [NOT DETECTED]
sink(s1);
sink(s2); // tainted [NOT DETECTED]
sink(s3); // tainted [NOT DETECTED]
sink(s4); // tainted [NOT DETECTED]
sink(ss1 >> b1);
sink(ss2 >> b2);
sink(ss2 >> b3 >> b4);
sink(b1);
sink(b2); // tainted [NOT DETECTED]
sink(b3); // tainted [NOT DETECTED]
sink(b4); // tainted [NOT DETECTED]
sink(ss1.read(b5, 100));
sink(ss2.read(b6, 100)); // tainted [NOT DETECTED]
sink(ss1.readsome(b7, 100));
sink(ss2.readsome(b8, 100)); // (returns a length, not significantly tainted)
sink(ss1.get(b9, 100));
sink(ss2.get(b10, 100));
sink(b5);
sink(b6); // tainted [NOT DETECTED]
sink(b7);
sink(b8); // tainted [NOT DETECTED]
sink(b9);
sink(b10); // tainted [NOT DETECTED]
sink(c1 = ss1.get());
sink(c2 = ss2.get()); // tainted [NOT DETECTED]
sink(c3 = ss1.peek());
sink(c4 = ss2.peek()); // tainted [NOT DETECTED]
sink(ss1.get(c5));
sink(ss2.get(c6)); // tainted [NOT DETECTED]
sink(c1);
sink(c2); // tainted [NOT DETECTED]
sink(c3);
sink(c4); // tainted [NOT DETECTED]
sink(c5);
sink(c6); // tainted [NOT DETECTED]
}
void test_stringstream_putback()
{
std::stringstream ss;
sink(ss.put('a'));
sink(ss.get());
sink(ss.putback('b'));
sink(ss.get());
sink(ss.putback(ns_char::source())); // tainted [NOT DETECTED]
sink(ss.get()); // tainted [NOT DETECTED]
}

View File

@@ -107,9 +107,9 @@ void array_test(int i) {
arr3[5] = 0;
sink(arr1[5]); // tainted
sink(arr1[i]); // tainted [NOT DETECTED]
sink(arr2[5]); // tainted [NOT DETECTED]
sink(arr2[i]); // tainted [NOT DETECTED]
sink(arr1[i]); // tainted
sink(arr2[5]); // tainted
sink(arr2[i]); // tainted
sink(arr3[5]);
sink(arr3[i]);
}
@@ -127,7 +127,7 @@ void pointer_test() {
*p2 = source();
sink(*p1); // tainted
sink(*p2); // tainted [NOT DETECTED]
sink(*p2); // tainted
sink(*p3);
p3 = &t1;
@@ -258,7 +258,7 @@ void test_lambdas()
c = source();
};
e(t, u, w);
sink(w); // tainted
sink(w); // tainted [NOT DETECTED]
}
// --- taint through return value ---
@@ -348,10 +348,10 @@ void test_outparams()
myNotAssign(e, t);
sink(t); // tainted
sink(a); // tainted
sink(b); // tainted
sink(c); // tainted [NOT DETECTED]
sink(d); // tainted [NOT DETECTED]
sink(a); // tainted [NOT DETECTED by IR]
sink(b); // tainted [NOT DETECTED by IR]
sink(c); // tainted [NOT DETECTED by IR]
sink(d); // tainted [NOT DETECTED by IR]
sink(e);
}
@@ -468,7 +468,7 @@ void test_swop() {
swop(x, y);
sink(x); // clean [FALSE POSITIVE]
sink(y); // tainted
sink(y); // tainted [NOT DETECTED by IR]
}
// --- getdelim ---

View File

@@ -1,8 +1,11 @@
| arrayassignment.cpp:17:7:17:10 | * ... | arrayassignment.cpp:14:9:14:14 | call to source |
| arrayassignment.cpp:33:7:33:9 | r_x | arrayassignment.cpp:29:8:29:13 | call to source |
| arrayassignment.cpp:57:10:57:12 | call to get | arrayassignment.cpp:54:9:54:14 | call to source |
| arrayassignment.cpp:67:10:67:12 | call to get | arrayassignment.cpp:64:13:64:18 | call to source |
| arrayassignment.cpp:101:7:101:18 | access to array | arrayassignment.cpp:99:17:99:22 | call to source |
| arrayassignment.cpp:135:7:135:10 | ref1 | arrayassignment.cpp:134:9:134:14 | call to source |
| arrayassignment.cpp:140:7:140:11 | * ... | arrayassignment.cpp:139:10:139:15 | call to source |
| arrayassignment.cpp:145:7:145:13 | access to array | arrayassignment.cpp:144:12:144:17 | call to source |
| copyableclass.cpp:40:8:40:9 | s1 | copyableclass.cpp:34:22:34:27 | call to source |
| copyableclass.cpp:41:8:41:9 | s2 | copyableclass.cpp:35:24:35:29 | call to source |
| copyableclass.cpp:42:8:42:9 | s3 | copyableclass.cpp:34:22:34:27 | call to source |
@@ -37,6 +40,12 @@
| movableclass.cpp:55:8:55:9 | s2 | movableclass.cpp:52:23:52:28 | call to source |
| movableclass.cpp:64:8:64:9 | s2 | movableclass.cpp:23:55:23:60 | call to source |
| movableclass.cpp:65:11:65:11 | call to operator= | movableclass.cpp:65:13:65:18 | call to source |
| smart_pointer.cpp:12:10:12:10 | call to operator* | smart_pointer.cpp:11:52:11:57 | call to source |
| smart_pointer.cpp:13:10:13:10 | p | smart_pointer.cpp:11:52:11:57 | call to source |
| smart_pointer.cpp:24:10:24:10 | call to operator* | smart_pointer.cpp:23:52:23:57 | call to source |
| smart_pointer.cpp:25:10:25:10 | p | smart_pointer.cpp:23:52:23:57 | call to source |
| smart_pointer.cpp:52:12:52:14 | call to get | smart_pointer.cpp:51:52:51:57 | call to source |
| smart_pointer.cpp:57:12:57:14 | call to get | smart_pointer.cpp:56:52:56:57 | call to source |
| standalone_iterators.cpp:40:10:40:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 |
| standalone_iterators.cpp:41:10:41:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 |
| standalone_iterators.cpp:42:10:42:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 |
@@ -156,6 +165,38 @@
| string.cpp:555:8:555:8 | d | string.cpp:549:27:549:32 | call to source |
| string.cpp:556:8:556:8 | e | string.cpp:550:31:550:36 | call to source |
| string.cpp:557:8:557:8 | f | string.cpp:551:18:551:23 | call to source |
| stringstream.cpp:32:11:32:11 | call to operator<< | stringstream.cpp:32:14:32:19 | call to source |
| stringstream.cpp:33:20:33:20 | call to operator<< | stringstream.cpp:33:23:33:28 | call to source |
| stringstream.cpp:34:23:34:23 | call to operator<< | stringstream.cpp:34:14:34:19 | call to source |
| stringstream.cpp:35:11:35:11 | call to operator<< | stringstream.cpp:29:16:29:21 | call to source |
| stringstream.cpp:38:7:38:9 | ss2 | stringstream.cpp:32:14:32:19 | call to source |
| stringstream.cpp:39:7:39:9 | ss3 | stringstream.cpp:33:23:33:28 | call to source |
| stringstream.cpp:40:7:40:9 | ss4 | stringstream.cpp:34:14:34:19 | call to source |
| stringstream.cpp:41:7:41:9 | ss5 | stringstream.cpp:29:16:29:21 | call to source |
| stringstream.cpp:43:11:43:13 | call to str | stringstream.cpp:32:14:32:19 | call to source |
| stringstream.cpp:44:11:44:13 | call to str | stringstream.cpp:33:23:33:28 | call to source |
| stringstream.cpp:45:11:45:13 | call to str | stringstream.cpp:34:14:34:19 | call to source |
| stringstream.cpp:46:11:46:13 | call to str | stringstream.cpp:29:16:29:21 | call to source |
| stringstream.cpp:52:7:52:9 | ss6 | stringstream.cpp:49:10:49:15 | call to source |
| stringstream.cpp:53:7:53:9 | ss7 | stringstream.cpp:50:10:50:15 | call to source |
| stringstream.cpp:56:11:56:13 | call to put | stringstream.cpp:56:15:56:29 | call to source |
| stringstream.cpp:57:44:57:46 | call to put | stringstream.cpp:57:25:57:39 | call to source |
| stringstream.cpp:59:7:59:9 | ss9 | stringstream.cpp:56:15:56:29 | call to source |
| stringstream.cpp:60:7:60:10 | ss10 | stringstream.cpp:57:25:57:39 | call to source |
| stringstream.cpp:63:12:63:16 | call to write | stringstream.cpp:63:18:63:23 | call to source |
| stringstream.cpp:64:54:64:58 | call to write | stringstream.cpp:64:36:64:41 | call to source |
| stringstream.cpp:66:7:66:10 | ss12 | stringstream.cpp:63:18:63:23 | call to source |
| stringstream.cpp:67:7:67:10 | ss13 | stringstream.cpp:64:36:64:41 | call to source |
| stringstream.cpp:76:11:76:11 | call to operator<< | stringstream.cpp:70:32:70:37 | source |
| stringstream.cpp:81:7:81:9 | ss2 | stringstream.cpp:70:32:70:37 | source |
| stringstream.cpp:83:11:83:13 | call to str | stringstream.cpp:70:32:70:37 | source |
| stringstream.cpp:100:11:100:11 | call to operator= | stringstream.cpp:100:31:100:36 | call to source |
| stringstream.cpp:103:7:103:9 | ss2 | stringstream.cpp:91:19:91:24 | call to source |
| stringstream.cpp:105:7:105:9 | ss4 | stringstream.cpp:95:44:95:49 | call to source |
| stringstream.cpp:107:7:107:9 | ss6 | stringstream.cpp:100:31:100:36 | call to source |
| stringstream.cpp:121:7:121:9 | ss2 | stringstream.cpp:113:24:113:29 | call to source |
| stringstream.cpp:123:7:123:9 | ss4 | stringstream.cpp:115:24:115:29 | call to source |
| stringstream.cpp:143:11:143:11 | call to operator<< | stringstream.cpp:143:14:143:19 | call to source |
| structlikeclass.cpp:35:8:35:9 | s1 | structlikeclass.cpp:29:22:29:27 | call to source |
| structlikeclass.cpp:36:8:36:9 | s2 | structlikeclass.cpp:30:24:30:29 | call to source |
| structlikeclass.cpp:37:8:37:9 | s3 | structlikeclass.cpp:29:22:29:27 | call to source |
@@ -219,7 +260,12 @@
| taint.cpp:91:11:91:11 | d | taint.cpp:77:7:77:12 | call to source |
| taint.cpp:93:11:93:11 | b | taint.cpp:71:22:71:27 | call to source |
| taint.cpp:94:11:94:11 | c | taint.cpp:72:7:72:12 | call to source |
| taint.cpp:109:7:109:13 | access to array | taint.cpp:105:12:105:17 | call to source |
| taint.cpp:110:7:110:13 | access to array | taint.cpp:105:12:105:17 | call to source |
| taint.cpp:111:7:111:13 | access to array | taint.cpp:106:12:106:17 | call to source |
| taint.cpp:112:7:112:13 | access to array | taint.cpp:106:12:106:17 | call to source |
| taint.cpp:129:7:129:9 | * ... | taint.cpp:120:11:120:16 | call to source |
| taint.cpp:130:7:130:9 | * ... | taint.cpp:127:8:127:13 | call to source |
| taint.cpp:134:7:134:9 | * ... | taint.cpp:120:11:120:16 | call to source |
| taint.cpp:137:7:137:9 | * ... | taint.cpp:120:11:120:16 | call to source |
| taint.cpp:151:7:151:12 | call to select | taint.cpp:151:20:151:25 | call to source |
@@ -247,6 +293,8 @@
| taint.cpp:350:7:350:7 | t | taint.cpp:330:6:330:11 | call to source |
| taint.cpp:351:7:351:7 | a | taint.cpp:330:6:330:11 | call to source |
| taint.cpp:352:7:352:7 | b | taint.cpp:330:6:330:11 | call to source |
| taint.cpp:353:7:353:7 | c | taint.cpp:330:6:330:11 | call to source |
| taint.cpp:354:7:354:7 | d | taint.cpp:330:6:330:11 | call to source |
| taint.cpp:372:7:372:7 | a | taint.cpp:365:24:365:29 | source |
| taint.cpp:374:7:374:7 | c | taint.cpp:365:24:365:29 | source |
| taint.cpp:382:7:382:7 | a | taint.cpp:377:23:377:28 | source |
@@ -302,6 +350,7 @@
| vector.cpp:139:7:139:8 | v1 | vector.cpp:126:15:126:20 | call to source |
| vector.cpp:140:7:140:8 | v2 | vector.cpp:127:15:127:20 | call to source |
| vector.cpp:141:7:141:8 | v3 | vector.cpp:128:15:128:20 | call to source |
| vector.cpp:162:8:162:15 | access to array | vector.cpp:161:14:161:19 | call to source |
| vector.cpp:171:13:171:13 | call to operator[] | vector.cpp:170:14:170:19 | call to source |
| vector.cpp:180:13:180:13 | call to operator[] | vector.cpp:179:14:179:19 | call to source |
| vector.cpp:201:13:201:13 | call to operator[] | vector.cpp:200:14:200:19 | call to source |

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