mirror of
https://github.com/github/codeql.git
synced 2026-05-02 12:15:17 +02:00
Merge branch 'main' into interleave-op-instr-field-flow
This commit is contained in:
@@ -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.
|
||||
@@ -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`.
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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`.
|
||||
*/
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 *)... |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
int source();
|
||||
void sink(...) {};
|
||||
void sink(...);
|
||||
|
||||
class MyCopyableClass {
|
||||
public:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -30,7 +30,7 @@ int sscanf(const char *s, const char *format, ...);
|
||||
// ----------
|
||||
|
||||
int source();
|
||||
void sink(...) {};
|
||||
void sink(...);
|
||||
|
||||
namespace string
|
||||
{
|
||||
|
||||
@@ -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 | |
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
#include "stl.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
char *source();
|
||||
|
||||
}
|
||||
namespace ns_char
|
||||
{
|
||||
char source();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
int source();
|
||||
void sink(...) {};
|
||||
void sink(...);
|
||||
|
||||
class StructLikeClass {
|
||||
public:
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
int source();
|
||||
void sink(...) {};
|
||||
void sink(...);
|
||||
|
||||
void arithAssignments(int source1, int clean1) {
|
||||
sink(clean1); // clean
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
35
cpp/ql/test/library-tests/dataflow/taint-tests/type_traits.h
Normal file
35
cpp/ql/test/library-tests/dataflow/taint-tests/type_traits.h
Normal 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;
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
@@ -21,6 +21,8 @@ notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
invalidOverlap
|
||||
nonUniqueEnclosingIRFunction
|
||||
fieldAddressOnNonPointer
|
||||
thisArgumentIsNonPointer
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user