Merge branch 'main' into interleave-op-instr-field-flow

This commit is contained in:
Mathias Vorreiter Pedersen
2020-11-09 09:58:19 +01:00
603 changed files with 57393 additions and 24593 deletions

View File

@@ -1,35 +0,0 @@
# Improvements to C# analysis
The following changes in version 1.26 affect C# analysis in all applications.
## New queries
| **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------|
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|------------------------------|------------------------|-----------------------------------|
| Weak encryption: Insufficient key size (`cs/insufficient-key-size`) | More results | The required key size has been increased from 1024 to 2048. |
## Removal of old queries
## Changes to code extraction
* Partial method bodies are extracted. Previously, partial method bodies were skipped completely.
* Inferring the lengths of implicitely sized arrays is fixed. Previously, multidimensional arrays were always extracted with the same length for
each dimension. With the fix, the array sizes `2` and `1` are extracted for `new int[,]{{1},{2}}`. Previously `2` and `2` were extracted.
* The extractor is now assembly-insensitive by default. This means that two entities with the same
fully-qualified name are now mapped to the same entity in the resulting database, regardless of
whether they belong to different assemblies. Assembly sensitivity can be reenabled by passing
`--assemblysensitivetrap` to the extractor.
## Changes to libraries
## Changes to autobuilder
## Changes to tooling support
* The Abstract Syntax Tree of C# files can be printed in Visual Studio Code.

View File

@@ -18,4 +18,3 @@ The following changes in version 1.26 affect Java analysis in all applications.
## Changes to libraries
* The QL class `Block`, denoting the `{ ... }` statement, is renamed to `BlockStmt`.

View File

@@ -4,6 +4,10 @@
* Angular-specific taint sources and sinks are now recognized by the security queries.
* Support for React has improved, with better handling of react hooks, react-router path parameters, lazy-loaded components, and components transformed using `react-redux` and/or `styled-components`.
* Dynamic imports are now analyzed more precisely.
* Support for the following frameworks and libraries has been improved:
- [@angular/*](https://www.npmjs.com/package/@angular/core)
- [AWS Serverless](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)
@@ -11,6 +15,8 @@
- [debounce](https://www.npmjs.com/package/debounce)
- [bluebird](https://www.npmjs.com/package/bluebird)
- [call-limit](https://www.npmjs.com/package/call-limit)
- [classnames](https://www.npmjs.com/package/classnames)
- [clsx](https://www.npmjs.com/package/clsx)
- [express](https://www.npmjs.com/package/express)
- [fast-json-stable-stringify](https://www.npmjs.com/package/fast-json-stable-stringify)
- [fast-safe-stringify](https://www.npmjs.com/package/fast-safe-stringify)
@@ -27,7 +33,13 @@
- [needle](https://www.npmjs.com/package/needle)
- [object-inspect](https://www.npmjs.com/package/object-inspect)
- [pretty-format](https://www.npmjs.com/package/pretty-format)
- [react](https://www.npmjs.com/package/react)
- [react-router-dom](https://www.npmjs.com/package/react-router-dom)
- [react-redux](https://www.npmjs.com/package/react-redux)
- [redis](https://www.npmjs.com/package/redis)
- [redux](https://www.npmjs.com/package/redux)
- [stringify-object](https://www.npmjs.com/package/stringify-object)
- [styled-components](https://www.npmjs.com/package/styled-components)
- [throttle-debounce](https://www.npmjs.com/package/throttle-debounce)
- [underscore](https://www.npmjs.com/package/underscore)

View File

@@ -19,15 +19,17 @@
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll",
"python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll",
"python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll"
"python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl.qll",
"python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl2.qll",
"python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl3.qll",
"python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl4.qll"
],
"DataFlow Java/C++/C#/Python Common": [
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
"cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll",
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll",
"python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll"
"python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll"
],
"TaintTracking::Configuration Java/C++/C#/Python": [
"cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
@@ -41,14 +43,17 @@
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll",
"java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
"java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
"python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
"python/ql/src/semmle/python/dataflow/new/internal/tainttracking1/TaintTrackingImpl.qll",
"python/ql/src/semmle/python/dataflow/new/internal/tainttracking2/TaintTrackingImpl.qll",
"python/ql/src/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
"python/ql/src/semmle/python/dataflow/new/internal/tainttracking4/TaintTrackingImpl.qll"
],
"DataFlow Java/C++/C#/Python Consistency checks": [
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll",
"cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll",
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll",
"python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll"
"python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplConsistency.qll"
],
"SsaReadPosition Java/C#": [
"java/ql/src/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
@@ -405,4 +410,4 @@
"javascript/ql/src/Comments/CommentedOutCodeReferences.qhelp",
"python/ql/src/Lexical/CommentedOutCodeReferences.qhelp"
]
}
}

View File

@@ -114,9 +114,47 @@ class PrintASTNode extends TPrintASTNode {
/**
* Gets the child node at index `childIndex`. Child indices must be unique,
* but need not be contiguous (but see `getChildByRank`).
* but need not be contiguous.
*/
abstract PrintASTNode getChild(int childIndex);
abstract PrintASTNode getChildInternal(int childIndex);
/**
* Gets the child node at index `childIndex`.
* Adds edges to fully converted expressions, that are not part of the
* regular parent/child relation traversal.
*/
final PrintASTNode getChild(int childIndex) {
// The exact value of `childIndex` doesn't matter, as long as we preserve the correct order.
result =
rank[childIndex](PrintASTNode child, int nonConvertedIndex, boolean isConverted |
childAndAccessorPredicate(child, _, nonConvertedIndex, isConverted)
|
// Unconverted children come first, then sort by original child index within each group.
child order by isConverted, nonConvertedIndex
)
}
/**
* Gets the node for the `.getFullyConverted()` version of the child originally at index
* `childIndex`, if that node has any conversions.
*/
private PrintASTNode getConvertedChild(int childIndex) {
exists(Expr expr |
expr = getChildInternal(childIndex).(ASTNode).getAST() and
expr.getFullyConverted() instanceof Conversion and
result.(ASTNode).getAST() = expr.getFullyConverted() and
not expr instanceof Conversion
)
}
/**
* Gets the child access predicate for the `.getFullyConverted()` version of the child originally
* at index `childIndex`, if that node has any conversions.
*/
private string getConvertedChildAccessorPredicate(int childIndex) {
exists(getConvertedChild(childIndex)) and
result = getChildAccessorPredicateInternal(childIndex) + ".getFullyConverted()"
}
/**
* Holds if this node should be printed in the output. By default, all nodes
@@ -150,15 +188,46 @@ class PrintASTNode extends TPrintASTNode {
}
/**
* Gets the label for the edge from this node to the specified child. By
* default, this is just the index of the child, but subclasses can override
* this.
* Holds if there is a child node `child` for original child index `nonConvertedIndex` with
* predicate name `childPredicate`. If the original child at that index has any conversions, there
* will be two result tuples for this predicate: one with the original child and predicate, with
* `isConverted = false`, and the other with the `.getFullyConverted()` version of the child and
* predicate, with `isConverted = true`. For a child without any conversions, there will be only
* one result tuple, with `isConverted = false`.
*/
string getChildEdgeLabel(int childIndex) {
exists(getChild(childIndex)) and
result = childIndex.toString()
private predicate childAndAccessorPredicate(
PrintASTNode child, string childPredicate, int nonConvertedIndex, boolean isConverted
) {
child = getChildInternal(nonConvertedIndex) and
childPredicate = getChildAccessorPredicateInternal(nonConvertedIndex) and
isConverted = false
or
child = getConvertedChild(nonConvertedIndex) and
childPredicate = getConvertedChildAccessorPredicate(nonConvertedIndex) and
isConverted = true
}
/**
* Gets the QL predicate that can be used to access the child at `childIndex`.
* May not always return a QL predicate, see for example `FunctionNode`.
*/
final string getChildAccessorPredicate(int childIndex) {
// The exact value of `childIndex` doesn't matter, as long as we preserve the correct order.
result =
rank[childIndex](string childPredicate, int nonConvertedIndex, boolean isConverted |
childAndAccessorPredicate(_, childPredicate, nonConvertedIndex, isConverted)
|
// Unconverted children come first, then sort by original child index within each group.
childPredicate order by isConverted, nonConvertedIndex
)
}
/**
* Gets the QL predicate that can be used to access the child at `childIndex`.
* INTERNAL DO NOT USE: Does not contain accessors for the synthesized nodes for conversions.
*/
abstract string getChildAccessorPredicateInternal(int childIndex);
/**
* Gets the `Function` that contains this node.
*/
@@ -205,9 +274,7 @@ class ExprNode extends ASTNode {
ExprNode() { expr = ast }
override ASTNode getChild(int childIndex) {
result.getAST() = expr.getChild(childIndex).getFullyConverted()
}
override ASTNode getChildInternal(int childIndex) { result.getAST() = expr.getChild(childIndex) }
override string getProperty(string key) {
result = super.getProperty(key)
@@ -222,6 +289,10 @@ class ExprNode extends ASTNode {
result = expr.getValueCategoryString()
}
override string getChildAccessorPredicateInternal(int childIndex) {
result = getChildAccessorWithoutConversions(ast, getChildInternal(childIndex).getAST())
}
/**
* Gets the value of this expression, if it is a constant.
*/
@@ -247,12 +318,11 @@ class ConversionNode extends ExprNode {
ConversionNode() { conv = expr }
override ASTNode getChild(int childIndex) {
override ASTNode getChildInternal(int childIndex) {
childIndex = 0 and
result.getAST() = conv.getExpr()
result.getAST() = conv.getExpr() and
conv.getExpr() instanceof Conversion
}
override string getChildEdgeLabel(int childIndex) { childIndex = 0 and result = "expr" }
}
/**
@@ -271,6 +341,18 @@ class CastNode extends ConversionNode {
}
}
/**
* A node representing a `StmtExpr`.
*/
class StmtExprNode extends ExprNode {
override StmtExpr expr;
override ASTNode getChildInternal(int childIndex) {
childIndex = 0 and
result.getAST() = expr.getStmt()
}
}
/**
* A node representing a `DeclarationEntry`.
*/
@@ -280,7 +362,9 @@ class DeclarationEntryNode extends BaseASTNode, TDeclarationEntryNode {
DeclarationEntryNode() { this = TDeclarationEntryNode(declStmt, ast) }
override PrintASTNode getChild(int childIndex) { none() }
override PrintASTNode getChildInternal(int childIndex) { none() }
override string getChildAccessorPredicateInternal(int childIndex) { none() }
override string getProperty(string key) {
result = BaseASTNode.super.getProperty(key)
@@ -296,12 +380,15 @@ class DeclarationEntryNode extends BaseASTNode, TDeclarationEntryNode {
class VariableDeclarationEntryNode extends DeclarationEntryNode {
override VariableDeclarationEntry ast;
override ASTNode getChild(int childIndex) {
override ASTNode getChildInternal(int childIndex) {
childIndex = 0 and
result.getAST() = ast.getVariable().getInitializer()
}
override string getChildEdgeLabel(int childIndex) { childIndex = 0 and result = "init" }
override string getChildAccessorPredicateInternal(int childIndex) {
childIndex = 0 and
result = "getVariable().getInitializer()"
}
}
/**
@@ -312,15 +399,19 @@ class StmtNode extends ASTNode {
StmtNode() { stmt = ast }
override BaseASTNode getChild(int childIndex) {
override BaseASTNode getChildInternal(int childIndex) {
exists(Locatable child |
child = stmt.getChild(childIndex) and
(
result.getAST() = child.(Expr).getFullyConverted() or
result.getAST() = child.(Expr) or
result.getAST() = child.(Stmt)
)
)
}
override string getChildAccessorPredicateInternal(int childIndex) {
result = getChildAccessorWithoutConversions(ast, getChildInternal(childIndex).getAST())
}
}
/**
@@ -331,7 +422,7 @@ class DeclStmtNode extends StmtNode {
DeclStmtNode() { declStmt = stmt }
override DeclarationEntryNode getChild(int childIndex) {
override DeclarationEntryNode getChildInternal(int childIndex) {
exists(DeclarationEntry entry |
declStmt.getDeclarationEntry(childIndex) = entry and
result = TDeclarationEntryNode(declStmt, entry)
@@ -347,7 +438,9 @@ class ParameterNode extends ASTNode {
ParameterNode() { param = ast }
final override PrintASTNode getChild(int childIndex) { none() }
final override PrintASTNode getChildInternal(int childIndex) { none() }
final override string getChildAccessorPredicateInternal(int childIndex) { none() }
final override string getProperty(string key) {
result = super.getProperty(key)
@@ -365,14 +458,14 @@ class InitializerNode extends ASTNode {
InitializerNode() { init = ast }
override ASTNode getChild(int childIndex) {
override ASTNode getChildInternal(int childIndex) {
childIndex = 0 and
result.getAST() = init.getExpr().getFullyConverted()
result.getAST() = init.getExpr()
}
override string getChildEdgeLabel(int childIndex) {
override string getChildAccessorPredicateInternal(int childIndex) {
childIndex = 0 and
result = "expr"
result = "getExpr()"
}
}
@@ -388,7 +481,14 @@ class ParametersNode extends PrintASTNode, TParametersNode {
final override Location getLocation() { result = getRepresentativeLocation(func) }
override ASTNode getChild(int childIndex) { result.getAST() = func.getParameter(childIndex) }
override ASTNode getChildInternal(int childIndex) {
result.getAST() = func.getParameter(childIndex)
}
override string getChildAccessorPredicateInternal(int childIndex) {
exists(getChildInternal(childIndex)) and
result = "getParameter(" + childIndex.toString() + ")"
}
/**
* Gets the `Function` for which this node represents the parameters.
@@ -408,10 +508,15 @@ class ConstructorInitializersNode extends PrintASTNode, TConstructorInitializers
final override Location getLocation() { result = getRepresentativeLocation(ctor) }
final override ASTNode getChild(int childIndex) {
final override ASTNode getChildInternal(int childIndex) {
result.getAST() = ctor.getInitializer(childIndex)
}
final override string getChildAccessorPredicateInternal(int childIndex) {
exists(getChildInternal(childIndex)) and
result = "getInitializer(" + childIndex.toString() + ")"
}
/**
* Gets the `Constructor` for which this node represents the initializer list.
*/
@@ -430,10 +535,15 @@ class DestructorDestructionsNode extends PrintASTNode, TDestructorDestructionsNo
final override Location getLocation() { result = getRepresentativeLocation(dtor) }
final override ASTNode getChild(int childIndex) {
final override ASTNode getChildInternal(int childIndex) {
result.getAST() = dtor.getDestruction(childIndex)
}
final override string getChildAccessorPredicateInternal(int childIndex) {
exists(getChildInternal(childIndex)) and
result = "getDestruction(" + childIndex.toString() + ")"
}
/**
* Gets the `Destructor` for which this node represents the destruction list.
*/
@@ -450,7 +560,7 @@ class FunctionNode extends ASTNode {
override string toString() { result = qlClass(func) + getIdentityString(func) }
override PrintASTNode getChild(int childIndex) {
override PrintASTNode getChildInternal(int childIndex) {
childIndex = 0 and
result.(ParametersNode).getFunction() = func
or
@@ -464,14 +574,14 @@ class FunctionNode extends ASTNode {
result.(DestructorDestructionsNode).getDestructor() = func
}
override string getChildEdgeLabel(int childIndex) {
childIndex = 0 and result = "params"
override string getChildAccessorPredicateInternal(int childIndex) {
childIndex = 0 and result = "<params>"
or
childIndex = 1 and result = "initializations"
childIndex = 1 and result = "<initializations>"
or
childIndex = 2 and result = "body"
childIndex = 2 and result = "getEntryPoint()"
or
childIndex = 3 and result = "destructions"
childIndex = 3 and result = "<destructions>"
}
private int getOrder() {
@@ -496,36 +606,237 @@ class FunctionNode extends ASTNode {
final Function getFunction() { result = func }
}
/**
* A node representing an `ClassAggregateLiteral`.
*/
class ClassAggregateLiteralNode extends ExprNode {
ClassAggregateLiteral list;
ClassAggregateLiteralNode() { list = ast }
override string getChildEdgeLabel(int childIndex) {
exists(Field field |
list.getFieldExpr(field) = list.getChild(childIndex) and
result = "." + field.getName()
private string getChildAccessorWithoutConversions(Locatable parent, Element child) {
shouldPrintFunction(getEnclosingFunction(parent)) and
(
exists(Stmt s | s = parent |
namedStmtChildPredicates(s, child, result)
or
not namedStmtChildPredicates(s, child, _) and
exists(int n | s.getChild(n) = child and result = "getChild(" + n + ")")
)
}
or
exists(Expr expr | expr = parent |
namedExprChildPredicates(expr, child, result)
or
not namedExprChildPredicates(expr, child, _) and
exists(int n | expr.getChild(n) = child and result = "getChild(" + n + ")")
)
)
}
/**
* A node representing an `ArrayAggregateLiteral`.
*/
class ArrayAggregateLiteralNode extends ExprNode {
ArrayAggregateLiteral list;
ArrayAggregateLiteralNode() { list = ast }
override string getChildEdgeLabel(int childIndex) {
exists(int elementIndex |
list.getElementExpr(elementIndex) = list.getChild(childIndex) and
result = "[" + elementIndex.toString() + "]"
private predicate namedStmtChildPredicates(Locatable s, Element e, string pred) {
shouldPrintFunction(getEnclosingFunction(s)) and
(
exists(int n | s.(BlockStmt).getStmt(n) = e and pred = "getStmt(" + n + ")")
or
s.(ComputedGotoStmt).getExpr() = e and pred = "getExpr()"
or
s.(ConstexprIfStmt).getCondition() = e and pred = "getCondition()"
or
s.(ConstexprIfStmt).getThen() = e and pred = "getThen()"
or
s.(ConstexprIfStmt).getElse() = e and pred = "getElse()"
or
s.(IfStmt).getCondition() = e and pred = "getCondition()"
or
s.(IfStmt).getThen() = e and pred = "getThen()"
or
s.(IfStmt).getElse() = e and pred = "getElse()"
or
s.(SwitchStmt).getExpr() = e and pred = "getExpr()"
or
s.(SwitchStmt).getStmt() = e and pred = "getStmt()"
or
s.(DoStmt).getCondition() = e and pred = "getCondition()"
or
s.(DoStmt).getStmt() = e and pred = "getStmt()"
or
s.(ForStmt).getInitialization() = e and pred = "getInitialization()"
or
s.(ForStmt).getCondition() = e and pred = "getCondition()"
or
s.(ForStmt).getUpdate() = e and pred = "getUpdate()"
or
s.(ForStmt).getStmt() = e and pred = "getStmt()"
or
s.(RangeBasedForStmt).getChild(0) = e and pred = "getChild(0)"
or
s.(RangeBasedForStmt).getBeginEndDeclaration() = e and pred = "getBeginEndDeclaration()"
or
s.(RangeBasedForStmt).getCondition() = e and pred = "getCondition()"
or
s.(RangeBasedForStmt).getUpdate() = e and pred = "getUpdate()"
or
s.(RangeBasedForStmt).getChild(4) = e and pred = "getChild(4)"
or
s.(RangeBasedForStmt).getStmt() = e and pred = "getStmt()"
or
s.(WhileStmt).getCondition() = e and pred = "getCondition()"
or
s.(WhileStmt).getStmt() = e and pred = "getStmt()"
or
exists(int n |
s.(DeclStmt).getDeclarationEntry(n) = e and pred = "getDeclarationEntry(" + n.toString() + ")"
)
}
or
// EmptyStmt does not have children
s.(ExprStmt).getExpr() = e and pred = "getExpr()"
or
s.(Handler).getBlock() = e and pred = "getBlock()"
or
s.(JumpStmt).getTarget() = e and pred = "getTarget()"
or
s.(MicrosoftTryStmt).getStmt() = e and pred = "getStmt()"
or
s.(MicrosoftTryExceptStmt).getCondition() = e and pred = "getCondition()"
or
s.(MicrosoftTryExceptStmt).getExcept() = e and pred = "getExcept()"
or
s.(MicrosoftTryFinallyStmt).getFinally() = e and pred = "getFinally()"
or
s.(ReturnStmt).getExpr() = e and pred = "getExpr()"
or
s.(SwitchCase).getExpr() = e and pred = "getExpr()"
or
s.(SwitchCase).getEndExpr() = e and pred = "getEndExpr()"
or
s.(TryStmt).getStmt() = e and pred = "getStmt()"
or
s.(VlaDimensionStmt).getDimensionExpr() = e and pred = "getDimensionExpr()"
)
}
private predicate namedExprChildPredicates(Expr expr, Element ele, string pred) {
shouldPrintFunction(expr.getEnclosingFunction()) and
(
expr.(Access).getTarget() = ele and pred = "getTarget()"
or
expr.(VariableAccess).getQualifier() = ele and pred = "getQualifier()"
or
exists(Field f |
expr.(ClassAggregateLiteral).getFieldExpr(f) = ele and
pred = "getFieldExpr(" + f.toString() + ")"
)
or
exists(int n |
expr.(ArrayOrVectorAggregateLiteral).getElementExpr(n) = ele and
pred = "getElementExpr(" + n.toString() + ")"
)
or
expr.(AlignofExprOperator).getExprOperand() = ele and pred = "getExprOperand()"
or
expr.(ArrayExpr).getArrayBase() = ele and pred = "getArrayBase()"
or
expr.(ArrayExpr).getArrayOffset() = ele and pred = "getArrayOffset()"
or
expr.(AssumeExpr).getOperand() = ele and pred = "getOperand()"
or
expr.(BuiltInComplexOperation).getRealOperand() = ele and pred = "getRealOperand()"
or
expr.(BuiltInComplexOperation).getImaginaryOperand() = ele and pred = "getImaginaryOperand()"
or
expr.(BuiltInVarArg).getVAList() = ele and pred = "getVAList()"
or
expr.(BuiltInVarArgCopy).getDestinationVAList() = ele and pred = "getDestinationVAList()"
or
expr.(BuiltInVarArgCopy).getSourceVAList() = ele and pred = "getSourceVAList()"
or
expr.(BuiltInVarArgsEnd).getVAList() = ele and pred = "getVAList()"
or
expr.(BuiltInVarArgsStart).getVAList() = ele and pred = "getVAList()"
or
expr.(BuiltInVarArgsStart).getLastNamedParameter() = ele and pred = "getLastNamedParameter()"
or
expr.(Call).getQualifier() = ele and pred = "getQualifier()"
or
exists(int n | expr.(Call).getArgument(n) = ele and pred = "getArgument(" + n.toString() + ")")
or
expr.(ExprCall).getExpr() = ele and pred = "getExpr()"
or
expr.(OverloadedArrayExpr).getArrayBase() = ele and pred = "getArrayBase()"
or
expr.(OverloadedArrayExpr).getArrayOffset() = ele and pred = "getArrayOffset()"
or
expr.(OverloadedPointerDereferenceExpr).getExpr() = ele and pred = "getExpr()"
or
expr.(CommaExpr).getLeftOperand() = ele and pred = "getLeftOperand()"
or
expr.(CommaExpr).getRightOperand() = ele and pred = "getRightOperand()"
or
expr.(ConditionDeclExpr).getVariableAccess() = ele and pred = "getVariableAccess()"
or
expr.(ConstructorFieldInit).getExpr() = ele and pred = "getExpr()"
or
expr.(Conversion).getExpr() = ele and pred = "getExpr()"
or
expr.(DeleteArrayExpr).getAllocatorCall() = ele and pred = "getAllocatorCall()"
or
expr.(DeleteArrayExpr).getDestructorCall() = ele and pred = "getDestructorCall()"
or
expr.(DeleteArrayExpr).getExpr() = ele and pred = "getExpr()"
or
expr.(DeleteExpr).getAllocatorCall() = ele and pred = "getAllocatorCall()"
or
expr.(DeleteExpr).getDestructorCall() = ele and pred = "getDestructorCall()"
or
expr.(DeleteExpr).getExpr() = ele and pred = "getExpr()"
or
expr.(DestructorFieldDestruction).getExpr() = ele and pred = "getExpr()"
or
expr.(FoldExpr).getInitExpr() = ele and pred = "getInitExpr()"
or
expr.(FoldExpr).getPackExpr() = ele and pred = "getPackExpr()"
or
expr.(LambdaExpression).getInitializer() = ele and pred = "getInitializer()"
or
expr.(NewOrNewArrayExpr).getAllocatorCall() = ele and pred = "getAllocatorCall()"
or
expr.(NewOrNewArrayExpr).getAlignmentArgument() = ele and pred = "getAlignmentArgument()"
or
expr.(NewArrayExpr).getInitializer() = ele and pred = "getInitializer()"
or
expr.(NewArrayExpr).getExtent() = ele and pred = "getExtent()"
or
expr.(NewExpr).getInitializer() = ele and pred = "getInitializer()"
or
expr.(NoExceptExpr).getExpr() = ele and pred = "getExpr()"
or
expr.(Assignment).getLValue() = ele and pred = "getLValue()"
or
expr.(Assignment).getRValue() = ele and pred = "getRValue()"
or
not expr instanceof RelationalOperation and
expr.(BinaryOperation).getLeftOperand() = ele and
pred = "getLeftOperand()"
or
not expr instanceof RelationalOperation and
expr.(BinaryOperation).getRightOperand() = ele and
pred = "getRightOperand()"
or
expr.(RelationalOperation).getGreaterOperand() = ele and pred = "getGreaterOperand()"
or
expr.(RelationalOperation).getLesserOperand() = ele and pred = "getLesserOperand()"
or
expr.(ConditionalExpr).getCondition() = ele and pred = "getCondition()"
or
// If ConditionalExpr is in two-operand form, getThen() = getCondition() holds
not expr.(ConditionalExpr).isTwoOperand() and
expr.(ConditionalExpr).getThen() = ele and
pred = "getThen()"
or
expr.(ConditionalExpr).getElse() = ele and pred = "getElse()"
or
expr.(UnaryOperation).getOperand() = ele and pred = "getOperand()"
or
expr.(SizeofExprOperator).getExprOperand() = ele and pred = "getExprOperand()"
or
expr.(StmtExpr).getStmt() = ele and pred = "getStmt()"
or
expr.(ThrowExpr).getExpr() = ele and pred = "getExpr()"
or
expr.(TypeidOperator).getExpr() = ele and pred = "getExpr()"
)
}
/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */
@@ -544,7 +855,7 @@ query predicate edges(PrintASTNode source, PrintASTNode target, string key, stri
target.shouldPrint() and
target = source.getChild(childIndex) and
(
key = "semmle.label" and value = source.getChildEdgeLabel(childIndex)
key = "semmle.label" and value = source.getChildAccessorPredicate(childIndex)
or
key = "semmle.order" and value = childIndex.toString()
)

View File

@@ -83,6 +83,8 @@ private predicate pointerToPointerStep(Expr pointerIn, Expr pointerOut) {
or
pointerIn.getConversion() = pointerOut.(ParenthesisExpr)
or
pointerIn.getConversion() = pointerOut.(TemporaryObjectExpr)
or
pointerIn = pointerOut.(ConditionalExpr).getThen().getFullyConverted()
or
pointerIn = pointerOut.(ConditionalExpr).getElse().getFullyConverted()

View File

@@ -81,6 +81,8 @@ private predicate pointerToPointerStep(Expr pointerIn, Expr pointerOut) {
or
pointerIn.getConversion() = pointerOut.(ParenthesisExpr)
or
pointerIn.getConversion() = pointerOut.(TemporaryObjectExpr)
or
pointerIn = pointerOut.(ConditionalExpr).getThen().getFullyConverted()
or
pointerIn = pointerOut.(ConditionalExpr).getElse().getFullyConverted()

View File

@@ -112,8 +112,8 @@ abstract class Configuration extends string {
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` measured in approximate
* number of interprocedural steps.
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
int explorationLimit() { none() }
@@ -123,7 +123,7 @@ abstract class Configuration extends string {
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards sink definitions.
*
* This predicate is intended for dataflow exploration and debugging and may
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sources is too big and/or the exploration
* limit is set too high without using barriers.
*
@@ -136,6 +136,29 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/**
* Holds if there is a partial data flow path from `node` to `sink`. The
* approximate distance between `node` and the closest sink is `dist` and
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards source definitions.
*
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sinks is too big and/or the exploration
* limit is set too high without using barriers.
*
* This predicate is disabled (has no results) by default. Override
* `explorationLimit()` with a suitable number to enable this predicate.
*
* To use this in a `path-problem` query, import the module `PartialPathGraph`.
*
* Note that reverse flow has slightly lower precision than the corresponding
* forward flow, as reverse flow disregards type pruning among other features.
*/
final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
revPartialFlow(node, sink, this) and
dist = node.getSinkDistance()
}
}
/**
@@ -2943,12 +2966,26 @@ private module FlowExploration {
)
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
)
}
private newtype TCallableExt =
TCallable(DataFlowCallable c, Configuration config) { interestingCallableSrc(c, config) } or
TCallableSrc()
TCallable(DataFlowCallable c, Configuration config) {
interestingCallableSrc(c, config) or
interestingCallableSink(c, config)
} or
TCallableSrc() or
TCallableSink()
private predicate callableExtSrc(TCallableSrc src) { any() }
private predicate callableExtSink(TCallableSink sink) { any() }
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
@@ -2961,15 +2998,32 @@ private module FlowExploration {
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
)
}
private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) {
callableExtStepFwd(ce2, ce1)
}
private int distSrcExt(TCallableExt c) =
shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result)
private int distSinkExt(TCallableExt c) =
shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result)
private int distSrc(DataFlowCallable c, Configuration config) {
result = distSrcExt(TCallable(c, config)) - 1
}
private int distSink(DataFlowCallable c, Configuration config) {
result = distSinkExt(TCallable(c, config)) - 1
}
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] }
@@ -2997,18 +3051,12 @@ private module FlowExploration {
or
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
}
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t))
}
}
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
@@ -3019,9 +3067,39 @@ private module FlowExploration {
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
}
override AccessPathFront getFront() {
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
private newtype TRevPartialAccessPath =
TRevPartialNil() or
TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] }
/**
* Conceptually a list of `Content`s, but only the first
* element of the list and its length are tracked.
*/
private class RevPartialAccessPath extends TRevPartialAccessPath {
abstract string toString();
Content getHead() { this = TRevPartialCons(result, _) }
int len() {
this = TRevPartialNil() and result = 0
or
this = TRevPartialCons(_, result)
}
}
private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil {
override string toString() { result = "" }
}
private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons {
override string toString() {
exists(Content c, int len | this = TRevPartialCons(c, len) |
if len = 1
then result = "[" + c.toString() + "]"
else result = "[" + c.toString() + ", ... (" + len.toString() + ")]"
)
}
}
@@ -3033,8 +3111,16 @@ private module FlowExploration {
TSummaryCtx2None() or
TSummaryCtx2Some(PartialAccessPath ap)
private newtype TRevSummaryCtx1 =
TRevSummaryCtx1None() or
TRevSummaryCtx1Some(ReturnPosition pos)
private newtype TRevSummaryCtx2 =
TRevSummaryCtx2None() or
TRevSummaryCtx2Some(RevPartialAccessPath ap)
private newtype TPartialPathNode =
TPartialPathNodeMk(
TPartialPathNodeFwd(
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
@@ -3048,6 +3134,23 @@ private module FlowExploration {
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
@@ -3055,7 +3158,7 @@ private module FlowExploration {
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNode mid |
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
@@ -3107,15 +3210,32 @@ private module FlowExploration {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
/**
* Gets the approximate distance to the nearest sink measured in number
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
exists(string s |
s = this.(PartialPathNodeFwd).getAp().toString() or
s = this.(PartialPathNodeRev).getAp().toString()
|
if s = "" then result = "" else result = " " + s
)
}
private string ppCtx() {
result = " <" + this.(PartialPathNodePriv).getCallContext().toString() + ">"
result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">"
}
/** Holds if this is a source in a forward-flow path. */
predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() }
/** Holds if this is a sink in a reverse-flow path. */
predicate isRevSink() { this.(PartialPathNodeRev).isSink() }
}
/**
@@ -3126,7 +3246,7 @@ private module FlowExploration {
query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b }
}
private class PartialPathNodePriv extends PartialPathNode {
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
Node node;
CallContext cc;
TSummaryCtx1 sc1;
@@ -3134,7 +3254,7 @@ private module FlowExploration {
PartialAccessPath ap;
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, sc1, sc2, ap, config) }
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
override Node getNode() { result = node }
@@ -3148,14 +3268,54 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodePriv getASuccessor() {
override PartialPathNodeFwd getASuccessor() {
partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
config.isSource(node) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap instanceof TPartialNil
}
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
Node node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
Configuration config;
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
override Node getNode() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
TRevSummaryCtx2 getSummaryCtx2() { result = sc2 }
RevPartialAccessPath getAp() { result = ap }
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
}
}
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
@@ -3221,8 +3381,7 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
) {
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
@@ -3238,7 +3397,7 @@ private module FlowExploration {
private predicate apConsFwd(
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
exists(PartialPathNodeFwd mid |
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
@@ -3246,7 +3405,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
exists(Node midNode |
@@ -3260,7 +3419,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable0(
PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
pos = getReturnPosition(mid.getNode()) and
@@ -3272,7 +3431,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc |
@@ -3286,7 +3445,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
@@ -3297,7 +3456,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(ArgumentNode arg |
@@ -3311,7 +3470,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
@@ -3319,7 +3478,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3340,7 +3499,7 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodePriv mid, ReturnNodeExt ret |
exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
mid.getNode() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -3353,7 +3512,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathThroughCallable0(
DataFlowCall call, PartialPathNodePriv mid, ReturnKindExt kind, CallContext cc,
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
@@ -3363,13 +3522,164 @@ private module FlowExploration {
}
private predicate partialPathThroughCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
out = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
localFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
jumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalJumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
revPartialPathReadStep(mid, _, _, node, ap) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(RevPartialAccessPath ap0, Content c |
revPartialPathStoreStep(mid, ap0, c, node, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsRev(ap, c, ap0, config)
)
or
exists(ParameterNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
pos = getReturnPosition(node)
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2()
}
pragma[inline]
private predicate revPartialPathReadStep(
PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
) {
exists(Node midNode |
midNode = mid.getNode() and
ap1 = mid.getAp() and
read(node, c, midNode) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
}
pragma[nomagic]
private predicate apConsRev(
RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodeRev mid |
revPartialPathReadStep(mid, ap1, c, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
) {
exists(Node midNode, TypedContent tc |
midNode = mid.getNode() and
ap = mid.getAp() and
store(node, tc, midNode, _) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
)
}
pragma[nomagic]
private predicate revPartialPathIntoReturn(
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
exists(Node out |
mid.getNode() = out and
viableReturnPosOut(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeRev mid, ParameterNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
revPartialPathIntoReturn(mid, _, sc1, sc2, call, _, config) and
revPartialPathFlowsThrough(pos, sc1, sc2, ap, config)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.argumentOf(call, pos)
)
}
}
import FlowExploration
@@ -3378,6 +3688,14 @@ private predicate partialFlow(
PartialPathNode source, PartialPathNode node, Configuration configuration
) {
source.getConfiguration() = configuration and
configuration.isSource(source.getNode()) and
source.isFwdSource() and
node = source.getASuccessor+()
}
private predicate revPartialFlow(
PartialPathNode node, PartialPathNode sink, Configuration configuration
) {
sink.getConfiguration() = configuration and
sink.isRevSink() and
node.getASuccessor+() = sink
}

View File

@@ -112,8 +112,8 @@ abstract class Configuration extends string {
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` measured in approximate
* number of interprocedural steps.
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
int explorationLimit() { none() }
@@ -123,7 +123,7 @@ abstract class Configuration extends string {
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards sink definitions.
*
* This predicate is intended for dataflow exploration and debugging and may
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sources is too big and/or the exploration
* limit is set too high without using barriers.
*
@@ -136,6 +136,29 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/**
* Holds if there is a partial data flow path from `node` to `sink`. The
* approximate distance between `node` and the closest sink is `dist` and
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards source definitions.
*
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sinks is too big and/or the exploration
* limit is set too high without using barriers.
*
* This predicate is disabled (has no results) by default. Override
* `explorationLimit()` with a suitable number to enable this predicate.
*
* To use this in a `path-problem` query, import the module `PartialPathGraph`.
*
* Note that reverse flow has slightly lower precision than the corresponding
* forward flow, as reverse flow disregards type pruning among other features.
*/
final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
revPartialFlow(node, sink, this) and
dist = node.getSinkDistance()
}
}
/**
@@ -2943,12 +2966,26 @@ private module FlowExploration {
)
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
)
}
private newtype TCallableExt =
TCallable(DataFlowCallable c, Configuration config) { interestingCallableSrc(c, config) } or
TCallableSrc()
TCallable(DataFlowCallable c, Configuration config) {
interestingCallableSrc(c, config) or
interestingCallableSink(c, config)
} or
TCallableSrc() or
TCallableSink()
private predicate callableExtSrc(TCallableSrc src) { any() }
private predicate callableExtSink(TCallableSink sink) { any() }
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
@@ -2961,15 +2998,32 @@ private module FlowExploration {
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
)
}
private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) {
callableExtStepFwd(ce2, ce1)
}
private int distSrcExt(TCallableExt c) =
shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result)
private int distSinkExt(TCallableExt c) =
shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result)
private int distSrc(DataFlowCallable c, Configuration config) {
result = distSrcExt(TCallable(c, config)) - 1
}
private int distSink(DataFlowCallable c, Configuration config) {
result = distSinkExt(TCallable(c, config)) - 1
}
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] }
@@ -2997,18 +3051,12 @@ private module FlowExploration {
or
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
}
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t))
}
}
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
@@ -3019,9 +3067,39 @@ private module FlowExploration {
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
}
override AccessPathFront getFront() {
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
private newtype TRevPartialAccessPath =
TRevPartialNil() or
TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] }
/**
* Conceptually a list of `Content`s, but only the first
* element of the list and its length are tracked.
*/
private class RevPartialAccessPath extends TRevPartialAccessPath {
abstract string toString();
Content getHead() { this = TRevPartialCons(result, _) }
int len() {
this = TRevPartialNil() and result = 0
or
this = TRevPartialCons(_, result)
}
}
private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil {
override string toString() { result = "" }
}
private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons {
override string toString() {
exists(Content c, int len | this = TRevPartialCons(c, len) |
if len = 1
then result = "[" + c.toString() + "]"
else result = "[" + c.toString() + ", ... (" + len.toString() + ")]"
)
}
}
@@ -3033,8 +3111,16 @@ private module FlowExploration {
TSummaryCtx2None() or
TSummaryCtx2Some(PartialAccessPath ap)
private newtype TRevSummaryCtx1 =
TRevSummaryCtx1None() or
TRevSummaryCtx1Some(ReturnPosition pos)
private newtype TRevSummaryCtx2 =
TRevSummaryCtx2None() or
TRevSummaryCtx2Some(RevPartialAccessPath ap)
private newtype TPartialPathNode =
TPartialPathNodeMk(
TPartialPathNodeFwd(
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
@@ -3048,6 +3134,23 @@ private module FlowExploration {
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
@@ -3055,7 +3158,7 @@ private module FlowExploration {
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNode mid |
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
@@ -3107,15 +3210,32 @@ private module FlowExploration {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
/**
* Gets the approximate distance to the nearest sink measured in number
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
exists(string s |
s = this.(PartialPathNodeFwd).getAp().toString() or
s = this.(PartialPathNodeRev).getAp().toString()
|
if s = "" then result = "" else result = " " + s
)
}
private string ppCtx() {
result = " <" + this.(PartialPathNodePriv).getCallContext().toString() + ">"
result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">"
}
/** Holds if this is a source in a forward-flow path. */
predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() }
/** Holds if this is a sink in a reverse-flow path. */
predicate isRevSink() { this.(PartialPathNodeRev).isSink() }
}
/**
@@ -3126,7 +3246,7 @@ private module FlowExploration {
query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b }
}
private class PartialPathNodePriv extends PartialPathNode {
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
Node node;
CallContext cc;
TSummaryCtx1 sc1;
@@ -3134,7 +3254,7 @@ private module FlowExploration {
PartialAccessPath ap;
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, sc1, sc2, ap, config) }
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
override Node getNode() { result = node }
@@ -3148,14 +3268,54 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodePriv getASuccessor() {
override PartialPathNodeFwd getASuccessor() {
partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
config.isSource(node) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap instanceof TPartialNil
}
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
Node node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
Configuration config;
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
override Node getNode() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
TRevSummaryCtx2 getSummaryCtx2() { result = sc2 }
RevPartialAccessPath getAp() { result = ap }
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
}
}
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
@@ -3221,8 +3381,7 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
) {
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
@@ -3238,7 +3397,7 @@ private module FlowExploration {
private predicate apConsFwd(
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
exists(PartialPathNodeFwd mid |
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
@@ -3246,7 +3405,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
exists(Node midNode |
@@ -3260,7 +3419,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable0(
PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
pos = getReturnPosition(mid.getNode()) and
@@ -3272,7 +3431,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc |
@@ -3286,7 +3445,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
@@ -3297,7 +3456,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(ArgumentNode arg |
@@ -3311,7 +3470,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
@@ -3319,7 +3478,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3340,7 +3499,7 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodePriv mid, ReturnNodeExt ret |
exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
mid.getNode() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -3353,7 +3512,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathThroughCallable0(
DataFlowCall call, PartialPathNodePriv mid, ReturnKindExt kind, CallContext cc,
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
@@ -3363,13 +3522,164 @@ private module FlowExploration {
}
private predicate partialPathThroughCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
out = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
localFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
jumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalJumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
revPartialPathReadStep(mid, _, _, node, ap) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(RevPartialAccessPath ap0, Content c |
revPartialPathStoreStep(mid, ap0, c, node, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsRev(ap, c, ap0, config)
)
or
exists(ParameterNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
pos = getReturnPosition(node)
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2()
}
pragma[inline]
private predicate revPartialPathReadStep(
PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
) {
exists(Node midNode |
midNode = mid.getNode() and
ap1 = mid.getAp() and
read(node, c, midNode) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
}
pragma[nomagic]
private predicate apConsRev(
RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodeRev mid |
revPartialPathReadStep(mid, ap1, c, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
) {
exists(Node midNode, TypedContent tc |
midNode = mid.getNode() and
ap = mid.getAp() and
store(node, tc, midNode, _) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
)
}
pragma[nomagic]
private predicate revPartialPathIntoReturn(
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
exists(Node out |
mid.getNode() = out and
viableReturnPosOut(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeRev mid, ParameterNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
revPartialPathIntoReturn(mid, _, sc1, sc2, call, _, config) and
revPartialPathFlowsThrough(pos, sc1, sc2, ap, config)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.argumentOf(call, pos)
)
}
}
import FlowExploration
@@ -3378,6 +3688,14 @@ private predicate partialFlow(
PartialPathNode source, PartialPathNode node, Configuration configuration
) {
source.getConfiguration() = configuration and
configuration.isSource(source.getNode()) and
source.isFwdSource() and
node = source.getASuccessor+()
}
private predicate revPartialFlow(
PartialPathNode node, PartialPathNode sink, Configuration configuration
) {
sink.getConfiguration() = configuration and
sink.isRevSink() and
node.getASuccessor+() = sink
}

View File

@@ -112,8 +112,8 @@ abstract class Configuration extends string {
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` measured in approximate
* number of interprocedural steps.
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
int explorationLimit() { none() }
@@ -123,7 +123,7 @@ abstract class Configuration extends string {
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards sink definitions.
*
* This predicate is intended for dataflow exploration and debugging and may
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sources is too big and/or the exploration
* limit is set too high without using barriers.
*
@@ -136,6 +136,29 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/**
* Holds if there is a partial data flow path from `node` to `sink`. The
* approximate distance between `node` and the closest sink is `dist` and
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards source definitions.
*
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sinks is too big and/or the exploration
* limit is set too high without using barriers.
*
* This predicate is disabled (has no results) by default. Override
* `explorationLimit()` with a suitable number to enable this predicate.
*
* To use this in a `path-problem` query, import the module `PartialPathGraph`.
*
* Note that reverse flow has slightly lower precision than the corresponding
* forward flow, as reverse flow disregards type pruning among other features.
*/
final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
revPartialFlow(node, sink, this) and
dist = node.getSinkDistance()
}
}
/**
@@ -2943,12 +2966,26 @@ private module FlowExploration {
)
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
)
}
private newtype TCallableExt =
TCallable(DataFlowCallable c, Configuration config) { interestingCallableSrc(c, config) } or
TCallableSrc()
TCallable(DataFlowCallable c, Configuration config) {
interestingCallableSrc(c, config) or
interestingCallableSink(c, config)
} or
TCallableSrc() or
TCallableSink()
private predicate callableExtSrc(TCallableSrc src) { any() }
private predicate callableExtSink(TCallableSink sink) { any() }
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
@@ -2961,15 +2998,32 @@ private module FlowExploration {
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
)
}
private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) {
callableExtStepFwd(ce2, ce1)
}
private int distSrcExt(TCallableExt c) =
shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result)
private int distSinkExt(TCallableExt c) =
shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result)
private int distSrc(DataFlowCallable c, Configuration config) {
result = distSrcExt(TCallable(c, config)) - 1
}
private int distSink(DataFlowCallable c, Configuration config) {
result = distSinkExt(TCallable(c, config)) - 1
}
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] }
@@ -2997,18 +3051,12 @@ private module FlowExploration {
or
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
}
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t))
}
}
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
@@ -3019,9 +3067,39 @@ private module FlowExploration {
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
}
override AccessPathFront getFront() {
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
private newtype TRevPartialAccessPath =
TRevPartialNil() or
TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] }
/**
* Conceptually a list of `Content`s, but only the first
* element of the list and its length are tracked.
*/
private class RevPartialAccessPath extends TRevPartialAccessPath {
abstract string toString();
Content getHead() { this = TRevPartialCons(result, _) }
int len() {
this = TRevPartialNil() and result = 0
or
this = TRevPartialCons(_, result)
}
}
private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil {
override string toString() { result = "" }
}
private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons {
override string toString() {
exists(Content c, int len | this = TRevPartialCons(c, len) |
if len = 1
then result = "[" + c.toString() + "]"
else result = "[" + c.toString() + ", ... (" + len.toString() + ")]"
)
}
}
@@ -3033,8 +3111,16 @@ private module FlowExploration {
TSummaryCtx2None() or
TSummaryCtx2Some(PartialAccessPath ap)
private newtype TRevSummaryCtx1 =
TRevSummaryCtx1None() or
TRevSummaryCtx1Some(ReturnPosition pos)
private newtype TRevSummaryCtx2 =
TRevSummaryCtx2None() or
TRevSummaryCtx2Some(RevPartialAccessPath ap)
private newtype TPartialPathNode =
TPartialPathNodeMk(
TPartialPathNodeFwd(
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
@@ -3048,6 +3134,23 @@ private module FlowExploration {
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
@@ -3055,7 +3158,7 @@ private module FlowExploration {
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNode mid |
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
@@ -3107,15 +3210,32 @@ private module FlowExploration {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
/**
* Gets the approximate distance to the nearest sink measured in number
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
exists(string s |
s = this.(PartialPathNodeFwd).getAp().toString() or
s = this.(PartialPathNodeRev).getAp().toString()
|
if s = "" then result = "" else result = " " + s
)
}
private string ppCtx() {
result = " <" + this.(PartialPathNodePriv).getCallContext().toString() + ">"
result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">"
}
/** Holds if this is a source in a forward-flow path. */
predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() }
/** Holds if this is a sink in a reverse-flow path. */
predicate isRevSink() { this.(PartialPathNodeRev).isSink() }
}
/**
@@ -3126,7 +3246,7 @@ private module FlowExploration {
query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b }
}
private class PartialPathNodePriv extends PartialPathNode {
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
Node node;
CallContext cc;
TSummaryCtx1 sc1;
@@ -3134,7 +3254,7 @@ private module FlowExploration {
PartialAccessPath ap;
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, sc1, sc2, ap, config) }
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
override Node getNode() { result = node }
@@ -3148,14 +3268,54 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodePriv getASuccessor() {
override PartialPathNodeFwd getASuccessor() {
partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
config.isSource(node) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap instanceof TPartialNil
}
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
Node node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
Configuration config;
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
override Node getNode() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
TRevSummaryCtx2 getSummaryCtx2() { result = sc2 }
RevPartialAccessPath getAp() { result = ap }
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
}
}
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
@@ -3221,8 +3381,7 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
) {
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
@@ -3238,7 +3397,7 @@ private module FlowExploration {
private predicate apConsFwd(
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
exists(PartialPathNodeFwd mid |
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
@@ -3246,7 +3405,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
exists(Node midNode |
@@ -3260,7 +3419,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable0(
PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
pos = getReturnPosition(mid.getNode()) and
@@ -3272,7 +3431,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc |
@@ -3286,7 +3445,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
@@ -3297,7 +3456,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(ArgumentNode arg |
@@ -3311,7 +3470,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
@@ -3319,7 +3478,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3340,7 +3499,7 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodePriv mid, ReturnNodeExt ret |
exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
mid.getNode() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -3353,7 +3512,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathThroughCallable0(
DataFlowCall call, PartialPathNodePriv mid, ReturnKindExt kind, CallContext cc,
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
@@ -3363,13 +3522,164 @@ private module FlowExploration {
}
private predicate partialPathThroughCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
out = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
localFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
jumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalJumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
revPartialPathReadStep(mid, _, _, node, ap) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(RevPartialAccessPath ap0, Content c |
revPartialPathStoreStep(mid, ap0, c, node, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsRev(ap, c, ap0, config)
)
or
exists(ParameterNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
pos = getReturnPosition(node)
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2()
}
pragma[inline]
private predicate revPartialPathReadStep(
PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
) {
exists(Node midNode |
midNode = mid.getNode() and
ap1 = mid.getAp() and
read(node, c, midNode) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
}
pragma[nomagic]
private predicate apConsRev(
RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodeRev mid |
revPartialPathReadStep(mid, ap1, c, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
) {
exists(Node midNode, TypedContent tc |
midNode = mid.getNode() and
ap = mid.getAp() and
store(node, tc, midNode, _) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
)
}
pragma[nomagic]
private predicate revPartialPathIntoReturn(
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
exists(Node out |
mid.getNode() = out and
viableReturnPosOut(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeRev mid, ParameterNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
revPartialPathIntoReturn(mid, _, sc1, sc2, call, _, config) and
revPartialPathFlowsThrough(pos, sc1, sc2, ap, config)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.argumentOf(call, pos)
)
}
}
import FlowExploration
@@ -3378,6 +3688,14 @@ private predicate partialFlow(
PartialPathNode source, PartialPathNode node, Configuration configuration
) {
source.getConfiguration() = configuration and
configuration.isSource(source.getNode()) and
source.isFwdSource() and
node = source.getASuccessor+()
}
private predicate revPartialFlow(
PartialPathNode node, PartialPathNode sink, Configuration configuration
) {
sink.getConfiguration() = configuration and
sink.isRevSink() and
node.getASuccessor+() = sink
}

View File

@@ -112,8 +112,8 @@ abstract class Configuration extends string {
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` measured in approximate
* number of interprocedural steps.
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
int explorationLimit() { none() }
@@ -123,7 +123,7 @@ abstract class Configuration extends string {
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards sink definitions.
*
* This predicate is intended for dataflow exploration and debugging and may
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sources is too big and/or the exploration
* limit is set too high without using barriers.
*
@@ -136,6 +136,29 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/**
* Holds if there is a partial data flow path from `node` to `sink`. The
* approximate distance between `node` and the closest sink is `dist` and
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards source definitions.
*
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sinks is too big and/or the exploration
* limit is set too high without using barriers.
*
* This predicate is disabled (has no results) by default. Override
* `explorationLimit()` with a suitable number to enable this predicate.
*
* To use this in a `path-problem` query, import the module `PartialPathGraph`.
*
* Note that reverse flow has slightly lower precision than the corresponding
* forward flow, as reverse flow disregards type pruning among other features.
*/
final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
revPartialFlow(node, sink, this) and
dist = node.getSinkDistance()
}
}
/**
@@ -2943,12 +2966,26 @@ private module FlowExploration {
)
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
)
}
private newtype TCallableExt =
TCallable(DataFlowCallable c, Configuration config) { interestingCallableSrc(c, config) } or
TCallableSrc()
TCallable(DataFlowCallable c, Configuration config) {
interestingCallableSrc(c, config) or
interestingCallableSink(c, config)
} or
TCallableSrc() or
TCallableSink()
private predicate callableExtSrc(TCallableSrc src) { any() }
private predicate callableExtSink(TCallableSink sink) { any() }
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
@@ -2961,15 +2998,32 @@ private module FlowExploration {
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
)
}
private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) {
callableExtStepFwd(ce2, ce1)
}
private int distSrcExt(TCallableExt c) =
shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result)
private int distSinkExt(TCallableExt c) =
shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result)
private int distSrc(DataFlowCallable c, Configuration config) {
result = distSrcExt(TCallable(c, config)) - 1
}
private int distSink(DataFlowCallable c, Configuration config) {
result = distSinkExt(TCallable(c, config)) - 1
}
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] }
@@ -2997,18 +3051,12 @@ private module FlowExploration {
or
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
}
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t))
}
}
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
@@ -3019,9 +3067,39 @@ private module FlowExploration {
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
}
override AccessPathFront getFront() {
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
private newtype TRevPartialAccessPath =
TRevPartialNil() or
TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] }
/**
* Conceptually a list of `Content`s, but only the first
* element of the list and its length are tracked.
*/
private class RevPartialAccessPath extends TRevPartialAccessPath {
abstract string toString();
Content getHead() { this = TRevPartialCons(result, _) }
int len() {
this = TRevPartialNil() and result = 0
or
this = TRevPartialCons(_, result)
}
}
private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil {
override string toString() { result = "" }
}
private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons {
override string toString() {
exists(Content c, int len | this = TRevPartialCons(c, len) |
if len = 1
then result = "[" + c.toString() + "]"
else result = "[" + c.toString() + ", ... (" + len.toString() + ")]"
)
}
}
@@ -3033,8 +3111,16 @@ private module FlowExploration {
TSummaryCtx2None() or
TSummaryCtx2Some(PartialAccessPath ap)
private newtype TRevSummaryCtx1 =
TRevSummaryCtx1None() or
TRevSummaryCtx1Some(ReturnPosition pos)
private newtype TRevSummaryCtx2 =
TRevSummaryCtx2None() or
TRevSummaryCtx2Some(RevPartialAccessPath ap)
private newtype TPartialPathNode =
TPartialPathNodeMk(
TPartialPathNodeFwd(
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
@@ -3048,6 +3134,23 @@ private module FlowExploration {
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
@@ -3055,7 +3158,7 @@ private module FlowExploration {
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNode mid |
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
@@ -3107,15 +3210,32 @@ private module FlowExploration {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
/**
* Gets the approximate distance to the nearest sink measured in number
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
exists(string s |
s = this.(PartialPathNodeFwd).getAp().toString() or
s = this.(PartialPathNodeRev).getAp().toString()
|
if s = "" then result = "" else result = " " + s
)
}
private string ppCtx() {
result = " <" + this.(PartialPathNodePriv).getCallContext().toString() + ">"
result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">"
}
/** Holds if this is a source in a forward-flow path. */
predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() }
/** Holds if this is a sink in a reverse-flow path. */
predicate isRevSink() { this.(PartialPathNodeRev).isSink() }
}
/**
@@ -3126,7 +3246,7 @@ private module FlowExploration {
query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b }
}
private class PartialPathNodePriv extends PartialPathNode {
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
Node node;
CallContext cc;
TSummaryCtx1 sc1;
@@ -3134,7 +3254,7 @@ private module FlowExploration {
PartialAccessPath ap;
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, sc1, sc2, ap, config) }
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
override Node getNode() { result = node }
@@ -3148,14 +3268,54 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodePriv getASuccessor() {
override PartialPathNodeFwd getASuccessor() {
partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
config.isSource(node) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap instanceof TPartialNil
}
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
Node node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
Configuration config;
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
override Node getNode() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
TRevSummaryCtx2 getSummaryCtx2() { result = sc2 }
RevPartialAccessPath getAp() { result = ap }
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
}
}
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
@@ -3221,8 +3381,7 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
) {
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
@@ -3238,7 +3397,7 @@ private module FlowExploration {
private predicate apConsFwd(
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
exists(PartialPathNodeFwd mid |
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
@@ -3246,7 +3405,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
exists(Node midNode |
@@ -3260,7 +3419,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable0(
PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
pos = getReturnPosition(mid.getNode()) and
@@ -3272,7 +3431,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc |
@@ -3286,7 +3445,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
@@ -3297,7 +3456,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(ArgumentNode arg |
@@ -3311,7 +3470,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
@@ -3319,7 +3478,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3340,7 +3499,7 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodePriv mid, ReturnNodeExt ret |
exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
mid.getNode() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -3353,7 +3512,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathThroughCallable0(
DataFlowCall call, PartialPathNodePriv mid, ReturnKindExt kind, CallContext cc,
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
@@ -3363,13 +3522,164 @@ private module FlowExploration {
}
private predicate partialPathThroughCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
out = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
localFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
jumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalJumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
revPartialPathReadStep(mid, _, _, node, ap) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(RevPartialAccessPath ap0, Content c |
revPartialPathStoreStep(mid, ap0, c, node, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsRev(ap, c, ap0, config)
)
or
exists(ParameterNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
pos = getReturnPosition(node)
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2()
}
pragma[inline]
private predicate revPartialPathReadStep(
PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
) {
exists(Node midNode |
midNode = mid.getNode() and
ap1 = mid.getAp() and
read(node, c, midNode) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
}
pragma[nomagic]
private predicate apConsRev(
RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodeRev mid |
revPartialPathReadStep(mid, ap1, c, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
) {
exists(Node midNode, TypedContent tc |
midNode = mid.getNode() and
ap = mid.getAp() and
store(node, tc, midNode, _) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
)
}
pragma[nomagic]
private predicate revPartialPathIntoReturn(
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
exists(Node out |
mid.getNode() = out and
viableReturnPosOut(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeRev mid, ParameterNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
revPartialPathIntoReturn(mid, _, sc1, sc2, call, _, config) and
revPartialPathFlowsThrough(pos, sc1, sc2, ap, config)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.argumentOf(call, pos)
)
}
}
import FlowExploration
@@ -3378,6 +3688,14 @@ private predicate partialFlow(
PartialPathNode source, PartialPathNode node, Configuration configuration
) {
source.getConfiguration() = configuration and
configuration.isSource(source.getNode()) and
source.isFwdSource() and
node = source.getASuccessor+()
}
private predicate revPartialFlow(
PartialPathNode node, PartialPathNode sink, Configuration configuration
) {
sink.getConfiguration() = configuration and
sink.isRevSink() and
node.getASuccessor+() = sink
}

View File

@@ -112,8 +112,8 @@ abstract class Configuration extends string {
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` measured in approximate
* number of interprocedural steps.
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
int explorationLimit() { none() }
@@ -123,7 +123,7 @@ abstract class Configuration extends string {
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards sink definitions.
*
* This predicate is intended for dataflow exploration and debugging and may
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sources is too big and/or the exploration
* limit is set too high without using barriers.
*
@@ -136,6 +136,29 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/**
* Holds if there is a partial data flow path from `node` to `sink`. The
* approximate distance between `node` and the closest sink is `dist` and
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards source definitions.
*
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sinks is too big and/or the exploration
* limit is set too high without using barriers.
*
* This predicate is disabled (has no results) by default. Override
* `explorationLimit()` with a suitable number to enable this predicate.
*
* To use this in a `path-problem` query, import the module `PartialPathGraph`.
*
* Note that reverse flow has slightly lower precision than the corresponding
* forward flow, as reverse flow disregards type pruning among other features.
*/
final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
revPartialFlow(node, sink, this) and
dist = node.getSinkDistance()
}
}
/**
@@ -2943,12 +2966,26 @@ private module FlowExploration {
)
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
)
}
private newtype TCallableExt =
TCallable(DataFlowCallable c, Configuration config) { interestingCallableSrc(c, config) } or
TCallableSrc()
TCallable(DataFlowCallable c, Configuration config) {
interestingCallableSrc(c, config) or
interestingCallableSink(c, config)
} or
TCallableSrc() or
TCallableSink()
private predicate callableExtSrc(TCallableSrc src) { any() }
private predicate callableExtSink(TCallableSink sink) { any() }
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
@@ -2961,15 +2998,32 @@ private module FlowExploration {
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
)
}
private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) {
callableExtStepFwd(ce2, ce1)
}
private int distSrcExt(TCallableExt c) =
shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result)
private int distSinkExt(TCallableExt c) =
shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result)
private int distSrc(DataFlowCallable c, Configuration config) {
result = distSrcExt(TCallable(c, config)) - 1
}
private int distSink(DataFlowCallable c, Configuration config) {
result = distSinkExt(TCallable(c, config)) - 1
}
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] }
@@ -2997,18 +3051,12 @@ private module FlowExploration {
or
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
}
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t))
}
}
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
@@ -3019,9 +3067,39 @@ private module FlowExploration {
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
}
override AccessPathFront getFront() {
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
private newtype TRevPartialAccessPath =
TRevPartialNil() or
TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] }
/**
* Conceptually a list of `Content`s, but only the first
* element of the list and its length are tracked.
*/
private class RevPartialAccessPath extends TRevPartialAccessPath {
abstract string toString();
Content getHead() { this = TRevPartialCons(result, _) }
int len() {
this = TRevPartialNil() and result = 0
or
this = TRevPartialCons(_, result)
}
}
private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil {
override string toString() { result = "" }
}
private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons {
override string toString() {
exists(Content c, int len | this = TRevPartialCons(c, len) |
if len = 1
then result = "[" + c.toString() + "]"
else result = "[" + c.toString() + ", ... (" + len.toString() + ")]"
)
}
}
@@ -3033,8 +3111,16 @@ private module FlowExploration {
TSummaryCtx2None() or
TSummaryCtx2Some(PartialAccessPath ap)
private newtype TRevSummaryCtx1 =
TRevSummaryCtx1None() or
TRevSummaryCtx1Some(ReturnPosition pos)
private newtype TRevSummaryCtx2 =
TRevSummaryCtx2None() or
TRevSummaryCtx2Some(RevPartialAccessPath ap)
private newtype TPartialPathNode =
TPartialPathNodeMk(
TPartialPathNodeFwd(
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
@@ -3048,6 +3134,23 @@ private module FlowExploration {
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
@@ -3055,7 +3158,7 @@ private module FlowExploration {
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNode mid |
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
@@ -3107,15 +3210,32 @@ private module FlowExploration {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
/**
* Gets the approximate distance to the nearest sink measured in number
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
exists(string s |
s = this.(PartialPathNodeFwd).getAp().toString() or
s = this.(PartialPathNodeRev).getAp().toString()
|
if s = "" then result = "" else result = " " + s
)
}
private string ppCtx() {
result = " <" + this.(PartialPathNodePriv).getCallContext().toString() + ">"
result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">"
}
/** Holds if this is a source in a forward-flow path. */
predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() }
/** Holds if this is a sink in a reverse-flow path. */
predicate isRevSink() { this.(PartialPathNodeRev).isSink() }
}
/**
@@ -3126,7 +3246,7 @@ private module FlowExploration {
query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b }
}
private class PartialPathNodePriv extends PartialPathNode {
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
Node node;
CallContext cc;
TSummaryCtx1 sc1;
@@ -3134,7 +3254,7 @@ private module FlowExploration {
PartialAccessPath ap;
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, sc1, sc2, ap, config) }
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
override Node getNode() { result = node }
@@ -3148,14 +3268,54 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodePriv getASuccessor() {
override PartialPathNodeFwd getASuccessor() {
partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
config.isSource(node) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap instanceof TPartialNil
}
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
Node node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
Configuration config;
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
override Node getNode() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
TRevSummaryCtx2 getSummaryCtx2() { result = sc2 }
RevPartialAccessPath getAp() { result = ap }
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
}
}
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
@@ -3221,8 +3381,7 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
) {
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
@@ -3238,7 +3397,7 @@ private module FlowExploration {
private predicate apConsFwd(
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
exists(PartialPathNodeFwd mid |
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
@@ -3246,7 +3405,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
exists(Node midNode |
@@ -3260,7 +3419,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable0(
PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
pos = getReturnPosition(mid.getNode()) and
@@ -3272,7 +3431,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc |
@@ -3286,7 +3445,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
@@ -3297,7 +3456,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(ArgumentNode arg |
@@ -3311,7 +3470,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
@@ -3319,7 +3478,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3340,7 +3499,7 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodePriv mid, ReturnNodeExt ret |
exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
mid.getNode() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -3353,7 +3512,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathThroughCallable0(
DataFlowCall call, PartialPathNodePriv mid, ReturnKindExt kind, CallContext cc,
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
@@ -3363,13 +3522,164 @@ private module FlowExploration {
}
private predicate partialPathThroughCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
out = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
localFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
jumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalJumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
revPartialPathReadStep(mid, _, _, node, ap) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(RevPartialAccessPath ap0, Content c |
revPartialPathStoreStep(mid, ap0, c, node, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsRev(ap, c, ap0, config)
)
or
exists(ParameterNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
pos = getReturnPosition(node)
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2()
}
pragma[inline]
private predicate revPartialPathReadStep(
PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
) {
exists(Node midNode |
midNode = mid.getNode() and
ap1 = mid.getAp() and
read(node, c, midNode) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
}
pragma[nomagic]
private predicate apConsRev(
RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodeRev mid |
revPartialPathReadStep(mid, ap1, c, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
) {
exists(Node midNode, TypedContent tc |
midNode = mid.getNode() and
ap = mid.getAp() and
store(node, tc, midNode, _) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
)
}
pragma[nomagic]
private predicate revPartialPathIntoReturn(
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
exists(Node out |
mid.getNode() = out and
viableReturnPosOut(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeRev mid, ParameterNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
revPartialPathIntoReturn(mid, _, sc1, sc2, call, _, config) and
revPartialPathFlowsThrough(pos, sc1, sc2, ap, config)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.argumentOf(call, pos)
)
}
}
import FlowExploration
@@ -3378,6 +3688,14 @@ private predicate partialFlow(
PartialPathNode source, PartialPathNode node, Configuration configuration
) {
source.getConfiguration() = configuration and
configuration.isSource(source.getNode()) and
source.isFwdSource() and
node = source.getASuccessor+()
}
private predicate revPartialFlow(
PartialPathNode node, PartialPathNode sink, Configuration configuration
) {
sink.getConfiguration() = configuration and
sink.isRevSink() and
node.getASuccessor+() = sink
}

View File

@@ -27,7 +27,7 @@ class VarArgsExpr extends BuiltInOperation, @var_args_expr { }
* __builtin_va_start(ap, last_named_param);
* ```
*/
class BuiltInVarArgsStart extends BuiltInOperation, @vastartexpr {
class BuiltInVarArgsStart extends VarArgsExpr, @vastartexpr {
override string toString() { result = "__builtin_va_start" }
override string getAPrimaryQlClass() { result = "BuiltInVarArgsStart" }
@@ -52,7 +52,7 @@ class BuiltInVarArgsStart extends BuiltInOperation, @vastartexpr {
* __builtin_va_end(ap);
* ```
*/
class BuiltInVarArgsEnd extends BuiltInOperation, @vaendexpr {
class BuiltInVarArgsEnd extends VarArgsExpr, @vaendexpr {
override string toString() { result = "__builtin_va_end" }
override string getAPrimaryQlClass() { result = "BuiltInVarArgsEnd" }
@@ -70,7 +70,7 @@ class BuiltInVarArgsEnd extends BuiltInOperation, @vaendexpr {
* ap = __builtin_va_arg(ap, long);
* ```
*/
class BuiltInVarArg extends BuiltInOperation, @vaargexpr {
class BuiltInVarArg extends VarArgsExpr, @vaargexpr {
override string toString() { result = "__builtin_va_arg" }
override string getAPrimaryQlClass() { result = "BuiltInVarArg" }
@@ -90,7 +90,7 @@ class BuiltInVarArg extends BuiltInOperation, @vaargexpr {
* va_copy(aq, ap);
* ```
*/
class BuiltInVarArgCopy extends BuiltInOperation, @vacopyexpr {
class BuiltInVarArgCopy extends VarArgsExpr, @vacopyexpr {
override string toString() { result = "__builtin_va_copy" }
override string getAPrimaryQlClass() { result = "BuiltInVarArgCopy" }

View File

@@ -840,6 +840,28 @@ class ArrayToPointerConversion extends Conversion, @array_to_pointer {
override predicate mayBeGloballyImpure() { none() }
}
/**
* A node representing a temporary object created as part of an expression.
*
* This is most commonly seen in the following cases:
* ```c++
* // when binding a reference to a prvalue
* const std::string& r = std::string("text");
*
* // when performing member access on a class prvalue
* strlen(std::string("text").c_str());
*
* // when a prvalue of a type with a destructor is discarded
* s.substr(0, 5); // Return value is discarded but requires destruction
* ```
*/
class TemporaryObjectExpr extends Conversion, @temp_init {
/** Gets a textual representation of this conversion. */
override string toString() { result = "temporary object" }
override string getAPrimaryQlClass() { result = "TemporaryObjectExpr" }
}
/**
* A node representing the Cast sub-class of entity `cast`.
*/

View File

@@ -83,7 +83,7 @@ private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
override predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
commonTaintStep(n1, n2)
}
override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
@@ -101,7 +101,7 @@ private class ToGlobalVarTaintTrackingCfg extends DataFlow::Configuration {
}
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
commonTaintStep(n1, n2)
or
writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable))
or
@@ -125,7 +125,7 @@ private class FromGlobalVarTaintTrackingCfg extends DataFlow2::Configuration {
override predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
commonTaintStep(n1, n2)
or
// Additional step for flow out of variables. There is no flow _into_
// variables in this configuration, so this step only serves to take flow
@@ -215,19 +215,62 @@ private predicate nodeIsBarrierIn(DataFlow::Node node) {
}
cached
private predicate instructionTaintStep(Instruction i1, Instruction i2) {
private predicate commonTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
instructionToInstructionTaintStep(fromNode.asInstruction(), toNode.asInstruction())
or
operandToInstructionTaintStep(fromNode.asOperand(), toNode.asInstruction())
or
operandToOperandTaintStep(fromNode.asOperand(), toNode.asOperand())
}
private predicate operandToOperandTaintStep(Operand fromOperand, Operand toOperand) {
exists(ReadSideEffectInstruction readInstr |
fromOperand = readInstr.getArgumentOperand() and
toOperand = readInstr.getSideEffectOperand()
)
}
private predicate operandToInstructionTaintStep(Operand fromOperand, Instruction toInstr) {
// Expressions computed from tainted data are also tainted
exists(CallInstruction call, int argIndex | call = i2 |
exists(CallInstruction call, int argIndex | call = toInstr |
isPureFunction(call.getStaticCallTarget().getName()) and
i1 = getACallArgumentOrIndirection(call, argIndex) and
forall(Instruction arg | arg = call.getAnArgument() |
arg = getACallArgumentOrIndirection(call, argIndex) or predictableInstruction(arg)
fromOperand = getACallArgumentOrIndirection(call, argIndex) and
forall(Operand argOperand | argOperand = call.getAnArgumentOperand() |
argOperand = getACallArgumentOrIndirection(call, argIndex) or
predictableInstruction(argOperand.getAnyDef())
) and
// flow through `strlen` tends to cause dubious results, if the length is
// bounded.
not call.getStaticCallTarget().getName() = "strlen"
)
or
// Flow from argument to return value
toInstr =
any(CallInstruction call |
exists(int indexIn |
modelTaintToReturnValue(call.getStaticCallTarget(), indexIn) and
fromOperand = getACallArgumentOrIndirection(call, indexIn) and
not predictableOnlyFlow(call.getStaticCallTarget().getName())
)
)
or
// Flow from input argument to output argument
// TODO: This won't work in practice as long as all aliased memory is tracked
// together in a single virtual variable.
// TODO: Will this work on the test for `TaintedPath.ql`, where the output arg
// is a pointer addition expression?
toInstr =
any(WriteSideEffectInstruction outInstr |
exists(CallInstruction call, int indexIn, int indexOut |
modelTaintToParameter(call.getStaticCallTarget(), indexIn, indexOut) and
fromOperand = getACallArgumentOrIndirection(call, indexIn) and
outInstr.getIndex() = indexOut and
outInstr.getPrimaryInstruction() = call
)
)
}
private predicate instructionToInstructionTaintStep(Instruction i1, Instruction i2) {
// Flow through pointer dereference
i2.(LoadInstruction).getSourceAddress() = i1
or
@@ -291,31 +334,6 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
read.getAnOperand().(SideEffectOperand).getAnyDef() = i1 and
read.getArgumentDef() = i2
)
or
// Flow from argument to return value
i2 =
any(CallInstruction call |
exists(int indexIn |
modelTaintToReturnValue(call.getStaticCallTarget(), indexIn) and
i1 = getACallArgumentOrIndirection(call, indexIn) and
not predictableOnlyFlow(call.getStaticCallTarget().getName())
)
)
or
// Flow from input argument to output argument
// TODO: This won't work in practice as long as all aliased memory is tracked
// together in a single virtual variable.
// TODO: Will this work on the test for `TaintedPath.ql`, where the output arg
// is a pointer addition expression?
i2 =
any(WriteSideEffectInstruction outNode |
exists(CallInstruction call, int indexIn, int indexOut |
modelTaintToParameter(call.getStaticCallTarget(), indexIn, indexOut) and
i1 = getACallArgumentOrIndirection(call, indexIn) and
outNode.getIndex() = indexOut and
outNode.getPrimaryInstruction() = call
)
)
}
pragma[noinline]
@@ -331,15 +349,25 @@ private InitializeParameterInstruction getInitializeParameter(IRFunction f, Para
}
/**
* Get an instruction that goes into argument `argumentIndex` of `call`. This
* Returns the index of the side effect instruction corresponding to the specified function output,
* if one exists.
*/
private int getWriteSideEffectIndex(FunctionOutput output) {
output.isParameterDeref(result)
or
output.isQualifierObject() and result = -1
}
/**
* Get an operand that goes into argument `argumentIndex` of `call`. This
* can be either directly or through one pointer indirection.
*/
private Instruction getACallArgumentOrIndirection(CallInstruction call, int argumentIndex) {
result = call.getPositionalArgument(argumentIndex)
private Operand getACallArgumentOrIndirection(CallInstruction call, int argumentIndex) {
result = call.getPositionalArgumentOperand(argumentIndex)
or
exists(ReadSideEffectInstruction readSE |
// TODO: why are read side effect operands imprecise?
result = readSE.getSideEffectOperand().getAnyDef() and
result = readSE.getSideEffectOperand() and
readSE.getPrimaryInstruction() = call and
readSE.getIndex() = argumentIndex
)
@@ -353,7 +381,7 @@ private predicate modelTaintToParameter(Function f, int parameterIn, int paramet
f.(TaintFunction).hasTaintFlow(modelIn, modelOut)
) and
(modelIn.isParameter(parameterIn) or modelIn.isParameterDeref(parameterIn)) and
modelOut.isParameterDeref(parameterOut)
parameterOut = getWriteSideEffectIndex(modelOut)
)
}
@@ -542,7 +570,7 @@ module TaintedWithPath {
}
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
commonTaintStep(n1, n2)
or
exists(TaintTrackingConfiguration cfg | cfg.taintThroughGlobals() |
writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable))

View File

@@ -112,8 +112,8 @@ abstract class Configuration extends string {
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` measured in approximate
* number of interprocedural steps.
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
int explorationLimit() { none() }
@@ -123,7 +123,7 @@ abstract class Configuration extends string {
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards sink definitions.
*
* This predicate is intended for dataflow exploration and debugging and may
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sources is too big and/or the exploration
* limit is set too high without using barriers.
*
@@ -136,6 +136,29 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/**
* Holds if there is a partial data flow path from `node` to `sink`. The
* approximate distance between `node` and the closest sink is `dist` and
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards source definitions.
*
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sinks is too big and/or the exploration
* limit is set too high without using barriers.
*
* This predicate is disabled (has no results) by default. Override
* `explorationLimit()` with a suitable number to enable this predicate.
*
* To use this in a `path-problem` query, import the module `PartialPathGraph`.
*
* Note that reverse flow has slightly lower precision than the corresponding
* forward flow, as reverse flow disregards type pruning among other features.
*/
final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
revPartialFlow(node, sink, this) and
dist = node.getSinkDistance()
}
}
/**
@@ -2943,12 +2966,26 @@ private module FlowExploration {
)
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
)
}
private newtype TCallableExt =
TCallable(DataFlowCallable c, Configuration config) { interestingCallableSrc(c, config) } or
TCallableSrc()
TCallable(DataFlowCallable c, Configuration config) {
interestingCallableSrc(c, config) or
interestingCallableSink(c, config)
} or
TCallableSrc() or
TCallableSink()
private predicate callableExtSrc(TCallableSrc src) { any() }
private predicate callableExtSink(TCallableSink sink) { any() }
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
@@ -2961,15 +2998,32 @@ private module FlowExploration {
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
)
}
private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) {
callableExtStepFwd(ce2, ce1)
}
private int distSrcExt(TCallableExt c) =
shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result)
private int distSinkExt(TCallableExt c) =
shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result)
private int distSrc(DataFlowCallable c, Configuration config) {
result = distSrcExt(TCallable(c, config)) - 1
}
private int distSink(DataFlowCallable c, Configuration config) {
result = distSinkExt(TCallable(c, config)) - 1
}
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] }
@@ -2997,18 +3051,12 @@ private module FlowExploration {
or
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
}
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t))
}
}
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
@@ -3019,9 +3067,39 @@ private module FlowExploration {
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
}
override AccessPathFront getFront() {
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
private newtype TRevPartialAccessPath =
TRevPartialNil() or
TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] }
/**
* Conceptually a list of `Content`s, but only the first
* element of the list and its length are tracked.
*/
private class RevPartialAccessPath extends TRevPartialAccessPath {
abstract string toString();
Content getHead() { this = TRevPartialCons(result, _) }
int len() {
this = TRevPartialNil() and result = 0
or
this = TRevPartialCons(_, result)
}
}
private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil {
override string toString() { result = "" }
}
private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons {
override string toString() {
exists(Content c, int len | this = TRevPartialCons(c, len) |
if len = 1
then result = "[" + c.toString() + "]"
else result = "[" + c.toString() + ", ... (" + len.toString() + ")]"
)
}
}
@@ -3033,8 +3111,16 @@ private module FlowExploration {
TSummaryCtx2None() or
TSummaryCtx2Some(PartialAccessPath ap)
private newtype TRevSummaryCtx1 =
TRevSummaryCtx1None() or
TRevSummaryCtx1Some(ReturnPosition pos)
private newtype TRevSummaryCtx2 =
TRevSummaryCtx2None() or
TRevSummaryCtx2Some(RevPartialAccessPath ap)
private newtype TPartialPathNode =
TPartialPathNodeMk(
TPartialPathNodeFwd(
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
@@ -3048,6 +3134,23 @@ private module FlowExploration {
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
@@ -3055,7 +3158,7 @@ private module FlowExploration {
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNode mid |
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
@@ -3107,15 +3210,32 @@ private module FlowExploration {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
/**
* Gets the approximate distance to the nearest sink measured in number
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
exists(string s |
s = this.(PartialPathNodeFwd).getAp().toString() or
s = this.(PartialPathNodeRev).getAp().toString()
|
if s = "" then result = "" else result = " " + s
)
}
private string ppCtx() {
result = " <" + this.(PartialPathNodePriv).getCallContext().toString() + ">"
result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">"
}
/** Holds if this is a source in a forward-flow path. */
predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() }
/** Holds if this is a sink in a reverse-flow path. */
predicate isRevSink() { this.(PartialPathNodeRev).isSink() }
}
/**
@@ -3126,7 +3246,7 @@ private module FlowExploration {
query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b }
}
private class PartialPathNodePriv extends PartialPathNode {
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
Node node;
CallContext cc;
TSummaryCtx1 sc1;
@@ -3134,7 +3254,7 @@ private module FlowExploration {
PartialAccessPath ap;
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, sc1, sc2, ap, config) }
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
override Node getNode() { result = node }
@@ -3148,14 +3268,54 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodePriv getASuccessor() {
override PartialPathNodeFwd getASuccessor() {
partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
config.isSource(node) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap instanceof TPartialNil
}
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
Node node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
Configuration config;
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
override Node getNode() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
TRevSummaryCtx2 getSummaryCtx2() { result = sc2 }
RevPartialAccessPath getAp() { result = ap }
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
}
}
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
@@ -3221,8 +3381,7 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
) {
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
@@ -3238,7 +3397,7 @@ private module FlowExploration {
private predicate apConsFwd(
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
exists(PartialPathNodeFwd mid |
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
@@ -3246,7 +3405,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
exists(Node midNode |
@@ -3260,7 +3419,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable0(
PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
pos = getReturnPosition(mid.getNode()) and
@@ -3272,7 +3431,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc |
@@ -3286,7 +3445,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
@@ -3297,7 +3456,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(ArgumentNode arg |
@@ -3311,7 +3470,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
@@ -3319,7 +3478,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3340,7 +3499,7 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodePriv mid, ReturnNodeExt ret |
exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
mid.getNode() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -3353,7 +3512,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathThroughCallable0(
DataFlowCall call, PartialPathNodePriv mid, ReturnKindExt kind, CallContext cc,
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
@@ -3363,13 +3522,164 @@ private module FlowExploration {
}
private predicate partialPathThroughCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
out = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
localFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
jumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalJumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
revPartialPathReadStep(mid, _, _, node, ap) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(RevPartialAccessPath ap0, Content c |
revPartialPathStoreStep(mid, ap0, c, node, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsRev(ap, c, ap0, config)
)
or
exists(ParameterNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
pos = getReturnPosition(node)
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2()
}
pragma[inline]
private predicate revPartialPathReadStep(
PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
) {
exists(Node midNode |
midNode = mid.getNode() and
ap1 = mid.getAp() and
read(node, c, midNode) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
}
pragma[nomagic]
private predicate apConsRev(
RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodeRev mid |
revPartialPathReadStep(mid, ap1, c, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
) {
exists(Node midNode, TypedContent tc |
midNode = mid.getNode() and
ap = mid.getAp() and
store(node, tc, midNode, _) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
)
}
pragma[nomagic]
private predicate revPartialPathIntoReturn(
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
exists(Node out |
mid.getNode() = out and
viableReturnPosOut(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeRev mid, ParameterNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
revPartialPathIntoReturn(mid, _, sc1, sc2, call, _, config) and
revPartialPathFlowsThrough(pos, sc1, sc2, ap, config)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.argumentOf(call, pos)
)
}
}
import FlowExploration
@@ -3378,6 +3688,14 @@ private predicate partialFlow(
PartialPathNode source, PartialPathNode node, Configuration configuration
) {
source.getConfiguration() = configuration and
configuration.isSource(source.getNode()) and
source.isFwdSource() and
node = source.getASuccessor+()
}
private predicate revPartialFlow(
PartialPathNode node, PartialPathNode sink, Configuration configuration
) {
sink.getConfiguration() = configuration and
sink.isRevSink() and
node.getASuccessor+() = sink
}

View File

@@ -112,8 +112,8 @@ abstract class Configuration extends string {
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` measured in approximate
* number of interprocedural steps.
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
int explorationLimit() { none() }
@@ -123,7 +123,7 @@ abstract class Configuration extends string {
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards sink definitions.
*
* This predicate is intended for dataflow exploration and debugging and may
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sources is too big and/or the exploration
* limit is set too high without using barriers.
*
@@ -136,6 +136,29 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/**
* Holds if there is a partial data flow path from `node` to `sink`. The
* approximate distance between `node` and the closest sink is `dist` and
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards source definitions.
*
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sinks is too big and/or the exploration
* limit is set too high without using barriers.
*
* This predicate is disabled (has no results) by default. Override
* `explorationLimit()` with a suitable number to enable this predicate.
*
* To use this in a `path-problem` query, import the module `PartialPathGraph`.
*
* Note that reverse flow has slightly lower precision than the corresponding
* forward flow, as reverse flow disregards type pruning among other features.
*/
final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
revPartialFlow(node, sink, this) and
dist = node.getSinkDistance()
}
}
/**
@@ -2943,12 +2966,26 @@ private module FlowExploration {
)
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
)
}
private newtype TCallableExt =
TCallable(DataFlowCallable c, Configuration config) { interestingCallableSrc(c, config) } or
TCallableSrc()
TCallable(DataFlowCallable c, Configuration config) {
interestingCallableSrc(c, config) or
interestingCallableSink(c, config)
} or
TCallableSrc() or
TCallableSink()
private predicate callableExtSrc(TCallableSrc src) { any() }
private predicate callableExtSink(TCallableSink sink) { any() }
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
@@ -2961,15 +2998,32 @@ private module FlowExploration {
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
)
}
private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) {
callableExtStepFwd(ce2, ce1)
}
private int distSrcExt(TCallableExt c) =
shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result)
private int distSinkExt(TCallableExt c) =
shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result)
private int distSrc(DataFlowCallable c, Configuration config) {
result = distSrcExt(TCallable(c, config)) - 1
}
private int distSink(DataFlowCallable c, Configuration config) {
result = distSinkExt(TCallable(c, config)) - 1
}
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] }
@@ -2997,18 +3051,12 @@ private module FlowExploration {
or
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
}
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t))
}
}
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
@@ -3019,9 +3067,39 @@ private module FlowExploration {
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
}
override AccessPathFront getFront() {
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
private newtype TRevPartialAccessPath =
TRevPartialNil() or
TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] }
/**
* Conceptually a list of `Content`s, but only the first
* element of the list and its length are tracked.
*/
private class RevPartialAccessPath extends TRevPartialAccessPath {
abstract string toString();
Content getHead() { this = TRevPartialCons(result, _) }
int len() {
this = TRevPartialNil() and result = 0
or
this = TRevPartialCons(_, result)
}
}
private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil {
override string toString() { result = "" }
}
private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons {
override string toString() {
exists(Content c, int len | this = TRevPartialCons(c, len) |
if len = 1
then result = "[" + c.toString() + "]"
else result = "[" + c.toString() + ", ... (" + len.toString() + ")]"
)
}
}
@@ -3033,8 +3111,16 @@ private module FlowExploration {
TSummaryCtx2None() or
TSummaryCtx2Some(PartialAccessPath ap)
private newtype TRevSummaryCtx1 =
TRevSummaryCtx1None() or
TRevSummaryCtx1Some(ReturnPosition pos)
private newtype TRevSummaryCtx2 =
TRevSummaryCtx2None() or
TRevSummaryCtx2Some(RevPartialAccessPath ap)
private newtype TPartialPathNode =
TPartialPathNodeMk(
TPartialPathNodeFwd(
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
@@ -3048,6 +3134,23 @@ private module FlowExploration {
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
@@ -3055,7 +3158,7 @@ private module FlowExploration {
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNode mid |
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
@@ -3107,15 +3210,32 @@ private module FlowExploration {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
/**
* Gets the approximate distance to the nearest sink measured in number
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
exists(string s |
s = this.(PartialPathNodeFwd).getAp().toString() or
s = this.(PartialPathNodeRev).getAp().toString()
|
if s = "" then result = "" else result = " " + s
)
}
private string ppCtx() {
result = " <" + this.(PartialPathNodePriv).getCallContext().toString() + ">"
result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">"
}
/** Holds if this is a source in a forward-flow path. */
predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() }
/** Holds if this is a sink in a reverse-flow path. */
predicate isRevSink() { this.(PartialPathNodeRev).isSink() }
}
/**
@@ -3126,7 +3246,7 @@ private module FlowExploration {
query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b }
}
private class PartialPathNodePriv extends PartialPathNode {
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
Node node;
CallContext cc;
TSummaryCtx1 sc1;
@@ -3134,7 +3254,7 @@ private module FlowExploration {
PartialAccessPath ap;
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, sc1, sc2, ap, config) }
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
override Node getNode() { result = node }
@@ -3148,14 +3268,54 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodePriv getASuccessor() {
override PartialPathNodeFwd getASuccessor() {
partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
config.isSource(node) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap instanceof TPartialNil
}
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
Node node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
Configuration config;
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
override Node getNode() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
TRevSummaryCtx2 getSummaryCtx2() { result = sc2 }
RevPartialAccessPath getAp() { result = ap }
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
}
}
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
@@ -3221,8 +3381,7 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
) {
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
@@ -3238,7 +3397,7 @@ private module FlowExploration {
private predicate apConsFwd(
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
exists(PartialPathNodeFwd mid |
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
@@ -3246,7 +3405,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
exists(Node midNode |
@@ -3260,7 +3419,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable0(
PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
pos = getReturnPosition(mid.getNode()) and
@@ -3272,7 +3431,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc |
@@ -3286,7 +3445,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
@@ -3297,7 +3456,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(ArgumentNode arg |
@@ -3311,7 +3470,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
@@ -3319,7 +3478,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3340,7 +3499,7 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodePriv mid, ReturnNodeExt ret |
exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
mid.getNode() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -3353,7 +3512,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathThroughCallable0(
DataFlowCall call, PartialPathNodePriv mid, ReturnKindExt kind, CallContext cc,
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
@@ -3363,13 +3522,164 @@ private module FlowExploration {
}
private predicate partialPathThroughCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
out = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
localFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
jumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalJumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
revPartialPathReadStep(mid, _, _, node, ap) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(RevPartialAccessPath ap0, Content c |
revPartialPathStoreStep(mid, ap0, c, node, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsRev(ap, c, ap0, config)
)
or
exists(ParameterNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
pos = getReturnPosition(node)
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2()
}
pragma[inline]
private predicate revPartialPathReadStep(
PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
) {
exists(Node midNode |
midNode = mid.getNode() and
ap1 = mid.getAp() and
read(node, c, midNode) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
}
pragma[nomagic]
private predicate apConsRev(
RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodeRev mid |
revPartialPathReadStep(mid, ap1, c, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
) {
exists(Node midNode, TypedContent tc |
midNode = mid.getNode() and
ap = mid.getAp() and
store(node, tc, midNode, _) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
)
}
pragma[nomagic]
private predicate revPartialPathIntoReturn(
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
exists(Node out |
mid.getNode() = out and
viableReturnPosOut(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeRev mid, ParameterNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
revPartialPathIntoReturn(mid, _, sc1, sc2, call, _, config) and
revPartialPathFlowsThrough(pos, sc1, sc2, ap, config)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.argumentOf(call, pos)
)
}
}
import FlowExploration
@@ -3378,6 +3688,14 @@ private predicate partialFlow(
PartialPathNode source, PartialPathNode node, Configuration configuration
) {
source.getConfiguration() = configuration and
configuration.isSource(source.getNode()) and
source.isFwdSource() and
node = source.getASuccessor+()
}
private predicate revPartialFlow(
PartialPathNode node, PartialPathNode sink, Configuration configuration
) {
sink.getConfiguration() = configuration and
sink.isRevSink() and
node.getASuccessor+() = sink
}

View File

@@ -112,8 +112,8 @@ abstract class Configuration extends string {
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` measured in approximate
* number of interprocedural steps.
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
int explorationLimit() { none() }
@@ -123,7 +123,7 @@ abstract class Configuration extends string {
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards sink definitions.
*
* This predicate is intended for dataflow exploration and debugging and may
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sources is too big and/or the exploration
* limit is set too high without using barriers.
*
@@ -136,6 +136,29 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/**
* Holds if there is a partial data flow path from `node` to `sink`. The
* approximate distance between `node` and the closest sink is `dist` and
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards source definitions.
*
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sinks is too big and/or the exploration
* limit is set too high without using barriers.
*
* This predicate is disabled (has no results) by default. Override
* `explorationLimit()` with a suitable number to enable this predicate.
*
* To use this in a `path-problem` query, import the module `PartialPathGraph`.
*
* Note that reverse flow has slightly lower precision than the corresponding
* forward flow, as reverse flow disregards type pruning among other features.
*/
final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
revPartialFlow(node, sink, this) and
dist = node.getSinkDistance()
}
}
/**
@@ -2943,12 +2966,26 @@ private module FlowExploration {
)
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
)
}
private newtype TCallableExt =
TCallable(DataFlowCallable c, Configuration config) { interestingCallableSrc(c, config) } or
TCallableSrc()
TCallable(DataFlowCallable c, Configuration config) {
interestingCallableSrc(c, config) or
interestingCallableSink(c, config)
} or
TCallableSrc() or
TCallableSink()
private predicate callableExtSrc(TCallableSrc src) { any() }
private predicate callableExtSink(TCallableSink sink) { any() }
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
@@ -2961,15 +2998,32 @@ private module FlowExploration {
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
)
}
private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) {
callableExtStepFwd(ce2, ce1)
}
private int distSrcExt(TCallableExt c) =
shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result)
private int distSinkExt(TCallableExt c) =
shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result)
private int distSrc(DataFlowCallable c, Configuration config) {
result = distSrcExt(TCallable(c, config)) - 1
}
private int distSink(DataFlowCallable c, Configuration config) {
result = distSinkExt(TCallable(c, config)) - 1
}
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] }
@@ -2997,18 +3051,12 @@ private module FlowExploration {
or
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
}
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t))
}
}
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
@@ -3019,9 +3067,39 @@ private module FlowExploration {
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
}
override AccessPathFront getFront() {
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
private newtype TRevPartialAccessPath =
TRevPartialNil() or
TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] }
/**
* Conceptually a list of `Content`s, but only the first
* element of the list and its length are tracked.
*/
private class RevPartialAccessPath extends TRevPartialAccessPath {
abstract string toString();
Content getHead() { this = TRevPartialCons(result, _) }
int len() {
this = TRevPartialNil() and result = 0
or
this = TRevPartialCons(_, result)
}
}
private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil {
override string toString() { result = "" }
}
private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons {
override string toString() {
exists(Content c, int len | this = TRevPartialCons(c, len) |
if len = 1
then result = "[" + c.toString() + "]"
else result = "[" + c.toString() + ", ... (" + len.toString() + ")]"
)
}
}
@@ -3033,8 +3111,16 @@ private module FlowExploration {
TSummaryCtx2None() or
TSummaryCtx2Some(PartialAccessPath ap)
private newtype TRevSummaryCtx1 =
TRevSummaryCtx1None() or
TRevSummaryCtx1Some(ReturnPosition pos)
private newtype TRevSummaryCtx2 =
TRevSummaryCtx2None() or
TRevSummaryCtx2Some(RevPartialAccessPath ap)
private newtype TPartialPathNode =
TPartialPathNodeMk(
TPartialPathNodeFwd(
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
@@ -3048,6 +3134,23 @@ private module FlowExploration {
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
@@ -3055,7 +3158,7 @@ private module FlowExploration {
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNode mid |
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
@@ -3107,15 +3210,32 @@ private module FlowExploration {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
/**
* Gets the approximate distance to the nearest sink measured in number
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
exists(string s |
s = this.(PartialPathNodeFwd).getAp().toString() or
s = this.(PartialPathNodeRev).getAp().toString()
|
if s = "" then result = "" else result = " " + s
)
}
private string ppCtx() {
result = " <" + this.(PartialPathNodePriv).getCallContext().toString() + ">"
result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">"
}
/** Holds if this is a source in a forward-flow path. */
predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() }
/** Holds if this is a sink in a reverse-flow path. */
predicate isRevSink() { this.(PartialPathNodeRev).isSink() }
}
/**
@@ -3126,7 +3246,7 @@ private module FlowExploration {
query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b }
}
private class PartialPathNodePriv extends PartialPathNode {
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
Node node;
CallContext cc;
TSummaryCtx1 sc1;
@@ -3134,7 +3254,7 @@ private module FlowExploration {
PartialAccessPath ap;
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, sc1, sc2, ap, config) }
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
override Node getNode() { result = node }
@@ -3148,14 +3268,54 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodePriv getASuccessor() {
override PartialPathNodeFwd getASuccessor() {
partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
config.isSource(node) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap instanceof TPartialNil
}
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
Node node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
Configuration config;
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
override Node getNode() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
TRevSummaryCtx2 getSummaryCtx2() { result = sc2 }
RevPartialAccessPath getAp() { result = ap }
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
}
}
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
@@ -3221,8 +3381,7 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
) {
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
@@ -3238,7 +3397,7 @@ private module FlowExploration {
private predicate apConsFwd(
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
exists(PartialPathNodeFwd mid |
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
@@ -3246,7 +3405,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
exists(Node midNode |
@@ -3260,7 +3419,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable0(
PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
pos = getReturnPosition(mid.getNode()) and
@@ -3272,7 +3431,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc |
@@ -3286,7 +3445,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
@@ -3297,7 +3456,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(ArgumentNode arg |
@@ -3311,7 +3470,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
@@ -3319,7 +3478,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3340,7 +3499,7 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodePriv mid, ReturnNodeExt ret |
exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
mid.getNode() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -3353,7 +3512,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathThroughCallable0(
DataFlowCall call, PartialPathNodePriv mid, ReturnKindExt kind, CallContext cc,
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
@@ -3363,13 +3522,164 @@ private module FlowExploration {
}
private predicate partialPathThroughCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
out = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
localFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
jumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalJumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
revPartialPathReadStep(mid, _, _, node, ap) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(RevPartialAccessPath ap0, Content c |
revPartialPathStoreStep(mid, ap0, c, node, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsRev(ap, c, ap0, config)
)
or
exists(ParameterNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
pos = getReturnPosition(node)
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2()
}
pragma[inline]
private predicate revPartialPathReadStep(
PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
) {
exists(Node midNode |
midNode = mid.getNode() and
ap1 = mid.getAp() and
read(node, c, midNode) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
}
pragma[nomagic]
private predicate apConsRev(
RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodeRev mid |
revPartialPathReadStep(mid, ap1, c, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
) {
exists(Node midNode, TypedContent tc |
midNode = mid.getNode() and
ap = mid.getAp() and
store(node, tc, midNode, _) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
)
}
pragma[nomagic]
private predicate revPartialPathIntoReturn(
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
exists(Node out |
mid.getNode() = out and
viableReturnPosOut(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeRev mid, ParameterNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
revPartialPathIntoReturn(mid, _, sc1, sc2, call, _, config) and
revPartialPathFlowsThrough(pos, sc1, sc2, ap, config)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.argumentOf(call, pos)
)
}
}
import FlowExploration
@@ -3378,6 +3688,14 @@ private predicate partialFlow(
PartialPathNode source, PartialPathNode node, Configuration configuration
) {
source.getConfiguration() = configuration and
configuration.isSource(source.getNode()) and
source.isFwdSource() and
node = source.getASuccessor+()
}
private predicate revPartialFlow(
PartialPathNode node, PartialPathNode sink, Configuration configuration
) {
sink.getConfiguration() = configuration and
sink.isRevSink() and
node.getASuccessor+() = sink
}

View File

@@ -112,8 +112,8 @@ abstract class Configuration extends string {
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` measured in approximate
* number of interprocedural steps.
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
int explorationLimit() { none() }
@@ -123,7 +123,7 @@ abstract class Configuration extends string {
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards sink definitions.
*
* This predicate is intended for dataflow exploration and debugging and may
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sources is too big and/or the exploration
* limit is set too high without using barriers.
*
@@ -136,6 +136,29 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and
dist = node.getSourceDistance()
}
/**
* Holds if there is a partial data flow path from `node` to `sink`. The
* approximate distance between `node` and the closest sink is `dist` and
* is restricted to be less than or equal to `explorationLimit()`. This
* predicate completely disregards source definitions.
*
* This predicate is intended for data-flow exploration and debugging and may
* perform poorly if the number of sinks is too big and/or the exploration
* limit is set too high without using barriers.
*
* This predicate is disabled (has no results) by default. Override
* `explorationLimit()` with a suitable number to enable this predicate.
*
* To use this in a `path-problem` query, import the module `PartialPathGraph`.
*
* Note that reverse flow has slightly lower precision than the corresponding
* forward flow, as reverse flow disregards type pruning among other features.
*/
final predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
revPartialFlow(node, sink, this) and
dist = node.getSinkDistance()
}
}
/**
@@ -2943,12 +2966,26 @@ private module FlowExploration {
)
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
)
}
private newtype TCallableExt =
TCallable(DataFlowCallable c, Configuration config) { interestingCallableSrc(c, config) } or
TCallableSrc()
TCallable(DataFlowCallable c, Configuration config) {
interestingCallableSrc(c, config) or
interestingCallableSink(c, config)
} or
TCallableSrc() or
TCallableSink()
private predicate callableExtSrc(TCallableSrc src) { any() }
private predicate callableExtSink(TCallableSink sink) { any() }
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
@@ -2961,15 +2998,32 @@ private module FlowExploration {
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
)
}
private predicate callableExtStepRev(TCallableExt ce1, TCallableExt ce2) {
callableExtStepFwd(ce2, ce1)
}
private int distSrcExt(TCallableExt c) =
shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result)
private int distSinkExt(TCallableExt c) =
shortestDistances(callableExtSink/1, callableExtStepRev/2)(_, c, result)
private int distSrc(DataFlowCallable c, Configuration config) {
result = distSrcExt(TCallable(c, config)) - 1
}
private int distSink(DataFlowCallable c, Configuration config) {
result = distSinkExt(TCallable(c, config)) - 1
}
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] }
@@ -2997,18 +3051,12 @@ private module FlowExploration {
or
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
}
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t))
}
}
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
@@ -3019,9 +3067,39 @@ private module FlowExploration {
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
}
override AccessPathFront getFront() {
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
private newtype TRevPartialAccessPath =
TRevPartialNil() or
TRevPartialCons(Content c, int len) { len in [1 .. accessPathLimit()] }
/**
* Conceptually a list of `Content`s, but only the first
* element of the list and its length are tracked.
*/
private class RevPartialAccessPath extends TRevPartialAccessPath {
abstract string toString();
Content getHead() { this = TRevPartialCons(result, _) }
int len() {
this = TRevPartialNil() and result = 0
or
this = TRevPartialCons(_, result)
}
}
private class RevPartialAccessPathNil extends RevPartialAccessPath, TRevPartialNil {
override string toString() { result = "" }
}
private class RevPartialAccessPathCons extends RevPartialAccessPath, TRevPartialCons {
override string toString() {
exists(Content c, int len | this = TRevPartialCons(c, len) |
if len = 1
then result = "[" + c.toString() + "]"
else result = "[" + c.toString() + ", ... (" + len.toString() + ")]"
)
}
}
@@ -3033,8 +3111,16 @@ private module FlowExploration {
TSummaryCtx2None() or
TSummaryCtx2Some(PartialAccessPath ap)
private newtype TRevSummaryCtx1 =
TRevSummaryCtx1None() or
TRevSummaryCtx1Some(ReturnPosition pos)
private newtype TRevSummaryCtx2 =
TRevSummaryCtx2None() or
TRevSummaryCtx2Some(RevPartialAccessPath ap)
private newtype TPartialPathNode =
TPartialPathNodeMk(
TPartialPathNodeFwd(
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
@@ -3048,6 +3134,23 @@ private module FlowExploration {
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
Configuration config
) {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil() and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
}
pragma[nomagic]
@@ -3055,7 +3158,7 @@ private module FlowExploration {
Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap,
Configuration config
) {
exists(PartialPathNode mid |
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
@@ -3107,15 +3210,32 @@ private module FlowExploration {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
/**
* Gets the approximate distance to the nearest sink measured in number
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
}
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
exists(string s |
s = this.(PartialPathNodeFwd).getAp().toString() or
s = this.(PartialPathNodeRev).getAp().toString()
|
if s = "" then result = "" else result = " " + s
)
}
private string ppCtx() {
result = " <" + this.(PartialPathNodePriv).getCallContext().toString() + ">"
result = " <" + this.(PartialPathNodeFwd).getCallContext().toString() + ">"
}
/** Holds if this is a source in a forward-flow path. */
predicate isFwdSource() { this.(PartialPathNodeFwd).isSource() }
/** Holds if this is a sink in a reverse-flow path. */
predicate isRevSink() { this.(PartialPathNodeRev).isSink() }
}
/**
@@ -3126,7 +3246,7 @@ private module FlowExploration {
query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b }
}
private class PartialPathNodePriv extends PartialPathNode {
private class PartialPathNodeFwd extends PartialPathNode, TPartialPathNodeFwd {
Node node;
CallContext cc;
TSummaryCtx1 sc1;
@@ -3134,7 +3254,7 @@ private module FlowExploration {
PartialAccessPath ap;
Configuration config;
PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, sc1, sc2, ap, config) }
PartialPathNodeFwd() { this = TPartialPathNodeFwd(node, cc, sc1, sc2, ap, config) }
override Node getNode() { result = node }
@@ -3148,14 +3268,54 @@ private module FlowExploration {
override Configuration getConfiguration() { result = config }
override PartialPathNodePriv getASuccessor() {
override PartialPathNodeFwd getASuccessor() {
partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(),
result.getSummaryCtx2(), result.getAp(), result.getConfiguration())
}
predicate isSource() {
config.isSource(node) and
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap instanceof TPartialNil
}
}
private class PartialPathNodeRev extends PartialPathNode, TPartialPathNodeRev {
Node node;
TRevSummaryCtx1 sc1;
TRevSummaryCtx2 sc2;
RevPartialAccessPath ap;
Configuration config;
PartialPathNodeRev() { this = TPartialPathNodeRev(node, sc1, sc2, ap, config) }
override Node getNode() { result = node }
TRevSummaryCtx1 getSummaryCtx1() { result = sc1 }
TRevSummaryCtx2 getSummaryCtx2() { result = sc2 }
RevPartialAccessPath getAp() { result = ap }
override Configuration getConfiguration() { result = config }
override PartialPathNodeRev getASuccessor() {
revPartialPathStep(result, this.getNode(), this.getSummaryCtx1(), this.getSummaryCtx2(),
this.getAp(), this.getConfiguration())
}
predicate isSink() {
config.isSink(node) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = TRevPartialNil()
}
}
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
@@ -3221,8 +3381,7 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2
) {
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
@@ -3238,7 +3397,7 @@ private module FlowExploration {
private predicate apConsFwd(
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
exists(PartialPathNodeFwd mid |
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
@@ -3246,7 +3405,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
exists(Node midNode |
@@ -3260,7 +3419,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable0(
PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
PartialPathNodeFwd mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap,
Configuration config
) {
pos = getReturnPosition(mid.getNode()) and
@@ -3272,7 +3431,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathOutOfCallable1(
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialPathNodeFwd mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc |
@@ -3286,7 +3445,7 @@ private module FlowExploration {
}
private predicate partialPathOutOfCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(ReturnKindExt kind, DataFlowCall call |
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
@@ -3297,7 +3456,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathIntoArg(
PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(ArgumentNode arg |
@@ -3311,7 +3470,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate partialPathIntoCallable0(
PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc,
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
DataFlowCall call, PartialAccessPath ap, Configuration config
) {
partialPathIntoArg(mid, i, outercc, call, ap, config) and
@@ -3319,7 +3478,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3340,7 +3499,7 @@ private module FlowExploration {
ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodePriv mid, ReturnNodeExt ret |
exists(PartialPathNodeFwd mid, ReturnNodeExt ret |
mid.getNode() = ret and
kind = ret.getKind() and
cc = mid.getCallContext() and
@@ -3353,7 +3512,7 @@ private module FlowExploration {
pragma[noinline]
private predicate partialPathThroughCallable0(
DataFlowCall call, PartialPathNodePriv mid, ReturnKindExt kind, CallContext cc,
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
@@ -3363,13 +3522,164 @@ private module FlowExploration {
}
private predicate partialPathThroughCallable(
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
PartialPathNodeFwd mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, ReturnKindExt kind |
partialPathThroughCallable0(call, mid, kind, cc, ap, config) and
out = kind.getAnOutNode(call)
)
}
private predicate revPartialPathStep(
PartialPathNodeRev mid, Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
RevPartialAccessPath ap, Configuration config
) {
localFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(node, mid.getNode(), config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
jumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalJumpStep(node, mid.getNode(), config) and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
mid.getAp() instanceof RevPartialAccessPathNil and
ap = TRevPartialNil() and
config = mid.getConfiguration()
or
revPartialPathReadStep(mid, _, _, node, ap) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(RevPartialAccessPath ap0, Content c |
revPartialPathStoreStep(mid, ap0, c, node, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsRev(ap, c, ap0, config)
)
or
exists(ParameterNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
sc1 = TRevSummaryCtx1None() and
sc2 = TRevSummaryCtx2None() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
or
exists(ReturnPosition pos |
revPartialPathIntoReturn(mid, pos, sc1, sc2, _, ap, config) and
pos = getReturnPosition(node)
)
or
revPartialPathThroughCallable(mid, node, ap, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2()
}
pragma[inline]
private predicate revPartialPathReadStep(
PartialPathNodeRev mid, RevPartialAccessPath ap1, Content c, Node node, RevPartialAccessPath ap2
) {
exists(Node midNode |
midNode = mid.getNode() and
ap1 = mid.getAp() and
read(node, c, midNode) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1)
)
}
pragma[nomagic]
private predicate apConsRev(
RevPartialAccessPath ap1, Content c, RevPartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodeRev mid |
revPartialPathReadStep(mid, ap1, c, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, Node node, Configuration config
) {
exists(Node midNode, TypedContent tc |
midNode = mid.getNode() and
ap = mid.getAp() and
store(node, tc, midNode, _) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
)
}
pragma[nomagic]
private predicate revPartialPathIntoReturn(
PartialPathNodeRev mid, ReturnPosition pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
DataFlowCall call, RevPartialAccessPath ap, Configuration config
) {
exists(Node out |
mid.getNode() = out and
viableReturnPosOut(call, pos, out) and
sc1 = TRevSummaryCtx1Some(pos) and
sc2 = TRevSummaryCtx2Some(ap) and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathFlowsThrough(
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeRev mid, ParameterNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
ap = mid.getAp() and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable0(
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
Configuration config
) {
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
revPartialPathIntoReturn(mid, _, sc1, sc2, call, _, config) and
revPartialPathFlowsThrough(pos, sc1, sc2, ap, config)
)
}
pragma[nomagic]
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
node.argumentOf(call, pos)
)
}
}
import FlowExploration
@@ -3378,6 +3688,14 @@ private predicate partialFlow(
PartialPathNode source, PartialPathNode node, Configuration configuration
) {
source.getConfiguration() = configuration and
configuration.isSource(source.getNode()) and
source.isFwdSource() and
node = source.getASuccessor+()
}
private predicate revPartialFlow(
PartialPathNode node, PartialPathNode sink, Configuration configuration
) {
sink.getConfiguration() = configuration and
sink.isRevSink() and
node.getASuccessor+() = sink
}

View File

@@ -26,15 +26,6 @@ class IRBlockBase extends TIRBlock {
/** Gets the source location of the first non-`Phi` instruction in this block. */
final Language::Location getLocation() { result = getFirstInstruction().getLocation() }
/**
* INTERNAL: Do not use.
*
* Gets a string that uniquely identifies this block within its enclosing function.
*
* This predicate is used by debugging and printing code only.
*/
final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() }
/**
* INTERNAL: Do not use.
*
@@ -47,14 +38,15 @@ class IRBlockBase extends TIRBlock {
config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction())
) and
this =
rank[result + 1](IRBlock funcBlock, int sortOverride |
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
funcBlock.getEnclosingFunction() = getEnclosingFunction() and
funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
// Ensure that the block containing `EnterFunction` always comes first.
if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction
then sortOverride = 0
else sortOverride = 1
|
funcBlock order by sortOverride, funcBlock.getUniqueId()
funcBlock order by sortOverride, sortKey1, sortKey2
)
}

View File

@@ -494,4 +494,34 @@ module InstructionConsistency {
irFunc = getInstructionIRFunction(instr, irFuncText)
)
}
/**
* Holds if the object address operand for the given `FieldAddress` instruction does not have an
* address type.
*/
query predicate fieldAddressOnNonPointer(
FieldAddressInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText
) {
not instr.getObjectAddressOperand().getIRType() instanceof IRAddressType and
message =
"FieldAddress instruction '" + instr.toString() +
"' has an object address operand that is not an address, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
/**
* Holds if the `this` argument operand for the given `Call` instruction does not have an address
* type.
*/
query predicate thisArgumentIsNonPointer(
CallInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText
) {
exists(ThisArgumentOperand thisOperand | thisOperand = instr.getThisArgumentOperand() |
not thisOperand.getIRType() instanceof IRAddressType
) and
message =
"Call instruction '" + instr.toString() +
"' has a `this` argument operand that is not an address, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
}

View File

@@ -171,6 +171,16 @@ class Instruction extends Construction::TStageInstruction {
*/
final string getUniqueId() { result = Construction::getInstructionUniqueId(this) }
/**
* INTERNAL: Do not use.
*
* Gets two sort keys for this instruction - used to order instructions for printing
* in test outputs.
*/
final predicate hasSortKeys(int key1, int key2) {
Construction::instructionHasSortKeys(this, key1, key2)
}
/**
* Gets the basic block that contains this instruction.
*/

View File

@@ -856,7 +856,8 @@ private module CachedForDebugging {
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
instr = getPhi(phiBlock, location) and
result =
"Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
"Phi Block(" + phiBlock.getFirstInstruction().getUniqueId() + ")[" + specificity + "]: " +
location.getUniqueId() and
if location instanceof Alias::VirtualVariable
then
// Sort Phi nodes for virtual variables before Phi nodes for member locations.
@@ -873,6 +874,24 @@ private module CachedForDebugging {
result.getAST() = var.getAST() and
result.getTag() = var.getTag()
}
cached
predicate instructionHasSortKeys(Instruction instr, int key1, int key2) {
exists(OldInstruction oldInstr |
oldInstr = getOldInstruction(instr) and
oldInstr.hasSortKeys(key1, key2)
)
or
instr instanceof TUnreachedInstruction and
key1 = maxValue() and
key2 = maxValue()
}
/**
* Returns the value of the maximum representable integer.
*/
cached
int maxValue() { result = 2147483647 }
}
module SSAConsistency {

View File

@@ -26,15 +26,6 @@ class IRBlockBase extends TIRBlock {
/** Gets the source location of the first non-`Phi` instruction in this block. */
final Language::Location getLocation() { result = getFirstInstruction().getLocation() }
/**
* INTERNAL: Do not use.
*
* Gets a string that uniquely identifies this block within its enclosing function.
*
* This predicate is used by debugging and printing code only.
*/
final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() }
/**
* INTERNAL: Do not use.
*
@@ -47,14 +38,15 @@ class IRBlockBase extends TIRBlock {
config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction())
) and
this =
rank[result + 1](IRBlock funcBlock, int sortOverride |
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
funcBlock.getEnclosingFunction() = getEnclosingFunction() and
funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
// Ensure that the block containing `EnterFunction` always comes first.
if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction
then sortOverride = 0
else sortOverride = 1
|
funcBlock order by sortOverride, funcBlock.getUniqueId()
funcBlock order by sortOverride, sortKey1, sortKey2
)
}

View File

@@ -494,4 +494,34 @@ module InstructionConsistency {
irFunc = getInstructionIRFunction(instr, irFuncText)
)
}
/**
* Holds if the object address operand for the given `FieldAddress` instruction does not have an
* address type.
*/
query predicate fieldAddressOnNonPointer(
FieldAddressInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText
) {
not instr.getObjectAddressOperand().getIRType() instanceof IRAddressType and
message =
"FieldAddress instruction '" + instr.toString() +
"' has an object address operand that is not an address, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
/**
* Holds if the `this` argument operand for the given `Call` instruction does not have an address
* type.
*/
query predicate thisArgumentIsNonPointer(
CallInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText
) {
exists(ThisArgumentOperand thisOperand | thisOperand = instr.getThisArgumentOperand() |
not thisOperand.getIRType() instanceof IRAddressType
) and
message =
"Call instruction '" + instr.toString() +
"' has a `this` argument operand that is not an address, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
}

View File

@@ -171,6 +171,16 @@ class Instruction extends Construction::TStageInstruction {
*/
final string getUniqueId() { result = Construction::getInstructionUniqueId(this) }
/**
* INTERNAL: Do not use.
*
* Gets two sort keys for this instruction - used to order instructions for printing
* in test outputs.
*/
final predicate hasSortKeys(int key1, int key2) {
Construction::instructionHasSortKeys(this, key1, key2)
}
/**
* Gets the basic block that contains this instruction.
*/

View File

@@ -380,10 +380,21 @@ private module CachedForDebugging {
string getTempVariableUniqueId(IRTempVariable var) {
exists(TranslatedElement element |
var = element.getTempVariable(_) and
result = element.getId() + ":" + getTempVariableTagId(var.getTag())
result = element.getId().toString() + ":" + getTempVariableTagId(var.getTag())
)
}
cached
predicate instructionHasSortKeys(Instruction instruction, int key1, int key2) {
key1 = getInstructionTranslatedElement(instruction).getId() and
getInstructionTag(instruction) =
rank[key2](InstructionTag tag, string tagId |
tagId = getInstructionTagId(tag)
|
tag order by tagId
)
}
cached
string getInstructionUniqueId(Instruction instruction) {
result =

View File

@@ -218,7 +218,7 @@ string getInstructionTagId(TInstructionTag tag) {
or
tag = DynamicInitializationFlagStoreTag() and result = "DynInitFlagStore"
or
tag = ThisAddressTag() and result = "ThisAddres"
tag = ThisAddressTag() and result = "ThisAddress"
or
tag = ThisLoadTag() and result = "ThisLoad"
}

View File

@@ -8,6 +8,16 @@ private import TranslatedElement
private import TranslatedExpr
private import TranslatedFunction
/**
* Gets the `CallInstruction` from the `TranslatedCallExpr` for the specified expression.
*/
private CallInstruction getTranslatedCallInstruction(Call call) {
exists(TranslatedCallExpr translatedCall |
translatedCall.getExpr() = call and
result = translatedCall.getInstruction(CallTag())
)
}
/**
* The IR translation of a call to a function. The call may be from an actual
* call in the source code, or could be a call that is part of the translation
@@ -388,7 +398,7 @@ class TranslatedAllocationSideEffects extends TranslatedSideEffects,
tag = OnlyInstructionTag() and
if expr instanceof NewOrNewArrayExpr
then result = getTranslatedAllocatorCall(expr).getInstruction(CallTag())
else result = getTranslatedExpr(expr).getInstruction(CallTag())
else result = getTranslatedCallInstruction(expr)
}
}
@@ -409,7 +419,7 @@ class TranslatedCallSideEffects extends TranslatedSideEffects, TTranslatedCallSi
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
tag = OnlyInstructionTag() and
result = getTranslatedExpr(expr).getInstruction(CallTag())
result = getTranslatedCallInstruction(expr)
}
}
@@ -599,7 +609,7 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
tag = OnlyInstructionTag() and
result = getTranslatedExpr(call).getInstruction(CallTag())
result = getTranslatedCallInstruction(call)
}
final override int getInstructionIndex(InstructionTag tag) {

View File

@@ -227,6 +227,125 @@ private predicate usedAsCondition(Expr expr) {
)
}
/**
* Holds if `conv` is an `InheritanceConversion` that requires a `TranslatedLoad`, despite not being
* marked as having an lvalue-to-rvalue conversion.
*
* This is necessary for an `InheritanceConversion` that is originally modeled as a
* prvalue-to-prvalue conversion, since we transform it into a glvalue-to-glvalue conversion. If it
* is actually consumed as a prvalue, such as on the right hand side of an assignment, we need to
* load the resulting glvalue.
*/
private predicate isInheritanceConversionWithImplicitLoad(InheritanceConversion conv) {
// Must have originally been a prvalue-to-prvalue conversion.
isClassPRValue(conv.getExpr()) and
not conv.hasLValueToRValueConversion() and
// Exclude that case where this will be consumed as a glvalue, such as when used as the qualifier
// of a field access.
not isPRValueConversionOnGLValue(conv)
}
/**
* Holds if `expr` is the result of a field access whose qualifier was a prvalue and whose result is
* a prvalue. These accesses are not marked as having loads, but we do need a load in the IR.
*/
private predicate isPRValueFieldAccessWithImplicitLoad(Expr expr) {
expr instanceof ValueFieldAccess and
expr.isPRValueCategory() and
// No need to do a load if we're replacing the result with a constant anyway.
not isIRConstant(expr) and
// Model an array prvalue as the address of the array, just like an array glvalue.
not expr.getUnspecifiedType() instanceof ArrayType
}
/**
* Holds if `expr` is a prvalue of class type.
*
* This same test is used in several places.
*/
pragma[inline]
private predicate isClassPRValue(Expr expr) {
expr.isPRValueCategory() and
expr.getUnspecifiedType() instanceof Class
}
/**
* Holds if `expr` is consumed as a glvalue by its parent. If `expr` is actually a prvalue, it will
* have any lvalue-to-rvalue conversion ignored. If it does not have an lvalue-to-rvalue conversion,
* it will be materialized into a temporary object.
*/
private predicate consumedAsGLValue(Expr expr) {
isClassPRValue(expr) and
(
// Qualifier of a field access.
expr = any(FieldAccess a).getQualifier().getFullyConverted()
or
// Qualifier of a member function call.
expr = any(Call c).getQualifier().getFullyConverted()
or
// The operand of an inheritance conversion.
expr = any(InheritanceConversion c).getExpr()
)
}
/**
* Holds if `expr` is a conversion that is originally a prvalue-to-prvalue conversion, but which is
* applied to a prvalue that will actually be consumed as a glvalue.
*/
predicate isPRValueConversionOnGLValue(Conversion conv) {
exists(Expr consumed |
consumedAsGLValue(consumed) and
isClassPRValue(conv.getExpr()) and
(
// Example: The conversion of `std::string` to `const std::string` when evaluating
// `std::string("foo").c_str()`.
conv instanceof PrvalueAdjustmentConversion
or
// Parentheses are transparent.
conv instanceof ParenthesisExpr
or
// Example: The base class conversion in `f().m()`, when `m` is member function of a base
// class of the return type of `f()`.
conv instanceof InheritanceConversion
) and
(
// Base case: The conversion is consumed directly.
conv = consumed
or
// Recursive case: The conversion is the operand of another prvalue conversion.
isPRValueConversionOnGLValue(conv.getConversion())
)
)
}
/**
* Holds if `expr` is a prvalue of class type that is used in a context that requires a glvalue.
*
* Any conversions between `expr` and the ancestor that consumes the glvalue will also be treated
* as glvalues, but are not part of this relation.
*
* For example:
* ```c++
* std::string("s").c_str();
* ```
* The object for the qualifier is a prvalue(load) of type `std::string`, but the actual
* fully-converted qualifier of the call to `c_str()` is a prvalue adjustment conversion that
* converts the type to `const std::string` to match the type of the `this` pointer of the
* member function. In this case, `mustTransformToGLValue()` will hold for the temporary
* `std::string` object, but not the prvalue adjustment on top of it.
* `isPRValueConversionOnGLValue()` would hold for the prvalue adjustment.
*/
private predicate mustTransformToGLValue(Expr expr) {
not isPRValueConversionOnGLValue(expr) and
(
// The expression is the fully converted qualifier, with no prvalue adjustments on top.
consumedAsGLValue(expr)
or
// The expression has conversions on top, but they are all prvalue adjustments.
isPRValueConversionOnGLValue(expr.getConversion())
)
}
/**
* Holds if `expr` has an lvalue-to-rvalue conversion that should be ignored
* when generating IR. This occurs for conversion from an lvalue of function type
@@ -234,15 +353,24 @@ private predicate usedAsCondition(Expr expr) {
* AST as an lvalue-to-rvalue conversion, but the IR represents both a function
* lvalue and a function pointer prvalue the same.
*/
private predicate ignoreLoad(Expr expr) {
predicate ignoreLoad(Expr expr) {
expr.hasLValueToRValueConversion() and
(
expr instanceof ThisExpr or
expr instanceof FunctionAccess or
expr instanceof ThisExpr
or
expr instanceof FunctionAccess
or
expr.(PointerDereferenceExpr).getOperand().getFullyConverted().getType().getUnspecifiedType()
instanceof FunctionPointerType or
instanceof FunctionPointerType
or
expr.(ReferenceDereferenceExpr).getExpr().getType().getUnspecifiedType() instanceof
FunctionReferenceType
or
// The extractor represents the qualifier of a field access or member function call as a load of
// the temporary object if the original qualifier was a prvalue. For IR purposes, we always want
// to use the address of the temporary object as the qualifier of a field access or the `this`
// argument to a member function call.
mustTransformToGLValue(expr)
)
}
@@ -257,6 +385,17 @@ private predicate needsLoadForParentExpr(Expr expr) {
exists(CrementOperation crement | expr = crement.getOperand().getFullyConverted())
or
exists(AssignOperation ao | expr = ao.getLValue().getFullyConverted())
or
// For arguments that are passed by value but require a constructor call, the extractor emits a
// `TemporaryObjectExpr` as the argument, and marks it as a glvalue. This is roughly how a code-
// generating compiler would implement this, passing the address of the temporary so that the
// callee is using the exact same memory location allocated by the caller. We don't fully model
// this yet, though, so we'll synthesize a load so that we appear to be passing the temporary
// object via a bitwise copy.
exists(Call call |
expr = call.getAnArgument().getFullyConverted().(TemporaryObjectExpr) and
expr.isGLValueCategory()
)
}
/**
@@ -267,6 +406,10 @@ predicate hasTranslatedLoad(Expr expr) {
expr.hasLValueToRValueConversion()
or
needsLoadForParentExpr(expr)
or
isPRValueFieldAccessWithImplicitLoad(expr)
or
isInheritanceConversionWithImplicitLoad(expr)
) and
not ignoreExpr(expr) and
not isNativeCondition(expr) and
@@ -274,6 +417,16 @@ predicate hasTranslatedLoad(Expr expr) {
not ignoreLoad(expr)
}
/**
* Holds if `expr` should have a `TranslatedSyntheticTemporaryObject` on it.
*/
predicate hasTranslatedSyntheticTemporaryObject(Expr expr) {
not ignoreExpr(expr) and
mustTransformToGLValue(expr) and
// If it's a load, we'll just ignore the load in `ignoreLoad()`.
not expr.hasLValueToRValueConversion()
}
/**
* Holds if the specified `DeclarationEntry` needs an IR translation. An IR translation is only
* necessary for automatic local variables, or for static local variables with dynamic
@@ -304,6 +457,9 @@ newtype TTranslatedElement =
// A separate element to handle the lvalue-to-rvalue conversion step of an
// expression.
TTranslatedLoad(Expr expr) { hasTranslatedLoad(expr) } or
// A temporary object that we had to synthesize ourselves, so that we could do a field access or
// method call on a prvalue.
TTranslatedSyntheticTemporaryObject(Expr expr) { hasTranslatedSyntheticTemporaryObject(expr) } or
// For expressions that would not otherwise generate an instruction.
TTranslatedResultCopy(Expr expr) {
not ignoreExpr(expr) and
@@ -351,6 +507,7 @@ newtype TTranslatedElement =
exists(ConstructorFieldInit fieldInit | fieldInit.getExpr().getFullyConverted() = expr) or
exists(NewExpr newExpr | newExpr.getInitializer().getFullyConverted() = expr) or
exists(ThrowExpr throw | throw.getExpr().getFullyConverted() = expr) or
exists(TemporaryObjectExpr temp | temp.getExpr() = expr) or
exists(LambdaExpression lambda | lambda.getInitializer().getFullyConverted() = expr)
)
} or
@@ -595,10 +752,10 @@ abstract class TranslatedElement extends TTranslatedElement {
abstract TranslatedElement getChild(int id);
/**
* Gets the an identifier string for the element. This string is unique within
* Gets the an identifier string for the element. This id is unique within
* the scope of the element's function.
*/
final string getId() { result = getUniqueId().toString() }
final int getId() { result = getUniqueId() }
private TranslatedElement getChildByRank(int rankIndex) {
result =

View File

@@ -15,8 +15,9 @@ private import TranslatedStmt
import TranslatedCall
/**
* Gets the TranslatedExpr for the specified expression. If `expr` is a load,
* the result is the TranslatedExpr for the load portion.
* Gets the TranslatedExpr for the specified expression. If `expr` is a load or synthesized
* temporary object, the result is the TranslatedExpr for the load or synthetic temporary object
* portion.
*/
TranslatedExpr getTranslatedExpr(Expr expr) {
result.getExpr() = expr and
@@ -107,12 +108,17 @@ abstract class TranslatedCoreExpr extends TranslatedExpr {
// If this TranslatedExpr doesn't produce the result, then it must represent
// a glvalue that is then loaded by a TranslatedLoad.
hasTranslatedLoad(expr)
or
// The expression should be treated as a glvalue because its operand was forced to be a glvalue,
// such as for the qualifier of a member access.
isPRValueConversionOnGLValue(expr)
}
final override predicate producesExprResult() {
// If there's no load, then this is the only TranslatedExpr for this
// If there's no load or temp object, then this is the only TranslatedExpr for this
// expression.
not hasTranslatedLoad(expr) and
not hasTranslatedSyntheticTemporaryObject(expr) and
// If there's a result copy, then this expression's result is the copy.
not exprNeedsCopyIfNotLoaded(expr)
}
@@ -246,19 +252,35 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
private TranslatedCondition getCondition() { result = getTranslatedCondition(expr) }
}
/**
* The IR translation of a node synthesized to adjust the value category of its operand.
* One of:
* - `TranslatedLoad` - Convert from glvalue to prvalue by loading from the location.
* - `TranslatedSyntheticTemporaryObject` - Convert from prvalue to glvalue by storing to a
* temporary variable.
*/
abstract class TranslatedValueCategoryAdjustment extends TranslatedExpr {
final override Instruction getFirstInstruction() { result = getOperand().getFirstInstruction() }
final override TranslatedElement getChild(int id) { id = 0 and result = getOperand() }
final override predicate producesExprResult() {
// A temp object always produces the result of the expression.
any()
}
final TranslatedCoreExpr getOperand() { result.getExpr() = expr }
}
/**
* IR translation of an implicit lvalue-to-rvalue conversion on the result of
* an expression.
*/
class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
class TranslatedLoad extends TranslatedValueCategoryAdjustment, TTranslatedLoad {
TranslatedLoad() { this = TTranslatedLoad(expr) }
override string toString() { result = "Load of " + expr.toString() }
override Instruction getFirstInstruction() { result = getOperand().getFirstInstruction() }
override TranslatedElement getChild(int id) { id = 0 and result = getOperand() }
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = LoadTag() and
opcode instanceof Opcode::Load and
@@ -286,18 +308,75 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
result = getOperand().getResult()
)
}
final override predicate producesExprResult() {
// A load always produces the result of the expression.
any()
}
TranslatedCoreExpr getOperand() { result.getExpr() = expr }
}
/**
* IR translation of an implicit lvalue-to-rvalue conversion on the result of
* an expression.
* The IR translation of a temporary object synthesized by the IR to hold a class prvalue on which
* a member access is going to be performed. This differs from `TranslatedTemporaryObjectExpr` in
* that instances of `TranslatedSyntheticTemporaryObject` are synthesized during IR construction,
* whereas `TranslatedTemporaryObjectExpr` instances are created from `TemporaryObjectExpr` nodes
* from the AST.
*/
class TranslatedSyntheticTemporaryObject extends TranslatedValueCategoryAdjustment,
TTranslatedSyntheticTemporaryObject {
TranslatedSyntheticTemporaryObject() { this = TTranslatedSyntheticTemporaryObject(expr) }
override string toString() { result = "Temporary materialization of " + expr.toString() }
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = InitializerVariableAddressTag() and
opcode instanceof Opcode::VariableAddress and
resultType = getTypeForGLValue(expr.getType())
or
tag = InitializerStoreTag() and
opcode instanceof Opcode::Store and
resultType = getTypeForPRValue(expr.getType())
}
override predicate isResultGLValue() { any() }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = InitializerVariableAddressTag() and
result = getInstruction(InitializerStoreTag()) and
kind instanceof GotoEdge
or
tag = InitializerStoreTag() and
result = getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = getOperand() and result = getInstruction(InitializerVariableAddressTag())
}
override Instruction getResult() { result = getInstruction(InitializerVariableAddressTag()) }
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
tag = InitializerStoreTag() and
(
operandTag instanceof AddressOperandTag and
result = getInstruction(InitializerVariableAddressTag())
or
operandTag instanceof StoreValueOperandTag and
result = getOperand().getResult()
)
}
final override predicate hasTempVariable(TempVariableTag tag, CppType type) {
tag = TempObjectTempVar() and
type = getTypeForPRValue(expr.getType())
}
final override IRVariable getInstructionVariable(InstructionTag tag) {
tag = InitializerVariableAddressTag() and
result = getIRTempVariable(expr, TempObjectTempVar())
}
}
/**
* IR translation of an expression that simply returns its result. We generate an otherwise useless
* `CopyValue` instruction for these expressions so that there is at least one instruction
* associated with the expression.
*/
class TranslatedResultCopy extends TranslatedExpr, TTranslatedResultCopy {
TranslatedResultCopy() { this = TTranslatedResultCopy(expr) }
@@ -2049,6 +2128,38 @@ class TranslatedBinaryConditionalExpr extends TranslatedConditionalExpr {
}
}
/**
* IR translation of the materialization of a temporary object.
*
* This translation allocates a temporary variable, and initializes it treating `expr.getExpr()` as
* its initializer.
*/
class TranslatedTemporaryObjectExpr extends TranslatedNonConstantExpr,
TranslatedVariableInitialization {
override TemporaryObjectExpr expr;
final override predicate hasTempVariable(TempVariableTag tag, CppType type) {
tag = TempObjectTempVar() and
type = getTypeForPRValue(expr.getType())
}
override Type getTargetType() { result = expr.getType() }
final override TranslatedInitialization getInitialization() {
result = getTranslatedInitialization(expr.getExpr())
}
final override IRVariable getIRVariable() {
result = getIRTempVariable(expr, TempObjectTempVar())
}
final override Instruction getInitializationSuccessor() {
result = getParent().getChildSuccessor(this)
}
final override Instruction getResult() { result = getTargetAddress() }
}
/**
* IR translation of a `throw` expression.
*/

View File

@@ -26,15 +26,6 @@ class IRBlockBase extends TIRBlock {
/** Gets the source location of the first non-`Phi` instruction in this block. */
final Language::Location getLocation() { result = getFirstInstruction().getLocation() }
/**
* INTERNAL: Do not use.
*
* Gets a string that uniquely identifies this block within its enclosing function.
*
* This predicate is used by debugging and printing code only.
*/
final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() }
/**
* INTERNAL: Do not use.
*
@@ -47,14 +38,15 @@ class IRBlockBase extends TIRBlock {
config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction())
) and
this =
rank[result + 1](IRBlock funcBlock, int sortOverride |
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
funcBlock.getEnclosingFunction() = getEnclosingFunction() and
funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
// Ensure that the block containing `EnterFunction` always comes first.
if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction
then sortOverride = 0
else sortOverride = 1
|
funcBlock order by sortOverride, funcBlock.getUniqueId()
funcBlock order by sortOverride, sortKey1, sortKey2
)
}

View File

@@ -494,4 +494,34 @@ module InstructionConsistency {
irFunc = getInstructionIRFunction(instr, irFuncText)
)
}
/**
* Holds if the object address operand for the given `FieldAddress` instruction does not have an
* address type.
*/
query predicate fieldAddressOnNonPointer(
FieldAddressInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText
) {
not instr.getObjectAddressOperand().getIRType() instanceof IRAddressType and
message =
"FieldAddress instruction '" + instr.toString() +
"' has an object address operand that is not an address, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
/**
* Holds if the `this` argument operand for the given `Call` instruction does not have an address
* type.
*/
query predicate thisArgumentIsNonPointer(
CallInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText
) {
exists(ThisArgumentOperand thisOperand | thisOperand = instr.getThisArgumentOperand() |
not thisOperand.getIRType() instanceof IRAddressType
) and
message =
"Call instruction '" + instr.toString() +
"' has a `this` argument operand that is not an address, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
}

View File

@@ -171,6 +171,16 @@ class Instruction extends Construction::TStageInstruction {
*/
final string getUniqueId() { result = Construction::getInstructionUniqueId(this) }
/**
* INTERNAL: Do not use.
*
* Gets two sort keys for this instruction - used to order instructions for printing
* in test outputs.
*/
final predicate hasSortKeys(int key1, int key2) {
Construction::instructionHasSortKeys(this, key1, key2)
}
/**
* Gets the basic block that contains this instruction.
*/

View File

@@ -856,7 +856,8 @@ private module CachedForDebugging {
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
instr = getPhi(phiBlock, location) and
result =
"Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
"Phi Block(" + phiBlock.getFirstInstruction().getUniqueId() + ")[" + specificity + "]: " +
location.getUniqueId() and
if location instanceof Alias::VirtualVariable
then
// Sort Phi nodes for virtual variables before Phi nodes for member locations.
@@ -873,6 +874,24 @@ private module CachedForDebugging {
result.getAST() = var.getAST() and
result.getTag() = var.getTag()
}
cached
predicate instructionHasSortKeys(Instruction instr, int key1, int key2) {
exists(OldInstruction oldInstr |
oldInstr = getOldInstruction(instr) and
oldInstr.hasSortKeys(key1, key2)
)
or
instr instanceof TUnreachedInstruction and
key1 = maxValue() and
key2 = maxValue()
}
/**
* Returns the value of the maximum representable integer.
*/
cached
int maxValue() { result = 2147483647 }
}
module SSAConsistency {

View File

@@ -4,7 +4,8 @@ newtype TTempVariableTag =
ThrowTempVar() or
LambdaTempVar() or
EllipsisTempVar() or
ThisTempVar()
ThisTempVar() or
TempObjectTempVar()
string getTempVariableTagId(TTempVariableTag tag) {
tag = ConditionValueTempVar() and result = "CondVal"
@@ -18,4 +19,6 @@ string getTempVariableTagId(TTempVariableTag tag) {
tag = EllipsisTempVar() and result = "Ellipsis"
or
tag = ThisTempVar() and result = "This"
or
tag = TempObjectTempVar() and result = "Temp"
}

View File

@@ -35,7 +35,11 @@ class ConversionConstructorModel extends Constructor, TaintFunction {
class CopyConstructorModel extends CopyConstructor, DataFlowFunction {
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
// data flow from the first constructor argument to the returned object
input.isParameter(0) and
(
input.isParameter(0)
or
input.isParameterDeref(0)
) and
(
output.isReturnValue()
or
@@ -50,7 +54,11 @@ class CopyConstructorModel extends CopyConstructor, DataFlowFunction {
class MoveConstructorModel extends MoveConstructor, DataFlowFunction {
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
// data flow from the first constructor argument to the returned object
input.isParameter(0) and
(
input.isParameter(0)
or
input.isParameterDeref(0)
) and
(
output.isReturnValue()
or

View File

@@ -5,32 +5,9 @@ import semmle.code.cpp.models.interfaces.SideEffect
class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideEffectFunction {
PureStrFunction() {
exists(string name |
hasGlobalOrStdName(name) and
(
name = "atof" or
name = "atoi" or
name = "atol" or
name = "atoll" or
name = "strcasestr" or
name = "strchnul" or
name = "strchr" or
name = "strchrnul" or
name = "strstr" or
name = "strpbrk" or
name = "strcmp" or
name = "strcspn" or
name = "strncmp" or
name = "strrchr" or
name = "strspn" or
name = "strtod" or
name = "strtof" or
name = "strtol" or
name = "strtoll" or
name = "strtoq" or
name = "strtoul"
)
)
hasGlobalOrStdName(["atof", "atoi", "atol", "atoll", "strcasestr", "strchnul", "strchr",
"strchrnul", "strstr", "strpbrk", "strcmp", "strcspn", "strncmp", "strrchr", "strspn",
"strtod", "strtof", "strtol", "strtoll", "strtoq", "strtoul"])
}
override predicate hasArrayInput(int bufParam) {
@@ -81,22 +58,9 @@ class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideE
class StrLenFunction extends AliasFunction, ArrayFunction, SideEffectFunction {
StrLenFunction() {
exists(string name |
hasGlobalOrStdName(name) and
(
name = "strlen" or
name = "strnlen" or
name = "wcslen"
)
or
hasGlobalName(name) and
(
name = "_mbslen" or
name = "_mbslen_l" or
name = "_mbstrlen" or
name = "_mbstrlen_l"
)
)
hasGlobalOrStdName(["strlen", "strnlen", "wcslen"])
or
hasGlobalName(["_mbslen", "_mbslen_l", "_mbstrlen", "_mbstrlen_l"])
}
override predicate hasArrayInput(int bufParam) {
@@ -126,15 +90,7 @@ class StrLenFunction extends AliasFunction, ArrayFunction, SideEffectFunction {
}
class PureFunction extends TaintFunction, SideEffectFunction {
PureFunction() {
exists(string name |
hasGlobalOrStdName(name) and
(
name = "abs" or
name = "labs"
)
)
}
PureFunction() { hasGlobalOrStdName(["abs", "labs"]) }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
exists(ParameterIndex i |

View File

@@ -17,7 +17,11 @@ class MakeUniqueOrShared extends TaintFunction {
// 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
(
input.isParameter([0 .. getNumberOfParameters() - 1])
or
input.isParameterDeref([0 .. getNumberOfParameters() - 1])
) and
output.isReturnValue()
}

View File

@@ -206,3 +206,34 @@ class StdSequenceContainerAt extends TaintFunction {
output.isQualifierObject()
}
}
/**
* The standard vector `emplace` function.
*/
class StdVectorEmplace extends TaintFunction {
StdVectorEmplace() { this.hasQualifiedName("std", "vector", "emplace") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from any parameter except the position iterator to qualifier and return value
// (here we assume taint flow from any constructor parameter to the constructed object)
input.isParameter([1 .. getNumberOfParameters() - 1]) and
(
output.isQualifierObject() or
output.isReturnValue()
)
}
}
/**
* The standard vector `emplace_back` function.
*/
class StdVectorEmplaceBack extends TaintFunction {
StdVectorEmplaceBack() { this.hasQualifiedName("std", "vector", "emplace_back") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from any parameter to qualifier
// (here we assume taint flow from any constructor parameter to the constructed object)
input.isParameter([0 .. getNumberOfParameters() - 1]) and
output.isQualifierObject()
}
}

View File

@@ -4,10 +4,40 @@
import semmle.code.cpp.models.interfaces.Taint
/**
* An instantiation of `std::pair<T1, T2>`.
*/
class StdPairClass extends ClassTemplateInstantiation {
StdPairClass() { getTemplate().hasQualifiedName("std", "pair") }
}
/**
* Any of the single-parameter constructors of `std::pair` that takes a reference to an
* instantiation of `std::pair`. These constructors allow conversion between pair types when the
* underlying element types are convertible.
*/
class StdPairCopyishConstructor extends Constructor, TaintFunction {
StdPairCopyishConstructor() {
this.getDeclaringType() instanceof StdPairClass and
this.getNumberOfParameters() = 1 and
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof StdPairClass
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// taint flow from the source object to the constructed object
input.isParameterDeref(0) and
(
output.isReturnValue()
or
output.isQualifierObject()
)
}
}
/**
* Additional model for `std::pair` constructors.
*/
class StdPairConstructor extends Constructor, TaintFunction {
private class StdPairConstructor extends Constructor, TaintFunction {
StdPairConstructor() { this.hasQualifiedName("std", "pair", "pair") }
/**
@@ -34,7 +64,7 @@ class StdPairConstructor extends Constructor, TaintFunction {
/**
* The standard pair `swap` function.
*/
class StdPairSwap extends TaintFunction {
private class StdPairSwap extends TaintFunction {
StdPairSwap() { this.hasQualifiedName("std", "pair", "swap") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {

View File

@@ -61,7 +61,7 @@ class StdSetEmplace extends TaintFunction {
// flow from any parameter to qualifier and return value
// (here we assume taint flow from any constructor parameter to the constructed object)
// (where the return value is a pair, this should really flow just to the first part of it)
input.isParameter([0 .. getNumberOfParameters() - 1]) and
input.isParameterDeref([0 .. getNumberOfParameters() - 1]) and
(
output.isQualifierObject() or
output.isReturnValue()

View File

@@ -30,10 +30,19 @@ class StdStringConstructor extends Constructor, TaintFunction {
* character).
*/
int getAStringParameterIndex() {
getParameter(result).getType() instanceof PointerType or // e.g. `std::basic_string::CharT *`
getParameter(result).getType() instanceof ReferenceType or // e.g. `std::basic_string &`
getParameter(result).getUnspecifiedType() =
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT`
exists(Type paramType | paramType = getParameter(result).getUnspecifiedType() |
// e.g. `std::basic_string::CharT *`
paramType instanceof PointerType
or
// e.g. `std::basic_string &`, avoiding `const Allocator&`
paramType instanceof ReferenceType and
not paramType.(ReferenceType).getBaseType() =
getDeclaringType().getTemplateArgument(2).(Type).getUnspecifiedType()
or
// i.e. `std::basic_string::CharT`
getParameter(result).getUnspecifiedType() =
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType()
)
}
/**

View File

@@ -1171,6 +1171,7 @@ conversionkinds(
| @parexpr
| @reference_to
| @ref_indirect
| @temp_init
;
/*
@@ -1673,6 +1674,7 @@ case @expr.kind of
| 326 = @spaceshipexpr
| 327 = @co_await
| 328 = @co_yield
| 329 = @temp_init
;
@var_args_expr = @vastartexpr

File diff suppressed because it is too large Load Diff

View File

@@ -43,15 +43,15 @@
* There is no need to write a `select` clause or query predicate. All of the differences between
* expected results and actual results will be reported in the `failures()` query predicate.
*
* To annotate the test source code with an expected result, place a comment on the
* To annotate the test source code with an expected result, place a comment starting with a `$` on the
* same line as the expected result, with text of the following format as the body of the comment:
*
* `$tag=expected-value`
* `tag=expected-value`
*
* Where `tag` is the value of the `tag` parameter from `hasActualResult()`, and `expected-value` is
* the value of the `value` parameter from `hasActualResult()`. The `=expected-value` portion may be
* omitted, in which case `expected-value` is treated as the empty string. Multiple expectations may
* be placed in the same comment, as long as each is prefixed by a `$`. Any actual result that
* be placed in the same comment. Any actual result that
* appears on a line that does not contain a matching expected result comment will be reported with
* a message of the form "Unexpected result: tag=value". Any expected result comment for which there
* is no matching actual result will be reported with a message of the form
@@ -60,30 +60,33 @@
* Example:
* ```cpp
* int i = x + 5; // $const=5
* int j = y + (7 - 3) // $const=7 $const=3 $const=4 // The result of the subtraction is a constant.
* int j = y + (7 - 3) // $const=7 const=3 const=4 // The result of the subtraction is a constant.
* ```
*
* For tests that contain known false positives and false negatives, it is possible to further
* annotate that a particular expected result is known to be a false positive, or that a particular
* missing result is known to be a false negative:
* For tests that contain known missing and spurious results, it is possible to further
* annotate that a particular expected result is known to be spurious, or that a particular
* missing result is known to be missing:
*
* `$f+:tag=expected-value` // False positive
* `$f-:tag=expected-value` // False negative
* `$ SPURIOUS: tag=expected-value` // Spurious result
* `$ MISSING: tag=expected-value` // Missing result
*
* A false positive expectation is treated as any other expected result, except that if there is no
* matching actual result, the message will be of the form "Fixed false positive: tag=value". A
* false negative expectation is treated as if there were no expected result, except that if a
* A spurious expectation is treated as any other expected result, except that if there is no
* matching actual result, the message will be of the form "Fixed spurious result: tag=value". A
* missing expectation is treated as if there were no expected result, except that if a
* matching expected result is found, the message will be of the form
* "Fixed false negative: tag=value".
* "Fixed missing result: tag=value".
*
* A single line can contain all the expected, spurious and missing results of that line. For instance:
* `$ tag1=value1 SPURIOUS: tag2=value2 MISSING: tag3=value3`.
*
* If the same result value is expected for two or more tags on the same line, there is a shorthand
* notation available:
*
* `$tag1,tag2=expected-value`
* `tag1,tag2=expected-value`
*
* is equivalent to:
*
* `$tag1=expected-value $tag2=expected-value`
* `tag1=expected-value tag2=expected-value`
*/
private import InlineExpectationsTestPrivate
@@ -126,7 +129,7 @@ abstract class InlineExpectationsTest extends string {
(
exists(FalseNegativeExpectation falseNegative |
falseNegative.matchesActualResult(actualResult) and
message = "Fixed false negative:" + falseNegative.getExpectationText()
message = "Fixed missing result:" + falseNegative.getExpectationText()
)
or
not exists(ValidExpectation expectation | expectation.matchesActualResult(actualResult)) and
@@ -143,7 +146,7 @@ abstract class InlineExpectationsTest extends string {
message = "Missing result:" + expectation.getExpectationText()
or
expectation instanceof FalsePositiveExpectation and
message = "Fixed false positive:" + expectation.getExpectationText()
message = "Fixed spurious result:" + expectation.getExpectationText()
)
)
or
@@ -160,20 +163,79 @@ abstract class InlineExpectationsTest extends string {
* is treated as part of the expected results, except that the comment may contain a `//` sequence
* to treat the remainder of the line as a regular (non-interpreted) comment.
*/
private string expectationCommentPattern() { result = "\\s*(\\$(?:[^/]|/[^/])*)(?://.*)?" }
private string expectationCommentPattern() { result = "\\s*\\$((?:[^/]|/[^/])*)(?://.*)?" }
/**
* RegEx pattern to match a single expected result, not including the leading `$`. It starts with an
* optional `f+:` or `f-:`, followed by one or more comma-separated tags containing only letters,
* `-`, and `_`, optionally followed by `=` and the expected value.
* The possible columns in an expectation comment. The `TDefaultColumn` branch represents the first
* column in a comment. This column is not precedeeded by a name. `TNamedColumn(name)` represents a
* column containing expected results preceeded by the string `name:`.
*/
private string expectationPattern() {
result = "(?:(f(?:\\+|-)):)?((?:[A-Za-z-_]+)(?:\\s*,\\s*[A-Za-z-_]+)*)(?:=(.*))?"
private newtype TColumn =
TDefaultColumn() or
TNamedColumn(string name) { name = ["MISSING", "SPURIOUS"] }
bindingset[start, content]
private int getEndOfColumnPosition(int start, string content) {
result =
min(string name, int cand |
exists(TNamedColumn(name)) and
cand = content.indexOf(name + ":") and
cand > start
|
cand
)
or
not exists(string name |
exists(TNamedColumn(name)) and
content.indexOf(name + ":") > start
) and
result = content.length()
}
private string getAnExpectation(LineComment comment) {
result = comment.getContents().regexpCapture(expectationCommentPattern(), 1).splitAt("$").trim() and
result != ""
private predicate getAnExpectation(
LineComment comment, TColumn column, string expectation, string tags, string value
) {
exists(string content |
content = comment.getContents().regexpCapture(expectationCommentPattern(), 1) and
(
column = TDefaultColumn() and
exists(int end |
end = getEndOfColumnPosition(0, content) and
expectation = content.prefix(end).regexpFind(expectationPattern(), _, _).trim()
)
or
exists(string name, int start, int end |
column = TNamedColumn(name) and
start = content.indexOf(name + ":") + name.length() + 1 and
end = getEndOfColumnPosition(start, content) and
expectation = content.substring(start, end).regexpFind(expectationPattern(), _, _).trim()
)
)
) and
tags = expectation.regexpCapture(expectationPattern(), 1) and
if exists(expectation.regexpCapture(expectationPattern(), 2))
then value = expectation.regexpCapture(expectationPattern(), 2)
else value = ""
}
private string getColumnString(TColumn column) {
column = TDefaultColumn() and result = ""
or
column = TNamedColumn(result)
}
/**
* RegEx pattern to match a single expected result, not including the leading `$`. It consists of one or
* more comma-separated tags containing only letters, digits, `-` and `_` (note that the first character
* must not be a digit), optionally followed by `=` and the expected value.
*/
private string expectationPattern() {
exists(string tag, string tags, string value |
tag = "[A-Za-z-_][A-Za-z-_0-9]*" and
tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and
value = "((?:\"[^\"]*\"|'[^']*'|\\S+)*)" and
result = tags + "(?:=" + value + ")?"
)
}
private newtype TFailureLocatable =
@@ -183,24 +245,14 @@ private newtype TFailureLocatable =
test.hasActualResult(location, element, tag, value)
} or
TValidExpectation(LineComment comment, string tag, string value, string knownFailure) {
exists(string expectation |
expectation = getAnExpectation(comment) and
expectation.regexpMatch(expectationPattern()) and
tag = expectation.regexpCapture(expectationPattern(), 2).splitAt(",").trim() and
(
if exists(expectation.regexpCapture(expectationPattern(), 3))
then value = expectation.regexpCapture(expectationPattern(), 3)
else value = ""
) and
(
if exists(expectation.regexpCapture(expectationPattern(), 1))
then knownFailure = expectation.regexpCapture(expectationPattern(), 1)
else knownFailure = ""
)
exists(TColumn column, string tags |
getAnExpectation(comment, column, _, tags, value) and
tag = tags.splitAt(",") and
knownFailure = getColumnString(column)
)
} or
TInvalidExpectation(LineComment comment, string expectation) {
expectation = getAnExpectation(comment) and
getAnExpectation(comment, _, expectation, _, _) and
not expectation.regexpMatch(expectationPattern())
}
@@ -265,16 +317,17 @@ private class ValidExpectation extends Expectation, TValidExpectation {
}
}
/* Note: These next three classes correspond to all the possible values of type `TColumn`. */
class GoodExpectation extends ValidExpectation {
GoodExpectation() { getKnownFailure() = "" }
}
class FalsePositiveExpectation extends ValidExpectation {
FalsePositiveExpectation() { getKnownFailure() = "f+" }
FalsePositiveExpectation() { getKnownFailure() = "SPURIOUS" }
}
class FalseNegativeExpectation extends ValidExpectation {
FalseNegativeExpectation() { getKnownFailure() = "f-" }
FalseNegativeExpectation() { getKnownFailure() = "MISSING" }
}
class InvalidExpectation extends Expectation, TInvalidExpectation {

View File

@@ -1,3 +1,11 @@
void Conversion4(int x) {
x = ((int)7);
}
char * retfn(void * v) {
return (char*)(void*)(int*)v;
}
void Conversion4_vardecl(int x) {
long y = (long) x;
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,3 +4,4 @@
| test.cpp:4:9:4:9 | this |
| test.cpp:4:9:4:11 | call to expression |
| test.cpp:10:5:10:11 | call to Foo |
| test.cpp:10:5:10:11 | temporary object |

View File

@@ -122,7 +122,7 @@
| conversions.cpp:179:36:179:37 | (..:: *)... | pointer-to-member derived class conversion | prval | ..:: * | ..:: * |
| conversions.cpp:180:10:180:47 | static_cast<..:: *>... | pointer-to-member derived class conversion | prval | ..:: * | ..:: * |
| conversions.cpp:180:43:180:46 | (..:: *)... | pointer-to-member derived class conversion | prval | ..:: * | ..:: * |
| conversions.cpp:190:22:190:29 | (const String)... | glvalue conversion | lval | const String | void |
| conversions.cpp:190:22:190:29 | (const String)... | glvalue conversion | lval | const String | String |
| conversions.cpp:193:20:193:31 | (const Base)... | glvalue conversion | lval | const Base | Base |
| conversions.cpp:193:31:193:31 | (Base)... | base class conversion | lval | Base | Middle |
| conversions.cpp:193:31:193:31 | (Middle)... | base class conversion | lval | Middle | Derived |

View File

@@ -9,7 +9,7 @@
int main(int argc, char *argv[]) {
int main() {
@@ -208,4 +208,50 @@ void test_field_to_obj_test_pointer_arith(Point* pp) {
(pp + sizeof(*pp))->x = getenv("VAR")[0];
sink(pp); // tainted [field -> object]
sink(pp + sizeof(*pp)); // tainted [field -> object]
}
}
void sink(char **);
void test_pointers1()
{
char buffer[1024];
char *s = getenv("VAR");
char *ptr1, **ptr2;
char *ptr3, **ptr4;
ptr1 = buffer;
ptr2 = &ptr1;
memcpy(buffer, s, 1024);
ptr3 = buffer;
ptr4 = &ptr3;
sink(buffer); // tainted
sink(ptr1); // tainted
sink(ptr2);
sink(*ptr2); // tainted [NOT DETECTED]
sink(ptr3); // tainted
sink(ptr4);
sink(*ptr4); // tainted [NOT DETECTED]
}
void test_pointers2()
{
char buffer[1024];
char *s = getenv("VAR");
char *ptr1, **ptr2;
char *ptr3, **ptr4;
ptr1 = buffer;
ptr2 = &ptr1;
memcpy(*ptr2, s, 1024);
ptr3 = buffer;
ptr4 = &ptr3;
sink(buffer); // tainted [NOT DETECTED]
sink(ptr1); // tainted [NOT DETECTED]
sink(ptr2);
sink(*ptr2); // tainted [NOT DETECTED]
sink(ptr3); // tainted [NOT DETECTED]
sink(ptr4);
sink(*ptr4); // tainted [NOT DETECTED]
}

View File

@@ -12,3 +12,6 @@ char *strcat(char * s1, const char * s2);
char *strdup(const char *string);
char *_strdup(const char *string);
char *unmodeled_function(const char *const_string);
typedef unsigned long size_t;
void *memcpy(void *s1, const void *s2, size_t n);

View File

@@ -71,9 +71,9 @@ void test_string()
sink(a); // tainted
sink(b);
sink(c); // tainted [NOT DETECTED]
sink(c); // tainted
sink(b.c_str());
sink(c.c_str()); // tainted [NOT DETECTED]
sink(c.c_str()); // tainted
}
void test_stringstream()
@@ -91,12 +91,12 @@ void test_stringstream()
sink(ss2); // tainted
sink(ss3); // tainted [NOT DETECTED]
sink(ss4); // tainted
sink(ss5); // tainted [NOT DETECTED]
sink(ss5); // tainted
sink(ss1.str());
sink(ss2.str()); // tainted
sink(ss3.str()); // tainted [NOT DETECTED]
sink(ss4.str()); // tainted
sink(ss5.str()); // tainted [NOT DETECTED]
sink(ss5.str()); // tainted
}
void test_stringstream_int(int source)
@@ -123,14 +123,14 @@ void sink(const char *filename, const char *mode);
void test_strings2()
{
string path1 = user_input();
sink(path1.c_str(), "r"); // tainted [NOT DETECTED]
sink(path1.c_str(), "r"); // tainted
string path2;
path2 = user_input();
sink(path2.c_str(), "r"); // tainted
string path3(user_input());
sink(path3.c_str(), "r"); // tainted [NOT DETECTED]
sink(path3.c_str(), "r"); // tainted
}
void test_string3()
@@ -141,7 +141,7 @@ void test_string3()
std::string ss(cs);
sink(cs); // tainted
sink(ss); // tainted [NOT DETECTED]
sink(ss); // tainted
}
void test_string4()
@@ -155,5 +155,5 @@ void test_string4()
cs = ss.c_str();
sink(cs); // tainted [NOT DETECTED]
sink(ss); // tainted [NOT DETECTED]
sink(ss); // tainted
}

View File

@@ -90,6 +90,7 @@
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (reference dereference) |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:23 | call to getenv |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | (reference to) |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | temporary object |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | shared.h:5:23:5:31 | sinkparam |
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:91:42:91:44 | arg |
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:92:12:92:14 | arg |
@@ -134,6 +135,26 @@
| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:27:208:32 | call to getenv |
| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:27:208:42 | (int)... |
| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:27:208:42 | access to array |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:218:8:218:8 | s |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:218:12:218:17 | call to getenv |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:224:2:224:7 | call to memcpy |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:224:17:224:17 | (const void *)... |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:224:17:224:17 | s |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:228:7:228:12 | (const char *)... |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:228:7:228:12 | array to pointer conversion |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:228:7:228:12 | buffer |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:229:7:229:10 | (const char *)... |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:229:7:229:10 | ptr1 |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:232:7:232:10 | (const char *)... |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:232:7:232:10 | ptr3 |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | shared.h:5:23:5:31 | sinkparam |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | shared.h:17:36:17:37 | s2 |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:240:8:240:8 | s |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:240:12:240:17 | call to getenv |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:2:246:7 | call to memcpy |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:16:246:16 | (const void *)... |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:16:246:16 | s |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | shared.h:17:36:17:37 | s2 |
| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:24:28:27 | call to atoi |
| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:34 | call to getenv |
| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:45 | (const char *)... |
@@ -176,7 +197,9 @@
| 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 | (unnamed parameter 0) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:114:43:118 | (unnamed parameter 1) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:44:176:44:178 | str |
| 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:63:30:63:30 | s |
| 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 |
@@ -185,6 +208,11 @@
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:24 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:72:7:72:7 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:72:7:72:7 | a |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | (const string)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | (reference to) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | c |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:7:76:7 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:7:76:7 | c |
| 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 |
@@ -203,40 +231,63 @@
| 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:88:6:88:6 | call to operator<< |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:6:88:10 | (reference dereference) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | (reference to) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | t |
| 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:94:7:94:9 | (const stringstream)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:94:7:94:9 | (reference to) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:94:7:94:9 | ss5 |
| 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:99:7:99:9 | (const basic_stringstream<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:99:7:99:9 | ss5 |
| 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 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:28 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:7:126:11 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:7:126:11 | path1 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:128:9:128:13 | path2 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:19 | call to user_input |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | temporary object |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | path2 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:24 | call to user_input |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:26 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:27 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:7:133:11 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:7:133:11 | path3 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:14:138:15 | cs |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:19:138:24 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:19:138:26 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:18 | cs |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:19 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:143:7:143:8 | cs |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | (const string)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | (reference to) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | ss |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:14:149:15 | cs |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:19:149:24 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:19:149:26 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:18 | cs |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:19 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:7:155:8 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:7:155:8 | ss |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | (const string)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | (reference to) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | ss |
| test_diff.cpp:92:10:92:13 | argv | shared.h:5:23:5:31 | sinkparam |
| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:13 | argv |
| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:16 | (const char *)... |

View File

@@ -12,6 +12,7 @@
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (const char *)... | IR only |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (reference dereference) | IR only |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | (reference to) | IR only |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | temporary object | IR only |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | shared.h:5:23:5:31 | sinkparam | IR only |
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:91:31:91:33 | ret | AST only |
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:92:5:92:8 | * ... | AST only |
@@ -36,12 +37,63 @@
| defaulttainttracking.cpp:195:11:195:16 | call to getenv | defaulttainttracking.cpp:195:7:195:7 | x | AST only |
| defaulttainttracking.cpp:201:13:201:18 | call to getenv | defaulttainttracking.cpp:201:9:201:9 | x | AST only |
| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:23:208:23 | x | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:213:11:213:14 | (unnamed parameter 0) | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:217:7:217:12 | buffer | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:219:8:219:11 | ptr1 | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:219:16:219:19 | ptr2 | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:220:8:220:11 | ptr3 | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:220:16:220:19 | ptr4 | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:222:2:222:5 | ptr1 | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:222:9:222:14 | buffer | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:223:2:223:5 | ptr2 | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:223:9:223:13 | & ... | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:223:10:223:13 | ptr1 | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:224:9:224:14 | buffer | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:225:2:225:5 | ptr3 | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:225:9:225:14 | buffer | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:226:2:226:5 | ptr4 | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:226:9:226:13 | & ... | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:226:10:226:13 | ptr3 | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:228:7:228:12 | (const char *)... | IR only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:228:7:228:12 | array to pointer conversion | IR only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:230:7:230:10 | ptr2 | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:231:7:231:11 | (const char *)... | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:231:7:231:11 | * ... | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:231:8:231:11 | ptr2 | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:233:7:233:10 | ptr4 | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:234:7:234:11 | (const char *)... | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:234:7:234:11 | * ... | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:234:8:234:11 | ptr4 | AST only |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | shared.h:17:20:17:21 | s1 | AST only |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:213:11:213:14 | (unnamed parameter 0) | AST only |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:241:8:241:11 | ptr1 | AST only |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:241:16:241:19 | ptr2 | AST only |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:245:2:245:5 | ptr2 | AST only |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:245:9:245:13 | & ... | AST only |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:245:10:245:13 | ptr1 | AST only |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:9:246:13 | * ... | AST only |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:10:246:13 | ptr2 | AST only |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:251:7:251:10 | (const char *)... | AST only |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:251:7:251:10 | ptr1 | AST only |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:252:7:252:10 | ptr2 | AST only |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:253:7:253:11 | (const char *)... | AST only |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:253:7:253:11 | * ... | AST only |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:253:8:253:11 | ptr2 | AST only |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | shared.h:5:23:5:31 | sinkparam | AST only |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | shared.h:17:20:17:21 | s1 | AST 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 | (unnamed parameter 0) | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:44:176:44:178 | str | 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:63:30:63:30 | s | IR 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:74:7:74:7 | (const string)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | (reference to) | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | c | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:7:76:7 | (const basic_string<char, char_traits<char>, allocator<char>>)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:7:76:7 | c | 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 |
@@ -53,26 +105,49 @@
| 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:88:6:88:6 | call to operator<< | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:6:88:10 | (reference dereference) | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | (const basic_string<char, char_traits<char>, allocator<char>>)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | (reference to) | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | t | 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:94:7:94:9 | (const stringstream)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:94:7:94:9 | (reference to) | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:94:7:94:9 | ss5 | 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:99:7:99:9 | (const basic_stringstream<char, char_traits<char>, allocator<char>>)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:99:7:99:9 | ss5 | 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:126:7:126:11 | (const basic_string<char, char_traits<char>, allocator<char>>)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:7:126:11 | path1 | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:128:9:128:13 | path2 | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | call to basic_string | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | temporary object | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | (const basic_string<char, char_traits<char>, allocator<char>>)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | path2 | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:27 | call to basic_string | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:7:133:11 | (const basic_string<char, char_traits<char>, allocator<char>>)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:7:133:11 | path3 | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:19 | call to basic_string | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | (const string)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | (reference to) | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | ss | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:19 | call to basic_string | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:7:155:8 | (const basic_string<char, char_traits<char>, allocator<char>>)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:7:155:8 | ss | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:157:7:157:8 | cs | AST only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | (const string)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | (reference to) | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | ss | IR only |
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only |
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:36:24:36:24 | p | AST only |
| test_diff.cpp:111:10:111:13 | argv | shared.h:5:23:5:31 | sinkparam | AST only |

View File

@@ -40,21 +40,21 @@ public:
cc.insert(nullptr);
ct.insert(new C());
sink(&cc); // no flow
sink(&ct); // $ast $f-:ir
sink(&ct); // $ ast MISSING: ir
}
void f1()
{
C *c = new C();
B *b = B::make(c);
sink(b->c); // $ast $f-:ir
sink(b->c); // $ast MISSING: ir
}
void f2()
{
B *b = new B();
b->set(new C1());
sink(b->get()); // $ast $ir=55:12
sink((new B(new C()))->get()); // $ast $ir
sink(b->get()); // $ ast ir=55:12
sink((new B(new C()))->get()); // $ ast ir
}
void f3()
@@ -63,7 +63,7 @@ public:
B *b2;
b2 = setOnB(b1, new C2());
sink(b1->c); // no flow
sink(b2->c); // $ast $f-:ir
sink(b2->c); // $ ast MISSING: ir
}
void f4()
@@ -72,7 +72,7 @@ public:
B *b2;
b2 = setOnBWrap(b1, new C2());
sink(b1->c); // no flow
sink(b2->c); // $ast $f-:ir
sink(b2->c); // $ ast MISSING: ir
}
B *setOnBWrap(B *b1, C *c)
@@ -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))
@@ -117,7 +117,7 @@ public:
}
if (C1 *c1 = dynamic_cast<C1 *>(cc))
{
sink(c1->a); //$f+:ast
sink(c1->a); // $ SPURIOUS: ast
}
}
@@ -129,7 +129,7 @@ public:
{
B *b = new B();
f7(b);
sink(b->c); // $ast,ir
sink(b->c); // $ ast,ir
}
class D
@@ -149,9 +149,9 @@ public:
{
B *b = new B();
D *d = new D(b, r());
sink(d->b); // $ast,ir=143:25 $ast,ir=150:12
sink(d->b->c); // $ast $f-:ir
sink(b->c); // $ast,ir
sink(d->b); // $ ast,ir=143:25 ast,ir=150:12
sink(d->b->c); // $ ast MISSING: ir
sink(b->c); // $ ast,ir
}
void f10()
@@ -162,11 +162,11 @@ public:
MyList *l3 = new MyList(nullptr, l2);
sink(l3->head); // no flow, b is nested beneath at least one ->next
sink(l3->next->head); // no flow
sink(l3->next->next->head); // $ast $f-:ir
sink(l3->next->next->head); // $ ast MISSING: ir
sink(l3->next->next->next->head); // no flow
for (MyList *l = l3; l != nullptr; l = l->next)
{
sink(l->head); // $ast $f-:ir
sink(l->head); // $ ast MISSING: ir
}
}

View File

@@ -6,7 +6,7 @@ class B
Elem *e = new Elem();
Box1 *b1 = new Box1(e, nullptr);
Box2 *b2 = new Box2(b1);
sink(b2->box1->elem1); // $ast $f-:ir
sink(b2->box1->elem1); // $ ast MISSING: ir
sink(b2->box1->elem2); // no flow
}
@@ -16,7 +16,7 @@ class B
Box1 *b1 = new B::Box1(nullptr, e);
Box2 *b2 = new Box2(b1);
sink(b2->box1->elem1); // no flow
sink(b2->box1->elem2); // $ast $f-:ir
sink(b2->box1->elem2); // $ ast MISSING: ir
}
static void sink(void *o) {}

View File

@@ -26,10 +26,10 @@ public:
void func()
{
sink(s1); // $ast $ir
sink(s2); // $f-:ast $f-:ir
sink(s3); // $ast $ir
sink(s4); // $f-:ast $f-:ir
sink(s1); // $ast ir
sink(s2); // $ MISSING: ast,ir
sink(s3); // $ast ir
sink(s4); // $ MISSING: ast,ir
}
static void sink(const void *o) {}

View File

@@ -19,7 +19,7 @@ public:
};
static void sinkWrap(Box2* b2) {
sink(b2->getBox1()->getElem()); // $ast=28:15 $ast=35:15 $ast=42:15 $ast=49:15 $f-:ir
sink(b2->getBox1()->getElem()); // $ast=28:15 ast=35:15 ast=42:15 ast=49:15 MISSING: ir
}
Box2* boxfield;
@@ -61,6 +61,6 @@ public:
private:
void f5b() {
sink(boxfield->box->elem); // $ast $f-:ir
sink(boxfield->box->elem); // $ ast MISSING: ir
}
};

View File

@@ -18,7 +18,7 @@ void sink(char *b);
void handlePacket(packet *p)
{
sink(p->data.buffer); // $ast $f-:ir
sink(p->data.buffer); // $ ast MISSING: ir
}
void f(buf* b)
@@ -28,7 +28,7 @@ void f(buf* b)
argument_source(raw);
argument_source(b->buffer);
argument_source(p.data.buffer);
sink(raw); // $ast $f-:ir
sink(b->buffer); // $ast $f-:ir
sink(raw); // $ ast MISSING: ir
sink(b->buffer); // $ ast MISSING: ir
handlePacket(&p);
}

View File

@@ -26,8 +26,8 @@ void callSetters() {
referenceSetter(s2);
copySetter(s3);
sink(s1.m1); // $ast,ir
sink(s2.m1); // $ast,ir
sink(s1.m1); // $ ast,ir
sink(s2.m1); // $ ast,ir
sink(s3.m1); // no flow
}
@@ -35,12 +35,12 @@ void assignAfterAlias() {
S s1 = { 0, 0 };
S &ref1 = s1;
ref1.m1 = user_input();
sink(s1.m1); // $f-:ast $ir
sink(s1.m1); // $ ir MISSING: ast
S s2 = { 0, 0 };
S &ref2 = s2;
s2.m1 = user_input();
sink(ref2.m1); // $f-:ast $ir
sink(ref2.m1); // $ ir MISSING: ast
}
void assignAfterCopy() {
@@ -59,7 +59,7 @@ void assignBeforeCopy() {
S s2 = { 0, 0 };
s2.m1 = user_input();
S copy2 = s2;
sink(copy2.m1); // $ast,ir
sink(copy2.m1); // $ ast,ir
}
struct Wrapper {
@@ -77,20 +77,20 @@ void pointerIntermediate() {
Wrapper w = { { 0, 0 } };
S *s = &w.s;
s->m1 = user_input();
sink(w.s.m1); // $f-:ast $ir
sink(w.s.m1); // $ ir MISSING: ast
}
void referenceIntermediate() {
Wrapper w = { { 0, 0 } };
S &s = w.s;
s.m1 = user_input();
sink(w.s.m1); // $f-:ast $ir
sink(w.s.m1); // $ ir MISSING: ast
}
void nestedAssign() {
Wrapper w = { { 0, 0 } };
w.s.m1 = user_input();
sink(w.s.m1); // $ast,ir
sink(w.s.m1); // $ ast,ir
}
void addressOfField() {
@@ -99,7 +99,7 @@ void addressOfField() {
S s_copy = s;
int* px = &s_copy.m1;
sink(*px); // $f-:ast $ir
sink(*px); // $ ir MISSING: ast
}
void taint_a_ptr(int* pa) {
@@ -119,28 +119,28 @@ struct S_with_pointer {
void pointer_deref(int* xs) {
taint_a_ptr(xs);
sink(xs[0]); // $f-:ast $ir
sink(xs[0]); // $ ir MISSING: ast
}
void pointer_deref_sub(int* xs) {
taint_a_ptr(xs - 2);
sink(*(xs - 2)); // $f-:ast $ir
sink(*(xs - 2)); // $ ir MISSING: ast
}
void pointer_many_addrof_and_deref(int* xs) {
taint_a_ptr(xs);
sink(*&*&*xs); // $f-:ast $ir
sink(*&*&*xs); // $ ir MISSING: ast
}
void pointer_unary_plus(int* xs) {
taint_a_ptr(+xs);
sink(*+xs); // $f-:ast $ir
sink(*+xs); // $ ir MISSING: ast
}
void pointer_member_index(S_with_pointer s) {
taint_a_ptr(s.data);
// `s.data` is points to all-aliased-memory
sink(s.data[0]); // $f-:ast,ir
sink(s.data[0]); // $ MISSING: ir,ast
}
void member_array_different_field(S_with_pointer* s) {
@@ -156,13 +156,13 @@ struct S_with_array {
void pointer_member_deref() {
S_with_array s;
taint_a_ptr(s.data);
sink(*s.data); // $ir,ast
sink(*s.data); // $ ir,ast
}
void array_member_deref() {
S_with_array s;
taint_a_ptr(s.data);
sink(s.data[0]); // $ir,ast
sink(s.data[0]); // $ ir,ast
}
struct S2 {
@@ -173,7 +173,7 @@ struct S2 {
void deep_member_field_dot() {
S2 s2;
taint_a_ptr(&s2.s.m1);
sink(s2.s.m1); // $ir,ast
sink(s2.s.m1); // $ ir,ast
}
void deep_member_field_dot_different_fields() {
@@ -186,7 +186,7 @@ void deep_member_field_dot_2() {
S2 s2;
taint_a_ptr(&s2.s.m1);
S2 s2_2 = s2;
sink(s2_2.s.m1); // $ir,ast
sink(s2_2.s.m1); // $ ir,ast
}
void deep_member_field_dot_different_fields_2() {
@@ -198,7 +198,7 @@ void deep_member_field_dot_different_fields_2() {
void deep_member_field_arrow(S2 *ps2) {
taint_a_ptr(&ps2->s.m1);
sink(ps2->s.m1); // $ir,ast
sink(ps2->s.m1); // $ ir,ast
}
void deep_member_field_arrow_different_fields(S2 *ps2) {

View File

@@ -4,17 +4,17 @@ 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
sink(arr[0]); // $ ast,ir
sink(arr[1]); // $ SPURIOUS: 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
sink(arr[0]); // $ ast,ir
sink(arr[1]); // $ SPURIOUS: ast
}
struct inner {
@@ -34,18 +34,18 @@ struct outer {
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
sink(o.nested.arr[1].data); // $ ast,ir
sink(o.nested.arr[0].data); // $ SPURIOUS: 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
sink(o.indirect->arr[1].data); // $ ast MISSING: ir
sink(o.indirect->arr[0].data); // $ SPURIOUS: 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[1].data); // $ MISSING: ir,ast
sink(o.indirect->ptr[0].data);
}

View File

@@ -48,19 +48,19 @@ struct S {
void test_setDirectly() {
S s;
s.setDirectly(user_input());
sink(s.getDirectly()); // $ast $ir
sink(s.getDirectly()); // $ast ir
}
void test_setIndirectly() {
S s;
s.setIndirectly(user_input());
sink(s.getIndirectly()); // $ast $ir
sink(s.getIndirectly()); // $ast ir
}
void test_setThroughNonMember() {
S s;
s.setThroughNonMember(user_input());
sink(s.getThroughNonMember()); // $ast $ir
sink(s.getThroughNonMember()); // $ast ir
}
void test_nonMemberSetA() {
@@ -107,13 +107,13 @@ void test_outer_with_ptr(Outer *pouter) {
taint_inner_a_ptr(pouter->inner_ptr);
taint_a_ptr(&pouter->a);
sink(outer.inner_nested.a); // $ast,ir
sink(outer.inner_ptr->a); // $ast $f-:ir
sink(outer.a); // $ast,ir
sink(outer.inner_nested.a); // $ ast,ir
sink(outer.inner_ptr->a); // $ ast MISSING: ir
sink(outer.a); // $ ast,ir
sink(pouter->inner_nested.a); // $ast,ir
sink(pouter->inner_ptr->a); // $ast $f-:ir
sink(pouter->a); // $ast,ir
sink(pouter->inner_nested.a); // $ ast,ir
sink(pouter->inner_ptr->a); // $ast MISSING: ir
sink(pouter->a); // $ ast,ir
}
void test_outer_with_ref(Outer *pouter) {
@@ -127,11 +127,11 @@ void test_outer_with_ref(Outer *pouter) {
taint_inner_a_ref(*pouter->inner_ptr);
taint_a_ref(pouter->a);
sink(outer.inner_nested.a); // $ast,ir
sink(outer.inner_ptr->a); // $ast $f-:ir
sink(outer.a); // $ast,ir
sink(outer.inner_nested.a); // $ ast,ir
sink(outer.inner_ptr->a); // $ ast MISSING: ir
sink(outer.a); // $ ast,ir
sink(pouter->inner_nested.a); // $ast,ir
sink(pouter->inner_ptr->a); // $ast $f-:ir
sink(pouter->a); // $ast,ir
sink(pouter->inner_nested.a); // $ ast,ir
sink(pouter->inner_ptr->a); // $ ast MISSING: ir
sink(pouter->a); // $ ast,ir
}

View File

@@ -39,8 +39,8 @@ void sink(int x)
void bar(Outer &b)
{
sink(b.inner.f.a()); // $ast=53:19 $ast=55:19 $ir=53:19 $ir=55:19
sink(b.inner.f.b()); // $ast=54:19 $ast=56:19 $ir=54:19 $ir=56:19
sink(b.inner.f.a()); // $ ast=53:19 ast=55:19 ir=53:19 ir=55:19
sink(b.inner.f.b()); // $ ast=54:19 ast=56:19 ir=54:19 ir=56:19
}
void foo()

View File

@@ -25,8 +25,8 @@ public:
void bar(Foo &f)
{
sink(f.a()); //$ast=34:11 $ast=36:11 $ir=34:11 $ir=36:11
sink(f.b()); //$ast=35:14 $ast=36:25 $ir=35:14 $ir=36:25
sink(f.a()); // $ ast=34:11 ast=36:11 ir=34:11 ir=36:11
sink(f.b()); // $ ast=35:14 ast=36:25 ir=35:14 ir=36:25
}
void foo()

View File

@@ -20,31 +20,31 @@ namespace qualifiers {
void assignToGetter(Outer outer) {
outer.getInner()->a = user_input();
sink(outer.inner->a); // $ast $f-:ir
sink(outer.inner->a); // $ ast MISSING: ir
}
void getterArgument1(Outer outer) {
outer.getInner()->setA(user_input());
sink(outer.inner->a); // $ast $f-:ir
sink(outer.inner->a); // $ ast MISSING: ir
}
void getterArgument2(Outer outer) {
pointerSetA(outer.getInner(), user_input());
sink(outer.inner->a); // $ast $f-:ir
sink(outer.inner->a); // $ ast MISSING: ir
}
void getterArgument2Ref(Outer outer) {
referenceSetA(*outer.getInner(), user_input());
sink(outer.inner->a); // $ast $f-:ir
sink(outer.inner->a); // $ ast MISSING: ir
}
void assignToGetterStar(Outer outer) {
(*outer.getInner()).a = user_input();
sink(outer.inner->a); // $ast $f-:ir
sink(outer.inner->a); // $ ast MISSING: ir
}
void assignToGetterAmp(Outer outer) {
(&outer)->getInner()->a = user_input();
sink(outer.inner->a); // $ast $f-:ir
sink(outer.inner->a); // $ ast MISSING: ir
}
}

View File

@@ -58,12 +58,12 @@ int main(int argc, char** argv) {
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
sink((void*)foo.bar[i].baz->userInput.bufferLen); // $ ast MISSING: 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
sink((void*)foo.bar[i].baz->userInput.buffer); // $ MISSING: ir,ast
sink((void*)dst); // ir MISSING: ast
i++;
}
return 0;

View File

@@ -25,8 +25,8 @@ public:
void bar(Foo &f)
{
sink(f.a()); //$ast=39:12 $ast=41:12 $ir=39:12 $ir=41:12
sink(f.b()); //$ast=40:12 $ast=42:12 $ir=40:12 $ir=42:12
sink(f.a()); // $ ast=39:12 ast=41:12 ir=39:12 ir=41:12
sink(f.b()); // $ ast=40:12 ast=42:12 ir=40:12 ir=42:12
}
void foo()
@@ -64,7 +64,7 @@ void single_field_test()
A a;
a.i = user_input();
A a2 = a;
sink(a2.i); //$ast,ir
sink(a2.i); //$ ast,ir
}
struct C {
@@ -81,7 +81,7 @@ struct C2
void m() {
f2.f1 = user_input();
sink(getf2f1()); //$ast,ir
sink(getf2f1()); //$ ast,ir
}
};
@@ -91,7 +91,7 @@ void single_field_test_typedef(A_typedef a)
{
a.i = user_input();
A_typedef a2 = a;
sink(a2.i); //$ast,ir
sink(a2.i); //$ ast,ir
}
} // namespace Simple

View File

@@ -12,14 +12,14 @@ struct Outer {
};
void absink(struct AB *ab) {
sink(ab->a); //$ast,ir=20:20 $ast,ir=27:7 $ast=40:20 $f-:ir
sink(ab->a); //$ ast,ir=20:20 ast,ir=27:7 ast=40:20 MISSING: ir
sink(ab->b); // no flow
}
int struct_init(void) {
struct AB ab = { user_input(), 0 };
sink(ab.a); //$ast,ir
sink(ab.a); //$ ast,ir
sink(ab.b); // no flow
absink(&ab);
@@ -28,9 +28,9 @@ int struct_init(void) {
&ab,
};
sink(outer.nestedAB.a); //$ast,ir
sink(outer.nestedAB.a); //$ ast,ir
sink(outer.nestedAB.b); // no flow
sink(outer.pointerAB->a); //$ast $f-:ir
sink(outer.pointerAB->a); //$ ast MISSING: ir
sink(outer.pointerAB->b); // no flow
absink(&outer.nestedAB);

View File

@@ -1,6 +1,6 @@
int source();
void sink(...) {};
void sink(...);
class MyCopyableClass {
public:

View File

@@ -1,6 +1,6 @@
int source();
void sink(...) {};
void sink(...);
class MyCopyableClassDeclOnly {
public:
@@ -15,7 +15,7 @@ public:
int v;
};
void test_copyableclass()
void test_copyableclass_declonly()
{
{
MyCopyableClassDeclOnly s1(1);

View File

@@ -30,7 +30,7 @@ int sscanf(const char *s, const char *format, ...);
// ----------
int source();
void sink(...) {};
void sink(...);
namespace string
{

View File

@@ -262,6 +262,10 @@
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| format.cpp:16:21:16:21 | s | format.cpp:22:22:22:22 | s | |
| format.cpp:16:31:16:31 | n | format.cpp:22:25:22:25 | n | |
| format.cpp:16:46:16:51 | format | format.cpp:22:28:22:33 | format | |
@@ -2062,8 +2066,8 @@
| movableclass.cpp:15:3:15:13 | ... = ... | movableclass.cpp:15:9:15:9 | v [post update] | |
| movableclass.cpp:15:13:15:13 | 0 | movableclass.cpp:15:3:15:13 | ... = ... | |
| movableclass.cpp:16:11:16:14 | this | movableclass.cpp:16:10:16:14 | * ... | TAINT |
| movableclass.cpp:22:57:22:57 | 1 | movableclass.cpp:22:42:22:58 | call to MyMovableClass | TAINT |
| movableclass.cpp:23:55:23:60 | call to source | movableclass.cpp:23:40:23:63 | call to MyMovableClass | TAINT |
| movableclass.cpp:22:57:22:57 | 1 | movableclass.cpp:22:35:22:59 | call to MyMovableClass | TAINT |
| movableclass.cpp:23:55:23:60 | call to source | movableclass.cpp:23:33:23:64 | call to MyMovableClass | TAINT |
| movableclass.cpp:28:21:28:21 | 1 | movableclass.cpp:28:21:28:22 | call to MyMovableClass | TAINT |
| movableclass.cpp:28:21:28:22 | call to MyMovableClass | movableclass.cpp:33:8:33:9 | s1 | |
| movableclass.cpp:29:22:29:23 | call to MyMovableClass | movableclass.cpp:34:8:34:9 | s2 | |
@@ -2092,10 +2096,8 @@
| movableclass.cpp:52:8:52:31 | call to MyMovableClass | movableclass.cpp:52:3:52:4 | ref arg s2 | TAINT |
| movableclass.cpp:52:8:52:31 | call to MyMovableClass | movableclass.cpp:52:6:52:6 | call to operator= | TAINT |
| movableclass.cpp:52:23:52:28 | call to source | movableclass.cpp:52:8:52:31 | call to MyMovableClass | TAINT |
| movableclass.cpp:59:21:59:32 | call to getUnTainted | movableclass.cpp:59:21:59:35 | call to MyMovableClass | |
| movableclass.cpp:59:21:59:35 | call to MyMovableClass | movableclass.cpp:63:8:63:9 | s1 | |
| movableclass.cpp:60:21:60:30 | call to getTainted | movableclass.cpp:60:21:60:33 | call to MyMovableClass | |
| movableclass.cpp:60:21:60:33 | call to MyMovableClass | movableclass.cpp:64:8:64:9 | s2 | |
| movableclass.cpp:59:21:59:32 | call to getUnTainted | movableclass.cpp:63:8:63:9 | s1 | |
| movableclass.cpp:60:21:60:30 | call to getTainted | movableclass.cpp:64:8:64:9 | s2 | |
| movableclass.cpp:61:18:61:19 | call to MyMovableClass | movableclass.cpp:65:8:65:9 | s3 | |
| movableclass.cpp:65:13:65:18 | call to source | movableclass.cpp:65:13:65:20 | call to MyMovableClass | TAINT |
| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:8:65:9 | ref arg s3 | TAINT |
@@ -3188,141 +3190,125 @@
| stl.h:292:30:292:40 | call to allocator | stl.h:292:21:292:41 | noexcept(...) | TAINT |
| stl.h:292:30:292:40 | call to allocator | stl.h:292:21:292:41 | noexcept(...) | TAINT |
| stl.h:292:53:292:63 | 0 | stl.h:292:46:292:64 | (no string representation) | TAINT |
| stl.h:385:9:385:9 | Unknown literal | stl.h:385:9:385:9 | constructor init of field first | TAINT |
| stl.h:385:9:385:9 | Unknown literal | stl.h:385:9:385:9 | constructor init of field second | TAINT |
| stl.h:385:9:385:9 | constructor init of field first [post-this] | stl.h:385:9:385:9 | constructor init of field second [pre-this] | |
| stl.h:385:9:385:9 | constructor init of field first [pre-this] | stl.h:385:9:385:9 | constructor init of field second [pre-this] | |
| stl.h:385:9:385:9 | this | stl.h:385:9:385:9 | constructor init of field first [pre-this] | |
| stl.h:392:3:392:3 | this | stl.h:392:36:392:43 | constructor init of field first [pre-this] | |
| stl.h:392:3:392:3 | this | stl.h:392:36:392:43 | constructor init of field first [pre-this] | |
| stl.h:392:3:392:3 | this | stl.h:392:36:392:43 | constructor init of field first [pre-this] | |
| stl.h:392:3:392:3 | this | stl.h:392:36:392:43 | constructor init of field first [pre-this] | |
| stl.h:392:3:392:3 | this | stl.h:392:36:392:43 | constructor init of field first [pre-this] | |
| stl.h:392:3:392:3 | this | stl.h:392:36:392:43 | constructor init of field first [pre-this] | |
| stl.h:392:3:392:3 | this | stl.h:392:36:392:43 | constructor init of field first [pre-this] | |
| stl.h:392:3:392:6 | this | stl.h:392:36:392:43 | constructor init of field first [pre-this] | |
| stl.h:392:18:392:18 | x | stl.h:392:18:392:18 | x | |
| stl.h:392:18:392:18 | x | stl.h:392:18:392:18 | x | |
| stl.h:392:18:392:18 | x | stl.h:392:18:392:18 | x | |
| stl.h:392:18:392:18 | x | stl.h:392:18:392:18 | x | |
| stl.h:392:18:392:18 | x | stl.h:392:42:392:42 | x | |
| stl.h:392:18:392:18 | x | stl.h:392:42:392:42 | x | |
| stl.h:392:18:392:18 | x | stl.h:392:42:392:42 | x | |
| stl.h:392:18:392:18 | x | stl.h:392:42:392:42 | x | |
| stl.h:392:18:392:18 | x | stl.h:392:42:392:42 | x | |
| stl.h:392:18:392:18 | x | stl.h:392:42:392:42 | x | |
| stl.h:392:18:392:18 | x | stl.h:392:42:392:42 | x | |
| stl.h:392:18:392:18 | x | stl.h:392:42:392:42 | x | |
| stl.h:392:31:392:31 | y | stl.h:392:31:392:31 | y | |
| stl.h:392:31:392:31 | y | stl.h:392:31:392:31 | y | |
| stl.h:392:31:392:31 | y | stl.h:392:31:392:31 | y | |
| stl.h:392:31:392:31 | y | stl.h:392:31:392:31 | y | |
| stl.h:392:31:392:31 | y | stl.h:392:53:392:53 | y | |
| stl.h:392:31:392:31 | y | stl.h:392:53:392:53 | y | |
| stl.h:392:31:392:31 | y | stl.h:392:53:392:53 | y | |
| stl.h:392:31:392:31 | y | stl.h:392:53:392:53 | y | |
| stl.h:392:31:392:31 | y | stl.h:392:53:392:53 | y | |
| stl.h:392:31:392:31 | y | stl.h:392:53:392:53 | y | |
| stl.h:392:31:392:31 | y | stl.h:392:53:392:53 | y | |
| stl.h:392:31:392:31 | y | stl.h:392:53:392:53 | y | |
| stl.h:392:36:392:43 | call to unknown function | stl.h:392:36:392:43 | constructor init of field first | TAINT |
| stl.h:392:36:392:43 | constructor init of field first [post-this] | stl.h:392:46:392:54 | constructor init of field second [pre-this] | |
| stl.h:392:36:392:43 | constructor init of field first [post-this] | stl.h:392:46:392:54 | constructor init of field second [pre-this] | |
| stl.h:392:36:392:43 | constructor init of field first [post-this] | stl.h:392:46:392:54 | constructor init of field second [pre-this] | |
| stl.h:392:36:392:43 | constructor init of field first [post-this] | stl.h:392:46:392:54 | constructor init of field second [pre-this] | |
| stl.h:392:36:392:43 | constructor init of field first [post-this] | stl.h:392:46:392:54 | constructor init of field second [pre-this] | |
| stl.h:392:36:392:43 | constructor init of field first [post-this] | stl.h:392:46:392:54 | constructor init of field second [pre-this] | |
| stl.h:392:36:392:43 | constructor init of field first [post-this] | stl.h:392:46:392:54 | constructor init of field second [pre-this] | |
| stl.h:392:36:392:43 | constructor init of field first [post-this] | stl.h:392:46:392:54 | constructor init of field second [pre-this] | |
| stl.h:392:36:392:43 | constructor init of field first [pre-this] | stl.h:392:46:392:54 | constructor init of field second [pre-this] | |
| stl.h:392:36:392:43 | constructor init of field first [pre-this] | stl.h:392:46:392:54 | constructor init of field second [pre-this] | |
| stl.h:392:36:392:43 | constructor init of field first [pre-this] | stl.h:392:46:392:54 | constructor init of field second [pre-this] | |
| stl.h:392:36:392:43 | constructor init of field first [pre-this] | stl.h:392:46:392:54 | constructor init of field second [pre-this] | |
| stl.h:392:36:392:43 | constructor init of field first [pre-this] | stl.h:392:46:392:54 | constructor init of field second [pre-this] | |
| stl.h:392:36:392:43 | constructor init of field first [pre-this] | stl.h:392:46:392:54 | constructor init of field second [pre-this] | |
| stl.h:392:36:392:43 | constructor init of field first [pre-this] | stl.h:392:46:392:54 | constructor init of field second [pre-this] | |
| stl.h:392:36:392:43 | constructor init of field first [pre-this] | stl.h:392:46:392:54 | constructor init of field second [pre-this] | |
| stl.h:392:42:392:42 | x | stl.h:392:36:392:43 | constructor init of field first | TAINT |
| stl.h:392:42:392:42 | x | stl.h:392:36:392:43 | constructor init of field first | TAINT |
| stl.h:392:42:392:42 | x | stl.h:392:36:392:43 | constructor init of field first | TAINT |
| stl.h:392:42:392:42 | x | stl.h:392:36:392:43 | constructor init of field first | TAINT |
| stl.h:392:42:392:42 | x | stl.h:392:36:392:43 | constructor init of field first | TAINT |
| stl.h:392:42:392:42 | x | stl.h:392:36:392:43 | constructor init of field first | TAINT |
| stl.h:392:42:392:42 | x | stl.h:392:36:392:43 | constructor init of field first | TAINT |
| stl.h:392:46:392:54 | call to unknown function | stl.h:392:46:392:54 | constructor init of field second | TAINT |
| stl.h:392:53:392:53 | y | stl.h:392:46:392:54 | constructor init of field second | TAINT |
| stl.h:392:53:392:53 | y | stl.h:392:46:392:54 | constructor init of field second | TAINT |
| stl.h:392:53:392:53 | y | stl.h:392:46:392:54 | constructor init of field second | TAINT |
| stl.h:392:53:392:53 | y | stl.h:392:46:392:54 | constructor init of field second | TAINT |
| stl.h:392:53:392:53 | y | stl.h:392:46:392:54 | constructor init of field second | TAINT |
| stl.h:392:53:392:53 | y | stl.h:392:46:392:54 | constructor init of field second | TAINT |
| stl.h:392:53:392:53 | y | stl.h:392:46:392:54 | constructor init of field second | TAINT |
| stl.h:398:109:398:109 | x | stl.h:398:109:398:109 | x | |
| stl.h:398:109:398:109 | x | stl.h:398:109:398:109 | x | |
| stl.h:398:109:398:109 | x | stl.h:398:109:398:109 | x | |
| stl.h:398:109:398:109 | x | stl.h:398:109:398:109 | x | |
| stl.h:398:109:398:109 | x | stl.h:398:109:398:109 | x | |
| stl.h:398:109:398:109 | x | stl.h:398:109:398:109 | x | |
| stl.h:398:109:398:109 | x | stl.h:398:109:398:109 | x | |
| stl.h:398:109:398:109 | x | stl.h:399:40:399:40 | x | |
| stl.h:398:109:398:109 | x | stl.h:399:40:399:40 | x | |
| stl.h:398:109:398:109 | x | stl.h:399:40:399:40 | x | |
| stl.h:398:109:398:109 | x | stl.h:399:40:399:40 | x | |
| stl.h:398:109:398:109 | x | stl.h:399:40:399:40 | x | |
| stl.h:398:109:398:109 | x | stl.h:399:40:399:40 | x | |
| stl.h:398:109:398:109 | x | stl.h:399:40:399:40 | x | |
| stl.h:398:117:398:117 | y | stl.h:398:117:398:117 | y | |
| stl.h:398:117:398:117 | y | stl.h:398:117:398:117 | y | |
| stl.h:398:117:398:117 | y | stl.h:398:117:398:117 | y | |
| stl.h:398:117:398:117 | y | stl.h:398:117:398:117 | y | |
| stl.h:398:117:398:117 | y | stl.h:398:117:398:117 | y | |
| stl.h:398:117:398:117 | y | stl.h:398:117:398:117 | y | |
| stl.h:398:117:398:117 | y | stl.h:398:117:398:117 | y | |
| stl.h:398:117:398:117 | y | stl.h:399:61:399:61 | y | |
| stl.h:398:117:398:117 | y | stl.h:399:61:399:61 | y | |
| stl.h:398:117:398:117 | y | stl.h:399:61:399:61 | y | |
| stl.h:398:117:398:117 | y | stl.h:399:61:399:61 | y | |
| stl.h:398:117:398:117 | y | stl.h:399:61:399:61 | y | |
| stl.h:398:117:398:117 | y | stl.h:399:61:399:61 | y | |
| stl.h:398:117:398:117 | y | stl.h:399:61:399:61 | y | |
| stl.h:399:10:399:63 | call to pair | stl.h:399:10:399:63 | call to pair | TAINT |
| stl.h:399:10:399:63 | call to pair | stl.h:399:10:399:63 | call to pair | TAINT |
| stl.h:399:10:399:63 | call to pair | stl.h:399:10:399:63 | call to pair | TAINT |
| stl.h:399:10:399:63 | call to pair | stl.h:399:10:399:63 | call to pair | TAINT |
| stl.h:399:10:399:63 | call to pair | stl.h:399:10:399:63 | call to pair | TAINT |
| stl.h:399:10:399:63 | call to pair | stl.h:399:10:399:63 | call to pair | TAINT |
| stl.h:399:23:399:38 | ref arg call to forward | stl.h:398:109:398:109 | x | |
| stl.h:399:23:399:38 | ref arg call to forward | stl.h:398:109:398:109 | x | |
| stl.h:399:23:399:38 | ref arg call to forward | stl.h:398:109:398:109 | x | |
| stl.h:399:23:399:38 | ref arg call to forward | stl.h:398:109:398:109 | x | |
| stl.h:399:23:399:38 | ref arg call to forward | stl.h:399:40:399:40 | x [inner post update] | |
| stl.h:399:23:399:38 | ref arg call to forward | stl.h:399:40:399:40 | x [inner post update] | |
| stl.h:399:23:399:38 | ref arg call to forward | stl.h:399:40:399:40 | x [inner post update] | |
| stl.h:399:23:399:38 | ref arg call to forward | stl.h:399:40:399:40 | x [inner post update] | |
| stl.h:399:40:399:40 | x | stl.h:399:23:399:38 | call to forward | |
| stl.h:399:40:399:40 | x | stl.h:399:23:399:38 | call to forward | |
| stl.h:399:40:399:40 | x | stl.h:399:23:399:38 | call to forward | |
| stl.h:399:40:399:40 | x | stl.h:399:23:399:38 | call to forward | |
| stl.h:399:40:399:40 | x | stl.h:399:23:399:38 | call to forward | |
| stl.h:399:40:399:40 | x | stl.h:399:23:399:38 | call to forward | |
| stl.h:399:44:399:59 | call to forward | stl.h:399:10:399:63 | call to pair | TAINT |
| stl.h:399:44:399:59 | call to forward | stl.h:399:10:399:63 | call to pair | TAINT |
| stl.h:399:44:399:59 | ref arg call to forward | stl.h:398:117:398:117 | y | |
| stl.h:399:44:399:59 | ref arg call to forward | stl.h:398:117:398:117 | y | |
| stl.h:399:44:399:59 | ref arg call to forward | stl.h:398:117:398:117 | y | |
| stl.h:399:44:399:59 | ref arg call to forward | stl.h:398:117:398:117 | y | |
| stl.h:399:44:399:59 | ref arg call to forward | stl.h:399:61:399:61 | y [inner post update] | |
| stl.h:399:44:399:59 | ref arg call to forward | stl.h:399:61:399:61 | y [inner post update] | |
| stl.h:399:44:399:59 | ref arg call to forward | stl.h:399:61:399:61 | y [inner post update] | |
| stl.h:399:44:399:59 | ref arg call to forward | stl.h:399:61:399:61 | y [inner post update] | |
| stl.h:399:61:399:61 | y | stl.h:399:10:399:63 | call to pair | TAINT |
| stl.h:399:61:399:61 | y | stl.h:399:10:399:63 | call to pair | TAINT |
| stl.h:399:61:399:61 | y | stl.h:399:44:399:59 | call to forward | |
| stl.h:399:61:399:61 | y | stl.h:399:44:399:59 | call to forward | |
| stl.h:399:61:399:61 | y | stl.h:399:44:399:59 | call to forward | |
| stl.h:399:61:399:61 | y | stl.h:399:44:399:59 | call to forward | |
| stl.h:399:61:399:61 | y | stl.h:399:44:399:59 | call to forward | |
| stl.h:399:61:399:61 | y | stl.h:399:44:399:59 | call to forward | |
| stl.h:388:9:388:9 | Unknown literal | stl.h:388:9:388:9 | constructor init of field first | TAINT |
| stl.h:388:9:388:9 | Unknown literal | stl.h:388:9:388:9 | constructor init of field first | TAINT |
| stl.h:388:9:388:9 | Unknown literal | stl.h:388:9:388:9 | constructor init of field first | TAINT |
| stl.h:388:9:388:9 | Unknown literal | stl.h:388:9:388:9 | constructor init of field first | TAINT |
| stl.h:388:9:388:9 | Unknown literal | stl.h:388:9:388:9 | constructor init of field first | TAINT |
| stl.h:388:9:388:9 | Unknown literal | stl.h:388:9:388:9 | constructor init of field second | TAINT |
| stl.h:388:9:388:9 | Unknown literal | stl.h:388:9:388:9 | constructor init of field second | TAINT |
| stl.h:388:9:388:9 | Unknown literal | stl.h:388:9:388:9 | constructor init of field second | TAINT |
| stl.h:388:9:388:9 | Unknown literal | stl.h:388:9:388:9 | constructor init of field second | TAINT |
| stl.h:388:9:388:9 | Unknown literal | stl.h:388:9:388:9 | constructor init of field second | TAINT |
| stl.h:388:9:388:9 | constructor init of field first [post-this] | stl.h:388:9:388:9 | constructor init of field second [pre-this] | |
| stl.h:388:9:388:9 | constructor init of field first [post-this] | stl.h:388:9:388:9 | constructor init of field second [pre-this] | |
| stl.h:388:9:388:9 | constructor init of field first [post-this] | stl.h:388:9:388:9 | constructor init of field second [pre-this] | |
| stl.h:388:9:388:9 | constructor init of field first [post-this] | stl.h:388:9:388:9 | constructor init of field second [pre-this] | |
| stl.h:388:9:388:9 | constructor init of field first [post-this] | stl.h:388:9:388:9 | constructor init of field second [pre-this] | |
| stl.h:388:9:388:9 | constructor init of field first [pre-this] | stl.h:388:9:388:9 | constructor init of field second [pre-this] | |
| stl.h:388:9:388:9 | constructor init of field first [pre-this] | stl.h:388:9:388:9 | constructor init of field second [pre-this] | |
| stl.h:388:9:388:9 | constructor init of field first [pre-this] | stl.h:388:9:388:9 | constructor init of field second [pre-this] | |
| stl.h:388:9:388:9 | constructor init of field first [pre-this] | stl.h:388:9:388:9 | constructor init of field second [pre-this] | |
| stl.h:388:9:388:9 | constructor init of field first [pre-this] | stl.h:388:9:388:9 | constructor init of field second [pre-this] | |
| stl.h:388:9:388:9 | this | stl.h:388:9:388:9 | constructor init of field first [pre-this] | |
| stl.h:388:9:388:9 | this | stl.h:388:9:388:9 | constructor init of field first [pre-this] | |
| stl.h:388:9:388:9 | this | stl.h:388:9:388:9 | constructor init of field first [pre-this] | |
| stl.h:388:9:388:9 | this | stl.h:388:9:388:9 | constructor init of field first [pre-this] | |
| stl.h:388:9:388:9 | this | stl.h:388:9:388:9 | constructor init of field first [pre-this] | |
| stl.h:395:3:395:3 | this | stl.h:395:36:395:43 | constructor init of field first [pre-this] | |
| stl.h:395:3:395:3 | this | stl.h:395:36:395:43 | constructor init of field first [pre-this] | |
| stl.h:395:3:395:3 | this | stl.h:395:36:395:43 | constructor init of field first [pre-this] | |
| stl.h:395:3:395:3 | this | stl.h:395:36:395:43 | constructor init of field first [pre-this] | |
| stl.h:395:3:395:3 | this | stl.h:395:36:395:43 | constructor init of field first [pre-this] | |
| stl.h:395:3:395:6 | this | stl.h:395:36:395:43 | constructor init of field first [pre-this] | |
| stl.h:395:18:395:18 | x | stl.h:395:42:395:42 | x | |
| stl.h:395:18:395:18 | x | stl.h:395:42:395:42 | x | |
| stl.h:395:18:395:18 | x | stl.h:395:42:395:42 | x | |
| stl.h:395:18:395:18 | x | stl.h:395:42:395:42 | x | |
| stl.h:395:18:395:18 | x | stl.h:395:42:395:42 | x | |
| stl.h:395:18:395:18 | x | stl.h:395:42:395:42 | x | |
| stl.h:395:31:395:31 | y | stl.h:395:53:395:53 | y | |
| stl.h:395:31:395:31 | y | stl.h:395:53:395:53 | y | |
| stl.h:395:31:395:31 | y | stl.h:395:53:395:53 | y | |
| stl.h:395:31:395:31 | y | stl.h:395:53:395:53 | y | |
| stl.h:395:31:395:31 | y | stl.h:395:53:395:53 | y | |
| stl.h:395:31:395:31 | y | stl.h:395:53:395:53 | y | |
| stl.h:395:36:395:43 | call to unknown function | stl.h:395:36:395:43 | constructor init of field first | TAINT |
| stl.h:395:36:395:43 | constructor init of field first [post-this] | stl.h:395:46:395:54 | constructor init of field second [pre-this] | |
| stl.h:395:36:395:43 | constructor init of field first [post-this] | stl.h:395:46:395:54 | constructor init of field second [pre-this] | |
| stl.h:395:36:395:43 | constructor init of field first [post-this] | stl.h:395:46:395:54 | constructor init of field second [pre-this] | |
| stl.h:395:36:395:43 | constructor init of field first [post-this] | stl.h:395:46:395:54 | constructor init of field second [pre-this] | |
| stl.h:395:36:395:43 | constructor init of field first [post-this] | stl.h:395:46:395:54 | constructor init of field second [pre-this] | |
| stl.h:395:36:395:43 | constructor init of field first [post-this] | stl.h:395:46:395:54 | constructor init of field second [pre-this] | |
| stl.h:395:36:395:43 | constructor init of field first [pre-this] | stl.h:395:46:395:54 | constructor init of field second [pre-this] | |
| stl.h:395:36:395:43 | constructor init of field first [pre-this] | stl.h:395:46:395:54 | constructor init of field second [pre-this] | |
| stl.h:395:36:395:43 | constructor init of field first [pre-this] | stl.h:395:46:395:54 | constructor init of field second [pre-this] | |
| stl.h:395:36:395:43 | constructor init of field first [pre-this] | stl.h:395:46:395:54 | constructor init of field second [pre-this] | |
| stl.h:395:36:395:43 | constructor init of field first [pre-this] | stl.h:395:46:395:54 | constructor init of field second [pre-this] | |
| stl.h:395:36:395:43 | constructor init of field first [pre-this] | stl.h:395:46:395:54 | constructor init of field second [pre-this] | |
| stl.h:395:42:395:42 | x | stl.h:395:36:395:43 | constructor init of field first | TAINT |
| stl.h:395:42:395:42 | x | stl.h:395:36:395:43 | constructor init of field first | TAINT |
| stl.h:395:42:395:42 | x | stl.h:395:36:395:43 | constructor init of field first | TAINT |
| stl.h:395:42:395:42 | x | stl.h:395:36:395:43 | constructor init of field first | TAINT |
| stl.h:395:42:395:42 | x | stl.h:395:36:395:43 | constructor init of field first | TAINT |
| stl.h:395:46:395:54 | call to unknown function | stl.h:395:46:395:54 | constructor init of field second | TAINT |
| stl.h:395:53:395:53 | y | stl.h:395:46:395:54 | constructor init of field second | TAINT |
| stl.h:395:53:395:53 | y | stl.h:395:46:395:54 | constructor init of field second | TAINT |
| stl.h:395:53:395:53 | y | stl.h:395:46:395:54 | constructor init of field second | TAINT |
| stl.h:395:53:395:53 | y | stl.h:395:46:395:54 | constructor init of field second | TAINT |
| stl.h:395:53:395:53 | y | stl.h:395:46:395:54 | constructor init of field second | TAINT |
| stl.h:401:87:401:87 | x | stl.h:401:87:401:87 | x | |
| stl.h:401:87:401:87 | x | stl.h:401:87:401:87 | x | |
| stl.h:401:87:401:87 | x | stl.h:401:87:401:87 | x | |
| stl.h:401:87:401:87 | x | stl.h:401:87:401:87 | x | |
| stl.h:401:87:401:87 | x | stl.h:401:87:401:87 | x | |
| stl.h:401:87:401:87 | x | stl.h:401:87:401:87 | x | |
| stl.h:401:87:401:87 | x | stl.h:401:87:401:87 | x | |
| stl.h:401:87:401:87 | x | stl.h:402:58:402:58 | x | |
| stl.h:401:87:401:87 | x | stl.h:402:58:402:58 | x | |
| stl.h:401:87:401:87 | x | stl.h:402:58:402:58 | x | |
| stl.h:401:87:401:87 | x | stl.h:402:58:402:58 | x | |
| stl.h:401:87:401:87 | x | stl.h:402:58:402:58 | x | |
| stl.h:401:87:401:87 | x | stl.h:402:58:402:58 | x | |
| stl.h:401:87:401:87 | x | stl.h:402:58:402:58 | x | |
| stl.h:401:95:401:95 | y | stl.h:401:95:401:95 | y | |
| stl.h:401:95:401:95 | y | stl.h:401:95:401:95 | y | |
| stl.h:401:95:401:95 | y | stl.h:401:95:401:95 | y | |
| stl.h:401:95:401:95 | y | stl.h:401:95:401:95 | y | |
| stl.h:401:95:401:95 | y | stl.h:401:95:401:95 | y | |
| stl.h:401:95:401:95 | y | stl.h:401:95:401:95 | y | |
| stl.h:401:95:401:95 | y | stl.h:401:95:401:95 | y | |
| stl.h:401:95:401:95 | y | stl.h:402:79:402:79 | y | |
| stl.h:401:95:401:95 | y | stl.h:402:79:402:79 | y | |
| stl.h:401:95:401:95 | y | stl.h:402:79:402:79 | y | |
| stl.h:401:95:401:95 | y | stl.h:402:79:402:79 | y | |
| stl.h:401:95:401:95 | y | stl.h:402:79:402:79 | y | |
| stl.h:401:95:401:95 | y | stl.h:402:79:402:79 | y | |
| stl.h:401:95:401:95 | y | stl.h:402:79:402:79 | y | |
| stl.h:402:58:402:58 | x | stl.h:402:41:402:56 | call to forward | |
| stl.h:402:58:402:58 | x | stl.h:402:41:402:56 | call to forward | |
| stl.h:402:58:402:58 | x | stl.h:402:41:402:56 | call to forward | |
| stl.h:402:58:402:58 | x | stl.h:402:41:402:56 | call to forward | |
| stl.h:402:58:402:58 | x | stl.h:402:41:402:56 | call to forward | |
| stl.h:402:58:402:58 | x | stl.h:402:41:402:56 | call to forward | |
| stl.h:402:62:402:77 | call to forward | stl.h:402:3:402:82 | call to pair | TAINT |
| stl.h:402:62:402:77 | call to forward | stl.h:402:3:402:82 | call to pair | TAINT |
| stl.h:402:62:402:77 | call to forward | stl.h:402:3:402:82 | call to pair | TAINT |
| stl.h:402:62:402:77 | call to forward | stl.h:402:3:402:82 | call to pair | TAINT |
| stl.h:402:62:402:77 | call to forward | stl.h:402:3:402:82 | call to pair | TAINT |
| stl.h:402:62:402:77 | call to forward | stl.h:402:3:402:82 | call to pair | TAINT |
| stl.h:402:79:402:79 | y | stl.h:402:3:402:82 | call to pair | TAINT |
| stl.h:402:79:402:79 | y | stl.h:402:3:402:82 | call to pair | TAINT |
| stl.h:402:79:402:79 | y | stl.h:402:3:402:82 | call to pair | TAINT |
| stl.h:402:79:402:79 | y | stl.h:402:3:402:82 | call to pair | TAINT |
| stl.h:402:79:402:79 | y | stl.h:402:3:402:82 | call to pair | TAINT |
| stl.h:402:79:402:79 | y | stl.h:402:3:402:82 | call to pair | TAINT |
| stl.h:402:79:402:79 | y | stl.h:402:62:402:77 | call to forward | |
| stl.h:402:79:402:79 | y | stl.h:402:62:402:77 | call to forward | |
| stl.h:402:79:402:79 | y | stl.h:402:62:402:77 | call to forward | |
| stl.h:402:79:402:79 | y | stl.h:402:62:402:77 | call to forward | |
| stl.h:402:79:402:79 | y | stl.h:402:62:402:77 | call to forward | |
| stl.h:402:79:402:79 | y | stl.h:402:62:402:77 | call to forward | |
| string.cpp:25:12:25:17 | call to source | string.cpp:29:7:29:7 | a | |
| string.cpp:26:16:26:20 | 123 | string.cpp:26:16:26:21 | call to basic_string | TAINT |
| string.cpp:26:16:26:21 | call to basic_string | string.cpp:30:7:30:7 | b | |
@@ -5060,16 +5046,10 @@
| swap1.cpp:56:30:56:34 | data1 | swap1.cpp:56:18:56:22 | ref arg data1 | |
| swap1.cpp:61:22:61:22 | x | swap1.cpp:61:22:61:22 | x | |
| swap1.cpp:61:22:61:22 | x | swap1.cpp:63:9:63:9 | x | |
| swap1.cpp:61:22:61:22 | x | swap2.cpp:61:22:61:22 | x | |
| swap1.cpp:61:22:61:22 | x | swap2.cpp:63:9:63:9 | x | |
| swap1.cpp:61:32:61:32 | y | swap1.cpp:61:32:61:32 | y | |
| swap1.cpp:61:32:61:32 | y | swap1.cpp:63:16:63:16 | y | |
| swap1.cpp:61:32:61:32 | y | swap2.cpp:61:32:61:32 | y | |
| swap1.cpp:61:32:61:32 | y | swap2.cpp:63:16:63:16 | y | |
| swap1.cpp:63:9:63:9 | ref arg x | swap1.cpp:61:22:61:22 | x | |
| swap1.cpp:63:9:63:9 | ref arg x | swap2.cpp:61:22:61:22 | x | |
| swap1.cpp:63:16:63:16 | ref arg y | swap1.cpp:61:32:61:32 | y | |
| swap1.cpp:63:16:63:16 | ref arg y | swap2.cpp:61:32:61:32 | y | |
| swap1.cpp:69:23:69:23 | x | swap1.cpp:71:5:71:5 | x | |
| swap1.cpp:69:23:69:23 | x | swap1.cpp:73:10:73:10 | x | |
| swap1.cpp:69:23:69:23 | x | swap1.cpp:76:9:76:9 | x | |
@@ -5230,17 +5210,11 @@
| swap2.cpp:56:50:56:53 | that | swap2.cpp:56:43:56:47 | ref arg data2 | |
| swap2.cpp:56:50:56:53 | that [post update] | swap2.cpp:53:26:53:29 | that | |
| swap2.cpp:56:55:56:59 | data2 | swap2.cpp:56:43:56:47 | ref arg data2 | |
| swap2.cpp:61:22:61:22 | x | swap1.cpp:61:22:61:22 | x | |
| swap2.cpp:61:22:61:22 | x | swap1.cpp:63:9:63:9 | x | |
| swap2.cpp:61:22:61:22 | x | swap2.cpp:61:22:61:22 | x | |
| swap2.cpp:61:22:61:22 | x | swap2.cpp:63:9:63:9 | x | |
| swap2.cpp:61:32:61:32 | y | swap1.cpp:61:32:61:32 | y | |
| swap2.cpp:61:32:61:32 | y | swap1.cpp:63:16:63:16 | y | |
| swap2.cpp:61:32:61:32 | y | swap2.cpp:61:32:61:32 | y | |
| swap2.cpp:61:32:61:32 | y | swap2.cpp:63:16:63:16 | y | |
| swap2.cpp:63:9:63:9 | ref arg x | swap1.cpp:61:22:61:22 | x | |
| swap2.cpp:63:9:63:9 | ref arg x | swap2.cpp:61:22:61:22 | x | |
| swap2.cpp:63:16:63:16 | ref arg y | swap1.cpp:61:32:61:32 | y | |
| swap2.cpp:63:16:63:16 | ref arg y | swap2.cpp:61:32:61:32 | y | |
| swap2.cpp:69:23:69:23 | x | swap2.cpp:71:5:71:5 | x | |
| swap2.cpp:69:23:69:23 | x | swap2.cpp:73:10:73:10 | x | |
@@ -7257,3 +7231,24 @@
| vector.cpp:484:29:484:33 | call to c_str | vector.cpp:484:3:484:8 | call to memcpy | TAINT |
| vector.cpp:484:29:484:33 | call to c_str | vector.cpp:484:10:484:22 | ref arg & ... | TAINT |
| vector.cpp:486:8:486:9 | ref arg cs | vector.cpp:487:2:487:2 | cs | |
| vector.cpp:491:22:491:24 | call to vector | vector.cpp:493:2:493:3 | v1 | |
| vector.cpp:491:22:491:24 | call to vector | vector.cpp:494:7:494:8 | v1 | |
| vector.cpp:491:22:491:24 | call to vector | vector.cpp:498:1:498:1 | v1 | |
| vector.cpp:491:30:491:32 | call to vector | vector.cpp:496:2:496:3 | v2 | |
| vector.cpp:491:30:491:32 | call to vector | vector.cpp:496:13:496:14 | v2 | |
| vector.cpp:491:30:491:32 | call to vector | vector.cpp:497:7:497:8 | v2 | |
| vector.cpp:491:30:491:32 | call to vector | vector.cpp:498:1:498:1 | v2 | |
| vector.cpp:493:2:493:3 | ref arg v1 | vector.cpp:494:7:494:8 | v1 | |
| vector.cpp:493:2:493:3 | ref arg v1 | vector.cpp:498:1:498:1 | v1 | |
| vector.cpp:493:18:493:23 | call to source | vector.cpp:493:2:493:3 | ref arg v1 | TAINT |
| vector.cpp:494:7:494:8 | ref arg v1 | vector.cpp:498:1:498:1 | v1 | |
| vector.cpp:496:2:496:3 | ref arg v2 | vector.cpp:497:7:497:8 | v2 | |
| vector.cpp:496:2:496:3 | ref arg v2 | vector.cpp:498:1:498:1 | v2 | |
| vector.cpp:496:13:496:14 | ref arg v2 | vector.cpp:496:2:496:3 | v2 | |
| vector.cpp:496:13:496:14 | ref arg v2 | vector.cpp:497:7:497:8 | v2 | |
| vector.cpp:496:13:496:14 | ref arg v2 | vector.cpp:498:1:498:1 | v2 | |
| vector.cpp:496:13:496:14 | v2 | vector.cpp:496:16:496:20 | call to begin | TAINT |
| vector.cpp:496:16:496:20 | call to begin | vector.cpp:496:13:496:22 | call to iterator | TAINT |
| vector.cpp:496:25:496:30 | call to source | vector.cpp:496:2:496:3 | ref arg v2 | TAINT |
| vector.cpp:496:25:496:30 | call to source | vector.cpp:496:5:496:11 | call to emplace | TAINT |
| vector.cpp:497:7:497:8 | ref arg v2 | vector.cpp:498:1:498:1 | v2 | |

View File

@@ -2,9 +2,9 @@
#include "stl.h"
using namespace std;
namespace {
char *source();
}
void sink(char *);
void sink(const char *);
void sink(bool);
@@ -84,10 +84,10 @@ void test_pair()
sink(make_pair("123", "456").first);
sink(make_pair("123", "456").second);
sink(make_pair(source(), "456")); // tainted [NOT DETECTED]
sink(make_pair(source(), "456").first); // tainted [NOT DETECTED]
sink(make_pair(source(), "456").first); // tainted
sink(make_pair(source(), "456").second);
sink(make_pair("123", source())); // tainted
sink(make_pair("123", source()).first); // [FALSE POSITIVE]
sink(make_pair("123", source()).first);
sink(make_pair("123", source()).second); // tainted
std::pair<std::pair<char *, char *>, char *> m;

View File

@@ -19,10 +19,10 @@ public:
int v;
};
MyMovableClass &&getUnTainted() { return MyMovableClass(1); }
MyMovableClass &&getTainted() { return MyMovableClass(source()); }
MyMovableClass getUnTainted() { return MyMovableClass(1); }
MyMovableClass getTainted() { return MyMovableClass(source()); }
void test_copyableclass()
void test_movableclass()
{
{
MyMovableClass s1(1);

View File

@@ -2,9 +2,9 @@
#include "stl.h"
using namespace std;
namespace {
char *source();
}
void sink(char *);
void sink(std::set<char *>);
void sink(std::set<char *>::iterator);

View File

@@ -1,28 +1,28 @@
typedef unsigned long size_t;
template<class T>
struct remove_const { typedef T type; };
template<class T>
struct remove_const<const T> { typedef T type; };
// `remove_const_t<T>` removes any `const` specifier from `T`
template<class T>
using remove_const_t = typename remove_const<T>::type;
template<class T>
struct remove_reference { typedef T type; };
template<class T>
struct remove_reference<T &> { typedef T type; };
template<class T>
struct remove_reference<T &&> { typedef T type; };
// `remove_reference_t<T>` removes any `&` from `T`
template<class T>
using remove_reference_t = typename remove_reference<T>::type;
#include "type_traits.h"
namespace std
{
@@ -332,6 +332,9 @@ namespace std {
iterator insert(const_iterator position, size_type n, const T& x);
template<class InputIterator> iterator insert(const_iterator position, InputIterator first, InputIterator last);
template <class... Args> iterator emplace (const_iterator position, Args&&... args);
template <class... Args> void emplace_back (Args&&... args);
void swap(vector&) noexcept/*(allocator_traits<Allocator>::propagate_on_container_swap::value || allocator_traits<Allocator>::is_always_equal::value)*/;
void clear() noexcept;
@@ -395,8 +398,8 @@ namespace std {
void swap(pair& p) /*noexcept(...)*/;
};
template<class T1, class T2> constexpr pair<remove_reference_t<T1>, remove_reference_t<T2>> make_pair(T1&& x, T2&& y) {
return pair<T1, T2>(std::forward<T1>(x), std::forward<T2>(y));
template<class T1, class T2> constexpr pair<decay_t<T1>, decay_t<T2>> make_pair(T1&& x, T2&& y) {
return pair<decay_t<T1>, decay_t<T2>>(std::forward<T1>(x), std::forward<T2>(y));
}
}

View File

@@ -2,9 +2,9 @@
#include "stl.h"
using namespace std;
namespace {
char *source();
}
namespace ns_char
{
char source();
@@ -499,7 +499,7 @@ void test_string_iterator_methods()
}
}
void test_constructors_more() {
void test_string_constructors_more() {
char *cs1 = "abc";
char *cs2 = source();
std::string s1(cs1);

View File

@@ -2,9 +2,9 @@
#include "stl.h"
using namespace std;
namespace {
char *source();
}
namespace ns_char
{
char source();

View File

@@ -1,6 +1,6 @@
int source();
void sink(...) {};
void sink(...);
class StructLikeClass {
public:

View File

@@ -13,7 +13,7 @@ namespace std
template <class T>
T &&move(T &t) noexcept { return static_cast<T &&>(t); } // simplified signature (and implementation)
} // namespace std
namespace Swap1 {
namespace IntWrapper
{
struct Class
@@ -84,7 +84,7 @@ void test_copy_assignment_operator()
swap(z1, z2);
sink(z2.data1); // tainted [FALSE NEGATIVE in IR]
sink(z2.data1); // tainted
sink(z1.data1); // clean [FALSE POSITIVE]
}
@@ -144,3 +144,5 @@ void test_move_assignment_method()
sink(y.data1); // tainted
sink(x.data1); // tainted
}
}

View File

@@ -13,7 +13,7 @@ namespace std
template <class T>
T &&move(T &t) noexcept { return static_cast<T &&>(t); } // simplified signature (and implementation)
} // namespace std
namespace Swap2 {
namespace IntWrapper
{
struct Class
@@ -84,7 +84,7 @@ void test_copy_assignment_operator()
swap(z1, z2);
sink(z2.data1); // tainted [FALSE NEGATIVE in IR]
sink(z2.data1); // tainted
sink(z1.data1); // clean [FALSE POSITIVE]
}
@@ -144,3 +144,5 @@ void test_move_assignment_method()
sink(y.data1); // tainted
sink(x.data1); // tainted
}
}

View File

@@ -1,5 +1,5 @@
int source();
void sink(...) {};
void sink(...);
void arithAssignments(int source1, int clean1) {
sink(clean1); // clean

View File

@@ -48,7 +48,9 @@
| map.cpp:77:9:77:14 | second | map.cpp:66:37:66:42 | call to source |
| map.cpp:78:7:78:7 | k | map.cpp:66:37:66:42 | call to source |
| map.cpp:81:7:81:7 | l | map.cpp:66:37:66:42 | call to source |
| map.cpp:87:34:87:38 | first | map.cpp:87:17:87:22 | call to source |
| map.cpp:89:7:89:32 | call to pair | map.cpp:89:24:89:29 | call to source |
| map.cpp:91:34:91:39 | second | map.cpp:91:24:91:29 | call to source |
| map.cpp:110:10:110:15 | call to insert | map.cpp:110:62:110:67 | call to source |
| map.cpp:112:10:112:25 | call to insert_or_assign | map.cpp:112:46:112:51 | call to source |
| map.cpp:114:7:114:8 | call to map | map.cpp:108:39:108:44 | call to source |
@@ -666,3 +668,5 @@
| vector.cpp:482:8:482:10 | src | vector.cpp:478:21:478:37 | call to source |
| vector.cpp:485:8:485:10 | src | vector.cpp:478:21:478:37 | call to source |
| vector.cpp:486:8:486:9 | cs | vector.cpp:478:21:478:37 | call to source |
| vector.cpp:494:7:494:8 | v1 | vector.cpp:493:18:493:23 | call to source |
| vector.cpp:497:7:497:8 | v2 | vector.cpp:496:25:496:30 | call to source |

View File

@@ -15,7 +15,6 @@
| arrayassignment.cpp:146:7:146:13 | arrayassignment.cpp:144:12:144:17 | IR only |
| copyableclass.cpp:67:11:67:11 | copyableclass.cpp:67:13:67:18 | AST only |
| copyableclass.cpp:67:11:67:21 | copyableclass.cpp:67:13:67:18 | IR only |
| copyableclass_declonly.cpp:42:8:42:9 | copyableclass_declonly.cpp:34:30:34:35 | AST only |
| copyableclass_declonly.cpp:67:11:67:11 | copyableclass_declonly.cpp:67:13:67:18 | AST only |
| map.cpp:49:9:49:13 | map.cpp:48:37:48:42 | IR only |
| map.cpp:54:9:54:13 | map.cpp:48:37:48:42 | IR only |
@@ -27,22 +26,8 @@
| map.cpp:79:9:79:13 | map.cpp:66:37:66:42 | IR only |
| map.cpp:80:9:80:14 | map.cpp:66:37:66:42 | IR only |
| map.cpp:90:34:90:38 | map.cpp:90:24:90:29 | IR only |
| map.cpp:91:34:91:39 | map.cpp:91:24:91:29 | IR only |
| map.cpp:108:7:108:54 | map.cpp:108:39:108:44 | IR only |
| map.cpp:111:7:111:48 | map.cpp:111:34:111:39 | IR only |
| map.cpp:114:7:114:8 | map.cpp:108:39:108:44 | AST only |
| map.cpp:116:7:116:8 | map.cpp:110:62:110:67 | AST only |
| map.cpp:117:7:117:8 | map.cpp:111:34:111:39 | AST only |
| map.cpp:118:7:118:8 | map.cpp:112:46:112:51 | AST only |
| map.cpp:123:10:123:13 | map.cpp:111:34:111:39 | AST only |
| map.cpp:124:10:124:13 | map.cpp:112:46:112:51 | AST only |
| map.cpp:129:10:129:13 | map.cpp:111:34:111:39 | AST only |
| map.cpp:130:10:130:13 | map.cpp:112:46:112:51 | AST only |
| map.cpp:137:7:137:8 | map.cpp:108:39:108:44 | AST only |
| map.cpp:138:7:138:8 | map.cpp:108:39:108:44 | AST only |
| map.cpp:139:7:139:8 | map.cpp:108:39:108:44 | AST only |
| map.cpp:140:10:140:13 | map.cpp:108:39:108:44 | AST only |
| map.cpp:141:10:141:13 | map.cpp:108:39:108:44 | AST only |
| map.cpp:155:12:155:16 | map.cpp:108:39:108:44 | IR only |
| map.cpp:156:12:156:17 | map.cpp:108:39:108:44 | IR only |
| map.cpp:161:12:161:16 | map.cpp:108:39:108:44 | IR only |
@@ -52,44 +37,10 @@
| map.cpp:184:7:184:31 | map.cpp:108:39:108:44 | IR only |
| map.cpp:185:7:185:32 | map.cpp:108:39:108:44 | IR only |
| map.cpp:187:7:187:32 | map.cpp:108:39:108:44 | IR only |
| map.cpp:193:7:193:9 | map.cpp:191:49:191:54 | AST only |
| map.cpp:196:7:196:9 | map.cpp:192:49:192:54 | AST only |
| map.cpp:199:7:199:9 | map.cpp:191:49:191:54 | AST only |
| map.cpp:200:7:200:9 | map.cpp:191:49:191:54 | AST only |
| map.cpp:201:7:201:9 | map.cpp:192:49:192:54 | AST only |
| map.cpp:202:7:202:9 | map.cpp:192:49:192:54 | AST only |
| map.cpp:210:7:210:9 | map.cpp:206:49:206:54 | AST only |
| map.cpp:213:7:213:9 | map.cpp:209:49:209:54 | AST only |
| map.cpp:216:7:216:9 | map.cpp:206:49:206:54 | AST only |
| map.cpp:218:7:218:9 | map.cpp:209:49:209:54 | AST only |
| map.cpp:219:7:219:9 | map.cpp:209:49:209:54 | AST only |
| map.cpp:225:7:225:9 | map.cpp:223:49:223:54 | AST only |
| map.cpp:225:7:225:9 | map.cpp:224:49:224:54 | AST only |
| map.cpp:227:7:227:9 | map.cpp:223:49:223:54 | AST only |
| map.cpp:227:7:227:9 | map.cpp:224:49:224:54 | AST only |
| map.cpp:229:7:229:9 | map.cpp:223:49:223:54 | AST only |
| map.cpp:229:7:229:9 | map.cpp:224:49:224:54 | AST only |
| map.cpp:235:7:235:40 | map.cpp:235:26:235:31 | IR only |
| map.cpp:236:7:236:9 | map.cpp:235:26:235:31 | AST only |
| map.cpp:240:7:240:9 | map.cpp:239:44:239:49 | AST only |
| map.cpp:246:7:246:44 | map.cpp:246:30:246:35 | IR only |
| map.cpp:247:7:247:9 | map.cpp:246:30:246:35 | AST only |
| map.cpp:251:7:251:9 | map.cpp:250:43:250:48 | AST only |
| map.cpp:260:7:260:54 | map.cpp:260:39:260:44 | IR only |
| map.cpp:263:7:263:48 | map.cpp:263:34:263:39 | IR only |
| map.cpp:266:7:266:8 | map.cpp:260:39:260:44 | AST only |
| map.cpp:268:7:268:8 | map.cpp:262:62:262:67 | AST only |
| map.cpp:269:7:269:8 | map.cpp:263:34:263:39 | AST only |
| map.cpp:270:7:270:8 | map.cpp:264:46:264:51 | AST only |
| map.cpp:275:10:275:13 | map.cpp:263:34:263:39 | AST only |
| map.cpp:276:10:276:13 | map.cpp:264:46:264:51 | AST only |
| map.cpp:281:10:281:13 | map.cpp:263:34:263:39 | AST only |
| map.cpp:282:10:282:13 | map.cpp:264:46:264:51 | AST only |
| map.cpp:289:7:289:8 | map.cpp:260:39:260:44 | AST only |
| map.cpp:290:7:290:8 | map.cpp:260:39:260:44 | AST only |
| map.cpp:291:7:291:8 | map.cpp:260:39:260:44 | AST only |
| map.cpp:292:10:292:13 | map.cpp:260:39:260:44 | AST only |
| map.cpp:293:10:293:13 | map.cpp:260:39:260:44 | AST only |
| map.cpp:307:12:307:16 | map.cpp:260:39:260:44 | IR only |
| map.cpp:308:12:308:17 | map.cpp:260:39:260:44 | IR only |
| map.cpp:313:12:313:16 | map.cpp:260:39:260:44 | IR only |
@@ -99,105 +50,25 @@
| map.cpp:334:7:334:31 | map.cpp:260:39:260:44 | IR only |
| map.cpp:335:7:335:32 | map.cpp:260:39:260:44 | IR only |
| map.cpp:336:7:336:32 | map.cpp:260:39:260:44 | IR only |
| map.cpp:342:7:342:9 | map.cpp:340:49:340:54 | AST only |
| map.cpp:345:7:345:9 | map.cpp:341:49:341:54 | AST only |
| map.cpp:348:7:348:9 | map.cpp:340:49:340:54 | AST only |
| map.cpp:349:7:349:9 | map.cpp:340:49:340:54 | AST only |
| map.cpp:350:7:350:9 | map.cpp:341:49:341:54 | AST only |
| map.cpp:351:7:351:9 | map.cpp:341:49:341:54 | AST only |
| map.cpp:359:7:359:9 | map.cpp:355:49:355:54 | AST only |
| map.cpp:362:7:362:9 | map.cpp:358:49:358:54 | AST only |
| map.cpp:365:7:365:9 | map.cpp:355:49:355:54 | AST only |
| map.cpp:367:7:367:9 | map.cpp:358:49:358:54 | AST only |
| map.cpp:368:7:368:9 | map.cpp:358:49:358:54 | AST only |
| map.cpp:374:7:374:9 | map.cpp:372:49:372:54 | AST only |
| map.cpp:374:7:374:9 | map.cpp:373:49:373:54 | AST only |
| map.cpp:376:7:376:9 | map.cpp:372:49:372:54 | AST only |
| map.cpp:376:7:376:9 | map.cpp:373:49:373:54 | AST only |
| map.cpp:378:7:378:9 | map.cpp:372:49:372:54 | AST only |
| map.cpp:378:7:378:9 | map.cpp:373:49:373:54 | AST only |
| map.cpp:384:7:384:40 | map.cpp:384:26:384:31 | IR only |
| map.cpp:385:7:385:9 | map.cpp:384:26:384:31 | AST only |
| map.cpp:389:7:389:9 | map.cpp:388:44:388:49 | AST only |
| map.cpp:396:7:396:44 | map.cpp:396:30:396:35 | IR only |
| map.cpp:397:40:397:45 | map.cpp:396:30:396:35 | IR only |
| map.cpp:397:40:397:45 | map.cpp:397:30:397:35 | IR only |
| map.cpp:398:7:398:9 | map.cpp:396:30:396:35 | AST only |
| map.cpp:398:7:398:9 | map.cpp:397:30:397:35 | AST only |
| map.cpp:402:7:402:9 | map.cpp:401:43:401:48 | AST only |
| map.cpp:417:7:417:9 | map.cpp:416:30:416:35 | AST only |
| map.cpp:418:7:418:16 | map.cpp:416:30:416:35 | AST only |
| map.cpp:420:7:420:9 | map.cpp:419:33:419:38 | AST only |
| map.cpp:421:7:421:16 | map.cpp:419:33:419:38 | AST only |
| map.cpp:431:7:431:67 | map.cpp:431:52:431:57 | IR only |
| map.cpp:432:7:432:9 | map.cpp:431:52:431:57 | AST only |
| movableclass.cpp:65:11:65:11 | movableclass.cpp:65:13:65:18 | AST only |
| movableclass.cpp:65:11:65:21 | movableclass.cpp:65:13:65:18 | IR only |
| set.cpp:20:7:20:31 | set.cpp:20:17:20:22 | IR only |
| set.cpp:26:7:26:8 | set.cpp:20:17:20:22 | AST only |
| set.cpp:28:7:28:8 | set.cpp:22:29:22:34 | AST only |
| set.cpp:30:7:30:8 | set.cpp:20:17:20:22 | AST only |
| set.cpp:44:7:44:8 | set.cpp:20:17:20:22 | AST only |
| set.cpp:45:7:45:8 | set.cpp:20:17:20:22 | AST only |
| set.cpp:46:7:46:8 | set.cpp:20:17:20:22 | AST only |
| set.cpp:47:7:47:9 | set.cpp:20:17:20:22 | AST only |
| set.cpp:48:10:48:13 | set.cpp:20:17:20:22 | AST only |
| set.cpp:49:10:49:13 | set.cpp:20:17:20:22 | AST only |
| set.cpp:61:8:61:11 | set.cpp:20:17:20:22 | IR only |
| set.cpp:71:7:71:32 | set.cpp:67:13:67:18 | IR only |
| set.cpp:72:7:72:33 | set.cpp:67:13:67:18 | IR only |
| set.cpp:78:7:78:9 | set.cpp:76:13:76:18 | AST only |
| set.cpp:81:7:81:9 | set.cpp:77:13:77:18 | AST only |
| set.cpp:84:7:84:9 | set.cpp:76:13:76:18 | AST only |
| set.cpp:85:7:85:9 | set.cpp:76:13:76:18 | AST only |
| set.cpp:86:7:86:9 | set.cpp:77:13:77:18 | AST only |
| set.cpp:87:7:87:9 | set.cpp:77:13:77:18 | AST only |
| set.cpp:95:7:95:9 | set.cpp:91:13:91:18 | AST only |
| set.cpp:98:7:98:9 | set.cpp:94:13:94:18 | AST only |
| set.cpp:101:7:101:9 | set.cpp:91:13:91:18 | AST only |
| set.cpp:103:7:103:9 | set.cpp:94:13:94:18 | AST only |
| set.cpp:104:7:104:9 | set.cpp:94:13:94:18 | AST only |
| set.cpp:110:7:110:9 | set.cpp:108:13:108:18 | AST only |
| set.cpp:110:7:110:9 | set.cpp:109:13:109:18 | AST only |
| set.cpp:112:7:112:9 | set.cpp:108:13:108:18 | AST only |
| set.cpp:112:7:112:9 | set.cpp:109:13:109:18 | AST only |
| set.cpp:114:7:114:9 | set.cpp:108:13:108:18 | AST only |
| set.cpp:114:7:114:9 | set.cpp:109:13:109:18 | AST only |
| set.cpp:120:7:120:33 | set.cpp:120:19:120:24 | IR only |
| set.cpp:121:7:121:9 | set.cpp:120:19:120:24 | AST only |
| set.cpp:125:7:125:9 | set.cpp:124:37:124:42 | AST only |
| set.cpp:134:7:134:31 | set.cpp:134:17:134:22 | IR only |
| set.cpp:140:7:140:8 | set.cpp:134:17:134:22 | AST only |
| set.cpp:142:7:142:8 | set.cpp:136:29:136:34 | AST only |
| set.cpp:144:7:144:8 | set.cpp:134:17:134:22 | AST only |
| set.cpp:158:7:158:8 | set.cpp:134:17:134:22 | AST only |
| set.cpp:159:7:159:8 | set.cpp:134:17:134:22 | AST only |
| set.cpp:160:7:160:8 | set.cpp:134:17:134:22 | AST only |
| set.cpp:161:7:161:9 | set.cpp:134:17:134:22 | AST only |
| set.cpp:162:10:162:13 | set.cpp:134:17:134:22 | AST only |
| set.cpp:163:10:163:13 | set.cpp:134:17:134:22 | AST only |
| set.cpp:175:8:175:11 | set.cpp:134:17:134:22 | IR only |
| set.cpp:183:7:183:32 | set.cpp:181:13:181:18 | IR only |
| set.cpp:184:7:184:33 | set.cpp:181:13:181:18 | IR only |
| set.cpp:190:7:190:9 | set.cpp:188:13:188:18 | AST only |
| set.cpp:193:7:193:9 | set.cpp:189:13:189:18 | AST only |
| set.cpp:196:7:196:9 | set.cpp:188:13:188:18 | AST only |
| set.cpp:197:7:197:9 | set.cpp:188:13:188:18 | AST only |
| set.cpp:198:7:198:9 | set.cpp:189:13:189:18 | AST only |
| set.cpp:199:7:199:9 | set.cpp:189:13:189:18 | AST only |
| set.cpp:207:7:207:9 | set.cpp:203:13:203:18 | AST only |
| set.cpp:210:7:210:9 | set.cpp:206:13:206:18 | AST only |
| set.cpp:213:7:213:9 | set.cpp:203:13:203:18 | AST only |
| set.cpp:215:7:215:9 | set.cpp:206:13:206:18 | AST only |
| set.cpp:216:7:216:9 | set.cpp:206:13:206:18 | AST only |
| set.cpp:222:7:222:9 | set.cpp:220:13:220:18 | AST only |
| set.cpp:222:7:222:9 | set.cpp:221:13:221:18 | AST only |
| set.cpp:224:7:224:9 | set.cpp:220:13:220:18 | AST only |
| set.cpp:224:7:224:9 | set.cpp:221:13:221:18 | AST only |
| set.cpp:226:7:226:9 | set.cpp:220:13:220:18 | AST only |
| set.cpp:226:7:226:9 | set.cpp:221:13:221:18 | AST only |
| set.cpp:232:7:232:33 | set.cpp:232:19:232:24 | IR only |
| set.cpp:233:7:233:9 | set.cpp:232:19:232:24 | AST only |
| set.cpp:237:7:237:9 | set.cpp:236:37:236:42 | AST only |
| smart_pointer.cpp:12:10:12:10 | smart_pointer.cpp:11:52:11:57 | AST only |
| smart_pointer.cpp:24:10:24:10 | smart_pointer.cpp:23:52:23:57 | AST only |
| standalone_iterators.cpp:41:10:41:10 | standalone_iterators.cpp:39:45:39:51 | AST only |
@@ -211,6 +82,10 @@
| string.cpp:46:13:46:17 | string.cpp:14:10:14:15 | AST only |
| string.cpp:70:7:70:8 | string.cpp:62:19:62:24 | AST only |
| string.cpp:126:8:126:11 | string.cpp:120:16:120:21 | IR only |
| string.cpp:145:8:145:14 | string.cpp:142:18:142:23 | IR only |
| string.cpp:146:8:146:14 | string.cpp:142:18:142:23 | IR only |
| string.cpp:147:8:147:14 | string.cpp:142:18:142:23 | IR only |
| string.cpp:150:8:150:20 | string.cpp:150:13:150:18 | IR only |
| string.cpp:162:11:162:11 | string.cpp:155:18:155:23 | AST only |
| string.cpp:166:11:166:11 | string.cpp:166:14:166:19 | AST only |
| string.cpp:167:11:167:11 | string.cpp:166:14:166:19 | AST only |
@@ -223,6 +98,7 @@
| string.cpp:247:10:247:16 | string.cpp:234:17:234:22 | AST only |
| string.cpp:251:10:251:16 | string.cpp:235:11:235:25 | AST only |
| string.cpp:312:9:312:12 | string.cpp:309:16:309:21 | AST only |
| string.cpp:323:7:323:29 | string.cpp:320:16:320:21 | IR only |
| string.cpp:340:7:340:7 | string.cpp:336:9:336:23 | AST only |
| string.cpp:341:7:341:7 | string.cpp:337:12:337:26 | AST only |
| string.cpp:342:7:342:7 | string.cpp:336:9:336:23 | AST only |
@@ -231,8 +107,8 @@
| string.cpp:363:11:363:16 | string.cpp:358:18:358:23 | AST only |
| string.cpp:382:8:382:14 | string.cpp:374:18:374:23 | IR only |
| string.cpp:383:13:383:15 | string.cpp:374:18:374:23 | IR only |
| string.cpp:396:8:396:8 | string.cpp:389:18:389:23 | AST only |
| string.cpp:397:8:397:8 | string.cpp:389:18:389:23 | AST only |
| string.cpp:396:8:396:15 | string.cpp:389:18:389:23 | IR only |
| string.cpp:397:8:397:15 | string.cpp:389:18:389:23 | IR only |
| string.cpp:399:8:399:8 | string.cpp:389:18:389:23 | AST only |
| string.cpp:401:8:401:8 | string.cpp:389:18:389:23 | AST only |
| string.cpp:404:8:404:11 | string.cpp:389:18:389:23 | IR only |
@@ -241,9 +117,7 @@
| string.cpp:411:8:411:8 | string.cpp:389:18:389:23 | AST only |
| string.cpp:415:8:415:11 | string.cpp:389:18:389:23 | IR only |
| string.cpp:418:8:418:8 | string.cpp:389:18:389:23 | AST only |
| string.cpp:419:8:419:10 | string.cpp:389:18:389:23 | AST only |
| string.cpp:421:8:421:8 | string.cpp:389:18:389:23 | AST only |
| string.cpp:422:8:422:10 | string.cpp:389:18:389:23 | AST only |
| string.cpp:436:10:436:15 | string.cpp:431:14:431:19 | AST only |
| string.cpp:449:10:449:15 | string.cpp:449:32:449:46 | AST only |
| string.cpp:462:10:462:15 | string.cpp:457:18:457:23 | AST only |
@@ -268,7 +142,9 @@
| stringstream.cpp:35:11:35:11 | stringstream.cpp:29:16:29:21 | AST only |
| stringstream.cpp:39:7:39:9 | stringstream.cpp:33:23:33:28 | AST only |
| stringstream.cpp:41:7:41:9 | stringstream.cpp:29:16:29:21 | AST only |
| stringstream.cpp:43:7:43:15 | stringstream.cpp:32:14:32:19 | IR only |
| stringstream.cpp:44:11:44:13 | stringstream.cpp:33:23:33:28 | AST only |
| stringstream.cpp:45:7:45:15 | stringstream.cpp:34:14:34:19 | IR only |
| stringstream.cpp:46:11:46:13 | stringstream.cpp:29:16:29:21 | AST only |
| stringstream.cpp:56:11:56:13 | stringstream.cpp:56:15:56:29 | AST only |
| stringstream.cpp:57:44:57:46 | stringstream.cpp:57:25:57:39 | AST only |
@@ -278,6 +154,7 @@
| stringstream.cpp:67:7:67:10 | stringstream.cpp:64:36:64:41 | AST only |
| stringstream.cpp:76:11:76:11 | stringstream.cpp:70:32:70:37 | AST only |
| stringstream.cpp:78:11:78:11 | stringstream.cpp:70:32:70:37 | AST only |
| stringstream.cpp:83:7:83:15 | stringstream.cpp:70:32:70:37 | IR only |
| stringstream.cpp:100:11:100:11 | stringstream.cpp:100:31:100:36 | AST only |
| stringstream.cpp:143:11:143:22 | stringstream.cpp:143:14:143:19 | IR only |
| stringstream.cpp:146:11:146:11 | stringstream.cpp:143:14:143:19 | AST only |
@@ -307,13 +184,13 @@
| stringstream.cpp:266:62:266:66 | stringstream.cpp:266:41:266:46 | AST only |
| stringstream.cpp:267:7:267:9 | stringstream.cpp:266:41:266:46 | AST only |
| swap1.cpp:78:12:78:16 | swap1.cpp:69:23:69:23 | AST only |
| swap1.cpp:87:13:87:17 | swap1.cpp:82:16:82:21 | AST only |
| swap1.cpp:88:13:88:17 | swap1.cpp:81:27:81:28 | AST only |
| swap1.cpp:102:12:102:16 | swap1.cpp:93:23:93:23 | AST only |
| swap1.cpp:115:18:115:22 | swap1.cpp:108:23:108:31 | AST only |
| swap1.cpp:129:12:129:16 | swap1.cpp:120:23:120:23 | AST only |
| swap1.cpp:144:12:144:16 | swap1.cpp:135:23:135:23 | AST only |
| swap2.cpp:78:12:78:16 | swap2.cpp:69:23:69:23 | AST only |
| swap2.cpp:87:13:87:17 | swap2.cpp:82:16:82:21 | IR only |
| swap2.cpp:88:13:88:17 | swap2.cpp:81:27:81:28 | AST only |
| swap2.cpp:102:12:102:16 | swap2.cpp:93:23:93:23 | AST only |
| swap2.cpp:115:18:115:22 | swap2.cpp:108:23:108:31 | AST only |
@@ -358,7 +235,6 @@
| vector.cpp:171:13:171:13 | vector.cpp:170:14:170:19 | AST only |
| vector.cpp:180:13:180:13 | vector.cpp:179:14:179:19 | AST only |
| vector.cpp:201:13:201:13 | vector.cpp:200:14:200:19 | AST only |
| vector.cpp:261:8:261:9 | vector.cpp:239:15:239:20 | AST only |
| vector.cpp:286:10:286:13 | vector.cpp:284:15:284:20 | AST only |
| vector.cpp:287:7:287:18 | vector.cpp:284:15:284:20 | AST only |
| vector.cpp:290:7:290:8 | vector.cpp:289:17:289:30 | AST only |
@@ -390,3 +266,5 @@
| vector.cpp:450:8:450:10 | vector.cpp:449:11:449:16 | AST only |
| vector.cpp:473:8:473:8 | vector.cpp:468:11:468:16 | AST only |
| vector.cpp:486:8:486:9 | vector.cpp:478:21:478:37 | AST only |
| vector.cpp:494:7:494:8 | vector.cpp:493:18:493:23 | AST only |
| vector.cpp:497:7:497:8 | vector.cpp:496:25:496:30 | AST only |

View File

@@ -26,6 +26,7 @@
| copyableclass.cpp:67:11:67:21 | (reference dereference) | copyableclass.cpp:67:13:67:18 | call to source |
| copyableclass_declonly.cpp:40:8:40:9 | s1 | copyableclass_declonly.cpp:34:30:34:35 | call to source |
| copyableclass_declonly.cpp:41:8:41:9 | s2 | copyableclass_declonly.cpp:35:32:35:37 | call to source |
| copyableclass_declonly.cpp:42:8:42:9 | s3 | copyableclass_declonly.cpp:34:30:34:35 | call to source |
| copyableclass_declonly.cpp:43:8:43:9 | s4 | copyableclass_declonly.cpp:38:8:38:13 | call to source |
| copyableclass_declonly.cpp:65:8:65:9 | s1 | copyableclass_declonly.cpp:60:56:60:61 | call to source |
| copyableclass_declonly.cpp:66:8:66:9 | s2 | copyableclass_declonly.cpp:63:32:63:37 | call to source |
@@ -66,6 +67,7 @@
| map.cpp:79:9:79:13 | first | map.cpp:66:37:66:42 | call to source |
| map.cpp:80:9:80:14 | second | map.cpp:66:37:66:42 | call to source |
| map.cpp:81:7:81:7 | l | map.cpp:66:37:66:42 | call to source |
| map.cpp:87:34:87:38 | first | map.cpp:87:17:87:22 | call to source |
| map.cpp:89:7:89:32 | call to pair | map.cpp:89:24:89:29 | call to source |
| map.cpp:90:34:90:38 | first | map.cpp:90:24:90:29 | call to source |
| map.cpp:91:34:91:39 | second | map.cpp:91:24:91:29 | call to source |
@@ -73,10 +75,23 @@
| map.cpp:110:10:110:15 | call to insert | map.cpp:110:62:110:67 | call to source |
| map.cpp:111:7:111:48 | call to iterator | map.cpp:111:34:111:39 | call to source |
| map.cpp:112:10:112:25 | call to insert_or_assign | map.cpp:112:46:112:51 | call to source |
| map.cpp:114:7:114:8 | call to map | map.cpp:108:39:108:44 | call to source |
| map.cpp:116:7:116:8 | call to map | map.cpp:110:62:110:67 | call to source |
| map.cpp:117:7:117:8 | call to map | map.cpp:111:34:111:39 | call to source |
| map.cpp:118:7:118:8 | call to map | map.cpp:112:46:112:51 | call to source |
| map.cpp:120:10:120:13 | call to find | map.cpp:108:39:108:44 | call to source |
| map.cpp:122:10:122:13 | call to find | map.cpp:110:62:110:67 | call to source |
| map.cpp:123:10:123:13 | call to find | map.cpp:111:34:111:39 | call to source |
| map.cpp:124:10:124:13 | call to find | map.cpp:112:46:112:51 | call to source |
| map.cpp:126:10:126:13 | call to find | map.cpp:108:39:108:44 | call to source |
| map.cpp:128:10:128:13 | call to find | map.cpp:110:62:110:67 | call to source |
| map.cpp:129:10:129:13 | call to find | map.cpp:111:34:111:39 | call to source |
| map.cpp:130:10:130:13 | call to find | map.cpp:112:46:112:51 | call to source |
| map.cpp:137:7:137:8 | call to map | map.cpp:108:39:108:44 | call to source |
| map.cpp:138:7:138:8 | call to map | map.cpp:108:39:108:44 | call to source |
| map.cpp:139:7:139:8 | call to map | map.cpp:108:39:108:44 | call to source |
| map.cpp:140:10:140:13 | call to find | map.cpp:108:39:108:44 | call to source |
| map.cpp:141:10:141:13 | call to find | map.cpp:108:39:108:44 | call to source |
| map.cpp:142:10:142:13 | call to find | map.cpp:108:39:108:44 | call to source |
| map.cpp:154:8:154:10 | call to pair | map.cpp:108:39:108:44 | call to source |
| map.cpp:155:12:155:16 | first | map.cpp:108:39:108:44 | call to source |
@@ -91,20 +106,54 @@
| map.cpp:185:7:185:32 | call to iterator | map.cpp:108:39:108:44 | call to source |
| map.cpp:186:10:186:20 | call to upper_bound | map.cpp:108:39:108:44 | call to source |
| map.cpp:187:7:187:32 | call to iterator | map.cpp:108:39:108:44 | call to source |
| map.cpp:193:7:193:9 | call to map | map.cpp:191:49:191:54 | call to source |
| map.cpp:196:7:196:9 | call to map | map.cpp:192:49:192:54 | call to source |
| map.cpp:199:7:199:9 | call to map | map.cpp:191:49:191:54 | call to source |
| map.cpp:200:7:200:9 | call to map | map.cpp:191:49:191:54 | call to source |
| map.cpp:201:7:201:9 | call to map | map.cpp:192:49:192:54 | call to source |
| map.cpp:202:7:202:9 | call to map | map.cpp:192:49:192:54 | call to source |
| map.cpp:210:7:210:9 | call to map | map.cpp:206:49:206:54 | call to source |
| map.cpp:213:7:213:9 | call to map | map.cpp:209:49:209:54 | call to source |
| map.cpp:216:7:216:9 | call to map | map.cpp:206:49:206:54 | call to source |
| map.cpp:218:7:218:9 | call to map | map.cpp:209:49:209:54 | call to source |
| map.cpp:219:7:219:9 | call to map | map.cpp:209:49:209:54 | call to source |
| map.cpp:225:7:225:9 | call to map | map.cpp:223:49:223:54 | call to source |
| map.cpp:225:7:225:9 | call to map | map.cpp:224:49:224:54 | call to source |
| map.cpp:226:11:226:15 | call to erase | map.cpp:223:49:223:54 | call to source |
| map.cpp:226:11:226:15 | call to erase | map.cpp:224:49:224:54 | call to source |
| map.cpp:227:7:227:9 | call to map | map.cpp:223:49:223:54 | call to source |
| map.cpp:227:7:227:9 | call to map | map.cpp:224:49:224:54 | call to source |
| map.cpp:229:7:229:9 | call to map | map.cpp:223:49:223:54 | call to source |
| map.cpp:229:7:229:9 | call to map | map.cpp:224:49:224:54 | call to source |
| map.cpp:235:7:235:40 | call to iterator | map.cpp:235:26:235:31 | call to source |
| map.cpp:236:7:236:9 | call to map | map.cpp:235:26:235:31 | call to source |
| map.cpp:239:11:239:22 | call to emplace_hint | map.cpp:239:44:239:49 | call to source |
| map.cpp:240:7:240:9 | call to map | map.cpp:239:44:239:49 | call to source |
| map.cpp:246:7:246:44 | call to iterator | map.cpp:246:30:246:35 | call to source |
| map.cpp:247:7:247:9 | call to map | map.cpp:246:30:246:35 | call to source |
| map.cpp:250:11:250:21 | call to try_emplace | map.cpp:250:43:250:48 | call to source |
| map.cpp:251:7:251:9 | call to map | map.cpp:250:43:250:48 | call to source |
| map.cpp:260:7:260:54 | call to iterator | map.cpp:260:39:260:44 | call to source |
| map.cpp:262:10:262:15 | call to insert | map.cpp:262:62:262:67 | call to source |
| map.cpp:263:7:263:48 | call to iterator | map.cpp:263:34:263:39 | call to source |
| map.cpp:264:10:264:25 | call to insert_or_assign | map.cpp:264:46:264:51 | call to source |
| map.cpp:266:7:266:8 | call to unordered_map | map.cpp:260:39:260:44 | call to source |
| map.cpp:268:7:268:8 | call to unordered_map | map.cpp:262:62:262:67 | call to source |
| map.cpp:269:7:269:8 | call to unordered_map | map.cpp:263:34:263:39 | call to source |
| map.cpp:270:7:270:8 | call to unordered_map | map.cpp:264:46:264:51 | call to source |
| map.cpp:272:10:272:13 | call to find | map.cpp:260:39:260:44 | call to source |
| map.cpp:274:10:274:13 | call to find | map.cpp:262:62:262:67 | call to source |
| map.cpp:275:10:275:13 | call to find | map.cpp:263:34:263:39 | call to source |
| map.cpp:276:10:276:13 | call to find | map.cpp:264:46:264:51 | call to source |
| map.cpp:278:10:278:13 | call to find | map.cpp:260:39:260:44 | call to source |
| map.cpp:280:10:280:13 | call to find | map.cpp:262:62:262:67 | call to source |
| map.cpp:281:10:281:13 | call to find | map.cpp:263:34:263:39 | call to source |
| map.cpp:282:10:282:13 | call to find | map.cpp:264:46:264:51 | call to source |
| map.cpp:289:7:289:8 | call to unordered_map | map.cpp:260:39:260:44 | call to source |
| map.cpp:290:7:290:8 | call to unordered_map | map.cpp:260:39:260:44 | call to source |
| map.cpp:291:7:291:8 | call to unordered_map | map.cpp:260:39:260:44 | call to source |
| map.cpp:292:10:292:13 | call to find | map.cpp:260:39:260:44 | call to source |
| map.cpp:293:10:293:13 | call to find | map.cpp:260:39:260:44 | call to source |
| map.cpp:294:10:294:13 | call to find | map.cpp:260:39:260:44 | call to source |
| map.cpp:306:8:306:10 | call to pair | map.cpp:260:39:260:44 | call to source |
| map.cpp:307:12:307:16 | first | map.cpp:260:39:260:44 | call to source |
@@ -116,16 +165,42 @@
| map.cpp:334:7:334:31 | call to iterator | map.cpp:260:39:260:44 | call to source |
| map.cpp:335:7:335:32 | call to iterator | map.cpp:260:39:260:44 | call to source |
| map.cpp:336:7:336:32 | call to iterator | map.cpp:260:39:260:44 | call to source |
| map.cpp:342:7:342:9 | call to unordered_map | map.cpp:340:49:340:54 | call to source |
| map.cpp:345:7:345:9 | call to unordered_map | map.cpp:341:49:341:54 | call to source |
| map.cpp:348:7:348:9 | call to unordered_map | map.cpp:340:49:340:54 | call to source |
| map.cpp:349:7:349:9 | call to unordered_map | map.cpp:340:49:340:54 | call to source |
| map.cpp:350:7:350:9 | call to unordered_map | map.cpp:341:49:341:54 | call to source |
| map.cpp:351:7:351:9 | call to unordered_map | map.cpp:341:49:341:54 | call to source |
| map.cpp:359:7:359:9 | call to unordered_map | map.cpp:355:49:355:54 | call to source |
| map.cpp:362:7:362:9 | call to unordered_map | map.cpp:358:49:358:54 | call to source |
| map.cpp:365:7:365:9 | call to unordered_map | map.cpp:355:49:355:54 | call to source |
| map.cpp:367:7:367:9 | call to unordered_map | map.cpp:358:49:358:54 | call to source |
| map.cpp:368:7:368:9 | call to unordered_map | map.cpp:358:49:358:54 | call to source |
| map.cpp:374:7:374:9 | call to unordered_map | map.cpp:372:49:372:54 | call to source |
| map.cpp:374:7:374:9 | call to unordered_map | map.cpp:373:49:373:54 | call to source |
| map.cpp:375:11:375:15 | call to erase | map.cpp:372:49:372:54 | call to source |
| map.cpp:375:11:375:15 | call to erase | map.cpp:373:49:373:54 | call to source |
| map.cpp:376:7:376:9 | call to unordered_map | map.cpp:372:49:372:54 | call to source |
| map.cpp:376:7:376:9 | call to unordered_map | map.cpp:373:49:373:54 | call to source |
| map.cpp:378:7:378:9 | call to unordered_map | map.cpp:372:49:372:54 | call to source |
| map.cpp:378:7:378:9 | call to unordered_map | map.cpp:373:49:373:54 | call to source |
| map.cpp:384:7:384:40 | call to iterator | map.cpp:384:26:384:31 | call to source |
| map.cpp:385:7:385:9 | call to unordered_map | map.cpp:384:26:384:31 | call to source |
| map.cpp:388:11:388:22 | call to emplace_hint | map.cpp:388:44:388:49 | call to source |
| map.cpp:389:7:389:9 | call to unordered_map | map.cpp:388:44:388:49 | call to source |
| map.cpp:396:7:396:44 | call to iterator | map.cpp:396:30:396:35 | call to source |
| map.cpp:397:40:397:45 | second | map.cpp:396:30:396:35 | call to source |
| map.cpp:397:40:397:45 | second | map.cpp:397:30:397:35 | call to source |
| map.cpp:398:7:398:9 | call to unordered_map | map.cpp:396:30:396:35 | call to source |
| map.cpp:398:7:398:9 | call to unordered_map | map.cpp:397:30:397:35 | call to source |
| map.cpp:401:11:401:21 | call to try_emplace | map.cpp:401:43:401:48 | call to source |
| map.cpp:402:7:402:9 | call to unordered_map | map.cpp:401:43:401:48 | call to source |
| map.cpp:416:7:416:41 | call to pair | map.cpp:416:30:416:35 | call to source |
| map.cpp:417:7:417:9 | call to unordered_map | map.cpp:416:30:416:35 | call to source |
| map.cpp:419:7:419:41 | call to pair | map.cpp:419:33:419:38 | call to source |
| map.cpp:420:7:420:9 | call to unordered_map | map.cpp:419:33:419:38 | call to source |
| map.cpp:431:7:431:67 | call to iterator | map.cpp:431:52:431:57 | call to source |
| map.cpp:432:7:432:9 | call to unordered_map | map.cpp:431:52:431:57 | call to source |
| map.cpp:433:11:433:22 | call to emplace_hint | map.cpp:431:52:431:57 | call to source |
| movableclass.cpp:44:8:44:9 | s1 | movableclass.cpp:39:21:39:26 | call to source |
| movableclass.cpp:45:8:45:9 | s2 | movableclass.cpp:40:23:40:28 | call to source |
@@ -136,9 +211,18 @@
| movableclass.cpp:65:11:65:21 | (reference dereference) | movableclass.cpp:65:13:65:18 | call to source |
| set.cpp:20:7:20:31 | call to iterator | set.cpp:20:17:20:22 | call to source |
| set.cpp:22:10:22:15 | call to insert | set.cpp:22:29:22:34 | call to source |
| set.cpp:26:7:26:8 | call to set | set.cpp:20:17:20:22 | call to source |
| set.cpp:28:7:28:8 | call to set | set.cpp:22:29:22:34 | call to source |
| set.cpp:30:7:30:8 | call to set | set.cpp:20:17:20:22 | call to source |
| set.cpp:32:10:32:13 | call to find | set.cpp:20:17:20:22 | call to source |
| set.cpp:34:10:34:13 | call to find | set.cpp:22:29:22:34 | call to source |
| set.cpp:36:10:36:13 | call to find | set.cpp:20:17:20:22 | call to source |
| set.cpp:44:7:44:8 | call to set | set.cpp:20:17:20:22 | call to source |
| set.cpp:45:7:45:8 | call to set | set.cpp:20:17:20:22 | call to source |
| set.cpp:46:7:46:8 | call to set | set.cpp:20:17:20:22 | call to source |
| set.cpp:47:7:47:9 | call to set | set.cpp:20:17:20:22 | call to source |
| set.cpp:48:10:48:13 | call to find | set.cpp:20:17:20:22 | call to source |
| set.cpp:49:10:49:13 | call to find | set.cpp:20:17:20:22 | call to source |
| set.cpp:50:10:50:13 | call to find | set.cpp:20:17:20:22 | call to source |
| set.cpp:51:11:51:14 | call to find | set.cpp:20:17:20:22 | call to source |
| set.cpp:61:8:61:8 | call to operator* | set.cpp:20:17:20:22 | call to source |
@@ -147,25 +231,72 @@
| set.cpp:70:11:70:21 | call to upper_bound | set.cpp:67:13:67:18 | call to source |
| set.cpp:71:7:71:32 | call to iterator | set.cpp:67:13:67:18 | call to source |
| set.cpp:72:7:72:33 | call to iterator | set.cpp:67:13:67:18 | call to source |
| set.cpp:78:7:78:9 | call to set | set.cpp:76:13:76:18 | call to source |
| set.cpp:81:7:81:9 | call to set | set.cpp:77:13:77:18 | call to source |
| set.cpp:84:7:84:9 | call to set | set.cpp:76:13:76:18 | call to source |
| set.cpp:85:7:85:9 | call to set | set.cpp:76:13:76:18 | call to source |
| set.cpp:86:7:86:9 | call to set | set.cpp:77:13:77:18 | call to source |
| set.cpp:87:7:87:9 | call to set | set.cpp:77:13:77:18 | call to source |
| set.cpp:95:7:95:9 | call to set | set.cpp:91:13:91:18 | call to source |
| set.cpp:98:7:98:9 | call to set | set.cpp:94:13:94:18 | call to source |
| set.cpp:101:7:101:9 | call to set | set.cpp:91:13:91:18 | call to source |
| set.cpp:103:7:103:9 | call to set | set.cpp:94:13:94:18 | call to source |
| set.cpp:104:7:104:9 | call to set | set.cpp:94:13:94:18 | call to source |
| set.cpp:110:7:110:9 | call to set | set.cpp:108:13:108:18 | call to source |
| set.cpp:110:7:110:9 | call to set | set.cpp:109:13:109:18 | call to source |
| set.cpp:111:11:111:15 | call to erase | set.cpp:108:13:108:18 | call to source |
| set.cpp:111:11:111:15 | call to erase | set.cpp:109:13:109:18 | call to source |
| set.cpp:112:7:112:9 | call to set | set.cpp:108:13:108:18 | call to source |
| set.cpp:112:7:112:9 | call to set | set.cpp:109:13:109:18 | call to source |
| set.cpp:114:7:114:9 | call to set | set.cpp:108:13:108:18 | call to source |
| set.cpp:114:7:114:9 | call to set | set.cpp:109:13:109:18 | call to source |
| set.cpp:120:7:120:33 | call to iterator | set.cpp:120:19:120:24 | call to source |
| set.cpp:121:7:121:9 | call to set | set.cpp:120:19:120:24 | call to source |
| set.cpp:124:11:124:22 | call to emplace_hint | set.cpp:124:37:124:42 | call to source |
| set.cpp:125:7:125:9 | call to set | set.cpp:124:37:124:42 | call to source |
| set.cpp:134:7:134:31 | call to iterator | set.cpp:134:17:134:22 | call to source |
| set.cpp:136:10:136:15 | call to insert | set.cpp:136:29:136:34 | call to source |
| set.cpp:140:7:140:8 | call to unordered_set | set.cpp:134:17:134:22 | call to source |
| set.cpp:142:7:142:8 | call to unordered_set | set.cpp:136:29:136:34 | call to source |
| set.cpp:144:7:144:8 | call to unordered_set | set.cpp:134:17:134:22 | call to source |
| set.cpp:146:10:146:13 | call to find | set.cpp:134:17:134:22 | call to source |
| set.cpp:148:10:148:13 | call to find | set.cpp:136:29:136:34 | call to source |
| set.cpp:150:10:150:13 | call to find | set.cpp:134:17:134:22 | call to source |
| set.cpp:158:7:158:8 | call to unordered_set | set.cpp:134:17:134:22 | call to source |
| set.cpp:159:7:159:8 | call to unordered_set | set.cpp:134:17:134:22 | call to source |
| set.cpp:160:7:160:8 | call to unordered_set | set.cpp:134:17:134:22 | call to source |
| set.cpp:161:7:161:9 | call to unordered_set | set.cpp:134:17:134:22 | call to source |
| set.cpp:162:10:162:13 | call to find | set.cpp:134:17:134:22 | call to source |
| set.cpp:163:10:163:13 | call to find | set.cpp:134:17:134:22 | call to source |
| set.cpp:164:10:164:13 | call to find | set.cpp:134:17:134:22 | call to source |
| set.cpp:165:11:165:14 | call to find | set.cpp:134:17:134:22 | call to source |
| set.cpp:175:8:175:8 | call to operator* | set.cpp:134:17:134:22 | call to source |
| set.cpp:175:8:175:11 | (reference dereference) | set.cpp:134:17:134:22 | call to source |
| set.cpp:183:7:183:32 | call to iterator | set.cpp:181:13:181:18 | call to source |
| set.cpp:184:7:184:33 | call to iterator | set.cpp:181:13:181:18 | call to source |
| set.cpp:190:7:190:9 | call to unordered_set | set.cpp:188:13:188:18 | call to source |
| set.cpp:193:7:193:9 | call to unordered_set | set.cpp:189:13:189:18 | call to source |
| set.cpp:196:7:196:9 | call to unordered_set | set.cpp:188:13:188:18 | call to source |
| set.cpp:197:7:197:9 | call to unordered_set | set.cpp:188:13:188:18 | call to source |
| set.cpp:198:7:198:9 | call to unordered_set | set.cpp:189:13:189:18 | call to source |
| set.cpp:199:7:199:9 | call to unordered_set | set.cpp:189:13:189:18 | call to source |
| set.cpp:207:7:207:9 | call to unordered_set | set.cpp:203:13:203:18 | call to source |
| set.cpp:210:7:210:9 | call to unordered_set | set.cpp:206:13:206:18 | call to source |
| set.cpp:213:7:213:9 | call to unordered_set | set.cpp:203:13:203:18 | call to source |
| set.cpp:215:7:215:9 | call to unordered_set | set.cpp:206:13:206:18 | call to source |
| set.cpp:216:7:216:9 | call to unordered_set | set.cpp:206:13:206:18 | call to source |
| set.cpp:222:7:222:9 | call to unordered_set | set.cpp:220:13:220:18 | call to source |
| set.cpp:222:7:222:9 | call to unordered_set | set.cpp:221:13:221:18 | call to source |
| set.cpp:223:11:223:15 | call to erase | set.cpp:220:13:220:18 | call to source |
| set.cpp:223:11:223:15 | call to erase | set.cpp:221:13:221:18 | call to source |
| set.cpp:224:7:224:9 | call to unordered_set | set.cpp:220:13:220:18 | call to source |
| set.cpp:224:7:224:9 | call to unordered_set | set.cpp:221:13:221:18 | call to source |
| set.cpp:226:7:226:9 | call to unordered_set | set.cpp:220:13:220:18 | call to source |
| set.cpp:226:7:226:9 | call to unordered_set | set.cpp:221:13:221:18 | call to source |
| set.cpp:232:7:232:33 | call to iterator | set.cpp:232:19:232:24 | call to source |
| set.cpp:233:7:233:9 | call to unordered_set | set.cpp:232:19:232:24 | call to source |
| set.cpp:236:11:236:22 | call to emplace_hint | set.cpp:236:37:236:42 | call to source |
| set.cpp:237:7:237:9 | call to unordered_set | set.cpp:236:37:236:42 | call to source |
| smart_pointer.cpp:13:10:13:10 | Argument 0 indirection | smart_pointer.cpp:11:52:11:57 | call to source |
| smart_pointer.cpp:25:10:25:10 | Argument 0 indirection | 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 |
@@ -189,9 +320,13 @@
| string.cpp:130:8:130:8 | c | string.cpp:120:16:120:21 | call to source |
| string.cpp:135:8:135:8 | (reference dereference) | string.cpp:133:28:133:33 | call to source |
| string.cpp:135:8:135:8 | c | string.cpp:133:28:133:33 | call to source |
| string.cpp:145:8:145:14 | Argument 0 indirection | string.cpp:142:18:142:23 | call to source |
| string.cpp:145:11:145:11 | call to operator+ | string.cpp:142:18:142:23 | call to source |
| string.cpp:146:8:146:14 | Argument 0 indirection | string.cpp:142:18:142:23 | call to source |
| string.cpp:146:11:146:11 | call to operator+ | string.cpp:142:18:142:23 | call to source |
| string.cpp:147:8:147:14 | Argument 0 indirection | string.cpp:142:18:142:23 | call to source |
| string.cpp:147:11:147:11 | call to operator+ | string.cpp:142:18:142:23 | call to source |
| string.cpp:150:8:150:20 | Argument 0 indirection | string.cpp:150:13:150:18 | call to source |
| string.cpp:150:11:150:11 | call to operator+ | string.cpp:150:13:150:18 | call to source |
| string.cpp:159:8:159:9 | Argument 0 indirection | string.cpp:155:18:155:23 | call to source |
| string.cpp:163:8:163:9 | Argument 0 indirection | string.cpp:155:18:155:23 | call to source |
@@ -220,18 +355,25 @@
| string.cpp:295:7:295:8 | Argument 0 indirection | string.cpp:291:17:291:22 | call to source |
| string.cpp:301:7:301:8 | Argument 0 indirection | string.cpp:289:17:289:22 | call to source |
| string.cpp:303:7:303:8 | Argument 0 indirection | string.cpp:291:17:291:22 | call to source |
| string.cpp:323:7:323:29 | Argument 0 indirection | string.cpp:320:16:320:21 | call to source |
| string.cpp:323:9:323:14 | call to substr | string.cpp:320:16:320:21 | call to source |
| string.cpp:364:8:364:9 | Argument 0 indirection | string.cpp:358:18:358:23 | call to source |
| string.cpp:382:8:382:8 | call to operator* | string.cpp:374:18:374:23 | call to source |
| string.cpp:382:8:382:14 | (reference dereference) | string.cpp:374:18:374:23 | call to source |
| string.cpp:383:13:383:13 | call to operator[] | string.cpp:374:18:374:23 | call to source |
| string.cpp:383:13:383:15 | (reference dereference) | string.cpp:374:18:374:23 | call to source |
| string.cpp:396:8:396:8 | call to operator* | string.cpp:389:18:389:23 | call to source |
| string.cpp:396:8:396:15 | (reference dereference) | string.cpp:389:18:389:23 | call to source |
| string.cpp:397:8:397:8 | call to operator* | string.cpp:389:18:389:23 | call to source |
| string.cpp:397:8:397:15 | (reference dereference) | string.cpp:389:18:389:23 | call to source |
| string.cpp:404:8:404:8 | call to operator* | string.cpp:389:18:389:23 | call to source |
| string.cpp:404:8:404:11 | (reference dereference) | string.cpp:389:18:389:23 | call to source |
| string.cpp:407:8:407:8 | call to operator* | string.cpp:389:18:389:23 | call to source |
| string.cpp:407:8:407:11 | (reference dereference) | string.cpp:389:18:389:23 | call to source |
| string.cpp:415:8:415:8 | call to operator* | string.cpp:389:18:389:23 | call to source |
| string.cpp:415:8:415:11 | (reference dereference) | string.cpp:389:18:389:23 | call to source |
| string.cpp:419:8:419:10 | call to iterator | string.cpp:389:18:389:23 | call to source |
| string.cpp:422:8:422:10 | call to iterator | string.cpp:389:18:389:23 | call to source |
| string.cpp:437:7:437:8 | Argument 0 indirection | string.cpp:431:14:431:19 | call to source |
| string.cpp:450:8:450:8 | Argument 0 indirection | string.cpp:449:32:449:46 | call to source |
| string.cpp:463:8:463:8 | Argument 0 indirection | string.cpp:457:18:457:23 | call to source |
@@ -254,13 +396,16 @@
| stringstream.cpp:34:23:34:31 | (reference dereference) | stringstream.cpp:34:14:34:19 | call to source |
| stringstream.cpp:38:7:38:9 | Argument 0 indirection | stringstream.cpp:32:14:32:19 | call to source |
| stringstream.cpp:40:7:40:9 | Argument 0 indirection | stringstream.cpp:34:14:34:19 | call to source |
| stringstream.cpp:43:7:43:15 | Argument 0 indirection | stringstream.cpp:32:14:32:19 | call to source |
| stringstream.cpp:43:11:43:13 | call to str | stringstream.cpp:32:14:32:19 | call to source |
| stringstream.cpp:45:7:45:15 | Argument 0 indirection | stringstream.cpp:34:14:34:19 | call to source |
| stringstream.cpp:45:11:45:13 | call to str | stringstream.cpp:34:14:34:19 | call to source |
| stringstream.cpp:52:7:52:9 | Argument 0 indirection | stringstream.cpp:49:10:49:15 | call to source |
| stringstream.cpp:53:7:53:9 | Argument 0 indirection | stringstream.cpp:50:10:50:15 | call to source |
| stringstream.cpp:59:7:59:9 | Argument 0 indirection | stringstream.cpp:56:15:56:29 | call to source |
| stringstream.cpp:66:7:66:10 | Argument 0 indirection | stringstream.cpp:63:18:63:23 | call to source |
| stringstream.cpp:81:7:81:9 | Argument 0 indirection | stringstream.cpp:70:32:70:37 | source |
| stringstream.cpp:83:7:83:15 | Argument 0 indirection | 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:85:7:85:8 | v2 | stringstream.cpp:70:32:70:37 | source |
| stringstream.cpp:103:7:103:9 | Argument 0 indirection | stringstream.cpp:91:19:91:24 | call to source |
@@ -274,10 +419,15 @@
| stringstream.cpp:143:11:143:22 | (reference dereference) | stringstream.cpp:143:14:143:19 | call to source |
| stringstream.cpp:149:7:149:8 | Argument 0 indirection | stringstream.cpp:143:14:143:19 | call to source |
| stringstream.cpp:150:7:150:8 | Argument 0 indirection | stringstream.cpp:143:14:143:19 | call to source |
| stringstream.cpp:157:7:157:8 | Argument 0 indirection | stringstream.cpp:143:14:143:19 | call to source |
| stringstream.cpp:157:7:157:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source |
| stringstream.cpp:158:7:158:8 | Argument 0 indirection | stringstream.cpp:143:14:143:19 | call to source |
| stringstream.cpp:158:7:158:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source |
| stringstream.cpp:168:7:168:8 | Argument 0 indirection | stringstream.cpp:143:14:143:19 | call to source |
| stringstream.cpp:168:7:168:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source |
| stringstream.cpp:170:7:170:8 | Argument 0 indirection | stringstream.cpp:143:14:143:19 | call to source |
| stringstream.cpp:170:7:170:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source |
| stringstream.cpp:172:7:172:9 | Argument 0 indirection | stringstream.cpp:143:14:143:19 | call to source |
| stringstream.cpp:172:7:172:9 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source |
| stringstream.cpp:175:7:175:20 | ... = ... | stringstream.cpp:143:14:143:19 | call to source |
| stringstream.cpp:177:7:177:21 | ... = ... | stringstream.cpp:143:14:143:19 | call to source |
@@ -285,16 +435,22 @@
| stringstream.cpp:183:7:183:8 | c4 | stringstream.cpp:143:14:143:19 | call to source |
| stringstream.cpp:185:7:185:8 | c6 | stringstream.cpp:143:14:143:19 | call to source |
| stringstream.cpp:197:10:197:12 | call to get | stringstream.cpp:196:18:196:32 | call to source |
| stringstream.cpp:219:7:219:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source |
| stringstream.cpp:219:7:219:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source |
| stringstream.cpp:220:7:220:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source |
| stringstream.cpp:220:7:220:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source |
| stringstream.cpp:227:7:227:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source |
| stringstream.cpp:227:7:227:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source |
| stringstream.cpp:228:7:228:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source |
| stringstream.cpp:228:7:228:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source |
| stringstream.cpp:231:7:231:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source |
| stringstream.cpp:231:7:231:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source |
| stringstream.cpp:239:7:239:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source |
| stringstream.cpp:240:7:240:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source |
| stringstream.cpp:247:7:247:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source |
| stringstream.cpp:248:7:248:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source |
| stringstream.cpp:251:7:251:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source |
| stringstream.cpp:263:7:263:8 | Argument 0 indirection | stringstream.cpp:257:24:257:29 | call to source |
| stringstream.cpp:263:7:263:8 | call to basic_string | stringstream.cpp:257:24:257:29 | 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 |
@@ -307,6 +463,7 @@
| swap1.cpp:78:12:78:16 | data1 | swap1.cpp:71:15:71:20 | call to source |
| swap1.cpp:79:12:79:16 | data1 | swap1.cpp:71:15:71:20 | call to source |
| swap1.cpp:83:13:83:17 | data1 | swap1.cpp:82:16:82:21 | call to source |
| swap1.cpp:87:13:87:17 | data1 | swap1.cpp:82:16:82:21 | call to source |
| swap1.cpp:88:13:88:17 | data1 | swap1.cpp:82:16:82:21 | call to source |
| swap1.cpp:97:12:97:16 | data1 | swap1.cpp:95:15:95:20 | call to source |
| swap1.cpp:102:12:102:16 | data1 | swap1.cpp:95:15:95:20 | call to source |
@@ -323,6 +480,7 @@
| swap2.cpp:78:12:78:16 | data1 | swap2.cpp:71:15:71:20 | call to source |
| swap2.cpp:79:12:79:16 | data1 | swap2.cpp:71:15:71:20 | call to source |
| swap2.cpp:83:13:83:17 | data1 | swap2.cpp:82:16:82:21 | call to source |
| swap2.cpp:87:13:87:17 | data1 | swap2.cpp:82:16:82:21 | call to source |
| swap2.cpp:88:13:88:17 | data1 | swap2.cpp:82:16:82:21 | call to source |
| swap2.cpp:97:12:97:16 | data1 | swap2.cpp:95:15:95:20 | call to source |
| swap2.cpp:102:12:102:16 | data1 | swap2.cpp:95:15:95:20 | call to source |
@@ -408,6 +566,7 @@
| vector.cpp:258:8:258:9 | Argument 0 indirection | vector.cpp:239:15:239:20 | call to source |
| vector.cpp:259:8:259:9 | Argument 0 indirection | vector.cpp:239:15:239:20 | call to source |
| vector.cpp:260:8:260:9 | Argument 0 indirection | vector.cpp:239:15:239:20 | call to source |
| vector.cpp:261:8:261:9 | Argument 0 indirection | vector.cpp:239:15:239:20 | call to source |
| vector.cpp:273:8:273:9 | Argument 0 indirection | vector.cpp:269:18:269:31 | call to source |
| vector.cpp:274:8:274:9 | Argument 0 indirection | vector.cpp:270:18:270:35 | call to source |
| vector.cpp:275:8:275:9 | Argument 0 indirection | vector.cpp:271:18:271:34 | call to source |

View File

@@ -0,0 +1,35 @@
template<class T>
struct remove_const { typedef T type; };
template<class T>
struct remove_const<const T> { typedef T type; };
// `remove_const_t<T>` removes any `const` specifier from `T`
template<class T>
using remove_const_t = typename remove_const<T>::type;
template<class T>
struct remove_reference { typedef T type; };
template<class T>
struct remove_reference<T &> { typedef T type; };
template<class T>
struct remove_reference<T &&> { typedef T type; };
// `remove_reference_t<T>` removes any `&` from `T`
template<class T>
using remove_reference_t = typename remove_reference<T>::type;
template<class T>
struct decay_impl {
typedef T type;
};
template<class T, size_t t_size>
struct decay_impl<T[t_size]> {
typedef T* type;
};
template<class T>
using decay_t = typename decay_impl<remove_reference_t<T>>::type;

View File

@@ -312,7 +312,7 @@ void test_vector_insert() {
sink(d); // tainted
}
void test_constructors_more() {
void test_vector_constructors_more() {
std::vector<int> v1;
std::vector<int> v2;
v2.push_back(source());
@@ -486,3 +486,13 @@ void test_vector_memcpy()
sink(cs); // tainted [NOT DETECTED by IR]
}
}
void test_vector_emplace() {
std::vector<int> v1(10), v2(10);
v1.emplace_back(source());
sink(v1); // tainted
v2.emplace(v2.begin(), source());
sink(v2); // tainted
}

View File

@@ -13,3 +13,4 @@
| test.cpp:42:11:42:11 | x |
| test.cpp:57:9:57:9 | 4 |
| test.cpp:63:9:63:19 | call to getAVirtual |
| test.cpp:63:9:63:21 | temporary object |

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,4 @@
missingOperand
| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
unexpectedOperand
duplicateOperand
missingPhiOperand
@@ -25,6 +21,8 @@ notMarkedAsConflated
wronglyMarkedAsConflated
invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -1,8 +1,4 @@
missingOperand
| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
unexpectedOperand
duplicateOperand
missingPhiOperand
@@ -25,6 +21,8 @@ notMarkedAsConflated
wronglyMarkedAsConflated
invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -997,7 +997,7 @@ int PointerDecay(int a[], int fn(float)) {
return a[0] + fn(1.0);
}
int ExprStmt(int b, int y, int z) {
int StmtExpr(int b, int y, int z) {
int x = ({
int w;
if (b) {
@@ -1322,4 +1322,129 @@ void f(int* p)
new (p) int;
}
template<typename T>
T defaultConstruct() {
return T();
}
class constructor_only {
public:
int x;
public:
constructor_only(int x);
};
class copy_constructor {
public:
int y;
public:
copy_constructor();
copy_constructor(const copy_constructor&);
void method();
};
class destructor_only {
public:
~destructor_only();
void method();
};
template<typename T>
void acceptRef(const T& v);
template<typename T>
void acceptValue(T v);
template<typename T>
T returnValue();
void temporary_string() {
String s = returnValue<String>(); // No temporary
const String& rs = returnValue<String>(); // Binding a reference variable to a temporary
acceptRef(s); // No temporary
acceptRef<String>("foo"); // Binding a const reference to a temporary
acceptValue(s);
acceptValue<String>("foo");
String().c_str();
returnValue<String>().c_str(); // Member access on a temporary
defaultConstruct<String>();
}
void temporary_destructor_only() {
destructor_only d = returnValue<destructor_only>();
const destructor_only& rd = returnValue<destructor_only>();
destructor_only d2;
acceptRef(d);
acceptValue(d);
destructor_only().method();
returnValue<destructor_only>().method();
defaultConstruct<destructor_only>();
}
void temporary_copy_constructor() {
copy_constructor d = returnValue<copy_constructor>();
const copy_constructor& rd = returnValue<copy_constructor>();
copy_constructor d2;
acceptRef(d);
acceptValue(d);
copy_constructor().method();
returnValue<copy_constructor>().method();
defaultConstruct<copy_constructor>();
int y = returnValue<copy_constructor>().y;
}
void temporary_point() {
Point p = returnValue<Point>(); // No temporary
const Point& rp = returnValue<Point>(); // Binding a reference variable to a temporary
acceptRef(p); // No temporary
acceptValue(p);
Point().x;
int y = returnValue<Point>().y;
defaultConstruct<Point>();
}
struct UnusualFields {
int& r;
float a[10];
};
void temporary_unusual_fields() {
const int& rx = returnValue<UnusualFields>().r;
int x = returnValue<UnusualFields>().r;
const float& rf = returnValue<UnusualFields>().a[3];
float f = returnValue<UnusualFields>().a[5];
}
struct POD_Base {
int x;
float f() const;
};
struct POD_Middle : POD_Base {
int y;
};
struct POD_Derived : POD_Middle {
int z;
};
void temporary_hierarchy() {
POD_Base b = returnValue<POD_Middle>();
b = (returnValue<POD_Derived>()); // Multiple conversions plus parens
int x = returnValue<POD_Derived>().x;
float f = (returnValue<POD_Derived>()).f();
}
// semmle-extractor-options: -std=c++17 --clang

View File

@@ -1,8 +1,4 @@
missingOperand
| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
unexpectedOperand
duplicateOperand
missingPhiOperand
@@ -25,6 +21,8 @@ notMarkedAsConflated
wronglyMarkedAsConflated
invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,4 @@
missingOperand
| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
unexpectedOperand
duplicateOperand
missingPhiOperand
@@ -25,6 +21,8 @@ notMarkedAsConflated
wronglyMarkedAsConflated
invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -1,8 +1,4 @@
missingOperand
| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() |
unexpectedOperand
duplicateOperand
missingPhiOperand
@@ -25,6 +21,8 @@ notMarkedAsConflated
wronglyMarkedAsConflated
invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -38,27 +38,27 @@ void Locals() {
void PointsTo(
int a, //$raw,ussa=a
Point& b, //$raw,ussa=b $ussa=*b
Point* c, //$raw,ussa=c $ussa=*c
int* d, //$raw,ussa=d $ussa=*d
DerivedSI* e, //$raw,ussa=e $ussa=*e
DerivedMI* f, //$raw,ussa=f $ussa=*f
DerivedVI* g //$raw,ussa=g $ussa=*g
Point& b, //$raw,ussa=b ussa=*b
Point* c, //$raw,ussa=c ussa=*c
int* d, //$raw,ussa=d ussa=*d
DerivedSI* e, //$raw,ussa=e ussa=*e
DerivedMI* f, //$raw,ussa=f ussa=*f
DerivedVI* g //$raw,ussa=g ussa=*g
) {
int i = a; //$raw,ussa=a
i = *&a; //$raw,ussa=a
i = *(&a + 0); //$raw,ussa=a
i = b.x; //$raw,ussa=b $ussa=*b[0..4)<int>
i = b.y; //$raw,ussa=b $ussa=*b[4..8)<int>
i = c->x; //$raw,ussa=c $ussa=*c[0..4)<int>
i = c->y; //$raw,ussa=c $ussa=*c[4..8)<int>
i = *d; //$raw,ussa=d $ussa=*d[0..4)<int>
i = *(d + 0); //$raw,ussa=d $ussa=*d[0..4)<int>
i = d[5]; //$raw,ussa=d $ussa=*d[20..24)<int>
i = 5[d]; //$raw,ussa=d $ussa=*d[20..24)<int>
i = d[a]; //$raw,ussa=d $raw,ussa=a $ussa=*d[?..?)<int>
i = a[d]; //$raw,ussa=d $raw,ussa=a $ussa=*d[?..?)<int>
i = b.x; //$raw,ussa=b ussa=*b[0..4)<int>
i = b.y; //$raw,ussa=b ussa=*b[4..8)<int>
i = c->x; //$raw,ussa=c ussa=*c[0..4)<int>
i = c->y; //$raw,ussa=c ussa=*c[4..8)<int>
i = *d; //$raw,ussa=d ussa=*d[0..4)<int>
i = *(d + 0); //$raw,ussa=d ussa=*d[0..4)<int>
i = d[5]; //$raw,ussa=d ussa=*d[20..24)<int>
i = 5[d]; //$raw,ussa=d ussa=*d[20..24)<int>
i = d[a]; //$raw,ussa=d raw,ussa=a ussa=*d[?..?)<int>
i = a[d]; //$raw,ussa=d raw,ussa=a ussa=*d[?..?)<int>
int* p = &b.x; //$raw,ussa=b
i = *p; //$ussa=*b[0..4)<int>
@@ -70,18 +70,18 @@ void PointsTo(
i = *p; //$ussa=*c[4..8)<int>
p = &d[5]; //$raw,ussa=d
i = *p; //$ussa=*d[20..24)<int>
p = &d[a]; //$raw,ussa=d $raw,ussa=a
p = &d[a]; //$raw,ussa=d raw,ussa=a
i = *p; //$ussa=*d[?..?)<int>
Point* q = &c[a]; //$raw,ussa=c $raw,ussa=a
Point* q = &c[a]; //$raw,ussa=c raw,ussa=a
i = q->x; //$ussa=*c[?..?)<int>
i = q->y; //$ussa=*c[?..?)<int>
i = e->b1; //$raw,ussa=e $ussa=*e[0..4)<int>
i = e->dsi; //$raw,ussa=e $ussa=*e[4..8)<int>
i = f->b1; //$raw,ussa=f $ussa=*f[0..4)<int>
i = f->b2; //$raw,ussa=f $ussa=*f[4..8)<int>
i = f->dmi; //$raw,ussa=f $ussa=*f[8..12)<int>
i = g->b1; //$raw,ussa=g $ussa=*g[?..?)<int>
i = g->dvi; //$raw,ussa=g $ussa=*g[8..12)<int>
i = e->b1; //$raw,ussa=e ussa=*e[0..4)<int>
i = e->dsi; //$raw,ussa=e ussa=*e[4..8)<int>
i = f->b1; //$raw,ussa=f ussa=*f[0..4)<int>
i = f->b2; //$raw,ussa=f ussa=*f[4..8)<int>
i = f->dmi; //$raw,ussa=f ussa=*f[8..12)<int>
i = g->b1; //$raw,ussa=g ussa=*g[?..?)<int>
i = g->dvi; //$raw,ussa=g ussa=*g[8..12)<int>
}

View File

@@ -21,6 +21,8 @@ notMarkedAsConflated
wronglyMarkedAsConflated
invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -21,6 +21,8 @@ notMarkedAsConflated
wronglyMarkedAsConflated
invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

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