mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge remote-tracking branch 'upstream/master' into loginjection
This commit is contained in:
4
.github/codeql/codeql-config.yml
vendored
Normal file
4
.github/codeql/codeql-config.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
name: "CodeQL config"
|
||||
|
||||
queries:
|
||||
- uses: security-and-quality
|
||||
52
.github/workflows/codeql-analysis.yml
vendored
Normal file
52
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
name: "Code scanning - action"
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 9 * * 1'
|
||||
|
||||
jobs:
|
||||
CodeQL-Build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
with:
|
||||
languages: csharp
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
@@ -11,6 +11,7 @@
|
||||
- [jGrowl](https://github.com/stanlemon/jGrowl)
|
||||
- [jQuery](https://jquery.com/)
|
||||
- [marsdb](https://www.npmjs.com/package/marsdb)
|
||||
- [micro](https://www.npmjs.com/package/micro/)
|
||||
- [minimongo](https://www.npmjs.com/package/minimongo/)
|
||||
- [mssql](https://www.npmjs.com/package/mssql)
|
||||
- [mysql](https://www.npmjs.com/package/mysql)
|
||||
@@ -20,6 +21,8 @@
|
||||
- [sqlite](https://www.npmjs.com/package/sqlite)
|
||||
- [ssh2-streams](https://www.npmjs.com/package/ssh2-streams)
|
||||
- [ssh2](https://www.npmjs.com/package/ssh2)
|
||||
- [yargs](https://www.npmjs.com/package/yargs)
|
||||
- [webpack-dev-server](https://www.npmjs.com/package/webpack-dev-server)
|
||||
|
||||
* TypeScript 3.9 is now supported.
|
||||
|
||||
@@ -30,10 +33,17 @@
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Cross-site scripting through DOM (`js/xss-through-dom`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where existing text from the DOM is used as HTML. Results are not shown on LGTM by default. |
|
||||
| DOM text reinterpreted as HTML (`js/xss-through-dom`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where existing text from the DOM is used as HTML. Results are shown on LGTM by default. |
|
||||
| Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. |
|
||||
| Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. |
|
||||
| Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. |
|
||||
| Download of sensitive file through insecure connection (`js/insecure-download`) | security, external/cwe/cwe-829 | Highlights downloads of sensitive files through an unencrypted protocol. Results are shown on LGTM by default. |
|
||||
| Exposure of private files (`js/exposure-of-private-files`) | security, external/cwe/cwe-200 | Highlights servers that serve private files. Results are shown on LGTM by default. |
|
||||
| Creating biased random numbers from a cryptographically secure source (`js/biased-cryptographic-random`) | security, external/cwe/cwe-327 | Highlights mathematical operations on cryptographically secure numbers that can create biased results. Results are shown on LGTM by default. |
|
||||
| Storage of sensitive information in build artifact (`js/build-artifact-leak`) | security, external/cwe/cwe-312 | Highlights storage of sensitive information in build artifacts. Results are shown on LGTM by default. |
|
||||
| Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. |
|
||||
| Disabling certificate validation (`js/disabling-certificate-validation`) | security, external/cwe-295 | Highlights locations where SSL certificate validation is disabled. Results are shown on LGTM by default. |
|
||||
| Incomplete multi-character sanitization (`js/incomplete-multi-character-sanitization`) | correctness, security, external/cwe/cwe-20, external/cwe/cwe-116 | Highlights sanitizers that fail to remove dangerous substrings completely. Results are shown on LGTM by default. |
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
@@ -42,9 +52,11 @@
|
||||
| Client-side cross-site scripting (`js/xss`) | Fewer results | This query now recognizes additional safe patterns of constructing HTML. |
|
||||
| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. |
|
||||
| Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. |
|
||||
| Exception text reinterpreted as HTML (`js/exception-xss`) | Rephrased and changed visibility | Rephrased name and alert message. Severity lowered from error to warning. Results are now shown on LGTM by default. |
|
||||
| Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. |
|
||||
| Hard-coded credentials (`js/hardcoded-credentials`) | More results | This query now recognizes hard-coded credentials sent via HTTP authorization headers. |
|
||||
| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. |
|
||||
| Insecure randomness (`js/insecure-randomness`) | Fewer results | This query now recognizes when an insecure random value is used as a fallback when secure random values are unsupported. |
|
||||
| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. |
|
||||
| Non-linear pattern (`js/non-linear-pattern`) | Fewer duplicates and message changed | This query now generates fewer duplicate alerts and has a clearer explanation in case of type annotations used in a pattern. |
|
||||
| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. |
|
||||
|
||||
@@ -96,10 +96,18 @@
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/UseSoundEscapeAnalysis.qll",
|
||||
"csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll"
|
||||
],
|
||||
"IR IRFunctionBase": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll",
|
||||
"csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll"
|
||||
],
|
||||
"IR Operand Tag": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll",
|
||||
"csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll"
|
||||
],
|
||||
"IR TInstruction":[
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll",
|
||||
"csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll"
|
||||
],
|
||||
"IR TIRVariable":[
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll",
|
||||
"csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll"
|
||||
@@ -177,6 +185,11 @@
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRBlockImports.qll"
|
||||
],
|
||||
"C++ IR IRFunctionImports": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll"
|
||||
],
|
||||
"C++ IR IRVariableImports": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRVariableImports.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll",
|
||||
@@ -287,6 +300,10 @@
|
||||
"csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll",
|
||||
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll"
|
||||
],
|
||||
"C# IR IRFunctionImports": [
|
||||
"csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll",
|
||||
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll"
|
||||
],
|
||||
"C# IR IRVariableImports": [
|
||||
"csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll",
|
||||
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll"
|
||||
|
||||
@@ -23,7 +23,7 @@ import semmle.code.cpp.ir.ValueNumbering
|
||||
class NullInstruction extends ConstantValueInstruction {
|
||||
NullInstruction() {
|
||||
this.getValue() = "0" and
|
||||
this.getResultType().getUnspecifiedType() instanceof PointerType
|
||||
this.getResultIRType() instanceof IRAddressType
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) {
|
||||
bool =
|
||||
any(ConvertInstruction convert |
|
||||
checked = convert.getUnary() and
|
||||
convert.getResultType() instanceof BoolType and
|
||||
checked.getResultType() instanceof PointerType
|
||||
convert.getResultIRType() instanceof IRBooleanType and
|
||||
checked.getResultIRType() instanceof IRAddressType
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
- qlpack: codeql-cpp
|
||||
- apply: security-extended-selectors.yml
|
||||
from: codeql-suite-helpers
|
||||
- apply: codeql-suites/excluded-slow-queries.yml
|
||||
- apply: codeql-suites/exclude-slow-queries.yml
|
||||
from: codeql-cpp
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides the `Initializer` class, representing C/C++ declaration initializers.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.controlflow.ControlFlowGraph
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides classes for loop iteration variables.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Variable
|
||||
|
||||
/**
|
||||
@@ -7,14 +11,18 @@ import semmle.code.cpp.Variable
|
||||
class LoopCounter extends Variable {
|
||||
LoopCounter() { exists(ForStmt f | f.getAnIterationVariable() = this) }
|
||||
|
||||
// Gets an access of this variable within loop `f`.
|
||||
/**
|
||||
* Gets an access of this variable within loop `f`.
|
||||
*/
|
||||
VariableAccess getVariableAccessInLoop(ForStmt f) {
|
||||
this.getALoop() = f and
|
||||
result.getEnclosingStmt().getParent*() = f and
|
||||
this = result.getTarget()
|
||||
}
|
||||
|
||||
// Gets a loop which uses this variable as its counter.
|
||||
/**
|
||||
* Gets a loop which uses this variable as its counter.
|
||||
*/
|
||||
ForStmt getALoop() { result.getAnIterationVariable() = this }
|
||||
}
|
||||
|
||||
@@ -25,14 +33,18 @@ class LoopCounter extends Variable {
|
||||
class LoopControlVariable extends Variable {
|
||||
LoopControlVariable() { this = loopControlVariable(_) }
|
||||
|
||||
// Gets an access of this variable within loop `f`.
|
||||
/**
|
||||
* Gets an access of this variable within loop `f`.
|
||||
*/
|
||||
VariableAccess getVariableAccessInLoop(ForStmt f) {
|
||||
this.getALoop() = f and
|
||||
result.getEnclosingStmt().getParent*() = f and
|
||||
this = result.getTarget()
|
||||
}
|
||||
|
||||
// Gets a loop which uses this variable as its control variable.
|
||||
/**
|
||||
* Gets a loop which uses this variable as its control variable.
|
||||
*/
|
||||
ForStmt getALoop() { this = loopControlVariable(result) }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Proivdes the `LinkTarget` class representing linker invocations during the build process.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Class
|
||||
import semmle.code.cpp.File
|
||||
import semmle.code.cpp.Function
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides classes and predicates for locations in the source code.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Element
|
||||
import semmle.code.cpp.File
|
||||
|
||||
|
||||
@@ -179,6 +179,11 @@ class MacroInvocation extends MacroAccess {
|
||||
result.(Stmt).getGeneratingMacro() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a function that includes an expression that is affected by this macro
|
||||
* invocation. If the macro expansion includes the end of one function and
|
||||
* the beginning of another, this predicate will get both.
|
||||
*/
|
||||
Function getEnclosingFunction() {
|
||||
result = this.getAnAffectedElement().(Expr).getEnclosingFunction()
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Class
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -198,123 +198,130 @@ private module Cached {
|
||||
/**
|
||||
* The final flow-through calculation:
|
||||
*
|
||||
* - Input access paths are abstracted with a `ContentOption` parameter
|
||||
* that represents the head of the access path. `TContentNone()` means that
|
||||
* the access path is unrestricted.
|
||||
* - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`)
|
||||
* or summarized as a single read step with before and after types recorded
|
||||
* in the `ReadStepTypesOption` parameter.
|
||||
* - Types are checked using the `compatibleTypes()` relation.
|
||||
*/
|
||||
private module Final {
|
||||
/**
|
||||
* Holds if `p` can flow to `node` in the same callable using only
|
||||
* value-preserving steps, not taking call contexts into account.
|
||||
* value-preserving steps and possibly a single read step, not taking
|
||||
* call contexts into account.
|
||||
*
|
||||
* `contentIn` describes the content of `p` that can flow to `node`
|
||||
* (if any).
|
||||
* If a read step was taken, then `read` captures the `Content`, the
|
||||
* container type, and the content type.
|
||||
*/
|
||||
predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) {
|
||||
parameterValueFlow0(p, node, contentIn) and
|
||||
predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) {
|
||||
parameterValueFlow0(p, node, read) and
|
||||
if node instanceof CastingNode
|
||||
then
|
||||
// normal flow through
|
||||
contentIn = TContentNone() and
|
||||
read = TReadStepTypesNone() and
|
||||
compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node))
|
||||
or
|
||||
// getter
|
||||
exists(Content fIn |
|
||||
contentIn.getContent() = fIn and
|
||||
compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node))
|
||||
)
|
||||
compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node))
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) {
|
||||
private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) {
|
||||
p = node and
|
||||
Cand::cand(p, _) and
|
||||
contentIn = TContentNone()
|
||||
read = TReadStepTypesNone()
|
||||
or
|
||||
// local flow
|
||||
exists(Node mid |
|
||||
parameterValueFlow(p, mid, contentIn) and
|
||||
parameterValueFlow(p, mid, read) and
|
||||
LocalFlowBigStep::localFlowBigStep(mid, node)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
parameterValueFlow(p, mid, TContentNone()) and
|
||||
readStep(mid, f, node) and
|
||||
contentIn.getContent() = f and
|
||||
exists(Node mid |
|
||||
parameterValueFlow(p, mid, TReadStepTypesNone()) and
|
||||
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
|
||||
read.getContentType()) and
|
||||
Cand::parameterValueFlowReturnCand(p, _, true) and
|
||||
compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType())
|
||||
compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType())
|
||||
)
|
||||
or
|
||||
// flow through: no prior read
|
||||
exists(ArgumentNode arg |
|
||||
parameterValueFlowArg(p, arg, TContentNone()) and
|
||||
argumentValueFlowsThrough(arg, contentIn, node)
|
||||
parameterValueFlowArg(p, arg, TReadStepTypesNone()) and
|
||||
argumentValueFlowsThrough(arg, read, node)
|
||||
)
|
||||
or
|
||||
// flow through: no read inside method
|
||||
exists(ArgumentNode arg |
|
||||
parameterValueFlowArg(p, arg, contentIn) and
|
||||
argumentValueFlowsThrough(arg, TContentNone(), node)
|
||||
parameterValueFlowArg(p, arg, read) and
|
||||
argumentValueFlowsThrough(arg, TReadStepTypesNone(), node)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlowArg(
|
||||
ParameterNode p, ArgumentNode arg, ContentOption contentIn
|
||||
ParameterNode p, ArgumentNode arg, ReadStepTypesOption read
|
||||
) {
|
||||
parameterValueFlow(p, arg, contentIn) and
|
||||
parameterValueFlow(p, arg, read) and
|
||||
Cand::argumentValueFlowsThroughCand(arg, _, _)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate argumentValueFlowsThrough0(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read
|
||||
) {
|
||||
exists(ParameterNode param | viableParamArg(call, param, arg) |
|
||||
parameterValueFlowReturn(param, kind, contentIn)
|
||||
parameterValueFlowReturn(param, kind, read)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `arg` flows to `out` through a call using only value-preserving steps,
|
||||
* not taking call contexts into account.
|
||||
* Holds if `arg` flows to `out` through a call using only
|
||||
* value-preserving steps and possibly a single read step, not taking
|
||||
* call contexts into account.
|
||||
*
|
||||
* `contentIn` describes the content of `arg` that can flow to `out` (if any).
|
||||
* If a read step was taken, then `read` captures the `Content`, the
|
||||
* container type, and the content type.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) {
|
||||
predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) {
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
argumentValueFlowsThrough0(call, arg, kind, contentIn) and
|
||||
argumentValueFlowsThrough0(call, arg, kind, read) and
|
||||
out = getAnOutNode(call, kind)
|
||||
|
|
||||
// normal flow through
|
||||
contentIn = TContentNone() and
|
||||
read = TReadStepTypesNone() and
|
||||
compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out))
|
||||
or
|
||||
// getter
|
||||
exists(Content fIn |
|
||||
contentIn.getContent() = fIn and
|
||||
compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and
|
||||
compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out))
|
||||
)
|
||||
compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and
|
||||
compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `arg` flows to `out` through a call using only
|
||||
* value-preserving steps and a single read step, not taking call
|
||||
* contexts into account, thus representing a getter-step.
|
||||
*/
|
||||
predicate getterStep(ArgumentNode arg, Content c, Node out) {
|
||||
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p` can flow to a return node of kind `kind` in the same
|
||||
* callable using only value-preserving steps.
|
||||
* callable using only value-preserving steps and possibly a single read
|
||||
* step.
|
||||
*
|
||||
* `contentIn` describes the content of `p` that can flow to the return
|
||||
* node (if any).
|
||||
* If a read step was taken, then `read` captures the `Content`, the
|
||||
* container type, and the content type.
|
||||
*/
|
||||
private predicate parameterValueFlowReturn(
|
||||
ParameterNode p, ReturnKind kind, ContentOption contentIn
|
||||
ParameterNode p, ReturnKind kind, ReadStepTypesOption read
|
||||
) {
|
||||
exists(ReturnNode ret |
|
||||
parameterValueFlow(p, ret, contentIn) and
|
||||
parameterValueFlow(p, ret, read) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
@@ -329,7 +336,27 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) {
|
||||
parameterValueFlow(p, n.getPreUpdateNode(), TContentNone())
|
||||
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
||||
}
|
||||
|
||||
private predicate store(
|
||||
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||
) {
|
||||
storeStep(node1, c, node2) and
|
||||
readStep(_, c, _) and
|
||||
contentType = getErasedNodeTypeBound(node1) and
|
||||
containerType = getErasedNodeTypeBound(node2)
|
||||
or
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
||||
or
|
||||
readStep(n2, c, n1) and
|
||||
contentType = getErasedNodeTypeBound(n1) and
|
||||
containerType = getErasedNodeTypeBound(n2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -340,17 +367,8 @@ private module Cached {
|
||||
* been stored into, in order to handle cases like `x.f1.f2 = y`.
|
||||
*/
|
||||
cached
|
||||
predicate store(Node node1, Content f, Node node2) {
|
||||
storeStep(node1, f, node2) and readStep(_, f, _)
|
||||
or
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TContentSome(f), n1)
|
||||
or
|
||||
readStep(n2, f, n1)
|
||||
)
|
||||
predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) {
|
||||
store(node1, tc.getContent(), node2, contentType, tc.getContainerType())
|
||||
}
|
||||
|
||||
import FlowThrough
|
||||
@@ -397,10 +415,13 @@ private module Cached {
|
||||
TBooleanNone() or
|
||||
TBooleanSome(boolean b) { b = true or b = false }
|
||||
|
||||
cached
|
||||
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
|
||||
|
||||
cached
|
||||
newtype TAccessPathFront =
|
||||
TFrontNil(DataFlowType t) or
|
||||
TFrontHead(Content f)
|
||||
TFrontHead(TypedContent tc)
|
||||
|
||||
cached
|
||||
newtype TAccessPathFrontOption =
|
||||
@@ -415,25 +436,38 @@ class CastingNode extends Node {
|
||||
CastingNode() {
|
||||
this instanceof ParameterNode or
|
||||
this instanceof CastNode or
|
||||
this instanceof OutNodeExt
|
||||
this instanceof OutNodeExt or
|
||||
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
||||
// is obtained by popping the head of the access path stack) is compatible with
|
||||
// the type of `x.f`.
|
||||
readStep(_, _, this)
|
||||
}
|
||||
}
|
||||
|
||||
newtype TContentOption =
|
||||
TContentNone() or
|
||||
TContentSome(Content f)
|
||||
private predicate readStepWithTypes(
|
||||
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
|
||||
) {
|
||||
readStep(n1, c, n2) and
|
||||
container = getErasedNodeTypeBound(n1) and
|
||||
content = getErasedNodeTypeBound(n2)
|
||||
}
|
||||
|
||||
private class ContentOption extends TContentOption {
|
||||
Content getContent() { this = TContentSome(result) }
|
||||
|
||||
predicate hasContent() { exists(this.getContent()) }
|
||||
|
||||
string toString() {
|
||||
result = this.getContent().toString()
|
||||
or
|
||||
not this.hasContent() and
|
||||
result = "<none>"
|
||||
private newtype TReadStepTypesOption =
|
||||
TReadStepTypesNone() or
|
||||
TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) {
|
||||
readStepWithTypes(_, container, c, _, content)
|
||||
}
|
||||
|
||||
private class ReadStepTypesOption extends TReadStepTypesOption {
|
||||
predicate isSome() { this instanceof TReadStepTypesSome }
|
||||
|
||||
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
|
||||
|
||||
Content getContent() { this = TReadStepTypesSome(_, result, _) }
|
||||
|
||||
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
|
||||
|
||||
string toString() { if this.isSome() then result = "Some(..)" else result = "None()" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -692,6 +726,23 @@ class BooleanOption extends TBooleanOption {
|
||||
}
|
||||
}
|
||||
|
||||
/** Content tagged with the type of a containing object. */
|
||||
class TypedContent extends MkTypedContent {
|
||||
private Content c;
|
||||
private DataFlowType t;
|
||||
|
||||
TypedContent() { this = MkTypedContent(c, t) }
|
||||
|
||||
/** Gets the content. */
|
||||
Content getContent() { result = c }
|
||||
|
||||
/** Gets the container type. */
|
||||
DataFlowType getContainerType() { result = t }
|
||||
|
||||
/** Gets a textual representation of this content. */
|
||||
string toString() { result = c.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The front of an access path. This is either a head or a nil.
|
||||
*/
|
||||
@@ -702,25 +753,36 @@ abstract class AccessPathFront extends TAccessPathFront {
|
||||
|
||||
abstract boolean toBoolNonEmpty();
|
||||
|
||||
predicate headUsesContent(Content f) { this = TFrontHead(f) }
|
||||
predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) }
|
||||
|
||||
predicate isClearedAt(Node n) {
|
||||
exists(TypedContent tc |
|
||||
this.headUsesContent(tc) and
|
||||
clearsContent(n, tc.getContent())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||
override string toString() {
|
||||
exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t))
|
||||
}
|
||||
private DataFlowType t;
|
||||
|
||||
override DataFlowType getType() { this = TFrontNil(result) }
|
||||
AccessPathFrontNil() { this = TFrontNil(t) }
|
||||
|
||||
override string toString() { result = ppReprType(t) }
|
||||
|
||||
override DataFlowType getType() { result = t }
|
||||
|
||||
override boolean toBoolNonEmpty() { result = false }
|
||||
}
|
||||
|
||||
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
|
||||
override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) }
|
||||
private TypedContent tc;
|
||||
|
||||
override DataFlowType getType() {
|
||||
exists(Content head | this = TFrontHead(head) | result = head.getContainerType())
|
||||
}
|
||||
AccessPathFrontHead() { this = TFrontHead(tc) }
|
||||
|
||||
override string toString() { result = tc.toString() }
|
||||
|
||||
override DataFlowType getType() { result = tc.getContainerType() }
|
||||
|
||||
override boolean toBoolNonEmpty() { result = true }
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -148,12 +148,6 @@ class Content extends TContent {
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0
|
||||
}
|
||||
|
||||
/** Gets the type of the object containing this content. */
|
||||
abstract Type getContainerType();
|
||||
|
||||
/** Gets the type of this content. */
|
||||
abstract Type getType();
|
||||
}
|
||||
|
||||
private class FieldContent extends Content, TFieldContent {
|
||||
@@ -168,26 +162,14 @@ private class FieldContent extends Content, TFieldContent {
|
||||
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
f.getLocation().hasLocationInfo(path, sl, sc, el, ec)
|
||||
}
|
||||
|
||||
override Type getContainerType() { result = f.getDeclaringType() }
|
||||
|
||||
override Type getType() { result = f.getType() }
|
||||
}
|
||||
|
||||
private class CollectionContent extends Content, TCollectionContent {
|
||||
override string toString() { result = "collection" }
|
||||
|
||||
override Type getContainerType() { none() }
|
||||
|
||||
override Type getType() { none() }
|
||||
}
|
||||
|
||||
private class ArrayContent extends Content, TArrayContent {
|
||||
override string toString() { result = "array" }
|
||||
|
||||
override Type getContainerType() { none() }
|
||||
|
||||
override Type getType() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,6 +216,13 @@ predicate readStep(Node node1, Content f, Node node2) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at node `n`.
|
||||
*/
|
||||
predicate clearsContent(Node n, Content c) {
|
||||
none() // stub implementation
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a representative (boxed) type for `t` for the purpose of pruning
|
||||
* possible flow. A single type is used for all numeric types to account for
|
||||
|
||||
@@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private
|
||||
* To create a configuration, extend this class with a subclass whose
|
||||
* characteristic predicate is a unique singleton string. For example, write
|
||||
*
|
||||
* ```
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
@@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
|
||||
@@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private
|
||||
* To create a configuration, extend this class with a subclass whose
|
||||
* characteristic predicate is a unique singleton string. For example, write
|
||||
*
|
||||
* ```
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
@@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -198,123 +198,130 @@ private module Cached {
|
||||
/**
|
||||
* The final flow-through calculation:
|
||||
*
|
||||
* - Input access paths are abstracted with a `ContentOption` parameter
|
||||
* that represents the head of the access path. `TContentNone()` means that
|
||||
* the access path is unrestricted.
|
||||
* - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`)
|
||||
* or summarized as a single read step with before and after types recorded
|
||||
* in the `ReadStepTypesOption` parameter.
|
||||
* - Types are checked using the `compatibleTypes()` relation.
|
||||
*/
|
||||
private module Final {
|
||||
/**
|
||||
* Holds if `p` can flow to `node` in the same callable using only
|
||||
* value-preserving steps, not taking call contexts into account.
|
||||
* value-preserving steps and possibly a single read step, not taking
|
||||
* call contexts into account.
|
||||
*
|
||||
* `contentIn` describes the content of `p` that can flow to `node`
|
||||
* (if any).
|
||||
* If a read step was taken, then `read` captures the `Content`, the
|
||||
* container type, and the content type.
|
||||
*/
|
||||
predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) {
|
||||
parameterValueFlow0(p, node, contentIn) and
|
||||
predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) {
|
||||
parameterValueFlow0(p, node, read) and
|
||||
if node instanceof CastingNode
|
||||
then
|
||||
// normal flow through
|
||||
contentIn = TContentNone() and
|
||||
read = TReadStepTypesNone() and
|
||||
compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node))
|
||||
or
|
||||
// getter
|
||||
exists(Content fIn |
|
||||
contentIn.getContent() = fIn and
|
||||
compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node))
|
||||
)
|
||||
compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node))
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) {
|
||||
private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) {
|
||||
p = node and
|
||||
Cand::cand(p, _) and
|
||||
contentIn = TContentNone()
|
||||
read = TReadStepTypesNone()
|
||||
or
|
||||
// local flow
|
||||
exists(Node mid |
|
||||
parameterValueFlow(p, mid, contentIn) and
|
||||
parameterValueFlow(p, mid, read) and
|
||||
LocalFlowBigStep::localFlowBigStep(mid, node)
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Node mid, Content f |
|
||||
parameterValueFlow(p, mid, TContentNone()) and
|
||||
readStep(mid, f, node) and
|
||||
contentIn.getContent() = f and
|
||||
exists(Node mid |
|
||||
parameterValueFlow(p, mid, TReadStepTypesNone()) and
|
||||
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
|
||||
read.getContentType()) and
|
||||
Cand::parameterValueFlowReturnCand(p, _, true) and
|
||||
compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType())
|
||||
compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType())
|
||||
)
|
||||
or
|
||||
// flow through: no prior read
|
||||
exists(ArgumentNode arg |
|
||||
parameterValueFlowArg(p, arg, TContentNone()) and
|
||||
argumentValueFlowsThrough(arg, contentIn, node)
|
||||
parameterValueFlowArg(p, arg, TReadStepTypesNone()) and
|
||||
argumentValueFlowsThrough(arg, read, node)
|
||||
)
|
||||
or
|
||||
// flow through: no read inside method
|
||||
exists(ArgumentNode arg |
|
||||
parameterValueFlowArg(p, arg, contentIn) and
|
||||
argumentValueFlowsThrough(arg, TContentNone(), node)
|
||||
parameterValueFlowArg(p, arg, read) and
|
||||
argumentValueFlowsThrough(arg, TReadStepTypesNone(), node)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlowArg(
|
||||
ParameterNode p, ArgumentNode arg, ContentOption contentIn
|
||||
ParameterNode p, ArgumentNode arg, ReadStepTypesOption read
|
||||
) {
|
||||
parameterValueFlow(p, arg, contentIn) and
|
||||
parameterValueFlow(p, arg, read) and
|
||||
Cand::argumentValueFlowsThroughCand(arg, _, _)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate argumentValueFlowsThrough0(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read
|
||||
) {
|
||||
exists(ParameterNode param | viableParamArg(call, param, arg) |
|
||||
parameterValueFlowReturn(param, kind, contentIn)
|
||||
parameterValueFlowReturn(param, kind, read)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `arg` flows to `out` through a call using only value-preserving steps,
|
||||
* not taking call contexts into account.
|
||||
* Holds if `arg` flows to `out` through a call using only
|
||||
* value-preserving steps and possibly a single read step, not taking
|
||||
* call contexts into account.
|
||||
*
|
||||
* `contentIn` describes the content of `arg` that can flow to `out` (if any).
|
||||
* If a read step was taken, then `read` captures the `Content`, the
|
||||
* container type, and the content type.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) {
|
||||
predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) {
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
argumentValueFlowsThrough0(call, arg, kind, contentIn) and
|
||||
argumentValueFlowsThrough0(call, arg, kind, read) and
|
||||
out = getAnOutNode(call, kind)
|
||||
|
|
||||
// normal flow through
|
||||
contentIn = TContentNone() and
|
||||
read = TReadStepTypesNone() and
|
||||
compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out))
|
||||
or
|
||||
// getter
|
||||
exists(Content fIn |
|
||||
contentIn.getContent() = fIn and
|
||||
compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and
|
||||
compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out))
|
||||
)
|
||||
compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and
|
||||
compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `arg` flows to `out` through a call using only
|
||||
* value-preserving steps and a single read step, not taking call
|
||||
* contexts into account, thus representing a getter-step.
|
||||
*/
|
||||
predicate getterStep(ArgumentNode arg, Content c, Node out) {
|
||||
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p` can flow to a return node of kind `kind` in the same
|
||||
* callable using only value-preserving steps.
|
||||
* callable using only value-preserving steps and possibly a single read
|
||||
* step.
|
||||
*
|
||||
* `contentIn` describes the content of `p` that can flow to the return
|
||||
* node (if any).
|
||||
* If a read step was taken, then `read` captures the `Content`, the
|
||||
* container type, and the content type.
|
||||
*/
|
||||
private predicate parameterValueFlowReturn(
|
||||
ParameterNode p, ReturnKind kind, ContentOption contentIn
|
||||
ParameterNode p, ReturnKind kind, ReadStepTypesOption read
|
||||
) {
|
||||
exists(ReturnNode ret |
|
||||
parameterValueFlow(p, ret, contentIn) and
|
||||
parameterValueFlow(p, ret, read) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
@@ -329,7 +336,27 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) {
|
||||
parameterValueFlow(p, n.getPreUpdateNode(), TContentNone())
|
||||
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
||||
}
|
||||
|
||||
private predicate store(
|
||||
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||
) {
|
||||
storeStep(node1, c, node2) and
|
||||
readStep(_, c, _) and
|
||||
contentType = getErasedNodeTypeBound(node1) and
|
||||
containerType = getErasedNodeTypeBound(node2)
|
||||
or
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
||||
or
|
||||
readStep(n2, c, n1) and
|
||||
contentType = getErasedNodeTypeBound(n1) and
|
||||
containerType = getErasedNodeTypeBound(n2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -340,17 +367,8 @@ private module Cached {
|
||||
* been stored into, in order to handle cases like `x.f1.f2 = y`.
|
||||
*/
|
||||
cached
|
||||
predicate store(Node node1, Content f, Node node2) {
|
||||
storeStep(node1, f, node2) and readStep(_, f, _)
|
||||
or
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TContentSome(f), n1)
|
||||
or
|
||||
readStep(n2, f, n1)
|
||||
)
|
||||
predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) {
|
||||
store(node1, tc.getContent(), node2, contentType, tc.getContainerType())
|
||||
}
|
||||
|
||||
import FlowThrough
|
||||
@@ -397,10 +415,13 @@ private module Cached {
|
||||
TBooleanNone() or
|
||||
TBooleanSome(boolean b) { b = true or b = false }
|
||||
|
||||
cached
|
||||
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
|
||||
|
||||
cached
|
||||
newtype TAccessPathFront =
|
||||
TFrontNil(DataFlowType t) or
|
||||
TFrontHead(Content f)
|
||||
TFrontHead(TypedContent tc)
|
||||
|
||||
cached
|
||||
newtype TAccessPathFrontOption =
|
||||
@@ -415,25 +436,38 @@ class CastingNode extends Node {
|
||||
CastingNode() {
|
||||
this instanceof ParameterNode or
|
||||
this instanceof CastNode or
|
||||
this instanceof OutNodeExt
|
||||
this instanceof OutNodeExt or
|
||||
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
||||
// is obtained by popping the head of the access path stack) is compatible with
|
||||
// the type of `x.f`.
|
||||
readStep(_, _, this)
|
||||
}
|
||||
}
|
||||
|
||||
newtype TContentOption =
|
||||
TContentNone() or
|
||||
TContentSome(Content f)
|
||||
private predicate readStepWithTypes(
|
||||
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
|
||||
) {
|
||||
readStep(n1, c, n2) and
|
||||
container = getErasedNodeTypeBound(n1) and
|
||||
content = getErasedNodeTypeBound(n2)
|
||||
}
|
||||
|
||||
private class ContentOption extends TContentOption {
|
||||
Content getContent() { this = TContentSome(result) }
|
||||
|
||||
predicate hasContent() { exists(this.getContent()) }
|
||||
|
||||
string toString() {
|
||||
result = this.getContent().toString()
|
||||
or
|
||||
not this.hasContent() and
|
||||
result = "<none>"
|
||||
private newtype TReadStepTypesOption =
|
||||
TReadStepTypesNone() or
|
||||
TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) {
|
||||
readStepWithTypes(_, container, c, _, content)
|
||||
}
|
||||
|
||||
private class ReadStepTypesOption extends TReadStepTypesOption {
|
||||
predicate isSome() { this instanceof TReadStepTypesSome }
|
||||
|
||||
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
|
||||
|
||||
Content getContent() { this = TReadStepTypesSome(_, result, _) }
|
||||
|
||||
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
|
||||
|
||||
string toString() { if this.isSome() then result = "Some(..)" else result = "None()" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -692,6 +726,23 @@ class BooleanOption extends TBooleanOption {
|
||||
}
|
||||
}
|
||||
|
||||
/** Content tagged with the type of a containing object. */
|
||||
class TypedContent extends MkTypedContent {
|
||||
private Content c;
|
||||
private DataFlowType t;
|
||||
|
||||
TypedContent() { this = MkTypedContent(c, t) }
|
||||
|
||||
/** Gets the content. */
|
||||
Content getContent() { result = c }
|
||||
|
||||
/** Gets the container type. */
|
||||
DataFlowType getContainerType() { result = t }
|
||||
|
||||
/** Gets a textual representation of this content. */
|
||||
string toString() { result = c.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The front of an access path. This is either a head or a nil.
|
||||
*/
|
||||
@@ -702,25 +753,36 @@ abstract class AccessPathFront extends TAccessPathFront {
|
||||
|
||||
abstract boolean toBoolNonEmpty();
|
||||
|
||||
predicate headUsesContent(Content f) { this = TFrontHead(f) }
|
||||
predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) }
|
||||
|
||||
predicate isClearedAt(Node n) {
|
||||
exists(TypedContent tc |
|
||||
this.headUsesContent(tc) and
|
||||
clearsContent(n, tc.getContent())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||
override string toString() {
|
||||
exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t))
|
||||
}
|
||||
private DataFlowType t;
|
||||
|
||||
override DataFlowType getType() { this = TFrontNil(result) }
|
||||
AccessPathFrontNil() { this = TFrontNil(t) }
|
||||
|
||||
override string toString() { result = ppReprType(t) }
|
||||
|
||||
override DataFlowType getType() { result = t }
|
||||
|
||||
override boolean toBoolNonEmpty() { result = false }
|
||||
}
|
||||
|
||||
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
|
||||
override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) }
|
||||
private TypedContent tc;
|
||||
|
||||
override DataFlowType getType() {
|
||||
exists(Content head | this = TFrontHead(head) | result = head.getContainerType())
|
||||
}
|
||||
AccessPathFrontHead() { this = TFrontHead(tc) }
|
||||
|
||||
override string toString() { result = tc.toString() }
|
||||
|
||||
override DataFlowType getType() { result = tc.getContainerType() }
|
||||
|
||||
override boolean toBoolNonEmpty() { result = true }
|
||||
}
|
||||
|
||||
@@ -128,8 +128,13 @@ private class SideEffectOutNode extends OutNode {
|
||||
* `kind`.
|
||||
*/
|
||||
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
|
||||
result.getCall() = call and
|
||||
result.getReturnKind() = kind
|
||||
// There should be only one `OutNode` for a given `(call, kind)` pair. Showing the optimizer that
|
||||
// this is true helps it make better decisions downstream, especially in virtual dispatch.
|
||||
result =
|
||||
unique(OutNode outNode |
|
||||
outNode.getCall() = call and
|
||||
outNode.getReturnKind() = kind
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,12 +160,6 @@ class Content extends TContent {
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0
|
||||
}
|
||||
|
||||
/** Gets the type of the object containing this content. */
|
||||
abstract Type getContainerType();
|
||||
|
||||
/** Gets the type of this content. */
|
||||
abstract Type getType();
|
||||
}
|
||||
|
||||
private class FieldContent extends Content, TFieldContent {
|
||||
@@ -175,26 +174,32 @@ private class FieldContent extends Content, TFieldContent {
|
||||
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
f.getLocation().hasLocationInfo(path, sl, sc, el, ec)
|
||||
}
|
||||
|
||||
override Type getContainerType() { result = f.getDeclaringType() }
|
||||
|
||||
override Type getType() { result = f.getType() }
|
||||
}
|
||||
|
||||
private class CollectionContent extends Content, TCollectionContent {
|
||||
override string toString() { result = "collection" }
|
||||
|
||||
override Type getContainerType() { none() }
|
||||
|
||||
override Type getType() { none() }
|
||||
}
|
||||
|
||||
private class ArrayContent extends Content, TArrayContent {
|
||||
override string toString() { result = "array" }
|
||||
}
|
||||
|
||||
override Type getContainerType() { none() }
|
||||
private predicate storeStepNoChi(Node node1, Content f, PostUpdateNode node2) {
|
||||
exists(FieldAddressInstruction fa, StoreInstruction store |
|
||||
store = node2.asInstruction() and
|
||||
store.getDestinationAddress() = fa and
|
||||
store.getSourceValue() = node1.asInstruction() and
|
||||
f.(FieldContent).getField() = fa.getField()
|
||||
)
|
||||
}
|
||||
|
||||
override Type getType() { none() }
|
||||
private predicate storeStepChi(Node node1, Content f, PostUpdateNode node2) {
|
||||
exists(FieldAddressInstruction fa, StoreInstruction store |
|
||||
node1.asInstruction() = store and
|
||||
store.getDestinationAddress() = fa and
|
||||
node2.asInstruction().(ChiInstruction).getPartial() = store and
|
||||
f.(FieldContent).getField() = fa.getField()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,9 +207,9 @@ private class ArrayContent extends Content, TArrayContent {
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*/
|
||||
predicate storeStep(Node node1, Content f, StoreStepNode node2) {
|
||||
node2.getStoredValue() = node1 and
|
||||
f.(FieldContent).getField() = node2.getAField()
|
||||
predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
|
||||
storeStepNoChi(node1, f, node2) or
|
||||
storeStepChi(node1, f, node2)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,9 +217,20 @@ predicate storeStep(Node node1, Content f, StoreStepNode node2) {
|
||||
* Thus, `node1` references an object with a field `f` whose value ends up in
|
||||
* `node2`.
|
||||
*/
|
||||
predicate readStep(Node node1, Content f, ReadStepNode node2) {
|
||||
node2.getReadValue() = node1 and
|
||||
f.(FieldContent).getField() = node2.getAField()
|
||||
predicate readStep(Node node1, Content f, Node node2) {
|
||||
exists(FieldAddressInstruction fa, LoadInstruction load |
|
||||
load.getSourceAddress() = fa and
|
||||
node1.asInstruction() = load.getSourceValueOperand().getAnyDef() and
|
||||
fa.getField() = f.(FieldContent).getField() and
|
||||
load = node2.asInstruction()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at node `n`.
|
||||
*/
|
||||
predicate clearsContent(Node n, Content c) {
|
||||
none() // stub implementation
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,9 +13,7 @@ private import semmle.code.cpp.models.interfaces.DataFlow
|
||||
|
||||
private newtype TIRDataFlowNode =
|
||||
TInstructionNode(Instruction i) or
|
||||
TVariableNode(Variable var) or
|
||||
TStoreNode(StoreChain chain) or
|
||||
TLoadNode(LoadChain load)
|
||||
TVariableNode(Variable var)
|
||||
|
||||
/**
|
||||
* A node in a data flow graph.
|
||||
@@ -273,7 +271,7 @@ deprecated class UninitializedNode extends Node {
|
||||
* This class exists to match the interface used by Java. There are currently no non-abstract
|
||||
* classes that extend it. When we implement field flow, we can revisit this.
|
||||
*/
|
||||
abstract class PostUpdateNode extends Node {
|
||||
abstract class PostUpdateNode extends InstructionNode {
|
||||
/**
|
||||
* Gets the node before the state update.
|
||||
*/
|
||||
@@ -288,15 +286,59 @@ abstract class PostUpdateNode extends Node {
|
||||
* value, but does not necessarily replace it entirely. For example:
|
||||
* ```
|
||||
* x.y = 1; // a partial definition of the object `x`.
|
||||
* x.y.z = 1; // a partial definition of the objects `x.y` and `x`.
|
||||
* x.y.z = 1; // a partial definition of the object `x.y`.
|
||||
* x.setY(1); // a partial definition of the object `x`.
|
||||
* setY(&x); // a partial definition of the object `x`.
|
||||
* ```
|
||||
*/
|
||||
abstract private class PartialDefinitionNode extends PostUpdateNode {
|
||||
abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode {
|
||||
abstract Expr getDefinedExpr();
|
||||
}
|
||||
|
||||
private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
|
||||
override ChiInstruction instr;
|
||||
FieldAddressInstruction field;
|
||||
|
||||
ExplicitFieldStoreQualifierNode() {
|
||||
not instr.isResultConflated() and
|
||||
exists(StoreInstruction store |
|
||||
instr.getPartial() = store and field = store.getDestinationAddress()
|
||||
)
|
||||
}
|
||||
|
||||
// There might be multiple `ChiInstructions` that has a particular instruction as
|
||||
// the total operand - so this definition gives consistency errors in
|
||||
// DataFlowImplConsistency::Consistency. However, it's not clear what (if any) implications
|
||||
// this consistency failure has.
|
||||
override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() }
|
||||
|
||||
override Expr getDefinedExpr() {
|
||||
result = field.getObjectAddress().getUnconvertedResultExpression()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to.
|
||||
* For instance, an update to a field of a struct containing only one field. For these cases we
|
||||
* attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case
|
||||
* (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`.
|
||||
*/
|
||||
private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode {
|
||||
override StoreInstruction instr;
|
||||
FieldAddressInstruction field;
|
||||
|
||||
ExplicitSingleFieldStoreQualifierNode() {
|
||||
field = instr.getDestinationAddress() and
|
||||
not exists(ChiInstruction chi | chi.getPartial() = instr)
|
||||
}
|
||||
|
||||
override Node getPreUpdateNode() { none() }
|
||||
|
||||
override Expr getDefinedExpr() {
|
||||
result = field.getObjectAddress().getUnconvertedResultExpression()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that represents the value of a variable after a function call that
|
||||
* may have changed the variable because it's passed by reference.
|
||||
@@ -388,413 +430,6 @@ class VariableNode extends Node, TVariableNode {
|
||||
override string toString() { result = v.toString() }
|
||||
}
|
||||
|
||||
/** The target node of a `readStep`. */
|
||||
abstract class ReadStepNode extends Node {
|
||||
/** Get the field that is read. */
|
||||
abstract Field getAField();
|
||||
|
||||
/** Get the node representing the value that is read. */
|
||||
abstract Node getReadValue();
|
||||
}
|
||||
|
||||
/** The target node of a `storeStep`. */
|
||||
abstract class StoreStepNode extends PostUpdateNode {
|
||||
/** Get the field that is stored into. */
|
||||
abstract Field getAField();
|
||||
|
||||
/** Get the node representing the value that is stored. */
|
||||
abstract Node getStoredValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sometimes a sequence of `FieldAddressInstruction`s does not end with a `StoreInstruction`.
|
||||
* This class abstracts out the information needed to end a `StoreChain`.
|
||||
*/
|
||||
abstract private class StoreChainEndInstruction extends Instruction {
|
||||
abstract FieldAddressInstruction getFieldInstruction();
|
||||
|
||||
abstract Instruction getBeginInstruction();
|
||||
|
||||
abstract Node getPreUpdateNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* A `StoreInstruction` that ends a sequence of `FieldAddressInstruction`s.
|
||||
*/
|
||||
private class StoreChainEndInstructionStoreWithChi extends StoreChainEndInstruction, ChiInstruction {
|
||||
StoreInstruction store;
|
||||
FieldAddressInstruction fi;
|
||||
|
||||
StoreChainEndInstructionStoreWithChi() {
|
||||
not this.isResultConflated() and
|
||||
this.getPartial() = store and
|
||||
fi = skipConversion*(store.getDestinationAddress())
|
||||
}
|
||||
|
||||
override FieldAddressInstruction getFieldInstruction() { result = fi }
|
||||
|
||||
override Node getPreUpdateNode() { result.asInstruction() = this.getTotal() }
|
||||
|
||||
override Instruction getBeginInstruction() { result = store }
|
||||
}
|
||||
|
||||
/**
|
||||
* Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to.
|
||||
* For instance, an update to a field of a struct containing only one field. For these cases we
|
||||
* attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case
|
||||
* (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`.
|
||||
*/
|
||||
private class StoreChainEndInstructionStoreWithoutChi extends StoreChainEndInstruction,
|
||||
StoreInstruction {
|
||||
FieldAddressInstruction fi;
|
||||
|
||||
StoreChainEndInstructionStoreWithoutChi() {
|
||||
not exists(ChiInstruction chi | chi.getPartial() = this) and
|
||||
fi = skipConversion*(this.getDestinationAddress())
|
||||
}
|
||||
|
||||
override FieldAddressInstruction getFieldInstruction() { result = fi }
|
||||
|
||||
override Node getPreUpdateNode() { none() }
|
||||
|
||||
override Instruction getBeginInstruction() { result = this.getSourceValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
* When traversing dependencies between an instruction and its operands
|
||||
* it is sometimes convenient to ignore certain instructions. For instance,
|
||||
* the `LoadChain` for `((B&)a.b).c` inserts a `CopyValueInstruction`
|
||||
* between the computed address for `b` and the `FieldAddressInstruction`
|
||||
* for `c`.
|
||||
*/
|
||||
private Instruction skipConversion(Instruction instr) {
|
||||
result = instr.(CopyInstruction).getSourceValue()
|
||||
or
|
||||
result = instr.(ConvertInstruction).getUnary()
|
||||
or
|
||||
result = instr.(CheckedConvertOrNullInstruction).getUnary()
|
||||
or
|
||||
result = instr.(InheritanceConversionInstruction).getUnary()
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends a `StoreChain` with a `WriteSideEffectInstruction` such that we build up
|
||||
* the correct access paths. For example in:
|
||||
* ```
|
||||
* void setter(B *b, int data) {
|
||||
* b->c = data;
|
||||
* }
|
||||
* ...
|
||||
* setter(&a.b, source());
|
||||
* sink(a.b.c)
|
||||
* ```
|
||||
* In order to register `a.b.c` as a `readStep`, the access path must
|
||||
* contain `[a, b, c]`, and thus the access path must be `[a, b]`
|
||||
* before entering `setter`.
|
||||
*/
|
||||
private class StoreChainEndInstructionSideEffect extends StoreChainEndInstruction, ChiInstruction {
|
||||
WriteSideEffectInstruction sideEffect;
|
||||
FieldAddressInstruction fi;
|
||||
|
||||
StoreChainEndInstructionSideEffect() {
|
||||
not this.isResultConflated() and
|
||||
this.getPartial() = sideEffect and
|
||||
fi = skipConversion*(sideEffect.getArgumentDef())
|
||||
}
|
||||
|
||||
override FieldAddressInstruction getFieldInstruction() { result = fi }
|
||||
|
||||
override Node getPreUpdateNode() { result.asInstruction() = this.getTotal() }
|
||||
|
||||
override Instruction getBeginInstruction() { result = sideEffect }
|
||||
}
|
||||
|
||||
private newtype TStoreChain =
|
||||
TStoreChainConsNil(FieldAddressInstruction f, StoreChainEndInstruction end) {
|
||||
end.getFieldInstruction() = f
|
||||
} or
|
||||
TStoreChainConsCons(FieldAddressInstruction f, TStoreChain next) {
|
||||
exists(FieldAddressInstruction g | skipConversion*(g.getObjectAddress()) = f |
|
||||
next = TStoreChainConsCons(g, _) or
|
||||
next = TStoreChainConsNil(g, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A `StoreChain` represents a series of field lookups that compute the destination of a store.
|
||||
* For example, given an assignment such as `a.b.c = x`, there are two `StoreChain`s:
|
||||
* One corresponding to the field `b`, and one corresponding to the field `c`. Here, `b` is the parent
|
||||
* `StoreChain` of `c`.
|
||||
*/
|
||||
private class StoreChain extends TStoreChain {
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets the parent of this `StoreChain`, if any. For example, for the assignment
|
||||
* ```
|
||||
* a.b.c = x;
|
||||
* ```
|
||||
* the parent of `c` is `b`, and `b` has no parent.
|
||||
*/
|
||||
final StoreChainConsCons getParent() { result.getChild() = this }
|
||||
|
||||
/** Gets the child of this `StoreChain`, if any. */
|
||||
StoreChain getChild() { none() }
|
||||
|
||||
/**
|
||||
* Gets the instruction that receives flow from the outermost `StoreChain` of this chain (i.e.,
|
||||
* the `StoreChain` with no parent).
|
||||
*/
|
||||
StoreChainEndInstruction getEndInstruction() { none() }
|
||||
|
||||
/**
|
||||
* Gets the instruction that flows to the innermost `StoreChain` of this chain (i.e.,
|
||||
* the `StoreChain` with no child).
|
||||
*/
|
||||
Instruction getBeginInstruction() { none() }
|
||||
|
||||
/** Gets the `FieldAddressInstruction` of this `StoreChain` */
|
||||
FieldAddressInstruction getFieldInstruction() { none() }
|
||||
|
||||
/** Gets the `FieldAddressInstruction` of any `StoreChain` in this chain. */
|
||||
FieldAddressInstruction getAFieldInstruction() { none() }
|
||||
|
||||
final Location getLocation() { result = getFieldInstruction().getLocation() }
|
||||
}
|
||||
|
||||
private class StoreChainConsNil extends StoreChain, TStoreChainConsNil {
|
||||
FieldAddressInstruction fi;
|
||||
StoreChainEndInstruction end;
|
||||
|
||||
StoreChainConsNil() { this = TStoreChainConsNil(fi, end) }
|
||||
|
||||
override string toString() { result = fi.getField().toString() }
|
||||
|
||||
override StoreChainEndInstruction getEndInstruction() { result = end }
|
||||
|
||||
override Instruction getBeginInstruction() { result = end.getBeginInstruction() }
|
||||
|
||||
override FieldAddressInstruction getFieldInstruction() { result = fi }
|
||||
|
||||
override FieldAddressInstruction getAFieldInstruction() { result = fi }
|
||||
}
|
||||
|
||||
private class StoreChainConsCons extends StoreChain, TStoreChainConsCons {
|
||||
FieldAddressInstruction fi;
|
||||
StoreChain next;
|
||||
|
||||
StoreChainConsCons() { this = TStoreChainConsCons(fi, next) }
|
||||
|
||||
override string toString() { result = fi.getField().toString() + "." + next.toString() }
|
||||
|
||||
override StoreChain getChild() { result = next }
|
||||
|
||||
override FieldAddressInstruction getFieldInstruction() { result = fi }
|
||||
|
||||
override FieldAddressInstruction getAFieldInstruction() {
|
||||
result = [fi, next.getAFieldInstruction()]
|
||||
}
|
||||
|
||||
override StoreChainEndInstruction getEndInstruction() { result = next.getEndInstruction() }
|
||||
|
||||
override Instruction getBeginInstruction() { result = next.getBeginInstruction() }
|
||||
}
|
||||
|
||||
private newtype TLoadChain =
|
||||
TLoadChainConsNil(FieldAddressInstruction fi, LoadChainEndInstruction end) {
|
||||
end.getFieldInstruction() = fi
|
||||
} or
|
||||
TLoadChainConsCons(FieldAddressInstruction fi, TLoadChain next) {
|
||||
exists(FieldAddressInstruction nextFi | skipConversion*(nextFi.getObjectAddress()) = fi |
|
||||
next = TLoadChainConsCons(nextFi, _) or
|
||||
next = TLoadChainConsNil(nextFi, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** This class abstracts out the information needed to end a `LoadChain`. */
|
||||
abstract private class LoadChainEndInstruction extends Instruction {
|
||||
abstract FieldAddressInstruction getFieldInstruction();
|
||||
|
||||
abstract Instruction getReadValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* A `LoadInstruction` that ends a sequence of `FieldAddressInstruction`s.
|
||||
*/
|
||||
private class LoadChainEndInstructionLoad extends LoadChainEndInstruction, LoadInstruction {
|
||||
FieldAddressInstruction fi;
|
||||
|
||||
LoadChainEndInstructionLoad() { fi = skipConversion*(this.getSourceAddress()) }
|
||||
|
||||
override FieldAddressInstruction getFieldInstruction() { result = fi }
|
||||
|
||||
override Instruction getReadValue() { result = getSourceValueOperand().getAnyDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends a `LoadChain` with a `ReadSideEffectInstruction`. This ensures that we pop content from the
|
||||
* access path when passing an argument that reads a field. For example in:
|
||||
* ```
|
||||
* void read_f(Inner* inner) {
|
||||
* sink(inner->f);
|
||||
* }
|
||||
* ...
|
||||
* outer.inner.f = taint();
|
||||
* read_f(&outer.inner);
|
||||
* ```
|
||||
* In order to register `inner->f` as a `readStep`, the head of the access path must
|
||||
* be `f`, and thus reading `&outer.inner` must pop `inner` from the access path
|
||||
* before entering `read_f`.
|
||||
*/
|
||||
private class LoadChainEndInstructionSideEffect extends LoadChainEndInstruction,
|
||||
ReadSideEffectInstruction {
|
||||
FieldAddressInstruction fi;
|
||||
|
||||
LoadChainEndInstructionSideEffect() { fi = skipConversion*(this.getArgumentDef()) }
|
||||
|
||||
override FieldAddressInstruction getFieldInstruction() { result = fi }
|
||||
|
||||
override Instruction getReadValue() { result = getSideEffectOperand().getAnyDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `LoadChain` represents a series of field lookups that compute the source address of a load.
|
||||
* For example, given the field lookup in `f(a.b.c)`, there are two `LoadChains`s:
|
||||
* One corresponding to the field `b`, and one corresponding to the field `c`. Here, `b` is the parent
|
||||
* `LoadChain` of `c`.
|
||||
*/
|
||||
private class LoadChain extends TLoadChain {
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets the instruction that receives flow from the innermost `LoadChain` of this chain (i.e.,
|
||||
* the `LoadChain` with no child).
|
||||
*/
|
||||
LoadChainEndInstruction getEndInstruction() { none() }
|
||||
|
||||
/**
|
||||
* Gets the parent of this `LoadChain`, if any. For example in `f(a.b.c)` the parent of `c` is `b`,
|
||||
* and `b` has no parent.
|
||||
*/
|
||||
final LoadChainConsCons getParent() { result.getChild() = this }
|
||||
|
||||
/** Gets the child of this `LoadChain`, if any. */
|
||||
LoadChain getChild() { none() }
|
||||
|
||||
/** Gets the `FieldAddressInstruction` of this `LoadChain` */
|
||||
FieldAddressInstruction getFieldInstruction() { none() }
|
||||
|
||||
final Location getLocation() { result = getFieldInstruction().getLocation() }
|
||||
}
|
||||
|
||||
private class LoadChainConsNil extends LoadChain, TLoadChainConsNil {
|
||||
FieldAddressInstruction fi;
|
||||
LoadChainEndInstruction end;
|
||||
|
||||
LoadChainConsNil() { this = TLoadChainConsNil(fi, end) }
|
||||
|
||||
override string toString() { result = fi.getField().toString() }
|
||||
|
||||
override LoadChainEndInstruction getEndInstruction() { result = end }
|
||||
|
||||
override FieldAddressInstruction getFieldInstruction() { result = fi }
|
||||
}
|
||||
|
||||
private class LoadChainConsCons extends LoadChain, TLoadChainConsCons {
|
||||
FieldAddressInstruction fi;
|
||||
LoadChain next;
|
||||
|
||||
LoadChainConsCons() { this = TLoadChainConsCons(fi, next) }
|
||||
|
||||
override string toString() { result = fi.getField().toString() + "." + next.toString() }
|
||||
|
||||
override LoadChainEndInstruction getEndInstruction() { result = next.getEndInstruction() }
|
||||
|
||||
override LoadChain getChild() { result = next }
|
||||
|
||||
override FieldAddressInstruction getFieldInstruction() { result = fi }
|
||||
}
|
||||
|
||||
/**
|
||||
* A dataflow node generated by a partial definition.
|
||||
* The `StoreNode` class extends `ReadStepNode` to participate in reverse read steps.
|
||||
* A reverse read is a store step that is "inferred" by the DataFlow library. For example in the
|
||||
* assignment:
|
||||
* ```
|
||||
* a.b.c = x;
|
||||
* ```
|
||||
* Here, the access path after the store must reflect that a value has been stored into the field `c` of
|
||||
* the object at field `b`. The field `c` is added to the access path through a `storeStep`, and the
|
||||
* field `b` is inferred by the DataFlow library because there's a read step (reading the field `b`) from
|
||||
* the pre update node for `b.c` to the pre update node for `c`.
|
||||
*/
|
||||
private class StoreNode extends TStoreNode, StoreStepNode, ReadStepNode, PartialDefinitionNode {
|
||||
StoreChain storeChain;
|
||||
|
||||
StoreNode() { this = TStoreNode(storeChain) }
|
||||
|
||||
override string toString() { result = storeChain.toString() }
|
||||
|
||||
StoreChain getStoreChain() { result = storeChain }
|
||||
|
||||
override Node getPreUpdateNode() {
|
||||
result.(StoreNode).getStoreChain() = storeChain.getParent()
|
||||
or
|
||||
not exists(storeChain.getParent()) and
|
||||
result = storeChain.getEndInstruction().getPreUpdateNode()
|
||||
}
|
||||
|
||||
override Field getAField() { result = storeChain.getFieldInstruction().getField() }
|
||||
|
||||
override Node getStoredValue() {
|
||||
// Only the `StoreNode` attached to the end of the `StoreChain` has a `getStoredValue()`, so
|
||||
// this is the only `StoreNode` that matches storeStep.
|
||||
not exists(storeChain.getChild()) and result.asInstruction() = storeChain.getBeginInstruction()
|
||||
}
|
||||
|
||||
override Node getReadValue() { result = getPreUpdateNode() }
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override Function getFunction() { result = storeChain.getEndInstruction().getEnclosingFunction() }
|
||||
|
||||
override Type getType() { result = storeChain.getEndInstruction().getResultType() }
|
||||
|
||||
override Location getLocation() { result = storeChain.getEndInstruction().getLocation() }
|
||||
|
||||
override Expr getDefinedExpr() {
|
||||
result = storeChain.getAFieldInstruction().getObjectAddress().getUnconvertedResultExpression()
|
||||
}
|
||||
}
|
||||
|
||||
/** A dataflow node generated by loading from an address computed by a sequence of fields lookups. */
|
||||
private class LoadNode extends TLoadNode, ReadStepNode {
|
||||
LoadChain loadChain;
|
||||
|
||||
LoadNode() { this = TLoadNode(loadChain) }
|
||||
|
||||
override Field getAField() { result = loadChain.getFieldInstruction().getField() }
|
||||
|
||||
override Node getReadValue() {
|
||||
result.(LoadNode).getLoadChain() = loadChain.getParent()
|
||||
or
|
||||
not exists(loadChain.getParent()) and
|
||||
result.asInstruction() = loadChain.getEndInstruction().getReadValue()
|
||||
}
|
||||
|
||||
LoadChain getLoadChain() { result = loadChain }
|
||||
|
||||
override string toString() { result = loadChain.toString() }
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override Function getFunction() { result = loadChain.getEndInstruction().getEnclosingFunction() }
|
||||
|
||||
override Type getType() { result = loadChain.getEndInstruction().getResultType() }
|
||||
|
||||
override Location getLocation() { result = loadChain.getEndInstruction().getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the node corresponding to `instr`.
|
||||
*/
|
||||
@@ -848,22 +483,6 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr
|
||||
*/
|
||||
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction())
|
||||
or
|
||||
// When flow has gone all the way through the chain of field accesses
|
||||
// `[f1,f2, ..., fn]` (from right to left) we add flow from f1 to the end instruction.
|
||||
exists(StoreNode synthFrom |
|
||||
synthFrom = nodeFrom and
|
||||
not exists(synthFrom.getStoreChain().getParent()) and
|
||||
synthFrom.getStoreChain().getEndInstruction() = nodeTo.asInstruction()
|
||||
)
|
||||
or
|
||||
// When flow has gone all the way through the chain of field accesses
|
||||
// `[f1, f2, ..., fn]` (from left to right) we add flow from fn to the end instruction.
|
||||
exists(LoadNode synthFrom |
|
||||
synthFrom = nodeFrom and
|
||||
not exists(synthFrom.getLoadChain().getChild()) and
|
||||
synthFrom.getLoadChain().getEndInstruction() = nodeTo.asInstruction()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
|
||||
@@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private
|
||||
* To create a configuration, extend this class with a subclass whose
|
||||
* characteristic predicate is a unique singleton string. For example, write
|
||||
*
|
||||
* ```
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
@@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
|
||||
@@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private
|
||||
* To create a configuration, extend this class with a subclass whose
|
||||
* characteristic predicate is a unique singleton string. For example, write
|
||||
*
|
||||
* ```
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
@@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
|
||||
@@ -111,6 +111,8 @@ private class IRSizedType extends IRType {
|
||||
this = TIRFunctionAddressType(byteSize) or
|
||||
this = TIROpaqueType(_, byteSize)
|
||||
}
|
||||
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
|
||||
// overridden only in the leaf classes.
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,7 +130,7 @@ class IRBooleanType extends IRSizedType, TIRBooleanType {
|
||||
}
|
||||
|
||||
/**
|
||||
* A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and
|
||||
* A numeric type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and
|
||||
* `IRFloatingPointType`.
|
||||
*/
|
||||
class IRNumericType extends IRSizedType {
|
||||
@@ -137,13 +139,27 @@ class IRNumericType extends IRSizedType {
|
||||
this = TIRUnsignedIntegerType(byteSize) or
|
||||
this = TIRFloatingPointType(byteSize, _, _)
|
||||
}
|
||||
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
|
||||
// overridden only in the leaf classes.
|
||||
}
|
||||
|
||||
/**
|
||||
* An integer type. This includes `IRSignedIntegerType` and `IRUnsignedIntegerType`.
|
||||
*/
|
||||
class IRIntegerType extends IRNumericType {
|
||||
IRIntegerType() {
|
||||
this = TIRSignedIntegerType(byteSize) or
|
||||
this = TIRUnsignedIntegerType(byteSize)
|
||||
}
|
||||
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
|
||||
// overridden only in the leaf classes.
|
||||
}
|
||||
|
||||
/**
|
||||
* A signed two's-complement integer. Also used to represent enums whose underlying type is a signed
|
||||
* integer, as well as character types whose representation is signed.
|
||||
*/
|
||||
class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType {
|
||||
class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType {
|
||||
final override string toString() { result = "int" + byteSize.toString() }
|
||||
|
||||
final override Language::LanguageType getCanonicalLanguageType() {
|
||||
@@ -158,7 +174,7 @@ class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType {
|
||||
* An unsigned two's-complement integer. Also used to represent enums whose underlying type is an
|
||||
* unsigned integer, as well as character types whose representation is unsigned.
|
||||
*/
|
||||
class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType {
|
||||
class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType {
|
||||
final override string toString() { result = "uint" + byteSize.toString() }
|
||||
|
||||
final override Language::LanguageType getCanonicalLanguageType() {
|
||||
|
||||
@@ -1,29 +1,12 @@
|
||||
private import internal.IRInternal
|
||||
private import internal.IRFunctionImports as Imports
|
||||
import Imports::IRFunctionBase
|
||||
import Instruction
|
||||
|
||||
private newtype TIRFunction =
|
||||
MkIRFunction(Language::Function func) { Construction::functionHasIR(func) }
|
||||
|
||||
/**
|
||||
* Represents the IR for a function.
|
||||
* The IR for a function.
|
||||
*/
|
||||
class IRFunction extends TIRFunction {
|
||||
Language::Function func;
|
||||
|
||||
IRFunction() { this = MkIRFunction(func) }
|
||||
|
||||
final string toString() { result = "IR: " + func.toString() }
|
||||
|
||||
/**
|
||||
* Gets the function whose IR is represented.
|
||||
*/
|
||||
final Language::Function getFunction() { result = func }
|
||||
|
||||
/**
|
||||
* Gets the location of the function.
|
||||
*/
|
||||
final Language::Location getLocation() { result = func.getLocation() }
|
||||
|
||||
class IRFunction extends IRFunctionBase {
|
||||
/**
|
||||
* Gets the entry point for this function.
|
||||
*/
|
||||
|
||||
@@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
|
||||
/**
|
||||
* Represents a single operation in the IR.
|
||||
*/
|
||||
class Instruction extends Construction::TInstruction {
|
||||
class Instruction extends Construction::TStageInstruction {
|
||||
Instruction() {
|
||||
// The base `TStageInstruction` type is a superset of the actual instructions appearing in this
|
||||
// stage. This call lets the stage filter out the ones that are not reused from raw IR.
|
||||
Construction::hasInstruction(this)
|
||||
}
|
||||
|
||||
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
|
||||
|
||||
/**
|
||||
@@ -194,14 +200,14 @@ class Instruction extends Construction::TInstruction {
|
||||
* conversion.
|
||||
*/
|
||||
final Language::Expr getConvertedResultExpression() {
|
||||
result = Construction::getInstructionConvertedResultExpression(this)
|
||||
result = Raw::getInstructionConvertedResultExpression(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Language::Expr getUnconvertedResultExpression() {
|
||||
result = Construction::getInstructionUnconvertedResultExpression(this)
|
||||
result = Raw::getInstructionUnconvertedResultExpression(this)
|
||||
}
|
||||
|
||||
final Language::LanguageType getResultLanguageType() {
|
||||
@@ -212,6 +218,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* Gets the type of the result produced by this instruction. If the instruction does not produce
|
||||
* a result, its result type will be `IRVoidType`.
|
||||
*/
|
||||
cached
|
||||
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
|
||||
|
||||
/**
|
||||
@@ -250,7 +257,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* result of the `Load` instruction is a prvalue of type `int`, representing
|
||||
* the integer value loaded from variable `x`.
|
||||
*/
|
||||
final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
|
||||
final predicate isGLValue() { getResultLanguageType().hasType(_, true) }
|
||||
|
||||
/**
|
||||
* Gets the size of the result produced by this instruction, in bytes. If the
|
||||
@@ -259,7 +266,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* If `this.isGLValue()` holds for this instruction, the value of
|
||||
* `getResultSize()` will always be the size of a pointer.
|
||||
*/
|
||||
final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
|
||||
final int getResultSize() { result = getResultLanguageType().getByteSize() }
|
||||
|
||||
/**
|
||||
* Gets the opcode that specifies the operation performed by this instruction.
|
||||
@@ -395,7 +402,7 @@ class Instruction extends Construction::TInstruction {
|
||||
class VariableInstruction extends Instruction {
|
||||
IRVariable var;
|
||||
|
||||
VariableInstruction() { var = Construction::getInstructionVariable(this) }
|
||||
VariableInstruction() { var = Raw::getInstructionVariable(this) }
|
||||
|
||||
override string getImmediateString() { result = var.toString() }
|
||||
|
||||
@@ -410,7 +417,7 @@ class VariableInstruction extends Instruction {
|
||||
class FieldInstruction extends Instruction {
|
||||
Language::Field field;
|
||||
|
||||
FieldInstruction() { field = Construction::getInstructionField(this) }
|
||||
FieldInstruction() { field = Raw::getInstructionField(this) }
|
||||
|
||||
final override string getImmediateString() { result = field.toString() }
|
||||
|
||||
@@ -420,7 +427,7 @@ class FieldInstruction extends Instruction {
|
||||
class FunctionInstruction extends Instruction {
|
||||
Language::Function funcSymbol;
|
||||
|
||||
FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) }
|
||||
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
|
||||
|
||||
final override string getImmediateString() { result = funcSymbol.toString() }
|
||||
|
||||
@@ -430,7 +437,7 @@ class FunctionInstruction extends Instruction {
|
||||
class ConstantValueInstruction extends Instruction {
|
||||
string value;
|
||||
|
||||
ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) }
|
||||
ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) }
|
||||
|
||||
final override string getImmediateString() { result = value }
|
||||
|
||||
@@ -440,7 +447,7 @@ class ConstantValueInstruction extends Instruction {
|
||||
class IndexedInstruction extends Instruction {
|
||||
int index;
|
||||
|
||||
IndexedInstruction() { index = Construction::getInstructionIndex(this) }
|
||||
IndexedInstruction() { index = Raw::getInstructionIndex(this) }
|
||||
|
||||
final override string getImmediateString() { result = index.toString() }
|
||||
|
||||
@@ -603,11 +610,16 @@ class ConstantInstruction extends ConstantValueInstruction {
|
||||
}
|
||||
|
||||
class IntegerConstantInstruction extends ConstantInstruction {
|
||||
IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType }
|
||||
IntegerConstantInstruction() {
|
||||
exists(IRType resultType |
|
||||
resultType = getResultIRType() and
|
||||
(resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class FloatConstantInstruction extends ConstantInstruction {
|
||||
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
|
||||
FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType }
|
||||
}
|
||||
|
||||
class StringConstantInstruction extends VariableInstruction {
|
||||
@@ -704,7 +716,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
||||
|
||||
PointerArithmeticInstruction() {
|
||||
getOpcode() instanceof PointerArithmeticOpcode and
|
||||
elementSize = Construction::getInstructionElementSize(this)
|
||||
elementSize = Raw::getInstructionElementSize(this)
|
||||
}
|
||||
|
||||
final override string getImmediateString() { result = elementSize.toString() }
|
||||
@@ -753,7 +765,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
Language::Class derivedClass;
|
||||
|
||||
InheritanceConversionInstruction() {
|
||||
Construction::getInstructionInheritance(this, baseClass, derivedClass)
|
||||
Raw::getInstructionInheritance(this, baseClass, derivedClass)
|
||||
}
|
||||
|
||||
final override string getImmediateString() {
|
||||
@@ -1216,7 +1228,7 @@ class CatchByTypeInstruction extends CatchInstruction {
|
||||
|
||||
CatchByTypeInstruction() {
|
||||
getOpcode() instanceof Opcode::CatchByType and
|
||||
exceptionType = Construction::getInstructionExceptionType(this)
|
||||
exceptionType = Raw::getInstructionExceptionType(this)
|
||||
}
|
||||
|
||||
final override string getImmediateString() { result = exceptionType.toString() }
|
||||
@@ -1362,7 +1374,7 @@ class BuiltInOperationInstruction extends Instruction {
|
||||
|
||||
BuiltInOperationInstruction() {
|
||||
getOpcode() instanceof BuiltInOperationOpcode and
|
||||
operation = Construction::getInstructionBuiltInOperation(this)
|
||||
operation = Raw::getInstructionBuiltInOperation(this)
|
||||
}
|
||||
|
||||
final Language::BuiltInOperation getBuiltInOperation() { result = operation }
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase
|
||||
@@ -1,3 +1,4 @@
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import SSAConstruction as Construction
|
||||
import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import SSAConstructionInternal
|
||||
private import SSAConstructionImports
|
||||
private import SSAConstructionImports as Imports
|
||||
private import Imports::Opcode
|
||||
private import Imports::OperandTag
|
||||
private import Imports::Overlap
|
||||
private import Imports::TInstruction
|
||||
private import Imports::RawIR as RawIR
|
||||
private import SSAInstructions
|
||||
private import NewIR
|
||||
|
||||
private class OldBlock = Reachability::ReachableBlock;
|
||||
@@ -10,54 +16,47 @@ import Cached
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
predicate hasPhiInstructionCached(
|
||||
OldInstruction blockStartInstr, Alias::MemoryLocation defLocation
|
||||
) {
|
||||
exists(OldBlock oldBlock |
|
||||
definitionHasPhiNode(defLocation, oldBlock) and
|
||||
blockStartInstr = oldBlock.getFirstInstruction()
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasChiInstructionCached(OldInstruction primaryInstruction) {
|
||||
hasChiNode(_, primaryInstruction)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
irFunc = oldInstruction.getEnclosingIRFunction() and
|
||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||
)
|
||||
}
|
||||
|
||||
class TStageInstruction =
|
||||
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
|
||||
|
||||
cached
|
||||
predicate hasInstruction(TStageInstruction instr) {
|
||||
instr instanceof TRawInstruction and instr instanceof OldInstruction
|
||||
or
|
||||
instr instanceof TPhiInstruction
|
||||
or
|
||||
instr instanceof TChiInstruction
|
||||
or
|
||||
instr instanceof TUnreachedInstruction
|
||||
}
|
||||
|
||||
private IRBlock getNewBlock(OldBlock oldBlock) {
|
||||
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
||||
}
|
||||
|
||||
cached
|
||||
predicate functionHasIR(Language::Function func) {
|
||||
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
|
||||
}
|
||||
|
||||
cached
|
||||
OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) }
|
||||
|
||||
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
|
||||
// This is just a type cast. Both classes derive from the same newtype.
|
||||
result = var
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TInstruction =
|
||||
WrappedInstruction(OldInstruction oldInstruction) {
|
||||
not oldInstruction instanceof OldIR::PhiInstruction
|
||||
} or
|
||||
Phi(OldBlock block, Alias::MemoryLocation defLocation) {
|
||||
definitionHasPhiNode(defLocation, block)
|
||||
} or
|
||||
Chi(OldInstruction oldInstruction) {
|
||||
not oldInstruction instanceof OldIR::PhiInstruction and
|
||||
hasChiNode(_, oldInstruction)
|
||||
} or
|
||||
Unreached(Language::Function function) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
function = oldInstruction.getEnclosingFunction() and
|
||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasTempVariable(
|
||||
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
|
||||
) {
|
||||
exists(OldIR::IRTempVariable var |
|
||||
var.getEnclosingFunction() = func and
|
||||
var.getAST() = ast and
|
||||
var.getTag() = tag and
|
||||
var.getLanguageType() = type
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasModeledMemoryResult(Instruction instruction) {
|
||||
exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or
|
||||
@@ -73,7 +72,7 @@ private module Cached {
|
||||
or
|
||||
// Chi instructions track virtual variables, and therefore a chi instruction is
|
||||
// conflated if it's associated with the aliased virtual variable.
|
||||
exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) |
|
||||
exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) |
|
||||
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
|
||||
Alias::AliasedVirtualVariable
|
||||
)
|
||||
@@ -81,7 +80,7 @@ private module Cached {
|
||||
// Phi instructions track locations, and therefore a phi instruction is
|
||||
// conflated if it's associated with a conflated location.
|
||||
exists(Alias::MemoryLocation location |
|
||||
instruction = Phi(_, location) and
|
||||
instruction = getPhi(_, location) and
|
||||
not exists(location.getAllocation())
|
||||
)
|
||||
}
|
||||
@@ -128,7 +127,7 @@ private module Cached {
|
||||
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
|
||||
)
|
||||
or
|
||||
instruction = Chi(getOldInstruction(result)) and
|
||||
instruction = getChi(getOldInstruction(result)) and
|
||||
tag instanceof ChiPartialOperandTag and
|
||||
overlap instanceof MustExactlyOverlap
|
||||
or
|
||||
@@ -172,13 +171,15 @@ private module Cached {
|
||||
|
||||
pragma[noopt]
|
||||
cached
|
||||
Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) {
|
||||
Instruction getPhiOperandDefinition(
|
||||
PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap
|
||||
) {
|
||||
exists(
|
||||
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
|
||||
OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation
|
||||
|
|
||||
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and
|
||||
instr = Phi(phiBlock, useLocation) and
|
||||
instr = getPhi(phiBlock, useLocation) and
|
||||
newPredecessorBlock = getNewBlock(predBlock) and
|
||||
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
|
||||
overlap = Alias::getOverlap(actualDefLocation, useLocation)
|
||||
@@ -191,7 +192,7 @@ private module Cached {
|
||||
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
|
||||
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
|
||||
|
|
||||
chiInstr = Chi(oldInstr) and
|
||||
chiInstr = getChi(oldInstr) and
|
||||
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
|
||||
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
|
||||
@@ -203,21 +204,11 @@ private module Cached {
|
||||
cached
|
||||
Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
||||
exists(OldBlock oldBlock |
|
||||
instr = Phi(oldBlock, _) and
|
||||
instr = getPhi(oldBlock, _) and
|
||||
result = getNewInstruction(oldBlock.getFirstInstruction())
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Language::Expr getInstructionConvertedResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getConvertedResultExpression()
|
||||
}
|
||||
|
||||
cached
|
||||
Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getUnconvertedResultExpression()
|
||||
}
|
||||
|
||||
/*
|
||||
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
|
||||
* that node is its successor in the new successor relation, and the Chi node's successors are
|
||||
@@ -228,20 +219,20 @@ private module Cached {
|
||||
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
if hasChiNode(_, getOldInstruction(instruction))
|
||||
then
|
||||
result = Chi(getOldInstruction(instruction)) and
|
||||
result = getChi(getOldInstruction(instruction)) and
|
||||
kind instanceof GotoEdge
|
||||
else (
|
||||
exists(OldInstruction oldInstruction |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
(
|
||||
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
|
||||
then result = Unreached(instruction.getEnclosingFunction())
|
||||
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
|
||||
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = Chi(oldInstruction) and
|
||||
instruction = getChi(oldInstruction) and
|
||||
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||
)
|
||||
)
|
||||
@@ -260,137 +251,73 @@ private module Cached {
|
||||
// `oldInstruction`, in which case the back edge should come out of the
|
||||
// chi node instead.
|
||||
if hasChiNode(_, oldInstruction)
|
||||
then instruction = Chi(oldInstruction)
|
||||
then instruction = getChi(oldInstruction)
|
||||
else instruction = getNewInstruction(oldInstruction)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Language::AST getInstructionAST(Instruction instruction) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = WrappedInstruction(oldInstruction)
|
||||
or
|
||||
instruction = Chi(oldInstruction)
|
||||
|
|
||||
result = oldInstruction.getAST()
|
||||
Language::AST getInstructionAST(Instruction instr) {
|
||||
result = getOldInstruction(instr).getAST()
|
||||
or
|
||||
exists(RawIR::Instruction blockStartInstr |
|
||||
instr = phiInstruction(blockStartInstr, _) and
|
||||
result = blockStartInstr.getAST()
|
||||
)
|
||||
or
|
||||
exists(OldBlock block |
|
||||
instruction = Phi(block, _) and
|
||||
result = block.getFirstInstruction().getAST()
|
||||
exists(RawIR::Instruction primaryInstr |
|
||||
instr = chiInstruction(primaryInstr) and
|
||||
result = primaryInstr.getAST()
|
||||
)
|
||||
or
|
||||
instruction = Unreached(result)
|
||||
exists(IRFunctionBase irFunc |
|
||||
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction()
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Language::LanguageType getInstructionResultType(Instruction instruction) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = WrappedInstruction(oldInstruction) and
|
||||
result = oldInstruction.getResultLanguageType()
|
||||
Language::LanguageType getInstructionResultType(Instruction instr) {
|
||||
result = instr.(RawIR::Instruction).getResultLanguageType()
|
||||
or
|
||||
exists(Alias::MemoryLocation defLocation |
|
||||
instr = phiInstruction(_, defLocation) and
|
||||
result = defLocation.getType()
|
||||
)
|
||||
or
|
||||
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
|
||||
instruction = Chi(oldInstruction) and
|
||||
hasChiNode(vvar, oldInstruction) and
|
||||
exists(Instruction primaryInstr, Alias::VirtualVariable vvar |
|
||||
instr = chiInstruction(primaryInstr) and
|
||||
hasChiNode(vvar, primaryInstr) and
|
||||
result = vvar.getType()
|
||||
)
|
||||
or
|
||||
exists(Alias::MemoryLocation location |
|
||||
instruction = Phi(_, location) and
|
||||
result = location.getType()
|
||||
instr = unreachedInstruction(_) and result = Language::getVoidType()
|
||||
}
|
||||
|
||||
cached
|
||||
Opcode getInstructionOpcode(Instruction instr) {
|
||||
result = getOldInstruction(instr).getOpcode()
|
||||
or
|
||||
instr = phiInstruction(_, _) and result instanceof Opcode::Phi
|
||||
or
|
||||
instr = chiInstruction(_) and result instanceof Opcode::Chi
|
||||
or
|
||||
instr = unreachedInstruction(_) and result instanceof Opcode::Unreached
|
||||
}
|
||||
|
||||
cached
|
||||
IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) {
|
||||
result = getOldInstruction(instr).getEnclosingIRFunction()
|
||||
or
|
||||
exists(OldInstruction blockStartInstr |
|
||||
instr = phiInstruction(blockStartInstr, _) and
|
||||
result = blockStartInstr.getEnclosingIRFunction()
|
||||
)
|
||||
or
|
||||
instruction = Unreached(_) and
|
||||
result = Language::getVoidType()
|
||||
}
|
||||
|
||||
cached
|
||||
Opcode getInstructionOpcode(Instruction instruction) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = WrappedInstruction(oldInstruction) and
|
||||
result = oldInstruction.getOpcode()
|
||||
exists(OldInstruction primaryInstr |
|
||||
instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction()
|
||||
)
|
||||
or
|
||||
instruction instanceof Chi and
|
||||
result instanceof Opcode::Chi
|
||||
or
|
||||
instruction instanceof Phi and
|
||||
result instanceof Opcode::Phi
|
||||
or
|
||||
instruction instanceof Unreached and
|
||||
result instanceof Opcode::Unreached
|
||||
}
|
||||
|
||||
cached
|
||||
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = WrappedInstruction(oldInstruction)
|
||||
or
|
||||
instruction = Chi(oldInstruction)
|
||||
|
|
||||
result.getFunction() = oldInstruction.getEnclosingFunction()
|
||||
)
|
||||
or
|
||||
exists(OldBlock block |
|
||||
instruction = Phi(block, _) and
|
||||
result.getFunction() = block.getEnclosingFunction()
|
||||
)
|
||||
or
|
||||
instruction = Unreached(result.getFunction())
|
||||
}
|
||||
|
||||
cached
|
||||
IRVariable getInstructionVariable(Instruction instruction) {
|
||||
result =
|
||||
getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getIRVariable())
|
||||
}
|
||||
|
||||
cached
|
||||
Language::Field getInstructionField(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
|
||||
}
|
||||
|
||||
cached
|
||||
int getInstructionIndex(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex()
|
||||
}
|
||||
|
||||
cached
|
||||
Language::Function getInstructionFunction(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
|
||||
}
|
||||
|
||||
cached
|
||||
string getInstructionConstantValue(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
|
||||
}
|
||||
|
||||
cached
|
||||
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
|
||||
result =
|
||||
getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation()
|
||||
}
|
||||
|
||||
cached
|
||||
Language::LanguageType getInstructionExceptionType(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
|
||||
}
|
||||
|
||||
cached
|
||||
int getInstructionElementSize(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize()
|
||||
}
|
||||
|
||||
cached
|
||||
predicate getInstructionInheritance(
|
||||
Instruction instruction, Language::Class baseClass, Language::Class derivedClass
|
||||
) {
|
||||
exists(OldIR::InheritanceConversionInstruction oldInstr |
|
||||
oldInstr = getOldInstruction(instruction) and
|
||||
baseClass = oldInstr.getBaseClass() and
|
||||
derivedClass = oldInstr.getDerivedClass()
|
||||
)
|
||||
instr = unreachedInstruction(result)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -401,7 +328,7 @@ private module Cached {
|
||||
)
|
||||
or
|
||||
exists(OldIR::Instruction oldInstruction |
|
||||
instruction = Chi(oldInstruction) and
|
||||
instruction = getChi(oldInstruction) and
|
||||
result = getNewInstruction(oldInstruction)
|
||||
)
|
||||
}
|
||||
@@ -409,6 +336,14 @@ private module Cached {
|
||||
|
||||
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
|
||||
|
||||
private OldInstruction getOldInstruction(Instruction instr) { instr = result }
|
||||
|
||||
private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) }
|
||||
|
||||
private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) {
|
||||
result = phiInstruction(defBlock.getFirstInstruction(), defLocation)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition
|
||||
* of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the
|
||||
@@ -588,7 +523,7 @@ module DefUse {
|
||||
|
|
||||
// An odd offset corresponds to the `Chi` instruction.
|
||||
defOffset = oldOffset * 2 + 1 and
|
||||
result = Chi(oldInstr) and
|
||||
result = getChi(oldInstr) and
|
||||
(
|
||||
defLocation = Alias::getResultMemoryLocation(oldInstr) or
|
||||
defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable()
|
||||
@@ -607,7 +542,7 @@ module DefUse {
|
||||
or
|
||||
defOffset = -1 and
|
||||
hasDefinition(_, defLocation, defBlock, defOffset) and
|
||||
result = Phi(defBlock, defLocation) and
|
||||
result = getPhi(defBlock, defLocation) and
|
||||
actualDefLocation = defLocation
|
||||
}
|
||||
|
||||
@@ -891,7 +826,7 @@ private module CachedForDebugging {
|
||||
)
|
||||
or
|
||||
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
|
||||
instr = Phi(phiBlock, location) and
|
||||
instr = getPhi(phiBlock, location) and
|
||||
result =
|
||||
"Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
|
||||
if location instanceof Alias::VirtualVariable
|
||||
@@ -901,7 +836,7 @@ private module CachedForDebugging {
|
||||
else specificity = "s"
|
||||
)
|
||||
or
|
||||
instr = Unreached(_) and
|
||||
instr = unreachedInstruction(_) and
|
||||
result = "Unreached"
|
||||
}
|
||||
|
||||
@@ -961,3 +896,19 @@ module SSAConsistency {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the portion of the parameterized IR interface that is used to construct the SSA stages
|
||||
* of the IR. The raw stage of the IR does not expose these predicates.
|
||||
* These predicates are all just aliases for predicates defined in the `Cached` module. This ensures
|
||||
* that all of SSA construction will be evaluated in the same stage.
|
||||
*/
|
||||
module SSA {
|
||||
class MemoryLocation = Alias::MemoryLocation;
|
||||
|
||||
predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2;
|
||||
|
||||
predicate hasChiInstruction = Cached::hasChiInstructionCached/1;
|
||||
|
||||
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import semmle.code.cpp.ir.implementation.Opcode
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
import semmle.code.cpp.ir.implementation.Opcode as Opcode
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||
import semmle.code.cpp.ir.internal.Overlap as Overlap
|
||||
import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction
|
||||
import semmle.code.cpp.ir.implementation.raw.IR as RawIR
|
||||
|
||||
@@ -2,5 +2,6 @@ import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as OldIR
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
|
||||
import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSSAInstructions as SSAInstructions
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import AliasedSSA as Alias
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Provides a base class, `IRFunctionBase`, for the stage-independent portions of `IRFunction`.
|
||||
*/
|
||||
|
||||
private import IRFunctionBaseInternal
|
||||
|
||||
private newtype TIRFunction =
|
||||
MkIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) }
|
||||
|
||||
/**
|
||||
* The IR for a function. This base class contains only the predicates that are the same between all
|
||||
* phases of the IR. Each instantiation of `IRFunction` extends this class.
|
||||
*/
|
||||
class IRFunctionBase extends TIRFunction {
|
||||
Language::Function func;
|
||||
|
||||
IRFunctionBase() { this = MkIRFunction(func) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = "IR: " + func.toString() }
|
||||
|
||||
/** Gets the function whose IR is represented. */
|
||||
final Language::Function getFunction() { result = func }
|
||||
|
||||
/** Gets the location of the function. */
|
||||
final Language::Location getLocation() { result = func.getLocation() }
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||
@@ -1,5 +1,5 @@
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as Construction
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Construction
|
||||
private import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag_
|
||||
|
||||
module Imports {
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
private import TInstructionInternal
|
||||
private import IRFunctionBase
|
||||
private import TInstructionImports as Imports
|
||||
private import Imports::IRType
|
||||
private import Imports::Opcode
|
||||
|
||||
/**
|
||||
* An IR instruction. `TInstruction` is shared across all phases of the IR. There are individual
|
||||
* branches of this type for instructions created directly from the AST (`TRawInstruction`) and for
|
||||
* instructions added by each stage of SSA construction (`T*PhiInstruction`, `T*ChiInstruction`,
|
||||
* `T*UnreachedInstruction`). Each stage then defines a `TStageInstruction` type that is a union of
|
||||
* all of the branches that can appear in that particular stage. The public `Instruction` class for
|
||||
* each phase extends the `TStageInstruction` type for that stage.
|
||||
*/
|
||||
cached
|
||||
newtype TInstruction =
|
||||
TRawInstruction(
|
||||
IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2
|
||||
) {
|
||||
IRConstruction::Raw::hasInstruction(tag1, tag2)
|
||||
} or
|
||||
TUnaliasedSSAPhiInstruction(
|
||||
TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation
|
||||
) {
|
||||
UnaliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
||||
} or
|
||||
TUnaliasedSSAChiInstruction(TRawInstruction primaryInstruction) { none() } or
|
||||
TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) {
|
||||
UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc)
|
||||
} or
|
||||
TAliasedSSAPhiInstruction(
|
||||
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
|
||||
) {
|
||||
AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
||||
} or
|
||||
TAliasedSSAChiInstruction(TRawInstruction primaryInstruction) {
|
||||
AliasedSSA::SSA::hasChiInstruction(primaryInstruction)
|
||||
} or
|
||||
TAliasedSSAUnreachedInstruction(IRFunctionBase irFunc) {
|
||||
AliasedSSA::SSA::hasUnreachedInstruction(irFunc)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides wrappers for the constructors of each branch of `TInstruction` that is used by the
|
||||
* unaliased SSA stage.
|
||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||
* a class alias.
|
||||
*/
|
||||
module UnaliasedSSAInstructions {
|
||||
class TPhiInstruction = TUnaliasedSSAPhiInstruction;
|
||||
|
||||
TPhiInstruction phiInstruction(
|
||||
TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation
|
||||
) {
|
||||
result = TUnaliasedSSAPhiInstruction(blockStartInstr, memoryLocation)
|
||||
}
|
||||
|
||||
class TChiInstruction = TUnaliasedSSAChiInstruction;
|
||||
|
||||
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
|
||||
result = TUnaliasedSSAChiInstruction(primaryInstruction)
|
||||
}
|
||||
|
||||
class TUnreachedInstruction = TUnaliasedSSAUnreachedInstruction;
|
||||
|
||||
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
|
||||
result = TUnaliasedSSAUnreachedInstruction(irFunc)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides wrappers for the constructors of each branch of `TInstruction` that is used by the
|
||||
* aliased SSA stage.
|
||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||
* a class alias.
|
||||
*/
|
||||
module AliasedSSAInstructions {
|
||||
class TPhiInstruction = TAliasedSSAPhiInstruction;
|
||||
|
||||
TPhiInstruction phiInstruction(
|
||||
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
|
||||
) {
|
||||
result = TAliasedSSAPhiInstruction(blockStartInstr, memoryLocation)
|
||||
}
|
||||
|
||||
class TChiInstruction = TAliasedSSAChiInstruction;
|
||||
|
||||
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
|
||||
result = TAliasedSSAChiInstruction(primaryInstruction)
|
||||
}
|
||||
|
||||
class TUnreachedInstruction = TAliasedSSAUnreachedInstruction;
|
||||
|
||||
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
|
||||
result = TAliasedSSAUnreachedInstruction(irFunc)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.implementation.Opcode as Opcode
|
||||
@@ -0,0 +1,4 @@
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSSA
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSSA
|
||||
@@ -1,29 +1,12 @@
|
||||
private import internal.IRInternal
|
||||
private import internal.IRFunctionImports as Imports
|
||||
import Imports::IRFunctionBase
|
||||
import Instruction
|
||||
|
||||
private newtype TIRFunction =
|
||||
MkIRFunction(Language::Function func) { Construction::functionHasIR(func) }
|
||||
|
||||
/**
|
||||
* Represents the IR for a function.
|
||||
* The IR for a function.
|
||||
*/
|
||||
class IRFunction extends TIRFunction {
|
||||
Language::Function func;
|
||||
|
||||
IRFunction() { this = MkIRFunction(func) }
|
||||
|
||||
final string toString() { result = "IR: " + func.toString() }
|
||||
|
||||
/**
|
||||
* Gets the function whose IR is represented.
|
||||
*/
|
||||
final Language::Function getFunction() { result = func }
|
||||
|
||||
/**
|
||||
* Gets the location of the function.
|
||||
*/
|
||||
final Language::Location getLocation() { result = func.getLocation() }
|
||||
|
||||
class IRFunction extends IRFunctionBase {
|
||||
/**
|
||||
* Gets the entry point for this function.
|
||||
*/
|
||||
|
||||
@@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
|
||||
/**
|
||||
* Represents a single operation in the IR.
|
||||
*/
|
||||
class Instruction extends Construction::TInstruction {
|
||||
class Instruction extends Construction::TStageInstruction {
|
||||
Instruction() {
|
||||
// The base `TStageInstruction` type is a superset of the actual instructions appearing in this
|
||||
// stage. This call lets the stage filter out the ones that are not reused from raw IR.
|
||||
Construction::hasInstruction(this)
|
||||
}
|
||||
|
||||
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
|
||||
|
||||
/**
|
||||
@@ -194,14 +200,14 @@ class Instruction extends Construction::TInstruction {
|
||||
* conversion.
|
||||
*/
|
||||
final Language::Expr getConvertedResultExpression() {
|
||||
result = Construction::getInstructionConvertedResultExpression(this)
|
||||
result = Raw::getInstructionConvertedResultExpression(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Language::Expr getUnconvertedResultExpression() {
|
||||
result = Construction::getInstructionUnconvertedResultExpression(this)
|
||||
result = Raw::getInstructionUnconvertedResultExpression(this)
|
||||
}
|
||||
|
||||
final Language::LanguageType getResultLanguageType() {
|
||||
@@ -212,6 +218,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* Gets the type of the result produced by this instruction. If the instruction does not produce
|
||||
* a result, its result type will be `IRVoidType`.
|
||||
*/
|
||||
cached
|
||||
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
|
||||
|
||||
/**
|
||||
@@ -250,7 +257,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* result of the `Load` instruction is a prvalue of type `int`, representing
|
||||
* the integer value loaded from variable `x`.
|
||||
*/
|
||||
final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
|
||||
final predicate isGLValue() { getResultLanguageType().hasType(_, true) }
|
||||
|
||||
/**
|
||||
* Gets the size of the result produced by this instruction, in bytes. If the
|
||||
@@ -259,7 +266,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* If `this.isGLValue()` holds for this instruction, the value of
|
||||
* `getResultSize()` will always be the size of a pointer.
|
||||
*/
|
||||
final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
|
||||
final int getResultSize() { result = getResultLanguageType().getByteSize() }
|
||||
|
||||
/**
|
||||
* Gets the opcode that specifies the operation performed by this instruction.
|
||||
@@ -395,7 +402,7 @@ class Instruction extends Construction::TInstruction {
|
||||
class VariableInstruction extends Instruction {
|
||||
IRVariable var;
|
||||
|
||||
VariableInstruction() { var = Construction::getInstructionVariable(this) }
|
||||
VariableInstruction() { var = Raw::getInstructionVariable(this) }
|
||||
|
||||
override string getImmediateString() { result = var.toString() }
|
||||
|
||||
@@ -410,7 +417,7 @@ class VariableInstruction extends Instruction {
|
||||
class FieldInstruction extends Instruction {
|
||||
Language::Field field;
|
||||
|
||||
FieldInstruction() { field = Construction::getInstructionField(this) }
|
||||
FieldInstruction() { field = Raw::getInstructionField(this) }
|
||||
|
||||
final override string getImmediateString() { result = field.toString() }
|
||||
|
||||
@@ -420,7 +427,7 @@ class FieldInstruction extends Instruction {
|
||||
class FunctionInstruction extends Instruction {
|
||||
Language::Function funcSymbol;
|
||||
|
||||
FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) }
|
||||
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
|
||||
|
||||
final override string getImmediateString() { result = funcSymbol.toString() }
|
||||
|
||||
@@ -430,7 +437,7 @@ class FunctionInstruction extends Instruction {
|
||||
class ConstantValueInstruction extends Instruction {
|
||||
string value;
|
||||
|
||||
ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) }
|
||||
ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) }
|
||||
|
||||
final override string getImmediateString() { result = value }
|
||||
|
||||
@@ -440,7 +447,7 @@ class ConstantValueInstruction extends Instruction {
|
||||
class IndexedInstruction extends Instruction {
|
||||
int index;
|
||||
|
||||
IndexedInstruction() { index = Construction::getInstructionIndex(this) }
|
||||
IndexedInstruction() { index = Raw::getInstructionIndex(this) }
|
||||
|
||||
final override string getImmediateString() { result = index.toString() }
|
||||
|
||||
@@ -603,11 +610,16 @@ class ConstantInstruction extends ConstantValueInstruction {
|
||||
}
|
||||
|
||||
class IntegerConstantInstruction extends ConstantInstruction {
|
||||
IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType }
|
||||
IntegerConstantInstruction() {
|
||||
exists(IRType resultType |
|
||||
resultType = getResultIRType() and
|
||||
(resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class FloatConstantInstruction extends ConstantInstruction {
|
||||
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
|
||||
FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType }
|
||||
}
|
||||
|
||||
class StringConstantInstruction extends VariableInstruction {
|
||||
@@ -704,7 +716,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
||||
|
||||
PointerArithmeticInstruction() {
|
||||
getOpcode() instanceof PointerArithmeticOpcode and
|
||||
elementSize = Construction::getInstructionElementSize(this)
|
||||
elementSize = Raw::getInstructionElementSize(this)
|
||||
}
|
||||
|
||||
final override string getImmediateString() { result = elementSize.toString() }
|
||||
@@ -753,7 +765,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
Language::Class derivedClass;
|
||||
|
||||
InheritanceConversionInstruction() {
|
||||
Construction::getInstructionInheritance(this, baseClass, derivedClass)
|
||||
Raw::getInstructionInheritance(this, baseClass, derivedClass)
|
||||
}
|
||||
|
||||
final override string getImmediateString() {
|
||||
@@ -1216,7 +1228,7 @@ class CatchByTypeInstruction extends CatchInstruction {
|
||||
|
||||
CatchByTypeInstruction() {
|
||||
getOpcode() instanceof Opcode::CatchByType and
|
||||
exceptionType = Construction::getInstructionExceptionType(this)
|
||||
exceptionType = Raw::getInstructionExceptionType(this)
|
||||
}
|
||||
|
||||
final override string getImmediateString() { result = exceptionType.toString() }
|
||||
@@ -1362,7 +1374,7 @@ class BuiltInOperationInstruction extends Instruction {
|
||||
|
||||
BuiltInOperationInstruction() {
|
||||
getOpcode() instanceof BuiltInOperationOpcode and
|
||||
operation = Construction::getInstructionBuiltInOperation(this)
|
||||
operation = Raw::getInstructionBuiltInOperation(this)
|
||||
}
|
||||
|
||||
final Language::BuiltInOperation getBuiltInOperation() { result = operation }
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
private import cpp
|
||||
import semmle.code.cpp.ir.implementation.raw.IR
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.implementation.internal.IRFunctionBase
|
||||
private import semmle.code.cpp.ir.implementation.internal.TInstruction
|
||||
private import semmle.code.cpp.ir.implementation.internal.TIRVariable
|
||||
private import semmle.code.cpp.ir.internal.CppType
|
||||
private import semmle.code.cpp.ir.internal.Overlap
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
@@ -12,34 +15,36 @@ private import TranslatedStmt
|
||||
private import TranslatedFunction
|
||||
|
||||
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
|
||||
instruction = MkInstruction(result, _)
|
||||
instruction = TRawInstruction(result, _)
|
||||
}
|
||||
|
||||
InstructionTag getInstructionTag(Instruction instruction) { instruction = MkInstruction(_, result) }
|
||||
|
||||
import Cached
|
||||
InstructionTag getInstructionTag(Instruction instruction) {
|
||||
instruction = TRawInstruction(_, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the portion of the parameterized IR interface that is used to construct the initial
|
||||
* "raw" stage of the IR. The other stages of the IR do not expose these predicates.
|
||||
*/
|
||||
cached
|
||||
private module Cached {
|
||||
module Raw {
|
||||
class InstructionTag1 = TranslatedElement;
|
||||
|
||||
class InstructionTag2 = InstructionTag;
|
||||
|
||||
cached
|
||||
predicate functionHasIR(Function func) { exists(getTranslatedFunction(func)) }
|
||||
|
||||
cached
|
||||
newtype TInstruction =
|
||||
MkInstruction(TranslatedElement element, InstructionTag tag) {
|
||||
element.hasInstruction(_, tag, _)
|
||||
}
|
||||
predicate hasInstruction(TranslatedElement element, InstructionTag tag) {
|
||||
element.hasInstruction(_, tag, _)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasUserVariable(Function func, Variable var, CppType type) {
|
||||
getTranslatedFunction(func).hasUserVariable(var, type)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasThisVariable(Function func, CppType type) {
|
||||
type = getTypeForGLValue(getTranslatedFunction(func).getThisType())
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, CppType type) {
|
||||
exists(TranslatedElement element |
|
||||
@@ -64,232 +69,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasModeledMemoryResult(Instruction instruction) { none() }
|
||||
|
||||
cached
|
||||
predicate hasConflatedMemoryResult(Instruction instruction) {
|
||||
instruction instanceof AliasedDefinitionInstruction
|
||||
or
|
||||
instruction.getOpcode() instanceof Opcode::InitializeNonLocal
|
||||
}
|
||||
|
||||
cached
|
||||
Expr getInstructionConvertedResultExpression(Instruction instruction) {
|
||||
exists(TranslatedExpr translatedExpr |
|
||||
translatedExpr = getTranslatedExpr(result) and
|
||||
instruction = translatedExpr.getResult() and
|
||||
// Only associate `instruction` with this expression if the translated
|
||||
// expression actually produced the instruction; not if it merely
|
||||
// forwarded the result of another translated expression.
|
||||
instruction = translatedExpr.getInstruction(_)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
result = getInstructionConvertedResultExpression(instruction).getUnconverted()
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction)
|
||||
.getInstructionRegisterOperand(getInstructionTag(instruction), tag)
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getMemoryOperandDefinition(
|
||||
Instruction instruction, MemoryOperandTag tag, Overlap overlap
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Gets a non-phi instruction that defines an operand of `instr`. */
|
||||
private Instruction getNonPhiOperandDef(Instruction instr) {
|
||||
result = getRegisterOperandDefinition(instr, _)
|
||||
or
|
||||
result = getMemoryOperandDefinition(instr, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a non-phi instruction that defines an operand of `instr` but only if
|
||||
* both `instr` and the result have neighbor on the other side of the edge
|
||||
* between them. This is a necessary condition for being in a cycle, and it
|
||||
* removes about two thirds of the tuples that would otherwise be in this
|
||||
* predicate.
|
||||
*/
|
||||
private Instruction getNonPhiOperandDefOfIntermediate(Instruction instr) {
|
||||
result = getNonPhiOperandDef(instr) and
|
||||
exists(getNonPhiOperandDef(result)) and
|
||||
instr = getNonPhiOperandDef(_)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
|
||||
* through a phi instruction and therefore should be impossible.
|
||||
*
|
||||
* If such cycles are present, either due to a programming error in the IR
|
||||
* generation or due to a malformed database, it can cause infinite loops in
|
||||
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
|
||||
* better to remove these operands than to leave cycles in the operand graph.
|
||||
*/
|
||||
pragma[noopt]
|
||||
cached
|
||||
predicate isInCycle(Instruction instr) {
|
||||
instr instanceof Instruction and
|
||||
getNonPhiOperandDefOfIntermediate+(instr) = instr
|
||||
}
|
||||
|
||||
cached
|
||||
CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) {
|
||||
// For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as
|
||||
// the result type of the load.
|
||||
tag instanceof LoadOperandTag and
|
||||
result = instruction.(LoadInstruction).getResultLanguageType()
|
||||
or
|
||||
not instruction instanceof LoadInstruction and
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction)
|
||||
.getInstructionMemoryOperandType(getInstructionTag(instruction), tag)
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getPhiOperandDefinition(
|
||||
PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() }
|
||||
|
||||
cached
|
||||
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction)
|
||||
.getInstructionSuccessor(getInstructionTag(instruction), kind)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the CFG edge (`sourceElement`, `sourceTag`) ---`kind`-->
|
||||
* `targetInstruction` is a back edge under the condition that
|
||||
* `requiredAncestor` is an ancestor of `sourceElement`.
|
||||
*/
|
||||
private predicate backEdgeCandidate(
|
||||
TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor,
|
||||
Instruction targetInstruction, EdgeKind kind
|
||||
) {
|
||||
// While loop:
|
||||
// Any edge from within the body of the loop to the condition of the loop
|
||||
// is a back edge. This includes edges from `continue` and the fall-through
|
||||
// edge(s) after the last instruction(s) in the body.
|
||||
exists(TranslatedWhileStmt s |
|
||||
targetInstruction = s.getFirstConditionInstruction() and
|
||||
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
|
||||
requiredAncestor = s.getBody()
|
||||
)
|
||||
or
|
||||
// Do-while loop:
|
||||
// The back edge should be the edge(s) from the condition to the
|
||||
// body. This ensures that it's the back edge that will be pruned in a `do
|
||||
// { ... } while (0)` statement. Note that all `continue` statements in a
|
||||
// do-while loop produce forward edges.
|
||||
exists(TranslatedDoStmt s |
|
||||
targetInstruction = s.getBody().getFirstInstruction() and
|
||||
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
|
||||
requiredAncestor = s.getCondition()
|
||||
)
|
||||
or
|
||||
// For loop:
|
||||
// Any edge from within the body or update of the loop to the condition of
|
||||
// the loop is a back edge. When there is no loop update expression, this
|
||||
// includes edges from `continue` and the fall-through edge(s) after the
|
||||
// last instruction(s) in the body. A for loop may not have a condition, in
|
||||
// which case `getFirstConditionInstruction` returns the body instead.
|
||||
exists(TranslatedForStmt s |
|
||||
targetInstruction = s.getFirstConditionInstruction() and
|
||||
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
|
||||
(
|
||||
requiredAncestor = s.getUpdate()
|
||||
or
|
||||
not exists(s.getUpdate()) and
|
||||
requiredAncestor = s.getBody()
|
||||
)
|
||||
)
|
||||
or
|
||||
// Range-based for loop:
|
||||
// Any edge from within the update of the loop to the condition of
|
||||
// the loop is a back edge.
|
||||
exists(TranslatedRangeBasedForStmt s |
|
||||
targetInstruction = s.getCondition().getFirstInstruction() and
|
||||
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
|
||||
requiredAncestor = s.getUpdate()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate jumpSourceHasAncestor(TranslatedElement jumpSource, TranslatedElement ancestor) {
|
||||
backEdgeCandidate(jumpSource, _, _, _, _) and
|
||||
ancestor = jumpSource
|
||||
or
|
||||
// For performance, we don't want a fastTC here
|
||||
jumpSourceHasAncestor(jumpSource, ancestor.getAChild())
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
exists(
|
||||
TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor
|
||||
|
|
||||
backEdgeCandidate(sourceElement, sourceTag, requiredAncestor, result, kind) and
|
||||
jumpSourceHasAncestor(sourceElement, requiredAncestor) and
|
||||
instruction = sourceElement.getInstruction(sourceTag)
|
||||
)
|
||||
or
|
||||
// Goto statement:
|
||||
// As a conservative approximation, any edge out of `goto` is a back edge
|
||||
// unless it goes strictly forward in the program text. A `goto` whose
|
||||
// source and target are both inside a macro will be seen as having the
|
||||
// same location for source and target, so we conservatively assume that
|
||||
// such a `goto` creates a back edge.
|
||||
exists(TranslatedElement s, GotoStmt goto |
|
||||
not isStrictlyForwardGoto(goto) and
|
||||
goto = s.getAST() and
|
||||
exists(InstructionTag tag |
|
||||
result = s.getInstructionSuccessor(tag, kind) and
|
||||
instruction = s.getInstruction(tag)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `goto` jumps strictly forward in the program text. */
|
||||
private predicate isStrictlyForwardGoto(GotoStmt goto) {
|
||||
goto.getLocation().isBefore(goto.getTarget().getLocation())
|
||||
}
|
||||
|
||||
cached
|
||||
Locatable getInstructionAST(Instruction instruction) {
|
||||
result = getInstructionTranslatedElement(instruction).getAST()
|
||||
}
|
||||
|
||||
cached
|
||||
CppType getInstructionResultType(Instruction instruction) {
|
||||
getInstructionTranslatedElement(instruction)
|
||||
.hasInstruction(_, getInstructionTag(instruction), result)
|
||||
}
|
||||
|
||||
cached
|
||||
Opcode getInstructionOpcode(Instruction instruction) {
|
||||
getInstructionTranslatedElement(instruction)
|
||||
.hasInstruction(result, getInstructionTag(instruction), _)
|
||||
}
|
||||
|
||||
cached
|
||||
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
|
||||
result.getFunction() = getInstructionTranslatedElement(instruction).getFunction()
|
||||
}
|
||||
|
||||
cached
|
||||
IRVariable getInstructionVariable(Instruction instruction) {
|
||||
TIRVariable getInstructionVariable(Instruction instruction) {
|
||||
exists(TranslatedElement element, InstructionTag tag |
|
||||
element = getInstructionTranslatedElement(instruction) and
|
||||
tag = getInstructionTag(instruction) and
|
||||
@@ -302,10 +82,9 @@ private module Cached {
|
||||
|
||||
cached
|
||||
Field getInstructionField(Instruction instruction) {
|
||||
exists(TranslatedElement element, InstructionTag tag |
|
||||
instructionOrigin(instruction, element, tag) and
|
||||
result = element.getInstructionField(tag)
|
||||
)
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction)
|
||||
.getInstructionField(getInstructionTag(instruction))
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -324,10 +103,9 @@ private module Cached {
|
||||
|
||||
cached
|
||||
int getInstructionIndex(Instruction instruction) {
|
||||
exists(TranslatedElement element, InstructionTag tag |
|
||||
instructionOrigin(instruction, element, tag) and
|
||||
result = element.getInstructionIndex(tag)
|
||||
)
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction)
|
||||
.getInstructionIndex(getInstructionTag(instruction))
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -350,20 +128,11 @@ private module Cached {
|
||||
.getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate instructionOrigin(
|
||||
Instruction instruction, TranslatedElement element, InstructionTag tag
|
||||
) {
|
||||
element = getInstructionTranslatedElement(instruction) and
|
||||
tag = getInstructionTag(instruction)
|
||||
}
|
||||
|
||||
cached
|
||||
int getInstructionElementSize(Instruction instruction) {
|
||||
exists(TranslatedElement element, InstructionTag tag |
|
||||
instructionOrigin(instruction, element, tag) and
|
||||
result = element.getInstructionElementSize(tag)
|
||||
)
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction)
|
||||
.getInstructionElementSize(getInstructionTag(instruction))
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -372,22 +141,225 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
int getInstructionResultSize(Instruction instruction) {
|
||||
exists(TranslatedElement element, InstructionTag tag |
|
||||
instructionOrigin(instruction, element, tag) and
|
||||
result = element.getInstructionResultSize(tag)
|
||||
Expr getInstructionConvertedResultExpression(Instruction instruction) {
|
||||
exists(TranslatedExpr translatedExpr |
|
||||
translatedExpr = getTranslatedExpr(result) and
|
||||
instruction = translatedExpr.getResult() and
|
||||
// Only associate `instruction` with this expression if the translated
|
||||
// expression actually produced the instruction; not if it merely
|
||||
// forwarded the result of another translated expression.
|
||||
instruction = translatedExpr.getInstruction(_)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getPrimaryInstructionForSideEffect(Instruction instruction) {
|
||||
exists(TranslatedElement element, InstructionTag tag |
|
||||
instructionOrigin(instruction, element, tag) and
|
||||
result = element.getPrimaryInstructionForSideEffect(tag)
|
||||
)
|
||||
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
result = getInstructionConvertedResultExpression(instruction).getUnconverted()
|
||||
}
|
||||
}
|
||||
|
||||
class TStageInstruction = TRawInstruction;
|
||||
|
||||
predicate hasInstruction(TRawInstruction instr) { any() }
|
||||
|
||||
predicate hasModeledMemoryResult(Instruction instruction) { none() }
|
||||
|
||||
predicate hasConflatedMemoryResult(Instruction instruction) {
|
||||
instruction instanceof AliasedDefinitionInstruction
|
||||
or
|
||||
instruction.getOpcode() instanceof Opcode::InitializeNonLocal
|
||||
}
|
||||
|
||||
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction)
|
||||
.getInstructionRegisterOperand(getInstructionTag(instruction), tag)
|
||||
}
|
||||
|
||||
Instruction getMemoryOperandDefinition(
|
||||
Instruction instruction, MemoryOperandTag tag, Overlap overlap
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Gets a non-phi instruction that defines an operand of `instr`. */
|
||||
private Instruction getNonPhiOperandDef(Instruction instr) {
|
||||
result = getRegisterOperandDefinition(instr, _)
|
||||
or
|
||||
result = getMemoryOperandDefinition(instr, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a non-phi instruction that defines an operand of `instr` but only if
|
||||
* both `instr` and the result have neighbor on the other side of the edge
|
||||
* between them. This is a necessary condition for being in a cycle, and it
|
||||
* removes about two thirds of the tuples that would otherwise be in this
|
||||
* predicate.
|
||||
*/
|
||||
private Instruction getNonPhiOperandDefOfIntermediate(Instruction instr) {
|
||||
result = getNonPhiOperandDef(instr) and
|
||||
exists(getNonPhiOperandDef(result)) and
|
||||
instr = getNonPhiOperandDef(_)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
|
||||
* through a phi instruction and therefore should be impossible.
|
||||
*
|
||||
* If such cycles are present, either due to a programming error in the IR
|
||||
* generation or due to a malformed database, it can cause infinite loops in
|
||||
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
|
||||
* better to remove these operands than to leave cycles in the operand graph.
|
||||
*/
|
||||
pragma[noopt]
|
||||
predicate isInCycle(Instruction instr) {
|
||||
instr instanceof Instruction and
|
||||
getNonPhiOperandDefOfIntermediate+(instr) = instr
|
||||
}
|
||||
|
||||
CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) {
|
||||
// For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as
|
||||
// the result type of the load.
|
||||
tag instanceof LoadOperandTag and
|
||||
result = instruction.(LoadInstruction).getResultLanguageType()
|
||||
or
|
||||
not instruction instanceof LoadInstruction and
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction)
|
||||
.getInstructionMemoryOperandType(getInstructionTag(instruction), tag)
|
||||
}
|
||||
|
||||
Instruction getPhiOperandDefinition(
|
||||
PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() }
|
||||
|
||||
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction)
|
||||
.getInstructionSuccessor(getInstructionTag(instruction), kind)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the CFG edge (`sourceElement`, `sourceTag`) ---`kind`-->
|
||||
* `targetInstruction` is a back edge under the condition that
|
||||
* `requiredAncestor` is an ancestor of `sourceElement`.
|
||||
*/
|
||||
private predicate backEdgeCandidate(
|
||||
TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor,
|
||||
Instruction targetInstruction, EdgeKind kind
|
||||
) {
|
||||
// While loop:
|
||||
// Any edge from within the body of the loop to the condition of the loop
|
||||
// is a back edge. This includes edges from `continue` and the fall-through
|
||||
// edge(s) after the last instruction(s) in the body.
|
||||
exists(TranslatedWhileStmt s |
|
||||
targetInstruction = s.getFirstConditionInstruction() and
|
||||
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
|
||||
requiredAncestor = s.getBody()
|
||||
)
|
||||
or
|
||||
// Do-while loop:
|
||||
// The back edge should be the edge(s) from the condition to the
|
||||
// body. This ensures that it's the back edge that will be pruned in a `do
|
||||
// { ... } while (0)` statement. Note that all `continue` statements in a
|
||||
// do-while loop produce forward edges.
|
||||
exists(TranslatedDoStmt s |
|
||||
targetInstruction = s.getBody().getFirstInstruction() and
|
||||
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
|
||||
requiredAncestor = s.getCondition()
|
||||
)
|
||||
or
|
||||
// For loop:
|
||||
// Any edge from within the body or update of the loop to the condition of
|
||||
// the loop is a back edge. When there is no loop update expression, this
|
||||
// includes edges from `continue` and the fall-through edge(s) after the
|
||||
// last instruction(s) in the body. A for loop may not have a condition, in
|
||||
// which case `getFirstConditionInstruction` returns the body instead.
|
||||
exists(TranslatedForStmt s |
|
||||
targetInstruction = s.getFirstConditionInstruction() and
|
||||
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
|
||||
(
|
||||
requiredAncestor = s.getUpdate()
|
||||
or
|
||||
not exists(s.getUpdate()) and
|
||||
requiredAncestor = s.getBody()
|
||||
)
|
||||
)
|
||||
or
|
||||
// Range-based for loop:
|
||||
// Any edge from within the update of the loop to the condition of
|
||||
// the loop is a back edge.
|
||||
exists(TranslatedRangeBasedForStmt s |
|
||||
targetInstruction = s.getCondition().getFirstInstruction() and
|
||||
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
|
||||
requiredAncestor = s.getUpdate()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate jumpSourceHasAncestor(TranslatedElement jumpSource, TranslatedElement ancestor) {
|
||||
backEdgeCandidate(jumpSource, _, _, _, _) and
|
||||
ancestor = jumpSource
|
||||
or
|
||||
// For performance, we don't want a fastTC here
|
||||
jumpSourceHasAncestor(jumpSource, ancestor.getAChild())
|
||||
}
|
||||
|
||||
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
exists(
|
||||
TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor
|
||||
|
|
||||
backEdgeCandidate(sourceElement, sourceTag, requiredAncestor, result, kind) and
|
||||
jumpSourceHasAncestor(sourceElement, requiredAncestor) and
|
||||
instruction = sourceElement.getInstruction(sourceTag)
|
||||
)
|
||||
or
|
||||
// Goto statement:
|
||||
// As a conservative approximation, any edge out of `goto` is a back edge
|
||||
// unless it goes strictly forward in the program text. A `goto` whose
|
||||
// source and target are both inside a macro will be seen as having the
|
||||
// same location for source and target, so we conservatively assume that
|
||||
// such a `goto` creates a back edge.
|
||||
exists(TranslatedElement s, GotoStmt goto |
|
||||
not isStrictlyForwardGoto(goto) and
|
||||
goto = s.getAST() and
|
||||
exists(InstructionTag tag |
|
||||
result = s.getInstructionSuccessor(tag, kind) and
|
||||
instruction = s.getInstruction(tag)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `goto` jumps strictly forward in the program text. */
|
||||
private predicate isStrictlyForwardGoto(GotoStmt goto) {
|
||||
goto.getLocation().isBefore(goto.getTarget().getLocation())
|
||||
}
|
||||
|
||||
Locatable getInstructionAST(TStageInstruction instr) {
|
||||
result = getInstructionTranslatedElement(instr).getAST()
|
||||
}
|
||||
|
||||
CppType getInstructionResultType(TStageInstruction instr) {
|
||||
getInstructionTranslatedElement(instr).hasInstruction(_, getInstructionTag(instr), result)
|
||||
}
|
||||
|
||||
Opcode getInstructionOpcode(TStageInstruction instr) {
|
||||
getInstructionTranslatedElement(instr).hasInstruction(result, getInstructionTag(instr), _)
|
||||
}
|
||||
|
||||
IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) {
|
||||
result.getFunction() = getInstructionTranslatedElement(instr).getFunction()
|
||||
}
|
||||
|
||||
Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction) {
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction)
|
||||
.getPrimaryInstructionForSideEffect(getInstructionTag(instruction))
|
||||
}
|
||||
|
||||
import CachedForDebugging
|
||||
|
||||
cached
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase
|
||||
@@ -1,3 +1,4 @@
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import IRConstruction as Construction
|
||||
import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration
|
||||
import IRConstruction::Raw as Raw
|
||||
|
||||
@@ -705,12 +705,8 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
int getInstructionElementSize(InstructionTag tag) { none() }
|
||||
|
||||
/**
|
||||
* If the instruction specified by `tag` has a result of type `UnknownType`,
|
||||
* gets the size of the result in bytes. If the result does not have a knonwn
|
||||
* constant size, this predicate does not hold.
|
||||
* Holds if the generated IR refers to an opaque type with size `byteSize`.
|
||||
*/
|
||||
int getInstructionResultSize(InstructionTag tag) { none() }
|
||||
|
||||
predicate needsUnknownOpaqueType(int byteSize) { none() }
|
||||
|
||||
/**
|
||||
|
||||
@@ -415,17 +415,6 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
|
||||
)
|
||||
}
|
||||
|
||||
override int getInstructionResultSize(InstructionTag tag) {
|
||||
exists(int elementCount |
|
||||
zeroInitRange(_, elementCount) and
|
||||
(
|
||||
tag = ZeroPadStringConstantTag() or
|
||||
tag = ZeroPadStringStoreTag()
|
||||
) and
|
||||
result = elementCount * getElementType().getSize()
|
||||
)
|
||||
}
|
||||
|
||||
private Type getElementType() {
|
||||
result = getContext().getTargetType().getUnspecifiedType().(ArrayType).getBaseType()
|
||||
}
|
||||
@@ -772,15 +761,6 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
|
||||
result = getZeroValue(getElementType())
|
||||
}
|
||||
|
||||
override int getInstructionResultSize(InstructionTag tag) {
|
||||
elementCount > 1 and
|
||||
(
|
||||
tag = getElementDefaultValueTag() or
|
||||
tag = getElementDefaultValueStoreTag()
|
||||
) and
|
||||
result = elementCount * getElementType().getSize()
|
||||
}
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
result = TranslatedElementInitialization.super.getInstructionRegisterOperand(tag, operandTag)
|
||||
or
|
||||
|
||||
@@ -1,29 +1,12 @@
|
||||
private import internal.IRInternal
|
||||
private import internal.IRFunctionImports as Imports
|
||||
import Imports::IRFunctionBase
|
||||
import Instruction
|
||||
|
||||
private newtype TIRFunction =
|
||||
MkIRFunction(Language::Function func) { Construction::functionHasIR(func) }
|
||||
|
||||
/**
|
||||
* Represents the IR for a function.
|
||||
* The IR for a function.
|
||||
*/
|
||||
class IRFunction extends TIRFunction {
|
||||
Language::Function func;
|
||||
|
||||
IRFunction() { this = MkIRFunction(func) }
|
||||
|
||||
final string toString() { result = "IR: " + func.toString() }
|
||||
|
||||
/**
|
||||
* Gets the function whose IR is represented.
|
||||
*/
|
||||
final Language::Function getFunction() { result = func }
|
||||
|
||||
/**
|
||||
* Gets the location of the function.
|
||||
*/
|
||||
final Language::Location getLocation() { result = func.getLocation() }
|
||||
|
||||
class IRFunction extends IRFunctionBase {
|
||||
/**
|
||||
* Gets the entry point for this function.
|
||||
*/
|
||||
|
||||
@@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
|
||||
/**
|
||||
* Represents a single operation in the IR.
|
||||
*/
|
||||
class Instruction extends Construction::TInstruction {
|
||||
class Instruction extends Construction::TStageInstruction {
|
||||
Instruction() {
|
||||
// The base `TStageInstruction` type is a superset of the actual instructions appearing in this
|
||||
// stage. This call lets the stage filter out the ones that are not reused from raw IR.
|
||||
Construction::hasInstruction(this)
|
||||
}
|
||||
|
||||
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
|
||||
|
||||
/**
|
||||
@@ -194,14 +200,14 @@ class Instruction extends Construction::TInstruction {
|
||||
* conversion.
|
||||
*/
|
||||
final Language::Expr getConvertedResultExpression() {
|
||||
result = Construction::getInstructionConvertedResultExpression(this)
|
||||
result = Raw::getInstructionConvertedResultExpression(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Language::Expr getUnconvertedResultExpression() {
|
||||
result = Construction::getInstructionUnconvertedResultExpression(this)
|
||||
result = Raw::getInstructionUnconvertedResultExpression(this)
|
||||
}
|
||||
|
||||
final Language::LanguageType getResultLanguageType() {
|
||||
@@ -212,6 +218,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* Gets the type of the result produced by this instruction. If the instruction does not produce
|
||||
* a result, its result type will be `IRVoidType`.
|
||||
*/
|
||||
cached
|
||||
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
|
||||
|
||||
/**
|
||||
@@ -250,7 +257,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* result of the `Load` instruction is a prvalue of type `int`, representing
|
||||
* the integer value loaded from variable `x`.
|
||||
*/
|
||||
final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
|
||||
final predicate isGLValue() { getResultLanguageType().hasType(_, true) }
|
||||
|
||||
/**
|
||||
* Gets the size of the result produced by this instruction, in bytes. If the
|
||||
@@ -259,7 +266,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* If `this.isGLValue()` holds for this instruction, the value of
|
||||
* `getResultSize()` will always be the size of a pointer.
|
||||
*/
|
||||
final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
|
||||
final int getResultSize() { result = getResultLanguageType().getByteSize() }
|
||||
|
||||
/**
|
||||
* Gets the opcode that specifies the operation performed by this instruction.
|
||||
@@ -395,7 +402,7 @@ class Instruction extends Construction::TInstruction {
|
||||
class VariableInstruction extends Instruction {
|
||||
IRVariable var;
|
||||
|
||||
VariableInstruction() { var = Construction::getInstructionVariable(this) }
|
||||
VariableInstruction() { var = Raw::getInstructionVariable(this) }
|
||||
|
||||
override string getImmediateString() { result = var.toString() }
|
||||
|
||||
@@ -410,7 +417,7 @@ class VariableInstruction extends Instruction {
|
||||
class FieldInstruction extends Instruction {
|
||||
Language::Field field;
|
||||
|
||||
FieldInstruction() { field = Construction::getInstructionField(this) }
|
||||
FieldInstruction() { field = Raw::getInstructionField(this) }
|
||||
|
||||
final override string getImmediateString() { result = field.toString() }
|
||||
|
||||
@@ -420,7 +427,7 @@ class FieldInstruction extends Instruction {
|
||||
class FunctionInstruction extends Instruction {
|
||||
Language::Function funcSymbol;
|
||||
|
||||
FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) }
|
||||
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
|
||||
|
||||
final override string getImmediateString() { result = funcSymbol.toString() }
|
||||
|
||||
@@ -430,7 +437,7 @@ class FunctionInstruction extends Instruction {
|
||||
class ConstantValueInstruction extends Instruction {
|
||||
string value;
|
||||
|
||||
ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) }
|
||||
ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) }
|
||||
|
||||
final override string getImmediateString() { result = value }
|
||||
|
||||
@@ -440,7 +447,7 @@ class ConstantValueInstruction extends Instruction {
|
||||
class IndexedInstruction extends Instruction {
|
||||
int index;
|
||||
|
||||
IndexedInstruction() { index = Construction::getInstructionIndex(this) }
|
||||
IndexedInstruction() { index = Raw::getInstructionIndex(this) }
|
||||
|
||||
final override string getImmediateString() { result = index.toString() }
|
||||
|
||||
@@ -603,11 +610,16 @@ class ConstantInstruction extends ConstantValueInstruction {
|
||||
}
|
||||
|
||||
class IntegerConstantInstruction extends ConstantInstruction {
|
||||
IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType }
|
||||
IntegerConstantInstruction() {
|
||||
exists(IRType resultType |
|
||||
resultType = getResultIRType() and
|
||||
(resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class FloatConstantInstruction extends ConstantInstruction {
|
||||
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
|
||||
FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType }
|
||||
}
|
||||
|
||||
class StringConstantInstruction extends VariableInstruction {
|
||||
@@ -704,7 +716,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
||||
|
||||
PointerArithmeticInstruction() {
|
||||
getOpcode() instanceof PointerArithmeticOpcode and
|
||||
elementSize = Construction::getInstructionElementSize(this)
|
||||
elementSize = Raw::getInstructionElementSize(this)
|
||||
}
|
||||
|
||||
final override string getImmediateString() { result = elementSize.toString() }
|
||||
@@ -753,7 +765,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
Language::Class derivedClass;
|
||||
|
||||
InheritanceConversionInstruction() {
|
||||
Construction::getInstructionInheritance(this, baseClass, derivedClass)
|
||||
Raw::getInstructionInheritance(this, baseClass, derivedClass)
|
||||
}
|
||||
|
||||
final override string getImmediateString() {
|
||||
@@ -1216,7 +1228,7 @@ class CatchByTypeInstruction extends CatchInstruction {
|
||||
|
||||
CatchByTypeInstruction() {
|
||||
getOpcode() instanceof Opcode::CatchByType and
|
||||
exceptionType = Construction::getInstructionExceptionType(this)
|
||||
exceptionType = Raw::getInstructionExceptionType(this)
|
||||
}
|
||||
|
||||
final override string getImmediateString() { result = exceptionType.toString() }
|
||||
@@ -1362,7 +1374,7 @@ class BuiltInOperationInstruction extends Instruction {
|
||||
|
||||
BuiltInOperationInstruction() {
|
||||
getOpcode() instanceof BuiltInOperationOpcode and
|
||||
operation = Construction::getInstructionBuiltInOperation(this)
|
||||
operation = Raw::getInstructionBuiltInOperation(this)
|
||||
}
|
||||
|
||||
final Language::BuiltInOperation getBuiltInOperation() { result = operation }
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase
|
||||
@@ -1,3 +1,4 @@
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import SSAConstruction as Construction
|
||||
import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import SSAConstructionInternal
|
||||
private import SSAConstructionImports
|
||||
private import SSAConstructionImports as Imports
|
||||
private import Imports::Opcode
|
||||
private import Imports::OperandTag
|
||||
private import Imports::Overlap
|
||||
private import Imports::TInstruction
|
||||
private import Imports::RawIR as RawIR
|
||||
private import SSAInstructions
|
||||
private import NewIR
|
||||
|
||||
private class OldBlock = Reachability::ReachableBlock;
|
||||
@@ -10,54 +16,47 @@ import Cached
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
predicate hasPhiInstructionCached(
|
||||
OldInstruction blockStartInstr, Alias::MemoryLocation defLocation
|
||||
) {
|
||||
exists(OldBlock oldBlock |
|
||||
definitionHasPhiNode(defLocation, oldBlock) and
|
||||
blockStartInstr = oldBlock.getFirstInstruction()
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasChiInstructionCached(OldInstruction primaryInstruction) {
|
||||
hasChiNode(_, primaryInstruction)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
irFunc = oldInstruction.getEnclosingIRFunction() and
|
||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||
)
|
||||
}
|
||||
|
||||
class TStageInstruction =
|
||||
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
|
||||
|
||||
cached
|
||||
predicate hasInstruction(TStageInstruction instr) {
|
||||
instr instanceof TRawInstruction and instr instanceof OldInstruction
|
||||
or
|
||||
instr instanceof TPhiInstruction
|
||||
or
|
||||
instr instanceof TChiInstruction
|
||||
or
|
||||
instr instanceof TUnreachedInstruction
|
||||
}
|
||||
|
||||
private IRBlock getNewBlock(OldBlock oldBlock) {
|
||||
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
||||
}
|
||||
|
||||
cached
|
||||
predicate functionHasIR(Language::Function func) {
|
||||
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
|
||||
}
|
||||
|
||||
cached
|
||||
OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) }
|
||||
|
||||
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
|
||||
// This is just a type cast. Both classes derive from the same newtype.
|
||||
result = var
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TInstruction =
|
||||
WrappedInstruction(OldInstruction oldInstruction) {
|
||||
not oldInstruction instanceof OldIR::PhiInstruction
|
||||
} or
|
||||
Phi(OldBlock block, Alias::MemoryLocation defLocation) {
|
||||
definitionHasPhiNode(defLocation, block)
|
||||
} or
|
||||
Chi(OldInstruction oldInstruction) {
|
||||
not oldInstruction instanceof OldIR::PhiInstruction and
|
||||
hasChiNode(_, oldInstruction)
|
||||
} or
|
||||
Unreached(Language::Function function) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
function = oldInstruction.getEnclosingFunction() and
|
||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasTempVariable(
|
||||
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
|
||||
) {
|
||||
exists(OldIR::IRTempVariable var |
|
||||
var.getEnclosingFunction() = func and
|
||||
var.getAST() = ast and
|
||||
var.getTag() = tag and
|
||||
var.getLanguageType() = type
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasModeledMemoryResult(Instruction instruction) {
|
||||
exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or
|
||||
@@ -73,7 +72,7 @@ private module Cached {
|
||||
or
|
||||
// Chi instructions track virtual variables, and therefore a chi instruction is
|
||||
// conflated if it's associated with the aliased virtual variable.
|
||||
exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) |
|
||||
exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) |
|
||||
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
|
||||
Alias::AliasedVirtualVariable
|
||||
)
|
||||
@@ -81,7 +80,7 @@ private module Cached {
|
||||
// Phi instructions track locations, and therefore a phi instruction is
|
||||
// conflated if it's associated with a conflated location.
|
||||
exists(Alias::MemoryLocation location |
|
||||
instruction = Phi(_, location) and
|
||||
instruction = getPhi(_, location) and
|
||||
not exists(location.getAllocation())
|
||||
)
|
||||
}
|
||||
@@ -128,7 +127,7 @@ private module Cached {
|
||||
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
|
||||
)
|
||||
or
|
||||
instruction = Chi(getOldInstruction(result)) and
|
||||
instruction = getChi(getOldInstruction(result)) and
|
||||
tag instanceof ChiPartialOperandTag and
|
||||
overlap instanceof MustExactlyOverlap
|
||||
or
|
||||
@@ -172,13 +171,15 @@ private module Cached {
|
||||
|
||||
pragma[noopt]
|
||||
cached
|
||||
Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) {
|
||||
Instruction getPhiOperandDefinition(
|
||||
PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap
|
||||
) {
|
||||
exists(
|
||||
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
|
||||
OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation
|
||||
|
|
||||
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and
|
||||
instr = Phi(phiBlock, useLocation) and
|
||||
instr = getPhi(phiBlock, useLocation) and
|
||||
newPredecessorBlock = getNewBlock(predBlock) and
|
||||
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
|
||||
overlap = Alias::getOverlap(actualDefLocation, useLocation)
|
||||
@@ -191,7 +192,7 @@ private module Cached {
|
||||
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
|
||||
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
|
||||
|
|
||||
chiInstr = Chi(oldInstr) and
|
||||
chiInstr = getChi(oldInstr) and
|
||||
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
|
||||
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
|
||||
@@ -203,21 +204,11 @@ private module Cached {
|
||||
cached
|
||||
Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
||||
exists(OldBlock oldBlock |
|
||||
instr = Phi(oldBlock, _) and
|
||||
instr = getPhi(oldBlock, _) and
|
||||
result = getNewInstruction(oldBlock.getFirstInstruction())
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Language::Expr getInstructionConvertedResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getConvertedResultExpression()
|
||||
}
|
||||
|
||||
cached
|
||||
Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getUnconvertedResultExpression()
|
||||
}
|
||||
|
||||
/*
|
||||
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
|
||||
* that node is its successor in the new successor relation, and the Chi node's successors are
|
||||
@@ -228,20 +219,20 @@ private module Cached {
|
||||
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
if hasChiNode(_, getOldInstruction(instruction))
|
||||
then
|
||||
result = Chi(getOldInstruction(instruction)) and
|
||||
result = getChi(getOldInstruction(instruction)) and
|
||||
kind instanceof GotoEdge
|
||||
else (
|
||||
exists(OldInstruction oldInstruction |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
(
|
||||
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
|
||||
then result = Unreached(instruction.getEnclosingFunction())
|
||||
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
|
||||
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = Chi(oldInstruction) and
|
||||
instruction = getChi(oldInstruction) and
|
||||
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||
)
|
||||
)
|
||||
@@ -260,137 +251,73 @@ private module Cached {
|
||||
// `oldInstruction`, in which case the back edge should come out of the
|
||||
// chi node instead.
|
||||
if hasChiNode(_, oldInstruction)
|
||||
then instruction = Chi(oldInstruction)
|
||||
then instruction = getChi(oldInstruction)
|
||||
else instruction = getNewInstruction(oldInstruction)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Language::AST getInstructionAST(Instruction instruction) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = WrappedInstruction(oldInstruction)
|
||||
or
|
||||
instruction = Chi(oldInstruction)
|
||||
|
|
||||
result = oldInstruction.getAST()
|
||||
Language::AST getInstructionAST(Instruction instr) {
|
||||
result = getOldInstruction(instr).getAST()
|
||||
or
|
||||
exists(RawIR::Instruction blockStartInstr |
|
||||
instr = phiInstruction(blockStartInstr, _) and
|
||||
result = blockStartInstr.getAST()
|
||||
)
|
||||
or
|
||||
exists(OldBlock block |
|
||||
instruction = Phi(block, _) and
|
||||
result = block.getFirstInstruction().getAST()
|
||||
exists(RawIR::Instruction primaryInstr |
|
||||
instr = chiInstruction(primaryInstr) and
|
||||
result = primaryInstr.getAST()
|
||||
)
|
||||
or
|
||||
instruction = Unreached(result)
|
||||
exists(IRFunctionBase irFunc |
|
||||
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction()
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Language::LanguageType getInstructionResultType(Instruction instruction) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = WrappedInstruction(oldInstruction) and
|
||||
result = oldInstruction.getResultLanguageType()
|
||||
Language::LanguageType getInstructionResultType(Instruction instr) {
|
||||
result = instr.(RawIR::Instruction).getResultLanguageType()
|
||||
or
|
||||
exists(Alias::MemoryLocation defLocation |
|
||||
instr = phiInstruction(_, defLocation) and
|
||||
result = defLocation.getType()
|
||||
)
|
||||
or
|
||||
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
|
||||
instruction = Chi(oldInstruction) and
|
||||
hasChiNode(vvar, oldInstruction) and
|
||||
exists(Instruction primaryInstr, Alias::VirtualVariable vvar |
|
||||
instr = chiInstruction(primaryInstr) and
|
||||
hasChiNode(vvar, primaryInstr) and
|
||||
result = vvar.getType()
|
||||
)
|
||||
or
|
||||
exists(Alias::MemoryLocation location |
|
||||
instruction = Phi(_, location) and
|
||||
result = location.getType()
|
||||
instr = unreachedInstruction(_) and result = Language::getVoidType()
|
||||
}
|
||||
|
||||
cached
|
||||
Opcode getInstructionOpcode(Instruction instr) {
|
||||
result = getOldInstruction(instr).getOpcode()
|
||||
or
|
||||
instr = phiInstruction(_, _) and result instanceof Opcode::Phi
|
||||
or
|
||||
instr = chiInstruction(_) and result instanceof Opcode::Chi
|
||||
or
|
||||
instr = unreachedInstruction(_) and result instanceof Opcode::Unreached
|
||||
}
|
||||
|
||||
cached
|
||||
IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) {
|
||||
result = getOldInstruction(instr).getEnclosingIRFunction()
|
||||
or
|
||||
exists(OldInstruction blockStartInstr |
|
||||
instr = phiInstruction(blockStartInstr, _) and
|
||||
result = blockStartInstr.getEnclosingIRFunction()
|
||||
)
|
||||
or
|
||||
instruction = Unreached(_) and
|
||||
result = Language::getVoidType()
|
||||
}
|
||||
|
||||
cached
|
||||
Opcode getInstructionOpcode(Instruction instruction) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = WrappedInstruction(oldInstruction) and
|
||||
result = oldInstruction.getOpcode()
|
||||
exists(OldInstruction primaryInstr |
|
||||
instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction()
|
||||
)
|
||||
or
|
||||
instruction instanceof Chi and
|
||||
result instanceof Opcode::Chi
|
||||
or
|
||||
instruction instanceof Phi and
|
||||
result instanceof Opcode::Phi
|
||||
or
|
||||
instruction instanceof Unreached and
|
||||
result instanceof Opcode::Unreached
|
||||
}
|
||||
|
||||
cached
|
||||
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = WrappedInstruction(oldInstruction)
|
||||
or
|
||||
instruction = Chi(oldInstruction)
|
||||
|
|
||||
result.getFunction() = oldInstruction.getEnclosingFunction()
|
||||
)
|
||||
or
|
||||
exists(OldBlock block |
|
||||
instruction = Phi(block, _) and
|
||||
result.getFunction() = block.getEnclosingFunction()
|
||||
)
|
||||
or
|
||||
instruction = Unreached(result.getFunction())
|
||||
}
|
||||
|
||||
cached
|
||||
IRVariable getInstructionVariable(Instruction instruction) {
|
||||
result =
|
||||
getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getIRVariable())
|
||||
}
|
||||
|
||||
cached
|
||||
Language::Field getInstructionField(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
|
||||
}
|
||||
|
||||
cached
|
||||
int getInstructionIndex(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex()
|
||||
}
|
||||
|
||||
cached
|
||||
Language::Function getInstructionFunction(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
|
||||
}
|
||||
|
||||
cached
|
||||
string getInstructionConstantValue(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
|
||||
}
|
||||
|
||||
cached
|
||||
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
|
||||
result =
|
||||
getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation()
|
||||
}
|
||||
|
||||
cached
|
||||
Language::LanguageType getInstructionExceptionType(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
|
||||
}
|
||||
|
||||
cached
|
||||
int getInstructionElementSize(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize()
|
||||
}
|
||||
|
||||
cached
|
||||
predicate getInstructionInheritance(
|
||||
Instruction instruction, Language::Class baseClass, Language::Class derivedClass
|
||||
) {
|
||||
exists(OldIR::InheritanceConversionInstruction oldInstr |
|
||||
oldInstr = getOldInstruction(instruction) and
|
||||
baseClass = oldInstr.getBaseClass() and
|
||||
derivedClass = oldInstr.getDerivedClass()
|
||||
)
|
||||
instr = unreachedInstruction(result)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -401,7 +328,7 @@ private module Cached {
|
||||
)
|
||||
or
|
||||
exists(OldIR::Instruction oldInstruction |
|
||||
instruction = Chi(oldInstruction) and
|
||||
instruction = getChi(oldInstruction) and
|
||||
result = getNewInstruction(oldInstruction)
|
||||
)
|
||||
}
|
||||
@@ -409,6 +336,14 @@ private module Cached {
|
||||
|
||||
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
|
||||
|
||||
private OldInstruction getOldInstruction(Instruction instr) { instr = result }
|
||||
|
||||
private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) }
|
||||
|
||||
private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) {
|
||||
result = phiInstruction(defBlock.getFirstInstruction(), defLocation)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition
|
||||
* of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the
|
||||
@@ -588,7 +523,7 @@ module DefUse {
|
||||
|
|
||||
// An odd offset corresponds to the `Chi` instruction.
|
||||
defOffset = oldOffset * 2 + 1 and
|
||||
result = Chi(oldInstr) and
|
||||
result = getChi(oldInstr) and
|
||||
(
|
||||
defLocation = Alias::getResultMemoryLocation(oldInstr) or
|
||||
defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable()
|
||||
@@ -607,7 +542,7 @@ module DefUse {
|
||||
or
|
||||
defOffset = -1 and
|
||||
hasDefinition(_, defLocation, defBlock, defOffset) and
|
||||
result = Phi(defBlock, defLocation) and
|
||||
result = getPhi(defBlock, defLocation) and
|
||||
actualDefLocation = defLocation
|
||||
}
|
||||
|
||||
@@ -891,7 +826,7 @@ private module CachedForDebugging {
|
||||
)
|
||||
or
|
||||
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
|
||||
instr = Phi(phiBlock, location) and
|
||||
instr = getPhi(phiBlock, location) and
|
||||
result =
|
||||
"Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
|
||||
if location instanceof Alias::VirtualVariable
|
||||
@@ -901,7 +836,7 @@ private module CachedForDebugging {
|
||||
else specificity = "s"
|
||||
)
|
||||
or
|
||||
instr = Unreached(_) and
|
||||
instr = unreachedInstruction(_) and
|
||||
result = "Unreached"
|
||||
}
|
||||
|
||||
@@ -961,3 +896,19 @@ module SSAConsistency {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the portion of the parameterized IR interface that is used to construct the SSA stages
|
||||
* of the IR. The raw stage of the IR does not expose these predicates.
|
||||
* These predicates are all just aliases for predicates defined in the `Cached` module. This ensures
|
||||
* that all of SSA construction will be evaluated in the same stage.
|
||||
*/
|
||||
module SSA {
|
||||
class MemoryLocation = Alias::MemoryLocation;
|
||||
|
||||
predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2;
|
||||
|
||||
predicate hasChiInstruction = Cached::hasChiInstructionCached/1;
|
||||
|
||||
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import semmle.code.cpp.ir.implementation.Opcode
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
import semmle.code.cpp.ir.implementation.Opcode as Opcode
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||
import semmle.code.cpp.ir.internal.Overlap as Overlap
|
||||
import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction
|
||||
import semmle.code.cpp.ir.implementation.raw.IR as RawIR
|
||||
|
||||
@@ -2,5 +2,7 @@ import semmle.code.cpp.ir.implementation.raw.IR as OldIR
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawStage
|
||||
import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import SimpleSSA as Alias
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.Print
|
||||
private import semmle.code.cpp.ir.implementation.IRType
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw
|
||||
|
||||
private int getPointerSize() { result = max(any(NullPointerType t).getSize()) }
|
||||
|
||||
@@ -143,7 +143,7 @@ private predicate isOpaqueType(Type type) {
|
||||
predicate hasOpaqueType(Type tag, int byteSize) {
|
||||
isOpaqueType(tag) and byteSize = getTypeSize(tag)
|
||||
or
|
||||
tag instanceof UnknownType and IRConstruction::needsUnknownOpaqueType(byteSize)
|
||||
tag instanceof UnknownType and Raw::needsUnknownOpaqueType(byteSize)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,7 +191,7 @@ private newtype TCppType =
|
||||
TPRValueType(Type type) { exists(getIRTypeForPRValue(type)) } or
|
||||
TFunctionGLValueType() or
|
||||
TGLValueAddressType(Type type) or
|
||||
TUnknownOpaqueType(int byteSize) { IRConstruction::needsUnknownOpaqueType(byteSize) } or
|
||||
TUnknownOpaqueType(int byteSize) { Raw::needsUnknownOpaqueType(byteSize) } or
|
||||
TUnknownType()
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,4 +48,17 @@ class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, Alias
|
||||
output.isParameterDeref(0) and
|
||||
description = "String read by " + this.getName()
|
||||
}
|
||||
|
||||
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
|
||||
not hasGlobalOrStdName("gets") and
|
||||
bufParam = 0 and
|
||||
countParam = 1
|
||||
}
|
||||
|
||||
override predicate hasArrayWithUnknownSize(int bufParam) {
|
||||
hasGlobalOrStdName("gets") and
|
||||
bufParam = 0
|
||||
}
|
||||
|
||||
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
|
||||
}
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/**
|
||||
* Provides implementation classes modelling various standard formatting
|
||||
* functions (`printf`, `snprintf` etc).
|
||||
* See `semmle.code.cpp.models.interfaces.FormattingFunction` for usage
|
||||
* information.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.FormattingFunction
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Provides implementation classes modelling `strcat` and various similar functions.
|
||||
* See `semmle.code.cpp.models.Models` for usage information.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||
import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
|
||||
@@ -19,5 +19,10 @@ import semmle.code.cpp.models.Models
|
||||
* to destinations; that is covered by `TaintModel.qll`.
|
||||
*/
|
||||
abstract class DataFlowFunction extends Function {
|
||||
/**
|
||||
* Holds if data can be copied from the argument, qualifier, or buffer
|
||||
* represented by `input` to the return value or buffer represented by
|
||||
* `output`
|
||||
*/
|
||||
abstract predicate hasDataFlow(FunctionInput input, FunctionOutput output);
|
||||
}
|
||||
|
||||
@@ -108,6 +108,20 @@ class FunctionInput extends TFunctionInput {
|
||||
predicate isQualifierAddress() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The input value of a parameter.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* void func(int n, char* p, float& r);
|
||||
* ```
|
||||
* - There is an `InParameter` representing the value of `n` (with type `int`) on entry to the
|
||||
* function.
|
||||
* - There is an `InParameter` representing the value of `p` (with type `char*`) on entry to the
|
||||
* function.
|
||||
* - There is an `InParameter` representing the "value" of the reference `r` (with type `float&`) on
|
||||
* entry to the function, _not_ the value of the referred-to `float`.
|
||||
*/
|
||||
class InParameter extends FunctionInput, TInParameter {
|
||||
ParameterIndex index;
|
||||
|
||||
@@ -121,6 +135,21 @@ class InParameter extends FunctionInput, TInParameter {
|
||||
override predicate isParameter(ParameterIndex i) { i = index }
|
||||
}
|
||||
|
||||
/**
|
||||
* The input value pointed to by a pointer parameter to a function, or the input value referred to
|
||||
* by a reference parameter to a function.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* void func(int n, char* p, float& r);
|
||||
* ```
|
||||
* - There is an `InParameterDeref` with `getIndex() = 1` that represents the value of `*p` (with
|
||||
* type `char`) on entry to the function.
|
||||
* - There is an `InParameterDeref` with `getIndex() = 2` that represents the value of `r` (with
|
||||
* type `float`) on entry to the function.
|
||||
* - There is no `InParameterDeref` representing the value of `n`, because `n` is neither a pointer
|
||||
* nor a reference.
|
||||
*/
|
||||
class InParameterDeref extends FunctionInput, TInParameterDeref {
|
||||
ParameterIndex index;
|
||||
|
||||
@@ -134,12 +163,36 @@ class InParameterDeref extends FunctionInput, TInParameterDeref {
|
||||
override predicate isParameterDeref(ParameterIndex i) { i = index }
|
||||
}
|
||||
|
||||
/**
|
||||
* The input value pointed to by the `this` pointer of an instance member function.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* struct C {
|
||||
* void mfunc(int n, char* p, float& r) const;
|
||||
* };
|
||||
* ```
|
||||
* - `InQualifierObject` represents the value of `*this` (with type `C const`) on entry to the
|
||||
* function.
|
||||
*/
|
||||
class InQualifierObject extends FunctionInput, TInQualifierObject {
|
||||
override string toString() { result = "InQualifierObject" }
|
||||
|
||||
override predicate isQualifierObject() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The input value of the `this` pointer of an instance member function.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* struct C {
|
||||
* void mfunc(int n, char* p, float& r) const;
|
||||
* };
|
||||
* ```
|
||||
* - `InQualifierAddress` represents the value of `this` (with type `C const *`) on entry to the
|
||||
* function.
|
||||
*/
|
||||
class InQualifierAddress extends FunctionInput, TInQualifierAddress {
|
||||
override string toString() { result = "InQualifierAddress" }
|
||||
|
||||
@@ -265,6 +318,21 @@ class FunctionOutput extends TFunctionOutput {
|
||||
deprecated final predicate isOutReturnPointer() { isReturnValueDeref() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The output value pointed to by a pointer parameter to a function, or the output value referred to
|
||||
* by a reference parameter to a function.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* void func(int n, char* p, float& r);
|
||||
* ```
|
||||
* - There is an `OutParameterDeref` with `getIndex()=1` that represents the value of `*p` (with
|
||||
* type `char`) on return from the function.
|
||||
* - There is an `OutParameterDeref` with `getIndex()=2` that represents the value of `r` (with
|
||||
* type `float`) on return from the function.
|
||||
* - There is no `OutParameterDeref` representing the value of `n`, because `n` is neither a
|
||||
* pointer nor a reference.
|
||||
*/
|
||||
class OutParameterDeref extends FunctionOutput, TOutParameterDeref {
|
||||
ParameterIndex index;
|
||||
|
||||
@@ -277,18 +345,62 @@ class OutParameterDeref extends FunctionOutput, TOutParameterDeref {
|
||||
override predicate isParameterDeref(ParameterIndex i) { i = index }
|
||||
}
|
||||
|
||||
/**
|
||||
* The output value pointed to by the `this` pointer of an instance member function.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* struct C {
|
||||
* void mfunc(int n, char* p, float& r);
|
||||
* };
|
||||
* ```
|
||||
* - The `OutQualifierObject` represents the value of `*this` (with type `C`) on return from the
|
||||
* function.
|
||||
*/
|
||||
class OutQualifierObject extends FunctionOutput, TOutQualifierObject {
|
||||
override string toString() { result = "OutQualifierObject" }
|
||||
|
||||
override predicate isQualifierObject() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The value returned by a function.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* int getInt();
|
||||
* char* getPointer();
|
||||
* float& getReference();
|
||||
* ```
|
||||
* - `OutReturnValue` represents the value returned by
|
||||
* `getInt()` (with type `int`).
|
||||
* - `OutReturnValue` represents the value returned by
|
||||
* `getPointer()` (with type `char*`).
|
||||
* - `OutReturnValue` represents the "value" of the reference returned by `getReference()` (with
|
||||
* type `float&`), _not_ the value of the referred-to `float`.
|
||||
*/
|
||||
class OutReturnValue extends FunctionOutput, TOutReturnValue {
|
||||
override string toString() { result = "OutReturnValue" }
|
||||
|
||||
override predicate isReturnValue() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The output value pointed to by the return value of a function, if the function returns a pointer,
|
||||
* or the output value referred to by the return value of a function, if the function returns a
|
||||
* reference.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* char* getPointer();
|
||||
* float& getReference();
|
||||
* int getInt();
|
||||
* ```
|
||||
* - `OutReturnValueDeref` represents the value of `*getPointer()` (with type `char`).
|
||||
* - `OutReturnValueDeref` represents the value of `getReference()` (with type `float`).
|
||||
* - `OutReturnValueDeref` does not represent the return value of `getInt()` because the return type
|
||||
* of `getInt()` is neither a pointer nor a reference.
|
||||
*/
|
||||
class OutReturnValueDeref extends FunctionOutput, TOutReturnValueDeref {
|
||||
override string toString() { result = "OutReturnValueDeref" }
|
||||
|
||||
|
||||
@@ -24,5 +24,9 @@ import semmle.code.cpp.models.Models
|
||||
* data flow.
|
||||
*/
|
||||
abstract class TaintFunction extends Function {
|
||||
/**
|
||||
* Holds if data passed into the argument, qualifier, or buffer represented by
|
||||
* `input` influences the return value or buffer represented by `output`
|
||||
*/
|
||||
abstract predicate hasTaintFlow(FunctionInput input, FunctionOutput output);
|
||||
}
|
||||
|
||||
@@ -146,6 +146,9 @@ class StrCopyBW extends BufferWriteCall {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the parameter that is the maximum size of the copy (in characters).
|
||||
*/
|
||||
int getParamSize() {
|
||||
exists(TopLevelFunction fn, string name |
|
||||
fn = getTarget() and
|
||||
@@ -161,6 +164,9 @@ class StrCopyBW extends BufferWriteCall {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the parameter that is the source of the copy.
|
||||
*/
|
||||
int getParamSrc() {
|
||||
exists(TopLevelFunction fn, string name |
|
||||
fn = getTarget() and
|
||||
@@ -194,8 +200,14 @@ class StrCopyBW extends BufferWriteCall {
|
||||
class StrCatBW extends BufferWriteCall {
|
||||
StrCatBW() { exists(TopLevelFunction fn | fn = getTarget() and fn instanceof StrcatFunction) }
|
||||
|
||||
/**
|
||||
* Gets the index of the parameter that is the maximum size of the copy (in characters).
|
||||
*/
|
||||
int getParamSize() { if exists(getArgument(2)) then result = 2 else none() }
|
||||
|
||||
/**
|
||||
* Gets the index of the parameter that is the source of the copy.
|
||||
*/
|
||||
int getParamSrc() { result = 1 }
|
||||
|
||||
override Type getBufferType() {
|
||||
@@ -349,6 +361,9 @@ class SnprintfBW extends BufferWriteCall {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the parameter that is the size of the destination (in characters).
|
||||
*/
|
||||
int getParamSize() { result = 1 }
|
||||
|
||||
override Type getBufferType() {
|
||||
@@ -399,6 +414,9 @@ class GetsBW extends BufferWriteCall {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the parameter that is the maximum number of characters to be read.
|
||||
*/
|
||||
int getParamSize() { if exists(getArgument(1)) then result = 1 else none() }
|
||||
|
||||
override Type getBufferType() { result = this.getTarget().getParameter(0).getUnspecifiedType() }
|
||||
@@ -434,6 +452,9 @@ class ScanfBW extends BufferWrite {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the parameter that is the first format argument.
|
||||
*/
|
||||
int getParamArgs() {
|
||||
exists(FunctionCall fc |
|
||||
this = fc.getArgument(_) and
|
||||
|
||||
@@ -2,21 +2,44 @@
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.security.FunctionWithWrappers
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/**
|
||||
* A function for running a command using a command interpreter.
|
||||
*/
|
||||
class SystemFunction extends FunctionWithWrappers {
|
||||
class SystemFunction extends FunctionWithWrappers, ArrayFunction, AliasFunction, SideEffectFunction {
|
||||
SystemFunction() {
|
||||
hasGlobalOrStdName("system") or
|
||||
hasGlobalName("popen") or
|
||||
hasGlobalOrStdName("system") or // system(command)
|
||||
hasGlobalName("popen") or // popen(command, mode)
|
||||
// Windows variants
|
||||
hasGlobalName("_popen") or
|
||||
hasGlobalName("_wpopen") or
|
||||
hasGlobalName("_wsystem")
|
||||
hasGlobalName("_popen") or // _popen(command, mode)
|
||||
hasGlobalName("_wpopen") or // _wpopen(command, mode)
|
||||
hasGlobalName("_wsystem") // _wsystem(command)
|
||||
}
|
||||
|
||||
override predicate interestingArg(int arg) { arg = 0 }
|
||||
|
||||
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 or bufParam = 1 }
|
||||
|
||||
override predicate hasArrayInput(int bufParam) { bufParam = 0 or bufParam = 1 }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = 0 or index = 1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate parameterIsAlwaysReturned(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() {
|
||||
hasGlobalOrStdName("system") or
|
||||
hasGlobalName("_wsystem")
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
(i = 0 or i = 1) and
|
||||
buffer = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
/**
|
||||
* Provides classes for modelling writing of data to files through various standard mechanisms such as `fprintf`, `fwrite` and `operator<<`.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* A function call that writes to a file
|
||||
* A function call that writes to a file.
|
||||
*/
|
||||
class FileWrite extends Expr {
|
||||
FileWrite() { fileWrite(this, _, _) }
|
||||
|
||||
/**
|
||||
* Gets a source expression of this write.
|
||||
*/
|
||||
Expr getASource() { fileWrite(this, result, _) }
|
||||
|
||||
/**
|
||||
* Gets the expression for the object being written to.
|
||||
*/
|
||||
Expr getDest() { fileWrite(this, _, result) }
|
||||
}
|
||||
|
||||
@@ -44,17 +54,17 @@ class BasicOStreamCall extends FunctionCall {
|
||||
*/
|
||||
abstract class ChainedOutputCall extends BasicOStreamCall {
|
||||
/**
|
||||
* The source expression of this output.
|
||||
* Gets the source expression of this output.
|
||||
*/
|
||||
abstract Expr getSource();
|
||||
|
||||
/**
|
||||
* The immediate destination expression of this output.
|
||||
* Gets the immediate destination expression of this output.
|
||||
*/
|
||||
abstract Expr getDest();
|
||||
|
||||
/**
|
||||
* The destination at the far left-hand end of the output chain.
|
||||
* Gets the destination at the far left-hand end of the output chain.
|
||||
*/
|
||||
Expr getEndDest() {
|
||||
// recurse into the destination
|
||||
@@ -108,7 +118,7 @@ class WriteFunctionCall extends ChainedOutputCall {
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the function call is a call to << that eventually starts at the given file stream.
|
||||
* Whether the function call is a call to `operator<<` or a similar function, that eventually starts at the given file stream.
|
||||
*/
|
||||
private predicate fileStreamChain(ChainedOutputCall out, Expr source, Expr dest) {
|
||||
source = out.getSource() and
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
/**
|
||||
* Provides classes for modelling output to standard output / standard error through various mechanisms such as `printf`, `puts` and `operator<<`.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import FileWrite
|
||||
|
||||
/**
|
||||
* A function call that writes to standard output or standard error
|
||||
* A function call that writes to standard output or standard error.
|
||||
*/
|
||||
class OutputWrite extends Expr {
|
||||
OutputWrite() { outputWrite(this, _) }
|
||||
|
||||
/**
|
||||
* Gets a source expression for this output.
|
||||
*/
|
||||
Expr getASource() { outputWrite(this, result) }
|
||||
}
|
||||
|
||||
@@ -49,7 +56,7 @@ private predicate outputFile(Expr e) {
|
||||
}
|
||||
|
||||
/**
|
||||
* is the function call a write to standard output or standard error from 'source'
|
||||
* Holds if the function call is a write to standard output or standard error from 'source'.
|
||||
*/
|
||||
private predicate outputWrite(Expr write, Expr source) {
|
||||
exists(Function f, int arg |
|
||||
|
||||
159
cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/stl.cpp
Normal file
159
cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/stl.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
typedef unsigned long size_t;
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<class charT> struct char_traits;
|
||||
|
||||
typedef size_t streamsize;
|
||||
|
||||
template <class T> class allocator {
|
||||
public:
|
||||
allocator() throw();
|
||||
};
|
||||
|
||||
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
|
||||
class basic_string {
|
||||
public:
|
||||
explicit basic_string(const Allocator& a = Allocator());
|
||||
basic_string(const charT* s, const Allocator& a = Allocator());
|
||||
|
||||
const charT* c_str() const;
|
||||
};
|
||||
|
||||
typedef basic_string<char> string;
|
||||
|
||||
template <class charT, class traits = char_traits<charT> >
|
||||
class basic_istream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
|
||||
public:
|
||||
basic_istream<charT,traits>& operator>>(int& n);
|
||||
};
|
||||
|
||||
template <class charT, class traits = char_traits<charT> >
|
||||
class basic_ostream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
|
||||
public:
|
||||
typedef charT char_type;
|
||||
basic_ostream<charT,traits>& write(const char_type* s, streamsize n);
|
||||
|
||||
basic_ostream<charT, traits>& operator<<(int n);
|
||||
};
|
||||
|
||||
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
|
||||
template<class charT, class traits, class Allocator> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const basic_string<charT, traits, Allocator>& str);
|
||||
|
||||
template<class charT, class traits = char_traits<charT>>
|
||||
class basic_iostream : public basic_istream<charT, traits>, public basic_ostream<charT, traits> {
|
||||
public:
|
||||
};
|
||||
|
||||
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>>
|
||||
class basic_stringstream : public basic_iostream<charT, traits> {
|
||||
public:
|
||||
explicit basic_stringstream(/*ios_base::openmode which = ios_base::out|ios_base::in - not needed for this test*/);
|
||||
|
||||
basic_string<charT, traits, Allocator> str() const;
|
||||
};
|
||||
|
||||
using stringstream = basic_stringstream<char>;
|
||||
}
|
||||
|
||||
char *source() { return getenv("USERDATA"); }
|
||||
void sink(const std::string &s) {};
|
||||
void sink(const std::stringstream &s) {};
|
||||
|
||||
void test_string()
|
||||
{
|
||||
char *a = source();
|
||||
std::string b("123");
|
||||
std::string c(source());
|
||||
|
||||
sink(a); // tainted
|
||||
sink(b);
|
||||
sink(c); // tainted [NOT DETECTED]
|
||||
sink(b.c_str());
|
||||
sink(c.c_str()); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test_stringstream()
|
||||
{
|
||||
std::stringstream ss1, ss2, ss3, ss4, ss5;
|
||||
std::string t(source());
|
||||
|
||||
ss1 << "1234";
|
||||
ss2 << source();
|
||||
ss3 << "123" << source();
|
||||
ss4 << source() << "456";
|
||||
ss5 << t;
|
||||
|
||||
sink(ss1);
|
||||
sink(ss2); // tainted [NOT DETECTED]
|
||||
sink(ss3); // tainted [NOT DETECTED]
|
||||
sink(ss4); // tainted [NOT DETECTED]
|
||||
sink(ss5); // tainted [NOT DETECTED]
|
||||
sink(ss1.str());
|
||||
sink(ss2.str()); // tainted [NOT DETECTED]
|
||||
sink(ss3.str()); // tainted [NOT DETECTED]
|
||||
sink(ss4.str()); // tainted [NOT DETECTED]
|
||||
sink(ss5.str()); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test_stringstream_int(int source)
|
||||
{
|
||||
std::stringstream ss1, ss2;
|
||||
|
||||
ss1 << 1234;
|
||||
ss2 << source;
|
||||
|
||||
sink(ss1);
|
||||
sink(ss2); // tainted [NOT DETECTED]
|
||||
sink(ss1.str());
|
||||
sink(ss2.str()); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
char *user_input() {
|
||||
return source();
|
||||
}
|
||||
|
||||
void sink(const char *filename, const char *mode);
|
||||
|
||||
void test_strings2()
|
||||
{
|
||||
string path1 = user_input();
|
||||
sink(path1.c_str(), "r"); // tainted [NOT DETECTED]
|
||||
|
||||
string path2;
|
||||
path2 = user_input();
|
||||
sink(path2.c_str(), "r"); // tainted
|
||||
|
||||
string path3(user_input());
|
||||
sink(path3.c_str(), "r"); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test_string3()
|
||||
{
|
||||
const char *cs = source();
|
||||
|
||||
// convert char * -> std::string
|
||||
std::string ss(cs);
|
||||
|
||||
sink(cs); // tainted
|
||||
sink(ss); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test_string4()
|
||||
{
|
||||
const char *cs = source();
|
||||
|
||||
// convert char * -> std::string
|
||||
std::string ss(cs);
|
||||
|
||||
// convert back std::string -> char *
|
||||
cs = ss.c_str();
|
||||
|
||||
sink(cs); // tainted [NOT DETECTED]
|
||||
sink(ss); // tainted [NOT DETECTED]
|
||||
}
|
||||
@@ -153,6 +153,50 @@
|
||||
| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:15:13:20 | call to getenv |
|
||||
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:16:15:16:21 | global2 |
|
||||
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:15:23:20 | call to getenv |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | shared.h:5:23:5:31 | sinkparam |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:21:29:21:29 | s |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:114:43:118 | p#1 |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:25:62:30 | call to getenv |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:8:68:8 | a |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:12:68:17 | call to source |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:21 | call to source |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:23 | (const char *)... |
|
||||
| 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:82:16:82:21 | call to source |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:23 | (const char *)... |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:9:85:14 | call to source |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:9:85:16 | (const char *)... |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:18:86:23 | call to source |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:18:86:25 | (const char *)... |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:14 | call to source |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp: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: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: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: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: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 |
|
||||
| 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 *)... |
|
||||
|
||||
@@ -31,6 +31,20 @@
|
||||
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:150:13:150:14 | & ... | IR only |
|
||||
| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:5:13:11 | global1 | AST only |
|
||||
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:5:23:11 | global2 | AST only |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:7:62:12 | source | AST only |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:24 | call to basic_string | IR only |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string | IR only |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... | IR only |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:117:7:117:16 | user_input | AST only |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string | IR only |
|
||||
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:128:9:128:13 | path2 | IR only |
|
||||
| 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: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:141:17:141:19 | call to basic_string | 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:157:7:157:8 | cs | AST 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 |
|
||||
|
||||
@@ -20,7 +20,7 @@ unreachableNodeCCtx
|
||||
localCallNodes
|
||||
postIsNotPre
|
||||
postHasUniquePre
|
||||
| simple.cpp:65:5:65:22 | i | PostUpdateNode should have one pre-update node but has 0. |
|
||||
| simple.cpp:65:5:65:22 | Store | PostUpdateNode should have one pre-update node but has 0. |
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | AST only |
|
||||
| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | AST only |
|
||||
| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | AST only |
|
||||
| complex.cpp:62:19:62:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | AST only |
|
||||
| complex.cpp:63:19:63:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | AST only |
|
||||
| complex.cpp:64:19:64:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | AST only |
|
||||
| complex.cpp:65:19:65:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | AST only |
|
||||
| qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:23:23:23:23 | a | AST only |
|
||||
| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:28:23:28:23 | a | AST only |
|
||||
| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:33:23:33:23 | a | AST only |
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
| complex.cpp:51:24:51:121 | // $ast=62:19 $f+:ast=63:19 $ast=64:19 $f+:ast=65:19 $ir=62:19 $f+:ir=63:19 $ir=64:19 $f+:ir=65:19 | Fixed false positive:ir=63:19 |
|
||||
| complex.cpp:51:24:51:121 | // $ast=62:19 $f+:ast=63:19 $ast=64:19 $f+:ast=65:19 $ir=62:19 $f+:ir=63:19 $ir=64:19 $f+:ir=65:19 | Fixed false positive:ir=65:19 |
|
||||
| complex.cpp:52:24:52:121 | // $f+:ast=62:19 $ast=63:19 $f+:ast=64:19 $ast=65:19 $f+:ir=62:19 $ir=63:19 $f+:ir=64:19 $ir=65:19 | Fixed false positive:ir=62:19 |
|
||||
| complex.cpp:52:24:52:121 | // $f+:ast=62:19 $ast=63:19 $f+:ast=64:19 $ast=65:19 $f+:ir=62:19 $ir=63:19 $f+:ir=64:19 $ir=65:19 | Fixed false positive:ir=64:19 |
|
||||
|
||||
@@ -7,24 +7,20 @@ edges
|
||||
| A.cpp:57:11:57:24 | B output argument [c] | A.cpp:57:10:57:25 | Argument -1 indirection [c] |
|
||||
| A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | B output argument [c] |
|
||||
| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Store |
|
||||
| A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | a [a] |
|
||||
| A.cpp:100:5:100:13 | a [a] | A.cpp:101:8:101:9 | Argument 0 indirection [a] |
|
||||
| A.cpp:100:5:100:13 | Chi [a] | A.cpp:101:8:101:9 | Argument 0 indirection [a] |
|
||||
| A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | Chi [a] |
|
||||
| A.cpp:101:8:101:9 | Argument 0 indirection [a] | A.cpp:103:14:103:14 | *c [a] |
|
||||
| A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a |
|
||||
| A.cpp:107:16:107:16 | a | A.cpp:107:16:107:16 | a |
|
||||
| A.cpp:126:5:126:5 | Chi [c] | A.cpp:131:8:131:8 | f7 output argument [c] |
|
||||
| A.cpp:126:5:126:5 | set output argument [c] | A.cpp:126:5:126:5 | Chi [c] |
|
||||
| A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | set output argument [c] |
|
||||
| A.cpp:131:8:131:8 | Chi [c] | A.cpp:132:13:132:13 | c |
|
||||
| A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:131:8:131:8 | Chi [c] |
|
||||
| A.cpp:132:13:132:13 | c | A.cpp:132:13:132:13 | c |
|
||||
| A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] |
|
||||
| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | c [c] |
|
||||
| A.cpp:142:7:142:20 | c [c] | A.cpp:142:7:142:20 | Chi [c] |
|
||||
| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] |
|
||||
| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store |
|
||||
| A.cpp:143:7:143:31 | Chi [b] | A.cpp:151:12:151:24 | D output argument [b] |
|
||||
| A.cpp:143:7:143:31 | Store | A.cpp:143:7:143:31 | b [b] |
|
||||
| A.cpp:143:7:143:31 | b [b] | A.cpp:143:7:143:31 | Chi [b] |
|
||||
| A.cpp:143:7:143:31 | Store | A.cpp:143:7:143:31 | Chi [b] |
|
||||
| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | Store |
|
||||
| A.cpp:150:12:150:18 | new | A.cpp:151:18:151:18 | b |
|
||||
| A.cpp:151:12:151:24 | Chi [b] | A.cpp:152:13:152:13 | b |
|
||||
@@ -32,45 +28,35 @@ edges
|
||||
| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c |
|
||||
| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] |
|
||||
| A.cpp:151:18:151:18 | b | A.cpp:151:12:151:24 | D output argument [b] |
|
||||
| A.cpp:152:13:152:13 | b | A.cpp:152:13:152:13 | b |
|
||||
| A.cpp:154:13:154:13 | c | A.cpp:154:13:154:13 | c |
|
||||
| C.cpp:18:12:18:18 | C output argument [s1] | C.cpp:19:5:19:5 | Argument -1 indirection [s1] |
|
||||
| C.cpp:18:12:18:18 | C output argument [s3] | C.cpp:19:5:19:5 | Argument -1 indirection [s3] |
|
||||
| C.cpp:19:5:19:5 | Argument -1 indirection [s1] | C.cpp:27:8:27:11 | *#this [s1] |
|
||||
| C.cpp:19:5:19:5 | Argument -1 indirection [s3] | C.cpp:27:8:27:11 | *#this [s3] |
|
||||
| C.cpp:22:12:22:21 | Store | C.cpp:22:12:22:21 | s1 [s1] |
|
||||
| C.cpp:22:12:22:21 | Chi [s1] | C.cpp:24:5:24:25 | Chi [s1] |
|
||||
| C.cpp:22:12:22:21 | Store | C.cpp:22:12:22:21 | Chi [s1] |
|
||||
| C.cpp:22:12:22:21 | new | C.cpp:22:12:22:21 | Store |
|
||||
| C.cpp:22:12:22:21 | s1 [s1] | C.cpp:24:5:24:25 | Chi [s1] |
|
||||
| C.cpp:24:5:24:25 | Chi [s1] | C.cpp:18:12:18:18 | C output argument [s1] |
|
||||
| C.cpp:24:5:24:25 | Chi [s3] | C.cpp:18:12:18:18 | C output argument [s3] |
|
||||
| C.cpp:24:5:24:25 | Store | C.cpp:24:5:24:25 | s3 [s3] |
|
||||
| C.cpp:24:5:24:25 | s3 [s3] | C.cpp:24:5:24:25 | Chi [s3] |
|
||||
| C.cpp:24:5:24:25 | Store | C.cpp:24:5:24:25 | Chi [s3] |
|
||||
| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | Store |
|
||||
| C.cpp:27:8:27:11 | *#this [s1] | C.cpp:29:10:29:11 | s1 |
|
||||
| C.cpp:27:8:27:11 | *#this [s3] | C.cpp:31:10:31:11 | s3 |
|
||||
| C.cpp:29:10:29:11 | s1 | C.cpp:29:10:29:11 | s1 |
|
||||
| C.cpp:31:10:31:11 | s3 | C.cpp:31:10:31:11 | s3 |
|
||||
| aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] |
|
||||
| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | m1 [m1] |
|
||||
| aliasing.cpp:9:3:9:22 | m1 [m1] | aliasing.cpp:9:3:9:22 | Chi [m1] |
|
||||
| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] |
|
||||
| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store |
|
||||
| aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] |
|
||||
| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | m1 [m1] |
|
||||
| aliasing.cpp:13:3:13:21 | m1 [m1] | aliasing.cpp:13:3:13:21 | Chi [m1] |
|
||||
| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | Chi [m1] |
|
||||
| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Store |
|
||||
| aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 |
|
||||
| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] |
|
||||
| aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 |
|
||||
| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] |
|
||||
| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:29:11:29:12 | m1 |
|
||||
| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:30:11:30:12 | m1 |
|
||||
| aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 |
|
||||
| aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 |
|
||||
| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | m1 [m1] |
|
||||
| aliasing.cpp:60:3:60:22 | m1 [m1] | aliasing.cpp:61:13:61:14 | Store [m1] |
|
||||
| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] |
|
||||
| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | Chi [m1] |
|
||||
| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Store |
|
||||
| aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 |
|
||||
| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:62:14:62:15 | m1 |
|
||||
| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 |
|
||||
| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 |
|
||||
| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 |
|
||||
@@ -88,117 +74,42 @@ edges
|
||||
| by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA |
|
||||
| by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] |
|
||||
| by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] |
|
||||
| by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | a [a] |
|
||||
| by_reference.cpp:84:3:84:25 | a [a] | by_reference.cpp:84:3:84:25 | Chi [a] |
|
||||
| by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | Chi [a] |
|
||||
| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Store |
|
||||
| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] |
|
||||
| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] |
|
||||
| by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | a [a] |
|
||||
| by_reference.cpp:88:3:88:24 | a [a] | by_reference.cpp:88:3:88:24 | Chi [a] |
|
||||
| by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | Chi [a] |
|
||||
| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Store |
|
||||
| by_reference.cpp:102:21:102:39 | Chi [inner_nested, a] | by_reference.cpp:110:27:110:27 | inner_nested.a [a] |
|
||||
| by_reference.cpp:102:21:102:39 | inner_nested [inner_nested, a] | by_reference.cpp:102:21:102:39 | Chi [inner_nested, a] |
|
||||
| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | inner_nested [inner_nested, a] |
|
||||
| by_reference.cpp:106:21:106:41 | Chi [inner_nested, a] | by_reference.cpp:114:29:114:29 | inner_nested.a [a] |
|
||||
| by_reference.cpp:106:21:106:41 | inner_nested [inner_nested, a] | by_reference.cpp:106:21:106:41 | Chi [inner_nested, a] |
|
||||
| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | inner_nested [inner_nested, a] |
|
||||
| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:110:27:110:27 | a |
|
||||
| by_reference.cpp:110:27:110:27 | inner_nested.a [a] | by_reference.cpp:110:27:110:27 | a |
|
||||
| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:114:29:114:29 | a |
|
||||
| by_reference.cpp:114:29:114:29 | inner_nested.a [a] | by_reference.cpp:114:29:114:29 | a |
|
||||
| by_reference.cpp:122:21:122:38 | Chi [inner_nested, a] | by_reference.cpp:130:27:130:27 | inner_nested.a [a] |
|
||||
| by_reference.cpp:122:21:122:38 | inner_nested [inner_nested, a] | by_reference.cpp:122:21:122:38 | Chi [inner_nested, a] |
|
||||
| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | inner_nested [inner_nested, a] |
|
||||
| by_reference.cpp:126:21:126:40 | Chi [inner_nested, a] | by_reference.cpp:134:29:134:29 | inner_nested.a [a] |
|
||||
| by_reference.cpp:126:21:126:40 | inner_nested [inner_nested, a] | by_reference.cpp:126:21:126:40 | Chi [inner_nested, a] |
|
||||
| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | inner_nested [inner_nested, a] |
|
||||
| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:130:27:130:27 | a |
|
||||
| by_reference.cpp:130:27:130:27 | inner_nested.a [a] | by_reference.cpp:130:27:130:27 | a |
|
||||
| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:134:29:134:29 | a |
|
||||
| by_reference.cpp:134:29:134:29 | inner_nested.a [a] | by_reference.cpp:134:29:134:29 | a |
|
||||
| by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a |
|
||||
| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] |
|
||||
| by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a |
|
||||
| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] |
|
||||
| by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a |
|
||||
| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] |
|
||||
| by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a |
|
||||
| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] |
|
||||
| complex.cpp:40:17:40:17 | *b [a_] | complex.cpp:51:16:51:16 | Argument -1 indirection [a_] |
|
||||
| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:51:16:51:16 | Argument -1 indirection [b_] |
|
||||
| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:52:16:52:16 | Argument -1 indirection [b_] |
|
||||
| complex.cpp:40:17:40:17 | *b [inner, b_] | complex.cpp:51:16:51:16 | inner.f [b_] |
|
||||
| complex.cpp:40:17:40:17 | *b [inner, f, ... (3)] | complex.cpp:51:16:51:16 | Argument -1 indirection [inner, f, ... (3)] |
|
||||
| complex.cpp:40:17:40:17 | *b [inner, f, ... (3)] | complex.cpp:51:16:51:16 | Chi [inner, f, ... (3)] |
|
||||
| complex.cpp:40:17:40:17 | *b [inner, f, ... (3)] | complex.cpp:51:16:51:16 | inner.f [f, a_] |
|
||||
| complex.cpp:40:17:40:17 | *b [inner, f, ... (3)] | complex.cpp:51:16:51:16 | inner.f [f, b_] |
|
||||
| complex.cpp:40:17:40:17 | *b [inner, f, ... (5)] | complex.cpp:51:16:51:16 | inner.f [f, inner, ... (4)] |
|
||||
| complex.cpp:51:16:51:16 | Argument -1 indirection [a_] | complex.cpp:51:16:51:16 | a output argument [a_] |
|
||||
| complex.cpp:51:16:51:16 | Argument -1 indirection [a_] | complex.cpp:51:18:51:18 | call to a |
|
||||
| complex.cpp:51:16:51:16 | Argument -1 indirection [b_] | complex.cpp:51:16:51:16 | a output argument [b_] |
|
||||
| complex.cpp:51:16:51:16 | Argument -1 indirection [inner, f, ... (3)] | complex.cpp:51:16:51:16 | a output argument [inner, f, ... (3)] |
|
||||
| complex.cpp:51:16:51:16 | Chi [inner, f, ... (3)] | complex.cpp:52:16:52:16 | inner.f [f, b_] |
|
||||
| complex.cpp:51:16:51:16 | a output argument [a_] | complex.cpp:51:16:51:16 | f [f, a_] |
|
||||
| complex.cpp:51:16:51:16 | a output argument [b_] | complex.cpp:51:16:51:16 | f [f, b_] |
|
||||
| complex.cpp:51:16:51:16 | a output argument [b_] | complex.cpp:52:16:52:16 | Argument -1 indirection [b_] |
|
||||
| complex.cpp:51:16:51:16 | a output argument [inner, f, ... (3)] | complex.cpp:51:16:51:16 | Chi [inner, f, ... (3)] |
|
||||
| complex.cpp:51:16:51:16 | f [a_] | complex.cpp:51:16:51:16 | Argument -1 indirection [a_] |
|
||||
| complex.cpp:51:16:51:16 | f [b_] | complex.cpp:51:16:51:16 | Argument -1 indirection [b_] |
|
||||
| complex.cpp:51:16:51:16 | f [f, a_] | complex.cpp:51:16:51:16 | inner.f [inner, f, ... (3)] |
|
||||
| complex.cpp:51:16:51:16 | f [f, b_] | complex.cpp:51:16:51:16 | inner.f [inner, f, ... (3)] |
|
||||
| complex.cpp:51:16:51:16 | f [inner, f, ... (3)] | complex.cpp:51:16:51:16 | Argument -1 indirection [inner, f, ... (3)] |
|
||||
| complex.cpp:51:16:51:16 | inner.f [b_] | complex.cpp:52:16:52:16 | Argument -1 indirection [b_] |
|
||||
| complex.cpp:51:16:51:16 | inner.f [f, a_] | complex.cpp:51:16:51:16 | f [a_] |
|
||||
| complex.cpp:51:16:51:16 | inner.f [f, b_] | complex.cpp:51:16:51:16 | f [b_] |
|
||||
| complex.cpp:51:16:51:16 | inner.f [f, inner, ... (4)] | complex.cpp:51:16:51:16 | f [inner, f, ... (3)] |
|
||||
| complex.cpp:51:16:51:16 | inner.f [inner, f, ... (3)] | complex.cpp:51:16:51:16 | Chi [inner, f, ... (3)] |
|
||||
| complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | complex.cpp:52:18:52:18 | call to b |
|
||||
| complex.cpp:52:16:52:16 | f [b_] | complex.cpp:52:16:52:16 | Argument -1 indirection [b_] |
|
||||
| complex.cpp:52:16:52:16 | inner.f [f, b_] | complex.cpp:52:16:52:16 | f [b_] |
|
||||
| complex.cpp:62:12:62:12 | f [f, a_] | complex.cpp:62:12:62:12 | inner.f [inner, f, ... (3)] |
|
||||
| complex.cpp:62:12:62:12 | inner.f [inner, f, ... (3)] | complex.cpp:68:7:68:8 | Argument 0 indirection [inner, f, ... (3)] |
|
||||
| complex.cpp:62:12:62:12 | setA output argument [a_] | complex.cpp:62:12:62:12 | f [f, a_] |
|
||||
| complex.cpp:62:12:62:12 | setA output argument [a_] | complex.cpp:68:7:68:8 | Argument 0 indirection [a_] |
|
||||
| complex.cpp:62:19:62:28 | call to user_input | complex.cpp:62:12:62:12 | setA output argument [a_] |
|
||||
| complex.cpp:63:12:63:12 | f [f, b_] | complex.cpp:63:12:63:12 | inner.f [inner, f, ... (3)] |
|
||||
| complex.cpp:63:12:63:12 | inner.f [inner, f, ... (3)] | complex.cpp:71:7:71:8 | Argument 0 indirection [inner, f, ... (3)] |
|
||||
| complex.cpp:63:12:63:12 | setB output argument [b_] | complex.cpp:63:12:63:12 | f [f, b_] |
|
||||
| complex.cpp:63:12:63:12 | setB output argument [b_] | complex.cpp:71:7:71:8 | Argument 0 indirection [b_] |
|
||||
| complex.cpp:63:19:63:28 | call to user_input | complex.cpp:63:12:63:12 | setB output argument [b_] |
|
||||
| complex.cpp:64:12:64:12 | Chi [inner, f, ... (3)] | complex.cpp:65:12:65:12 | inner.f [f, a_] |
|
||||
| complex.cpp:64:12:64:12 | Chi [inner, f, ... (3)] | complex.cpp:65:12:65:12 | inner.f [f, b_] |
|
||||
| complex.cpp:64:12:64:12 | Chi [inner, f, ... (3)] | complex.cpp:65:12:65:12 | inner.f [f, b_] |
|
||||
| complex.cpp:64:12:64:12 | f [f, a_] | complex.cpp:64:12:64:12 | inner.f [inner, f, ... (3)] |
|
||||
| complex.cpp:64:12:64:12 | inner.f [inner, f, ... (3)] | complex.cpp:64:12:64:12 | Chi [inner, f, ... (3)] |
|
||||
| complex.cpp:64:12:64:12 | inner.f [inner, f, ... (3)] | complex.cpp:65:12:65:12 | Argument -1 indirection [inner, f, ... (3)] |
|
||||
| complex.cpp:64:12:64:12 | inner.f [inner, f, ... (3)] | complex.cpp:74:7:74:8 | Argument 0 indirection [inner, f, ... (3)] |
|
||||
| complex.cpp:64:12:64:12 | setA output argument [a_] | complex.cpp:64:12:64:12 | f [f, a_] |
|
||||
| complex.cpp:64:12:64:12 | setA output argument [a_] | complex.cpp:65:12:65:12 | Argument -1 indirection [a_] |
|
||||
| complex.cpp:64:12:64:12 | setA output argument [a_] | complex.cpp:74:7:74:8 | Argument 0 indirection [a_] |
|
||||
| complex.cpp:64:19:64:28 | call to user_input | complex.cpp:64:12:64:12 | setA output argument [a_] |
|
||||
| complex.cpp:65:12:65:12 | Argument -1 indirection [a_] | complex.cpp:65:12:65:12 | setB output argument [a_] |
|
||||
| complex.cpp:65:12:65:12 | Argument -1 indirection [b_] | complex.cpp:65:12:65:12 | setB output argument [b_] |
|
||||
| complex.cpp:65:12:65:12 | Argument -1 indirection [inner, f, ... (3)] | complex.cpp:65:12:65:12 | setB output argument [inner, f, ... (3)] |
|
||||
| complex.cpp:65:12:65:12 | f [a_] | complex.cpp:65:12:65:12 | Argument -1 indirection [a_] |
|
||||
| complex.cpp:65:12:65:12 | f [b_] | complex.cpp:65:12:65:12 | Argument -1 indirection [b_] |
|
||||
| complex.cpp:65:12:65:12 | f [b_] | complex.cpp:65:12:65:12 | inner.f [inner, b_] |
|
||||
| complex.cpp:65:12:65:12 | f [f, a_] | complex.cpp:65:12:65:12 | inner.f [inner, f, ... (3)] |
|
||||
| complex.cpp:65:12:65:12 | f [f, b_] | complex.cpp:65:12:65:12 | inner.f [inner, f, ... (3)] |
|
||||
| complex.cpp:65:12:65:12 | f [f, inner, ... (4)] | complex.cpp:65:12:65:12 | inner.f [inner, f, ... (5)] |
|
||||
| complex.cpp:65:12:65:12 | inner.f [f, a_] | complex.cpp:65:12:65:12 | f [a_] |
|
||||
| complex.cpp:65:12:65:12 | inner.f [f, b_] | complex.cpp:65:12:65:12 | f [b_] |
|
||||
| complex.cpp:65:12:65:12 | inner.f [f, b_] | complex.cpp:65:12:65:12 | f [b_] |
|
||||
| complex.cpp:65:12:65:12 | inner.f [inner, b_] | complex.cpp:74:7:74:8 | Argument 0 indirection [inner, b_] |
|
||||
| complex.cpp:65:12:65:12 | inner.f [inner, f, ... (3)] | complex.cpp:74:7:74:8 | Argument 0 indirection [inner, f, ... (3)] |
|
||||
| complex.cpp:65:12:65:12 | inner.f [inner, f, ... (5)] | complex.cpp:74:7:74:8 | Argument 0 indirection [inner, f, ... (5)] |
|
||||
| complex.cpp:65:12:65:12 | setB output argument [a_] | complex.cpp:65:12:65:12 | f [f, a_] |
|
||||
| complex.cpp:65:12:65:12 | setB output argument [a_] | complex.cpp:74:7:74:8 | Argument 0 indirection [a_] |
|
||||
| complex.cpp:65:12:65:12 | setB output argument [b_] | complex.cpp:65:12:65:12 | f [f, b_] |
|
||||
| complex.cpp:65:12:65:12 | setB output argument [b_] | complex.cpp:74:7:74:8 | Argument 0 indirection [b_] |
|
||||
| complex.cpp:65:12:65:12 | setB output argument [inner, f, ... (3)] | complex.cpp:65:12:65:12 | f [f, inner, ... (4)] |
|
||||
| complex.cpp:65:12:65:12 | setB output argument [inner, f, ... (3)] | complex.cpp:74:7:74:8 | Argument 0 indirection [inner, f, ... (3)] |
|
||||
| complex.cpp:65:19:65:28 | call to user_input | complex.cpp:65:12:65:12 | setB output argument [b_] |
|
||||
| complex.cpp:68:7:68:8 | Argument 0 indirection [a_] | complex.cpp:40:17:40:17 | *b [a_] |
|
||||
| complex.cpp:68:7:68:8 | Argument 0 indirection [inner, f, ... (3)] | complex.cpp:40:17:40:17 | *b [inner, f, ... (3)] |
|
||||
| complex.cpp:71:7:71:8 | Argument 0 indirection [b_] | complex.cpp:40:17:40:17 | *b [b_] |
|
||||
| complex.cpp:71:7:71:8 | Argument 0 indirection [inner, f, ... (3)] | complex.cpp:40:17:40:17 | *b [inner, f, ... (3)] |
|
||||
| complex.cpp:74:7:74:8 | Argument 0 indirection [a_] | complex.cpp:40:17:40:17 | *b [a_] |
|
||||
| complex.cpp:74:7:74:8 | Argument 0 indirection [b_] | complex.cpp:40:17:40:17 | *b [b_] |
|
||||
| complex.cpp:74:7:74:8 | Argument 0 indirection [inner, b_] | complex.cpp:40:17:40:17 | *b [inner, b_] |
|
||||
| complex.cpp:74:7:74:8 | Argument 0 indirection [inner, f, ... (3)] | complex.cpp:40:17:40:17 | *b [inner, f, ... (3)] |
|
||||
| complex.cpp:74:7:74:8 | Argument 0 indirection [inner, f, ... (5)] | complex.cpp:40:17:40:17 | *b [inner, f, ... (5)] |
|
||||
| constructors.cpp:26:15:26:15 | *f [a_] | constructors.cpp:28:10:28:10 | Argument -1 indirection [a_] |
|
||||
| constructors.cpp:26:15:26:15 | *f [b_] | constructors.cpp:28:10:28:10 | Argument -1 indirection [b_] |
|
||||
| constructors.cpp:26:15:26:15 | *f [b_] | constructors.cpp:29:10:29:10 | Argument -1 indirection [b_] |
|
||||
@@ -240,81 +151,24 @@ edges
|
||||
| simple.cpp:48:9:48:9 | Argument 0 indirection [b_] | simple.cpp:26:15:26:15 | *f [b_] |
|
||||
| simple.cpp:51:9:51:9 | Argument 0 indirection [a_] | simple.cpp:26:15:26:15 | *f [a_] |
|
||||
| simple.cpp:51:9:51:9 | Argument 0 indirection [b_] | simple.cpp:26:15:26:15 | *f [b_] |
|
||||
| simple.cpp:65:5:65:22 | i [i] | simple.cpp:66:12:66:12 | Store [i] |
|
||||
| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | i [i] |
|
||||
| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] |
|
||||
| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] |
|
||||
| simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i |
|
||||
| simple.cpp:67:13:67:13 | i | simple.cpp:67:13:67:13 | i |
|
||||
| simple.cpp:83:9:83:28 | Store | simple.cpp:83:9:83:28 | f1 [f1] |
|
||||
| simple.cpp:83:9:83:28 | f1 [f1] | simple.cpp:83:9:83:28 | f2.f1 [f2, f1] |
|
||||
| simple.cpp:83:9:83:28 | f2.f1 [f2, f1] | simple.cpp:84:14:84:20 | Argument -1 indirection [f2, f1] |
|
||||
| simple.cpp:83:9:83:28 | Chi [f1] | simple.cpp:84:14:84:20 | Argument -1 indirection [f1] |
|
||||
| simple.cpp:83:9:83:28 | Store | simple.cpp:83:9:83:28 | Chi [f1] |
|
||||
| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Store |
|
||||
| simple.cpp:84:14:84:20 | Argument -1 indirection [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 |
|
||||
| simple.cpp:108:30:108:31 | d2 [d1_2, y] | simple.cpp:111:18:111:18 | d1_2.y [y] |
|
||||
| simple.cpp:111:18:111:18 | d1_2.y [y] | simple.cpp:111:18:111:18 | y |
|
||||
| simple.cpp:111:18:111:18 | y | simple.cpp:111:18:111:18 | y |
|
||||
| simple.cpp:114:37:114:38 | *d2 [d1_2, y] | simple.cpp:117:19:117:19 | d1_2.y [y] |
|
||||
| simple.cpp:117:19:117:19 | d1_2.y [y] | simple.cpp:117:19:117:19 | y |
|
||||
| simple.cpp:117:19:117:19 | y | simple.cpp:117:19:117:19 | y |
|
||||
| simple.cpp:122:5:122:33 | Chi [d2_1, d1_1, ... (3)] | simple.cpp:123:27:123:30 | d2_1 [d1_1, x] |
|
||||
| simple.cpp:122:5:122:33 | Store | simple.cpp:122:5:122:33 | x [x] |
|
||||
| simple.cpp:122:5:122:33 | d1_1.x [d1_1, x] | simple.cpp:122:5:122:33 | d2_1.d1_1.x [d2_1, d1_1, ... (3)] |
|
||||
| simple.cpp:122:5:122:33 | d2_1.d1_1.x [d2_1, d1_1, ... (3)] | simple.cpp:122:5:122:33 | Chi [d2_1, d1_1, ... (3)] |
|
||||
| simple.cpp:122:5:122:33 | x [x] | simple.cpp:122:5:122:33 | d1_1.x [d1_1, x] |
|
||||
| simple.cpp:122:22:122:31 | call to user_input | simple.cpp:122:5:122:33 | Store |
|
||||
| simple.cpp:123:27:123:30 | Store [d1_1, x] | simple.cpp:124:20:124:20 | d1_1.x [x] |
|
||||
| simple.cpp:123:27:123:30 | Store [d1_1, x] | simple.cpp:130:15:130:15 | d1_1.x [x] |
|
||||
| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | simple.cpp:123:27:123:30 | Store [d1_1, x] |
|
||||
| simple.cpp:124:20:124:20 | d1_1.x [x] | simple.cpp:124:20:124:20 | x |
|
||||
| simple.cpp:124:20:124:20 | x | simple.cpp:124:20:124:20 | x |
|
||||
| simple.cpp:130:15:130:15 | d1_1.x [x] | simple.cpp:130:15:130:15 | x |
|
||||
| simple.cpp:130:15:130:15 | x | simple.cpp:130:15:130:15 | x |
|
||||
| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:139:23:139:23 | d2_1.d1_2.y [d1_2, y] |
|
||||
| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] |
|
||||
| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:143:23:143:30 | d2_1 [d1_2, y] |
|
||||
| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:143:23:143:30 | d2_1 [d1_2, y] |
|
||||
| simple.cpp:136:21:136:28 | d2_1 [d2_1, d1_2, ... (3)] | simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] |
|
||||
| simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | simple.cpp:136:21:136:28 | d2_1 [d2_1, d1_2, ... (3)] |
|
||||
| simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] |
|
||||
| simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] |
|
||||
| simple.cpp:136:31:136:40 | call to user_input | simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] |
|
||||
| simple.cpp:139:23:139:23 | d1_2.y [y] | simple.cpp:139:23:139:23 | y |
|
||||
| simple.cpp:139:23:139:23 | d2_1.d1_2.y [d1_2, y] | simple.cpp:139:23:139:23 | d1_2.y [y] |
|
||||
| simple.cpp:139:23:139:23 | y | simple.cpp:139:23:139:23 | y |
|
||||
| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | simple.cpp:108:30:108:31 | d2 [d1_2, y] |
|
||||
| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] |
|
||||
| simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | simple.cpp:114:37:114:38 | *d2 [d1_2, y] |
|
||||
| simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | simple.cpp:143:23:143:30 | read_from_y_deref output argument [d1_2, y] |
|
||||
| simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] |
|
||||
| simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] |
|
||||
| simple.cpp:143:23:143:30 | read_from_y_deref output argument [d1_2, y] | simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] |
|
||||
| simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | simple.cpp:114:37:114:38 | *d2 [d1_2, y] |
|
||||
| simple.cpp:159:20:159:24 | *inner [f] | simple.cpp:161:17:161:17 | f |
|
||||
| simple.cpp:161:17:161:17 | f | simple.cpp:161:17:161:17 | f |
|
||||
| simple.cpp:167:5:167:32 | Chi [inner, f] | simple.cpp:168:12:168:23 | inner [f] |
|
||||
| simple.cpp:167:5:167:32 | Store | simple.cpp:167:5:167:32 | f [f] |
|
||||
| simple.cpp:167:5:167:32 | f [f] | simple.cpp:167:5:167:32 | inner.f [inner, f] |
|
||||
| simple.cpp:167:5:167:32 | inner.f [inner, f] | simple.cpp:167:5:167:32 | Chi [inner, f] |
|
||||
| simple.cpp:167:21:167:30 | call to user_input | simple.cpp:167:5:167:32 | Store |
|
||||
| simple.cpp:168:12:168:23 | Argument 0 indirection [f] | simple.cpp:159:20:159:24 | *inner [f] |
|
||||
| simple.cpp:168:12:168:23 | inner [f] | simple.cpp:168:12:168:23 | Argument 0 indirection [f] |
|
||||
| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | simple.cpp:84:14:84:20 | call to getf2f1 |
|
||||
| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a |
|
||||
| struct_init.c:15:12:15:12 | a | struct_init.c:15:12:15:12 | a |
|
||||
| struct_init.c:20:20:20:29 | Store | struct_init.c:20:20:20:29 | a [a] |
|
||||
| struct_init.c:20:20:20:29 | a [a] | struct_init.c:24:10:24:12 | Argument 0 indirection [a] |
|
||||
| struct_init.c:20:20:20:29 | Chi [a] | struct_init.c:24:10:24:12 | Argument 0 indirection [a] |
|
||||
| struct_init.c:20:20:20:29 | Store | struct_init.c:20:20:20:29 | Chi [a] |
|
||||
| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | Store |
|
||||
| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a |
|
||||
| struct_init.c:24:10:24:12 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] |
|
||||
| struct_init.c:27:7:27:16 | Chi [nestedAB, a] | struct_init.c:27:21:27:21 | nestedAB.b [a] |
|
||||
| struct_init.c:27:7:27:16 | Store | struct_init.c:27:7:27:16 | a [a] |
|
||||
| struct_init.c:27:7:27:16 | a [a] | struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] |
|
||||
| struct_init.c:27:7:27:16 | Chi [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] |
|
||||
| struct_init.c:27:7:27:16 | Store | struct_init.c:27:7:27:16 | Chi [a] |
|
||||
| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:7:27:16 | Store |
|
||||
| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a |
|
||||
| struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | struct_init.c:27:7:27:16 | Chi [nestedAB, a] |
|
||||
| struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | struct_init.c:28:5:28:7 | Chi [nestedAB, a] |
|
||||
| struct_init.c:27:21:27:21 | nestedAB.b [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] |
|
||||
| struct_init.c:28:5:28:7 | Chi [nestedAB, a] | struct_init.c:36:10:36:24 | nestedAB [a] |
|
||||
| struct_init.c:36:10:36:24 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] |
|
||||
| struct_init.c:36:10:36:24 | nestedAB [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] |
|
||||
nodes
|
||||
| A.cpp:55:5:55:5 | set output argument [c] | semmle.label | set output argument [c] |
|
||||
| A.cpp:55:12:55:19 | (C *)... | semmle.label | (C *)... |
|
||||
@@ -326,26 +180,22 @@ nodes
|
||||
| A.cpp:57:17:57:23 | new | semmle.label | new |
|
||||
| A.cpp:57:28:57:30 | call to get | semmle.label | call to get |
|
||||
| A.cpp:98:12:98:18 | new | semmle.label | new |
|
||||
| A.cpp:100:5:100:13 | Chi [a] | semmle.label | Chi [a] |
|
||||
| A.cpp:100:5:100:13 | Store | semmle.label | Store |
|
||||
| A.cpp:100:5:100:13 | a [a] | semmle.label | a [a] |
|
||||
| A.cpp:101:8:101:9 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] |
|
||||
| A.cpp:103:14:103:14 | *c [a] | semmle.label | *c [a] |
|
||||
| A.cpp:107:16:107:16 | a | semmle.label | a |
|
||||
| A.cpp:107:16:107:16 | a | semmle.label | a |
|
||||
| A.cpp:126:5:126:5 | Chi [c] | semmle.label | Chi [c] |
|
||||
| A.cpp:126:5:126:5 | set output argument [c] | semmle.label | set output argument [c] |
|
||||
| A.cpp:126:12:126:18 | new | semmle.label | new |
|
||||
| A.cpp:131:8:131:8 | Chi [c] | semmle.label | Chi [c] |
|
||||
| A.cpp:131:8:131:8 | f7 output argument [c] | semmle.label | f7 output argument [c] |
|
||||
| A.cpp:132:13:132:13 | c | semmle.label | c |
|
||||
| A.cpp:132:13:132:13 | c | semmle.label | c |
|
||||
| A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] |
|
||||
| A.cpp:142:7:142:20 | Store | semmle.label | Store |
|
||||
| A.cpp:142:7:142:20 | c [c] | semmle.label | c [c] |
|
||||
| A.cpp:142:14:142:20 | new | semmle.label | new |
|
||||
| A.cpp:143:7:143:31 | Chi [b] | semmle.label | Chi [b] |
|
||||
| A.cpp:143:7:143:31 | Store | semmle.label | Store |
|
||||
| A.cpp:143:7:143:31 | b [b] | semmle.label | b [b] |
|
||||
| A.cpp:143:25:143:31 | new | semmle.label | new |
|
||||
| A.cpp:150:12:150:18 | new | semmle.label | new |
|
||||
| A.cpp:151:12:151:24 | Chi [b] | semmle.label | Chi [b] |
|
||||
@@ -354,53 +204,43 @@ nodes
|
||||
| A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] |
|
||||
| A.cpp:151:18:151:18 | b | semmle.label | b |
|
||||
| A.cpp:152:13:152:13 | b | semmle.label | b |
|
||||
| A.cpp:152:13:152:13 | b | semmle.label | b |
|
||||
| A.cpp:154:13:154:13 | c | semmle.label | c |
|
||||
| A.cpp:154:13:154:13 | c | semmle.label | c |
|
||||
| C.cpp:18:12:18:18 | C output argument [s1] | semmle.label | C output argument [s1] |
|
||||
| C.cpp:18:12:18:18 | C output argument [s3] | semmle.label | C output argument [s3] |
|
||||
| C.cpp:19:5:19:5 | Argument -1 indirection [s1] | semmle.label | Argument -1 indirection [s1] |
|
||||
| C.cpp:19:5:19:5 | Argument -1 indirection [s3] | semmle.label | Argument -1 indirection [s3] |
|
||||
| C.cpp:22:12:22:21 | Chi [s1] | semmle.label | Chi [s1] |
|
||||
| C.cpp:22:12:22:21 | Store | semmle.label | Store |
|
||||
| C.cpp:22:12:22:21 | new | semmle.label | new |
|
||||
| C.cpp:22:12:22:21 | s1 [s1] | semmle.label | s1 [s1] |
|
||||
| C.cpp:24:5:24:25 | Chi [s1] | semmle.label | Chi [s1] |
|
||||
| C.cpp:24:5:24:25 | Chi [s3] | semmle.label | Chi [s3] |
|
||||
| C.cpp:24:5:24:25 | Store | semmle.label | Store |
|
||||
| C.cpp:24:5:24:25 | s3 [s3] | semmle.label | s3 [s3] |
|
||||
| C.cpp:24:16:24:25 | new | semmle.label | new |
|
||||
| C.cpp:27:8:27:11 | *#this [s1] | semmle.label | *#this [s1] |
|
||||
| C.cpp:27:8:27:11 | *#this [s3] | semmle.label | *#this [s3] |
|
||||
| C.cpp:29:10:29:11 | s1 | semmle.label | s1 |
|
||||
| C.cpp:29:10:29:11 | s1 | semmle.label | s1 |
|
||||
| C.cpp:31:10:31:11 | s3 | semmle.label | s3 |
|
||||
| C.cpp:31:10:31:11 | s3 | semmle.label | s3 |
|
||||
| aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] |
|
||||
| aliasing.cpp:9:3:9:22 | Store | semmle.label | Store |
|
||||
| aliasing.cpp:9:3:9:22 | m1 [m1] | semmle.label | m1 [m1] |
|
||||
| aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] |
|
||||
| aliasing.cpp:13:3:13:21 | Store | semmle.label | Store |
|
||||
| aliasing.cpp:13:3:13:21 | m1 [m1] | semmle.label | m1 [m1] |
|
||||
| aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] |
|
||||
| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] |
|
||||
| aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] |
|
||||
| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] |
|
||||
| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:37:13:37:22 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] |
|
||||
| aliasing.cpp:60:3:60:22 | Store | semmle.label | Store |
|
||||
| aliasing.cpp:60:3:60:22 | m1 [m1] | semmle.label | m1 [m1] |
|
||||
| aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] |
|
||||
| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:86:10:86:19 | call to user_input | semmle.label | call to user_input |
|
||||
@@ -425,104 +265,44 @@ nodes
|
||||
| by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] |
|
||||
| by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] |
|
||||
| by_reference.cpp:84:3:84:25 | Store | semmle.label | Store |
|
||||
| by_reference.cpp:84:3:84:25 | a [a] | semmle.label | a [a] |
|
||||
| by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input |
|
||||
| by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] |
|
||||
| by_reference.cpp:88:3:88:24 | Store | semmle.label | Store |
|
||||
| by_reference.cpp:88:3:88:24 | a [a] | semmle.label | a [a] |
|
||||
| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input |
|
||||
| by_reference.cpp:102:21:102:39 | Chi [inner_nested, a] | semmle.label | Chi [inner_nested, a] |
|
||||
| by_reference.cpp:102:21:102:39 | inner_nested [inner_nested, a] | semmle.label | inner_nested [inner_nested, a] |
|
||||
| by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] |
|
||||
| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] |
|
||||
| by_reference.cpp:106:21:106:41 | Chi [inner_nested, a] | semmle.label | Chi [inner_nested, a] |
|
||||
| by_reference.cpp:106:21:106:41 | inner_nested [inner_nested, a] | semmle.label | inner_nested [inner_nested, a] |
|
||||
| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] |
|
||||
| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] |
|
||||
| by_reference.cpp:110:27:110:27 | a | semmle.label | a |
|
||||
| by_reference.cpp:110:27:110:27 | a | semmle.label | a |
|
||||
| by_reference.cpp:110:27:110:27 | inner_nested.a [a] | semmle.label | inner_nested.a [a] |
|
||||
| by_reference.cpp:114:29:114:29 | a | semmle.label | a |
|
||||
| by_reference.cpp:114:29:114:29 | a | semmle.label | a |
|
||||
| by_reference.cpp:114:29:114:29 | inner_nested.a [a] | semmle.label | inner_nested.a [a] |
|
||||
| by_reference.cpp:122:21:122:38 | Chi [inner_nested, a] | semmle.label | Chi [inner_nested, a] |
|
||||
| by_reference.cpp:122:21:122:38 | inner_nested [inner_nested, a] | semmle.label | inner_nested [inner_nested, a] |
|
||||
| by_reference.cpp:122:21:122:38 | Chi [a] | semmle.label | Chi [a] |
|
||||
| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] |
|
||||
| by_reference.cpp:126:21:126:40 | Chi [inner_nested, a] | semmle.label | Chi [inner_nested, a] |
|
||||
| by_reference.cpp:126:21:126:40 | inner_nested [inner_nested, a] | semmle.label | inner_nested [inner_nested, a] |
|
||||
| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] |
|
||||
| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] |
|
||||
| by_reference.cpp:130:27:130:27 | a | semmle.label | a |
|
||||
| by_reference.cpp:130:27:130:27 | a | semmle.label | a |
|
||||
| by_reference.cpp:130:27:130:27 | inner_nested.a [a] | semmle.label | inner_nested.a [a] |
|
||||
| by_reference.cpp:134:29:134:29 | a | semmle.label | a |
|
||||
| by_reference.cpp:134:29:134:29 | a | semmle.label | a |
|
||||
| by_reference.cpp:134:29:134:29 | inner_nested.a [a] | semmle.label | inner_nested.a [a] |
|
||||
| complex.cpp:40:17:40:17 | *b [a_] | semmle.label | *b [a_] |
|
||||
| complex.cpp:40:17:40:17 | *b [b_] | semmle.label | *b [b_] |
|
||||
| complex.cpp:40:17:40:17 | *b [inner, b_] | semmle.label | *b [inner, b_] |
|
||||
| complex.cpp:40:17:40:17 | *b [inner, f, ... (3)] | semmle.label | *b [inner, f, ... (3)] |
|
||||
| complex.cpp:40:17:40:17 | *b [inner, f, ... (5)] | semmle.label | *b [inner, f, ... (5)] |
|
||||
| complex.cpp:51:16:51:16 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] |
|
||||
| complex.cpp:51:16:51:16 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] |
|
||||
| complex.cpp:51:16:51:16 | Argument -1 indirection [inner, f, ... (3)] | semmle.label | Argument -1 indirection [inner, f, ... (3)] |
|
||||
| complex.cpp:51:16:51:16 | Chi [inner, f, ... (3)] | semmle.label | Chi [inner, f, ... (3)] |
|
||||
| complex.cpp:51:16:51:16 | a output argument [a_] | semmle.label | a output argument [a_] |
|
||||
| complex.cpp:51:16:51:16 | a output argument [b_] | semmle.label | a output argument [b_] |
|
||||
| complex.cpp:51:16:51:16 | a output argument [inner, f, ... (3)] | semmle.label | a output argument [inner, f, ... (3)] |
|
||||
| complex.cpp:51:16:51:16 | f [a_] | semmle.label | f [a_] |
|
||||
| complex.cpp:51:16:51:16 | f [b_] | semmle.label | f [b_] |
|
||||
| complex.cpp:51:16:51:16 | f [f, a_] | semmle.label | f [f, a_] |
|
||||
| complex.cpp:51:16:51:16 | f [f, b_] | semmle.label | f [f, b_] |
|
||||
| complex.cpp:51:16:51:16 | f [inner, f, ... (3)] | semmle.label | f [inner, f, ... (3)] |
|
||||
| complex.cpp:51:16:51:16 | inner.f [b_] | semmle.label | inner.f [b_] |
|
||||
| complex.cpp:51:16:51:16 | inner.f [f, a_] | semmle.label | inner.f [f, a_] |
|
||||
| complex.cpp:51:16:51:16 | inner.f [f, b_] | semmle.label | inner.f [f, b_] |
|
||||
| complex.cpp:51:16:51:16 | inner.f [f, inner, ... (4)] | semmle.label | inner.f [f, inner, ... (4)] |
|
||||
| complex.cpp:51:16:51:16 | inner.f [inner, f, ... (3)] | semmle.label | inner.f [inner, f, ... (3)] |
|
||||
| complex.cpp:51:18:51:18 | call to a | semmle.label | call to a |
|
||||
| complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] |
|
||||
| complex.cpp:52:16:52:16 | f [b_] | semmle.label | f [b_] |
|
||||
| complex.cpp:52:16:52:16 | inner.f [f, b_] | semmle.label | inner.f [f, b_] |
|
||||
| complex.cpp:52:18:52:18 | call to b | semmle.label | call to b |
|
||||
| complex.cpp:62:12:62:12 | f [f, a_] | semmle.label | f [f, a_] |
|
||||
| complex.cpp:62:12:62:12 | inner.f [inner, f, ... (3)] | semmle.label | inner.f [inner, f, ... (3)] |
|
||||
| complex.cpp:62:12:62:12 | setA output argument [a_] | semmle.label | setA output argument [a_] |
|
||||
| complex.cpp:62:19:62:28 | call to user_input | semmle.label | call to user_input |
|
||||
| complex.cpp:63:12:63:12 | f [f, b_] | semmle.label | f [f, b_] |
|
||||
| complex.cpp:63:12:63:12 | inner.f [inner, f, ... (3)] | semmle.label | inner.f [inner, f, ... (3)] |
|
||||
| complex.cpp:63:12:63:12 | setB output argument [b_] | semmle.label | setB output argument [b_] |
|
||||
| complex.cpp:63:19:63:28 | call to user_input | semmle.label | call to user_input |
|
||||
| complex.cpp:64:12:64:12 | Chi [inner, f, ... (3)] | semmle.label | Chi [inner, f, ... (3)] |
|
||||
| complex.cpp:64:12:64:12 | f [f, a_] | semmle.label | f [f, a_] |
|
||||
| complex.cpp:64:12:64:12 | inner.f [inner, f, ... (3)] | semmle.label | inner.f [inner, f, ... (3)] |
|
||||
| complex.cpp:64:12:64:12 | setA output argument [a_] | semmle.label | setA output argument [a_] |
|
||||
| complex.cpp:64:19:64:28 | call to user_input | semmle.label | call to user_input |
|
||||
| complex.cpp:65:12:65:12 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] |
|
||||
| complex.cpp:65:12:65:12 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] |
|
||||
| complex.cpp:65:12:65:12 | Argument -1 indirection [inner, f, ... (3)] | semmle.label | Argument -1 indirection [inner, f, ... (3)] |
|
||||
| complex.cpp:65:12:65:12 | f [a_] | semmle.label | f [a_] |
|
||||
| complex.cpp:65:12:65:12 | f [b_] | semmle.label | f [b_] |
|
||||
| complex.cpp:65:12:65:12 | f [b_] | semmle.label | f [b_] |
|
||||
| complex.cpp:65:12:65:12 | f [f, a_] | semmle.label | f [f, a_] |
|
||||
| complex.cpp:65:12:65:12 | f [f, b_] | semmle.label | f [f, b_] |
|
||||
| complex.cpp:65:12:65:12 | f [f, inner, ... (4)] | semmle.label | f [f, inner, ... (4)] |
|
||||
| complex.cpp:65:12:65:12 | inner.f [f, a_] | semmle.label | inner.f [f, a_] |
|
||||
| complex.cpp:65:12:65:12 | inner.f [f, b_] | semmle.label | inner.f [f, b_] |
|
||||
| complex.cpp:65:12:65:12 | inner.f [f, b_] | semmle.label | inner.f [f, b_] |
|
||||
| complex.cpp:65:12:65:12 | inner.f [inner, b_] | semmle.label | inner.f [inner, b_] |
|
||||
| complex.cpp:65:12:65:12 | inner.f [inner, f, ... (3)] | semmle.label | inner.f [inner, f, ... (3)] |
|
||||
| complex.cpp:65:12:65:12 | inner.f [inner, f, ... (5)] | semmle.label | inner.f [inner, f, ... (5)] |
|
||||
| complex.cpp:65:12:65:12 | setB output argument [a_] | semmle.label | setB output argument [a_] |
|
||||
| complex.cpp:65:12:65:12 | setB output argument [b_] | semmle.label | setB output argument [b_] |
|
||||
| complex.cpp:65:12:65:12 | setB output argument [inner, f, ... (3)] | semmle.label | setB output argument [inner, f, ... (3)] |
|
||||
| complex.cpp:65:19:65:28 | call to user_input | semmle.label | call to user_input |
|
||||
| complex.cpp:68:7:68:8 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] |
|
||||
| complex.cpp:68:7:68:8 | Argument 0 indirection [inner, f, ... (3)] | semmle.label | Argument 0 indirection [inner, f, ... (3)] |
|
||||
| complex.cpp:71:7:71:8 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] |
|
||||
| complex.cpp:71:7:71:8 | Argument 0 indirection [inner, f, ... (3)] | semmle.label | Argument 0 indirection [inner, f, ... (3)] |
|
||||
| complex.cpp:74:7:74:8 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] |
|
||||
| complex.cpp:74:7:74:8 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] |
|
||||
| complex.cpp:74:7:74:8 | Argument 0 indirection [inner, b_] | semmle.label | Argument 0 indirection [inner, b_] |
|
||||
| complex.cpp:74:7:74:8 | Argument 0 indirection [inner, f, ... (3)] | semmle.label | Argument 0 indirection [inner, f, ... (3)] |
|
||||
| complex.cpp:74:7:74:8 | Argument 0 indirection [inner, f, ... (5)] | semmle.label | Argument 0 indirection [inner, f, ... (5)] |
|
||||
| constructors.cpp:26:15:26:15 | *f [a_] | semmle.label | *f [a_] |
|
||||
| constructors.cpp:26:15:26:15 | *f [b_] | semmle.label | *f [b_] |
|
||||
| constructors.cpp:28:10:28:10 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] |
|
||||
@@ -565,82 +345,27 @@ nodes
|
||||
| simple.cpp:48:9:48:9 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] |
|
||||
| simple.cpp:51:9:51:9 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] |
|
||||
| simple.cpp:51:9:51:9 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] |
|
||||
| simple.cpp:65:5:65:22 | i [i] | semmle.label | i [i] |
|
||||
| simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] |
|
||||
| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] |
|
||||
| simple.cpp:67:13:67:13 | i | semmle.label | i |
|
||||
| simple.cpp:67:13:67:13 | i | semmle.label | i |
|
||||
| simple.cpp:83:9:83:28 | Chi [f1] | semmle.label | Chi [f1] |
|
||||
| simple.cpp:83:9:83:28 | Store | semmle.label | Store |
|
||||
| simple.cpp:83:9:83:28 | f1 [f1] | semmle.label | f1 [f1] |
|
||||
| simple.cpp:83:9:83:28 | f2.f1 [f2, f1] | semmle.label | f2.f1 [f2, f1] |
|
||||
| simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:84:14:84:20 | Argument -1 indirection [f2, f1] | semmle.label | Argument -1 indirection [f2, f1] |
|
||||
| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | semmle.label | Argument -1 indirection [f1] |
|
||||
| simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 |
|
||||
| simple.cpp:108:30:108:31 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] |
|
||||
| simple.cpp:111:18:111:18 | d1_2.y [y] | semmle.label | d1_2.y [y] |
|
||||
| simple.cpp:111:18:111:18 | y | semmle.label | y |
|
||||
| simple.cpp:111:18:111:18 | y | semmle.label | y |
|
||||
| simple.cpp:114:37:114:38 | *d2 [d1_2, y] | semmle.label | *d2 [d1_2, y] |
|
||||
| simple.cpp:117:19:117:19 | d1_2.y [y] | semmle.label | d1_2.y [y] |
|
||||
| simple.cpp:117:19:117:19 | y | semmle.label | y |
|
||||
| simple.cpp:117:19:117:19 | y | semmle.label | y |
|
||||
| simple.cpp:122:5:122:33 | Chi [d2_1, d1_1, ... (3)] | semmle.label | Chi [d2_1, d1_1, ... (3)] |
|
||||
| simple.cpp:122:5:122:33 | Store | semmle.label | Store |
|
||||
| simple.cpp:122:5:122:33 | d1_1.x [d1_1, x] | semmle.label | d1_1.x [d1_1, x] |
|
||||
| simple.cpp:122:5:122:33 | d2_1.d1_1.x [d2_1, d1_1, ... (3)] | semmle.label | d2_1.d1_1.x [d2_1, d1_1, ... (3)] |
|
||||
| simple.cpp:122:5:122:33 | x [x] | semmle.label | x [x] |
|
||||
| simple.cpp:122:22:122:31 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:123:27:123:30 | Store [d1_1, x] | semmle.label | Store [d1_1, x] |
|
||||
| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | semmle.label | d2_1 [d1_1, x] |
|
||||
| simple.cpp:124:20:124:20 | d1_1.x [x] | semmle.label | d1_1.x [x] |
|
||||
| simple.cpp:124:20:124:20 | x | semmle.label | x |
|
||||
| simple.cpp:124:20:124:20 | x | semmle.label | x |
|
||||
| simple.cpp:130:15:130:15 | d1_1.x [x] | semmle.label | d1_1.x [x] |
|
||||
| simple.cpp:130:15:130:15 | x | semmle.label | x |
|
||||
| simple.cpp:130:15:130:15 | x | semmle.label | x |
|
||||
| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | semmle.label | Chi [d2_1, d1_2, ... (3)] |
|
||||
| simple.cpp:136:21:136:28 | d2_1 [d2_1, d1_2, ... (3)] | semmle.label | d2_1 [d2_1, d1_2, ... (3)] |
|
||||
| simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | semmle.label | write_to_d1_2_y output argument [d1_2, y] |
|
||||
| simple.cpp:136:31:136:40 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:139:23:139:23 | d1_2.y [y] | semmle.label | d1_2.y [y] |
|
||||
| simple.cpp:139:23:139:23 | d2_1.d1_2.y [d1_2, y] | semmle.label | d2_1.d1_2.y [d1_2, y] |
|
||||
| simple.cpp:139:23:139:23 | y | semmle.label | y |
|
||||
| simple.cpp:139:23:139:23 | y | semmle.label | y |
|
||||
| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] |
|
||||
| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] |
|
||||
| simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | semmle.label | Argument 0 indirection [d1_2, y] |
|
||||
| simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] |
|
||||
| simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] |
|
||||
| simple.cpp:143:23:143:30 | read_from_y_deref output argument [d1_2, y] | semmle.label | read_from_y_deref output argument [d1_2, y] |
|
||||
| simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | semmle.label | Argument 0 indirection [d1_2, y] |
|
||||
| simple.cpp:159:20:159:24 | *inner [f] | semmle.label | *inner [f] |
|
||||
| simple.cpp:161:17:161:17 | f | semmle.label | f |
|
||||
| simple.cpp:161:17:161:17 | f | semmle.label | f |
|
||||
| simple.cpp:167:5:167:32 | Chi [inner, f] | semmle.label | Chi [inner, f] |
|
||||
| simple.cpp:167:5:167:32 | Store | semmle.label | Store |
|
||||
| simple.cpp:167:5:167:32 | f [f] | semmle.label | f [f] |
|
||||
| simple.cpp:167:5:167:32 | inner.f [inner, f] | semmle.label | inner.f [inner, f] |
|
||||
| simple.cpp:167:21:167:30 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:168:12:168:23 | Argument 0 indirection [f] | semmle.label | Argument 0 indirection [f] |
|
||||
| simple.cpp:168:12:168:23 | inner [f] | semmle.label | inner [f] |
|
||||
| struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] |
|
||||
| struct_init.c:15:12:15:12 | a | semmle.label | a |
|
||||
| struct_init.c:15:12:15:12 | a | semmle.label | a |
|
||||
| struct_init.c:20:20:20:29 | Chi [a] | semmle.label | Chi [a] |
|
||||
| struct_init.c:20:20:20:29 | Store | semmle.label | Store |
|
||||
| struct_init.c:20:20:20:29 | a [a] | semmle.label | a [a] |
|
||||
| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input |
|
||||
| struct_init.c:22:11:22:11 | a | semmle.label | a |
|
||||
| struct_init.c:24:10:24:12 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] |
|
||||
| struct_init.c:27:7:27:16 | Chi [nestedAB, a] | semmle.label | Chi [nestedAB, a] |
|
||||
| struct_init.c:27:7:27:16 | Chi [a] | semmle.label | Chi [a] |
|
||||
| struct_init.c:27:7:27:16 | Store | semmle.label | Store |
|
||||
| struct_init.c:27:7:27:16 | a [a] | semmle.label | a [a] |
|
||||
| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input |
|
||||
| struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | semmle.label | nestedAB.a [nestedAB, a] |
|
||||
| struct_init.c:27:21:27:21 | nestedAB.b [a] | semmle.label | nestedAB.b [a] |
|
||||
| struct_init.c:28:5:28:7 | Chi [nestedAB, a] | semmle.label | Chi [nestedAB, a] |
|
||||
| struct_init.c:31:23:31:23 | a | semmle.label | a |
|
||||
| struct_init.c:36:10:36:24 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] |
|
||||
| struct_init.c:36:10:36:24 | nestedAB [a] | semmle.label | nestedAB [a] |
|
||||
#select
|
||||
| A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | (C *)... | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | (C *)... | (C *)... |
|
||||
| A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | new | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | new | new |
|
||||
@@ -669,12 +394,8 @@ nodes
|
||||
| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input |
|
||||
| complex.cpp:51:18:51:18 | call to a | complex.cpp:62:19:62:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:62:19:62:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:51:18:51:18 | call to a | complex.cpp:63:19:63:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:63:19:63:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:51:18:51:18 | call to a | complex.cpp:64:19:64:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:64:19:64:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:51:18:51:18 | call to a | complex.cpp:65:19:65:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:65:19:65:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:52:18:52:18 | call to b | complex.cpp:62:19:62:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:62:19:62:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:52:18:52:18 | call to b | complex.cpp:63:19:63:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:63:19:63:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:52:18:52:18 | call to b | complex.cpp:64:19:64:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:64:19:64:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:52:18:52:18 | call to b | complex.cpp:65:19:65:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:65:19:65:28 | call to user_input | call to user_input |
|
||||
| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:34:11:34:20 | call to user_input | call to user_input |
|
||||
| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:36:11:36:20 | call to user_input | call to user_input |
|
||||
@@ -686,12 +407,6 @@ nodes
|
||||
| simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input |
|
||||
| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input |
|
||||
| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input |
|
||||
| simple.cpp:111:18:111:18 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:111:18:111:18 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input |
|
||||
| simple.cpp:117:19:117:19 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:117:19:117:19 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input |
|
||||
| simple.cpp:124:20:124:20 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:124:20:124:20 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input |
|
||||
| simple.cpp:130:15:130:15 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:130:15:130:15 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input |
|
||||
| simple.cpp:139:23:139:23 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:139:23:139:23 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input |
|
||||
| simple.cpp:161:17:161:17 | f | simple.cpp:167:21:167:30 | call to user_input | simple.cpp:161:17:161:17 | f | f flows from $@ | simple.cpp:167:21:167:30 | call to user_input | call to user_input |
|
||||
| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
|
||||
| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input |
|
||||
| struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
| aliasing.cpp:72:5:72:6 | m1 | AST only |
|
||||
| aliasing.cpp:79:6:79:7 | m1 | AST only |
|
||||
| aliasing.cpp:86:5:86:6 | m1 | AST only |
|
||||
| aliasing.cpp:92:3:92:3 | w | AST only |
|
||||
| aliasing.cpp:92:7:92:8 | m1 | AST only |
|
||||
| by_reference.cpp:12:8:12:8 | a | AST only |
|
||||
| by_reference.cpp:16:11:16:11 | a | AST only |
|
||||
@@ -177,13 +178,17 @@
|
||||
| by_reference.cpp:84:10:84:10 | a | AST only |
|
||||
| by_reference.cpp:88:9:88:9 | a | AST only |
|
||||
| by_reference.cpp:102:21:102:39 | & ... | AST only |
|
||||
| by_reference.cpp:102:22:102:26 | outer | AST only |
|
||||
| by_reference.cpp:103:21:103:25 | outer | AST only |
|
||||
| by_reference.cpp:103:27:103:35 | inner_ptr | AST only |
|
||||
| by_reference.cpp:104:15:104:22 | & ... | AST only |
|
||||
| by_reference.cpp:104:16:104:20 | outer | AST only |
|
||||
| by_reference.cpp:106:21:106:41 | & ... | AST only |
|
||||
| by_reference.cpp:106:22:106:27 | pouter | AST only |
|
||||
| by_reference.cpp:107:21:107:26 | pouter | AST only |
|
||||
| by_reference.cpp:107:29:107:37 | inner_ptr | AST only |
|
||||
| by_reference.cpp:108:15:108:24 | & ... | AST only |
|
||||
| by_reference.cpp:108:16:108:21 | pouter | AST only |
|
||||
| by_reference.cpp:110:8:110:12 | outer | AST only |
|
||||
| by_reference.cpp:110:14:110:25 | inner_nested | AST only |
|
||||
| by_reference.cpp:110:27:110:27 | a | AST only |
|
||||
@@ -200,13 +205,17 @@
|
||||
| by_reference.cpp:115:27:115:27 | a | AST only |
|
||||
| by_reference.cpp:116:8:116:13 | pouter | AST only |
|
||||
| by_reference.cpp:116:16:116:16 | a | AST only |
|
||||
| by_reference.cpp:122:21:122:25 | outer | AST only |
|
||||
| by_reference.cpp:122:27:122:38 | inner_nested | AST only |
|
||||
| by_reference.cpp:123:21:123:36 | * ... | AST only |
|
||||
| by_reference.cpp:123:22:123:26 | outer | AST only |
|
||||
| by_reference.cpp:124:15:124:19 | outer | AST only |
|
||||
| by_reference.cpp:124:21:124:21 | a | AST only |
|
||||
| by_reference.cpp:126:21:126:26 | pouter | AST only |
|
||||
| by_reference.cpp:126:29:126:40 | inner_nested | AST only |
|
||||
| by_reference.cpp:127:21:127:38 | * ... | AST only |
|
||||
| by_reference.cpp:127:22:127:27 | pouter | AST only |
|
||||
| by_reference.cpp:128:15:128:20 | pouter | AST only |
|
||||
| by_reference.cpp:128:23:128:23 | a | AST only |
|
||||
| by_reference.cpp:130:8:130:12 | outer | AST only |
|
||||
| by_reference.cpp:130:14:130:25 | inner_nested | AST only |
|
||||
@@ -226,11 +235,23 @@
|
||||
| by_reference.cpp:136:16:136:16 | a | AST only |
|
||||
| complex.cpp:11:22:11:23 | a_ | AST only |
|
||||
| complex.cpp:12:22:12:23 | b_ | AST only |
|
||||
| complex.cpp:51:8:51:8 | b | AST only |
|
||||
| complex.cpp:51:10:51:14 | inner | AST only |
|
||||
| complex.cpp:51:16:51:16 | f | AST only |
|
||||
| complex.cpp:52:8:52:8 | b | AST only |
|
||||
| complex.cpp:52:10:52:14 | inner | AST only |
|
||||
| complex.cpp:52:16:52:16 | f | AST only |
|
||||
| complex.cpp:62:3:62:4 | b1 | AST only |
|
||||
| complex.cpp:62:6:62:10 | inner | AST only |
|
||||
| complex.cpp:62:12:62:12 | f | AST only |
|
||||
| complex.cpp:63:3:63:4 | b2 | AST only |
|
||||
| complex.cpp:63:6:63:10 | inner | AST only |
|
||||
| complex.cpp:63:12:63:12 | f | AST only |
|
||||
| complex.cpp:64:3:64:4 | b3 | AST only |
|
||||
| complex.cpp:64:6:64:10 | inner | AST only |
|
||||
| complex.cpp:64:12:64:12 | f | AST only |
|
||||
| complex.cpp:65:3:65:4 | b3 | AST only |
|
||||
| complex.cpp:65:6:65:10 | inner | AST only |
|
||||
| complex.cpp:65:12:65:12 | f | AST only |
|
||||
| complex.cpp:68:7:68:8 | b1 | AST only |
|
||||
| complex.cpp:71:7:71:8 | b2 | AST only |
|
||||
@@ -296,15 +317,9 @@
|
||||
| simple.cpp:51:9:51:9 | h | AST only |
|
||||
| simple.cpp:54:9:54:9 | i | AST only |
|
||||
| simple.cpp:65:7:65:7 | i | AST only |
|
||||
| simple.cpp:83:9:83:10 | this | AST only |
|
||||
| simple.cpp:83:12:83:13 | f1 | AST only |
|
||||
| simple.cpp:84:14:84:20 | this | AST only |
|
||||
| simple.cpp:105:14:105:14 | y | AST only |
|
||||
| simple.cpp:122:18:122:18 | x | AST only |
|
||||
| simple.cpp:136:21:136:28 | & ... | AST only |
|
||||
| simple.cpp:143:23:143:30 | & ... | AST only |
|
||||
| simple.cpp:144:23:144:30 | & ... | AST only |
|
||||
| simple.cpp:167:17:167:17 | f | AST only |
|
||||
| simple.cpp:168:12:168:23 | & ... | AST only |
|
||||
| struct_init.c:15:8:15:9 | ab | AST only |
|
||||
| struct_init.c:15:12:15:12 | a | AST only |
|
||||
| struct_init.c:16:8:16:9 | ab | AST only |
|
||||
@@ -327,5 +342,6 @@
|
||||
| struct_init.c:34:14:34:22 | pointerAB | AST only |
|
||||
| struct_init.c:34:25:34:25 | b | AST only |
|
||||
| struct_init.c:36:10:36:24 | & ... | AST only |
|
||||
| struct_init.c:36:11:36:15 | outer | AST only |
|
||||
| struct_init.c:46:10:46:14 | outer | AST only |
|
||||
| struct_init.c:46:16:46:24 | pointerAB | AST only |
|
||||
|
||||
@@ -23,38 +23,15 @@
|
||||
| aliasing.cpp:54:3:54:4 | s2 |
|
||||
| aliasing.cpp:60:3:60:4 | s2 |
|
||||
| aliasing.cpp:72:3:72:3 | s |
|
||||
| aliasing.cpp:78:11:78:11 | w |
|
||||
| aliasing.cpp:79:3:79:3 | s |
|
||||
| aliasing.cpp:85:10:85:10 | w |
|
||||
| aliasing.cpp:86:3:86:3 | s |
|
||||
| aliasing.cpp:92:3:92:3 | w |
|
||||
| aliasing.cpp:92:5:92:5 | s |
|
||||
| by_reference.cpp:12:5:12:5 | s |
|
||||
| by_reference.cpp:16:5:16:8 | this |
|
||||
| by_reference.cpp:84:3:84:7 | inner |
|
||||
| by_reference.cpp:88:3:88:7 | inner |
|
||||
| by_reference.cpp:102:22:102:26 | outer |
|
||||
| by_reference.cpp:104:16:104:20 | outer |
|
||||
| by_reference.cpp:106:22:106:27 | pouter |
|
||||
| by_reference.cpp:108:16:108:21 | pouter |
|
||||
| by_reference.cpp:122:21:122:25 | outer |
|
||||
| by_reference.cpp:124:15:124:19 | outer |
|
||||
| by_reference.cpp:126:21:126:26 | pouter |
|
||||
| by_reference.cpp:128:15:128:20 | pouter |
|
||||
| complex.cpp:11:22:11:23 | this |
|
||||
| complex.cpp:12:22:12:23 | this |
|
||||
| complex.cpp:51:8:51:8 | b |
|
||||
| complex.cpp:51:10:51:14 | inner |
|
||||
| complex.cpp:52:8:52:8 | b |
|
||||
| complex.cpp:52:10:52:14 | inner |
|
||||
| complex.cpp:62:3:62:4 | b1 |
|
||||
| complex.cpp:62:6:62:10 | inner |
|
||||
| complex.cpp:63:3:63:4 | b2 |
|
||||
| complex.cpp:63:6:63:10 | inner |
|
||||
| complex.cpp:64:3:64:4 | b3 |
|
||||
| complex.cpp:64:6:64:10 | inner |
|
||||
| complex.cpp:65:3:65:4 | b3 |
|
||||
| complex.cpp:65:6:65:10 | inner |
|
||||
| constructors.cpp:20:24:20:25 | this |
|
||||
| constructors.cpp:21:24:21:25 | this |
|
||||
| qualifiers.cpp:9:30:9:33 | this |
|
||||
@@ -64,16 +41,3 @@
|
||||
| simple.cpp:21:24:21:25 | this |
|
||||
| simple.cpp:65:5:65:5 | a |
|
||||
| simple.cpp:83:9:83:10 | f2 |
|
||||
| simple.cpp:83:9:83:10 | this |
|
||||
| simple.cpp:105:5:105:6 | d2 |
|
||||
| simple.cpp:105:9:105:12 | d1_2 |
|
||||
| simple.cpp:122:5:122:6 | d3 |
|
||||
| simple.cpp:122:8:122:11 | d2_1 |
|
||||
| simple.cpp:122:13:122:16 | d1_1 |
|
||||
| simple.cpp:136:22:136:23 | d3 |
|
||||
| simple.cpp:143:24:143:25 | d3 |
|
||||
| simple.cpp:144:24:144:25 | d3 |
|
||||
| simple.cpp:167:5:167:9 | outer |
|
||||
| simple.cpp:167:11:167:15 | inner |
|
||||
| simple.cpp:168:13:168:17 | outer |
|
||||
| struct_init.c:36:11:36:15 | outer |
|
||||
|
||||
@@ -363,24 +363,6 @@
|
||||
| simple.cpp:83:9:83:10 | this |
|
||||
| simple.cpp:83:12:83:13 | f1 |
|
||||
| simple.cpp:84:14:84:20 | this |
|
||||
| simple.cpp:105:5:105:6 | d2 |
|
||||
| simple.cpp:105:9:105:12 | d1_2 |
|
||||
| simple.cpp:105:14:105:14 | y |
|
||||
| simple.cpp:122:5:122:6 | d3 |
|
||||
| simple.cpp:122:8:122:11 | d2_1 |
|
||||
| simple.cpp:122:13:122:16 | d1_1 |
|
||||
| simple.cpp:122:18:122:18 | x |
|
||||
| simple.cpp:136:21:136:28 | & ... |
|
||||
| simple.cpp:136:22:136:23 | d3 |
|
||||
| simple.cpp:143:23:143:30 | & ... |
|
||||
| simple.cpp:143:24:143:25 | d3 |
|
||||
| simple.cpp:144:23:144:30 | & ... |
|
||||
| simple.cpp:144:24:144:25 | d3 |
|
||||
| simple.cpp:167:5:167:9 | outer |
|
||||
| simple.cpp:167:11:167:15 | inner |
|
||||
| simple.cpp:167:17:167:17 | f |
|
||||
| simple.cpp:168:12:168:23 | & ... |
|
||||
| simple.cpp:168:13:168:17 | outer |
|
||||
| struct_init.c:15:8:15:9 | ab |
|
||||
| struct_init.c:15:12:15:12 | a |
|
||||
| struct_init.c:16:8:16:9 | ab |
|
||||
|
||||
@@ -332,48 +332,6 @@ edges
|
||||
| simple.cpp:83:9:83:28 | ... = ... | simple.cpp:83:9:83:10 | f2 [post update] [f1] |
|
||||
| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | ... = ... |
|
||||
| simple.cpp:84:14:84:20 | this [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 |
|
||||
| simple.cpp:108:30:108:31 | d2 [d1_2, y] | simple.cpp:111:10:111:11 | d2 [d1_2, y] |
|
||||
| simple.cpp:111:10:111:11 | d2 [d1_2, y] | simple.cpp:111:13:111:16 | d1_2 [y] |
|
||||
| simple.cpp:111:13:111:16 | d1_2 [y] | simple.cpp:111:18:111:18 | y |
|
||||
| simple.cpp:114:37:114:38 | d2 [d1_2, y] | simple.cpp:117:10:117:11 | d2 [d1_2, y] |
|
||||
| simple.cpp:117:10:117:11 | d2 [d1_2, y] | simple.cpp:117:14:117:17 | d1_2 [y] |
|
||||
| simple.cpp:117:14:117:17 | d1_2 [y] | simple.cpp:117:19:117:19 | y |
|
||||
| simple.cpp:122:5:122:6 | d3 [post update] [d2_1, d1_1, ... (3)] | simple.cpp:123:24:123:25 | d3 [d2_1, d1_1, ... (3)] |
|
||||
| simple.cpp:122:5:122:33 | ... = ... | simple.cpp:122:13:122:16 | d1_1 [post update] [x] |
|
||||
| simple.cpp:122:8:122:11 | d2_1 [post update] [d1_1, x] | simple.cpp:122:5:122:6 | d3 [post update] [d2_1, d1_1, ... (3)] |
|
||||
| simple.cpp:122:13:122:16 | d1_1 [post update] [x] | simple.cpp:122:8:122:11 | d2_1 [post update] [d1_1, x] |
|
||||
| simple.cpp:122:22:122:31 | call to user_input | simple.cpp:122:5:122:33 | ... = ... |
|
||||
| simple.cpp:123:24:123:25 | d3 [d2_1, d1_1, ... (3)] | simple.cpp:123:27:123:30 | d2_1 [d1_1, x] |
|
||||
| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | simple.cpp:124:10:124:13 | d2_1 [d1_1, x] |
|
||||
| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | simple.cpp:129:25:129:28 | d2_1 [d1_1, x] |
|
||||
| simple.cpp:124:10:124:13 | d2_1 [d1_1, x] | simple.cpp:124:15:124:18 | d1_1 [x] |
|
||||
| simple.cpp:124:15:124:18 | d1_1 [x] | simple.cpp:124:20:124:20 | x |
|
||||
| simple.cpp:129:25:129:28 | d2_1 [d1_1, x] | simple.cpp:129:30:129:33 | d1_1 [x] |
|
||||
| simple.cpp:129:30:129:33 | d1_1 [x] | simple.cpp:130:10:130:12 | pd1 [x] |
|
||||
| simple.cpp:130:10:130:12 | pd1 [x] | simple.cpp:130:15:130:15 | x |
|
||||
| simple.cpp:136:21:136:28 | ref arg & ... [d1_2, y] | simple.cpp:136:25:136:28 | d2_1 [inner post update] [d1_2, y] |
|
||||
| simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | simple.cpp:139:10:139:11 | d3 [d2_1, d1_2, ... (3)] |
|
||||
| simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | simple.cpp:141:17:141:18 | d3 [d2_1, d1_2, ... (3)] |
|
||||
| simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | simple.cpp:143:24:143:25 | d3 [d2_1, d1_2, ... (3)] |
|
||||
| simple.cpp:136:25:136:28 | d2_1 [inner post update] [d1_2, y] | simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] |
|
||||
| simple.cpp:136:31:136:40 | call to user_input | simple.cpp:136:21:136:28 | ref arg & ... [d1_2, y] |
|
||||
| simple.cpp:139:10:139:11 | d3 [d2_1, d1_2, ... (3)] | simple.cpp:139:13:139:16 | d2_1 [d1_2, y] |
|
||||
| simple.cpp:139:13:139:16 | d2_1 [d1_2, y] | simple.cpp:139:18:139:21 | d1_2 [y] |
|
||||
| simple.cpp:139:18:139:21 | d1_2 [y] | simple.cpp:139:23:139:23 | y |
|
||||
| simple.cpp:141:17:141:18 | d3 [d2_1, d1_2, ... (3)] | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] |
|
||||
| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | simple.cpp:108:30:108:31 | d2 [d1_2, y] |
|
||||
| simple.cpp:143:23:143:30 | & ... [d1_2, y] | simple.cpp:114:37:114:38 | d2 [d1_2, y] |
|
||||
| simple.cpp:143:24:143:25 | d3 [d2_1, d1_2, ... (3)] | simple.cpp:143:27:143:30 | d2_1 [d1_2, y] |
|
||||
| simple.cpp:143:27:143:30 | d2_1 [d1_2, y] | simple.cpp:143:23:143:30 | & ... [d1_2, y] |
|
||||
| simple.cpp:159:20:159:24 | inner [f] | simple.cpp:161:10:161:14 | inner [f] |
|
||||
| simple.cpp:161:10:161:14 | inner [f] | simple.cpp:161:17:161:17 | f |
|
||||
| simple.cpp:167:5:167:9 | outer [post update] [inner, f] | simple.cpp:168:13:168:17 | outer [inner, f] |
|
||||
| simple.cpp:167:5:167:32 | ... = ... | simple.cpp:167:11:167:15 | inner [post update] [f] |
|
||||
| simple.cpp:167:11:167:15 | inner [post update] [f] | simple.cpp:167:5:167:9 | outer [post update] [inner, f] |
|
||||
| simple.cpp:167:21:167:30 | call to user_input | simple.cpp:167:5:167:32 | ... = ... |
|
||||
| simple.cpp:168:12:168:23 | & ... [f] | simple.cpp:159:20:159:24 | inner [f] |
|
||||
| simple.cpp:168:13:168:17 | outer [inner, f] | simple.cpp:168:19:168:23 | inner [f] |
|
||||
| simple.cpp:168:19:168:23 | inner [f] | simple.cpp:168:12:168:23 | & ... [f] |
|
||||
| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] |
|
||||
| struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a |
|
||||
| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] |
|
||||
@@ -774,51 +732,6 @@ nodes
|
||||
| simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 |
|
||||
| simple.cpp:84:14:84:20 | this [f2, f1] | semmle.label | this [f2, f1] |
|
||||
| simple.cpp:108:30:108:31 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] |
|
||||
| simple.cpp:111:10:111:11 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] |
|
||||
| simple.cpp:111:13:111:16 | d1_2 [y] | semmle.label | d1_2 [y] |
|
||||
| simple.cpp:111:18:111:18 | y | semmle.label | y |
|
||||
| simple.cpp:114:37:114:38 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] |
|
||||
| simple.cpp:117:10:117:11 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] |
|
||||
| simple.cpp:117:14:117:17 | d1_2 [y] | semmle.label | d1_2 [y] |
|
||||
| simple.cpp:117:19:117:19 | y | semmle.label | y |
|
||||
| simple.cpp:122:5:122:6 | d3 [post update] [d2_1, d1_1, ... (3)] | semmle.label | d3 [post update] [d2_1, d1_1, ... (3)] |
|
||||
| simple.cpp:122:5:122:33 | ... = ... | semmle.label | ... = ... |
|
||||
| simple.cpp:122:8:122:11 | d2_1 [post update] [d1_1, x] | semmle.label | d2_1 [post update] [d1_1, x] |
|
||||
| simple.cpp:122:13:122:16 | d1_1 [post update] [x] | semmle.label | d1_1 [post update] [x] |
|
||||
| simple.cpp:122:22:122:31 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:123:24:123:25 | d3 [d2_1, d1_1, ... (3)] | semmle.label | d3 [d2_1, d1_1, ... (3)] |
|
||||
| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | semmle.label | d2_1 [d1_1, x] |
|
||||
| simple.cpp:124:10:124:13 | d2_1 [d1_1, x] | semmle.label | d2_1 [d1_1, x] |
|
||||
| simple.cpp:124:15:124:18 | d1_1 [x] | semmle.label | d1_1 [x] |
|
||||
| simple.cpp:124:20:124:20 | x | semmle.label | x |
|
||||
| simple.cpp:129:25:129:28 | d2_1 [d1_1, x] | semmle.label | d2_1 [d1_1, x] |
|
||||
| simple.cpp:129:30:129:33 | d1_1 [x] | semmle.label | d1_1 [x] |
|
||||
| simple.cpp:130:10:130:12 | pd1 [x] | semmle.label | pd1 [x] |
|
||||
| simple.cpp:130:15:130:15 | x | semmle.label | x |
|
||||
| simple.cpp:136:21:136:28 | ref arg & ... [d1_2, y] | semmle.label | ref arg & ... [d1_2, y] |
|
||||
| simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | semmle.label | d3 [post update] [d2_1, d1_2, ... (3)] |
|
||||
| simple.cpp:136:25:136:28 | d2_1 [inner post update] [d1_2, y] | semmle.label | d2_1 [inner post update] [d1_2, y] |
|
||||
| simple.cpp:136:31:136:40 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:139:10:139:11 | d3 [d2_1, d1_2, ... (3)] | semmle.label | d3 [d2_1, d1_2, ... (3)] |
|
||||
| simple.cpp:139:13:139:16 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] |
|
||||
| simple.cpp:139:18:139:21 | d1_2 [y] | semmle.label | d1_2 [y] |
|
||||
| simple.cpp:139:23:139:23 | y | semmle.label | y |
|
||||
| simple.cpp:141:17:141:18 | d3 [d2_1, d1_2, ... (3)] | semmle.label | d3 [d2_1, d1_2, ... (3)] |
|
||||
| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] |
|
||||
| simple.cpp:143:23:143:30 | & ... [d1_2, y] | semmle.label | & ... [d1_2, y] |
|
||||
| simple.cpp:143:24:143:25 | d3 [d2_1, d1_2, ... (3)] | semmle.label | d3 [d2_1, d1_2, ... (3)] |
|
||||
| simple.cpp:143:27:143:30 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] |
|
||||
| simple.cpp:159:20:159:24 | inner [f] | semmle.label | inner [f] |
|
||||
| simple.cpp:161:10:161:14 | inner [f] | semmle.label | inner [f] |
|
||||
| simple.cpp:161:17:161:17 | f | semmle.label | f |
|
||||
| simple.cpp:167:5:167:9 | outer [post update] [inner, f] | semmle.label | outer [post update] [inner, f] |
|
||||
| simple.cpp:167:5:167:32 | ... = ... | semmle.label | ... = ... |
|
||||
| simple.cpp:167:11:167:15 | inner [post update] [f] | semmle.label | inner [post update] [f] |
|
||||
| simple.cpp:167:21:167:30 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:168:12:168:23 | & ... [f] | semmle.label | & ... [f] |
|
||||
| simple.cpp:168:13:168:17 | outer [inner, f] | semmle.label | outer [inner, f] |
|
||||
| simple.cpp:168:19:168:23 | inner [f] | semmle.label | inner [f] |
|
||||
| struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] |
|
||||
| struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] |
|
||||
| struct_init.c:15:12:15:12 | a | semmle.label | a |
|
||||
@@ -917,12 +830,6 @@ nodes
|
||||
| simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input |
|
||||
| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input |
|
||||
| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input |
|
||||
| simple.cpp:111:18:111:18 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:111:18:111:18 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input |
|
||||
| simple.cpp:117:19:117:19 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:117:19:117:19 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input |
|
||||
| simple.cpp:124:20:124:20 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:124:20:124:20 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input |
|
||||
| simple.cpp:130:15:130:15 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:130:15:130:15 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input |
|
||||
| simple.cpp:139:23:139:23 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:139:23:139:23 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input |
|
||||
| simple.cpp:161:17:161:17 | f | simple.cpp:167:21:167:30 | call to user_input | simple.cpp:161:17:161:17 | f | f flows from $@ | simple.cpp:167:21:167:30 | call to user_input | call to user_input |
|
||||
| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
|
||||
| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input |
|
||||
| struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input |
|
||||
|
||||
@@ -85,87 +85,4 @@ struct C2
|
||||
}
|
||||
};
|
||||
|
||||
struct DeepStruct1 {
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
struct DeepStruct2 {
|
||||
DeepStruct1 d1_1;
|
||||
DeepStruct1 d1_2;
|
||||
};
|
||||
|
||||
struct DeepStruct3 {
|
||||
DeepStruct2 d2_1;
|
||||
DeepStruct2 d2_2;
|
||||
DeepStruct1 d1_1;
|
||||
};
|
||||
|
||||
void write_to_d1_2_y(DeepStruct2* d2, int val) {
|
||||
d2->d1_2.y = val;
|
||||
}
|
||||
|
||||
void read_from_y(DeepStruct2 d2) {
|
||||
sink(d2.d1_1.y);
|
||||
|
||||
sink(d2.d1_2.y); //$ast,ir
|
||||
}
|
||||
|
||||
void read_from_y_deref(DeepStruct2* d2) {
|
||||
sink(d2->d1_1.y);
|
||||
|
||||
sink(d2->d1_2.y); //$ast,ir
|
||||
}
|
||||
|
||||
void test_deep_structs() {
|
||||
DeepStruct3 d3;
|
||||
d3.d2_1.d1_1.x = user_input();
|
||||
DeepStruct2 d2_1 = d3.d2_1;
|
||||
sink(d2_1.d1_1.x); //$ast,ir
|
||||
sink(d2_1.d1_1.y);
|
||||
|
||||
sink(d2_1.d1_2.x);
|
||||
|
||||
DeepStruct1* pd1 = &d2_1.d1_1;
|
||||
sink(pd1->x); //$ast,ir
|
||||
}
|
||||
|
||||
void test_deep_structs_setter() {
|
||||
DeepStruct3 d3;
|
||||
|
||||
write_to_d1_2_y(&d3.d2_1, user_input());
|
||||
|
||||
sink(d3.d2_1.d1_1.y);
|
||||
sink(d3.d2_1.d1_2.y); //$ast,ir
|
||||
|
||||
read_from_y(d3.d2_1);
|
||||
read_from_y(d3.d2_2);
|
||||
read_from_y_deref(&d3.d2_1);
|
||||
read_from_y_deref(&d3.d2_2);
|
||||
}
|
||||
|
||||
struct Inner
|
||||
{
|
||||
int f;
|
||||
int g;
|
||||
};
|
||||
|
||||
struct Outer
|
||||
{
|
||||
Inner inner;
|
||||
int h;
|
||||
};
|
||||
|
||||
void read_f(Inner *inner)
|
||||
{
|
||||
sink(inner->f); //$ast,ir
|
||||
}
|
||||
|
||||
void test()
|
||||
{
|
||||
Outer outer;
|
||||
outer.inner.f = user_input();
|
||||
read_f(&outer.inner);
|
||||
}
|
||||
|
||||
} // namespace Simple
|
||||
|
||||
@@ -188,6 +188,17 @@
|
||||
| stl.cpp:131:15:131:24 | call to user_input | stl.cpp:131:15:131:27 | call to basic_string | TAINT |
|
||||
| stl.cpp:131:15:131:27 | call to basic_string | stl.cpp:132:7:132:11 | path3 | |
|
||||
| stl.cpp:132:7:132:11 | path3 | stl.cpp:132:13:132:17 | call to c_str | TAINT |
|
||||
| stl.cpp:137:19:137:24 | call to source | stl.cpp:140:17:140:18 | cs | |
|
||||
| stl.cpp:137:19:137:24 | call to source | stl.cpp:142:7:142:8 | cs | |
|
||||
| stl.cpp:140:17:140:18 | cs | stl.cpp:140:17:140:19 | call to basic_string | TAINT |
|
||||
| stl.cpp:140:17:140:19 | call to basic_string | stl.cpp:143:7:143:8 | ss | |
|
||||
| stl.cpp:148:19:148:24 | call to source | stl.cpp:151:17:151:18 | cs | |
|
||||
| stl.cpp:151:17:151:18 | cs | stl.cpp:151:17:151:19 | call to basic_string | TAINT |
|
||||
| stl.cpp:151:17:151:19 | call to basic_string | stl.cpp:154:7:154:8 | ss | |
|
||||
| stl.cpp:151:17:151:19 | call to basic_string | stl.cpp:157:7:157:8 | ss | |
|
||||
| stl.cpp:154:7:154:8 | ss | stl.cpp:154:10:154:14 | call to c_str | TAINT |
|
||||
| stl.cpp:154:10:154:14 | call to c_str | stl.cpp:154:2:154:16 | ... = ... | |
|
||||
| stl.cpp:154:10:154:14 | call to c_str | stl.cpp:156:7:156:8 | cs | |
|
||||
| swap1.cpp:14:17:14:17 | t | swap1.cpp:14:17:14:17 | t | |
|
||||
| swap1.cpp:14:17:14:17 | t | swap1.cpp:14:17:14:17 | t | |
|
||||
| swap1.cpp:14:17:14:17 | t | swap1.cpp:14:56:14:56 | t | |
|
||||
|
||||
@@ -131,3 +131,28 @@ void test_strings2()
|
||||
string path3(user_input());
|
||||
sink(path3.c_str(), "r"); // tainted
|
||||
}
|
||||
|
||||
void test_string3()
|
||||
{
|
||||
const char *cs = source();
|
||||
|
||||
// convert char * -> std::string
|
||||
std::string ss(cs);
|
||||
|
||||
sink(cs); // tainted
|
||||
sink(ss); // tainted
|
||||
}
|
||||
|
||||
void test_string4()
|
||||
{
|
||||
const char *cs = source();
|
||||
|
||||
// convert char * -> std::string
|
||||
std::string ss(cs);
|
||||
|
||||
// convert back std::string -> char *
|
||||
cs = ss.c_str();
|
||||
|
||||
sink(cs); // tainted
|
||||
sink(ss); // tainted
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
| stl.cpp:125:13:125:17 | call to c_str | stl.cpp:117:10:117:15 | call to source |
|
||||
| stl.cpp:129:13:129:17 | call to c_str | stl.cpp:117:10:117:15 | call to source |
|
||||
| stl.cpp:132:13:132:17 | call to c_str | stl.cpp:117:10:117:15 | call to source |
|
||||
| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:24 | call to source |
|
||||
| stl.cpp:143:7:143:8 | ss | stl.cpp:137:19:137:24 | call to source |
|
||||
| stl.cpp:156:7:156:8 | cs | stl.cpp:148:19:148:24 | call to source |
|
||||
| stl.cpp:157:7:157:8 | ss | stl.cpp:148:19:148:24 | call to source |
|
||||
| swap1.cpp:60:12:60:16 | data1 | swap1.cpp:58:15:58:20 | call to source |
|
||||
| swap1.cpp:65:12:65:16 | data1 | swap1.cpp:58:15:58:20 | call to source |
|
||||
| swap1.cpp:66:12:66:16 | data1 | swap1.cpp:58:15:58:20 | call to source |
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
| stl.cpp:125:13:125:17 | stl.cpp:117:10:117:15 | AST only |
|
||||
| stl.cpp:129:13:129:17 | stl.cpp:117:10:117:15 | AST only |
|
||||
| stl.cpp:132:13:132:17 | stl.cpp:117:10:117:15 | AST only |
|
||||
| stl.cpp:142:7:142:8 | stl.cpp:137:19:137:26 | IR only |
|
||||
| stl.cpp:143:7:143:8 | stl.cpp:137:19:137:24 | AST only |
|
||||
| stl.cpp:156:7:156:8 | stl.cpp:148:19:148:24 | AST only |
|
||||
| stl.cpp:157:7:157:8 | stl.cpp:148:19:148:24 | AST only |
|
||||
| swap1.cpp:74:13:74:17 | swap1.cpp:69:16:69:21 | AST only |
|
||||
| swap1.cpp:75:13:75:17 | swap1.cpp:68:27:68:28 | AST only |
|
||||
| swap1.cpp:89:12:89:16 | swap1.cpp:80:23:80:23 | AST only |
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
| format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source |
|
||||
| stl.cpp:71:7:71:7 | (const char *)... | stl.cpp:67:12:67:17 | call to source |
|
||||
| stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source |
|
||||
| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:24 | call to source |
|
||||
| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:26 | (const char *)... |
|
||||
| swap1.cpp:60:12:60:16 | data1 | swap1.cpp:58:15:58:20 | call to source |
|
||||
| swap1.cpp:65:12:65:16 | data1 | swap1.cpp:58:15:58:20 | call to source |
|
||||
| swap1.cpp:66:12:66:16 | data1 | swap1.cpp:58:15:58:20 | call to source |
|
||||
|
||||
@@ -659,10 +659,10 @@ unreachableNodeCCtx
|
||||
localCallNodes
|
||||
postIsNotPre
|
||||
postHasUniquePre
|
||||
| assignexpr.cpp:9:2:9:12 | i | PostUpdateNode should have one pre-update node but has 0. |
|
||||
| bad_asts.cpp:15:10:15:12 | x | PostUpdateNode should have one pre-update node but has 0. |
|
||||
| cpp11.cpp:65:19:65:45 | x | PostUpdateNode should have one pre-update node but has 0. |
|
||||
| ir.cpp:531:14:531:14 | d | PostUpdateNode should have one pre-update node but has 0. |
|
||||
| assignexpr.cpp:9:2:9:12 | Store | PostUpdateNode should have one pre-update node but has 0. |
|
||||
| bad_asts.cpp:15:10:15:12 | Store | PostUpdateNode should have one pre-update node but has 0. |
|
||||
| cpp11.cpp:65:19:65:45 | Store | PostUpdateNode should have one pre-update node but has 0. |
|
||||
| ir.cpp:531:14:531:14 | Store | PostUpdateNode should have one pre-update node but has 0. |
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
|
||||
@@ -2,3 +2,5 @@
|
||||
- qlpack: codeql-csharp
|
||||
- apply: code-scanning-selectors.yml
|
||||
from: codeql-suite-helpers
|
||||
- apply: codeql-suites/exclude-dependency-queries.yml
|
||||
from: codeql-csharp
|
||||
|
||||
@@ -2,3 +2,5 @@
|
||||
- qlpack: codeql-csharp
|
||||
- apply: security-and-quality-selectors.yml
|
||||
from: codeql-suite-helpers
|
||||
- apply: codeql-suites/exclude-dependency-queries.yml
|
||||
from: codeql-csharp
|
||||
|
||||
@@ -2,3 +2,5 @@
|
||||
- qlpack: codeql-csharp
|
||||
- apply: security-extended-selectors.yml
|
||||
from: codeql-suite-helpers
|
||||
- apply: codeql-suites/exclude-dependency-queries.yml
|
||||
from: codeql-csharp
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
- description: C# queries which overlap with dependency analysis
|
||||
- exclude:
|
||||
query path:
|
||||
- Security Features/CWE-937/VulnerablePackage.ql
|
||||
@@ -111,6 +111,8 @@ private class IRSizedType extends IRType {
|
||||
this = TIRFunctionAddressType(byteSize) or
|
||||
this = TIROpaqueType(_, byteSize)
|
||||
}
|
||||
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
|
||||
// overridden only in the leaf classes.
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,7 +130,7 @@ class IRBooleanType extends IRSizedType, TIRBooleanType {
|
||||
}
|
||||
|
||||
/**
|
||||
* A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and
|
||||
* A numeric type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and
|
||||
* `IRFloatingPointType`.
|
||||
*/
|
||||
class IRNumericType extends IRSizedType {
|
||||
@@ -137,13 +139,27 @@ class IRNumericType extends IRSizedType {
|
||||
this = TIRUnsignedIntegerType(byteSize) or
|
||||
this = TIRFloatingPointType(byteSize, _, _)
|
||||
}
|
||||
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
|
||||
// overridden only in the leaf classes.
|
||||
}
|
||||
|
||||
/**
|
||||
* An integer type. This includes `IRSignedIntegerType` and `IRUnsignedIntegerType`.
|
||||
*/
|
||||
class IRIntegerType extends IRNumericType {
|
||||
IRIntegerType() {
|
||||
this = TIRSignedIntegerType(byteSize) or
|
||||
this = TIRUnsignedIntegerType(byteSize)
|
||||
}
|
||||
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
|
||||
// overridden only in the leaf classes.
|
||||
}
|
||||
|
||||
/**
|
||||
* A signed two's-complement integer. Also used to represent enums whose underlying type is a signed
|
||||
* integer, as well as character types whose representation is signed.
|
||||
*/
|
||||
class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType {
|
||||
class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType {
|
||||
final override string toString() { result = "int" + byteSize.toString() }
|
||||
|
||||
final override Language::LanguageType getCanonicalLanguageType() {
|
||||
@@ -158,7 +174,7 @@ class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType {
|
||||
* An unsigned two's-complement integer. Also used to represent enums whose underlying type is an
|
||||
* unsigned integer, as well as character types whose representation is unsigned.
|
||||
*/
|
||||
class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType {
|
||||
class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType {
|
||||
final override string toString() { result = "uint" + byteSize.toString() }
|
||||
|
||||
final override Language::LanguageType getCanonicalLanguageType() {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Provides a stub implementation of the required aliased SSA interface until we implement aliased
|
||||
* SSA construction for C#.
|
||||
*/
|
||||
|
||||
private import IRFunctionBase
|
||||
private import TInstruction
|
||||
|
||||
module SSA {
|
||||
class MemoryLocation = boolean;
|
||||
|
||||
predicate hasPhiInstruction(TRawInstruction blockStartInstr, MemoryLocation memoryLocation) {
|
||||
none()
|
||||
}
|
||||
|
||||
predicate hasChiInstruction(TRawInstruction primaryInstruction) { none() }
|
||||
|
||||
predicate hasUnreachedInstruction(IRFunctionBase irFunc) { none() }
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Provides a base class, `IRFunctionBase`, for the stage-independent portions of `IRFunction`.
|
||||
*/
|
||||
|
||||
private import IRFunctionBaseInternal
|
||||
|
||||
private newtype TIRFunction =
|
||||
MkIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) }
|
||||
|
||||
/**
|
||||
* The IR for a function. This base class contains only the predicates that are the same between all
|
||||
* phases of the IR. Each instantiation of `IRFunction` extends this class.
|
||||
*/
|
||||
class IRFunctionBase extends TIRFunction {
|
||||
Language::Function func;
|
||||
|
||||
IRFunctionBase() { this = MkIRFunction(func) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = "IR: " + func.toString() }
|
||||
|
||||
/** Gets the function whose IR is represented. */
|
||||
final Language::Function getFunction() { result = func }
|
||||
|
||||
/** Gets the location of the function. */
|
||||
final Language::Location getLocation() { result = func.getLocation() }
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
import experimental.ir.internal.IRCSharpLanguage as Language
|
||||
import experimental.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||
@@ -1,5 +1,5 @@
|
||||
import experimental.ir.internal.IRCSharpLanguage as Language
|
||||
import experimental.ir.implementation.raw.internal.IRConstruction as Construction
|
||||
import experimental.ir.implementation.raw.internal.IRConstruction::Raw as Construction
|
||||
private import experimental.ir.implementation.TempVariableTag as TempVariableTag_
|
||||
|
||||
module Imports {
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
private import TInstructionInternal
|
||||
private import IRFunctionBase
|
||||
private import TInstructionImports as Imports
|
||||
private import Imports::IRType
|
||||
private import Imports::Opcode
|
||||
|
||||
/**
|
||||
* An IR instruction. `TInstruction` is shared across all phases of the IR. There are individual
|
||||
* branches of this type for instructions created directly from the AST (`TRawInstruction`) and for
|
||||
* instructions added by each stage of SSA construction (`T*PhiInstruction`, `T*ChiInstruction`,
|
||||
* `T*UnreachedInstruction`). Each stage then defines a `TStageInstruction` type that is a union of
|
||||
* all of the branches that can appear in that particular stage. The public `Instruction` class for
|
||||
* each phase extends the `TStageInstruction` type for that stage.
|
||||
*/
|
||||
cached
|
||||
newtype TInstruction =
|
||||
TRawInstruction(
|
||||
IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2
|
||||
) {
|
||||
IRConstruction::Raw::hasInstruction(tag1, tag2)
|
||||
} or
|
||||
TUnaliasedSSAPhiInstruction(
|
||||
TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation
|
||||
) {
|
||||
UnaliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
||||
} or
|
||||
TUnaliasedSSAChiInstruction(TRawInstruction primaryInstruction) { none() } or
|
||||
TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) {
|
||||
UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc)
|
||||
} or
|
||||
TAliasedSSAPhiInstruction(
|
||||
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
|
||||
) {
|
||||
AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
||||
} or
|
||||
TAliasedSSAChiInstruction(TRawInstruction primaryInstruction) {
|
||||
AliasedSSA::SSA::hasChiInstruction(primaryInstruction)
|
||||
} or
|
||||
TAliasedSSAUnreachedInstruction(IRFunctionBase irFunc) {
|
||||
AliasedSSA::SSA::hasUnreachedInstruction(irFunc)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides wrappers for the constructors of each branch of `TInstruction` that is used by the
|
||||
* unaliased SSA stage.
|
||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||
* a class alias.
|
||||
*/
|
||||
module UnaliasedSSAInstructions {
|
||||
class TPhiInstruction = TUnaliasedSSAPhiInstruction;
|
||||
|
||||
TPhiInstruction phiInstruction(
|
||||
TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation
|
||||
) {
|
||||
result = TUnaliasedSSAPhiInstruction(blockStartInstr, memoryLocation)
|
||||
}
|
||||
|
||||
class TChiInstruction = TUnaliasedSSAChiInstruction;
|
||||
|
||||
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
|
||||
result = TUnaliasedSSAChiInstruction(primaryInstruction)
|
||||
}
|
||||
|
||||
class TUnreachedInstruction = TUnaliasedSSAUnreachedInstruction;
|
||||
|
||||
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
|
||||
result = TUnaliasedSSAUnreachedInstruction(irFunc)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides wrappers for the constructors of each branch of `TInstruction` that is used by the
|
||||
* aliased SSA stage.
|
||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||
* a class alias.
|
||||
*/
|
||||
module AliasedSSAInstructions {
|
||||
class TPhiInstruction = TAliasedSSAPhiInstruction;
|
||||
|
||||
TPhiInstruction phiInstruction(
|
||||
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
|
||||
) {
|
||||
result = TAliasedSSAPhiInstruction(blockStartInstr, memoryLocation)
|
||||
}
|
||||
|
||||
class TChiInstruction = TAliasedSSAChiInstruction;
|
||||
|
||||
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
|
||||
result = TAliasedSSAChiInstruction(primaryInstruction)
|
||||
}
|
||||
|
||||
class TUnreachedInstruction = TAliasedSSAUnreachedInstruction;
|
||||
|
||||
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
|
||||
result = TAliasedSSAUnreachedInstruction(irFunc)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
import experimental.ir.implementation.IRType as IRType
|
||||
import experimental.ir.implementation.Opcode as Opcode
|
||||
@@ -0,0 +1,4 @@
|
||||
import experimental.ir.internal.IRCSharpLanguage as Language
|
||||
import experimental.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||
import experimental.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSSA
|
||||
import AliasedSSAStub as AliasedSSA
|
||||
@@ -1,29 +1,12 @@
|
||||
private import internal.IRInternal
|
||||
private import internal.IRFunctionImports as Imports
|
||||
import Imports::IRFunctionBase
|
||||
import Instruction
|
||||
|
||||
private newtype TIRFunction =
|
||||
MkIRFunction(Language::Function func) { Construction::functionHasIR(func) }
|
||||
|
||||
/**
|
||||
* Represents the IR for a function.
|
||||
* The IR for a function.
|
||||
*/
|
||||
class IRFunction extends TIRFunction {
|
||||
Language::Function func;
|
||||
|
||||
IRFunction() { this = MkIRFunction(func) }
|
||||
|
||||
final string toString() { result = "IR: " + func.toString() }
|
||||
|
||||
/**
|
||||
* Gets the function whose IR is represented.
|
||||
*/
|
||||
final Language::Function getFunction() { result = func }
|
||||
|
||||
/**
|
||||
* Gets the location of the function.
|
||||
*/
|
||||
final Language::Location getLocation() { result = func.getLocation() }
|
||||
|
||||
class IRFunction extends IRFunctionBase {
|
||||
/**
|
||||
* Gets the entry point for this function.
|
||||
*/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user