Merge remote-tracking branch 'upstream/master' into loginjection

This commit is contained in:
ubuntu
2020-06-24 19:15:27 +02:00
326 changed files with 12406 additions and 7552 deletions

4
.github/codeql/codeql-config.yml vendored Normal file
View File

@@ -0,0 +1,4 @@
name: "CodeQL config"
queries:
- uses: security-and-quality

52
.github/workflows/codeql-analysis.yml vendored Normal file
View 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

View File

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

View File

@@ -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"

View File

@@ -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
)
}

View File

@@ -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

View File

@@ -1,3 +1,7 @@
/**
* Provides the `Initializer` class, representing C/C++ declaration initializers.
*/
import semmle.code.cpp.controlflow.ControlFlowGraph
/**

View File

@@ -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) }
}

View File

@@ -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

View File

@@ -1,3 +1,7 @@
/**
* Provides classes and predicates for locations in the source code.
*/
import semmle.code.cpp.Element
import semmle.code.cpp.File

View 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()
}

View File

@@ -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

View File

@@ -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 }
}

View File

@@ -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

View File

@@ -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))
* ```
*

View File

@@ -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))
* ```
*

View File

@@ -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 }
}

View File

@@ -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
}
/**

View File

@@ -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]

View File

@@ -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))
* ```
*

View File

@@ -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))
* ```
*

View File

@@ -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() {

View File

@@ -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.
*/

View File

@@ -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 }

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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() }
}

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction

View File

@@ -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 {

View File

@@ -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)
}
}

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.implementation.IRType as IRType
import semmle.code.cpp.ir.implementation.Opcode as Opcode

View File

@@ -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

View File

@@ -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.
*/

View File

@@ -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 }

View File

@@ -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

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase

View File

@@ -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

View File

@@ -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() }
/**

View File

@@ -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

View File

@@ -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.
*/

View File

@@ -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 }

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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()
/**

View File

@@ -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 }
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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" }

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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
}
}
/**

View File

@@ -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 &lt;&lt; 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

View File

@@ -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 |

View 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]
}

View File

@@ -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 *)... |

View File

@@ -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 |

View File

@@ -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

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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

View File

@@ -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 | |

View File

@@ -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
}

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,4 @@
- description: C# queries which overlap with dependency analysis
- exclude:
query path:
- Security Features/CWE-937/VulnerablePackage.ql

View File

@@ -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() {

View File

@@ -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() }
}

View File

@@ -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() }
}

View File

@@ -0,0 +1,2 @@
import experimental.ir.internal.IRCSharpLanguage as Language
import experimental.ir.implementation.raw.internal.IRConstruction as IRConstruction

View File

@@ -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 {

View File

@@ -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)
}
}

View File

@@ -0,0 +1,2 @@
import experimental.ir.implementation.IRType as IRType
import experimental.ir.implementation.Opcode as Opcode

View File

@@ -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

View File

@@ -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