Compare commits

..

1 Commits

Author SHA1 Message Date
Tamas Vajk
a484766dbd C#: enable buildless mode 2024-04-09 17:56:03 +01:00
1860 changed files with 274415 additions and 45288 deletions

5
.gitattributes vendored
View File

@@ -67,6 +67,11 @@ go/extractor/opencsv/CSVReader.java -text
# for those testing dbscheme files.
*/ql/lib/upgrades/initial/*.dbscheme -text
# Generated test files - these are synced from the standard JavaScript libraries using
# `javascript/ql/experimental/adaptivethreatmodeling/test/update_endpoint_test_files.py`.
javascript/ql/experimental/adaptivethreatmodeling/test/endpoint_large_scale/autogenerated/**/*.js linguist-generated=true -merge
javascript/ql/experimental/adaptivethreatmodeling/test/endpoint_large_scale/autogenerated/**/*.ts linguist-generated=true -merge
# Auto-generated modeling for Python
python/ql/lib/semmle/python/frameworks/data/internal/subclass-capture/*.yml linguist-generated=true

5
.github/labeler.yml vendored
View File

@@ -15,7 +15,7 @@ Java:
- change-notes/**/*java.*
JS:
- any: [ 'javascript/**/*' ]
- any: [ 'javascript/**/*', '!javascript/ql/experimental/adaptivethreatmodeling/**/*' ]
- change-notes/**/*javascript*
Kotlin:
@@ -46,3 +46,6 @@ documentation:
# Since these are all shared files that need to be synced, just pick _one_ copy of each.
"DataFlow Library":
- "shared/dataflow/**/*"
"ATM":
- javascript/ql/experimental/adaptivethreatmodeling/**/*

View File

@@ -6,7 +6,6 @@ on:
- "swift/**"
- "misc/bazel/**"
- "misc/codegen/**"
- "shared/**"
- "*.bazel*"
- .github/workflows/swift.yml
- .github/actions/**
@@ -23,12 +22,10 @@ on:
- "swift/**"
- "misc/bazel/**"
- "misc/codegen/**"
- "shared/**"
- "*.bazel*"
- .github/workflows/swift.yml
- .github/actions/**
- codeql-workspace.yml
- .pre-commit-config.yaml
- "!**/*.md"
- "!**/*.qhelp"
branches:

View File

@@ -12,6 +12,9 @@
/java/ql/test-kotlin1/ @github/codeql-kotlin
/java/ql/test-kotlin2/ @github/codeql-kotlin
# ML-powered queries
/javascript/ql/experimental/adaptivethreatmodeling/ @github/codeql-ml-powered-queries-reviewers
# CodeQL tools and associated docs
/docs/codeql/codeql-cli/ @github/codeql-cli-reviewers
/docs/codeql/codeql-for-visual-studio-code/ @github/codeql-vscode-reviewers
@@ -34,7 +37,9 @@ MODULE.bazel @github/codeql-ci-reviewers
# Workflows
/.github/workflows/ @github/codeql-ci-reviewers
/.github/workflows/atm-* @github/codeql-ml-powered-queries-reviewers
/.github/workflows/go-* @github/codeql-go
/.github/workflows/js-ml-tests.yml @github/codeql-ml-powered-queries-reviewers
/.github/workflows/ql-for-ql-* @github/codeql-ql-for-ql-reviewers
/.github/workflows/ruby-* @github/codeql-ruby
/.github/workflows/swift.yml @github/codeql-swift

View File

@@ -14,7 +14,7 @@ local_path_override(
# see https://registry.bazel.build/ for a list of available packages
bazel_dep(name = "platforms", version = "0.0.8")
bazel_dep(name = "rules_pkg", version = "0.10.1")
bazel_dep(name = "rules_pkg", version = "0.9.1")
bazel_dep(name = "rules_nodejs", version = "6.0.3")
bazel_dep(name = "rules_python", version = "0.31.0")
bazel_dep(name = "bazel_skylib", version = "1.5.0")
@@ -31,8 +31,6 @@ pip.parse(
use_repo(pip, "codegen_deps")
swift_deps = use_extension("//swift/third_party:load.bzl", "swift_deps")
# following list can be kept in sync with `bazel mod tidy`
use_repo(
swift_deps,
"binlog",

View File

@@ -11,6 +11,16 @@ provide:
- "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml"
- "go/ql/config/legacy-support/qlpack.yml"
- "go/build/codeql-extractor-go/codeql-extractor.yml"
- "javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml"
# This pack is explicitly excluded from the workspace since most users
# will want to use a version of this pack from the package cache. Internal
# users can uncomment the following line and place a custom ML model
# in the corresponding pack to test a custom ML model within their local
# checkout.
# - "javascript/ql/experimental/adaptivethreatmodeling/model/qlpack.yml"
- "javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml"
- "javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml"
- "javascript/ql/experimental/adaptivethreatmodeling/test/qlpack.yml"
- "csharp/ql/campaigns/Solorigate/lib/qlpack.yml"
- "csharp/ql/campaigns/Solorigate/src/qlpack.yml"
- "csharp/ql/campaigns/Solorigate/test/qlpack.yml"

View File

@@ -1,4 +1,4 @@
load("@rules_pkg//pkg:mappings.bzl", "pkg_filegroup")
load("@rules_pkg//:mappings.bzl", "pkg_filegroup")
package(default_visibility = ["//visibility:public"])

View File

@@ -1,4 +1,4 @@
load("@rules_pkg//pkg:mappings.bzl", "pkg_files", "strip_prefix")
load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
pkg_files(
name = "downgrades",

View File

@@ -1,4 +1,4 @@
load("@rules_pkg//pkg:mappings.bzl", "pkg_files")
load("@rules_pkg//:mappings.bzl", "pkg_files")
package(default_visibility = ["//cpp:__pkg__"])

View File

@@ -1,7 +1,3 @@
## 0.12.11
No user-facing changes.
## 0.12.10
### New Features

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The alias analysis used internally by various libraries has been improved to answer alias questions more conservatively. As a result, some queries may report fewer false positives.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Parameters of functions without definitions now have `ParameterNode`s.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Source models have been added for the standard library function `getc` (and variations).

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* Models-as-Data support has been added for C/C++. This feature allows flow sources, sinks and summaries to be expressed in compact strings as an alternative to modelling each source / sink / summary with explicit QL. See `dataflow/ExternalFlow.qll` for documentation and specification of the model format, and `models/implementations/ZMQ.qll` for a simple example of models. Importing models from `.yml` is not yet supported.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Source, sink and flow models for the ZeroMQ (ZMQ) networking library have been added.

View File

@@ -1,3 +0,0 @@
## 0.12.11
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.12.11
lastReleaseVersion: 0.12.10

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 0.12.12-dev
version: 0.12.11-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
@@ -7,10 +7,8 @@ library: true
upgrades: upgrades
dependencies:
codeql/dataflow: ${workspace}
codeql/mad: ${workspace}
codeql/rangeanalysis: ${workspace}
codeql/ssa: ${workspace}
codeql/typeflow: ${workspace}
codeql/tutorial: ${workspace}
codeql/util: ${workspace}
codeql/xml: ${workspace}

View File

@@ -364,8 +364,6 @@ class ConversionNode extends ExprNode {
childIndex = 0 and
result.getAst() = conv.getExpr() and
conv.getExpr() instanceof Conversion
or
result.getAst() = expr.getImplicitDestructorCall(childIndex - 1)
}
}

View File

@@ -1,556 +0,0 @@
/**
* INTERNAL use only. This is an experimental API subject to change without notice.
*
* Provides classes and predicates for dealing with flow models specified in CSV format.
*
* The CSV specification has the following columns:
* - Sources:
* `namespace; type; subtypes; name; signature; ext; output; kind`
* - Sinks:
* `namespace; type; subtypes; name; signature; ext; input; kind`
* - Summaries:
* `namespace; type; subtypes; name; signature; ext; input; output; kind`
*
* The interpretation of a row is similar to API-graphs with a left-to-right
* reading.
* 1. The `namespace` column selects a namespace.
* 2. The `type` column selects a type within that namespace.
* 3. The `subtypes` is a boolean that indicates whether to jump to an
* arbitrary subtype of that type. Set this to `false` if leaving the `type`
* blank (for example, a free function).
* 4. The `name` column optionally selects a specific named member of the type.
* 5. The `signature` column optionally restricts the named member. If
* `signature` is blank then no such filtering is done. The format of the
* signature is a comma-separated list of types enclosed in parentheses. The
* types can be short names or fully qualified names (mixing these two options
* is not allowed within a single signature).
* 6. The `ext` column specifies additional API-graph-like edges. Currently
* there is only one valid value: "".
* 7. The `input` column specifies how data enters the element selected by the
* first 6 columns, and the `output` column specifies how data leaves the
* element selected by the first 6 columns. An `input` can be either:
* - "": Selects a write to the selected element in case this is a field.
* - "Argument[n]": Selects an argument in a call to the selected element.
* The arguments are zero-indexed, and `-1` specifies the qualifier object,
* that is, `*this`.
* - one or more "*" can be added in front of the argument index to indicate
* indirection, for example, `Argument[*0]` indicates the first indirection
* of the 0th argument.
* - `n1..n2` syntax can be used to indicate a range of arguments, inclusive
* at both ends. One or more "*"s can be added in front of the whole range
* to indicate that every argument in the range is indirect, for example
* `*0..1` is the first indirection of both arguments 0 and 1.
* - "ReturnValue": Selects a value being returned by the selected element.
* One or more "*" can be added as an argument to indicate indirection, for
* example, "ReturnValue[*]" indicates the first indirection of the return
* value.
*
* An `output` can be either:
* - "": Selects a read of a selected field.
* - "Argument[n]": Selects the post-update value of an argument in a call to
* the selected element. That is, the value of the argument after the call
* returns. The arguments are zero-indexed, and `-1` specifies the qualifier
* object, that is, `*this`.
* - one or more "*" can be added in front of the argument index to indicate
* indirection, for example, `Argument[*0]` indicates the first indirection
* of the 0th argument.
* - `n1..n2` syntax can be used to indicate a range of arguments, inclusive
* at both ends. One or more "*"s can be added in front of the whole range
* to indicate that every argument in the range is indirect, for example
* `*0..1` is the first indirection of both arguments 0 and 1.
* - "Parameter[n]": Selects the value of a parameter of the selected element.
* The syntax is the same as for "Argument", for example "Parameter[0]",
* "Parameter[*0]", "Parameter[0..2]" etc.
* - "ReturnValue": Selects a value being returned by the selected element.
* One or more "*" can be added as an argument to indicate indirection, for
* example, "ReturnValue[*]" indicates the first indirection of the return
* value.
* 8. The `kind` column is a tag that can be referenced from QL to determine to
* which classes the interpreted elements should be added. For example, for
* sources "remote" indicates a default remote flow source, and for summaries
* "taint" indicates a default additional taint step and "value" indicates a
* globally applicable value-preserving step.
*/
import cpp
private import new.DataFlow
private import internal.FlowSummaryImpl
private import internal.FlowSummaryImpl::Public
private import internal.FlowSummaryImpl::Private
private import internal.FlowSummaryImpl::Private::External
private import codeql.mad.ModelValidation as SharedModelVal
private import codeql.util.Unit
/**
* A unit class for adding additional source model rows.
*
* Extend this class to add additional source definitions.
*/
class SourceModelCsv extends Unit {
/** Holds if `row` specifies a source definition. */
abstract predicate row(string row);
}
/**
* A unit class for adding additional sink model rows.
*
* Extend this class to add additional sink definitions.
*/
class SinkModelCsv extends Unit {
/** Holds if `row` specifies a sink definition. */
abstract predicate row(string row);
}
/**
* A unit class for adding additional summary model rows.
*
* Extend this class to add additional flow summary definitions.
*/
class SummaryModelCsv extends Unit {
/** Holds if `row` specifies a summary definition. */
abstract predicate row(string row);
}
/** Holds if `row` is a source model. */
predicate sourceModel(string row) { any(SourceModelCsv s).row(row) }
/** Holds if `row` is a sink model. */
predicate sinkModel(string row) { any(SinkModelCsv s).row(row) }
/** Holds if `row` is a summary model. */
predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
/** Holds if a source model exists for the given parameters. */
predicate sourceModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string output, string kind, string provenance
) {
exists(string row |
sourceModel(row) and
row.splitAt(";", 0) = namespace and
row.splitAt(";", 1) = type and
row.splitAt(";", 2) = subtypes.toString() and
subtypes = [true, false] and
row.splitAt(";", 3) = name and
row.splitAt(";", 4) = signature and
row.splitAt(";", 5) = ext and
row.splitAt(";", 6) = output and
row.splitAt(";", 7) = kind
) and
provenance = "manual"
}
/** Holds if a sink model exists for the given parameters. */
predicate sinkModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string input, string kind, string provenance
) {
exists(string row |
sinkModel(row) and
row.splitAt(";", 0) = namespace and
row.splitAt(";", 1) = type and
row.splitAt(";", 2) = subtypes.toString() and
subtypes = [true, false] and
row.splitAt(";", 3) = name and
row.splitAt(";", 4) = signature and
row.splitAt(";", 5) = ext and
row.splitAt(";", 6) = input and
row.splitAt(";", 7) = kind
) and
provenance = "manual"
}
/** Holds if a summary model exists for the given parameters. */
predicate summaryModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, string provenance
) {
exists(string row |
summaryModel(row) and
row.splitAt(";", 0) = namespace and
row.splitAt(";", 1) = type and
row.splitAt(";", 2) = subtypes.toString() and
subtypes = [true, false] and
row.splitAt(";", 3) = name and
row.splitAt(";", 4) = signature and
row.splitAt(";", 5) = ext and
row.splitAt(";", 6) = input and
row.splitAt(";", 7) = output and
row.splitAt(";", 8) = kind
) and
provenance = "manual"
}
private predicate relevantNamespace(string namespace) {
sourceModel(namespace, _, _, _, _, _, _, _, _) or
sinkModel(namespace, _, _, _, _, _, _, _, _) or
summaryModel(namespace, _, _, _, _, _, _, _, _, _)
}
private predicate namespaceLink(string shortns, string longns) {
relevantNamespace(shortns) and
relevantNamespace(longns) and
longns.prefix(longns.indexOf("::")) = shortns
}
private predicate canonicalNamespace(string namespace) {
relevantNamespace(namespace) and not namespaceLink(_, namespace)
}
private predicate canonicalNamespaceLink(string namespace, string subns) {
canonicalNamespace(namespace) and
(subns = namespace or namespaceLink(namespace, subns))
}
/**
* Holds if CSV framework coverage of `namespace` is `n` api endpoints of the
* kind `(kind, part)`.
*/
predicate modelCoverage(string namespace, int namespaces, string kind, string part, int n) {
namespaces = strictcount(string subns | canonicalNamespaceLink(namespace, subns)) and
(
part = "source" and
n =
strictcount(string subns, string type, boolean subtypes, string name, string signature,
string ext, string output, string provenance |
canonicalNamespaceLink(namespace, subns) and
sourceModel(subns, type, subtypes, name, signature, ext, output, kind, provenance)
)
or
part = "sink" and
n =
strictcount(string subns, string type, boolean subtypes, string name, string signature,
string ext, string input, string provenance |
canonicalNamespaceLink(namespace, subns) and
sinkModel(subns, type, subtypes, name, signature, ext, input, kind, provenance)
)
or
part = "summary" and
n =
strictcount(string subns, string type, boolean subtypes, string name, string signature,
string ext, string input, string output, string provenance |
canonicalNamespaceLink(namespace, subns) and
summaryModel(subns, type, subtypes, name, signature, ext, input, output, kind, provenance)
)
)
}
/** Provides a query predicate to check the CSV data for validation errors. */
module CsvValidation {
private string getInvalidModelInput() {
exists(string pred, AccessPath input, string part |
sinkModel(_, _, _, _, _, _, input, _, _) and pred = "sink"
or
summaryModel(_, _, _, _, _, _, input, _, _, _) and pred = "summary"
|
(
invalidSpecComponent(input, part) and
not part = "" and
not (part = "Argument" and pred = "sink") and
not parseArg(part, _)
or
part = input.getToken(_) and
parseParam(part, _)
) and
result = "Unrecognized input specification \"" + part + "\" in " + pred + " model."
)
}
private string getInvalidModelOutput() {
exists(string pred, string output, string part |
sourceModel(_, _, _, _, _, _, output, _, _) and pred = "source"
or
summaryModel(_, _, _, _, _, _, _, output, _, _) and pred = "summary"
|
invalidSpecComponent(output, part) and
not part = "" and
not (part = ["Argument", "Parameter"] and pred = "source") and
result = "Unrecognized output specification \"" + part + "\" in " + pred + " model."
)
}
private module KindValConfig implements SharedModelVal::KindValidationConfigSig {
predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) }
predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) }
predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) }
}
private module KindVal = SharedModelVal::KindValidation<KindValConfig>;
private string getInvalidModelSubtype() {
exists(string pred, string row |
sourceModel(row) and pred = "source"
or
sinkModel(row) and pred = "sink"
or
summaryModel(row) and pred = "summary"
|
exists(string b |
b = row.splitAt(";", 2) and
not b = ["true", "false"] and
result = "Invalid boolean \"" + b + "\" in " + pred + " model."
)
)
}
private string getInvalidModelColumnCount() {
exists(string pred, string row, int expect |
sourceModel(row) and expect = 8 and pred = "source"
or
sinkModel(row) and expect = 8 and pred = "sink"
or
summaryModel(row) and expect = 9 and pred = "summary"
|
exists(int cols |
cols = 1 + max(int n | exists(row.splitAt(";", n))) and
cols != expect and
result =
"Wrong number of columns in " + pred + " model row, expected " + expect + ", got " + cols +
"."
)
)
}
private string getInvalidModelSignature() {
exists(string pred, string namespace, string type, string name, string signature, string ext |
sourceModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "source"
or
sinkModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "sink"
or
summaryModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "summary"
|
not namespace.regexpMatch("[a-zA-Z0-9_\\.]+") and
result = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
or
not type.regexpMatch("[a-zA-Z0-9_<>,\\+]+") and
result = "Dubious type \"" + type + "\" in " + pred + " model."
or
not name.regexpMatch("[a-zA-Z0-9_<>,]*") and
result = "Dubious member name \"" + name + "\" in " + pred + " model."
or
not signature.regexpMatch("|\\([a-zA-Z0-9_<>\\.\\+\\*,\\[\\]]*\\)") and
result = "Dubious signature \"" + signature + "\" in " + pred + " model."
or
not ext.regexpMatch("|Attribute") and
result = "Unrecognized extra API graph element \"" + ext + "\" in " + pred + " model."
)
}
/** Holds if some row in a CSV-based flow model appears to contain typos. */
query predicate invalidModelRow(string msg) {
msg =
[
getInvalidModelSignature(), getInvalidModelInput(), getInvalidModelOutput(),
getInvalidModelSubtype(), getInvalidModelColumnCount(), KindVal::getInvalidModelKind()
]
}
}
private predicate elementSpec(
string namespace, string type, boolean subtypes, string name, string signature, string ext
) {
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _) or
sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _) or
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _)
}
private string paramsStringPart(Function c, int i) {
i = -1 and result = "(" and exists(c)
or
exists(int n, string p | c.getParameter(n).getType().toString() = p |
i = 2 * n and result = p
or
i = 2 * n - 1 and result = "," and n != 0
)
or
i = 2 * c.getNumberOfParameters() and result = ")"
}
/**
* Gets a parenthesized string containing all parameter types of this callable, separated by a comma.
*
* Returns the empty string if the callable has no parameters.
* Parameter types are represented by their type erasure.
*/
cached
private string paramsString(Function c) {
result = concat(int i | | paramsStringPart(c, i) order by i)
}
bindingset[func]
private predicate matchesSignature(Function func, string signature) {
signature = "" or
paramsString(func) = signature
}
/**
* Gets the element in module `namespace` that satisfies the following properties:
* 1. If the element is a member of a class-like type, then the class-like type has name `type`
* 2. If `subtypes = true` and the element is a member of a class-like type, then overrides of the element
* are also returned.
* 3. The element has name `name`
* 4. If `signature` is non-empty, then the element has a list of parameter types described by `signature`.
*
* NOTE: `namespace` is currently not used (since we don't properly extract modules yet).
*/
pragma[nomagic]
private Element interpretElement0(
string namespace, string type, boolean subtypes, string name, string signature
) {
elementSpec(namespace, type, subtypes, name, signature, _) and
(
// Non-member functions
exists(Function func |
func.hasQualifiedName(namespace, name) and
type = "" and
matchesSignature(func, signature) and
subtypes = false and
not exists(func.getDeclaringType()) and
result = func
)
or
// Member functions
exists(Class namedClass, Class classWithMethod, Function method |
classWithMethod = method.getClassAndName(name) and
namedClass.hasQualifiedName(namespace, type) and
matchesSignature(method, signature) and
result = method
|
// member declared in the named type or a subtype of it
subtypes = true and
classWithMethod = namedClass.getADerivedClass*()
or
// member declared directly in the named type
subtypes = false and
classWithMethod = namedClass
)
or
// Member variables
signature = "" and
exists(Class namedClass, Class classWithMember, MemberVariable member |
member.getName() = name and
member = classWithMember.getAMember() and
namedClass.hasQualifiedName(namespace, type) and
result = member
|
// field declared in the named type or a subtype of it (or an extension of any)
subtypes = true and
classWithMember = namedClass.getADerivedClass*()
or
// field declared directly in the named type (or an extension of it)
subtypes = false and
classWithMember = namedClass
)
or
// Global or namespace variables
signature = "" and
type = "" and
subtypes = false and
result = any(GlobalOrNamespaceVariable v | v.hasQualifiedName(namespace, name))
)
}
/** Gets the source/sink/summary element corresponding to the supplied parameters. */
Element interpretElement(
string namespace, string type, boolean subtypes, string name, string signature, string ext
) {
elementSpec(namespace, type, subtypes, name, signature, ext) and
exists(Element e | e = interpretElement0(namespace, type, subtypes, name, signature) |
ext = "" and result = e
)
}
cached
private module Cached {
/**
* Holds if `node` is specified as a source with the given kind in a CSV flow
* model.
*/
cached
predicate sourceNode(DataFlow::Node node, string kind) {
exists(SourceSinkInterpretationInput::InterpretNode n |
isSourceNode(n, kind, _) and n.asNode() = node // TODO
)
}
/**
* Holds if `node` is specified as a sink with the given kind in a CSV flow
* model.
*/
cached
predicate sinkNode(DataFlow::Node node, string kind) {
exists(SourceSinkInterpretationInput::InterpretNode n |
isSinkNode(n, kind, _) and n.asNode() = node // TODO
)
}
}
import Cached
private predicate interpretSummary(
Function f, string input, string output, string kind, string provenance
) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance) and
f = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}
// adapter class for converting Mad summaries to `SummarizedCallable`s
private class SummarizedCallableAdapter extends SummarizedCallable {
SummarizedCallableAdapter() { interpretSummary(this, _, _, _, _) }
private predicate relevantSummaryElementManual(string input, string output, string kind) {
exists(Provenance provenance |
interpretSummary(this, input, output, kind, provenance) and
provenance.isManual()
)
}
private predicate relevantSummaryElementGenerated(string input, string output, string kind) {
exists(Provenance provenance |
interpretSummary(this, input, output, kind, provenance) and
provenance.isGenerated()
)
}
override predicate propagatesFlow(
string input, string output, boolean preservesValue, string model
) {
exists(string kind |
this.relevantSummaryElementManual(input, output, kind)
or
not this.relevantSummaryElementManual(_, _, _) and
this.relevantSummaryElementGenerated(input, output, kind)
|
if kind = "value" then preservesValue = true else preservesValue = false
) and
model = "" // TODO
}
override predicate hasProvenance(Provenance provenance) {
interpretSummary(this, _, _, _, provenance)
}
}
// adapter class for converting Mad neutrals to `NeutralCallable`s
private class NeutralCallableAdapter extends NeutralCallable {
string kind;
string provenance_;
NeutralCallableAdapter() {
// Neutral models have not been implemented for CPP.
none() and
exists(this) and
exists(kind) and
exists(provenance_)
}
override string getKind() { result = kind }
override predicate hasProvenance(Provenance provenance) { provenance = provenance_ }
}

View File

@@ -263,10 +263,9 @@ deprecated private module Config implements FullStateConfigSig {
predicate isBarrierOut(Node node, FlowState state) { none() }
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
predicate isAdditionalFlowStep(Node node1, Node node2) {
singleConfiguration() and
any(Configuration config).isAdditionalFlowStep(node1, node2) and
model = ""
any(Configuration config).isAdditionalFlowStep(node1, node2)
}
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {

View File

@@ -263,10 +263,9 @@ deprecated private module Config implements FullStateConfigSig {
predicate isBarrierOut(Node node, FlowState state) { none() }
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
predicate isAdditionalFlowStep(Node node1, Node node2) {
singleConfiguration() and
any(Configuration config).isAdditionalFlowStep(node1, node2) and
model = ""
any(Configuration config).isAdditionalFlowStep(node1, node2)
}
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {

View File

@@ -263,10 +263,9 @@ deprecated private module Config implements FullStateConfigSig {
predicate isBarrierOut(Node node, FlowState state) { none() }
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
predicate isAdditionalFlowStep(Node node1, Node node2) {
singleConfiguration() and
any(Configuration config).isAdditionalFlowStep(node1, node2) and
model = ""
any(Configuration config).isAdditionalFlowStep(node1, node2)
}
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {

View File

@@ -263,10 +263,9 @@ deprecated private module Config implements FullStateConfigSig {
predicate isBarrierOut(Node node, FlowState state) { none() }
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
predicate isAdditionalFlowStep(Node node1, Node node2) {
singleConfiguration() and
any(Configuration config).isAdditionalFlowStep(node1, node2) and
model = ""
any(Configuration config).isAdditionalFlowStep(node1, node2)
}
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {

View File

@@ -263,10 +263,9 @@ deprecated private module Config implements FullStateConfigSig {
predicate isBarrierOut(Node node, FlowState state) { none() }
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
predicate isAdditionalFlowStep(Node node1, Node node2) {
singleConfiguration() and
any(Configuration config).isAdditionalFlowStep(node1, node2) and
model = ""
any(Configuration config).isAdditionalFlowStep(node1, node2)
}
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {

View File

@@ -286,12 +286,6 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { no
/** Extra data-flow steps needed for lambda flow analysis. */
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
predicate knownSourceModel(Node source, string model) { none() }
predicate knownSinkModel(Node sink, string model) { none() }
class DataFlowSecondLevelScope = Unit;
/**
* Holds if flow is allowed to pass from parameter `p` and back to itself as a
* side-effect, resulting in a summary from `p` to itself.

View File

@@ -516,7 +516,7 @@ private module ThisFlow {
*/
cached
predicate localFlowStep(Node nodeFrom, Node nodeTo) {
simpleLocalFlowStep(nodeFrom, nodeTo, _)
simpleLocalFlowStep(nodeFrom, nodeTo)
or
// Field flow is not strictly a "step" but covers the whole function
// transitively. There's no way to get a step-like relation out of the global
@@ -530,67 +530,64 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) {
* This is the local flow predicate that's used as a building block in global
* data flow. It may have less flow than the `localFlowStep` predicate.
*/
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
(
// Expr -> Expr
exprToExprStep_nocfg(nodeFrom.asExpr(), nodeTo.asExpr())
or
// Assignment -> LValue post-update node
//
// This is used for assignments whose left-hand side is not a variable
// assignment or a storeStep but is still modeled by other means. It could be
// a call to `operator*` or `operator[]` where taint should flow to the
// post-update node of the qualifier.
exists(AssignExpr assign |
nodeFrom.asExpr() = assign and
nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() = assign.getLValue()
)
or
// Node -> FlowVar -> VariableAccess
exists(FlowVar var |
(
exprToVarStep(nodeFrom.asExpr(), var)
or
varSourceBaseCase(var, nodeFrom.asParameter())
or
varSourceBaseCase(var, nodeFrom.asUninitialized())
or
var.definedPartiallyAt(nodeFrom.asPartialDefinition())
) and
varToNodeStep(var, nodeTo)
)
or
// Expr -> DefinitionByReferenceNode
exprToDefinitionByReferenceStep(nodeFrom.asExpr(), nodeTo.asDefiningArgument())
or
// `this` -> adjacent-`this`
ThisFlow::adjacentThisRefs(nodeFrom, nodeTo)
or
// post-update-`this` -> following-`this`-ref
ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
or
// In `f(&x->a)`, this step provides the flow from post-`&` to post-`x->a`,
// from which there is field flow to `x` via reverse read.
exists(PartialDefinition def, Expr inner, Expr outer |
def.definesExpressions(inner, outer) and
inner = nodeTo.(InnerPartialDefinitionNode).getPreUpdateNode().asExpr() and
outer = nodeFrom.(PartialDefinitionNode).getPreUpdateNode().asExpr()
)
or
// Reverse flow: data that flows from the post-update node of a reference
// returned by a function call, back into the qualifier of that function.
// This allows data to flow 'in' through references returned by a modeled
// function such as `operator[]`.
exists(DataFlowFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
call.getTarget() = f and
inModel.isReturnValueDeref() and
outModel.isQualifierObject() and
f.hasDataFlow(inModel, outModel) and
nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr() = call and
nodeTo.asDefiningArgument() = call.getQualifier()
)
) and
model = ""
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
// Expr -> Expr
exprToExprStep_nocfg(nodeFrom.asExpr(), nodeTo.asExpr())
or
// Assignment -> LValue post-update node
//
// This is used for assignments whose left-hand side is not a variable
// assignment or a storeStep but is still modeled by other means. It could be
// a call to `operator*` or `operator[]` where taint should flow to the
// post-update node of the qualifier.
exists(AssignExpr assign |
nodeFrom.asExpr() = assign and
nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() = assign.getLValue()
)
or
// Node -> FlowVar -> VariableAccess
exists(FlowVar var |
(
exprToVarStep(nodeFrom.asExpr(), var)
or
varSourceBaseCase(var, nodeFrom.asParameter())
or
varSourceBaseCase(var, nodeFrom.asUninitialized())
or
var.definedPartiallyAt(nodeFrom.asPartialDefinition())
) and
varToNodeStep(var, nodeTo)
)
or
// Expr -> DefinitionByReferenceNode
exprToDefinitionByReferenceStep(nodeFrom.asExpr(), nodeTo.asDefiningArgument())
or
// `this` -> adjacent-`this`
ThisFlow::adjacentThisRefs(nodeFrom, nodeTo)
or
// post-update-`this` -> following-`this`-ref
ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
or
// In `f(&x->a)`, this step provides the flow from post-`&` to post-`x->a`,
// from which there is field flow to `x` via reverse read.
exists(PartialDefinition def, Expr inner, Expr outer |
def.definesExpressions(inner, outer) and
inner = nodeTo.(InnerPartialDefinitionNode).getPreUpdateNode().asExpr() and
outer = nodeFrom.(PartialDefinitionNode).getPreUpdateNode().asExpr()
)
or
// Reverse flow: data that flows from the post-update node of a reference
// returned by a function call, back into the qualifier of that function.
// This allows data to flow 'in' through references returned by a modeled
// function such as `operator[]`.
exists(DataFlowFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
call.getTarget() = f and
inModel.isReturnValueDeref() and
outModel.isQualifierObject() and
f.hasDataFlow(inModel, outModel) and
nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr() = call and
nodeTo.asDefiningArgument() = call.getQualifier()
)
}
/**

View File

@@ -1,271 +0,0 @@
/**
* Provides classes and predicates for defining flow summaries.
*/
private import cpp as Cpp
private import codeql.dataflow.internal.FlowSummaryImpl
private import codeql.dataflow.internal.AccessPathSyntax as AccessPath
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific as DataFlowImplSpecific
private import semmle.code.cpp.dataflow.ExternalFlow
private import semmle.code.cpp.ir.IR
module Input implements InputSig<Location, DataFlowImplSpecific::CppDataFlow> {
class SummarizedCallableBase = Function;
ArgumentPosition callbackSelfParameterPosition() { result = TDirectPosition(-1) }
ReturnKind getStandardReturnValueKind() { result.(NormalReturnKind).getIndirectionIndex() = 0 }
string encodeParameterPosition(ParameterPosition pos) { result = pos.toString() }
string encodeArgumentPosition(ArgumentPosition pos) { result = pos.toString() }
string encodeReturn(ReturnKind rk, string arg) {
rk != getStandardReturnValueKind() and
result = "ReturnValue" and
arg = repeatStars(rk.(NormalReturnKind).getIndirectionIndex())
}
string encodeContent(ContentSet cs, string arg) {
exists(FieldContent c |
cs.isSingleton(c) and
// FieldContent indices have 0 for the address, 1 for content, so we need to subtract one.
result = "Field" and
arg = repeatStars(c.getIndirectionIndex() - 1) + c.getField().getName()
)
}
string encodeWithoutContent(ContentSet c, string arg) {
// used for type tracking, not currently used in C/C++.
result = "WithoutContent" + c and arg = ""
}
string encodeWithContent(ContentSet c, string arg) {
// used for type tracking, not currently used in C/C++.
result = "WithContent" + c and arg = ""
}
/**
* Decodes an argument / parameter position string, for example the `0` in `Argument[0]`.
* Supports ranges (`Argument[x..y]`), qualifiers (`Argument[-1]`), indirections
* (`Argument[*x]`) and combinations (such as `Argument[**0..1]`).
*/
bindingset[argString]
private TPosition decodePosition(string argString) {
exists(int indirection, string posString, int pos |
argString = repeatStars(indirection) + posString and
pos = AccessPath::parseInt(posString) and
(
pos >= 0 and indirection = 0 and result = TDirectPosition(pos)
or
pos >= 0 and indirection > 0 and result = TIndirectionPosition(pos, indirection)
or
// `Argument[-1]` / `Parameter[-1]` is the qualifier object `*this`, not the `this` pointer itself.
pos = -1 and result = TIndirectionPosition(pos, indirection + 1)
)
)
}
bindingset[token]
ParameterPosition decodeUnknownParameterPosition(AccessPath::AccessPathTokenBase token) {
token.getName() = "Argument" and
result = decodePosition(token.getAnArgument())
}
bindingset[token]
ArgumentPosition decodeUnknownArgumentPosition(AccessPath::AccessPathTokenBase token) {
token.getName() = "Parameter" and
result = decodePosition(token.getAnArgument())
}
bindingset[token]
ContentSet decodeUnknownContent(AccessPath::AccessPathTokenBase token) {
// field content (no indirection support)
exists(FieldContent c |
result.isSingleton(c) and
token.getName() = c.getField().getName() and
not exists(token.getArgumentList()) and
c.getIndirectionIndex() = 1
)
or
// field content (with indirection support)
exists(FieldContent c |
result.isSingleton(c) and
token.getName() = c.getField().getName() and
// FieldContent indices have 0 for the address, 1 for content, so we need to subtract one.
token.getAnArgument() = repeatStars(c.getIndirectionIndex() - 1)
)
}
}
private import Make<Location, DataFlowImplSpecific::CppDataFlow, Input> as Impl
private module StepsInput implements Impl::Private::StepsInputSig {
DataFlowCall getACall(Public::SummarizedCallable sc) {
result.getStaticCallTarget().getUnderlyingCallable() = sc
}
}
module SourceSinkInterpretationInput implements
Impl::Private::External::SourceSinkInterpretationInputSig
{
class Element = Cpp::Element;
class SourceOrSinkElement = Element;
/**
* Holds if an external source specification exists for `e` with output specification
* `output`, kind `kind`, and provenance `provenance`.
*/
predicate sourceElement(
SourceOrSinkElement e, string output, string kind, Public::Provenance provenance, string model
) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance) and
e = interpretElement(namespace, type, subtypes, name, signature, ext) and
model = "" // TODO
)
}
/**
* Holds if an external sink specification exists for `e` with input specification
* `input`, kind `kind` and provenance `provenance`.
*/
predicate sinkElement(
SourceOrSinkElement e, string input, string kind, Public::Provenance provenance, string model
) {
exists(
string package, string type, boolean subtypes, string name, string signature, string ext
|
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance) and
e = interpretElement(package, type, subtypes, name, signature, ext) and
model = "" // TODO
)
}
private newtype TInterpretNode =
TElement_(Element n) or
TNode_(Node n)
/** An entity used to interpret a source/sink specification. */
class InterpretNode extends TInterpretNode {
/** Gets the element that this node corresponds to, if any. */
SourceOrSinkElement asElement() { this = TElement_(result) }
/** Gets the data-flow node that this node corresponds to, if any. */
Node asNode() { this = TNode_(result) }
/** Gets the call that this node corresponds to, if any. */
DataFlowCall asCall() {
this.asElement() = result.asCallInstruction().getUnconvertedResultExpression()
}
/** Gets the callable that this node corresponds to, if any. */
DataFlowCallable asCallable() { result.getUnderlyingCallable() = this.asElement() }
/** Gets the target of this call, if any. */
Element getCallTarget() { result = this.asCall().getStaticCallTarget().getUnderlyingCallable() }
/** Gets a textual representation of this node. */
string toString() {
result = this.asElement().toString()
or
result = this.asNode().toString()
or
result = this.asCall().toString()
}
/** Gets the location of this node. */
Location getLocation() {
result = this.asElement().getLocation()
or
result = this.asNode().getLocation()
or
result = this.asCall().getLocation()
}
}
/** Provides additional sink specification logic. */
bindingset[c]
predicate interpretOutput(string c, InterpretNode mid, InterpretNode node) {
// Allow variables to be picked as output nodes.
exists(Node n, Element ast |
n = node.asNode() and
ast = mid.asElement()
|
c = "" and
n.asExpr().(VariableAccess).getTarget() = ast
)
}
/** Provides additional source specification logic. */
bindingset[c]
predicate interpretInput(string c, InterpretNode mid, InterpretNode node) {
exists(Node n, Element ast, VariableAccess e |
n = node.asNode() and
ast = mid.asElement() and
e.getTarget() = ast
|
// Allow variables to be picked as input nodes.
// We could simply do this as `e = n.asExpr()`, but that would not allow
// us to pick `x` as a sink in an example such as `x = source()` (but
// only subsequent uses of `x`) since the variable access on `x` doesn't
// actually load the value of `x`. So instead, we pick the instruction
// node corresponding to the generated `StoreInstruction` and use the
// expression associated with the destination instruction. This means
// that the `x` in `x = source()` can be marked as an input.
c = "" and
exists(StoreInstruction store |
store.getDestinationAddress().getUnconvertedResultExpression() = e and
n.asInstruction() = store
)
)
}
}
module Private {
import Impl::Private
module Steps = Impl::Private::Steps<StepsInput>;
module External {
import Impl::Private::External
import Impl::Private::External::SourceSinkInterpretation<SourceSinkInterpretationInput>
}
/**
* Provides predicates for constructing summary components.
*/
module SummaryComponent {
private import Impl::Private::SummaryComponent as SC
predicate parameter = SC::parameter/1;
predicate argument = SC::argument/1;
predicate content = SC::content/1;
predicate withoutContent = SC::withoutContent/1;
predicate withContent = SC::withContent/1;
}
/**
* Provides predicates for constructing stacks of summary components.
*/
module SummaryComponentStack {
private import Impl::Private::SummaryComponentStack as SCS
predicate singleton = SCS::singleton/1;
predicate push = SCS::push/2;
predicate argument = SCS::argument/1;
}
}
module Public = Impl::Public;

View File

@@ -32,8 +32,8 @@ predicate localTaintStep(DataFlow::Node src, DataFlow::Node sink) {
* Holds if the additional step from `src` to `sink` should be included in all
* global taint flow configurations.
*/
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink, string model) {
localAdditionalTaintStep(src, sink) and model = ""
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
localAdditionalTaintStep(src, sink)
}
/**

View File

@@ -127,7 +127,7 @@ abstract deprecated class Configuration extends DataFlow::Configuration {
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
this.isAdditionalTaintStep(node1, node2) or
defaultAdditionalTaintStep(node1, node2, _)
defaultAdditionalTaintStep(node1, node2)
}
/**

View File

@@ -127,7 +127,7 @@ abstract deprecated class Configuration extends DataFlow::Configuration {
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
this.isAdditionalTaintStep(node1, node2) or
defaultAdditionalTaintStep(node1, node2, _)
defaultAdditionalTaintStep(node1, node2)
}
/**

View File

@@ -63,12 +63,6 @@ class Expr extends StmtParent, @expr {
* order of destruction.
*/
DestructorCall getImplicitDestructorCall(int n) {
exists(Expr e |
e = this.(TemporaryObjectExpr).getExpr() and
synthetic_destructor_call(e, max(int i | synthetic_destructor_call(e, i, _)) - n, result)
)
or
not this = any(TemporaryObjectExpr temp).getExpr() and
synthetic_destructor_call(this, max(int i | synthetic_destructor_call(this, i, _)) - n, result)
}
@@ -1338,24 +1332,6 @@ class CoAwaitExpr extends UnaryOperation, @co_await {
override string getOperator() { result = "co_await" }
override int getPrecedence() { result = 16 }
/**
* Gets the Boolean expression that is used to decide if the enclosing
* coroutine should be suspended.
*/
Expr getAwaitReady() { result = this.getChild(1) }
/**
* Gets the expression that represents the resume point if the enclosing
* coroutine was suspended.
*/
Expr getAwaitResume() { result = this.getChild(2) }
/**
* Gets the expression that is evaluated when the enclosing coroutine is
* suspended.
*/
Expr getAwaitSuspend() { result = this.getChild(3) }
}
/**
@@ -1370,24 +1346,6 @@ class CoYieldExpr extends UnaryOperation, @co_yield {
override string getOperator() { result = "co_yield" }
override int getPrecedence() { result = 2 }
/**
* Gets the Boolean expression that is used to decide if the enclosing
* coroutine should be suspended.
*/
Expr getAwaitReady() { result = this.getChild(1) }
/**
* Gets the expression that represents the resume point if the enclosing
* coroutine was suspended.
*/
Expr getAwaitResume() { result = this.getChild(2) }
/**
* Gets the expression that is evaluated when the enclosing coroutine is
* suspended.
*/
Expr getAwaitSuspend() { result = this.getChild(3) }
}
/**
@@ -1407,7 +1365,17 @@ class ReuseExpr extends Expr, @reuseexpr {
/**
* Gets the expression that is being re-used.
*/
Expr getReusedExpr() { expr_reuse(underlyingElement(this), unresolveElement(result), _) }
Expr getReusedExpr() {
// In the case of a prvalue, the extractor outputs the expression
// before conversion, but the converted expression is intended.
if this.isPRValueCategory()
then result = this.getBaseReusedExpr().getFullyConverted()
else result = this.getBaseReusedExpr()
}
private Expr getBaseReusedExpr() {
expr_reuse(underlyingElement(this), unresolveElement(result), _)
}
override Type getType() { result = this.getReusedExpr().getType() }

View File

@@ -7,7 +7,6 @@ import cpp
private import semmle.code.cpp.ir.ValueNumbering
private import internal.DataFlowDispatch
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
/**
* Resolve potential target function(s) for `call`.
@@ -17,9 +16,8 @@ private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
* to identify the possible target(s).
*/
Function resolveCall(Call call) {
exists(DataFlowCall dataFlowCall, CallInstruction callInstruction |
exists(CallInstruction callInstruction |
callInstruction.getAst() = call and
callInstruction = dataFlowCall.asCallInstruction() and
result = viableCallable(dataFlowCall).getUnderlyingCallable()
result = viableCallable(callInstruction)
)
}

View File

@@ -23,13 +23,13 @@ DataFlowCallable defaultViableCallable(DataFlowCall call) {
// function with the right signature is present in the database, we return
// that as a potential callee.
exists(string qualifiedName, int nparams |
callSignatureWithoutBody(qualifiedName, nparams, call.asCallInstruction()) and
functionSignatureWithBody(qualifiedName, nparams, result.getUnderlyingCallable()) and
callSignatureWithoutBody(qualifiedName, nparams, call) and
functionSignatureWithBody(qualifiedName, nparams, result) and
strictcount(Function other | functionSignatureWithBody(qualifiedName, nparams, other)) = 1
)
or
// Virtual dispatch
result.asSourceCallable() = call.(VirtualDispatch::DataSensitiveCall).resolve()
result = call.(VirtualDispatch::DataSensitiveCall).resolve()
}
/**
@@ -40,9 +40,7 @@ DataFlowCallable viableCallable(DataFlowCall call) {
result = defaultViableCallable(call)
or
// Additional call targets
result.getUnderlyingCallable() =
any(AdditionalCallTarget additional)
.viableTarget(call.asCallInstruction().getUnconvertedResultExpression())
result = any(AdditionalCallTarget additional).viableTarget(call.getUnconvertedResultExpression())
}
/**
@@ -152,7 +150,7 @@ private module VirtualDispatch {
ReturnNode node, ReturnKind kind, DataFlowCallable callable
) {
node.getKind() = kind and
node.getEnclosingCallable() = callable.getUnderlyingCallable()
node.getEnclosingCallable() = callable
}
/** Call through a function pointer. */
@@ -178,15 +176,10 @@ private module VirtualDispatch {
/** Call to a virtual function. */
private class DataSensitiveOverriddenFunctionCall extends DataSensitiveCall {
DataSensitiveOverriddenFunctionCall() {
exists(
this.getStaticCallTarget()
.getUnderlyingCallable()
.(VirtualFunction)
.getAnOverridingFunction()
)
exists(this.getStaticCallTarget().(VirtualFunction).getAnOverridingFunction())
}
override DataFlow::Node getDispatchValue() { result.asInstruction() = this.getArgument(-1) }
override DataFlow::Node getDispatchValue() { result.asInstruction() = this.getThisArgument() }
override MemberFunction resolve() {
exists(Class overridingClass |
@@ -201,8 +194,7 @@ private module VirtualDispatch {
*/
pragma[noinline]
private predicate overrideMayAffectCall(Class overridingClass, MemberFunction overridingFunction) {
overridingFunction.getAnOverriddenFunction+() =
this.getStaticCallTarget().getUnderlyingCallable().(VirtualFunction) and
overridingFunction.getAnOverriddenFunction+() = this.getStaticCallTarget().(VirtualFunction) and
overridingFunction.getDeclaringType() = overridingClass
}
@@ -264,12 +256,12 @@ predicate mayBenefitFromCallContext(DataFlowCall call) { mayBenefitFromCallConte
* value is given as the `arg`'th argument to `f`.
*/
private predicate mayBenefitFromCallContext(
VirtualDispatch::DataSensitiveCall call, DataFlowCallable f, int arg
VirtualDispatch::DataSensitiveCall call, Function f, int arg
) {
f = pragma[only_bind_out](call).getEnclosingCallable() and
exists(InitializeParameterInstruction init |
not exists(call.getStaticCallTarget()) and
init.getEnclosingFunction() = f.getUnderlyingCallable() and
init.getEnclosingFunction() = f and
call.flowsFrom(DataFlow::instructionNode(init), _) and
init.getParameter().getIndex() = arg
)
@@ -281,11 +273,10 @@ private predicate mayBenefitFromCallContext(
*/
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
result = viableCallable(call) and
exists(int i, DataFlowCallable f |
exists(int i, Function f |
mayBenefitFromCallContext(pragma[only_bind_into](call), f, i) and
f = ctx.getStaticCallTarget() and
result.asSourceCallable() =
ctx.getArgument(i).getUnconvertedResultExpression().(FunctionAccess).getTarget()
result = ctx.getArgument(i).getUnconvertedResultExpression().(FunctionAccess).getTarget()
)
}

View File

@@ -263,10 +263,9 @@ deprecated private module Config implements FullStateConfigSig {
predicate isBarrierOut(Node node, FlowState state) { none() }
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
predicate isAdditionalFlowStep(Node node1, Node node2) {
singleConfiguration() and
any(Configuration config).isAdditionalFlowStep(node1, node2) and
model = ""
any(Configuration config).isAdditionalFlowStep(node1, node2)
}
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {

View File

@@ -263,10 +263,9 @@ deprecated private module Config implements FullStateConfigSig {
predicate isBarrierOut(Node node, FlowState state) { none() }
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
predicate isAdditionalFlowStep(Node node1, Node node2) {
singleConfiguration() and
any(Configuration config).isAdditionalFlowStep(node1, node2) and
model = ""
any(Configuration config).isAdditionalFlowStep(node1, node2)
}
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {

View File

@@ -263,10 +263,9 @@ deprecated private module Config implements FullStateConfigSig {
predicate isBarrierOut(Node node, FlowState state) { none() }
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
predicate isAdditionalFlowStep(Node node1, Node node2) {
singleConfiguration() and
any(Configuration config).isAdditionalFlowStep(node1, node2) and
model = ""
any(Configuration config).isAdditionalFlowStep(node1, node2)
}
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {

View File

@@ -263,10 +263,9 @@ deprecated private module Config implements FullStateConfigSig {
predicate isBarrierOut(Node node, FlowState state) { none() }
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
predicate isAdditionalFlowStep(Node node1, Node node2) {
singleConfiguration() and
any(Configuration config).isAdditionalFlowStep(node1, node2) and
model = ""
any(Configuration config).isAdditionalFlowStep(node1, node2)
}
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {

View File

@@ -22,13 +22,9 @@ module CppDataFlow implements InputSig<Location> {
predicate getAdditionalFlowIntoCallNodeTerm = Private::getAdditionalFlowIntoCallNodeTerm/2;
predicate getSecondLevelScope = Private::getSecondLevelScope/1;
predicate validParameterAliasStep = Private::validParameterAliasStep/2;
predicate mayBenefitFromCallContext = Private::mayBenefitFromCallContext/1;
predicate viableImplInCallContext = Private::viableImplInCallContext/2;
predicate neverSkipInPathGraph = Private::neverSkipInPathGraph/1;
}

View File

@@ -3,7 +3,6 @@ private import DataFlowUtil
private import semmle.code.cpp.ir.IR
private import DataFlowDispatch
private import semmle.code.cpp.ir.internal.IRCppLanguage
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import SsaInternals as Ssa
private import DataFlowImplCommon as DataFlowImplCommon
private import codeql.util.Unit
@@ -78,8 +77,15 @@ module NodeStars {
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
or
result = n.(FinalParameterNode).getIndirectionIndex()
}
private int maxNumberOfIndirections() { result = max(getNumberOfIndirections(_)) }
private string repeatStars(int n) {
n = 0 and result = ""
or
result = n.(BodyLessParameterNodeImpl).getIndirectionIndex()
n = [1 .. maxNumberOfIndirections()] and
result = "*" + repeatStars(n - 1)
}
/**
@@ -91,11 +97,6 @@ module NodeStars {
import NodeStars
/**
* A cut-down `DataFlow::Node` class that does not depend on the output of SSA.
* This can thus be safely used in the SSA computations themselves, as well as
* in construction of other node classes (`TIRDataFlowNode`).
*/
class Node0Impl extends TIRDataFlowNode0 {
/**
* INTERNAL: Do not use.
@@ -332,9 +333,7 @@ private module IndirectInstructions {
import IndirectInstructions
/** Gets the callable in which this node occurs. */
DataFlowCallable nodeGetEnclosingCallable(Node n) {
result.getUnderlyingCallable() = n.getEnclosingCallable()
}
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
@@ -380,30 +379,12 @@ private class SideEffectArgumentNode extends ArgumentNode, SideEffectOperandNode
override predicate argumentOf(DataFlowCall dfCall, ArgumentPosition pos) {
exists(int indirectionIndex |
pos = TIndirectionPosition(argumentIndex, pragma[only_bind_into](indirectionIndex)) and
this.getCallInstruction() = dfCall.asCallInstruction() and
this.getCallInstruction() = dfCall and
super.hasAddressOperandAndIndirectionIndex(_, pragma[only_bind_into](indirectionIndex))
)
}
}
/**
* An argument node that is part of a summary. These only occur when the
* summary contains a synthesized call.
*/
class SummaryArgumentNode extends ArgumentNode, FlowSummaryNode {
private SummaryCall call_;
private ArgumentPosition pos_;
SummaryArgumentNode() {
FlowSummaryImpl::Private::summaryArgumentNode(call_.getReceiver(), this.getSummaryNode(), pos_)
}
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
call = call_ and
pos = pos_
}
}
/** A parameter position represented by an integer. */
class ParameterPosition = Position;
@@ -451,42 +432,24 @@ class IndirectionPosition extends Position, TIndirectionPosition {
}
newtype TPosition =
TDirectPosition(int argumentIndex) { exists(any(CallInstruction c).getArgument(argumentIndex)) } or
TDirectPosition(int index) { exists(any(CallInstruction c).getArgument(index)) } or
TIndirectionPosition(int argumentIndex, int indirectionIndex) {
Ssa::hasIndirectOperand(any(CallInstruction call).getArgumentOperand(argumentIndex),
hasOperandAndIndex(_, any(CallInstruction call).getArgumentOperand(argumentIndex),
indirectionIndex)
}
private newtype TReturnKind =
TNormalReturnKind(int indirectionIndex) {
// derive a possible return indirection from SSA
// (this is a more durable approach if SSA infers additional indirections for any reason)
Ssa::hasIndirectOperand(any(ReturnValueInstruction ret).getReturnAddressOperand(),
indirectionIndex + 1) // We subtract one because the return loads the value.
or
// derive a possible return kind from the AST
// (this approach includes functions declared that have no body; they may still have flow summaries)
indirectionIndex =
[0 .. max(Cpp::Function f |
not exists(f.getBlock())
|
Ssa::getMaxIndirectionsForType(f.getUnspecifiedType()) - 1 // -1 because a returned value is a prvalue not a glvalue
)]
TNormalReturnKind(int index) {
exists(IndirectReturnNode return |
return.isNormalReturn() and
index = return.getIndirectionIndex() - 1 // We subtract one because the return loads the value.
)
} or
TIndirectReturnKind(int argumentIndex, int indirectionIndex) {
// derive a possible return argument from SSA
exists(Ssa::FinalParameterUse use |
use.getIndirectionIndex() = indirectionIndex and
use.getArgumentIndex() = argumentIndex
exists(IndirectReturnNode return |
return.isParameterReturn(argumentIndex) and
indirectionIndex = return.getIndirectionIndex()
)
or
// derive a possible return argument from the AST
indirectionIndex =
[0 .. max(Cpp::Function f |
not exists(f.getBlock())
|
Ssa::getMaxIndirectionsForType(f.getParameter(argumentIndex).getUnspecifiedType()) - 1 // -1 because an argument is a prvalue not a glvalue
)]
}
/**
@@ -494,44 +457,29 @@ private newtype TReturnKind =
* from a callable. For C++, this is simply a function return.
*/
class ReturnKind extends TReturnKind {
/**
* Gets the indirection index of this return kind.
*/
abstract int getIndirectionIndex();
/** Gets a textual representation of this return kind. */
abstract string toString();
}
/**
* A value returned from a callable using a `return` statement, that is, a "normal" return.
*/
class NormalReturnKind extends ReturnKind, TNormalReturnKind {
int indirectionIndex;
private class NormalReturnKind extends ReturnKind, TNormalReturnKind {
int index;
NormalReturnKind() { this = TNormalReturnKind(indirectionIndex) }
override int getIndirectionIndex() { result = indirectionIndex }
NormalReturnKind() { this = TNormalReturnKind(index) }
override string toString() { result = "indirect return" }
}
/**
* A value returned from a callable through a parameter.
*/
private class IndirectReturnKind extends ReturnKind, TIndirectReturnKind {
int argumentIndex;
int indirectionIndex;
IndirectReturnKind() { this = TIndirectReturnKind(argumentIndex, indirectionIndex) }
override int getIndirectionIndex() { result = indirectionIndex }
override string toString() { result = "indirect outparam[" + argumentIndex.toString() + "]" }
}
/** A data flow node that occurs as the result of a `ReturnStmt`. */
abstract class ReturnNode extends Node {
class ReturnNode extends Node instanceof IndirectReturnNode {
/** Gets the kind of this returned value. */
abstract ReturnKind getKind();
}
@@ -562,17 +510,6 @@ class ReturnIndirectionNode extends IndirectReturnNode, ReturnNode {
}
}
/**
* A return node that is part of a summary.
*/
private class SummaryReturnNode extends ReturnNode, FlowSummaryNode {
private ReturnKind rk;
SummaryReturnNode() { FlowSummaryImpl::Private::summaryReturnNode(this.getSummaryNode(), rk) }
override ReturnKind getKind() { result = rk }
}
private Operand fullyConvertedCallStepImpl(Operand op) {
not exists(getANonConversionUse(op)) and
exists(Instruction instr |
@@ -679,10 +616,7 @@ predicate simpleOutNode(Node node, CallInstruction call) {
instructionForFullyConvertedCall(node.asInstruction(), call)
}
/**
* A data flow node that represents the output of a call (for example, a
* return value) at the call site.
*/
/** A data flow node that represents the output of a call. */
class OutNode extends Node {
OutNode() {
// Return values not hidden behind indirections
@@ -693,15 +627,11 @@ class OutNode extends Node {
or
// Modified arguments hidden behind indirections
this instanceof IndirectArgumentOutNode
or
// Summary node
FlowSummaryImpl::Private::summaryOutNode(_, this.(FlowSummaryNode).getSummaryNode(), _)
}
/** Gets the underlying call. */
abstract DataFlowCall getCall();
/** Gets the kind of this out node. */
abstract ReturnKind getReturnKind();
}
@@ -710,44 +640,25 @@ private class DirectCallOutNode extends OutNode {
DirectCallOutNode() { simpleOutNode(this, call) }
override DataFlowCall getCall() { result.asCallInstruction() = call }
override DataFlowCall getCall() { result = call }
override ReturnKind getReturnKind() { result = TNormalReturnKind(0) }
}
private class IndirectCallOutNode extends OutNode, IndirectReturnOutNode {
override DataFlowCall getCall() { result.asCallInstruction() = this.getCallInstruction() }
override DataFlowCall getCall() { result = this.getCallInstruction() }
override ReturnKind getReturnKind() { result = TNormalReturnKind(this.getIndirectionIndex()) }
}
private class SideEffectOutNode extends OutNode, IndirectArgumentOutNode {
override DataFlowCall getCall() { result.asCallInstruction() = this.getCallInstruction() }
override DataFlowCall getCall() { result = this.getCallInstruction() }
override ReturnKind getReturnKind() {
result = TIndirectReturnKind(this.getArgumentIndex(), this.getIndirectionIndex())
}
}
/**
* An output node that is part of a summary. An output node is needed when the
* model contains a synthesized call (`SummaryCall`) and the return value of
* that call is needed by the summary (for example when the model has flow from
* `Argument[0].ReturnValue`).
*/
private class SummaryOutNode extends OutNode, FlowSummaryNode {
private SummaryCall call;
private ReturnKind kind_;
SummaryOutNode() {
FlowSummaryImpl::Private::summaryOutNode(call.getReceiver(), this.getSummaryNode(), kind_)
}
override DataFlowCall getCall() { result = call }
override ReturnKind getReturnKind() { result = kind_ }
}
/**
* Gets a node that can read the value returned from `call` with return kind
* `kind`.
@@ -810,10 +721,6 @@ predicate jumpStep(Node n1, Node n2) {
v = n1.asIndirectVariable(globalDef.getIndirection())
)
)
or
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryJumpStep(n1.(FlowSummaryNode).getSummaryNode(),
n2.(FlowSummaryNode).getSummaryNode())
}
/**
@@ -822,35 +729,25 @@ predicate jumpStep(Node n1, Node n2) {
* value of `node1`.
*
* The boolean `certain` is true if the destination address does not involve
* any pointer arithmetic, and false otherwise. This has to do with whether a
* store step can be used to clear a field (see `clearsContent`).
* any pointer arithmetic, and false otherwise.
*/
predicate storeStepImpl(Node node1, Content c, Node node2, boolean certain) {
exists(
PostFieldUpdateNode postFieldUpdate, int indirectionIndex1, int numberOfLoads,
StoreInstruction store
|
postFieldUpdate = node2 and
predicate storeStepImpl(Node node1, Content c, PostFieldUpdateNode node2, boolean certain) {
exists(int indirectionIndex1, int numberOfLoads, StoreInstruction store |
nodeHasInstruction(node1, store, pragma[only_bind_into](indirectionIndex1)) and
postFieldUpdate.getIndirectionIndex() = 1 and
numberOfLoadsFromOperand(postFieldUpdate.getFieldAddress(),
store.getDestinationAddressOperand(), numberOfLoads, certain)
node2.getIndirectionIndex() = 1 and
numberOfLoadsFromOperand(node2.getFieldAddress(), store.getDestinationAddressOperand(),
numberOfLoads, certain)
|
exists(FieldContent fc | fc = c |
fc.getField() = postFieldUpdate.getUpdatedField() and
fc.getField() = node2.getUpdatedField() and
fc.getIndirectionIndex() = 1 + indirectionIndex1 + numberOfLoads
)
or
exists(UnionContent uc | uc = c |
uc.getAField() = postFieldUpdate.getUpdatedField() and
uc.getAField() = node2.getUpdatedField() and
uc.getIndirectionIndex() = 1 + indirectionIndex1 + numberOfLoads
)
)
or
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
node2.(FlowSummaryNode).getSummaryNode()) and
certain = true
}
/**
@@ -937,10 +834,6 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
uc.getIndirectionIndex() = indirectionIndex2 + numberOfLoads
)
)
or
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c,
node2.(FlowSummaryNode).getSummaryNode())
}
/**
@@ -1014,213 +907,21 @@ class CastNode extends Node {
CastNode() { none() } // stub implementation
}
cached
private newtype TDataFlowCallable =
TSourceCallable(Cpp::Declaration decl) {
not decl instanceof FlowSummaryImpl::Public::SummarizedCallable
} or
TSummarizedCallable(FlowSummaryImpl::Public::SummarizedCallable c)
/**
* A callable, which may be:
* - a function (that may contain code)
* - a summarized function (that may contain only `FlowSummaryNode`s)
* - a variable (this is used as context for global initialization, and also
* for the mid-point in interprocedural data flow between a write and read
* of a global variable in different functions).
* When flow crosses from one _enclosing callable_ to another, the
* interprocedural data-flow library discards call contexts and inserts a node
* in the big-step relation used for human-readable path explanations.
* A function that may contain code or a variable that may contain itself. When
* flow crosses from one _enclosing callable_ to another, the interprocedural
* data-flow library discards call contexts and inserts a node in the big-step
* relation used for human-readable path explanations.
*/
class DataFlowCallable extends TDataFlowCallable {
/** Gets the location of this callable. */
Location getLocation() { none() }
/** Gets a textual representation of this callable. */
string toString() { none() }
/**
* Gets the `Declaration` corresponding to this callable if it exists in the database.
* For summarized callables (which may not exist in the database), use `asSummarizedCallable`.
*/
Cpp::Declaration asSourceCallable() { this = TSourceCallable(result) }
/**
* Gets the underlying summarized callable, if
* this callable is generated from a models-as-data
* model.
*/
FlowSummaryImpl::Public::SummarizedCallable asSummarizedCallable() {
this = TSummarizedCallable(result)
}
/**
* Gets the underlying `Declaration` of this `DataFlowCallable`. This
* predicate returns a result for both source and summarized callables.
*/
Cpp::Declaration getUnderlyingCallable() {
result = this.asSummarizedCallable() or // SummarizedCallable = Function (in CPP)
result = this.asSourceCallable()
}
}
/**
* A source callable, conceptually, a function in the source code for the
* purpose of computing data flow. In practice this excludes functions that
* are summarized using models-as-data (as we don't want to create
* unmodeled flows or duplicate paths), and includes variables (for reasons
* explained in `DataFlowCallable`).
*/
class SourceCallable extends DataFlowCallable, TSourceCallable {
Cpp::Declaration decl;
SourceCallable() { this = TSourceCallable(decl) }
override string toString() { result = decl.toString() }
override Location getLocation() { result = decl.getLocation() }
}
/**
* A summarized callable, that is, a function synthesized from one or more
* models-as-data models as a place to contain the corresponding
* `FlowSummaryNode`s.
*/
class SummarizedCallable extends DataFlowCallable, TSummarizedCallable {
FlowSummaryImpl::Public::SummarizedCallable sc;
SummarizedCallable() { this = TSummarizedCallable(sc) }
override string toString() { result = sc.toString() }
override Location getLocation() { result = sc.getLocation() }
}
class DataFlowCallable = Cpp::Declaration;
class DataFlowExpr = Expr;
class DataFlowType = Type;
cached
private newtype TDataFlowCall =
TNormalCall(CallInstruction call) or
TSummaryCall(
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
) {
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
}
/**
* A function call relevant for data flow. This includes calls from source
* code and calls inside library callables with a flow summary.
*/
class DataFlowCall extends TDataFlowCall {
/**
* Gets the underlying data flow call instruction, if any.
*/
CallInstruction asCallInstruction() { none() }
/**
* Gets the operand the specifies the target function of the call.
*/
CallTargetOperand getCallTargetOperand() { none() }
/**
* Gets the `Function` that the call targets, if this is statically known.
*/
DataFlowCallable getStaticCallTarget() { none() }
/**
* Gets the `index`'th argument operand. The qualifier is considered to have index `-1`.
*/
ArgumentOperand getArgumentOperand(int index) { none() }
/**
* Gets the argument at the specified index, or `this` if `index` is `-1`.
*/
pragma[noinline]
final Instruction getArgument(int index) { result = this.getArgumentOperand(index).getDef() }
/**
* Gets the number of arguments of the call, including the `this` pointer, if any.
*/
final int getNumberOfArguments() { result = count(this.getArgumentOperand(_)) }
/**
* Gets the enclosing callable, if any.
*/
DataFlowCallable getEnclosingCallable() { none() }
/**
* Gets a textual representation of this call.
*/
string toString() { none() }
/**
* Gets the location of this call.
*/
Location getLocation() { none() }
}
/**
* A function call relevant for data flow, that exists in source code.
*/
private class NormalCall extends DataFlowCall, TNormalCall {
private CallInstruction call;
NormalCall() { this = TNormalCall(call) }
override CallInstruction asCallInstruction() { result = call }
override CallTargetOperand getCallTargetOperand() { result = call.getCallTargetOperand() }
override DataFlowCallable getStaticCallTarget() {
result.getUnderlyingCallable() = call.getStaticCallTarget()
}
override ArgumentOperand getArgumentOperand(int index) { result = call.getArgumentOperand(index) }
override DataFlowCallable getEnclosingCallable() {
result.getUnderlyingCallable() = call.getEnclosingFunction()
}
override string toString() { result = call.toString() }
override Location getLocation() { result = call.getLocation() }
}
/**
* A synthesized call inside a callable with a flow summary.
*
* For example, consider the function:
* ```
* int myFunction(int (*funPtr)());
* ```
* with an accompanying models-as-data flow summary involving `funPtr` (for
* example from `Argument[0].ReturnValue` to `ReturnValue`). A `SummaryCall`
* will be synthesized representing a call to `funPtr` inside `myFunction`,
* so that flow can be connected as described in the model.
*/
class SummaryCall extends DataFlowCall, TSummaryCall {
private FlowSummaryImpl::Public::SummarizedCallable c;
private FlowSummaryImpl::Private::SummaryNode receiver;
SummaryCall() { this = TSummaryCall(c, receiver) }
/**
* Gets the data flow node that holds the address of the function this call
* targets.
*/
FlowSummaryImpl::Private::SummaryNode getReceiver() { result = receiver }
// no implementation for `getCallTargetOperand()`, `getStaticCallTarget()`
// or `getArgumentOperand(int index)`. This is because the flow summary
// library is responsible for finding the call target, and there are no
// IR nodes available for the call target operand or argument operands.
override DataFlowCallable getEnclosingCallable() { result = TSummarizedCallable(c) }
override string toString() { result = "[summary] call to " + receiver + " in " + c }
override UnknownLocation getLocation() { any() }
/** A function call relevant for data flow. */
class DataFlowCall extends CallInstruction {
DataFlowCallable getEnclosingCallable() { result = this.getEnclosingFunction() }
}
module IsUnreachableInCall {
@@ -1249,7 +950,7 @@ module IsUnreachableInCall {
predicate isUnreachableInCall(Node n, DataFlowCall call) {
exists(
InstructionDirectParameterNode paramNode, ConstantIntegralTypeArgumentNode arg,
DirectParameterNode paramNode, ConstantIntegralTypeArgumentNode arg,
IntegerConstantInstruction constant, int k, Operand left, Operand right, IRBlock block
|
// arg flows into `paramNode`
@@ -1308,34 +1009,17 @@ predicate nodeIsHidden(Node n) {
n instanceof InitialGlobalValue
}
predicate neverSkipInPathGraph(Node n) {
// Always show the right-hand side of assignments in the path graph
exists(n.asDefinition())
or
exists(n.asIndirectDefinition())
}
class LambdaCallKind = Unit;
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) {
creation.asInstruction().(FunctionAddressInstruction).getFunctionSymbol() = c.asSourceCallable() and
exists(kind)
}
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { none() }
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
call.(SummaryCall).getReceiver() = receiver.(FlowSummaryNode).getSummaryNode() and
exists(kind)
}
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { none() }
/** Extra data-flow steps needed for lambda flow analysis. */
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
predicate knownSourceModel(Node source, string model) { none() }
predicate knownSinkModel(Node sink, string model) { none() }
/**
* Holds if flow is allowed to pass from parameter `p` and back to itself as a
* side-effect, resulting in a summary from `p` to itself.
@@ -1343,15 +1027,7 @@ predicate knownSinkModel(Node sink, string model) { none() }
* One example would be to allow flow like `p.foo = p.bar;`, which is disallowed
* by default as a heuristic.
*/
predicate allowParameterReturnInSelf(ParameterNode p) {
p instanceof IndirectParameterNode
or
// models-as-data summarized flow
exists(DataFlowCallable c, ParameterPosition pos |
p.isParameterOf(c, pos) and
FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(c.asSummarizedCallable(), pos)
)
}
predicate allowParameterReturnInSelf(ParameterNode p) { p instanceof IndirectParameterNode }
private predicate fieldHasApproxName(Field f, string s) {
s = f.getName().charAt(0) and
@@ -1420,7 +1096,7 @@ private predicate localFlowStepWithSummaries(Node node1, Node node2) {
or
readStep(node1, _, node2)
or
DataFlowImplCommon::argumentValueFlowsThrough(node1, _, node2, _)
DataFlowImplCommon::argumentValueFlowsThrough(node1, _, node2)
}
/** Holds if `node` flows to a node that is used in a `SwitchInstruction`. */
@@ -1463,7 +1139,7 @@ private predicate getAdditionalFlowIntoCallNodeTermStep(Node node1, Node node2)
/** Gets the `IRVariable` associated with the parameter node `p`. */
pragma[nomagic]
private IRVariable getIRVariableForParameterNode(ParameterNode p) {
result = p.(InstructionDirectParameterNode).getIRVariable()
result = p.(DirectParameterNode).getIRVariable()
or
result.getAst() = p.(IndirectParameterNode).getParameter()
}
@@ -1583,74 +1259,3 @@ predicate validParameterAliasStep(Node node1, Node node2) {
)
)
}
private predicate isTopLevel(Cpp::Stmt s) { any(Function f).getBlock().getAStmt() = s }
private Cpp::Stmt getAChainedBranch(Cpp::IfStmt s) {
result = s.getThen()
or
exists(Cpp::Stmt elseBranch | s.getElse() = elseBranch |
result = getAChainedBranch(elseBranch)
or
result = elseBranch and not elseBranch instanceof Cpp::IfStmt
)
}
private Instruction getInstruction(Node n) {
result = n.asInstruction() or
result = n.asOperand().getUse() or
result = n.(SsaPhiNode).getPhiNode().getBasicBlock().getFirstInstruction() or
n.(IndirectInstruction).hasInstructionAndIndirectionIndex(result, _) or
result = getInstruction(n.(PostUpdateNode).getPreUpdateNode())
}
private newtype TDataFlowSecondLevelScope =
TTopLevelIfBranch(Cpp::Stmt s) {
exists(Cpp::IfStmt ifstmt | s = getAChainedBranch(ifstmt) and isTopLevel(ifstmt))
} or
TTopLevelSwitchCase(Cpp::SwitchCase s) {
exists(Cpp::SwitchStmt switchstmt | s = switchstmt.getASwitchCase() and isTopLevel(switchstmt))
}
/**
* A second-level control-flow scope in a `switch` or a chained `if` statement.
*
* This is a `switch` case or a branch of a chained `if` statement, given that
* the `switch` or `if` statement is top level, that is, it is not nested inside
* other CFG constructs.
*/
class DataFlowSecondLevelScope extends TDataFlowSecondLevelScope {
/** Gets a textual representation of this element. */
string toString() {
exists(Cpp::Stmt s | this = TTopLevelIfBranch(s) | result = s.toString())
or
exists(Cpp::SwitchCase s | this = TTopLevelSwitchCase(s) | result = s.toString())
}
/** Gets the primary location of this element. */
Cpp::Location getLocation() {
exists(Cpp::Stmt s | this = TTopLevelIfBranch(s) | result = s.getLocation())
or
exists(Cpp::SwitchCase s | this = TTopLevelSwitchCase(s) | result = s.getLocation())
}
/**
* Gets a statement directly contained in this scope. For an `if` branch, this
* is the branch itself, and for a `switch case`, this is one the statements
* of that case branch.
*/
private Cpp::Stmt getAStmt() {
exists(Cpp::Stmt s | this = TTopLevelIfBranch(s) | result = s)
or
exists(Cpp::SwitchCase s | this = TTopLevelSwitchCase(s) | result = s.getAStmt())
}
/** Gets a data-flow node nested within this scope. */
Node getANode() {
getInstruction(result).getAst().(Cpp::ControlFlowNode).getEnclosingStmt().getParentStmt*() =
this.getAStmt()
}
}
/** Gets the second-level scope containing the node `n`, if any. */
DataFlowSecondLevelScope getSecondLevelScope(Node n) { result.getANode() = n }

View File

@@ -10,7 +10,6 @@ private import semmle.code.cpp.ir.ValueNumbering
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.controlflow.IRGuards
private import semmle.code.cpp.models.interfaces.DataFlow
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import DataFlowPrivate
private import ModelUtil
private import SsaInternals as Ssa
@@ -60,17 +59,7 @@ private newtype TIRDataFlowNode =
)
} or
TFinalGlobalValue(Ssa::GlobalUse globalUse) or
TInitialGlobalValue(Ssa::GlobalDef globalUse) or
TBodyLessParameterNodeImpl(Parameter p, int indirectionIndex) {
// Rule out parameters of catch blocks.
not exists(p.getCatchBlock()) and
// We subtract one because `getMaxIndirectionsForType` returns the maximum
// indirection for a glvalue of a given type, and this doesn't apply to
// parameters.
indirectionIndex = [0 .. Ssa::getMaxIndirectionsForType(p.getUnspecifiedType()) - 1] and
not any(InitializeParameterInstruction init).getParameter() = p
} or
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn)
TInitialGlobalValue(Ssa::GlobalDef globalUse)
/**
* An operand that is defined by a `FieldAddressInstruction`.
@@ -398,7 +387,7 @@ class Node extends TIRDataFlowNode {
index = 0 and
result = this.(ExplicitParameterNode).getParameter()
or
this.(IndirectParameterNode).getIndirectionIndex() = index and
this.(IndirectParameterNode).hasInstructionAndIndirectionIndex(_, index) and
result = this.(IndirectParameterNode).getParameter()
}
@@ -749,65 +738,37 @@ class InitialGlobalValue extends Node, TInitialGlobalValue {
/**
* INTERNAL: do not use.
*
* A node representing a parameter for a function with no body.
* A node representing an indirection of a parameter.
*/
class BodyLessParameterNodeImpl extends Node, TBodyLessParameterNodeImpl {
Parameter p;
int indirectionIndex;
class IndirectParameterNode extends Node instanceof IndirectInstruction {
InitializeParameterInstruction init;
BodyLessParameterNodeImpl() { this = TBodyLessParameterNodeImpl(p, indirectionIndex) }
IndirectParameterNode() { IndirectInstruction.super.hasInstructionAndIndirectionIndex(init, _) }
int getArgumentIndex() { init.hasIndex(result) }
/** Gets the parameter whose indirection is initialized. */
Parameter getParameter() { result = init.getParameter() }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Declaration getFunction() { result = p.getFunction() }
override Declaration getFunction() { result = init.getEnclosingFunction() }
/** Gets the indirection index of this node. */
int getIndirectionIndex() { result = indirectionIndex }
override DataFlowType getType() {
result = getTypeImpl(p.getUnderlyingType(), this.getIndirectionIndex())
/** Gets the underlying operand and the underlying indirection index. */
predicate hasInstructionAndIndirectionIndex(Instruction instr, int index) {
IndirectInstruction.super.hasInstructionAndIndirectionIndex(instr, index)
}
final override Location getLocationImpl() {
result = unique( | | p.getLocation())
or
count(p.getLocation()) != 1 and
result instanceof UnknownDefaultLocation
override Location getLocationImpl() { result = this.getParameter().getLocation() }
override string toStringImpl() {
exists(string prefix | prefix = stars(this) |
result = prefix + this.getParameter().toString()
or
not exists(this.getParameter()) and
result = prefix + "this"
)
}
final override string toStringImpl() {
exists(string prefix | prefix = stars(this) | result = prefix + p.toString())
}
}
/**
* A data-flow node used to model flow summaries. That is, a dataflow node
* that is synthesized to represent a parameter, return value, or other part
* of a models-as-data modeled function.
*/
class FlowSummaryNode extends Node, TFlowSummaryNode {
/**
* Gets the models-as-data `SummaryNode` associated with this dataflow
* `FlowSummaryNode`.
*/
FlowSummaryImpl::Private::SummaryNode getSummaryNode() { this = TFlowSummaryNode(result) }
/**
* Gets the summarized callable that this node belongs to.
*/
FlowSummaryImpl::Public::SummarizedCallable getSummarizedCallable() {
result = this.getSummaryNode().getSummarizedCallable()
}
/**
* Gets the enclosing callable. For a `FlowSummaryNode` this is always the
* summarized function this node is part of.
*/
override Declaration getEnclosingCallable() { result = this.getSummarizedCallable() }
override Location getLocationImpl() { result = this.getSummarizedCallable().getLocation() }
override string toStringImpl() { result = this.getSummaryNode().toString() }
}
/**
@@ -865,9 +826,6 @@ class IndirectArgumentOutNode extends PostUpdateNodeImpl {
CallInstruction getCallInstruction() { result.getAnArgumentOperand() = operand }
/**
* Gets the `Function` that the call targets, if this is statically known.
*/
Function getStaticCallTarget() { result = this.getCallInstruction().getStaticCallTarget() }
override string toStringImpl() {
@@ -1662,36 +1620,68 @@ class IndirectExprNode extends Node instanceof IndirectExprNodeBase {
}
}
abstract private class AbstractParameterNode extends Node {
/**
* The value of a parameter at function entry, viewed as a node in a data
* flow graph. This includes both explicit parameters such as `x` in `f(x)`
* and implicit parameters such as `this` in `x.f()`.
*
* To match a specific kind of parameter, consider using one of the subclasses
* `ExplicitParameterNode`, `ThisParameterNode`, or
* `ParameterIndirectionNode`.
*/
class ParameterNode extends Node {
ParameterNode() {
// To avoid making this class abstract, we enumerate its values here
this.asInstruction() instanceof InitializeParameterInstruction
or
this instanceof IndirectParameterNode
}
/**
* Holds if this node is the parameter of `f` at the specified position. The
* implicit `this` parameter is considered to have position `-1`, and
* pointer-indirection parameters are at further negative positions.
*/
abstract predicate isParameterOf(DataFlowCallable f, ParameterPosition pos);
predicate isParameterOf(Function f, ParameterPosition pos) { none() } // overridden by subclasses
/** Gets the `Parameter` associated with this node, if it exists. */
Parameter getParameter() { none() } // overridden by subclasses
}
abstract private class AbstractIndirectParameterNode extends AbstractParameterNode {
/** Gets the indirection index of this parameter node. */
abstract int getIndirectionIndex();
/** An explicit positional parameter, including `this`, but not `...`. */
class DirectParameterNode extends InstructionNode {
override InitializeParameterInstruction instr;
/**
* INTERNAL: Do not use.
*
* Gets the `IRVariable` that this parameter references.
*/
IRVariable getIRVariable() { result = instr.getIRVariable() }
}
/**
* INTERNAL: do not use.
*
* A node representing an indirection of a parameter.
*/
final class IndirectParameterNode = AbstractIndirectParameterNode;
/** An explicit positional parameter, not including `this` or `...`. */
private class ExplicitParameterNode extends ParameterNode, DirectParameterNode {
ExplicitParameterNode() { exists(instr.getParameter()) }
pragma[noinline]
private predicate indirectParameterNodeHasArgumentIndexAndIndex(
IndirectInstructionParameterNode node, int argumentIndex, int indirectionIndex
) {
node.hasInstructionAndIndirectionIndex(_, indirectionIndex) and
node.getArgumentIndex() = argumentIndex
override predicate isParameterOf(Function f, ParameterPosition pos) {
f.getParameter(pos.(DirectPosition).getIndex()) = instr.getParameter()
}
override string toStringImpl() { result = instr.getParameter().toString() }
override Parameter getParameter() { result = instr.getParameter() }
}
/** An implicit `this` parameter. */
class ThisParameterNode extends ParameterNode, DirectParameterNode {
ThisParameterNode() { instr.getIRVariable() instanceof IRThisVariable }
override predicate isParameterOf(Function f, ParameterPosition pos) {
pos.(DirectPosition).getIndex() = -1 and instr.getEnclosingFunction() = f
}
override string toStringImpl() { result = "this" }
}
pragma[noinline]
@@ -1702,167 +1692,23 @@ private predicate indirectPositionHasArgumentIndexAndIndex(
pos.getIndirectionIndex() = indirectionIndex
}
private class IndirectInstructionParameterNode extends AbstractIndirectParameterNode instanceof IndirectInstruction
{
InitializeParameterInstruction init;
pragma[noinline]
private predicate indirectParameterNodeHasArgumentIndexAndIndex(
IndirectParameterNode node, int argumentIndex, int indirectionIndex
) {
node.hasInstructionAndIndirectionIndex(_, indirectionIndex) and
node.getArgumentIndex() = argumentIndex
}
IndirectInstructionParameterNode() {
IndirectInstruction.super.hasInstructionAndIndirectionIndex(init, _)
}
int getArgumentIndex() { init.hasIndex(result) }
override string toStringImpl() {
exists(string prefix | prefix = stars(this) |
result = prefix + this.getParameter().toString()
or
not exists(this.getParameter()) and
result = prefix + "this"
)
}
/** Gets the parameter whose indirection is initialized. */
override Parameter getParameter() { result = init.getParameter() }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Declaration getFunction() { result = init.getEnclosingFunction() }
override predicate isParameterOf(DataFlowCallable f, ParameterPosition pos) {
this.getEnclosingCallable() = f.getUnderlyingCallable() and
/** A synthetic parameter to model the pointed-to object of a pointer parameter. */
class ParameterIndirectionNode extends ParameterNode instanceof IndirectParameterNode {
override predicate isParameterOf(Function f, ParameterPosition pos) {
IndirectParameterNode.super.getEnclosingCallable() = f and
exists(int argumentIndex, int indirectionIndex |
indirectPositionHasArgumentIndexAndIndex(pos, argumentIndex, indirectionIndex) and
indirectParameterNodeHasArgumentIndexAndIndex(this, argumentIndex, indirectionIndex)
)
}
/** Gets the underlying operand and the underlying indirection index. */
predicate hasInstructionAndIndirectionIndex(Instruction instr, int index) {
IndirectInstruction.super.hasInstructionAndIndirectionIndex(instr, index)
}
final override int getIndirectionIndex() { this.hasInstructionAndIndirectionIndex(init, result) }
}
/**
* The value of a parameter at function entry, viewed as a node in a data
* flow graph. This includes both explicit parameters such as `x` in `f(x)`
* and implicit parameters such as `this` in `x.f()`.
*
* To match a specific kind of parameter, consider using one of the subclasses
* `ExplicitParameterNode`, `ThisParameterNode`, or
* `ParameterIndirectionNode`.
*/
final class ParameterNode = AbstractParameterNode;
abstract private class AbstractDirectParameterNode extends AbstractParameterNode { }
/** An explicit positional parameter, including `this`, but not `...`. */
final class DirectParameterNode = AbstractDirectParameterNode;
/**
* INTERNAL: Do not use.
*
* A non-indirect parameter node that is represented as an `Instruction`.
*/
abstract class InstructionDirectParameterNode extends InstructionNode, AbstractDirectParameterNode {
final override InitializeParameterInstruction instr;
/**
* INTERNAL: Do not use.
*
* Gets the `IRVariable` that this parameter references.
*/
final IRVariable getIRVariable() { result = instr.getIRVariable() }
}
abstract private class AbstractExplicitParameterNode extends AbstractDirectParameterNode { }
final class ExplicitParameterNode = AbstractExplicitParameterNode;
/** An explicit positional parameter, not including `this` or `...`. */
private class ExplicitParameterInstructionNode extends AbstractExplicitParameterNode,
InstructionDirectParameterNode
{
ExplicitParameterInstructionNode() { exists(instr.getParameter()) }
override predicate isParameterOf(DataFlowCallable f, ParameterPosition pos) {
f.getUnderlyingCallable().(Function).getParameter(pos.(DirectPosition).getIndex()) =
instr.getParameter()
}
override string toStringImpl() { result = instr.getParameter().toString() }
override Parameter getParameter() { result = instr.getParameter() }
}
/** An implicit `this` parameter. */
class ThisParameterInstructionNode extends AbstractExplicitParameterNode,
InstructionDirectParameterNode
{
ThisParameterInstructionNode() { instr.getIRVariable() instanceof IRThisVariable }
override predicate isParameterOf(DataFlowCallable f, ParameterPosition pos) {
pos.(DirectPosition).getIndex() = -1 and
instr.getEnclosingFunction() = f.getUnderlyingCallable()
}
override string toStringImpl() { result = "this" }
}
/**
* A parameter node that is part of a summary.
*/
class SummaryParameterNode extends AbstractParameterNode, FlowSummaryNode {
SummaryParameterNode() {
FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), _)
}
private ParameterPosition getPosition() {
FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), result)
}
override predicate isParameterOf(DataFlowCallable c, ParameterPosition p) {
c.getUnderlyingCallable() = this.getSummarizedCallable() and
p = this.getPosition()
}
}
private class DirectBodyLessParameterNode extends AbstractExplicitParameterNode,
BodyLessParameterNodeImpl
{
DirectBodyLessParameterNode() { indirectionIndex = 0 }
override predicate isParameterOf(DataFlowCallable f, ParameterPosition pos) {
exists(Function func |
this.getFunction() = func and
f.asSourceCallable() = func and
func.getParameter(pos.(DirectPosition).getIndex()) = p
)
}
override Parameter getParameter() { result = p }
}
private class IndirectBodyLessParameterNode extends AbstractIndirectParameterNode,
BodyLessParameterNodeImpl
{
IndirectBodyLessParameterNode() { not this instanceof DirectBodyLessParameterNode }
override predicate isParameterOf(DataFlowCallable f, ParameterPosition pos) {
exists(Function func, int argumentPosition |
this.getFunction() = func and
f.asSourceCallable() = func and
indirectPositionHasArgumentIndexAndIndex(pos, argumentPosition, indirectionIndex) and
func.getParameter(argumentPosition) = p
)
}
override int getIndirectionIndex() {
result = BodyLessParameterNodeImpl.super.getIndirectionIndex()
}
override Parameter getParameter() { result = p }
}
/**
@@ -1907,22 +1753,6 @@ abstract private class PartialDefinitionNode extends PostUpdateNode {
abstract Expr getDefinedExpr();
}
/**
* A `PostUpdateNode` that is part of a flow summary. These are synthesized,
* for example, when a models-as-data summary models a write to a field since
* the write needs to target a `PostUpdateNode`.
*/
class SummaryPostUpdateNode extends FlowSummaryNode, PostUpdateNode {
SummaryPostUpdateNode() {
FlowSummaryImpl::Private::summaryPostUpdateNode(this.getSummaryNode(), _)
}
override Node getPreUpdateNode() {
FlowSummaryImpl::Private::summaryPostUpdateNode(this.getSummaryNode(),
result.(FlowSummaryNode).getSummaryNode())
}
}
/**
* 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.
@@ -2059,20 +1889,10 @@ cached
private module Cached {
/**
* Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local
* (intra-procedural) step. This relation is only used for local dataflow
* (for example `DataFlow::localFlow(source, sink)`) so it contains
* special cases that should only apply to local dataflow.
* (intra-procedural) step.
*/
cached
predicate localFlowStep(Node nodeFrom, Node nodeTo) {
// common dataflow steps
simpleLocalFlowStep(nodeFrom, nodeTo, _)
or
// models-as-data summarized flow for local data flow (i.e. special case for flow
// through calls to modeled functions, without relying on global dataflow to join
// the dots).
FlowSummaryImpl::Private::Steps::summaryThroughStepValue(nodeFrom, nodeTo, _)
}
predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo) }
private predicate indirectionOperandFlow(RawIndirectOperand nodeFrom, Node nodeTo) {
nodeFrom != nodeTo and
@@ -2138,54 +1958,45 @@ private module Cached {
/**
* INTERNAL: do not use.
*
* This is the local flow predicate that's used as a building block in both
* local and global data flow. It may have less flow than the `localFlowStep`
* predicate.
* This is the local flow predicate that's used as a building block in global
* data flow. It may have less flow than the `localFlowStep` predicate.
*/
cached
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
(
// Post update node -> Node flow
Ssa::postUpdateFlow(nodeFrom, nodeTo)
or
// Def-use/Use-use flow
Ssa::ssaFlow(nodeFrom, nodeTo)
or
// Operand -> Instruction flow
simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction())
or
// Instruction -> Operand flow
exists(Instruction iFrom, Operand opTo |
iFrom = nodeFrom.asInstruction() and opTo = nodeTo.asOperand()
|
simpleOperandLocalFlowStep(iFrom, opTo) and
// Omit when the instruction node also represents the operand.
not iFrom = Ssa::getIRRepresentationOfOperand(opTo)
)
or
// Phi node -> Node flow
Ssa::fromPhiNode(nodeFrom, nodeTo)
or
// Indirect operand -> (indirect) instruction flow
indirectionOperandFlow(nodeFrom, nodeTo)
or
// Indirect instruction -> indirect operand flow
indirectionInstructionFlow(nodeFrom, nodeTo)
) and
model = ""
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
// Post update node -> Node flow
Ssa::postUpdateFlow(nodeFrom, nodeTo)
or
// Def-use/Use-use flow
Ssa::ssaFlow(nodeFrom, nodeTo)
or
// Operand -> Instruction flow
simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction())
or
// Instruction -> Operand flow
exists(Instruction iFrom, Operand opTo |
iFrom = nodeFrom.asInstruction() and opTo = nodeTo.asOperand()
|
simpleOperandLocalFlowStep(iFrom, opTo) and
// Omit when the instruction node also represents the operand.
not iFrom = Ssa::getIRRepresentationOfOperand(opTo)
)
or
// Phi node -> Node flow
Ssa::fromPhiNode(nodeFrom, nodeTo)
or
// Indirect operand -> (indirect) instruction flow
indirectionOperandFlow(nodeFrom, nodeTo)
or
// Indirect instruction -> indirect operand flow
indirectionInstructionFlow(nodeFrom, nodeTo)
or
// Flow through modeled functions
modelFlow(nodeFrom, nodeTo, model)
modelFlow(nodeFrom, nodeTo)
or
// Reverse flow: data that flows from the definition node back into the indirection returned
// by a function. This allows data to flow 'in' through references returned by a modeled
// function such as `operator[]`.
reverseFlow(nodeFrom, nodeTo) and
model = ""
or
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), true, model)
reverseFlow(nodeFrom, nodeTo)
}
private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo) {
@@ -2200,13 +2011,12 @@ private module Cached {
opTo.getDef() = iFrom
}
private predicate modelFlow(Node nodeFrom, Node nodeTo, string model) {
private predicate modelFlow(Node nodeFrom, Node nodeTo) {
exists(
CallInstruction call, DataFlowFunction func, FunctionInput modelIn, FunctionOutput modelOut
|
call.getStaticCallTarget() = func and
func.hasDataFlow(modelIn, modelOut) and
model = "DataFlowFunction"
func.hasDataFlow(modelIn, modelOut)
|
nodeFrom = callInput(call, modelIn) and
nodeTo = callOutput(call, modelOut)
@@ -2427,8 +2237,6 @@ private Field getAFieldWithSize(Union u, int bytes) {
cached
private newtype TContent =
TFieldContent(Field f, int indirectionIndex) {
// the indirection index for field content starts at 1 (because `TFieldContent` is thought of as
// the address of the field, `FieldAddress` in the IR).
indirectionIndex = [1 .. Ssa::getMaxIndirectionsForType(f.getUnspecifiedType())] and
// Reads and writes of union fields are tracked using `UnionContent`.
not f.getDeclaringType() instanceof Union
@@ -2438,8 +2246,7 @@ private newtype TContent =
f = u.getAField() and
bytes = getFieldSize(f) and
// We key `UnionContent` by the union instead of its fields since a write to one
// field can be read by any read of the union's fields. Again, the indirection index
// is 1-based (because 0 is considered the address).
// field can be read by any read of the union's fields.
indirectionIndex =
[1 .. max(Ssa::getMaxIndirectionsForType(getAFieldWithSize(u, bytes).getUnspecifiedType()))]
)
@@ -2473,14 +2280,16 @@ class Content extends TContent {
abstract predicate impliesClearOf(Content c);
}
/**
* Gets a string consisting of `n` star characters ("*"), where n >= 0. This is
* used to represent indirection.
*/
bindingset[n]
string repeatStars(int n) { result = concat(int i | i in [1 .. n] | "*") }
private module ContentStars {
private int maxNumberOfIndirections() { result = max(any(Content c).getIndirectionIndex()) }
private string repeatStars(int n) {
n = 0 and result = ""
or
n = [1 .. maxNumberOfIndirections()] and
result = "*" + repeatStars(n - 1)
}
/**
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
* output for `c`.
@@ -2560,12 +2369,6 @@ class UnionContent extends Content, TUnionContent {
* stored into (`getAStoreContent`) or read from (`getAReadContent`).
*/
class ContentSet instanceof Content {
/**
* Holds if this content set is the singleton `{c}`. At present, this is
* the only kind of content set supported in C/C++.
*/
predicate isSingleton(Content c) { this = c }
/** Gets a content that may be stored into when storing into this set. */
Content getAStoreContent() { result = this }
@@ -2783,5 +2586,5 @@ class AdditionalCallTarget extends Unit {
/**
* Gets a viable target for `call`.
*/
abstract Declaration viableTarget(Call call);
abstract DataFlowCallable viableTarget(Call call);
}

View File

@@ -3,26 +3,12 @@
* `toString` for `Instruction` and `Operand` dataflow nodes.
*/
private import cpp
private import semmle.code.cpp.ir.IR
private import codeql.util.Unit
private import Node0ToString
private import DataFlowUtil
private import DataFlowPrivate
/**
* Gets the string representation of the unconverted expression `loc` if
* `loc` is an `Expression`.
*
* Otherwise, this gets the string representation of `loc`.
*/
private string unconvertedAstToString(Locatable loc) {
result = loc.(Expr).getUnconverted().toString()
or
not loc instanceof Expr and
result = loc.toString()
}
private class NormalNode0ToString extends Node0ToString {
NormalNode0ToString() {
// Silence warning about `this` not being bound.
@@ -32,10 +18,14 @@ private class NormalNode0ToString extends Node0ToString {
override string instructionToString(Instruction i) {
if i.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = unconvertedAstToString(i.getAst())
else result = i.getAst().toString()
}
override string operandToString(Operand op) { result = this.instructionToString(op.getDef()) }
override string operandToString(Operand op) {
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = op.getDef().getAst().toString()
}
override string toExprString(Node n) {
result = n.asExpr(0).toString()

View File

@@ -10,7 +10,7 @@ private import PrintIRUtilities
*/
private string getFromFlow(Node node2, int order1, int order2) {
exists(Node node1 |
simpleLocalFlowStep(node1, node2, _) and
simpleLocalFlowStep(node1, node2) and
result = nodeId(node1, order1, order2)
)
}
@@ -20,7 +20,7 @@ private string getFromFlow(Node node2, int order1, int order2) {
*/
private string getToFlow(Node node1, int order1, int order2) {
exists(Node node2 |
simpleLocalFlowStep(node1, node2, _) and
simpleLocalFlowStep(node1, node2) and
result = nodeId(node2, order1, order2)
)
}

View File

@@ -19,6 +19,15 @@ private module SourceVariables {
ind = [0 .. countIndirectionsForCppType(base.getLanguageType()) + 1]
}
private int maxNumberOfIndirections() { result = max(SourceVariable sv | | sv.getIndirection()) }
private string repeatStars(int n) {
n = 0 and result = ""
or
n = [1 .. maxNumberOfIndirections()] and
result = "*" + repeatStars(n - 1)
}
class SourceVariable extends TSourceVariable {
BaseSourceVariable base;
int ind;
@@ -64,27 +73,18 @@ private module SourceVariables {
import SourceVariables
/**
* Holds if `indirectionIndex` is a valid non-zero indirection index for
* operand `op`. That is, `indirectionIndex` is between 1 and the maximum
* indirection for the operand's type.
*/
predicate hasIndirectOperand(Operand op, int indirectionIndex) {
exists(CppType type, int m |
not ignoreOperand(op) and
type = getLanguageType(op) and
m = countIndirectionsForCppType(type) and
indirectionIndex = [1 .. m]
)
}
/**
* Holds if the `(operand, indirectionIndex)` columns should be
* assigned a `RawIndirectOperand` value.
*/
predicate hasRawIndirectOperand(Operand op, int indirectionIndex) {
hasIndirectOperand(op, indirectionIndex) and
not hasIRRepresentationOfIndirectOperand(op, indirectionIndex, _, _)
exists(CppType type, int m |
not ignoreOperand(op) and
type = getLanguageType(op) and
m = countIndirectionsForCppType(type) and
indirectionIndex = [1 .. m] and
not hasIRRepresentationOfIndirectOperand(op, indirectionIndex, _, _)
)
}
/**
@@ -443,8 +443,6 @@ class FinalParameterUse extends UseImpl, TFinalParameterUse {
Parameter getParameter() { result = p }
int getArgumentIndex() { result = p.getIndex() }
override Node getNode() { finalParameterNodeHasParameterAndIndex(result, p, ind) }
override int getIndirection() { result = ind + 1 }
@@ -893,7 +891,7 @@ private predicate isArgumentOfCallableInstruction(DataFlowCall call, Instruction
}
private predicate isArgumentOfCallableOperand(DataFlowCall call, Operand operand) {
operand = call.getArgumentOperand(_)
operand.(ArgumentOperand).getCall() = call
or
exists(FieldAddressInstruction fai |
fai.getObjectAddressOperand() = operand and

View File

@@ -6,7 +6,6 @@ private import DataFlowImplCommon as DataFlowImplCommon
private import DataFlowUtil
private import semmle.code.cpp.models.interfaces.PointerWrapper
private import DataFlowPrivate
private import TypeFlow
private import semmle.code.cpp.ir.ValueNumbering
/**
@@ -956,7 +955,11 @@ private module Cached {
* Holds if the address computed by `operand` is guaranteed to write
* to a specific address.
*/
private predicate isCertainAddress(Operand operand) { isPointerToSingleObject(operand.getDef()) }
private predicate isCertainAddress(Operand operand) {
valueNumberOfOperand(operand).getAnInstruction() instanceof VariableAddressInstruction
or
operand.getType() instanceof Cpp::ReferenceType
}
/**
* Holds if `address` is a use of an SSA variable rooted at `base`, and the

View File

@@ -6,26 +6,16 @@ private import semmle.code.cpp.models.interfaces.SideEffect
private import DataFlowUtil
private import DataFlowPrivate
private import SsaInternals as Ssa
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.cpp.ir.dataflow.FlowSteps
/**
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
* (intra-procedural) step. This relation is only used for local taint flow
* (for example `TaintTracking::localTaint(source, sink)`) so it may contain
* special cases that should only apply to local taint flow.
* (intra-procedural) step.
*/
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// dataflow step
DataFlow::localFlowStep(nodeFrom, nodeTo)
or
// taint flow step
localAdditionalTaintStep(nodeFrom, nodeTo, _)
or
// models-as-data summarized flow for local data flow (i.e. special case for flow
// through calls to modeled functions, without relying on global dataflow to join
// the dots).
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(nodeFrom, nodeTo, _)
localAdditionalTaintStep(nodeFrom, nodeTo)
}
/**
@@ -34,11 +24,10 @@ predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
* different objects.
*/
cached
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) {
operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction()) and
model = ""
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction())
or
modeledTaintStep(nodeFrom, nodeTo, model)
modeledTaintStep(nodeFrom, nodeTo)
or
// Flow from (the indirection of) an operand of a pointer arithmetic instruction to the
// indirection of the pointer arithmetic instruction. This provides flow from `source`
@@ -46,22 +35,15 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
exists(PointerArithmeticInstruction pai, int indirectionIndex |
nodeHasOperand(nodeFrom, pai.getAnOperand(), pragma[only_bind_into](indirectionIndex)) and
hasInstructionAndIndex(nodeTo, pai, indirectionIndex + 1)
) and
model = ""
)
or
any(Ssa::Indirection ind).isAdditionalTaintStep(nodeFrom, nodeTo) and
model = ""
or
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), false, model)
any(Ssa::Indirection ind).isAdditionalTaintStep(nodeFrom, nodeTo)
or
// object->field conflation for content that is a `TaintInheritingContent`.
exists(DataFlow::ContentSet f |
readStep(nodeFrom, f, nodeTo) and
f.getAReadContent() instanceof TaintInheritingContent
) and
model = ""
)
}
/**
@@ -138,8 +120,8 @@ predicate localExprTaint(Expr e1, Expr e2) {
* Holds if the additional step from `src` to `sink` should be included in all
* global taint flow configurations.
*/
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink, string model) {
localAdditionalTaintStep(src, sink, model)
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
localAdditionalTaintStep(src, sink)
}
/**
@@ -159,7 +141,7 @@ predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
* Holds if taint can flow from `nodeIn` to `nodeOut` through a call to a
* modeled function.
*/
predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut, string model) {
predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut) {
// Normal taint steps
exists(CallInstruction call, TaintFunction func, FunctionInput modelIn, FunctionOutput modelOut |
call.getStaticCallTarget() = func and
@@ -168,8 +150,7 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut, string
nodeIn = callInput(call, modelIn) and nodeOut = callOutput(call, modelOut)
or
exists(int d | nodeIn = callInput(call, modelIn, d) and nodeOut = callOutput(call, modelOut, d))
) and
model = "TaintFunction"
)
or
// Taint flow from one argument to another and data flow from an argument to a
// return value. This happens in functions like `strcat` and `memcpy`. We
@@ -186,8 +167,7 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut, string
func.(TaintFunction).hasTaintFlow(modelIn, modelMidOut) and
func.(DataFlowFunction).hasDataFlow(modelMidIn, modelOut) and
modelMidOut.isParameterDeref(indexMid) and
modelMidIn.isParameter(indexMid) and
model = "TaintFunction"
modelMidIn.isParameter(indexMid)
)
or
// Taint flow from a pointer argument to an output, when the model specifies flow from the deref
@@ -200,11 +180,9 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut, string
indirectArgument.hasAddressOperandAndIndirectionIndex(nodeIn.asOperand(), _) and
call.getStaticCallTarget() = func and
(
func.(DataFlowFunction).hasDataFlow(modelIn, modelOut) and
model = "DataFlowFunction"
func.(DataFlowFunction).hasDataFlow(modelIn, modelOut)
or
func.(TaintFunction).hasTaintFlow(modelIn, modelOut) and
model = "TaintFunction"
func.(TaintFunction).hasTaintFlow(modelIn, modelOut)
) and
nodeOut = callOutput(call, modelOut)
)

View File

@@ -1,278 +0,0 @@
private import cpp
private import semmle.code.cpp.ir.IR
private import codeql.typeflow.TypeFlow
private module Input implements TypeFlowInput<Location> {
/** Holds if `alloc` dynamically allocates a single object. */
private predicate isSingleObjectAllocation(AllocationExpr alloc) {
// i.e., `new int`;
alloc instanceof NewExpr
or
// i.e., `malloc(sizeof(int))`
exists(SizeofTypeOperator sizeOf | sizeOf = alloc.getSizeExpr() |
not sizeOf.getTypeOperand().getUnspecifiedType() instanceof ArrayType
)
}
/**
* Holds if `i` is the result of a dynamic allocation.
*
* `isObject` is `true` if the allocation allocated a single object,
* and `false` otherwise.
*/
private predicate isAllocation(Instruction i, boolean isObject) {
exists(AllocationExpr alloc | alloc = i.getUnconvertedResultExpression() |
if isSingleObjectAllocation(alloc) then isObject = true else isObject = false
)
}
private predicate hasExactSingleType(Instruction i) {
// The address of a variable is always a single object
i instanceof VariableAddressInstruction
or
// A reference always points to a single object
i.getResultLanguageType().hasUnspecifiedType(any(ReferenceType rt), false)
or
// `this` is never an array
i instanceof InitializeThisInstruction
or
// An allocation of a non-array object
isAllocation(i, true)
}
private predicate hasExactBufferType(Instruction i) {
// Anything with an array type is a buffer
i.getResultLanguageType().hasUnspecifiedType(any(ArrayType at), false)
or
// An allocation expression that we couldn't conclude allocated a single
// expression is assigned a buffer type.
isAllocation(i, false)
}
private newtype TTypeFlowNode =
TInstructionNode(Instruction i) or
TFunctionNode(IRFunction func)
abstract class TypeFlowNode extends TTypeFlowNode {
/** Gets a textual representation of this node. */
abstract string toString();
/**
* Gets the type of this node. This type may not be the most precise
* possible type, but will be used as a starting point of the analysis.
*/
abstract Type getType();
/** Gets the location of this node. */
abstract Location getLocation();
/** Gets the underlying `Instruction` of this node, if any. */
Instruction asInstruction() { none() }
/** Gets the underlying `IRFunction` of this node, if any. */
IRFunction asFunction() { none() }
/** Holds if the value of this node is always null. */
abstract predicate isNullValue();
}
private class InstructionNode extends TypeFlowNode, TInstructionNode {
Instruction instr;
InstructionNode() { this = TInstructionNode(instr) }
override string toString() { result = instr.toString() }
override Type getType() {
if hasExactSingleType(instr) then result.isSingle() else result.isBuffer()
}
override Location getLocation() { result = instr.getLocation() }
override Instruction asInstruction() { result = instr }
override predicate isNullValue() {
instr.(ConstantInstruction).getValue() = "0" and
instr.getResultIRType() instanceof IRAddressType
}
}
/** Gets the `TypeFlowNode` corresponding to `i`. */
additional InstructionNode instructionNode(Instruction i) { result.asInstruction() = i }
private class FunctionNode extends TypeFlowNode, TFunctionNode {
IRFunction func;
FunctionNode() { this = TFunctionNode(func) }
override string toString() { result = func.toString() }
Instruction getReturnValueInstruction() {
result = func.getReturnInstruction().(ReturnValueInstruction).getReturnValue()
}
override Type getType() { result = instructionNode(this.getReturnValueInstruction()).getType() }
override Location getLocation() { result = func.getLocation() }
override IRFunction asFunction() { result = func }
override predicate isNullValue() {
instructionNode(this.getReturnValueInstruction()).isNullValue()
}
}
/**
* Gets an ultimiate definition of `phi`. That is, an input to `phi` that is
* not itself a `PhiInstruction`.
*/
private Instruction getAnUltimateLocalDefinition(PhiInstruction phi) {
result = phi.getAnInput*() and not result instanceof PhiInstruction
}
/**
* Holds if this function is private (i.e., cannot be accessed outside its
* compilation unit). This means we can use a closed-world assumption about
* calls to this function.
*/
private predicate isPrivate(Function func) {
// static functions have internal linkage
func.isStatic()
or
// anonymous namespaces have internal linkage
func.getNamespace().getParentNamespace*().isAnonymous()
or
// private member functions are only called internally from inside the class
func.(MemberFunction).isPrivate()
}
/**
* Holds if `arg` is an argument for the parameter `p` in a private callable.
*/
pragma[nomagic]
private predicate privateParamArg(InitializeParameterInstruction p, Instruction arg) {
exists(CallInstruction call, int i, Function func |
call.getArgument(pragma[only_bind_into](i)) = arg and
func = call.getStaticCallTarget() and
func.getParameter(pragma[only_bind_into](i)) = p.getParameter() and
isPrivate(func)
)
}
predicate joinStep(TypeFlowNode n1, TypeFlowNode n2) {
// instruction -> phi
getAnUltimateLocalDefinition(n2.asInstruction()) = n1.asInstruction()
or
// return value -> function
n2.(FunctionNode).getReturnValueInstruction() = n1.asInstruction()
or
// function -> call
exists(Function func | func = n1.asFunction().getFunction() |
not func.isVirtual() and
n2.asInstruction().(CallInstruction).getStaticCallTarget() = func
)
or
// Argument -> parameter where the parameter's enclosing function
// is "private".
exists(Instruction arg, Instruction p |
privateParamArg(p, arg) and
n1.asInstruction() = arg and
n2.asInstruction() = p
)
}
/**
* Holds if knowing whether `i1` points to a single object or buffer implies
* knowing whether `i2` points to a single object or buffer.
*/
private predicate instructionStep(Instruction i1, Instruction i2) {
i2.(CopyInstruction).getSourceValue() = i1
or
i2.(CopyValueInstruction).getSourceValue() = i1
or
i2.(ConvertInstruction).getUnary() = i1
or
i2.(CheckedConvertOrNullInstruction).getUnary() = i1
or
i2.(InheritanceConversionInstruction).getUnary() = i1
or
i2.(PointerArithmeticInstruction).getLeft() = i1
}
predicate step(TypeFlowNode n1, TypeFlowNode n2) {
instructionStep(n1.asInstruction(), n2.asInstruction())
}
predicate isNullValue(TypeFlowNode n) { n.isNullValue() }
private newtype TType =
TSingle() or
TBuffer()
class Type extends TType {
string toString() {
this.isSingle() and
result = "Single"
or
this.isBuffer() and
result = "Buffer"
}
/** Holds if this type is the type that represents a single object. */
predicate isSingle() { this = TSingle() }
/** Holds if this type is the type that represents a buffer. */
predicate isBuffer() { this = TBuffer() }
/**
* Gets a super type of this type, if any.
*
* The type relation is `Single <: Buffer`.
*/
Type getASupertype() {
this.isSingle() and
result.isBuffer()
}
}
predicate exactTypeBase(TypeFlowNode n, Type t) {
exists(Instruction instr | instr = n.asInstruction() |
hasExactSingleType(instr) and t.isSingle()
or
hasExactBufferType(instr) and t.isBuffer()
)
}
pragma[nomagic]
private predicate upcastCand(TypeFlowNode n, Type t1, Type t2) {
exists(TypeFlowNode next |
step(n, next)
or
joinStep(n, next)
|
n.getType() = t1 and
next.getType() = t2 and
t1 != t2
)
}
private predicate upcast(TypeFlowNode n, Type t1) {
exists(Type t2 | upcastCand(n, t1, t2) |
// No need for transitive closure since the subtyping relation is just `Single <: Buffer`
t1.getASupertype() = t2
)
}
predicate typeFlowBaseCand(TypeFlowNode n, Type t) { upcast(n, t) }
}
private module TypeFlow = Make<Location, Input>;
/**
* Holds if `i` is an instruction that computes an address that points to a
* single object (as opposed to pointing into a buffer).
*/
pragma[nomagic]
predicate isPointerToSingleObject(Instruction i) {
TypeFlow::bestTypeFlow(Input::instructionNode(i), any(Input::Type t | t.isSingle()), _)
}

View File

@@ -127,7 +127,7 @@ abstract deprecated class Configuration extends DataFlow::Configuration {
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
this.isAdditionalTaintStep(node1, node2) or
defaultAdditionalTaintStep(node1, node2, _)
defaultAdditionalTaintStep(node1, node2)
}
/**

View File

@@ -127,7 +127,7 @@ abstract deprecated class Configuration extends DataFlow::Configuration {
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
this.isAdditionalTaintStep(node1, node2) or
defaultAdditionalTaintStep(node1, node2, _)
defaultAdditionalTaintStep(node1, node2)
}
/**

View File

@@ -127,7 +127,7 @@ abstract deprecated class Configuration extends DataFlow::Configuration {
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
this.isAdditionalTaintStep(node1, node2) or
defaultAdditionalTaintStep(node1, node2, _)
defaultAdditionalTaintStep(node1, node2)
}
/**

View File

@@ -41,5 +41,5 @@ class IREscapeAnalysisConfiguration extends TIREscapeAnalysisConfiguration {
* Holds if the escape analysis done by SSA construction should be sound. By default, the SSA is
* built assuming that no variable's address ever escapes.
*/
predicate useSoundEscapeAnalysis() { any() }
predicate useSoundEscapeAnalysis() { none() }
}

View File

@@ -89,8 +89,7 @@ newtype TInstructionTag =
ImplicitDestructorTag(int index) {
exists(Expr e | exists(e.getImplicitDestructorCall(index))) or
exists(Stmt s | exists(s.getImplicitDestructorCall(index)))
} or
CoAwaitBranchTag()
}
class InstructionTag extends TInstructionTag {
final string toString() { result = getInstructionTagId(this) }
@@ -187,8 +186,6 @@ string getInstructionTagId(TInstructionTag tag) {
or
tag = BoolConversionCompareTag() and result = "BoolConvComp"
or
tag = ResultCopyTag() and result = "ResultCopy"
or
tag = LoadTag() and result = "Load" // Implicit load due to lvalue-to-rvalue conversion
or
tag = CatchTag() and result = "Catch"
@@ -266,6 +263,4 @@ string getInstructionTagId(TInstructionTag tag) {
exists(int index |
tag = ImplicitDestructorTag(index) and result = "ImplicitDestructor(" + index + ")"
)
or
tag = CoAwaitBranchTag() and result = "CoAwaitBranch"
}

View File

@@ -128,10 +128,8 @@ private predicate ignoreExprAndDescendants(Expr expr) {
vaStartExpr.getLastNamedParameter().getFullyConverted() = expr
)
or
// Do not translate implicit destructor calls for unnamed temporary variables that are
// conditionally constructed (until we have a mechanism for calling these only when the
// temporary's constructor was run)
isConditionalTemporaryDestructorCall(expr)
// suppress destructors of temporary variables until proper support is added for them.
exists(Expr parent | parent.getAnImplicitDestructorCall() = expr)
}
/**
@@ -257,42 +255,6 @@ private predicate usedAsCondition(Expr expr) {
)
}
private predicate hasThrowingChild(Expr e) {
e = any(ThrowExpr throw).getFullyConverted()
or
exists(Expr child |
e = getRealParent(child) and
hasThrowingChild(child)
)
}
private predicate isInConditionalEvaluation(Expr e) {
exists(ConditionalExpr cond |
e = cond.getThen().getFullyConverted() and not cond.isTwoOperand()
or
e = cond.getElse().getFullyConverted()
or
// If one of the operands throws then the temporaries constructed in either
// branch will also be attached to the ternary expression. We suppress
// those destructor calls as well.
hasThrowingChild([cond.getThen(), cond.getElse()]) and
e = cond.getFullyConverted()
)
or
e = any(LogicalAndExpr lae).getRightOperand().getFullyConverted()
or
e = any(LogicalOrExpr loe).getRightOperand().getFullyConverted()
or
isInConditionalEvaluation(getRealParent(e))
}
private predicate isConditionalTemporaryDestructorCall(DestructorCall dc) {
exists(TemporaryObjectExpr temp |
temp = dc.getQualifier().(ReuseExpr).getReusedExpr() and
isInConditionalEvaluation(temp)
)
}
/**
* Holds if `conv` is an `InheritanceConversion` that requires a `TranslatedLoad`, despite not being
* marked as having an lvalue-to-rvalue conversion.
@@ -544,7 +506,8 @@ private module IRDeclarationEntries {
* An entity that represents a declaration entry in the database.
*
* This class exists to work around the fact that `DeclStmt`s in some cases
* do not have `DeclarationEntry`s in older databases.
* do not have `DeclarationEntry`s. Currently, this is the case for:
* - `DeclStmt`s in template instantiations.
*
* So instead, the IR works with `IRDeclarationEntry`s that synthesize missing
* `DeclarationEntry`s when there is no result for `DeclStmt::getDeclarationEntry`.
@@ -820,16 +783,6 @@ newtype TTranslatedElement =
not ignoreSideEffects(expr) and
opcode = getCallSideEffectOpcode(expr)
} or
// The set of destructors to invoke after a `throw`. These need to be special
// cased because the edge kind following a throw is an `ExceptionEdge`, and
// we need to make sure that the edge kind is still an `ExceptionEdge` after
// all the destructors have run.
TTranslatedDestructorsAfterThrow(ThrowExpr throw) {
exists(DestructorCall dc |
dc = throw.getAnImplicitDestructorCall() and
not ignoreExpr(dc)
)
} or
// A precise side effect of an argument to a `Call`
TTranslatedArgumentExprSideEffect(Call call, Expr expr, int n, SideEffectOpcode opcode) {
not ignoreExpr(expr) and

View File

@@ -90,26 +90,10 @@ abstract class TranslatedExpr extends TranslatedElement {
final override TranslatedElement getChild(int id) {
result = this.getChildInternal(id)
or
exists(int destructorIndex |
result = this.getImplicitDestructorCall(destructorIndex) and
id = this.getFirstDestructorCallIndex() + destructorIndex
)
}
final private TranslatedExpr getImplicitDestructorCall(int index) {
result.getExpr() = expr.getImplicitDestructorCall(index)
}
final override predicate hasAnImplicitDestructorCall() {
exists(this.getImplicitDestructorCall(_))
}
final override int getFirstDestructorCallIndex() {
not this.handlesDestructorsExplicitly() and
(
result = max(int childId | exists(this.getChildInternal(childId))) + 1
or
not exists(this.getChildInternal(_)) and result = 0
exists(int maxChildId, int destructorIndex |
maxChildId = max(int childId | exists(this.getChildInternal(childId))) and
result.(TranslatedExpr).getExpr() = expr.getImplicitDestructorCall(destructorIndex) and
id = maxChildId + 1 + destructorIndex
)
}
@@ -411,14 +395,6 @@ class TranslatedLoad extends TranslatedValueCategoryAdjustment, TTranslatedLoad
result = this.getOperand().getResult()
)
}
override predicate handlesDestructorsExplicitly() {
// The class that generates IR for `e` will (implicitly or explicitly)
// handle the generation of destructor calls for `e`. Without disabling
// destructor call generation here the destructor will get multiple
// parents.
any()
}
}
/**
@@ -1306,146 +1282,6 @@ class TranslatedUnaryExpr extends TranslatedSingleInstructionExpr {
}
}
/**
* IR translation of a `co_await` or `co_yield` expression.
*
* The translation of `x = co_await ...` is essentially:
* ```cpp
* if (!awaiter.await_ready()) {
* awaiter.await_suspend();
* }
* x = awaiter.await_resume();
* ```
* where `awaiter` is an object constructed from programmer-supplied
* input, and for IR construction purposes these are resolved by the C/C++
* front-end.
*
* See https://en.cppreference.com/w/cpp/language/coroutines#co_await for the
* specification on how `awaiter` is obtained.
*/
abstract private class TranslatedCoExpr extends TranslatedNonConstantExpr {
/** Gets the operand of this operation. */
abstract Expr getOperand();
/**
* Gets the expression that decides if the enclosing coroutine should be
* suspended.
*/
abstract Expr getAwaitReady();
/**
* Gets the expression that is evaluated when the enclosing coroutine is
* suspended.
*/
abstract Expr getAwaitSuspend();
/**
* Gets the expression that represents the resume point if the enclosing
* coroutine was suspended.
*/
abstract Expr getAwaitResume();
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getTranslatedOperand().getFirstInstruction(kind)
}
override Instruction getALastInstructionInternal() {
result = this.getTranslatedAwaitResume().getALastInstruction()
}
final override TranslatedElement getChildInternal(int id) {
id = 0 and result = this.getTranslatedOperand()
or
id = 1 and result = this.getTranslatedAwaitReady()
or
id = 2 and result = this.getTranslatedAwaitResume()
or
id = 3 and result = this.getTranslatedAwaitSuspend()
}
final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
tag = CoAwaitBranchTag() and
(
kind instanceof TrueEdge and
result = this.getTranslatedAwaitResume().getFirstInstruction(any(GotoEdge goto))
or
kind instanceof FalseEdge and
result = this.getTranslatedAwaitSuspend().getFirstInstruction(any(GotoEdge goto))
)
}
override Instruction getResult() { result = this.getTranslatedAwaitResume().getResult() }
final override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
child = this.getTranslatedOperand() and
result = this.getTranslatedAwaitReady().getFirstInstruction(kind)
or
child = this.getTranslatedAwaitReady() and
kind instanceof GotoEdge and
result = this.getInstruction(CoAwaitBranchTag())
or
child = this.getTranslatedAwaitSuspend() and
result = this.getTranslatedAwaitResume().getFirstInstruction(kind)
or
child = this.getTranslatedAwaitResume() and
result = this.getParent().getChildSuccessor(this, kind)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = CoAwaitBranchTag() and
opcode instanceof Opcode::ConditionalBranch and
resultType = getVoidType()
}
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
tag = CoAwaitBranchTag() and
operandTag instanceof ConditionOperandTag and
result = this.getTranslatedAwaitReady().getResult()
}
private TranslatedExpr getTranslatedOperand() {
result = getTranslatedExpr(this.getOperand().getFullyConverted())
}
private TranslatedExpr getTranslatedAwaitReady() {
result = getTranslatedExpr(this.getAwaitReady().getFullyConverted())
}
private TranslatedExpr getTranslatedAwaitResume() {
result = getTranslatedExpr(this.getAwaitResume().getFullyConverted())
}
private TranslatedExpr getTranslatedAwaitSuspend() {
result = getTranslatedExpr(this.getAwaitSuspend().getFullyConverted())
}
}
/** IR translation of `co_await`. */
class TranslatedCoAwaitExpr extends TranslatedCoExpr {
override CoAwaitExpr expr;
final override Expr getOperand() { result = expr.getOperand() }
final override Expr getAwaitReady() { result = expr.getAwaitReady() }
final override Expr getAwaitSuspend() { result = expr.getAwaitSuspend() }
final override Expr getAwaitResume() { result = expr.getAwaitResume() }
}
/** IR translation of `co_yield`. */
class TranslatedCoYieldxpr extends TranslatedCoExpr {
override CoYieldExpr expr;
final override Expr getOperand() { result = expr.getOperand() }
final override Expr getAwaitReady() { result = expr.getAwaitReady() }
final override Expr getAwaitSuspend() { result = expr.getAwaitSuspend() }
final override Expr getAwaitResume() { result = expr.getAwaitResume() }
}
abstract class TranslatedConversion extends TranslatedNonConstantExpr {
override Conversion expr;
@@ -2163,13 +1999,6 @@ abstract class TranslatedAllocationSize extends TranslatedExpr, TTranslatedAlloc
final override predicate producesExprResult() { none() }
final override Instruction getResult() { result = this.getInstruction(AllocationSizeTag()) }
final override predicate handlesDestructorsExplicitly() {
// Since the enclosing `TranslatedNewOrNewArrayExpr` (implicitly) handles the destructors
// we need to disable the implicit handling here as otherwise the destructors will have
// multiple parents
any()
}
}
TranslatedAllocationSize getTranslatedAllocationSize(NewOrNewArrayExpr newExpr) {
@@ -2327,13 +2156,6 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect
final override predicate producesExprResult() { none() }
final override predicate handlesDestructorsExplicitly() {
// Since the enclosing `TranslatedNewOrNewArrayExpr` (implicitly) handles the destructors
// we need to disable the implicit handling here as otherwise the destructors will have
// multiple parents
any()
}
override Function getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and result = expr.getAllocator()
}
@@ -2995,68 +2817,6 @@ class TranslatedReuseExpr extends TranslatedNonConstantExpr {
}
}
/**
* The IR translation of the destructor calls of the parent `TranslatedThrow`.
*
* This object does not itself generate the destructor calls. Instead, its
* children provide the actual calls, and this object ensures that we correctly
* exit with an `ExceptionEdge` after executing all the destructor calls.
*/
class TranslatedDestructorsAfterThrow extends TranslatedElement, TTranslatedDestructorsAfterThrow {
ThrowExpr throw;
TranslatedDestructorsAfterThrow() { this = TTranslatedDestructorsAfterThrow(throw) }
override string toString() { result = "Destructor calls after throw: " + throw }
private TranslatedCall getTranslatedImplicitDestructorCall(int id) {
result.getExpr() = throw.getImplicitDestructorCall(id)
}
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getChild(0).getFirstInstruction(kind)
}
override ThrowExpr getAst() { result = throw }
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) { none() }
override TranslatedElement getChild(int id) {
result = this.getTranslatedImplicitDestructorCall(id)
}
override predicate handlesDestructorsExplicitly() { any() }
override Declaration getFunction() { result = throw.getEnclosingFunction() }
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
exists(int id | child = this.getChild(id) |
// Transition to the next child, if any.
result = this.getChild(id + 1).getFirstInstruction(kind)
or
// And otherwise, exit this element with an exceptional edge
not exists(this.getChild(id + 1)) and
kind instanceof ExceptionEdge and
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
)
}
override TranslatedElement getLastChild() {
result =
this.getTranslatedImplicitDestructorCall(max(int id |
exists(throw.getImplicitDestructorCall(id))
))
}
override Instruction getALastInstructionInternal() {
result = this.getLastChild().getALastInstruction()
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
none()
}
}
/**
* IR translation of a `throw` expression.
*/
@@ -3071,22 +2831,13 @@ abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr {
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
tag = ThrowTag() and
(
result = this.getDestructors().getFirstInstruction(kind)
or
not exists(this.getDestructors()) and
kind instanceof ExceptionEdge and
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
)
kind instanceof ExceptionEdge and
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
}
override Instruction getResult() { none() }
abstract Opcode getThrowOpcode();
override predicate handlesDestructorsExplicitly() { any() }
TranslatedDestructorsAfterThrow getDestructors() { result.getAst() = expr }
}
/**
@@ -3098,9 +2849,6 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableIn
final override TranslatedElement getChildInternal(int id) {
result = TranslatedVariableInitialization.super.getChildInternal(id)
or
id = max(int i | exists(TranslatedVariableInitialization.super.getChildInternal(i))) + 1 and
result = this.getDestructors()
}
final override Instruction getChildSuccessorInternal(TranslatedElement elem, EdgeKind kind) {
@@ -3166,22 +2914,14 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableIn
class TranslatedReThrowExpr extends TranslatedThrowExpr {
override ReThrowExpr expr;
override TranslatedElement getChildInternal(int id) {
id = 0 and
result = this.getDestructors()
}
override TranslatedElement getChildInternal(int id) { none() }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(ThrowTag()) and
kind instanceof GotoEdge
}
override Instruction getALastInstructionInternal() {
result = this.getDestructors().getALastInstruction()
or
not this.hasAnImplicitDestructorCall() and
result = this.getInstruction(ThrowTag())
}
override Instruction getALastInstructionInternal() { result = this.getInstruction(ThrowTag()) }
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { none() }

View File

@@ -1501,41 +1501,3 @@ class TranslatedVlaDeclarationStmt extends TranslatedStmt {
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { none() }
}
class TranslatedCoReturnStmt extends TranslatedStmt {
override CoReturnStmt stmt;
private TranslatedExpr getTranslatedOperand() {
result = getTranslatedExpr(stmt.getOperand().getFullyConverted())
}
override TranslatedExpr getChildInternal(int id) {
id = 0 and
result = this.getTranslatedOperand()
}
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getTranslatedOperand().getFirstInstruction(kind)
}
override Instruction getALastInstructionInternal() {
result = this.getInstruction(OnlyInstructionTag())
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = OnlyInstructionTag() and
opcode instanceof Opcode::NoOp and
resultType = getVoidType()
}
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
result = this.getParent().getChildSuccessor(this, kind)
}
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
child = this.getTranslatedOperand() and
kind instanceof GotoEdge and
result = this.getInstruction(OnlyInstructionTag())
}
}

View File

@@ -1,6 +1,5 @@
private import implementations.Allocation
private import implementations.Deallocation
private import implementations.Fopen
private import implementations.Fread
private import implementations.Getenv
private import implementations.Gets
@@ -42,4 +41,4 @@ private import implementations.SqLite3
private import implementations.PostgreSql
private import implementations.System
private import implementations.StructuredExceptionHandling
private import implementations.ZMQ
private import implementations.Fopen

View File

@@ -112,21 +112,3 @@ private class GetsFunction extends DataFlowFunction, ArrayFunction, AliasFunctio
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
}
/**
* A model for `getc` and similar functions that are flow sources.
*/
private class GetcSource extends SourceModelCsv {
override predicate row(string row) {
row =
[
";;false;getc;;;ReturnValue;remote", ";;false;getwc;;;ReturnValue;remote",
";;false;_getc_nolock;;;ReturnValue;remote", ";;false;_getwc_nolock;;;ReturnValue;remote",
";;false;getch;;;ReturnValue;local", ";;false;_getch;;;ReturnValue;local",
";;false;_getwch;;;ReturnValue;local", ";;false;_getch_nolock;;;ReturnValue;local",
";;false;_getwch_nolock;;;ReturnValue;local", ";;false;getchar;;;ReturnValue;local",
";;false;getwchar;;;ReturnValue;local", ";;false;_getchar_nolock;;;ReturnValue;local",
";;false;_getwchar_nolock;;;ReturnValue;local",
]
}
}

View File

@@ -123,7 +123,7 @@ class IteratorCrementNonMemberOperator extends Operator {
}
private class IteratorCrementNonMemberOperatorModel extends IteratorCrementNonMemberOperator,
DataFlowFunction, SideEffectFunction, AliasFunction
DataFlowFunction
{
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
input = getIteratorArgumentInput(this, 0) and
@@ -131,24 +131,6 @@ private class IteratorCrementNonMemberOperatorModel extends IteratorCrementNonMe
or
input.isParameterDeref(0) and output.isReturnValueDeref()
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = 0 and buffer = false
}
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
// See the comment on `IteratorCrementMemberOperatorModel::hasSpecificWriteSideEffect`
// for an explanation of these values.
i = 0 and buffer = false and mustWrite = false
}
override predicate parameterNeverEscapes(int index) { none() }
override predicate parameterEscapesOnlyViaReturn(int index) { index = 0 }
}
/**
@@ -164,7 +146,7 @@ class IteratorCrementMemberOperator extends MemberFunction {
}
private class IteratorCrementMemberOperatorModel extends IteratorCrementMemberOperator,
DataFlowFunction, TaintFunction, SideEffectFunction, AliasFunction
DataFlowFunction, TaintFunction
{
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
input.isQualifierAddress() and
@@ -181,28 +163,6 @@ private class IteratorCrementMemberOperatorModel extends IteratorCrementMemberOp
input.isQualifierObject() and
output.isReturnValueDeref()
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
// We have two choices here: either `buffer` must be `true` or `mustWrite`
// must be `false` to ensure that the IR alias analysis doesn't think that
// `it++` completely override the value of the iterator.
// We choose `mustWrite` must be `false`. In that case, the value of
// `buffer` isn't super important (it just decides which kind of read side
// effect will be emitted).
i = -1 and buffer = false and mustWrite = false
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
}
/**
@@ -372,7 +332,7 @@ class IteratorAssignArithmeticOperator extends Function {
* non-member and member versions, use `IteratorPointerDereferenceOperator`.
*/
class IteratorPointerDereferenceMemberOperator extends MemberFunction, TaintFunction,
IteratorReferenceFunction, AliasFunction, SideEffectFunction
IteratorReferenceFunction
{
IteratorPointerDereferenceMemberOperator() {
this.getClassAndName("operator*") instanceof Iterator
@@ -385,18 +345,6 @@ class IteratorPointerDereferenceMemberOperator extends MemberFunction, TaintFunc
input.isReturnValueDeref() and
output.isQualifierObject()
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
/**
@@ -413,7 +361,7 @@ class IteratorPointerDereferenceNonMemberOperator extends Operator, IteratorRefe
}
private class IteratorPointerDereferenceNonMemberOperatorModel extends IteratorPointerDereferenceNonMemberOperator,
TaintFunction, AliasFunction, SideEffectFunction
TaintFunction
{
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input = getIteratorArgumentInput(this, 0) and
@@ -422,18 +370,6 @@ private class IteratorPointerDereferenceNonMemberOperatorModel extends IteratorP
input.isReturnValueDeref() and
output.isParameterDeref(0)
}
override predicate parameterNeverEscapes(int index) { index = 0 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = 0 and buffer = false
}
}
/**
@@ -484,71 +420,6 @@ class IteratorAssignmentMemberOperator extends MemberFunction {
}
}
/**
* A member `operator==` or `operator!=` function for an iterator type.
*
* Note that this class _only_ matches member functions. To find both
* non-member and member versions, use `IteratorLogicalOperator`.
*/
class IteratorLogicalMemberOperator extends MemberFunction {
IteratorLogicalMemberOperator() {
this.getClassAndName(["operator!=", "operator=="]) instanceof Iterator
}
}
private class IteratorLogicalMemberOperatorModel extends IteratorLogicalMemberOperator,
AliasFunction, SideEffectFunction
{
override predicate parameterNeverEscapes(int index) { index = [-1, 0] }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
/**
* A member `operator==` or `operator!=` function for an iterator type.
*
* Note that this class _only_ matches non-member functions. To find both
* non-member and member versions, use `IteratorLogicalOperator`.
*/
class IteratorLogicalNonMemberOperator extends Function {
IteratorLogicalNonMemberOperator() {
this.hasName(["operator!=", "operator=="]) and
exists(getIteratorArgumentInput(this, 0)) and
exists(getIteratorArgumentInput(this, 1))
}
}
private class IteratorLogicalNonMemberOperatorModel extends IteratorLogicalNonMemberOperator,
AliasFunction, SideEffectFunction
{
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}
/**
* A (member or non-member) `operator==` or `operator!=` function for an iterator type.
*/
class IteratorLogicalOperator extends Function {
IteratorLogicalOperator() {
this instanceof IteratorLogicalNonMemberOperator
or
this instanceof IteratorLogicalMemberOperator
}
}
/**
* An `operator=` member function of an iterator class that is not a copy or move assignment
* operator.
@@ -557,26 +428,12 @@ class IteratorLogicalOperator extends Function {
* `operator*` and use their own `operator=` to assign to the container.
*/
private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMemberOperator,
TaintFunction, SideEffectFunction, AliasFunction
TaintFunction
{
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isParameterDeref(0) and
output.isQualifierObject()
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
// See the comment on `IteratorCrementMemberOperatorModel::hasSpecificWriteSideEffect`
// for an explanation of these values.
i = -1 and buffer = false and mustWrite = false
}
override predicate parameterNeverEscapes(int index) { index = 0 }
override predicate parameterEscapesOnlyViaReturn(int index) { index = -1 }
}
/**

View File

@@ -1,45 +0,0 @@
/**
* Provides implementation classes modeling the ZeroMQ networking library.
*/
import semmle.code.cpp.models.interfaces.FlowSource
/**
* Remote flow sources.
*/
private class ZmqSource extends SourceModelCsv {
override predicate row(string row) {
row =
[
";;false;zmq_recv;;;Argument[*1];remote", ";;false;zmq_recvmsg;;;Argument[*1];remote",
";;false;zmq_msg_recv;;;Argument[*0];remote",
]
}
}
/**
* Remote flow sinks.
*/
private class ZmqSinks extends SinkModelCsv {
override predicate row(string row) {
row =
[
";;false;zmq_send;;;Argument[*1];remote-sink",
";;false;zmq_sendmsg;;;Argument[*1];remote-sink",
";;false;zmq_msg_send;;;Argument[*0];remote-sink",
]
}
}
/**
* Flow steps.
*/
private class ZmqSummaries extends SummaryModelCsv {
override predicate row(string row) {
row =
[
";;false;zmq_msg_init_data;;;Argument[*1];Argument[*0];taint",
";;false;zmq_msg_data;;;Argument[*0];ReturnValue[*];taint",
]
}
}

View File

@@ -9,7 +9,6 @@
import cpp
import FunctionInputsAndOutputs
import semmle.code.cpp.models.Models
import semmle.code.cpp.dataflow.ExternalFlow
/**
* A library function that returns data that may be read from a network connection.

View File

@@ -20,9 +20,6 @@ abstract class RemoteFlowSource extends FlowSource { }
/** A data flow source of local user input. */
abstract class LocalFlowSource extends FlowSource { }
/**
* A remote data flow source that is defined through a `RemoteFlowSourceFunction` model.
*/
private class RemoteModelSource extends RemoteFlowSource {
string sourceType;
@@ -37,9 +34,6 @@ private class RemoteModelSource extends RemoteFlowSource {
override string getSourceType() { result = sourceType }
}
/**
* A local data flow source that is defined through a `LocalFlowSourceFunction` model.
*/
private class LocalModelSource extends LocalFlowSource {
string sourceType;
@@ -54,9 +48,6 @@ private class LocalModelSource extends LocalFlowSource {
override string getSourceType() { result = sourceType }
}
/**
* A local data flow source that the `argv` parameter to `main`.
*/
private class ArgvSource extends LocalFlowSource {
ArgvSource() {
exists(Function main, Parameter argv |
@@ -69,33 +60,12 @@ private class ArgvSource extends LocalFlowSource {
override string getSourceType() { result = "a command-line argument" }
}
/**
* A remote data flow source that is defined through 'models as data'.
*/
private class ExternalRemoteFlowSource extends RemoteFlowSource {
ExternalRemoteFlowSource() { sourceNode(this, "remote") }
override string getSourceType() { result = "external" }
}
/**
* A local data flow source that is defined through 'models as data'.
*/
private class ExternalLocalFlowSource extends LocalFlowSource {
ExternalLocalFlowSource() { sourceNode(this, "local") }
override string getSourceType() { result = "external" }
}
/** A remote data flow sink. */
abstract class RemoteFlowSink extends DataFlow::Node {
/** Gets a string that describes the type of this flow sink. */
abstract string getSinkType();
}
/**
* A remote flow sink derived from the `RemoteFlowSinkFunction` model.
*/
private class RemoteParameterSink extends RemoteFlowSink {
string sourceType;
@@ -109,12 +79,3 @@ private class RemoteParameterSink extends RemoteFlowSink {
override string getSinkType() { result = sourceType }
}
/**
* A remote flow sink defined in a CSV model.
*/
private class RemoteFlowFromCsvSink extends RemoteFlowSink {
RemoteFlowFromCsvSink() { sinkNode(this, "remote-sink") }
override string getSinkType() { result = "remote flow sink" }
}

View File

@@ -139,7 +139,6 @@ private module ParameterSinks {
}
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
/**
* Holds if `n` represents the expression `e`, and `e` is a pointer that is
@@ -150,11 +149,11 @@ private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
predicate isUse(DataFlow::Node n, Expr e) {
isUse0(e) and n.asExpr() = e
or
exists(DataFlowCall call, InitializeParameterInstruction init |
exists(CallInstruction call, InitializeParameterInstruction init |
n.asOperand().getDef().getUnconvertedResultExpression() = e and
pragma[only_bind_into](init) = ParameterSinks::getAnAlwaysDereferencedParameter() and
viableParamArg(call, DataFlow::instructionNode(init), n) and
pragma[only_bind_out](init.getEnclosingFunction()) =
pragma[only_bind_out](call.asCallInstruction().getStaticCallTarget())
pragma[only_bind_out](call.getStaticCallTarget())
)
}

View File

@@ -1,7 +1,3 @@
## 0.9.10
No user-facing changes.
## 0.9.9
### New Queries

View File

@@ -31,9 +31,7 @@ predicate useFunc(GlobalVariable v, Function f) {
}
predicate uninitialisedBefore(GlobalVariable v, Function f) {
f.hasGlobalName("main") and
not initialisedAtDeclaration(v) and
not isStdlibVariable(v)
f.hasGlobalName("main")
or
exists(Call call, Function g |
uninitialisedBefore(v, g) and
@@ -100,15 +98,10 @@ predicate callReaches(Call call, ControlFlowNode successor) {
)
}
/** Holds if `v` has an initializer. */
predicate initialisedAtDeclaration(GlobalVariable v) { exists(v.getInitializer()) }
/** Holds if `v` is a global variable that does not need to be initialized. */
predicate isStdlibVariable(GlobalVariable v) { v.hasGlobalName(["stdin", "stdout", "stderr"]) }
from GlobalVariable v, Function f
where
uninitialisedBefore(v, f) and
useFunc(v, f)
select f, "The variable $@ is used in this function but may not be initialized when it is called.",
v, v.getName()
select f,
"The variable '" + v.getName() +
" is used in this function but may not be initialized when it is called."

View File

@@ -15,8 +15,6 @@ import cpp
from StackVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked
where
checked = v.getAnAccess() and
// The check can often be in a macro for handling exception
not checked.isInMacroExpansion() and
dereferenced(checked) and
unchecked = v.getAnAccess() and
dereferenced(unchecked) and

View File

@@ -14,10 +14,5 @@ predicate hasDuplicateFunctionEntryPointLocation(Function func) {
predicate hasDuplicateFunctionEntryPoint(Function func) { count(func.getEntryPoint()) > 1 }
predicate hasDuplicateDeclarationEntry(DeclStmt stmt, int i) {
strictcount(stmt.getDeclarationEntry(i)) > 1
}
select count(Function f | hasDuplicateFunctionEntryPoint(f)) as duplicateFunctionEntryPoint,
count(Function f | hasDuplicateFunctionEntryPointLocation(f)) as duplicateFunctionEntryPointLocation,
count(DeclStmt stmt, int i | hasDuplicateDeclarationEntry(stmt, i)) as duplicateDeclarationEntry
select count(Function f | hasDuplicateFunctionEntryPoint(f) | f) as duplicateFunctionEntryPoint,
count(Function f | hasDuplicateFunctionEntryPointLocation(f) | f) as duplicateFunctionEntryPointLocation

View File

@@ -16,7 +16,6 @@ import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.models.interfaces.FlowSource
import semmle.code.cpp.models.implementations.Memset
import semmle.code.cpp.security.FlowSources
import ExposedSystemData::PathGraph
import SystemData
@@ -24,11 +23,11 @@ module ExposedSystemDataConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source = any(SystemData sd).getAnExpr() }
predicate isSink(DataFlow::Node sink) {
sink instanceof RemoteFlowSink
or
// workaround for cases where the sink contains the tainted thing as a child; this could
// probably be handled better with taint inheriting content or similar modeling.
exists(RemoteFlowSink sinkNode | sinkNode.asIndirectExpr().getAChild*() = sink.asIndirectExpr())
exists(FunctionCall fc, FunctionInput input, int arg |
fc.getTarget().(RemoteFlowSinkFunction).hasRemoteFlowSink(input, _) and
input.isParameterDeref(arg) and
fc.getArgument(arg).getAChild*() = sink.asIndirectExpr()
)
}
predicate isBarrier(DataFlow::Node node) {

View File

@@ -35,7 +35,7 @@ module XxeConfig implements DataFlow::StateConfigSig {
) {
// create additional flow steps for `XxeFlowStateTransformer`s
state2 = node2.asIndirectExpr().(XxeFlowStateTransformer).transform(state1) and
DataFlow::simpleLocalFlowStep(node1, node2, _)
DataFlow::simpleLocalFlowStep(node1, node2)
}
predicate isBarrier(DataFlow::Node node, FlowState flowstate) {

View File

@@ -1,5 +0,0 @@
---
category: minorAnalysis
---
* The "Global variable may be used before initialization" query (`cpp/global-use-before-init`) no longer raises an alert on global variables that are initialized when they are declared.
* The "Inconsistent null check of pointer" query (`cpp/inconsistent-nullness-testing`) query no longer raises an alert when the guarded check is in a macro expansion.

View File

@@ -1,3 +0,0 @@
## 0.9.10
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.9.10
lastReleaseVersion: 0.9.9

View File

@@ -11,6 +11,7 @@
* external/cwe/cwe-664
*/
// IMPORTANT: This query does not currently find anything since it relies on extractor and analysis improvements that hasn't yet been released
import cpp
import semmle.code.cpp.ir.IR
import semmle.code.cpp.dataflow.new.DataFlow
@@ -18,20 +19,26 @@ import semmle.code.cpp.models.implementations.StdContainer
import semmle.code.cpp.models.implementations.StdMap
import semmle.code.cpp.models.implementations.Iterator
private predicate tempToDestructorSink(DataFlow::Node sink, CallInstruction call) {
call = sink.asOperand().(ThisArgumentOperand).getCall() and
call.getStaticCallTarget() instanceof Destructor
/**
* A configuration to track flow from a temporary variable to the qualifier of
* a destructor call
*/
module TempToDestructorConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asInstruction().(VariableAddressInstruction).getIRVariable() instanceof IRTempVariable
}
predicate isSink(DataFlow::Node sink) {
sink.asOperand().(ThisArgumentOperand).getCall().getStaticCallTarget() instanceof Destructor
}
}
/** Holds if `pun` is the post-update node of the qualifier of `Call`. */
private predicate isPostUpdateOfQualifier(CallInstruction call, DataFlow::PostUpdateNode pun) {
call.getThisArgumentOperand() = pun.getPreUpdateNode().asOperand()
}
module TempToDestructorFlow = DataFlow::Global<TempToDestructorConfig>;
/**
* Gets a `DataFlow::Node` that represents a temporary that will be destroyed
* by a call to a destructor when `n` is destroyed, or a `DataFlow::Node` that
* will transitively be destroyed by a call to a destructor.
* by a call to a destructor, or a `DataFlow::Node` that will transitively be
* destroyed by a call to a destructor.
*
* For the latter case, consider something like:
* ```
@@ -43,25 +50,22 @@ private predicate isPostUpdateOfQualifier(CallInstruction call, DataFlow::PostUp
* destroyed by a call to `std::vector<std::vector<int>>::~vector`,
* and thus the result of `get_2d_vector()[0]` is also an invalid reference.
*/
DataFlow::Node getADestroyedNode(DataFlow::Node n) {
// Case 1: The pointer that goes into the destructor call is destroyed
exists(CallInstruction destructorCall |
tempToDestructorSink(n, destructorCall) and
isPostUpdateOfQualifier(destructorCall, result)
)
or
// Case 2: Anything that was derived from the temporary that is now destroyed
// is also destroyed.
exists(CallInstruction call |
result.asInstruction() = call and
DataFlow::localFlow(DataFlow::operandNode(call.getThisArgumentOperand()), n)
|
call.getStaticCallTarget() instanceof StdSequenceContainerAt or
call.getStaticCallTarget() instanceof StdMapAt
DataFlow::Node getADestroyedNode() {
exists(TempToDestructorFlow::PathNode destroyedTemp | destroyedTemp.isSource() |
result = destroyedTemp.getNode()
or
exists(CallInstruction call |
result.asInstruction() = call and
DataFlow::localFlow(destroyedTemp.getNode(),
DataFlow::operandNode(call.getThisArgumentOperand()))
|
call.getStaticCallTarget() instanceof StdSequenceContainerAt or
call.getStaticCallTarget() instanceof StdMapAt
)
)
}
predicate destroyedToBeginSink(DataFlow::Node sink, FunctionCall fc) {
predicate isSinkImpl(DataFlow::Node sink, FunctionCall fc) {
exists(CallInstruction call |
call = sink.asOperand().(ThisArgumentOperand).getCall() and
fc = call.getUnconvertedResultExpression() and
@@ -70,39 +74,12 @@ predicate destroyedToBeginSink(DataFlow::Node sink, FunctionCall fc) {
}
/**
* A configuration to track flow from a temporary variable to the qualifier of
* a destructor call, and subsequently to a qualifier of a call to `begin` or
* `end`.
* Flow from any destroyed object to the qualifier of a `begin` or `end` call
*/
module Config implements DataFlow::StateConfigSig {
newtype FlowState =
additional TempToDestructor() or
additional DestroyedToBegin(DataFlow::Node n) {
exists(DataFlow::Node thisOperand |
tempToDestructorSink(thisOperand, _) and
n = getADestroyedNode(thisOperand)
)
}
module DestroyedToBeginConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source = getADestroyedNode() }
predicate isSource(DataFlow::Node source, FlowState state) {
source.asInstruction().(VariableAddressInstruction).getIRVariable() instanceof IRTempVariable and
state = TempToDestructor()
}
predicate isAdditionalFlowStep(
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
) {
tempToDestructorSink(node1, _) and
state1 = TempToDestructor() and
state2 = DestroyedToBegin(node2) and
node2 = getADestroyedNode(node1)
}
predicate isSink(DataFlow::Node sink, FlowState state) {
// Note: This is a non-trivial cartesian product!
// Hopefully, both of these sets are quite small in practice
destroyedToBeginSink(sink, _) and state instanceof DestroyedToBegin
}
predicate isSink(DataFlow::Node sink) { isSinkImpl(sink, _) }
DataFlow::FlowFeature getAFeature() {
// By blocking argument-to-parameter flow we ensure that we don't enter a
@@ -119,11 +96,8 @@ module Config implements DataFlow::StateConfigSig {
}
}
module Flow = DataFlow::GlobalWithState<Config>;
module DestroyedToBeginFlow = DataFlow::Global<DestroyedToBeginConfig>;
from Flow::PathNode source, Flow::PathNode sink, FunctionCall beginOrEnd, DataFlow::Node mid
where
Flow::flowPath(source, sink) and
destroyedToBeginSink(sink.getNode(), beginOrEnd) and
sink.getState() = Config::DestroyedToBegin(mid)
select mid, "This object is destroyed before $@ is called.", beginOrEnd, beginOrEnd.toString()
from DataFlow::Node source, DataFlow::Node sink, FunctionCall beginOrEnd
where DestroyedToBeginFlow::flow(source, sink) and isSinkImpl(sink, beginOrEnd)
select source, "This object is destroyed before $@ is called.", beginOrEnd, beginOrEnd.toString()

View File

@@ -1,20 +0,0 @@
import cpp
class StringVariable extends Variable {
StringVariable() {
this.getType().(PointerType).stripType().getName() = "char"
}
}
class StringField extends StringVariable, Field
{
}
class StringParameter extends StringVariable, Parameter
{
}
from StringVariable f
where f.getFile().getRelativePath().matches("c/extractor/src/%")
and not f.getASpecifier().getName() = "extern"
select f, f.getFile().getRelativePath()

View File

@@ -1,9 +0,0 @@
import cpp
import relevant
from Function fn
where
fn.getNamespace() instanceof GlobalNamespace and
not exists(fn.getDeclaringType()) and
is_relevant_result(fn.getFile())
select fn, "This function is not declared in a namespace", fn.getFile().getRelativePath()

View File

@@ -1,4 +0,0 @@
import cpp
from Function fn
where not exists(fn.getDeclaringType()) and is_relevant_result(fn.getFile())

View File

@@ -1,25 +0,0 @@
// Flags use of global variables
import cpp
class RelevantGlobalVariable extends GlobalVariable
{
RelevantGlobalVariable() {
any()
}
}
predicate is_valid_global_variable(Variable var) {
var.getType().stripType().getName() = "trie_node" or
var.getType().isConst() or
var.getType().isDeeplyConst() or
var.isConstexpr() or
var.getType() instanceof ArrayType or
var.getASpecifier().getName() = "extern" or
var.getFile().getRelativePath().matches("c/extractor/edg/%")
}
from GlobalVariable globalVariable, string typeName
where
not is_valid_global_variable(globalVariable) and
typeName = globalVariable.getType().stripType().getName()
select globalVariable, typeName, globalVariable.getFile().getRelativePath()

View File

@@ -1,7 +0,0 @@
import cpp
import relevant
from Call call
where call.getTarget().getName().matches("%printf")
and is_relevant_result(call.getFile())
select call, "Call to a printf formatter", call.getFile().getRelativePath()

View File

@@ -1,6 +0,0 @@
import cpp
predicate is_relevant_result(File file)
{
not file.getRelativePath().matches("c/extractor/edg%")
}

View File

@@ -1,25 +0,0 @@
import cpp
class ACompressedFileWrite extends Function {
ACompressedFileWrite() {
this.getName() = "operator<<" and
this.getParameter(0).getType().stripType().getName() = "a_compressed_file"
}
}
class LabelDefinition extends Call {
LabelDefinition() {
this.getTarget() instanceof ACompressedFileWrite and
this.getArgument(1).(StringLiteral).getValue().matches("=%")
}
}
predicate is_valid_file_write(Call call) {
call.getFile().getBaseName() = "dbscheme.cpp"
}
from Call call
where
call.getTarget() instanceof ACompressedFileWrite
and not is_valid_file_write(call)
select call

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 0.9.11-dev
version: 0.9.10-dev
groups:
- cpp
- queries

View File

@@ -1,12 +1,12 @@
| test.cpp:15:8:15:11 | Load: aptr | VNLength(InitializeParameter: count) | 0 | ZeroOffset | 0 |
| test.cpp:19:8:19:8 | Load: a | VNLength(Load: count) | 0 | ZeroOffset | 0 |
| test.cpp:21:8:21:8 | Load: a | VNLength(Load: count) | -1 | ZeroOffset | 0 |
| test.cpp:23:8:23:8 | Load: a | VNLength(Load: count) | 1 | ZeroOffset | 0 |
| test.cpp:27:8:27:8 | Load: c | VNLength(Load: count) | 0 | ZeroOffset | 0 |
| test.cpp:28:8:28:24 | Convert: (unsigned char *)... | VNLength(Load: count) | 0 | ZeroOffset | 0 |
| test.cpp:30:8:30:8 | Load: v | VNLength(Load: count) | 0 | ZeroOffset | 0 |
| test.cpp:19:8:19:8 | Load: a | VNLength(Chi: ptr) | 0 | ZeroOffset | 0 |
| test.cpp:21:8:21:8 | Load: a | VNLength(Chi: ptr) | -1 | ZeroOffset | 0 |
| test.cpp:23:8:23:8 | Load: a | VNLength(Chi: ptr) | 1 | ZeroOffset | 0 |
| test.cpp:27:8:27:8 | Load: c | VNLength(Chi: ptr) | 0 | ZeroOffset | 0 |
| test.cpp:28:8:28:24 | Convert: (unsigned char *)... | VNLength(Chi: ptr) | 0 | ZeroOffset | 0 |
| test.cpp:30:8:30:8 | Load: v | VNLength(Chi: ptr) | 0 | ZeroOffset | 0 |
| test.cpp:34:8:34:12 | Convert: array to pointer conversion | ZeroLength | 100 | ZeroOffset | 0 |
| test.cpp:37:10:37:10 | Load: b | VNLength(Load: count) | 0 | ZeroOffset | 0 |
| test.cpp:37:10:37:10 | Load: b | VNLength(Chi: ptr) | 0 | ZeroOffset | 0 |
| test.cpp:44:8:44:8 | Load: a | VNLength(InitializeParameter: count) | 0 | ZeroOffset | 2 |
| test.cpp:53:10:53:10 | Load: a | VNLength(InitializeParameter: count) | 0 | ZeroOffset | 2 |
| test.cpp:56:10:56:10 | Load: a | VNLength(InitializeParameter: count) | 0 | ZeroOffset | 3 |

View File

@@ -16,8 +16,7 @@
| inline_assembly.c:10:3:10:7 | Store: ... = ... | positive strictlyPositive |
| inline_assembly.c:10:7:10:7 | Constant: (unsigned int)... | positive strictlyPositive |
| inline_assembly.c:12:32:12:32 | Load: y | positive strictlyPositive |
| inline_assembly.c:21:29:21:29 | Load: x | positive |
| inline_assembly.c:21:32:21:32 | Load: y | positive |
| inline_assembly.c:21:32:21:32 | Load: y | positive strictlyPositive |
| minmax.c:16:9:16:10 | Constant: 1 | positive strictlyPositive |
| minmax.c:16:9:16:10 | Store: 1 | positive strictlyPositive |
| minmax.c:16:16:16:17 | Constant: 2 | positive strictlyPositive |

View File

@@ -1,9 +1,7 @@
edges
| test.cpp:22:27:22:30 | **argv | test.cpp:23:20:23:26 | *access to array | provenance | |
| test.cpp:23:20:23:26 | *access to array | test.cpp:29:13:29:20 | *filePath | provenance | |
| test.cpp:22:27:22:30 | **argv | test.cpp:29:13:29:20 | *filePath | provenance | |
nodes
| test.cpp:22:27:22:30 | **argv | semmle.label | **argv |
| test.cpp:23:20:23:26 | *access to array | semmle.label | *access to array |
| test.cpp:29:13:29:20 | *filePath | semmle.label | *filePath |
subpaths
#select

View File

@@ -1,5 +1,4 @@
edges
| test.cpp:22:17:22:21 | ... * ... | test.cpp:22:17:22:21 | ... * ... | provenance | |
| test.cpp:22:17:22:21 | ... * ... | test.cpp:23:33:23:37 | size1 | provenance | |
| test.cpp:37:24:37:27 | size | test.cpp:37:46:37:49 | size | provenance | |
| test.cpp:45:36:45:40 | ... * ... | test.cpp:37:24:37:27 | size | provenance | |
@@ -8,7 +7,6 @@ nodes
| test.cpp:15:31:15:35 | ... * ... | semmle.label | ... * ... |
| test.cpp:19:34:19:38 | ... * ... | semmle.label | ... * ... |
| test.cpp:22:17:22:21 | ... * ... | semmle.label | ... * ... |
| test.cpp:22:17:22:21 | ... * ... | semmle.label | ... * ... |
| test.cpp:23:33:23:37 | size1 | semmle.label | size1 |
| test.cpp:30:18:30:32 | ... * ... | semmle.label | ... * ... |
| test.cpp:31:18:31:32 | ... * ... | semmle.label | ... * ... |

View File

@@ -1,5 +1,4 @@
edges
| test.cpp:4:17:4:22 | call to malloc | test.cpp:4:17:4:22 | call to malloc | provenance | |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:6:9:6:11 | arr | provenance | |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:10:9:10:11 | arr | provenance | |
| test.cpp:19:9:19:16 | *mk_array [p] | test.cpp:28:19:28:26 | call to mk_array [p] | provenance | |
@@ -7,9 +6,7 @@ edges
| test.cpp:21:5:21:7 | *arr [post update] [p] | test.cpp:22:5:22:7 | *arr [p] | provenance | |
| test.cpp:21:5:21:24 | ... = ... | test.cpp:21:5:21:7 | *arr [post update] [p] | provenance | |
| test.cpp:21:13:21:18 | call to malloc | test.cpp:21:5:21:24 | ... = ... | provenance | |
| test.cpp:22:5:22:7 | *arr [p] | test.cpp:24:12:24:14 | arr [p] | provenance | |
| test.cpp:24:12:24:14 | arr [p] | test.cpp:19:9:19:16 | *mk_array [p] | provenance | |
| test.cpp:28:19:28:26 | call to mk_array [p] | test.cpp:28:19:28:26 | call to mk_array [p] | provenance | |
| test.cpp:22:5:22:7 | *arr [p] | test.cpp:19:9:19:16 | *mk_array [p] | provenance | |
| test.cpp:28:19:28:26 | call to mk_array [p] | test.cpp:31:9:31:11 | *arr [p] | provenance | |
| test.cpp:28:19:28:26 | call to mk_array [p] | test.cpp:35:9:35:11 | *arr [p] | provenance | |
| test.cpp:31:9:31:11 | *arr [p] | test.cpp:31:13:31:13 | p | provenance | |
@@ -31,9 +28,7 @@ edges
| test.cpp:69:5:69:7 | *arr [post update] [p] | test.cpp:70:5:70:7 | *arr [p] | provenance | |
| test.cpp:69:5:69:25 | ... = ... | test.cpp:69:5:69:7 | *arr [post update] [p] | provenance | |
| test.cpp:69:14:69:19 | call to malloc | test.cpp:69:5:69:25 | ... = ... | provenance | |
| test.cpp:70:5:70:7 | *arr [p] | test.cpp:72:12:72:14 | *arr [p] | provenance | |
| test.cpp:72:12:72:14 | *arr [p] | test.cpp:67:10:67:19 | **mk_array_p [p] | provenance | |
| test.cpp:76:20:76:29 | *call to mk_array_p [p] | test.cpp:76:20:76:29 | *call to mk_array_p [p] | provenance | |
| test.cpp:70:5:70:7 | *arr [p] | test.cpp:67:10:67:19 | **mk_array_p [p] | provenance | |
| test.cpp:76:20:76:29 | *call to mk_array_p [p] | test.cpp:79:9:79:11 | *arr [p] | provenance | |
| test.cpp:76:20:76:29 | *call to mk_array_p [p] | test.cpp:83:9:83:11 | *arr [p] | provenance | |
| test.cpp:79:9:79:11 | *arr [p] | test.cpp:79:14:79:14 | p | provenance | |
@@ -48,7 +43,6 @@ edges
| test.cpp:98:18:98:27 | test6_callee output argument [p] | test.cpp:98:18:98:27 | *call to mk_array_p [p] | provenance | |
nodes
| test.cpp:4:17:4:22 | call to malloc | semmle.label | call to malloc |
| test.cpp:4:17:4:22 | call to malloc | semmle.label | call to malloc |
| test.cpp:6:9:6:11 | arr | semmle.label | arr |
| test.cpp:10:9:10:11 | arr | semmle.label | arr |
| test.cpp:19:9:19:16 | *mk_array [p] | semmle.label | *mk_array [p] |
@@ -56,8 +50,6 @@ nodes
| test.cpp:21:5:21:24 | ... = ... | semmle.label | ... = ... |
| test.cpp:21:13:21:18 | call to malloc | semmle.label | call to malloc |
| test.cpp:22:5:22:7 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:24:12:24:14 | arr [p] | semmle.label | arr [p] |
| test.cpp:28:19:28:26 | call to mk_array [p] | semmle.label | call to mk_array [p] |
| test.cpp:28:19:28:26 | call to mk_array [p] | semmle.label | call to mk_array [p] |
| test.cpp:31:9:31:11 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:31:13:31:13 | p | semmle.label | p |
@@ -82,8 +74,6 @@ nodes
| test.cpp:69:5:69:25 | ... = ... | semmle.label | ... = ... |
| test.cpp:69:14:69:19 | call to malloc | semmle.label | call to malloc |
| test.cpp:70:5:70:7 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:72:12:72:14 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:76:20:76:29 | *call to mk_array_p [p] | semmle.label | *call to mk_array_p [p] |
| test.cpp:76:20:76:29 | *call to mk_array_p [p] | semmle.label | *call to mk_array_p [p] |
| test.cpp:79:9:79:11 | *arr [p] | semmle.label | *arr [p] |
| test.cpp:79:14:79:14 | p | semmle.label | p |

View File

@@ -18,9 +18,8 @@ edges
| test.cpp:77:32:77:34 | buf | test.cpp:77:26:77:44 | & ... | provenance | |
| test.cpp:79:27:79:34 | buf | test.cpp:70:33:70:33 | p | provenance | |
| test.cpp:79:32:79:34 | buf | test.cpp:79:27:79:34 | buf | provenance | |
| test.cpp:85:21:85:36 | buf | test.cpp:87:5:87:31 | access to array | provenance | |
| test.cpp:85:21:85:36 | buf | test.cpp:88:5:88:27 | access to array | provenance | |
| test.cpp:85:34:85:36 | buf | test.cpp:85:21:85:36 | buf | provenance | |
| test.cpp:85:34:85:36 | buf | test.cpp:87:5:87:31 | access to array | provenance | |
| test.cpp:85:34:85:36 | buf | test.cpp:88:5:88:27 | access to array | provenance | |
| test.cpp:96:13:96:15 | arr | test.cpp:96:13:96:18 | access to array | provenance | |
| test.cpp:111:17:111:19 | arr | test.cpp:111:17:111:22 | access to array | provenance | |
| test.cpp:111:17:111:19 | arr | test.cpp:115:35:115:40 | access to array | provenance | |
@@ -33,21 +32,17 @@ edges
| test.cpp:119:17:119:19 | arr | test.cpp:119:17:119:22 | access to array | provenance | |
| test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array | provenance | |
| test.cpp:134:25:134:27 | arr | test.cpp:136:9:136:16 | ... += ... | provenance | |
| test.cpp:136:9:136:16 | ... += ... | test.cpp:136:9:136:16 | ... += ... | provenance | |
| test.cpp:136:9:136:16 | ... += ... | test.cpp:138:13:138:15 | arr | provenance | |
| test.cpp:143:18:143:21 | asdf | test.cpp:134:25:134:27 | arr | provenance | |
| test.cpp:143:18:143:21 | asdf | test.cpp:143:18:143:21 | asdf | provenance | |
| test.cpp:146:26:146:26 | *p | test.cpp:147:4:147:9 | -- ... | provenance | |
| test.cpp:156:12:156:14 | buf | test.cpp:156:12:156:18 | ... + ... | provenance | |
| test.cpp:156:12:156:18 | ... + ... | test.cpp:156:12:156:18 | ... + ... | provenance | |
| test.cpp:156:12:156:18 | ... + ... | test.cpp:158:17:158:18 | *& ... | provenance | |
| test.cpp:158:17:158:18 | *& ... | test.cpp:146:26:146:26 | *p | provenance | |
| test.cpp:218:16:218:28 | buffer | test.cpp:220:5:220:11 | access to array | provenance | |
| test.cpp:218:16:218:28 | buffer | test.cpp:221:5:221:11 | access to array | provenance | |
| test.cpp:218:23:218:28 | buffer | test.cpp:218:16:218:28 | buffer | provenance | |
| test.cpp:229:17:229:29 | array | test.cpp:231:5:231:10 | access to array | provenance | |
| test.cpp:229:17:229:29 | array | test.cpp:232:5:232:10 | access to array | provenance | |
| test.cpp:229:25:229:29 | array | test.cpp:229:17:229:29 | array | provenance | |
| test.cpp:218:23:218:28 | buffer | test.cpp:220:5:220:11 | access to array | provenance | |
| test.cpp:218:23:218:28 | buffer | test.cpp:221:5:221:11 | access to array | provenance | |
| test.cpp:229:25:229:29 | array | test.cpp:231:5:231:10 | access to array | provenance | |
| test.cpp:229:25:229:29 | array | test.cpp:232:5:232:10 | access to array | provenance | |
| test.cpp:245:30:245:30 | p | test.cpp:261:27:261:30 | access to array | provenance | |
| test.cpp:245:30:245:30 | p | test.cpp:261:27:261:30 | access to array | provenance | |
| test.cpp:274:14:274:20 | buffer3 | test.cpp:245:30:245:30 | p | provenance | |
@@ -66,16 +61,13 @@ edges
| test.cpp:306:20:306:23 | arr1 | test.cpp:306:20:306:23 | arr1 | provenance | |
| test.cpp:309:20:309:23 | arr2 | test.cpp:292:25:292:27 | arr | provenance | |
| test.cpp:309:20:309:23 | arr2 | test.cpp:309:20:309:23 | arr2 | provenance | |
| test.cpp:319:13:319:27 | ... = ... | test.cpp:325:24:325:26 | end | provenance | |
| test.cpp:319:19:319:22 | temp | test.cpp:319:19:319:27 | ... + ... | provenance | |
| test.cpp:319:19:319:22 | temp | test.cpp:324:23:324:32 | ... + ... | provenance | |
| test.cpp:319:19:319:27 | ... + ... | test.cpp:319:13:319:27 | ... = ... | provenance | |
| test.cpp:322:13:322:27 | ... = ... | test.cpp:325:24:325:26 | end | provenance | |
| test.cpp:319:19:319:27 | ... + ... | test.cpp:325:24:325:26 | end | provenance | |
| test.cpp:322:19:322:22 | temp | test.cpp:322:19:322:27 | ... + ... | provenance | |
| test.cpp:322:19:322:22 | temp | test.cpp:324:23:324:32 | ... + ... | provenance | |
| test.cpp:322:19:322:27 | ... + ... | test.cpp:322:13:322:27 | ... = ... | provenance | |
| test.cpp:322:19:322:27 | ... + ... | test.cpp:325:24:325:26 | end | provenance | |
| test.cpp:324:23:324:26 | temp | test.cpp:324:23:324:32 | ... + ... | provenance | |
| test.cpp:324:23:324:32 | ... + ... | test.cpp:324:23:324:32 | ... + ... | provenance | |
| test.cpp:324:23:324:32 | ... + ... | test.cpp:325:15:325:19 | temp2 | provenance | |
nodes
| test.cpp:34:5:34:24 | access to array | semmle.label | access to array |
@@ -111,7 +103,6 @@ nodes
| test.cpp:77:32:77:34 | buf | semmle.label | buf |
| test.cpp:79:27:79:34 | buf | semmle.label | buf |
| test.cpp:79:32:79:34 | buf | semmle.label | buf |
| test.cpp:85:21:85:36 | buf | semmle.label | buf |
| test.cpp:85:34:85:36 | buf | semmle.label | buf |
| test.cpp:87:5:87:31 | access to array | semmle.label | access to array |
| test.cpp:88:5:88:27 | access to array | semmle.label | access to array |
@@ -127,7 +118,6 @@ nodes
| test.cpp:128:9:128:14 | access to array | semmle.label | access to array |
| test.cpp:134:25:134:27 | arr | semmle.label | arr |
| test.cpp:136:9:136:16 | ... += ... | semmle.label | ... += ... |
| test.cpp:136:9:136:16 | ... += ... | semmle.label | ... += ... |
| test.cpp:138:13:138:15 | arr | semmle.label | arr |
| test.cpp:143:18:143:21 | asdf | semmle.label | asdf |
| test.cpp:143:18:143:21 | asdf | semmle.label | asdf |
@@ -135,13 +125,10 @@ nodes
| test.cpp:147:4:147:9 | -- ... | semmle.label | -- ... |
| test.cpp:156:12:156:14 | buf | semmle.label | buf |
| test.cpp:156:12:156:18 | ... + ... | semmle.label | ... + ... |
| test.cpp:156:12:156:18 | ... + ... | semmle.label | ... + ... |
| test.cpp:158:17:158:18 | *& ... | semmle.label | *& ... |
| test.cpp:218:16:218:28 | buffer | semmle.label | buffer |
| test.cpp:218:23:218:28 | buffer | semmle.label | buffer |
| test.cpp:220:5:220:11 | access to array | semmle.label | access to array |
| test.cpp:221:5:221:11 | access to array | semmle.label | access to array |
| test.cpp:229:17:229:29 | array | semmle.label | array |
| test.cpp:229:25:229:29 | array | semmle.label | array |
| test.cpp:231:5:231:10 | access to array | semmle.label | access to array |
| test.cpp:232:5:232:10 | access to array | semmle.label | access to array |
@@ -165,15 +152,12 @@ nodes
| test.cpp:306:20:306:23 | arr1 | semmle.label | arr1 |
| test.cpp:309:20:309:23 | arr2 | semmle.label | arr2 |
| test.cpp:309:20:309:23 | arr2 | semmle.label | arr2 |
| test.cpp:319:13:319:27 | ... = ... | semmle.label | ... = ... |
| test.cpp:319:19:319:22 | temp | semmle.label | temp |
| test.cpp:319:19:319:27 | ... + ... | semmle.label | ... + ... |
| test.cpp:322:13:322:27 | ... = ... | semmle.label | ... = ... |
| test.cpp:322:19:322:22 | temp | semmle.label | temp |
| test.cpp:322:19:322:27 | ... + ... | semmle.label | ... + ... |
| test.cpp:324:23:324:26 | temp | semmle.label | temp |
| test.cpp:324:23:324:32 | ... + ... | semmle.label | ... + ... |
| test.cpp:324:23:324:32 | ... + ... | semmle.label | ... + ... |
| test.cpp:325:15:325:19 | temp2 | semmle.label | temp2 |
| test.cpp:325:24:325:26 | end | semmle.label | end |
| test.cpp:325:24:325:26 | end | semmle.label | end |

View File

@@ -1,12 +1,9 @@
edges
| test.cpp:45:18:45:23 | buffer | test.cpp:47:10:47:15 | buffer | provenance | |
| test.cpp:47:10:47:15 | buffer | test.cpp:45:7:45:10 | *func | provenance | |
| test.cpp:74:24:74:30 | medical | test.cpp:77:16:77:22 | medical | provenance | |
| test.cpp:45:18:45:23 | buffer | test.cpp:45:7:45:10 | *func | provenance | |
| test.cpp:74:24:74:30 | medical | test.cpp:78:24:78:27 | temp | provenance | |
| test.cpp:74:24:74:30 | medical | test.cpp:81:22:81:28 | medical | provenance | |
| test.cpp:77:16:77:22 | medical | test.cpp:77:16:77:22 | medical | provenance | |
| test.cpp:77:16:77:22 | medical | test.cpp:78:24:78:27 | temp | provenance | |
| test.cpp:77:16:77:22 | medical | test.cpp:81:22:81:28 | medical | provenance | |
| test.cpp:81:17:81:20 | call to func | test.cpp:81:17:81:20 | call to func | provenance | |
| test.cpp:81:17:81:20 | call to func | test.cpp:82:24:82:28 | buff5 | provenance | |
| test.cpp:81:22:81:28 | medical | test.cpp:45:18:45:23 | buffer | provenance | |
| test.cpp:81:22:81:28 | medical | test.cpp:81:17:81:20 | call to func | provenance | |
@@ -15,15 +12,12 @@ edges
nodes
| test.cpp:45:7:45:10 | *func | semmle.label | *func |
| test.cpp:45:18:45:23 | buffer | semmle.label | buffer |
| test.cpp:47:10:47:15 | buffer | semmle.label | buffer |
| test.cpp:57:9:57:18 | theZipcode | semmle.label | theZipcode |
| test.cpp:74:24:74:30 | medical | semmle.label | medical |
| test.cpp:74:24:74:30 | medical | semmle.label | medical |
| test.cpp:77:16:77:22 | medical | semmle.label | medical |
| test.cpp:77:16:77:22 | medical | semmle.label | medical |
| test.cpp:78:24:78:27 | temp | semmle.label | temp |
| test.cpp:81:17:81:20 | call to func | semmle.label | call to func |
| test.cpp:81:17:81:20 | call to func | semmle.label | call to func |
| test.cpp:81:22:81:28 | medical | semmle.label | medical |
| test.cpp:82:24:82:28 | buff5 | semmle.label | buff5 |
| test.cpp:96:37:96:46 | theZipcode | semmle.label | theZipcode |

View File

@@ -1,11 +0,0 @@
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:680:17:680:17 | call to begin | call to begin |
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:680:17:680:17 | call to end | call to end |
| test.cpp:683:31:683:32 | call to at | This object is destroyed before $@ is called. | test.cpp:683:17:683:17 | call to begin | call to begin |
| test.cpp:683:31:683:32 | call to at | This object is destroyed before $@ is called. | test.cpp:683:17:683:17 | call to end | call to end |
| test.cpp:689:46:689:58 | pointer to ~vector output argument | This object is destroyed before $@ is called. | test.cpp:689:60:689:62 | call to end | call to end |
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:703:19:703:23 | call to begin | call to begin |
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:703:36:703:38 | call to end | call to end |
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:750:17:750:17 | call to begin | call to begin |
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:750:17:750:17 | call to end | call to end |
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:759:17:759:17 | call to begin | call to begin |
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:759:17:759:17 | call to end | call to end |

View File

@@ -677,10 +677,10 @@ std::vector<std::vector<int>> return_self_by_value(const std::vector<std::vector
void test() {
for (auto x : returnValue()) {} // GOOD
for (auto x : returnValue()[0]) {} // BAD
for (auto x : returnValue()[0]) {} // BAD [NOT DETECTED] (see *)
for (auto x : external_by_value(returnValue())) {} // GOOD
for (auto x : external_by_const_ref(returnValue())) {} // GOOD
for (auto x : returnValue().at(0)) {} // BAD
for (auto x : returnValue().at(0)) {} // BAD [NOT DETECTED] (see *)
for (auto x : returnRef()) {} // GOOD
for (auto x : returnRef()[0]) {} // GOOD
@@ -700,7 +700,7 @@ void test() {
{
auto&& v = returnValue()[0];
for(auto it = v.begin(); it != v.end(); ++it) {} // BAD
for(auto it = v.begin(); it != v.end(); ++it) {} // BAD [NOT DETECTED] (see *)
}
{
@@ -713,7 +713,7 @@ void test() {
for(auto it = v.begin(); it != v.end(); ++it) {} // GOOD
}
for (auto x : return_self_by_ref(returnValue())) {} // BAD [NOT DETECTED]
for (auto x : return_self_by_ref(returnValue())) {} // BAD [NOT DETECTED] (see *)
for (auto x : return_self_by_value(returnValue())) {} // GOOD
}
@@ -724,7 +724,7 @@ void iterate(const std::vector<T>& v) {
}
std::vector<int>& ref_to_first_in_returnValue_1() {
return returnValue()[0]; // BAD
return returnValue()[0]; // BAD [NOT DETECTED] (see *)
}
std::vector<int>& ref_to_first_in_returnValue_2() {
@@ -732,7 +732,7 @@ std::vector<int>& ref_to_first_in_returnValue_2() {
}
std::vector<int>& ref_to_first_in_returnValue_3() {
return returnValue()[0]; // BAD
return returnValue()[0]; // BAD [NOT DETECTED] (see *)
}
std::vector<int> first_in_returnValue_1() {
@@ -766,30 +766,3 @@ void test2() {
for (auto x : value) {}
}
}
void test3() {
const std::vector<std::vector<int>>& v = returnValue(); // GOOD
for(const std::vector<int>& x : v) {}
}
struct A : public std::vector<int> {
void foo(std::vector<int>& result) {
int i = 0;
while (i < 10) {
A chunk;
result.insert(result.end(), chunk.begin(), chunk.end());
++i;
}
}
~A() = default;
};
void test4() {
// This creates a temporary, after which `~A` is called at the semicolon, and
// `~A` calls `~vector<int>` inside the compiler-generated destructor.
// If we don't preserve the call context and return to the destructor call in this
// function we may end up in the destructor call `chunk.~A()`in `A.foo`. This destructor
// call can flow to `begin` through the back-edge and cause a strange FP.
auto zero = A().size();
}

View File

@@ -10,9 +10,7 @@
| CPP-205.cpp:2:15:5:1 | { ... } | isFromUninstantiatedTemplate(fn) |
| CPP-205.cpp:3:3:3:33 | declaration | isFromTemplateInstantiation(fn) |
| CPP-205.cpp:3:3:3:33 | declaration | isFromUninstantiatedTemplate(fn) |
| CPP-205.cpp:3:15:3:15 | declaration of y | isFromTemplateInstantiation(fn) |
| CPP-205.cpp:3:15:3:15 | declaration of y | isFromUninstantiatedTemplate(fn) |
| CPP-205.cpp:3:15:3:15 | y | isFromTemplateInstantiation(fn) |
| CPP-205.cpp:3:15:3:15 | y | isFromUninstantiatedTemplate(fn) |
| CPP-205.cpp:3:17:3:31 | 5 | isFromTemplateInstantiation(fn) |
| CPP-205.cpp:4:3:4:11 | return ... | isFromTemplateInstantiation(fn) |

View File

@@ -33,7 +33,6 @@ argHasPostUpdate
| test.cpp:67:29:67:35 | source1 | ArgumentNode is missing PostUpdateNode. |
| test.cpp:813:19:813:35 | * ... | ArgumentNode is missing PostUpdateNode. |
| test.cpp:848:23:848:25 | rpx | ArgumentNode is missing PostUpdateNode. |
| test.cpp:1057:19:1057:21 | * ... | ArgumentNode is missing PostUpdateNode. |
postWithInFlow
| BarrierGuard.cpp:49:6:49:6 | x [post update] | PostUpdateNode should not be the target of local flow. |
| BarrierGuard.cpp:60:7:60:7 | x [post update] | PostUpdateNode should not be the target of local flow. |
@@ -169,13 +168,6 @@ postWithInFlow
| test.cpp:1045:9:1045:11 | ref arg buf | PostUpdateNode should not be the target of local flow. |
| test.cpp:1051:5:1051:11 | content [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:1052:9:1052:9 | a [inner post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:1056:5:1056:7 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:1056:6:1056:7 | pp [inner post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:1062:53:1062:53 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:1072:3:1072:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:1072:4:1072:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:1073:3:1073:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:1073:4:1073:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
viableImplInCallContextTooLarge
uniqueParameterNodeAtPosition
uniqueParameterNodePosition

View File

@@ -125,8 +125,8 @@
| test.cpp:384:16:384:23 | *& ... | test.cpp:384:3:384:8 | *call to memcpy |
| test.cpp:384:16:384:23 | *& ... | test.cpp:384:10:384:13 | memcpy output argument |
| test.cpp:384:16:384:23 | *& ... | test.cpp:384:16:384:23 | *& ... |
| test.cpp:384:16:384:23 | **& ... | test.cpp:384:3:384:8 | **call to memcpy |
| test.cpp:384:16:384:23 | **& ... | test.cpp:384:10:384:13 | memcpy output argument |
| test.cpp:384:16:384:23 | **(const void *)... | test.cpp:384:3:384:8 | **call to memcpy |
| test.cpp:384:16:384:23 | **(const void *)... | test.cpp:384:10:384:13 | memcpy output argument |
| test.cpp:384:17:384:23 | *source1 | test.cpp:384:16:384:23 | *& ... |
| test.cpp:384:17:384:23 | source1 | test.cpp:384:16:384:23 | & ... |
| test.cpp:388:53:388:59 | source1 | test.cpp:391:16:391:23 | *& ... |
@@ -152,8 +152,8 @@
| test.cpp:391:16:391:23 | *& ... | test.cpp:391:3:391:8 | *call to memcpy |
| test.cpp:391:16:391:23 | *& ... | test.cpp:391:10:391:13 | memcpy output argument |
| test.cpp:391:16:391:23 | *& ... | test.cpp:391:16:391:23 | *& ... |
| test.cpp:391:16:391:23 | **& ... | test.cpp:391:3:391:8 | **call to memcpy |
| test.cpp:391:16:391:23 | **& ... | test.cpp:391:10:391:13 | memcpy output argument |
| test.cpp:391:16:391:23 | **(const void *)... | test.cpp:391:3:391:8 | **call to memcpy |
| test.cpp:391:16:391:23 | **(const void *)... | test.cpp:391:10:391:13 | memcpy output argument |
| test.cpp:391:17:391:23 | *source1 | test.cpp:391:16:391:23 | *& ... |
| test.cpp:391:17:391:23 | source1 | test.cpp:391:16:391:23 | & ... |
| test.cpp:392:8:392:10 | tmp | test.cpp:394:10:394:12 | tmp |

View File

@@ -1050,26 +1050,4 @@ void flow_out_of_address_with_local_flow() {
MyStruct a;
a.content = nullptr;
sink(&a); // $ SPURIOUS: ast
}
static void static_func_that_reassigns_pointer_before_sink(char** pp) { // $ ast-def=pp ir-def=*pp ir-def=**pp
*pp = "";
indirect_sink(*pp); // clean
}
void test_static_func_that_reassigns_pointer_before_sink() {
char* p = (char*)indirect_source();
static_func_that_reassigns_pointer_before_sink(&p);
}
void single_object_in_both_cases(bool b, int x, int y) {
int* p;
if(b) {
p = &x;
} else {
p = &y;
}
*p = source();
*p = 0;
sink(*p); // clean
}
}

View File

@@ -7,13 +7,12 @@ incorrectBaseType
| flowOut.cpp:84:9:84:10 | *& ... | Expected 'Node.getType()' to be int, but it was int * |
| flowOut.cpp:101:13:101:14 | *& ... | Expected 'Node.getType()' to be int, but it was int * |
| self_parameter_flow.cpp:8:8:8:9 | *& ... | Expected 'Node.getType()' to be unsigned char, but it was unsigned char * |
| test.cpp:67:28:67:37 | call to move | Expected 'Node.getType()' to be const int, but it was int * |
| test.cpp:67:28:67:37 | (reference dereference) | Expected 'Node.getType()' to be const int, but it was int * |
| test.cpp:531:39:531:40 | *& ... | Expected 'Node.getType()' to be int, but it was const int * |
| test.cpp:615:13:615:21 | *& ... | Expected 'Node.getType()' to be int, but it was void |
| test.cpp:704:22:704:25 | *& ... | Expected 'Node.getType()' to be int, but it was int * |
| test.cpp:715:24:715:25 | *& ... | Expected 'Node.getType()' to be unsigned char, but it was unsigned char * |
| test.cpp:848:23:848:25 | rpx | Expected 'Node.getType()' to be int, but it was int * |
| test.cpp:848:23:848:25 | (reference dereference) | Expected 'Node.getType()' to be int, but it was int * |
| test.cpp:854:10:854:36 | * ... | Expected 'Node.getType()' to be const int, but it was int |
| test.cpp:867:10:867:30 | * ... | Expected 'Node.getType()' to be const int, but it was int |
| test.cpp:1062:52:1062:53 | *& ... | Expected 'Node.getType()' to be char, but it was char * |
failures

View File

@@ -6,17 +6,13 @@ edges
| A.cpp:28:8:28:10 | *this [c] | A.cpp:28:23:28:26 | *this [c] | provenance | |
| A.cpp:28:23:28:26 | *this [c] | A.cpp:28:29:28:29 | c | provenance | |
| A.cpp:28:29:28:29 | c | A.cpp:28:8:28:10 | *get | provenance | |
| A.cpp:28:29:28:29 | c | A.cpp:28:29:28:29 | c | provenance | |
| A.cpp:29:23:29:23 | c | A.cpp:31:20:31:20 | c | provenance | |
| A.cpp:31:14:31:21 | *new [c] | A.cpp:29:15:29:18 | **make [c] | provenance | |
| A.cpp:31:14:31:21 | call to B [c] | A.cpp:31:14:31:21 | *new [c] | provenance | |
| A.cpp:31:14:31:21 | call to B [c] | A.cpp:29:15:29:18 | **make [c] | provenance | |
| A.cpp:31:20:31:20 | c | A.cpp:23:10:23:10 | c | provenance | |
| A.cpp:31:20:31:20 | c | A.cpp:31:14:31:21 | call to B [c] | provenance | |
| A.cpp:41:5:41:6 | insert output argument | A.cpp:43:10:43:12 | *& ... | provenance | |
| A.cpp:41:15:41:21 | new | A.cpp:41:5:41:6 | insert output argument | provenance | |
| A.cpp:47:12:47:18 | new | A.cpp:47:12:47:18 | new | provenance | |
| A.cpp:47:12:47:18 | new | A.cpp:48:20:48:20 | c | provenance | |
| A.cpp:48:12:48:18 | *call to make [c] | A.cpp:48:12:48:18 | *call to make [c] | provenance | |
| A.cpp:48:12:48:18 | *call to make [c] | A.cpp:49:10:49:10 | *b [c] | provenance | |
| A.cpp:48:20:48:20 | c | A.cpp:29:23:29:23 | c | provenance | |
| A.cpp:48:20:48:20 | c | A.cpp:48:12:48:18 | *call to make [c] | provenance | |
@@ -32,39 +28,29 @@ edges
| A.cpp:57:17:57:23 | new | A.cpp:23:10:23:10 | c | provenance | |
| A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | call to B [c] | provenance | |
| A.cpp:57:17:57:23 | new | A.cpp:57:17:57:23 | new | provenance | |
| A.cpp:64:5:64:29 | *... = ... [c] | A.cpp:66:10:66:11 | *b2 [c] | provenance | |
| A.cpp:64:10:64:15 | *call to setOnB [c] | A.cpp:64:5:64:29 | *... = ... [c] | provenance | |
| A.cpp:64:10:64:15 | *call to setOnB [c] | A.cpp:66:10:66:11 | *b2 [c] | provenance | |
| A.cpp:64:21:64:28 | new | A.cpp:64:10:64:15 | *call to setOnB [c] | provenance | |
| A.cpp:64:21:64:28 | new | A.cpp:85:26:85:26 | c | provenance | |
| A.cpp:66:10:66:11 | *b2 [c] | A.cpp:66:10:66:14 | c | provenance | |
| A.cpp:73:5:73:33 | *... = ... [c] | A.cpp:75:10:75:11 | *b2 [c] | provenance | |
| A.cpp:73:10:73:19 | *call to setOnBWrap [c] | A.cpp:73:5:73:33 | *... = ... [c] | provenance | |
| A.cpp:73:10:73:19 | *call to setOnBWrap [c] | A.cpp:75:10:75:11 | *b2 [c] | provenance | |
| A.cpp:73:25:73:32 | new | A.cpp:73:10:73:19 | *call to setOnBWrap [c] | provenance | |
| A.cpp:73:25:73:32 | new | A.cpp:78:27:78:27 | c | provenance | |
| A.cpp:75:10:75:11 | *b2 [c] | A.cpp:75:10:75:14 | c | provenance | |
| A.cpp:78:27:78:27 | c | A.cpp:81:21:81:21 | c | provenance | |
| A.cpp:81:5:81:22 | *... = ... [c] | A.cpp:82:12:82:24 | *... ? ... : ... [c] | provenance | |
| A.cpp:81:10:81:15 | *call to setOnB [c] | A.cpp:81:5:81:22 | *... = ... [c] | provenance | |
| A.cpp:81:10:81:15 | *call to setOnB [c] | A.cpp:78:6:78:15 | **setOnBWrap [c] | provenance | |
| A.cpp:81:21:81:21 | c | A.cpp:81:10:81:15 | *call to setOnB [c] | provenance | |
| A.cpp:81:21:81:21 | c | A.cpp:85:26:85:26 | c | provenance | |
| A.cpp:82:12:82:24 | *... ? ... : ... [c] | A.cpp:78:6:78:15 | **setOnBWrap [c] | provenance | |
| A.cpp:85:26:85:26 | c | A.cpp:90:15:90:15 | c | provenance | |
| A.cpp:90:7:90:8 | set output argument [c] | A.cpp:91:14:91:15 | *b2 [c] | provenance | |
| A.cpp:90:7:90:8 | set output argument [c] | A.cpp:85:9:85:14 | **setOnB [c] | provenance | |
| A.cpp:90:15:90:15 | c | A.cpp:27:17:27:17 | c | provenance | |
| A.cpp:90:15:90:15 | c | A.cpp:90:7:90:8 | set output argument [c] | provenance | |
| A.cpp:91:14:91:15 | *b2 [c] | A.cpp:85:9:85:14 | **setOnB [c] | provenance | |
| A.cpp:98:12:98:18 | new | A.cpp:98:12:98:18 | new | provenance | |
| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | ... = ... | provenance | |
| A.cpp:100:5:100:6 | *c1 [post update] [a] | A.cpp:101:8:101:9 | *c1 [a] | provenance | |
| A.cpp:100:5:100:13 | ... = ... | A.cpp:100:5:100:6 | *c1 [post update] [a] | provenance | |
| A.cpp:101:8:101:9 | *c1 [a] | A.cpp:103:14:103:14 | *c [a] | provenance | |
| A.cpp:103:14:103:14 | *c [a] | A.cpp:105:18:105:38 | *c [a] | provenance | |
| A.cpp:103:14:103:14 | *c [a] | A.cpp:110:18:110:38 | *c [a] | provenance | |
| A.cpp:105:18:105:38 | *c [a] | A.cpp:107:12:107:13 | *c1 [a] | provenance | |
| A.cpp:103:14:103:14 | *c [a] | A.cpp:107:12:107:13 | *c1 [a] | provenance | |
| A.cpp:103:14:103:14 | *c [a] | A.cpp:120:12:120:13 | *c1 [a] | provenance | |
| A.cpp:107:12:107:13 | *c1 [a] | A.cpp:107:12:107:16 | a | provenance | |
| A.cpp:110:18:110:38 | *c [a] | A.cpp:112:7:112:13 | *... = ... [a] | provenance | |
| A.cpp:112:7:112:13 | *... = ... [a] | A.cpp:118:18:118:39 | *cc [a] | provenance | |
| A.cpp:118:18:118:39 | *cc [a] | A.cpp:120:12:120:13 | *c1 [a] | provenance | |
| A.cpp:120:12:120:13 | *c1 [a] | A.cpp:120:12:120:16 | a | provenance | |
| A.cpp:124:14:124:14 | *b [c] | A.cpp:131:8:131:8 | f7 output argument [c] | provenance | |
| A.cpp:126:5:126:5 | set output argument [c] | A.cpp:124:14:124:14 | *b [c] | provenance | |
@@ -87,13 +73,10 @@ edges
| A.cpp:143:7:143:31 | ... = ... | A.cpp:143:7:143:10 | *this [post update] [b] | provenance | |
| A.cpp:143:7:143:31 | ... = ... | A.cpp:143:7:143:10 | *this [post update] [b] | provenance | |
| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | ... = ... | provenance | |
| A.cpp:150:12:150:18 | new | A.cpp:150:12:150:18 | new | provenance | |
| A.cpp:150:12:150:18 | new | A.cpp:151:18:151:18 | b | provenance | |
| A.cpp:151:12:151:24 | *new [*b, c] | A.cpp:152:10:152:10 | *d [*b, c] | provenance | |
| A.cpp:151:12:151:24 | *new [*b, c] | A.cpp:153:10:153:10 | *d [*b, c] | provenance | |
| A.cpp:151:12:151:24 | *new [b] | A.cpp:152:10:152:10 | *d [b] | provenance | |
| A.cpp:151:12:151:24 | call to D [*b, c] | A.cpp:151:12:151:24 | *new [*b, c] | provenance | |
| A.cpp:151:12:151:24 | call to D [b] | A.cpp:151:12:151:24 | *new [b] | provenance | |
| A.cpp:151:12:151:24 | call to D [*b, c] | A.cpp:152:10:152:10 | *d [*b, c] | provenance | |
| A.cpp:151:12:151:24 | call to D [*b, c] | A.cpp:153:10:153:10 | *d [*b, c] | provenance | |
| A.cpp:151:12:151:24 | call to D [b] | A.cpp:152:10:152:10 | *d [b] | provenance | |
| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:154:10:154:10 | *b [c] | provenance | |
| A.cpp:151:18:151:18 | b | A.cpp:140:13:140:13 | b | provenance | |
| A.cpp:151:18:151:18 | b | A.cpp:151:12:151:24 | call to D [b] | provenance | |
@@ -108,31 +91,24 @@ edges
| A.cpp:153:10:153:10 | *d [*b, c] | A.cpp:153:13:153:13 | *b [c] | provenance | |
| A.cpp:153:13:153:13 | *b [c] | A.cpp:153:10:153:16 | c | provenance | |
| A.cpp:154:10:154:10 | *b [c] | A.cpp:154:10:154:13 | c | provenance | |
| A.cpp:159:12:159:18 | new | A.cpp:159:12:159:18 | new | provenance | |
| A.cpp:159:12:159:18 | new | A.cpp:160:29:160:29 | b | provenance | |
| A.cpp:160:18:160:60 | *new [head] | A.cpp:161:38:161:39 | *l1 [head] | provenance | |
| A.cpp:160:18:160:60 | call to MyList [head] | A.cpp:160:18:160:60 | *new [head] | provenance | |
| A.cpp:160:18:160:60 | call to MyList [head] | A.cpp:161:38:161:39 | *l1 [head] | provenance | |
| A.cpp:160:29:160:29 | b | A.cpp:160:18:160:60 | call to MyList [head] | provenance | |
| A.cpp:160:29:160:29 | b | A.cpp:181:15:181:21 | newHead | provenance | |
| A.cpp:161:18:161:40 | *new [*next, head] | A.cpp:162:38:162:39 | *l2 [*next, head] | provenance | |
| A.cpp:161:18:161:40 | call to MyList [*next, head] | A.cpp:161:18:161:40 | *new [*next, head] | provenance | |
| A.cpp:161:18:161:40 | call to MyList [*next, head] | A.cpp:162:38:162:39 | *l2 [*next, head] | provenance | |
| A.cpp:161:38:161:39 | *l1 [head] | A.cpp:161:18:161:40 | call to MyList [*next, head] | provenance | |
| A.cpp:161:38:161:39 | *l1 [head] | A.cpp:181:32:181:35 | *next [head] | provenance | |
| A.cpp:162:18:162:40 | *new [*next, *next, head] | A.cpp:165:10:165:11 | *l3 [*next, *next, head] | provenance | |
| A.cpp:162:18:162:40 | *new [*next, *next, head] | A.cpp:167:22:167:23 | *l3 [*next, *next, head] | provenance | |
| A.cpp:162:18:162:40 | call to MyList [*next, *next, head] | A.cpp:162:18:162:40 | *new [*next, *next, head] | provenance | |
| A.cpp:162:18:162:40 | call to MyList [*next, *next, head] | A.cpp:165:10:165:11 | *l3 [*next, *next, head] | provenance | |
| A.cpp:162:18:162:40 | call to MyList [*next, *next, head] | A.cpp:167:44:167:44 | *l [*next, *next, head] | provenance | |
| A.cpp:162:38:162:39 | *l2 [*next, head] | A.cpp:162:18:162:40 | call to MyList [*next, *next, head] | provenance | |
| A.cpp:162:38:162:39 | *l2 [*next, head] | A.cpp:181:32:181:35 | *next [*next, head] | provenance | |
| A.cpp:165:10:165:11 | *l3 [*next, *next, head] | A.cpp:165:14:165:17 | *next [*next, head] | provenance | |
| A.cpp:165:14:165:17 | *next [*next, head] | A.cpp:165:20:165:23 | *next [head] | provenance | |
| A.cpp:165:20:165:23 | *next [head] | A.cpp:165:10:165:29 | head | provenance | |
| A.cpp:167:22:167:23 | *l3 [*next, *next, head] | A.cpp:167:44:167:44 | *l [*next, *next, head] | provenance | |
| A.cpp:167:40:167:50 | *... = ... [*next, head] | A.cpp:167:44:167:44 | *l [*next, head] | provenance | |
| A.cpp:167:40:167:50 | *... = ... [head] | A.cpp:169:12:169:12 | *l [head] | provenance | |
| A.cpp:167:44:167:44 | *l [*next, *next, head] | A.cpp:167:47:167:50 | *next [*next, head] | provenance | |
| A.cpp:167:44:167:44 | *l [*next, head] | A.cpp:167:47:167:50 | *next [head] | provenance | |
| A.cpp:167:47:167:50 | *next [*next, head] | A.cpp:167:40:167:50 | *... = ... [*next, head] | provenance | |
| A.cpp:167:47:167:50 | *next [head] | A.cpp:167:40:167:50 | *... = ... [head] | provenance | |
| A.cpp:167:47:167:50 | *next [*next, head] | A.cpp:167:44:167:44 | *l [*next, head] | provenance | |
| A.cpp:167:47:167:50 | *next [head] | A.cpp:169:12:169:12 | *l [head] | provenance | |
| A.cpp:169:12:169:12 | *l [head] | A.cpp:169:12:169:18 | head | provenance | |
| A.cpp:173:26:173:26 | *o [c] | A.cpp:173:26:173:26 | *o [c] | provenance | |
| A.cpp:181:15:181:21 | newHead | A.cpp:183:7:183:20 | ... = ... | provenance | |
@@ -141,26 +117,20 @@ edges
| A.cpp:183:7:183:20 | ... = ... | A.cpp:183:7:183:10 | *this [post update] [head] | provenance | |
| A.cpp:184:7:184:23 | *... = ... [*next, head] | A.cpp:184:7:184:10 | *this [post update] [*next, *next, head] | provenance | |
| A.cpp:184:7:184:23 | *... = ... [head] | A.cpp:184:7:184:10 | *this [post update] [*next, head] | provenance | |
| B.cpp:6:15:6:24 | new | B.cpp:6:15:6:24 | new | provenance | |
| B.cpp:6:15:6:24 | new | B.cpp:7:25:7:25 | e | provenance | |
| B.cpp:7:16:7:35 | *new [elem1] | B.cpp:8:25:8:26 | *b1 [elem1] | provenance | |
| B.cpp:7:16:7:35 | call to Box1 [elem1] | B.cpp:7:16:7:35 | *new [elem1] | provenance | |
| B.cpp:7:16:7:35 | call to Box1 [elem1] | B.cpp:8:25:8:26 | *b1 [elem1] | provenance | |
| B.cpp:7:25:7:25 | e | B.cpp:7:16:7:35 | call to Box1 [elem1] | provenance | |
| B.cpp:7:25:7:25 | e | B.cpp:33:16:33:17 | e1 | provenance | |
| B.cpp:8:16:8:27 | *new [*box1, elem1] | B.cpp:9:10:9:11 | *b2 [*box1, elem1] | provenance | |
| B.cpp:8:16:8:27 | call to Box2 [*box1, elem1] | B.cpp:8:16:8:27 | *new [*box1, elem1] | provenance | |
| B.cpp:8:16:8:27 | call to Box2 [*box1, elem1] | B.cpp:9:10:9:11 | *b2 [*box1, elem1] | provenance | |
| B.cpp:8:25:8:26 | *b1 [elem1] | B.cpp:8:16:8:27 | call to Box2 [*box1, elem1] | provenance | |
| B.cpp:8:25:8:26 | *b1 [elem1] | B.cpp:44:16:44:17 | *b1 [elem1] | provenance | |
| B.cpp:9:10:9:11 | *b2 [*box1, elem1] | B.cpp:9:14:9:17 | *box1 [elem1] | provenance | |
| B.cpp:9:14:9:17 | *box1 [elem1] | B.cpp:9:10:9:24 | elem1 | provenance | |
| B.cpp:15:15:15:27 | new | B.cpp:15:15:15:27 | new | provenance | |
| B.cpp:15:15:15:27 | new | B.cpp:16:37:16:37 | e | provenance | |
| B.cpp:16:16:16:38 | *new [elem2] | B.cpp:17:25:17:26 | *b1 [elem2] | provenance | |
| B.cpp:16:16:16:38 | call to Box1 [elem2] | B.cpp:16:16:16:38 | *new [elem2] | provenance | |
| B.cpp:16:16:16:38 | call to Box1 [elem2] | B.cpp:17:25:17:26 | *b1 [elem2] | provenance | |
| B.cpp:16:37:16:37 | e | B.cpp:16:16:16:38 | call to Box1 [elem2] | provenance | |
| B.cpp:16:37:16:37 | e | B.cpp:33:26:33:27 | e2 | provenance | |
| B.cpp:17:16:17:27 | *new [*box1, elem2] | B.cpp:19:10:19:11 | *b2 [*box1, elem2] | provenance | |
| B.cpp:17:16:17:27 | call to Box2 [*box1, elem2] | B.cpp:17:16:17:27 | *new [*box1, elem2] | provenance | |
| B.cpp:17:16:17:27 | call to Box2 [*box1, elem2] | B.cpp:19:10:19:11 | *b2 [*box1, elem2] | provenance | |
| B.cpp:17:25:17:26 | *b1 [elem2] | B.cpp:17:16:17:27 | call to Box2 [*box1, elem2] | provenance | |
| B.cpp:17:25:17:26 | *b1 [elem2] | B.cpp:44:16:44:17 | *b1 [elem2] | provenance | |
| B.cpp:19:10:19:11 | *b2 [*box1, elem2] | B.cpp:19:14:19:17 | *box1 [elem2] | provenance | |
@@ -173,10 +143,8 @@ edges
| B.cpp:44:16:44:17 | *b1 [elem2] | B.cpp:46:7:46:21 | *... = ... [elem2] | provenance | |
| B.cpp:46:7:46:21 | *... = ... [elem1] | B.cpp:46:7:46:10 | *this [post update] [*box1, elem1] | provenance | |
| B.cpp:46:7:46:21 | *... = ... [elem2] | B.cpp:46:7:46:10 | *this [post update] [*box1, elem2] | provenance | |
| C.cpp:18:12:18:18 | *new [s1] | C.cpp:19:5:19:5 | *c [s1] | provenance | |
| C.cpp:18:12:18:18 | *new [s3] | C.cpp:19:5:19:5 | *c [s3] | provenance | |
| C.cpp:18:12:18:18 | call to C [s1] | C.cpp:18:12:18:18 | *new [s1] | provenance | |
| C.cpp:18:12:18:18 | call to C [s3] | C.cpp:18:12:18:18 | *new [s3] | provenance | |
| C.cpp:18:12:18:18 | call to C [s1] | C.cpp:19:5:19:5 | *c [s1] | provenance | |
| C.cpp:18:12:18:18 | call to C [s3] | C.cpp:19:5:19:5 | *c [s3] | provenance | |
| C.cpp:19:5:19:5 | *c [s1] | C.cpp:27:8:27:11 | *this [s1] | provenance | |
| C.cpp:19:5:19:5 | *c [s3] | C.cpp:27:8:27:11 | *this [s3] | provenance | |
| C.cpp:22:3:22:3 | *this [post update] [s1] | C.cpp:18:12:18:18 | call to C [s1] | provenance | |
@@ -192,45 +160,38 @@ edges
| D.cpp:10:11:10:17 | *this [elem] | D.cpp:10:30:10:33 | *this [elem] | provenance | |
| D.cpp:10:30:10:33 | *this [elem] | D.cpp:10:30:10:33 | elem | provenance | |
| D.cpp:10:30:10:33 | elem | D.cpp:10:11:10:17 | *getElem | provenance | |
| D.cpp:10:30:10:33 | elem | D.cpp:10:30:10:33 | elem | provenance | |
| D.cpp:11:24:11:24 | e | D.cpp:11:29:11:36 | ... = ... | provenance | |
| D.cpp:11:29:11:36 | ... = ... | D.cpp:11:29:11:32 | *this [post update] [elem] | provenance | |
| D.cpp:17:11:17:17 | *this [*box, elem] | D.cpp:17:30:17:32 | *this [*box, elem] | provenance | |
| D.cpp:17:30:17:32 | *box [elem] | D.cpp:17:11:17:17 | **getBox1 [elem] | provenance | |
| D.cpp:17:30:17:32 | *box [elem] | D.cpp:17:30:17:32 | *box [elem] | provenance | |
| D.cpp:17:30:17:32 | *this [*box, elem] | D.cpp:17:30:17:32 | *box [elem] | provenance | |
| D.cpp:21:30:21:31 | *b2 [*box, elem] | D.cpp:22:10:22:11 | *b2 [*box, elem] | provenance | |
| D.cpp:22:10:22:11 | *b2 [*box, elem] | D.cpp:17:11:17:17 | *this [*box, elem] | provenance | |
| D.cpp:22:10:22:11 | *b2 [*box, elem] | D.cpp:22:14:22:20 | *call to getBox1 [elem] | provenance | |
| D.cpp:22:14:22:20 | *call to getBox1 [elem] | D.cpp:10:11:10:17 | *this [elem] | provenance | |
| D.cpp:22:14:22:20 | *call to getBox1 [elem] | D.cpp:22:10:22:33 | call to getElem | provenance | |
| D.cpp:28:15:28:24 | new | D.cpp:28:15:28:24 | new | provenance | |
| D.cpp:28:15:28:24 | new | D.cpp:30:5:30:20 | ... = ... | provenance | |
| D.cpp:30:5:30:5 | *b [post update] [*box, elem] | D.cpp:31:14:31:14 | *b [*box, elem] | provenance | |
| D.cpp:30:5:30:20 | ... = ... | D.cpp:30:8:30:10 | *box [post update] [elem] | provenance | |
| D.cpp:30:8:30:10 | *box [post update] [elem] | D.cpp:30:5:30:5 | *b [post update] [*box, elem] | provenance | |
| D.cpp:31:14:31:14 | *b [*box, elem] | D.cpp:21:30:21:31 | *b2 [*box, elem] | provenance | |
| D.cpp:35:15:35:24 | new | D.cpp:35:15:35:24 | new | provenance | |
| D.cpp:35:15:35:24 | new | D.cpp:37:21:37:21 | e | provenance | |
| D.cpp:37:5:37:5 | *b [post update] [*box, elem] | D.cpp:38:14:38:14 | *b [*box, elem] | provenance | |
| D.cpp:37:8:37:10 | setElem output argument [elem] | D.cpp:37:5:37:5 | *b [post update] [*box, elem] | provenance | |
| D.cpp:37:21:37:21 | e | D.cpp:11:24:11:24 | e | provenance | |
| D.cpp:37:21:37:21 | e | D.cpp:37:8:37:10 | setElem output argument [elem] | provenance | |
| D.cpp:38:14:38:14 | *b [*box, elem] | D.cpp:21:30:21:31 | *b2 [*box, elem] | provenance | |
| D.cpp:42:15:42:24 | new | D.cpp:42:15:42:24 | new | provenance | |
| D.cpp:42:15:42:24 | new | D.cpp:44:5:44:26 | ... = ... | provenance | |
| D.cpp:44:5:44:5 | getBox1 output argument [*box, elem] | D.cpp:45:14:45:14 | *b [*box, elem] | provenance | |
| D.cpp:44:5:44:26 | ... = ... | D.cpp:44:8:44:14 | *call to getBox1 [post update] [elem] | provenance | |
| D.cpp:44:8:44:14 | *call to getBox1 [post update] [elem] | D.cpp:44:5:44:5 | getBox1 output argument [*box, elem] | provenance | |
| D.cpp:45:14:45:14 | *b [*box, elem] | D.cpp:21:30:21:31 | *b2 [*box, elem] | provenance | |
| D.cpp:49:15:49:24 | new | D.cpp:49:15:49:24 | new | provenance | |
| D.cpp:49:15:49:24 | new | D.cpp:51:27:51:27 | e | provenance | |
| D.cpp:51:5:51:5 | getBox1 output argument [*box, elem] | D.cpp:52:14:52:14 | *b [*box, elem] | provenance | |
| D.cpp:51:8:51:14 | setElem output argument [elem] | D.cpp:51:5:51:5 | getBox1 output argument [*box, elem] | provenance | |
| D.cpp:51:27:51:27 | e | D.cpp:11:24:11:24 | e | provenance | |
| D.cpp:51:27:51:27 | e | D.cpp:51:8:51:14 | setElem output argument [elem] | provenance | |
| D.cpp:52:14:52:14 | *b [*box, elem] | D.cpp:21:30:21:31 | *b2 [*box, elem] | provenance | |
| D.cpp:56:15:56:24 | new | D.cpp:56:15:56:24 | new | provenance | |
| D.cpp:56:15:56:24 | new | D.cpp:58:5:58:27 | ... = ... | provenance | |
| D.cpp:58:5:58:12 | *boxfield [post update] [*box, elem] | D.cpp:58:5:58:12 | *this [post update] [*boxfield, *box, elem] | provenance | |
| D.cpp:58:5:58:12 | *this [post update] [*boxfield, *box, elem] | D.cpp:59:5:59:7 | *this [*boxfield, *box, elem] | provenance | |
@@ -266,10 +227,9 @@ edges
| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:30:8:30:9 | *s2 [m1] | provenance | |
| aliasing.cpp:29:8:29:9 | *s1 [m1] | aliasing.cpp:29:11:29:12 | m1 | provenance | |
| aliasing.cpp:30:8:30:9 | *s2 [m1] | aliasing.cpp:30:11:30:12 | m1 | provenance | |
| aliasing.cpp:60:3:60:4 | *s2 [post update] [m1] | aliasing.cpp:61:13:61:14 | s2 [m1] | provenance | |
| aliasing.cpp:60:3:60:4 | *s2 [post update] [m1] | aliasing.cpp:62:8:62:12 | *copy2 [m1] | provenance | |
| aliasing.cpp:60:3:60:22 | ... = ... | aliasing.cpp:60:3:60:4 | *s2 [post update] [m1] | provenance | |
| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | ... = ... | provenance | |
| aliasing.cpp:61:13:61:14 | s2 [m1] | aliasing.cpp:62:8:62:12 | *copy2 [m1] | provenance | |
| aliasing.cpp:62:8:62:12 | *copy2 [m1] | aliasing.cpp:62:14:62:15 | m1 | provenance | |
| aliasing.cpp:92:3:92:3 | *w [post update] [s, m1] | aliasing.cpp:93:8:93:8 | *w [s, m1] | provenance | |
| aliasing.cpp:92:3:92:23 | ... = ... | aliasing.cpp:92:5:92:5 | *s [post update] [m1] | provenance | |
@@ -277,11 +237,9 @@ edges
| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:92:3:92:23 | ... = ... | provenance | |
| aliasing.cpp:93:8:93:8 | *w [s, m1] | aliasing.cpp:93:10:93:10 | *s [m1] | provenance | |
| aliasing.cpp:93:10:93:10 | *s [m1] | aliasing.cpp:93:12:93:13 | m1 | provenance | |
| aliasing.cpp:98:3:98:3 | *s [post update] [m1] | aliasing.cpp:100:14:100:14 | s [m1] | provenance | |
| aliasing.cpp:98:3:98:3 | *s [post update] [m1] | aliasing.cpp:101:14:101:19 | *s_copy [m1] | provenance | |
| aliasing.cpp:98:3:98:21 | ... = ... | aliasing.cpp:98:3:98:3 | *s [post update] [m1] | provenance | |
| aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:98:3:98:21 | ... = ... | provenance | |
| aliasing.cpp:100:14:100:14 | s [m1] | aliasing.cpp:101:14:101:19 | *s_copy [m1] | provenance | |
| aliasing.cpp:101:13:101:22 | *& ... | aliasing.cpp:101:13:101:22 | *& ... | provenance | |
| aliasing.cpp:101:13:101:22 | *& ... | aliasing.cpp:102:8:102:10 | * ... | provenance | |
| aliasing.cpp:101:14:101:19 | *s_copy [m1] | aliasing.cpp:101:13:101:22 | *& ... | provenance | |
| aliasing.cpp:105:23:105:24 | *pa | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument | provenance | |
@@ -294,8 +252,7 @@ edges
| aliasing.cpp:105:23:105:24 | *pa | aliasing.cpp:175:15:175:22 | taint_a_ptr output argument | provenance | |
| aliasing.cpp:105:23:105:24 | *pa | aliasing.cpp:187:15:187:22 | taint_a_ptr output argument | provenance | |
| aliasing.cpp:105:23:105:24 | *pa | aliasing.cpp:200:15:200:24 | taint_a_ptr output argument | provenance | |
| aliasing.cpp:106:3:106:20 | ... = ... | aliasing.cpp:105:23:105:24 | *pa | provenance | |
| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:106:3:106:20 | ... = ... | provenance | |
| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:105:23:105:24 | *pa | provenance | |
| aliasing.cpp:121:15:121:16 | taint_a_ptr output argument | aliasing.cpp:122:8:122:12 | access to array | provenance | |
| aliasing.cpp:126:15:126:20 | taint_a_ptr output argument | aliasing.cpp:127:8:127:16 | * ... | provenance | |
| aliasing.cpp:131:15:131:16 | taint_a_ptr output argument | aliasing.cpp:132:8:132:14 | * ... | provenance | |
@@ -317,9 +274,8 @@ edges
| aliasing.cpp:176:8:176:9 | *s2 [s, m1] | aliasing.cpp:176:11:176:11 | *s [m1] | provenance | |
| aliasing.cpp:176:11:176:11 | *s [m1] | aliasing.cpp:176:13:176:14 | m1 | provenance | |
| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument | aliasing.cpp:187:19:187:19 | *s [post update] [m1] | provenance | |
| aliasing.cpp:187:16:187:17 | *s2 [post update] [s, m1] | aliasing.cpp:188:13:188:14 | s2 [s, m1] | provenance | |
| aliasing.cpp:187:16:187:17 | *s2 [post update] [s, m1] | aliasing.cpp:189:8:189:11 | *s2_2 [s, m1] | provenance | |
| aliasing.cpp:187:19:187:19 | *s [post update] [m1] | aliasing.cpp:187:16:187:17 | *s2 [post update] [s, m1] | provenance | |
| aliasing.cpp:188:13:188:14 | s2 [s, m1] | aliasing.cpp:189:8:189:11 | *s2_2 [s, m1] | provenance | |
| aliasing.cpp:189:8:189:11 | *s2_2 [s, m1] | aliasing.cpp:189:13:189:13 | *s [m1] | provenance | |
| aliasing.cpp:189:13:189:13 | *s [m1] | aliasing.cpp:189:15:189:16 | m1 | provenance | |
| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument | aliasing.cpp:200:21:200:21 | *s [post update] [m1] | provenance | |
@@ -327,14 +283,12 @@ edges
| aliasing.cpp:200:21:200:21 | *s [post update] [m1] | aliasing.cpp:200:16:200:18 | *ps2 [post update] [s, m1] | provenance | |
| aliasing.cpp:201:8:201:10 | *ps2 [s, m1] | aliasing.cpp:201:13:201:13 | *s [m1] | provenance | |
| aliasing.cpp:201:13:201:13 | *s [m1] | aliasing.cpp:201:15:201:16 | m1 | provenance | |
| arrays.cpp:6:3:6:23 | ... = ... | arrays.cpp:7:8:7:13 | access to array | provenance | |
| arrays.cpp:6:3:6:23 | ... = ... | arrays.cpp:8:8:8:13 | access to array | provenance | |
| arrays.cpp:6:3:6:23 | ... = ... | arrays.cpp:9:8:9:11 | * ... | provenance | |
| arrays.cpp:6:3:6:23 | ... = ... | arrays.cpp:10:8:10:15 | * ... | provenance | |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:6:3:6:23 | ... = ... | provenance | |
| arrays.cpp:15:3:15:25 | ... = ... | arrays.cpp:16:8:16:13 | access to array | provenance | |
| arrays.cpp:15:3:15:25 | ... = ... | arrays.cpp:17:8:17:13 | access to array | provenance | |
| arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:15:3:15:25 | ... = ... | provenance | |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array | provenance | |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:8:8:8:13 | access to array | provenance | |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | provenance | |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... | provenance | |
| arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:16:8:16:13 | access to array | provenance | |
| arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:17:8:17:13 | access to array | provenance | |
| arrays.cpp:36:3:36:3 | *o [post update] [nested, arr, data] | arrays.cpp:37:8:37:8 | *o [nested, arr, data] | provenance | |
| arrays.cpp:36:3:36:3 | *o [post update] [nested, arr, data] | arrays.cpp:38:8:38:8 | *o [nested, arr, data] | provenance | |
| arrays.cpp:36:3:36:17 | *access to array [post update] [data] | arrays.cpp:36:5:36:10 | *nested [post update] [arr, data] | provenance | |
@@ -389,19 +343,15 @@ edges
| by_reference.cpp:31:46:31:46 | *s [a] | by_reference.cpp:32:12:32:12 | *s [a] | provenance | |
| by_reference.cpp:32:12:32:12 | *s [a] | by_reference.cpp:32:15:32:15 | a | provenance | |
| by_reference.cpp:32:15:32:15 | a | by_reference.cpp:31:16:31:28 | *nonMemberGetA | provenance | |
| by_reference.cpp:32:15:32:15 | a | by_reference.cpp:32:15:32:15 | a | provenance | |
| by_reference.cpp:35:9:35:19 | *this [a] | by_reference.cpp:36:12:36:15 | *this [a] | provenance | |
| by_reference.cpp:36:12:36:15 | *this [a] | by_reference.cpp:36:18:36:18 | a | provenance | |
| by_reference.cpp:36:18:36:18 | a | by_reference.cpp:35:9:35:19 | *getDirectly | provenance | |
| by_reference.cpp:36:18:36:18 | a | by_reference.cpp:36:18:36:18 | a | provenance | |
| by_reference.cpp:39:9:39:21 | *this [a] | by_reference.cpp:40:12:40:15 | *this [a] | provenance | |
| by_reference.cpp:40:12:40:15 | *this [a] | by_reference.cpp:35:9:35:19 | *this [a] | provenance | |
| by_reference.cpp:40:12:40:15 | *this [a] | by_reference.cpp:40:18:40:28 | call to getDirectly | provenance | |
| by_reference.cpp:40:18:40:28 | call to getDirectly | by_reference.cpp:39:9:39:21 | *getIndirectly | provenance | |
| by_reference.cpp:40:18:40:28 | call to getDirectly | by_reference.cpp:40:18:40:28 | call to getDirectly | provenance | |
| by_reference.cpp:43:9:43:27 | *this [a] | by_reference.cpp:44:26:44:29 | *this [a] | provenance | |
| by_reference.cpp:44:12:44:24 | call to nonMemberGetA | by_reference.cpp:43:9:43:27 | *getThroughNonMember | provenance | |
| by_reference.cpp:44:12:44:24 | call to nonMemberGetA | by_reference.cpp:44:12:44:24 | call to nonMemberGetA | provenance | |
| by_reference.cpp:44:26:44:29 | *this [a] | by_reference.cpp:31:46:31:46 | *s [a] | provenance | |
| by_reference.cpp:44:26:44:29 | *this [a] | by_reference.cpp:44:12:44:24 | call to nonMemberGetA | provenance | |
| by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | by_reference.cpp:51:8:51:8 | *s [a] | provenance | |
@@ -448,12 +398,10 @@ edges
| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | ... = ... | provenance | |
| by_reference.cpp:91:25:91:26 | *pa | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument | provenance | |
| by_reference.cpp:91:25:91:26 | *pa | by_reference.cpp:108:15:108:24 | taint_a_ptr output argument | provenance | |
| by_reference.cpp:92:3:92:20 | ... = ... | by_reference.cpp:91:25:91:26 | *pa | provenance | |
| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:92:3:92:20 | ... = ... | provenance | |
| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:91:25:91:26 | *pa | provenance | |
| by_reference.cpp:95:25:95:26 | *pa | by_reference.cpp:124:15:124:21 | taint_a_ref output argument | provenance | |
| by_reference.cpp:95:25:95:26 | *pa | by_reference.cpp:128:15:128:23 | taint_a_ref output argument | provenance | |
| by_reference.cpp:96:3:96:19 | ... = ... | by_reference.cpp:95:25:95:26 | *pa | provenance | |
| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:96:3:96:19 | ... = ... | provenance | |
| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:95:25:95:26 | *pa | provenance | |
| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:22:102:26 | *outer [post update] [inner_nested, a] | provenance | |
| by_reference.cpp:102:22:102:26 | *outer [post update] [inner_nested, a] | by_reference.cpp:110:8:110:12 | *outer [inner_nested, a] | provenance | |
| by_reference.cpp:103:21:103:25 | *outer [post update] [*inner_ptr, a] | by_reference.cpp:111:8:111:12 | *outer [*inner_ptr, a] | provenance | |
@@ -593,11 +541,9 @@ edges
| complex.cpp:9:7:9:7 | *this [a_] | complex.cpp:9:20:9:21 | *this [a_] | provenance | |
| complex.cpp:9:20:9:21 | *this [a_] | complex.cpp:9:20:9:21 | a_ | provenance | |
| complex.cpp:9:20:9:21 | a_ | complex.cpp:9:7:9:7 | *a | provenance | |
| complex.cpp:9:20:9:21 | a_ | complex.cpp:9:20:9:21 | a_ | provenance | |
| complex.cpp:10:7:10:7 | *this [b_] | complex.cpp:10:20:10:21 | *this [b_] | provenance | |
| complex.cpp:10:20:10:21 | *this [b_] | complex.cpp:10:20:10:21 | b_ | provenance | |
| complex.cpp:10:20:10:21 | b_ | complex.cpp:10:7:10:7 | *b | provenance | |
| complex.cpp:10:20:10:21 | b_ | complex.cpp:10:20:10:21 | b_ | provenance | |
| complex.cpp:11:17:11:17 | a | complex.cpp:11:22:11:27 | ... = ... | provenance | |
| complex.cpp:11:22:11:27 | ... = ... | complex.cpp:11:22:11:23 | *this [post update] [a_] | provenance | |
| complex.cpp:12:17:12:17 | b | complex.cpp:12:22:12:27 | ... = ... | provenance | |
@@ -664,11 +610,9 @@ edges
| constructors.cpp:18:9:18:9 | *this [a_] | constructors.cpp:18:22:18:23 | *this [a_] | provenance | |
| constructors.cpp:18:22:18:23 | *this [a_] | constructors.cpp:18:22:18:23 | a_ | provenance | |
| constructors.cpp:18:22:18:23 | a_ | constructors.cpp:18:9:18:9 | *a | provenance | |
| constructors.cpp:18:22:18:23 | a_ | constructors.cpp:18:22:18:23 | a_ | provenance | |
| constructors.cpp:19:9:19:9 | *this [b_] | constructors.cpp:19:22:19:23 | *this [b_] | provenance | |
| constructors.cpp:19:22:19:23 | *this [b_] | constructors.cpp:19:22:19:23 | b_ | provenance | |
| constructors.cpp:19:22:19:23 | b_ | constructors.cpp:19:9:19:9 | *b | provenance | |
| constructors.cpp:19:22:19:23 | b_ | constructors.cpp:19:22:19:23 | b_ | provenance | |
| constructors.cpp:23:13:23:13 | a | constructors.cpp:23:28:23:28 | a | provenance | |
| constructors.cpp:23:20:23:20 | b | constructors.cpp:23:35:23:35 | b | provenance | |
| constructors.cpp:23:28:23:28 | a | constructors.cpp:23:5:23:7 | *this [post update] [a_] | provenance | |
@@ -752,11 +696,9 @@ edges
| simple.cpp:18:9:18:9 | *this [a_] | simple.cpp:18:22:18:23 | *this [a_] | provenance | |
| simple.cpp:18:22:18:23 | *this [a_] | simple.cpp:18:22:18:23 | a_ | provenance | |
| simple.cpp:18:22:18:23 | a_ | simple.cpp:18:9:18:9 | *a | provenance | |
| simple.cpp:18:22:18:23 | a_ | simple.cpp:18:22:18:23 | a_ | provenance | |
| simple.cpp:19:9:19:9 | *this [b_] | simple.cpp:19:22:19:23 | *this [b_] | provenance | |
| simple.cpp:19:22:19:23 | *this [b_] | simple.cpp:19:22:19:23 | b_ | provenance | |
| simple.cpp:19:22:19:23 | b_ | simple.cpp:19:9:19:9 | *b | provenance | |
| simple.cpp:19:22:19:23 | b_ | simple.cpp:19:22:19:23 | b_ | provenance | |
| simple.cpp:20:19:20:19 | a | simple.cpp:20:24:20:29 | ... = ... | provenance | |
| simple.cpp:20:24:20:29 | ... = ... | simple.cpp:20:24:20:25 | *this [post update] [a_] | provenance | |
| simple.cpp:21:19:21:19 | b | simple.cpp:21:24:21:29 | ... = ... | provenance | |
@@ -783,29 +725,25 @@ edges
| simple.cpp:48:9:48:9 | *g [b_] | simple.cpp:26:15:26:15 | *f [b_] | provenance | |
| simple.cpp:51:9:51:9 | *h [a_] | simple.cpp:26:15:26:15 | *f [a_] | provenance | |
| simple.cpp:51:9:51:9 | *h [b_] | simple.cpp:26:15:26:15 | *f [b_] | provenance | |
| simple.cpp:65:5:65:5 | *a [post update] [i] | simple.cpp:66:12:66:12 | a [i] | provenance | |
| simple.cpp:65:5:65:5 | *a [post update] [i] | simple.cpp:67:10:67:11 | *a2 [i] | provenance | |
| simple.cpp:65:5:65:22 | ... = ... | simple.cpp:65:5:65:5 | *a [post update] [i] | provenance | |
| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | ... = ... | provenance | |
| simple.cpp:66:12:66:12 | a [i] | simple.cpp:67:10:67:11 | *a2 [i] | provenance | |
| simple.cpp:67:10:67:11 | *a2 [i] | simple.cpp:67:13:67:13 | i | provenance | |
| simple.cpp:78:9:78:15 | *this [f2, f1] | simple.cpp:79:16:79:17 | *this [f2, f1] | provenance | |
| simple.cpp:79:16:79:17 | *f2 [f1] | simple.cpp:79:19:79:20 | f1 | provenance | |
| simple.cpp:79:16:79:17 | *this [f2, f1] | simple.cpp:79:16:79:17 | *f2 [f1] | provenance | |
| simple.cpp:79:19:79:20 | f1 | simple.cpp:78:9:78:15 | *getf2f1 | provenance | |
| simple.cpp:79:19:79:20 | f1 | simple.cpp:79:19:79:20 | f1 | provenance | |
| simple.cpp:83:9:83:10 | *f2 [post update] [f1] | simple.cpp:83:9:83:10 | *this [post update] [f2, f1] | provenance | |
| simple.cpp:83:9:83:10 | *this [post update] [f2, f1] | simple.cpp:84:14:84:20 | *this [f2, f1] | provenance | |
| simple.cpp:83:9:83:28 | ... = ... | simple.cpp:83:9:83:10 | *f2 [post update] [f1] | provenance | |
| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | ... = ... | provenance | |
| simple.cpp:84:14:84:20 | *this [f2, f1] | simple.cpp:78:9:78:15 | *this [f2, f1] | provenance | |
| simple.cpp:84:14:84:20 | *this [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 | provenance | |
| simple.cpp:92:5:92:5 | *a [post update] [i] | simple.cpp:93:20:93:20 | a [i] | provenance | |
| simple.cpp:92:5:92:5 | *a [post update] [i] | simple.cpp:94:10:94:11 | *a2 [i] | provenance | |
| simple.cpp:92:5:92:22 | ... = ... | simple.cpp:92:5:92:5 | *a [post update] [i] | provenance | |
| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | ... = ... | provenance | |
| simple.cpp:93:20:93:20 | a [i] | simple.cpp:94:10:94:11 | *a2 [i] | provenance | |
| simple.cpp:94:10:94:11 | *a2 [i] | simple.cpp:94:13:94:13 | i | provenance | |
| simple.cpp:103:24:103:24 | x | simple.cpp:104:14:104:14 | x | provenance | |
| simple.cpp:108:17:108:26 | call to user_input | simple.cpp:108:17:108:26 | call to user_input | provenance | |
| simple.cpp:108:17:108:26 | call to user_input | simple.cpp:109:43:109:43 | x | provenance | |
| simple.cpp:109:43:109:43 | x | simple.cpp:103:24:103:24 | x | provenance | |
| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:14:24:14:25 | *ab [a] | provenance | |
@@ -854,18 +792,14 @@ nodes
| A.cpp:28:8:28:10 | *this [c] | semmle.label | *this [c] |
| A.cpp:28:23:28:26 | *this [c] | semmle.label | *this [c] |
| A.cpp:28:29:28:29 | c | semmle.label | c |
| A.cpp:28:29:28:29 | c | semmle.label | c |
| A.cpp:29:15:29:18 | **make [c] | semmle.label | **make [c] |
| A.cpp:29:23:29:23 | c | semmle.label | c |
| A.cpp:31:14:31:21 | *new [c] | semmle.label | *new [c] |
| A.cpp:31:14:31:21 | call to B [c] | semmle.label | call to B [c] |
| A.cpp:31:20:31:20 | c | semmle.label | c |
| A.cpp:41:5:41:6 | insert output argument | semmle.label | insert output argument |
| A.cpp:41:15:41:21 | new | semmle.label | new |
| A.cpp:43:10:43:12 | *& ... | semmle.label | *& ... |
| A.cpp:47:12:47:18 | new | semmle.label | new |
| A.cpp:47:12:47:18 | new | semmle.label | new |
| A.cpp:48:12:48:18 | *call to make [c] | semmle.label | *call to make [c] |
| A.cpp:48:12:48:18 | *call to make [c] | semmle.label | *call to make [c] |
| A.cpp:48:20:48:20 | c | semmle.label | c |
| A.cpp:49:10:49:10 | *b [c] | semmle.label | *b [c] |
@@ -879,39 +813,29 @@ nodes
| A.cpp:57:11:57:24 | call to B [c] | semmle.label | call to B [c] |
| A.cpp:57:17:57:23 | new | semmle.label | new |
| A.cpp:57:17:57:23 | new | semmle.label | new |
| A.cpp:64:5:64:29 | *... = ... [c] | semmle.label | *... = ... [c] |
| A.cpp:64:10:64:15 | *call to setOnB [c] | semmle.label | *call to setOnB [c] |
| A.cpp:64:21:64:28 | new | semmle.label | new |
| A.cpp:66:10:66:11 | *b2 [c] | semmle.label | *b2 [c] |
| A.cpp:66:10:66:14 | c | semmle.label | c |
| A.cpp:73:5:73:33 | *... = ... [c] | semmle.label | *... = ... [c] |
| A.cpp:73:10:73:19 | *call to setOnBWrap [c] | semmle.label | *call to setOnBWrap [c] |
| A.cpp:73:25:73:32 | new | semmle.label | new |
| A.cpp:75:10:75:11 | *b2 [c] | semmle.label | *b2 [c] |
| A.cpp:75:10:75:14 | c | semmle.label | c |
| A.cpp:78:6:78:15 | **setOnBWrap [c] | semmle.label | **setOnBWrap [c] |
| A.cpp:78:27:78:27 | c | semmle.label | c |
| A.cpp:81:5:81:22 | *... = ... [c] | semmle.label | *... = ... [c] |
| A.cpp:81:10:81:15 | *call to setOnB [c] | semmle.label | *call to setOnB [c] |
| A.cpp:81:21:81:21 | c | semmle.label | c |
| A.cpp:82:12:82:24 | *... ? ... : ... [c] | semmle.label | *... ? ... : ... [c] |
| A.cpp:85:9:85:14 | **setOnB [c] | semmle.label | **setOnB [c] |
| A.cpp:85:26:85:26 | c | semmle.label | c |
| A.cpp:90:7:90:8 | set output argument [c] | semmle.label | set output argument [c] |
| A.cpp:90:15:90:15 | c | semmle.label | c |
| A.cpp:91:14:91:15 | *b2 [c] | semmle.label | *b2 [c] |
| A.cpp:98:12:98:18 | new | semmle.label | new |
| A.cpp:98:12:98:18 | new | semmle.label | new |
| A.cpp:100:5:100:6 | *c1 [post update] [a] | semmle.label | *c1 [post update] [a] |
| A.cpp:100:5:100:13 | ... = ... | semmle.label | ... = ... |
| A.cpp:101:8:101:9 | *c1 [a] | semmle.label | *c1 [a] |
| A.cpp:103:14:103:14 | *c [a] | semmle.label | *c [a] |
| A.cpp:105:18:105:38 | *c [a] | semmle.label | *c [a] |
| A.cpp:107:12:107:13 | *c1 [a] | semmle.label | *c1 [a] |
| A.cpp:107:12:107:16 | a | semmle.label | a |
| A.cpp:110:18:110:38 | *c [a] | semmle.label | *c [a] |
| A.cpp:112:7:112:13 | *... = ... [a] | semmle.label | *... = ... [a] |
| A.cpp:118:18:118:39 | *cc [a] | semmle.label | *cc [a] |
| A.cpp:120:12:120:13 | *c1 [a] | semmle.label | *c1 [a] |
| A.cpp:120:12:120:16 | a | semmle.label | a |
| A.cpp:124:14:124:14 | *b [c] | semmle.label | *b [c] |
@@ -934,9 +858,6 @@ nodes
| A.cpp:143:7:143:31 | ... = ... | semmle.label | ... = ... |
| A.cpp:143:25:143:31 | new | semmle.label | new |
| A.cpp:150:12:150:18 | new | semmle.label | new |
| A.cpp:150:12:150:18 | new | semmle.label | new |
| A.cpp:151:12:151:24 | *new [*b, c] | semmle.label | *new [*b, c] |
| A.cpp:151:12:151:24 | *new [b] | semmle.label | *new [b] |
| A.cpp:151:12:151:24 | call to D [*b, c] | semmle.label | call to D [*b, c] |
| A.cpp:151:12:151:24 | call to D [b] | semmle.label | call to D [b] |
| A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] |
@@ -954,23 +875,16 @@ nodes
| A.cpp:154:10:154:10 | *b [c] | semmle.label | *b [c] |
| A.cpp:154:10:154:13 | c | semmle.label | c |
| A.cpp:159:12:159:18 | new | semmle.label | new |
| A.cpp:159:12:159:18 | new | semmle.label | new |
| A.cpp:160:18:160:60 | *new [head] | semmle.label | *new [head] |
| A.cpp:160:18:160:60 | call to MyList [head] | semmle.label | call to MyList [head] |
| A.cpp:160:29:160:29 | b | semmle.label | b |
| A.cpp:161:18:161:40 | *new [*next, head] | semmle.label | *new [*next, head] |
| A.cpp:161:18:161:40 | call to MyList [*next, head] | semmle.label | call to MyList [*next, head] |
| A.cpp:161:38:161:39 | *l1 [head] | semmle.label | *l1 [head] |
| A.cpp:162:18:162:40 | *new [*next, *next, head] | semmle.label | *new [*next, *next, head] |
| A.cpp:162:18:162:40 | call to MyList [*next, *next, head] | semmle.label | call to MyList [*next, *next, head] |
| A.cpp:162:38:162:39 | *l2 [*next, head] | semmle.label | *l2 [*next, head] |
| A.cpp:165:10:165:11 | *l3 [*next, *next, head] | semmle.label | *l3 [*next, *next, head] |
| A.cpp:165:10:165:29 | head | semmle.label | head |
| A.cpp:165:14:165:17 | *next [*next, head] | semmle.label | *next [*next, head] |
| A.cpp:165:20:165:23 | *next [head] | semmle.label | *next [head] |
| A.cpp:167:22:167:23 | *l3 [*next, *next, head] | semmle.label | *l3 [*next, *next, head] |
| A.cpp:167:40:167:50 | *... = ... [*next, head] | semmle.label | *... = ... [*next, head] |
| A.cpp:167:40:167:50 | *... = ... [head] | semmle.label | *... = ... [head] |
| A.cpp:167:44:167:44 | *l [*next, *next, head] | semmle.label | *l [*next, *next, head] |
| A.cpp:167:44:167:44 | *l [*next, head] | semmle.label | *l [*next, head] |
| A.cpp:167:47:167:50 | *next [*next, head] | semmle.label | *next [*next, head] |
@@ -989,22 +903,16 @@ nodes
| A.cpp:184:7:184:23 | *... = ... [*next, head] | semmle.label | *... = ... [*next, head] |
| A.cpp:184:7:184:23 | *... = ... [head] | semmle.label | *... = ... [head] |
| B.cpp:6:15:6:24 | new | semmle.label | new |
| B.cpp:6:15:6:24 | new | semmle.label | new |
| B.cpp:7:16:7:35 | *new [elem1] | semmle.label | *new [elem1] |
| B.cpp:7:16:7:35 | call to Box1 [elem1] | semmle.label | call to Box1 [elem1] |
| B.cpp:7:25:7:25 | e | semmle.label | e |
| B.cpp:8:16:8:27 | *new [*box1, elem1] | semmle.label | *new [*box1, elem1] |
| B.cpp:8:16:8:27 | call to Box2 [*box1, elem1] | semmle.label | call to Box2 [*box1, elem1] |
| B.cpp:8:25:8:26 | *b1 [elem1] | semmle.label | *b1 [elem1] |
| B.cpp:9:10:9:11 | *b2 [*box1, elem1] | semmle.label | *b2 [*box1, elem1] |
| B.cpp:9:10:9:24 | elem1 | semmle.label | elem1 |
| B.cpp:9:14:9:17 | *box1 [elem1] | semmle.label | *box1 [elem1] |
| B.cpp:15:15:15:27 | new | semmle.label | new |
| B.cpp:15:15:15:27 | new | semmle.label | new |
| B.cpp:16:16:16:38 | *new [elem2] | semmle.label | *new [elem2] |
| B.cpp:16:16:16:38 | call to Box1 [elem2] | semmle.label | call to Box1 [elem2] |
| B.cpp:16:37:16:37 | e | semmle.label | e |
| B.cpp:17:16:17:27 | *new [*box1, elem2] | semmle.label | *new [*box1, elem2] |
| B.cpp:17:16:17:27 | call to Box2 [*box1, elem2] | semmle.label | call to Box2 [*box1, elem2] |
| B.cpp:17:25:17:26 | *b1 [elem2] | semmle.label | *b1 [elem2] |
| B.cpp:19:10:19:11 | *b2 [*box1, elem2] | semmle.label | *b2 [*box1, elem2] |
@@ -1022,8 +930,6 @@ nodes
| B.cpp:46:7:46:10 | *this [post update] [*box1, elem2] | semmle.label | *this [post update] [*box1, elem2] |
| B.cpp:46:7:46:21 | *... = ... [elem1] | semmle.label | *... = ... [elem1] |
| B.cpp:46:7:46:21 | *... = ... [elem2] | semmle.label | *... = ... [elem2] |
| C.cpp:18:12:18:18 | *new [s1] | semmle.label | *new [s1] |
| C.cpp:18:12:18:18 | *new [s3] | semmle.label | *new [s3] |
| C.cpp:18:12:18:18 | call to C [s1] | semmle.label | call to C [s1] |
| C.cpp:18:12:18:18 | call to C [s3] | semmle.label | call to C [s3] |
| C.cpp:19:5:19:5 | *c [s1] | semmle.label | *c [s1] |
@@ -1044,45 +950,38 @@ nodes
| D.cpp:10:11:10:17 | *this [elem] | semmle.label | *this [elem] |
| D.cpp:10:30:10:33 | *this [elem] | semmle.label | *this [elem] |
| D.cpp:10:30:10:33 | elem | semmle.label | elem |
| D.cpp:10:30:10:33 | elem | semmle.label | elem |
| D.cpp:11:24:11:24 | e | semmle.label | e |
| D.cpp:11:29:11:32 | *this [post update] [elem] | semmle.label | *this [post update] [elem] |
| D.cpp:11:29:11:36 | ... = ... | semmle.label | ... = ... |
| D.cpp:17:11:17:17 | **getBox1 [elem] | semmle.label | **getBox1 [elem] |
| D.cpp:17:11:17:17 | *this [*box, elem] | semmle.label | *this [*box, elem] |
| D.cpp:17:30:17:32 | *box [elem] | semmle.label | *box [elem] |
| D.cpp:17:30:17:32 | *box [elem] | semmle.label | *box [elem] |
| D.cpp:17:30:17:32 | *this [*box, elem] | semmle.label | *this [*box, elem] |
| D.cpp:21:30:21:31 | *b2 [*box, elem] | semmle.label | *b2 [*box, elem] |
| D.cpp:22:10:22:11 | *b2 [*box, elem] | semmle.label | *b2 [*box, elem] |
| D.cpp:22:10:22:33 | call to getElem | semmle.label | call to getElem |
| D.cpp:22:14:22:20 | *call to getBox1 [elem] | semmle.label | *call to getBox1 [elem] |
| D.cpp:28:15:28:24 | new | semmle.label | new |
| D.cpp:28:15:28:24 | new | semmle.label | new |
| D.cpp:30:5:30:5 | *b [post update] [*box, elem] | semmle.label | *b [post update] [*box, elem] |
| D.cpp:30:5:30:20 | ... = ... | semmle.label | ... = ... |
| D.cpp:30:8:30:10 | *box [post update] [elem] | semmle.label | *box [post update] [elem] |
| D.cpp:31:14:31:14 | *b [*box, elem] | semmle.label | *b [*box, elem] |
| D.cpp:35:15:35:24 | new | semmle.label | new |
| D.cpp:35:15:35:24 | new | semmle.label | new |
| D.cpp:37:5:37:5 | *b [post update] [*box, elem] | semmle.label | *b [post update] [*box, elem] |
| D.cpp:37:8:37:10 | setElem output argument [elem] | semmle.label | setElem output argument [elem] |
| D.cpp:37:21:37:21 | e | semmle.label | e |
| D.cpp:38:14:38:14 | *b [*box, elem] | semmle.label | *b [*box, elem] |
| D.cpp:42:15:42:24 | new | semmle.label | new |
| D.cpp:42:15:42:24 | new | semmle.label | new |
| D.cpp:44:5:44:5 | getBox1 output argument [*box, elem] | semmle.label | getBox1 output argument [*box, elem] |
| D.cpp:44:5:44:26 | ... = ... | semmle.label | ... = ... |
| D.cpp:44:8:44:14 | *call to getBox1 [post update] [elem] | semmle.label | *call to getBox1 [post update] [elem] |
| D.cpp:45:14:45:14 | *b [*box, elem] | semmle.label | *b [*box, elem] |
| D.cpp:49:15:49:24 | new | semmle.label | new |
| D.cpp:49:15:49:24 | new | semmle.label | new |
| D.cpp:51:5:51:5 | getBox1 output argument [*box, elem] | semmle.label | getBox1 output argument [*box, elem] |
| D.cpp:51:8:51:14 | setElem output argument [elem] | semmle.label | setElem output argument [elem] |
| D.cpp:51:27:51:27 | e | semmle.label | e |
| D.cpp:52:14:52:14 | *b [*box, elem] | semmle.label | *b [*box, elem] |
| D.cpp:56:15:56:24 | new | semmle.label | new |
| D.cpp:56:15:56:24 | new | semmle.label | new |
| D.cpp:58:5:58:12 | *boxfield [post update] [*box, elem] | semmle.label | *boxfield [post update] [*box, elem] |
| D.cpp:58:5:58:12 | *this [post update] [*boxfield, *box, elem] | semmle.label | *this [post update] [*boxfield, *box, elem] |
| D.cpp:58:5:58:27 | ... = ... | semmle.label | ... = ... |
@@ -1124,7 +1023,6 @@ nodes
| aliasing.cpp:60:3:60:4 | *s2 [post update] [m1] | semmle.label | *s2 [post update] [m1] |
| aliasing.cpp:60:3:60:22 | ... = ... | semmle.label | ... = ... |
| aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:61:13:61:14 | s2 [m1] | semmle.label | s2 [m1] |
| aliasing.cpp:62:8:62:12 | *copy2 [m1] | semmle.label | *copy2 [m1] |
| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 |
| aliasing.cpp:92:3:92:3 | *w [post update] [s, m1] | semmle.label | *w [post update] [s, m1] |
@@ -1137,13 +1035,10 @@ nodes
| aliasing.cpp:98:3:98:3 | *s [post update] [m1] | semmle.label | *s [post update] [m1] |
| aliasing.cpp:98:3:98:21 | ... = ... | semmle.label | ... = ... |
| aliasing.cpp:98:10:98:19 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:100:14:100:14 | s [m1] | semmle.label | s [m1] |
| aliasing.cpp:101:13:101:22 | *& ... | semmle.label | *& ... |
| aliasing.cpp:101:13:101:22 | *& ... | semmle.label | *& ... |
| aliasing.cpp:101:14:101:19 | *s_copy [m1] | semmle.label | *s_copy [m1] |
| aliasing.cpp:102:8:102:10 | * ... | semmle.label | * ... |
| aliasing.cpp:105:23:105:24 | *pa | semmle.label | *pa |
| aliasing.cpp:106:3:106:20 | ... = ... | semmle.label | ... = ... |
| aliasing.cpp:106:9:106:18 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:121:15:121:16 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument |
| aliasing.cpp:122:8:122:12 | access to array | semmle.label | access to array |
@@ -1175,7 +1070,6 @@ nodes
| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument |
| aliasing.cpp:187:16:187:17 | *s2 [post update] [s, m1] | semmle.label | *s2 [post update] [s, m1] |
| aliasing.cpp:187:19:187:19 | *s [post update] [m1] | semmle.label | *s [post update] [m1] |
| aliasing.cpp:188:13:188:14 | s2 [s, m1] | semmle.label | s2 [s, m1] |
| aliasing.cpp:189:8:189:11 | *s2_2 [s, m1] | semmle.label | *s2_2 [s, m1] |
| aliasing.cpp:189:13:189:13 | *s [m1] | semmle.label | *s [m1] |
| aliasing.cpp:189:15:189:16 | m1 | semmle.label | m1 |
@@ -1185,13 +1079,11 @@ nodes
| aliasing.cpp:201:8:201:10 | *ps2 [s, m1] | semmle.label | *ps2 [s, m1] |
| aliasing.cpp:201:13:201:13 | *s [m1] | semmle.label | *s [m1] |
| aliasing.cpp:201:15:201:16 | m1 | semmle.label | m1 |
| arrays.cpp:6:3:6:23 | ... = ... | semmle.label | ... = ... |
| arrays.cpp:6:12:6:21 | call to user_input | semmle.label | call to user_input |
| arrays.cpp:7:8:7:13 | access to array | semmle.label | access to array |
| arrays.cpp:8:8:8:13 | access to array | semmle.label | access to array |
| arrays.cpp:9:8:9:11 | * ... | semmle.label | * ... |
| arrays.cpp:10:8:10:15 | * ... | semmle.label | * ... |
| arrays.cpp:15:3:15:25 | ... = ... | semmle.label | ... = ... |
| arrays.cpp:15:14:15:23 | call to user_input | semmle.label | call to user_input |
| arrays.cpp:16:8:16:13 | access to array | semmle.label | access to array |
| arrays.cpp:17:8:17:13 | access to array | semmle.label | access to array |
@@ -1253,21 +1145,17 @@ nodes
| by_reference.cpp:31:46:31:46 | *s [a] | semmle.label | *s [a] |
| by_reference.cpp:32:12:32:12 | *s [a] | semmle.label | *s [a] |
| by_reference.cpp:32:15:32:15 | a | semmle.label | a |
| by_reference.cpp:32:15:32:15 | a | semmle.label | a |
| by_reference.cpp:35:9:35:19 | *getDirectly | semmle.label | *getDirectly |
| by_reference.cpp:35:9:35:19 | *this [a] | semmle.label | *this [a] |
| by_reference.cpp:36:12:36:15 | *this [a] | semmle.label | *this [a] |
| by_reference.cpp:36:18:36:18 | a | semmle.label | a |
| by_reference.cpp:36:18:36:18 | a | semmle.label | a |
| by_reference.cpp:39:9:39:21 | *getIndirectly | semmle.label | *getIndirectly |
| by_reference.cpp:39:9:39:21 | *this [a] | semmle.label | *this [a] |
| by_reference.cpp:40:12:40:15 | *this [a] | semmle.label | *this [a] |
| by_reference.cpp:40:18:40:28 | call to getDirectly | semmle.label | call to getDirectly |
| by_reference.cpp:40:18:40:28 | call to getDirectly | semmle.label | call to getDirectly |
| by_reference.cpp:43:9:43:27 | *getThroughNonMember | semmle.label | *getThroughNonMember |
| by_reference.cpp:43:9:43:27 | *this [a] | semmle.label | *this [a] |
| by_reference.cpp:44:12:44:24 | call to nonMemberGetA | semmle.label | call to nonMemberGetA |
| by_reference.cpp:44:12:44:24 | call to nonMemberGetA | semmle.label | call to nonMemberGetA |
| by_reference.cpp:44:26:44:29 | *this [a] | semmle.label | *this [a] |
| by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | semmle.label | setDirectly output argument [a] |
| by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input |
@@ -1294,10 +1182,8 @@ nodes
| by_reference.cpp:88:3:88:24 | ... = ... | semmle.label | ... = ... |
| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:91:25:91:26 | *pa | semmle.label | *pa |
| by_reference.cpp:92:3:92:20 | ... = ... | semmle.label | ... = ... |
| by_reference.cpp:92:9:92:18 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:95:25:95:26 | *pa | semmle.label | *pa |
| by_reference.cpp:96:3:96:19 | ... = ... | semmle.label | ... = ... |
| by_reference.cpp:96:8:96:17 | call to user_input | semmle.label | call to user_input |
| 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:102:22:102:26 | *outer [post update] [inner_nested, a] | semmle.label | *outer [post update] [inner_nested, a] |
@@ -1448,12 +1334,10 @@ nodes
| complex.cpp:9:7:9:7 | *this [a_] | semmle.label | *this [a_] |
| complex.cpp:9:20:9:21 | *this [a_] | semmle.label | *this [a_] |
| complex.cpp:9:20:9:21 | a_ | semmle.label | a_ |
| complex.cpp:9:20:9:21 | a_ | semmle.label | a_ |
| complex.cpp:10:7:10:7 | *b | semmle.label | *b |
| complex.cpp:10:7:10:7 | *this [b_] | semmle.label | *this [b_] |
| complex.cpp:10:20:10:21 | *this [b_] | semmle.label | *this [b_] |
| complex.cpp:10:20:10:21 | b_ | semmle.label | b_ |
| complex.cpp:10:20:10:21 | b_ | semmle.label | b_ |
| complex.cpp:11:17:11:17 | a | semmle.label | a |
| complex.cpp:11:22:11:23 | *this [post update] [a_] | semmle.label | *this [post update] [a_] |
| complex.cpp:11:22:11:27 | ... = ... | semmle.label | ... = ... |
@@ -1525,12 +1409,10 @@ nodes
| constructors.cpp:18:9:18:9 | *this [a_] | semmle.label | *this [a_] |
| constructors.cpp:18:22:18:23 | *this [a_] | semmle.label | *this [a_] |
| constructors.cpp:18:22:18:23 | a_ | semmle.label | a_ |
| constructors.cpp:18:22:18:23 | a_ | semmle.label | a_ |
| constructors.cpp:19:9:19:9 | *b | semmle.label | *b |
| constructors.cpp:19:9:19:9 | *this [b_] | semmle.label | *this [b_] |
| constructors.cpp:19:22:19:23 | *this [b_] | semmle.label | *this [b_] |
| constructors.cpp:19:22:19:23 | b_ | semmle.label | b_ |
| constructors.cpp:19:22:19:23 | b_ | semmle.label | b_ |
| constructors.cpp:23:5:23:7 | *this [post update] [a_] | semmle.label | *this [post update] [a_] |
| constructors.cpp:23:5:23:7 | *this [post update] [b_] | semmle.label | *this [post update] [b_] |
| constructors.cpp:23:13:23:13 | a | semmle.label | a |
@@ -1620,12 +1502,10 @@ nodes
| simple.cpp:18:9:18:9 | *this [a_] | semmle.label | *this [a_] |
| simple.cpp:18:22:18:23 | *this [a_] | semmle.label | *this [a_] |
| simple.cpp:18:22:18:23 | a_ | semmle.label | a_ |
| simple.cpp:18:22:18:23 | a_ | semmle.label | a_ |
| simple.cpp:19:9:19:9 | *b | semmle.label | *b |
| simple.cpp:19:9:19:9 | *this [b_] | semmle.label | *this [b_] |
| simple.cpp:19:22:19:23 | *this [b_] | semmle.label | *this [b_] |
| simple.cpp:19:22:19:23 | b_ | semmle.label | b_ |
| simple.cpp:19:22:19:23 | b_ | semmle.label | b_ |
| simple.cpp:20:19:20:19 | a | semmle.label | a |
| simple.cpp:20:24:20:25 | *this [post update] [a_] | semmle.label | *this [post update] [a_] |
| simple.cpp:20:24:20:29 | ... = ... | semmle.label | ... = ... |
@@ -1653,7 +1533,6 @@ nodes
| simple.cpp:65:5:65:5 | *a [post update] [i] | semmle.label | *a [post update] [i] |
| simple.cpp:65:5:65:22 | ... = ... | semmle.label | ... = ... |
| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input |
| simple.cpp:66:12:66:12 | a [i] | semmle.label | a [i] |
| simple.cpp:67:10:67:11 | *a2 [i] | semmle.label | *a2 [i] |
| simple.cpp:67:13:67:13 | i | semmle.label | i |
| simple.cpp:78:9:78:15 | *getf2f1 | semmle.label | *getf2f1 |
@@ -1661,7 +1540,6 @@ nodes
| simple.cpp:79:16:79:17 | *f2 [f1] | semmle.label | *f2 [f1] |
| simple.cpp:79:16:79:17 | *this [f2, f1] | semmle.label | *this [f2, f1] |
| simple.cpp:79:19:79:20 | f1 | semmle.label | f1 |
| simple.cpp:79:19:79:20 | f1 | semmle.label | f1 |
| simple.cpp:83:9:83:10 | *f2 [post update] [f1] | semmle.label | *f2 [post update] [f1] |
| simple.cpp:83:9:83:10 | *this [post update] [f2, f1] | semmle.label | *this [post update] [f2, f1] |
| simple.cpp:83:9:83:28 | ... = ... | semmle.label | ... = ... |
@@ -1671,13 +1549,11 @@ nodes
| simple.cpp:92:5:92:5 | *a [post update] [i] | semmle.label | *a [post update] [i] |
| simple.cpp:92:5:92:22 | ... = ... | semmle.label | ... = ... |
| simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input |
| simple.cpp:93:20:93:20 | a [i] | semmle.label | a [i] |
| simple.cpp:94:10:94:11 | *a2 [i] | semmle.label | *a2 [i] |
| simple.cpp:94:13:94:13 | i | semmle.label | i |
| simple.cpp:103:24:103:24 | x | semmle.label | x |
| simple.cpp:104:14:104:14 | x | semmle.label | x |
| simple.cpp:108:17:108:26 | call to user_input | semmle.label | call to user_input |
| simple.cpp:108:17:108:26 | call to user_input | semmle.label | call to user_input |
| simple.cpp:109:43:109:43 | x | semmle.label | x |
| struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] |
| struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] |

View File

@@ -1,76 +0,0 @@
| tests.cpp:144:5:144:19 | [summary param] 0 in madArg0ToReturn | ParameterNode | madArg0ToReturn | madArg0ToReturn |
| tests.cpp:144:5:144:19 | [summary] to write: ReturnValue in madArg0ToReturn | ReturnNode | madArg0ToReturn | madArg0ToReturn |
| tests.cpp:145:6:145:28 | [summary param] 0 in madArg0ToReturnIndirect | ParameterNode | madArg0ToReturnIndirect | madArg0ToReturnIndirect |
| tests.cpp:145:6:145:28 | [summary] to write: ReturnValue[*] in madArg0ToReturnIndirect | ReturnNode | madArg0ToReturnIndirect | madArg0ToReturnIndirect |
| tests.cpp:147:5:147:28 | [summary param] 0 in madArg0ToReturnValueFlow | ParameterNode | madArg0ToReturnValueFlow | madArg0ToReturnValueFlow |
| tests.cpp:147:5:147:28 | [summary] to write: ReturnValue in madArg0ToReturnValueFlow | ReturnNode | madArg0ToReturnValueFlow | madArg0ToReturnValueFlow |
| tests.cpp:148:5:148:27 | [summary param] 0 indirection in madArg0IndirectToReturn | ParameterNode | madArg0IndirectToReturn | madArg0IndirectToReturn |
| tests.cpp:148:5:148:27 | [summary] to write: ReturnValue in madArg0IndirectToReturn | ReturnNode | madArg0IndirectToReturn | madArg0IndirectToReturn |
| tests.cpp:149:5:149:33 | [summary param] 0 indirection in madArg0DoubleIndirectToReturn | ParameterNode | madArg0DoubleIndirectToReturn | madArg0DoubleIndirectToReturn |
| tests.cpp:149:5:149:33 | [summary] to write: ReturnValue in madArg0DoubleIndirectToReturn | ReturnNode | madArg0DoubleIndirectToReturn | madArg0DoubleIndirectToReturn |
| tests.cpp:150:5:150:30 | [summary param] 0 in madArg0NotIndirectToReturn | ParameterNode | madArg0NotIndirectToReturn | madArg0NotIndirectToReturn |
| tests.cpp:150:5:150:30 | [summary] to write: ReturnValue in madArg0NotIndirectToReturn | ReturnNode | madArg0NotIndirectToReturn | madArg0NotIndirectToReturn |
| tests.cpp:151:6:151:26 | [summary param] 0 in madArg0ToArg1Indirect | ParameterNode | madArg0ToArg1Indirect | madArg0ToArg1Indirect |
| tests.cpp:151:6:151:26 | [summary param] 1 indirection in madArg0ToArg1Indirect | ParameterNode | madArg0ToArg1Indirect | madArg0ToArg1Indirect |
| tests.cpp:151:6:151:26 | [summary] to write: Argument[1 indirection] in madArg0ToArg1Indirect | PostUpdateNode | madArg0ToArg1Indirect | madArg0ToArg1Indirect |
| tests.cpp:152:6:152:34 | [summary param] 0 indirection in madArg0IndirectToArg1Indirect | ParameterNode | madArg0IndirectToArg1Indirect | madArg0IndirectToArg1Indirect |
| tests.cpp:152:6:152:34 | [summary param] 1 indirection in madArg0IndirectToArg1Indirect | ParameterNode | madArg0IndirectToArg1Indirect | madArg0IndirectToArg1Indirect |
| tests.cpp:152:6:152:34 | [summary] to write: Argument[1 indirection] in madArg0IndirectToArg1Indirect | PostUpdateNode | madArg0IndirectToArg1Indirect | madArg0IndirectToArg1Indirect |
| tests.cpp:153:5:153:18 | [summary param] 0 indirection in madArgsComplex | ParameterNode | madArgsComplex | madArgsComplex |
| tests.cpp:153:5:153:18 | [summary param] 1 indirection in madArgsComplex | ParameterNode | madArgsComplex | madArgsComplex |
| tests.cpp:153:5:153:18 | [summary param] 2 in madArgsComplex | ParameterNode | madArgsComplex | madArgsComplex |
| tests.cpp:153:5:153:18 | [summary] to write: ReturnValue in madArgsComplex | ReturnNode | madArgsComplex | madArgsComplex |
| tests.cpp:155:5:155:28 | [summary param] 2 in madAndImplementedComplex | ParameterNode | madAndImplementedComplex | madAndImplementedComplex |
| tests.cpp:155:5:155:28 | [summary] to write: ReturnValue in madAndImplementedComplex | ReturnNode | madAndImplementedComplex | madAndImplementedComplex |
| tests.cpp:160:5:160:24 | [summary param] 0 in madArg0FieldToReturn | ParameterNode | madArg0FieldToReturn | madArg0FieldToReturn |
| tests.cpp:160:5:160:24 | [summary] read: Argument[0].Field[value] in madArg0FieldToReturn | | madArg0FieldToReturn | madArg0FieldToReturn |
| tests.cpp:160:5:160:24 | [summary] to write: ReturnValue in madArg0FieldToReturn | ReturnNode | madArg0FieldToReturn | madArg0FieldToReturn |
| tests.cpp:161:5:161:32 | [summary param] 0 indirection in madArg0IndirectFieldToReturn | ParameterNode | madArg0IndirectFieldToReturn | madArg0IndirectFieldToReturn |
| tests.cpp:161:5:161:32 | [summary] read: Argument[0 indirection].Field[value] in madArg0IndirectFieldToReturn | | madArg0IndirectFieldToReturn | madArg0IndirectFieldToReturn |
| tests.cpp:161:5:161:32 | [summary] to write: ReturnValue in madArg0IndirectFieldToReturn | ReturnNode | madArg0IndirectFieldToReturn | madArg0IndirectFieldToReturn |
| tests.cpp:162:5:162:32 | [summary param] 0 in madArg0FieldIndirectToReturn | ParameterNode | madArg0FieldIndirectToReturn | madArg0FieldIndirectToReturn |
| tests.cpp:162:5:162:32 | [summary] read: Argument[0].Field[*ptr] in madArg0FieldIndirectToReturn | | madArg0FieldIndirectToReturn | madArg0FieldIndirectToReturn |
| tests.cpp:162:5:162:32 | [summary] to write: ReturnValue in madArg0FieldIndirectToReturn | ReturnNode | madArg0FieldIndirectToReturn | madArg0FieldIndirectToReturn |
| tests.cpp:163:13:163:32 | [summary param] 0 in madArg0ToReturnField | ParameterNode | madArg0ToReturnField | madArg0ToReturnField |
| tests.cpp:163:13:163:32 | [summary] to write: ReturnValue in madArg0ToReturnField | ReturnNode | madArg0ToReturnField | madArg0ToReturnField |
| tests.cpp:163:13:163:32 | [summary] to write: ReturnValue.Field[value] in madArg0ToReturnField | | madArg0ToReturnField | madArg0ToReturnField |
| tests.cpp:164:14:164:41 | [summary param] 0 in madArg0ToReturnIndirectField | ParameterNode | madArg0ToReturnIndirectField | madArg0ToReturnIndirectField |
| tests.cpp:164:14:164:41 | [summary] to write: ReturnValue[*] in madArg0ToReturnIndirectField | ReturnNode | madArg0ToReturnIndirectField | madArg0ToReturnIndirectField |
| tests.cpp:164:14:164:41 | [summary] to write: ReturnValue[*].Field[value] in madArg0ToReturnIndirectField | | madArg0ToReturnIndirectField | madArg0ToReturnIndirectField |
| tests.cpp:165:13:165:40 | [summary param] 0 in madArg0ToReturnFieldIndirect | ParameterNode | madArg0ToReturnFieldIndirect | madArg0ToReturnFieldIndirect |
| tests.cpp:165:13:165:40 | [summary] to write: ReturnValue in madArg0ToReturnFieldIndirect | ReturnNode | madArg0ToReturnFieldIndirect | madArg0ToReturnFieldIndirect |
| tests.cpp:165:13:165:40 | [summary] to write: ReturnValue.Field[*ptr] in madArg0ToReturnFieldIndirect | | madArg0ToReturnFieldIndirect | madArg0ToReturnFieldIndirect |
| tests.cpp:284:7:284:19 | [summary param] 0 in madArg0ToSelf | ParameterNode | madArg0ToSelf | madArg0ToSelf |
| tests.cpp:284:7:284:19 | [summary param] this indirection in madArg0ToSelf | ParameterNode | madArg0ToSelf | madArg0ToSelf |
| tests.cpp:284:7:284:19 | [summary] to write: Argument[this indirection] in madArg0ToSelf | PostUpdateNode | madArg0ToSelf | madArg0ToSelf |
| tests.cpp:285:6:285:20 | [summary param] this indirection in madSelfToReturn | ParameterNode | madSelfToReturn | madSelfToReturn |
| tests.cpp:285:6:285:20 | [summary] to write: ReturnValue in madSelfToReturn | ReturnNode | madSelfToReturn | madSelfToReturn |
| tests.cpp:287:7:287:20 | [summary param] 0 in madArg0ToField | ParameterNode | madArg0ToField | madArg0ToField |
| tests.cpp:287:7:287:20 | [summary param] this indirection in madArg0ToField | ParameterNode | madArg0ToField | madArg0ToField |
| tests.cpp:287:7:287:20 | [summary] to write: Argument[this indirection] in madArg0ToField | PostUpdateNode | madArg0ToField | madArg0ToField |
| tests.cpp:287:7:287:20 | [summary] to write: Argument[this indirection].Field[val] in madArg0ToField | | madArg0ToField | madArg0ToField |
| tests.cpp:288:6:288:21 | [summary param] this indirection in madFieldToReturn | ParameterNode | madFieldToReturn | madFieldToReturn |
| tests.cpp:288:6:288:21 | [summary] read: Argument[this indirection].Field[val] in madFieldToReturn | | madFieldToReturn | madFieldToReturn |
| tests.cpp:288:6:288:21 | [summary] to write: ReturnValue in madFieldToReturn | ReturnNode | madFieldToReturn | madFieldToReturn |
| tests.cpp:313:7:313:30 | [summary param] this indirection in namespaceMadSelfToReturn | ParameterNode | namespaceMadSelfToReturn | namespaceMadSelfToReturn |
| tests.cpp:313:7:313:30 | [summary] to write: ReturnValue in namespaceMadSelfToReturn | ReturnNode | namespaceMadSelfToReturn | namespaceMadSelfToReturn |
| tests.cpp:434:5:434:29 | [summary param] 0 in madCallArg0ReturnToReturn | ParameterNode | madCallArg0ReturnToReturn | madCallArg0ReturnToReturn |
| tests.cpp:434:5:434:29 | [summary] read: Argument[0].Parameter[this] in madCallArg0ReturnToReturn | PostUpdateNode | madCallArg0ReturnToReturn | madCallArg0ReturnToReturn |
| tests.cpp:434:5:434:29 | [summary] read: Argument[0].ReturnValue in madCallArg0ReturnToReturn | OutNode | madCallArg0ReturnToReturn | madCallArg0ReturnToReturn |
| tests.cpp:434:5:434:29 | [summary] to write: Argument[0].Parameter[this] in madCallArg0ReturnToReturn | ArgumentNode | madCallArg0ReturnToReturn | madCallArg0ReturnToReturn |
| tests.cpp:434:5:434:29 | [summary] to write: ReturnValue in madCallArg0ReturnToReturn | ReturnNode | madCallArg0ReturnToReturn | madCallArg0ReturnToReturn |
| tests.cpp:435:9:435:38 | [summary param] 0 in madCallArg0ReturnToReturnFirst | ParameterNode | madCallArg0ReturnToReturnFirst | madCallArg0ReturnToReturnFirst |
| tests.cpp:435:9:435:38 | [summary] read: Argument[0].Parameter[this] in madCallArg0ReturnToReturnFirst | PostUpdateNode | madCallArg0ReturnToReturnFirst | madCallArg0ReturnToReturnFirst |
| tests.cpp:435:9:435:38 | [summary] read: Argument[0].ReturnValue in madCallArg0ReturnToReturnFirst | OutNode | madCallArg0ReturnToReturnFirst | madCallArg0ReturnToReturnFirst |
| tests.cpp:435:9:435:38 | [summary] to write: Argument[0].Parameter[this] in madCallArg0ReturnToReturnFirst | ArgumentNode | madCallArg0ReturnToReturnFirst | madCallArg0ReturnToReturnFirst |
| tests.cpp:435:9:435:38 | [summary] to write: ReturnValue in madCallArg0ReturnToReturnFirst | ReturnNode | madCallArg0ReturnToReturnFirst | madCallArg0ReturnToReturnFirst |
| tests.cpp:435:9:435:38 | [summary] to write: ReturnValue.Field[first] in madCallArg0ReturnToReturnFirst | | madCallArg0ReturnToReturnFirst | madCallArg0ReturnToReturnFirst |
| tests.cpp:436:6:436:25 | [summary param] 0 in madCallArg0WithValue | ParameterNode | madCallArg0WithValue | madCallArg0WithValue |
| tests.cpp:436:6:436:25 | [summary param] 1 in madCallArg0WithValue | ParameterNode | madCallArg0WithValue | madCallArg0WithValue |
| tests.cpp:436:6:436:25 | [summary] read: Argument[0].Parameter[0] in madCallArg0WithValue | PostUpdateNode | madCallArg0WithValue | madCallArg0WithValue |
| tests.cpp:436:6:436:25 | [summary] read: Argument[0].Parameter[this] in madCallArg0WithValue | PostUpdateNode | madCallArg0WithValue | madCallArg0WithValue |
| tests.cpp:436:6:436:25 | [summary] to write: Argument[0].Parameter[0] in madCallArg0WithValue | ArgumentNode | madCallArg0WithValue | madCallArg0WithValue |
| tests.cpp:436:6:436:25 | [summary] to write: Argument[0].Parameter[this] in madCallArg0WithValue | ArgumentNode | madCallArg0WithValue | madCallArg0WithValue |
| tests.cpp:436:6:436:25 | [summary] to write: Argument[1] in madCallArg0WithValue | PostUpdateNode | madCallArg0WithValue | madCallArg0WithValue |
| tests.cpp:437:5:437:36 | [summary param] 1 in madCallReturnValueIgnoreFunction | ParameterNode | madCallReturnValueIgnoreFunction | madCallReturnValueIgnoreFunction |
| tests.cpp:437:5:437:36 | [summary] to write: ReturnValue in madCallReturnValueIgnoreFunction | ReturnNode | madCallReturnValueIgnoreFunction | madCallReturnValueIgnoreFunction |

View File

@@ -1,19 +0,0 @@
import testModels
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
string describe(DataFlow::Node n) {
n instanceof ParameterNode and result = "ParameterNode"
or
n instanceof PostUpdateNode and result = "PostUpdateNode"
or
n instanceof ArgumentNode and result = "ArgumentNode"
or
n instanceof ReturnNode and result = "ReturnNode"
or
n instanceof OutNode and result = "OutNode"
}
from FlowSummaryNode n
select n, concat(describe(n), ", "), concat(n.getSummarizedCallable().toString(), ", "),
concat(n.getEnclosingCallable().toString(), ", ")

View File

@@ -1,220 +0,0 @@
summaryCalls
| file://:0:0:0:0 | [summary] call to [summary param] 0 in madCallArg0ReturnToReturn in madCallArg0ReturnToReturn |
| file://:0:0:0:0 | [summary] call to [summary param] 0 in madCallArg0ReturnToReturnFirst in madCallArg0ReturnToReturnFirst |
| file://:0:0:0:0 | [summary] call to [summary param] 0 in madCallArg0WithValue in madCallArg0WithValue |
summarizedCallables
| tests.cpp:144:5:144:19 | madArg0ToReturn |
| tests.cpp:145:6:145:28 | madArg0ToReturnIndirect |
| tests.cpp:147:5:147:28 | madArg0ToReturnValueFlow |
| tests.cpp:148:5:148:27 | madArg0IndirectToReturn |
| tests.cpp:149:5:149:33 | madArg0DoubleIndirectToReturn |
| tests.cpp:150:5:150:30 | madArg0NotIndirectToReturn |
| tests.cpp:151:6:151:26 | madArg0ToArg1Indirect |
| tests.cpp:152:6:152:34 | madArg0IndirectToArg1Indirect |
| tests.cpp:153:5:153:18 | madArgsComplex |
| tests.cpp:154:5:154:14 | madArgsAny |
| tests.cpp:155:5:155:28 | madAndImplementedComplex |
| tests.cpp:160:5:160:24 | madArg0FieldToReturn |
| tests.cpp:161:5:161:32 | madArg0IndirectFieldToReturn |
| tests.cpp:162:5:162:32 | madArg0FieldIndirectToReturn |
| tests.cpp:163:13:163:32 | madArg0ToReturnField |
| tests.cpp:164:14:164:41 | madArg0ToReturnIndirectField |
| tests.cpp:165:13:165:40 | madArg0ToReturnFieldIndirect |
| tests.cpp:284:7:284:19 | madArg0ToSelf |
| tests.cpp:285:6:285:20 | madSelfToReturn |
| tests.cpp:287:7:287:20 | madArg0ToField |
| tests.cpp:288:6:288:21 | madFieldToReturn |
| tests.cpp:313:7:313:30 | namespaceMadSelfToReturn |
| tests.cpp:434:5:434:29 | madCallArg0ReturnToReturn |
| tests.cpp:435:9:435:38 | madCallArg0ReturnToReturnFirst |
| tests.cpp:436:6:436:25 | madCallArg0WithValue |
| tests.cpp:437:5:437:36 | madCallReturnValueIgnoreFunction |
sourceCallables
| tests.cpp:3:5:3:10 | source |
| tests.cpp:4:6:4:14 | sourcePtr |
| tests.cpp:5:6:5:19 | sourceIndirect |
| tests.cpp:6:6:6:9 | sink |
| tests.cpp:6:15:6:17 | val |
| tests.cpp:7:6:7:9 | sink |
| tests.cpp:7:16:7:18 | ptr |
| tests.cpp:11:5:11:18 | localMadSource |
| tests.cpp:12:5:12:19 | remoteMadSource |
| tests.cpp:13:5:13:14 | notASource |
| tests.cpp:14:5:14:22 | localMadSourceVoid |
| tests.cpp:15:5:15:25 | localMadSourceHasBody |
| tests.cpp:16:6:16:28 | remoteMadSourceIndirect |
| tests.cpp:17:7:17:35 | remoteMadSourceDoubleIndirect |
| tests.cpp:18:6:18:32 | remoteMadSourceIndirectArg0 |
| tests.cpp:18:39:18:39 | x |
| tests.cpp:18:47:18:47 | y |
| tests.cpp:19:6:19:32 | remoteMadSourceIndirectArg1 |
| tests.cpp:19:39:19:39 | x |
| tests.cpp:19:47:19:47 | y |
| tests.cpp:20:5:20:22 | remoteMadSourceVar |
| tests.cpp:21:6:21:31 | remoteMadSourceVarIndirect |
| tests.cpp:24:6:24:28 | namespaceLocalMadSource |
| tests.cpp:25:6:25:31 | namespaceLocalMadSourceVar |
| tests.cpp:28:7:28:30 | namespace2LocalMadSource |
| tests.cpp:31:6:31:19 | localMadSource |
| tests.cpp:33:5:33:27 | namespaceLocalMadSource |
| tests.cpp:35:6:35:17 | test_sources |
| tests.cpp:50:6:50:6 | v |
| tests.cpp:51:7:51:16 | v_indirect |
| tests.cpp:52:6:52:13 | v_direct |
| tests.cpp:63:6:63:6 | a |
| tests.cpp:63:9:63:9 | b |
| tests.cpp:63:12:63:12 | c |
| tests.cpp:63:15:63:15 | d |
| tests.cpp:75:6:75:6 | e |
| tests.cpp:85:6:85:26 | remoteMadSourceParam0 |
| tests.cpp:85:32:85:32 | x |
| tests.cpp:92:6:92:16 | madSinkArg0 |
| tests.cpp:92:22:92:22 | x |
| tests.cpp:93:6:93:13 | notASink |
| tests.cpp:93:19:93:19 | x |
| tests.cpp:94:6:94:16 | madSinkArg1 |
| tests.cpp:94:22:94:22 | x |
| tests.cpp:94:29:94:29 | y |
| tests.cpp:95:6:95:17 | madSinkArg01 |
| tests.cpp:95:23:95:23 | x |
| tests.cpp:95:30:95:30 | y |
| tests.cpp:95:37:95:37 | z |
| tests.cpp:96:6:96:17 | madSinkArg02 |
| tests.cpp:96:23:96:23 | x |
| tests.cpp:96:30:96:30 | y |
| tests.cpp:96:37:96:37 | z |
| tests.cpp:97:6:97:24 | madSinkIndirectArg0 |
| tests.cpp:97:31:97:31 | x |
| tests.cpp:98:6:98:30 | madSinkDoubleIndirectArg0 |
| tests.cpp:98:38:98:38 | x |
| tests.cpp:99:5:99:14 | madSinkVar |
| tests.cpp:100:6:100:23 | madSinkVarIndirect |
| tests.cpp:102:6:102:15 | test_sinks |
| tests.cpp:116:6:116:6 | a |
| tests.cpp:117:7:117:11 | a_ptr |
| tests.cpp:132:6:132:18 | madSinkParam0 |
| tests.cpp:132:24:132:24 | x |
| tests.cpp:138:8:138:8 | operator= |
| tests.cpp:138:8:138:8 | operator= |
| tests.cpp:138:8:138:18 | MyContainer |
| tests.cpp:139:6:139:10 | value |
| tests.cpp:140:6:140:11 | value2 |
| tests.cpp:141:7:141:9 | ptr |
| tests.cpp:144:25:144:25 | x |
| tests.cpp:145:34:145:34 | x |
| tests.cpp:146:5:146:15 | notASummary |
| tests.cpp:146:21:146:21 | x |
| tests.cpp:147:34:147:34 | x |
| tests.cpp:148:34:148:34 | x |
| tests.cpp:149:41:149:41 | x |
| tests.cpp:150:37:150:37 | x |
| tests.cpp:151:32:151:32 | x |
| tests.cpp:151:40:151:40 | y |
| tests.cpp:152:47:152:47 | x |
| tests.cpp:152:55:152:55 | y |
| tests.cpp:153:25:153:25 | a |
| tests.cpp:153:33:153:33 | b |
| tests.cpp:153:40:153:40 | c |
| tests.cpp:153:47:153:47 | d |
| tests.cpp:154:20:154:20 | a |
| tests.cpp:154:28:154:28 | b |
| tests.cpp:155:34:155:34 | a |
| tests.cpp:155:41:155:41 | b |
| tests.cpp:155:48:155:48 | c |
| tests.cpp:160:38:160:39 | mc |
| tests.cpp:161:47:161:48 | mc |
| tests.cpp:162:46:162:47 | mc |
| tests.cpp:163:38:163:38 | x |
| tests.cpp:164:47:164:47 | x |
| tests.cpp:165:46:165:46 | x |
| tests.cpp:167:13:167:30 | madFieldToFieldVar |
| tests.cpp:168:13:168:38 | madFieldToIndirectFieldVar |
| tests.cpp:169:14:169:39 | madIndirectFieldToFieldVar |
| tests.cpp:171:6:171:19 | test_summaries |
| tests.cpp:174:6:174:6 | a |
| tests.cpp:174:9:174:9 | b |
| tests.cpp:174:12:174:12 | c |
| tests.cpp:174:15:174:15 | d |
| tests.cpp:174:18:174:18 | e |
| tests.cpp:175:7:175:11 | a_ptr |
| tests.cpp:218:14:218:16 | mc1 |
| tests.cpp:218:19:218:21 | mc2 |
| tests.cpp:237:15:237:18 | rtn1 |
| tests.cpp:240:14:240:17 | rtn2 |
| tests.cpp:241:7:241:14 | rtn2_ptr |
| tests.cpp:267:7:267:7 | operator= |
| tests.cpp:267:7:267:7 | operator= |
| tests.cpp:267:7:267:13 | MyClass |
| tests.cpp:270:6:270:26 | memberRemoteMadSource |
| tests.cpp:271:7:271:39 | memberRemoteMadSourceIndirectArg0 |
| tests.cpp:271:46:271:46 | x |
| tests.cpp:272:6:272:29 | memberRemoteMadSourceVar |
| tests.cpp:273:7:273:21 | qualifierSource |
| tests.cpp:274:7:274:26 | qualifierFieldSource |
| tests.cpp:277:7:277:23 | memberMadSinkArg0 |
| tests.cpp:277:29:277:29 | x |
| tests.cpp:278:6:278:21 | memberMadSinkVar |
| tests.cpp:279:7:279:19 | qualifierSink |
| tests.cpp:280:7:280:23 | qualifierArg0Sink |
| tests.cpp:280:29:280:29 | x |
| tests.cpp:281:7:281:24 | qualifierFieldSink |
| tests.cpp:284:25:284:25 | x |
| tests.cpp:286:6:286:16 | notASummary |
| tests.cpp:287:26:287:26 | x |
| tests.cpp:290:6:290:8 | val |
| tests.cpp:293:7:293:7 | MyDerivedClass |
| tests.cpp:293:7:293:7 | operator= |
| tests.cpp:293:7:293:7 | operator= |
| tests.cpp:293:7:293:20 | MyDerivedClass |
| tests.cpp:295:6:295:28 | subtypeRemoteMadSource1 |
| tests.cpp:296:6:296:21 | subtypeNonSource |
| tests.cpp:297:6:297:28 | subtypeRemoteMadSource2 |
| tests.cpp:300:9:300:15 | source2 |
| tests.cpp:301:6:301:9 | sink |
| tests.cpp:301:19:301:20 | mc |
| tests.cpp:304:8:304:8 | operator= |
| tests.cpp:304:8:304:8 | operator= |
| tests.cpp:304:8:304:14 | MyClass |
| tests.cpp:307:8:307:33 | namespaceMemberMadSinkArg0 |
| tests.cpp:307:39:307:39 | x |
| tests.cpp:308:15:308:46 | namespaceStaticMemberMadSinkArg0 |
| tests.cpp:308:52:308:52 | x |
| tests.cpp:309:7:309:31 | namespaceMemberMadSinkVar |
| tests.cpp:310:14:310:44 | namespaceStaticMemberMadSinkVar |
| tests.cpp:317:22:317:28 | source3 |
| tests.cpp:319:6:319:23 | test_class_members |
| tests.cpp:320:10:320:11 | mc |
| tests.cpp:320:14:320:16 | mc2 |
| tests.cpp:320:19:320:21 | mc3 |
| tests.cpp:320:24:320:26 | mc4 |
| tests.cpp:320:29:320:31 | mc5 |
| tests.cpp:320:34:320:36 | mc6 |
| tests.cpp:320:39:320:41 | mc7 |
| tests.cpp:320:44:320:46 | mc8 |
| tests.cpp:320:49:320:51 | mc9 |
| tests.cpp:320:54:320:57 | mc10 |
| tests.cpp:320:60:320:63 | mc11 |
| tests.cpp:321:11:321:13 | ptr |
| tests.cpp:321:17:321:23 | mc4_ptr |
| tests.cpp:322:17:322:19 | mdc |
| tests.cpp:323:23:323:25 | mnc |
| tests.cpp:323:28:323:31 | mnc2 |
| tests.cpp:324:24:324:31 | mnc2_ptr |
| tests.cpp:330:6:330:6 | a |
| tests.cpp:429:8:429:8 | operator= |
| tests.cpp:429:8:429:8 | operator= |
| tests.cpp:429:8:429:14 | intPair |
| tests.cpp:430:6:430:10 | first |
| tests.cpp:431:6:431:11 | second |
| tests.cpp:434:37:434:43 | fun_ptr |
| tests.cpp:435:46:435:52 | fun_ptr |
| tests.cpp:436:34:436:40 | fun_ptr |
| tests.cpp:436:53:436:57 | value |
| tests.cpp:437:45:437:51 | fun_ptr |
| tests.cpp:437:64:437:68 | value |
| tests.cpp:439:5:439:14 | getTainted |
| tests.cpp:440:6:440:13 | useValue |
| tests.cpp:440:19:440:19 | x |
| tests.cpp:441:6:441:17 | dontUseValue |
| tests.cpp:441:23:441:23 | x |
| tests.cpp:443:6:443:27 | test_function_pointers |

View File

@@ -1,9 +0,0 @@
import testModels
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
query predicate summaryCalls(SummaryCall c) { any() }
query predicate summarizedCallables(SummarizedCallable c) { any() }
query predicate sourceCallables(SourceCallable c) { c.getLocation().getFile().toString() != "" }

View File

@@ -1,2 +0,0 @@
testFailures
failures

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