Compare commits

..

2 Commits

Author SHA1 Message Date
Paolo Tranquilli
bd1f548fbc Swift: use git-lfs devcontainer feature 2024-07-16 11:24:01 +02:00
Paolo Tranquilli
1dbe908024 Swift: tentative fix to install git-lfs in codespace without direct write access 2024-07-09 10:48:18 +02:00
2847 changed files with 50526 additions and 283616 deletions

View File

@@ -24,6 +24,5 @@ common --registry=file:///%workspace%/misc/bazel/registry
common --registry=https://bcr.bazel.build
common --@rules_dotnet//dotnet/settings:strict_deps=false
common --experimental_isolated_extension_usages
try-import %workspace%/local.bazelrc

View File

@@ -8,4 +8,3 @@ common --registry=https://bcr.bazel.build
# its implementation packages without providing any code itself.
# We either can depend on internal implementation details, or turn of strict deps.
common --@rules_dotnet//dotnet/settings:strict_deps=false
common --experimental_isolated_extension_usages

View File

@@ -1,25 +1,28 @@
{
"extensions": [
"github.vscode-codeql",
"hbenl.vscode-test-explorer",
"ms-vscode.test-adapter-converter",
"slevesque.vscode-zipexplorer",
"ms-vscode.cpptools"
],
"settings": {
"files.watcherExclude": {
"**/target/**": true
},
"codeQL.runningQueries.memory": 2048
},
"build": {
"dockerfile": "Dockerfile",
},
"runArgs": [
"--cap-add=SYS_PTRACE",
"--security-opt",
"seccomp=unconfined"
],
"remoteUser": "vscode",
"onCreateCommand": ".devcontainer/swift/user.sh"
"extensions": [
"github.vscode-codeql",
"hbenl.vscode-test-explorer",
"ms-vscode.test-adapter-converter",
"slevesque.vscode-zipexplorer",
"ms-vscode.cpptools"
],
"features": {
"git-lfs": "latest"
},
"settings": {
"files.watcherExclude": {
"**/target/**": true
},
"codeQL.runningQueries.memory": 2048
},
"build": {
"dockerfile": "Dockerfile",
},
"runArgs": [
"--cap-add=SYS_PTRACE",
"--security-opt",
"seccomp=unconfined"
],
"remoteUser": "vscode",
"onCreateCommand": ".devcontainer/swift/user.sh"
}

View File

@@ -3,9 +3,6 @@ set -xe
BAZELISK_VERSION=v1.12.0
BAZELISK_DOWNLOAD_SHA=6b0bcb2ea15bca16fffabe6fda75803440375354c085480fe361d2cbf32501db
# install git lfs apt source
curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash
# install gh apt source
(type -p wget >/dev/null || (sudo apt update && sudo apt-get install wget -y)) \
&& sudo mkdir -p -m 755 /etc/apt/keyrings \
@@ -21,7 +18,6 @@ apt-get -y install --no-install-recommends \
python3-distutils \
python3-pip \
bash-completion \
git-lfs \
gh
# Install Bazel

View File

@@ -1,7 +1,5 @@
set -xe
git lfs install
# add the workspace to the codeql search path
mkdir -p /home/vscode/.config/codeql
echo "--search-path /workspaces/codeql" > /home/vscode/.config/codeql/config

View File

@@ -24,5 +24,5 @@ jobs:
extra_args: >
buildifier --all-files 2>&1 ||
(
echo -e "In order to format all bazel files, please run:\n bazel run //misc/bazel/buildifier"; exit 1
echo -e "In order to format all bazel files, please run:\n bazel run //misc/bazel:buildifier"; exit 1
)

View File

@@ -29,6 +29,8 @@ jobs:
key: all-queries
- name: check formatting
run: find shared */ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 -n 3000 -P 10 codeql query format -q --check-only
- name: Omit DatabaseQualityDiagnostics.ql from compile checking # Remove me once CodeQL 2.18.0 is released!
run: mv java/ql/src/Telemetry/DatabaseQualityDiagnostics.ql{,.hidden}
- name: compile queries - check-only
# run with --check-only if running in a PR (github.sha != main)
if : ${{ github.event_name == 'pull_request' }}
@@ -39,3 +41,6 @@ jobs:
if : ${{ github.event_name != 'pull_request' }}
shell: bash
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500
- name: Restore DatabaseQualityDiagnostics.ql after compile checking # Remove me once CodeQL 2.18.0 is released
run: mv java/ql/src/Telemetry/DatabaseQualityDiagnostics.ql{.hidden,}

View File

@@ -26,7 +26,7 @@ repos:
name: Format bazel files
files: \.(bazel|bzl)
language: system
entry: bazel run //misc/bazel/buildifier
entry: bazel run //misc/bazel:buildifier
pass_filenames: false
# DISABLED: can be enabled by copying this config and installing `pre-commit` with `--config` on the copy

View File

@@ -1,7 +1,6 @@
module(
name = "ql",
name = "codeql",
version = "0.0",
repo_name = "codeql",
)
# this points to our internal repository when `codeql` is checked out as a submodule thereof
@@ -15,7 +14,7 @@ local_path_override(
# see https://registry.bazel.build/ for a list of available packages
bazel_dep(name = "platforms", version = "0.0.10")
bazel_dep(name = "rules_go", version = "0.49.0")
bazel_dep(name = "rules_go", version = "0.48.0")
bazel_dep(name = "rules_pkg", version = "0.10.1")
bazel_dep(name = "rules_nodejs", version = "6.2.0-codeql.1")
bazel_dep(name = "rules_python", version = "0.32.2")
@@ -24,20 +23,18 @@ bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl")
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
bazel_dep(name = "fmt", version = "10.0.0")
bazel_dep(name = "rules_kotlin", version = "1.9.4-codeql.1")
bazel_dep(name = "gazelle", version = "0.38.0")
bazel_dep(name = "gazelle", version = "0.37.0")
bazel_dep(name = "rules_dotnet", version = "0.15.1")
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
bazel_dep(name = "rules_rust", version = "0.49.1")
bazel_dep(name = "rules_rust", version = "0.46.0")
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
# crate_py but shortened due to Windows file path considerations
cp = use_extension(
crate = use_extension(
"@rules_rust//crate_universe:extension.bzl",
"crate",
isolate = True,
)
cp.from_cargo(
crate.from_cargo(
name = "py_deps",
cargo_lockfile = "//python/extractor/tsg-python:Cargo.lock",
manifests = [
@@ -45,23 +42,15 @@ cp.from_cargo(
"//python/extractor/tsg-python/tsp:Cargo.toml",
],
)
use_repo(cp, "py_deps")
# crate_ruby, but shortened due to windows file paths
r = use_extension(
"@rules_rust//crate_universe:extension.bzl",
"crate",
isolate = True,
)
r.from_cargo(
name = "rd",
crate.from_cargo(
name = "ruby_deps",
cargo_lockfile = "//ruby/extractor:Cargo.lock",
manifests = [
"//ruby/extractor:Cargo.toml",
"//ruby/extractor/codeql-extractor-fake-crate:Cargo.toml",
],
)
use_repo(r, ruby_deps = "rd")
use_repo(crate, "py_deps", "ruby_deps")
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
dotnet.toolchain(dotnet_version = "8.0.101")
@@ -123,7 +112,6 @@ use_repo(
"kotlin-compiler-1.9.0-Beta",
"kotlin-compiler-1.9.20-Beta",
"kotlin-compiler-2.0.0-RC1",
"kotlin-compiler-2.0.20-Beta2",
"kotlin-compiler-embeddable-1.5.0",
"kotlin-compiler-embeddable-1.5.10",
"kotlin-compiler-embeddable-1.5.20",
@@ -136,7 +124,6 @@ use_repo(
"kotlin-compiler-embeddable-1.9.0-Beta",
"kotlin-compiler-embeddable-1.9.20-Beta",
"kotlin-compiler-embeddable-2.0.0-RC1",
"kotlin-compiler-embeddable-2.0.20-Beta2",
"kotlin-stdlib-1.5.0",
"kotlin-stdlib-1.5.10",
"kotlin-stdlib-1.5.20",
@@ -149,16 +136,11 @@ use_repo(
"kotlin-stdlib-1.9.0-Beta",
"kotlin-stdlib-1.9.20-Beta",
"kotlin-stdlib-2.0.0-RC1",
"kotlin-stdlib-2.0.20-Beta2",
)
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
go_sdk.download(version = "1.22.2")
go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
go_deps.from_file(go_mod = "//go/extractor:go.mod")
use_repo(go_deps, "org_golang_x_mod", "org_golang_x_tools")
lfs_files = use_repo_rule("//misc/bazel:lfs.bzl", "lfs_files")
lfs_files(

View File

@@ -1,4 +0,0 @@
description: Revert support for using-enum declarations.
compatibility: partial
usings.rel: run usings.qlo
using_container.rel: run using_container.qlo

View File

@@ -1,14 +0,0 @@
class UsingEntry extends @using {
string toString() { none() }
}
class Element extends @element {
string toString() { none() }
}
from UsingEntry u, Element parent, int kind
where
usings(u, _, _, kind) and
using_container(parent, u) and
kind != 3
select parent, u

View File

@@ -1,17 +0,0 @@
class UsingEntry extends @using {
string toString() { none() }
}
class Element extends @element {
string toString() { none() }
}
class Location extends @location_default {
string toString() { none() }
}
from UsingEntry u, Element target, Location loc, int kind
where
usings(u, target, loc, kind) and
kind != 3
select u, target, loc

View File

@@ -1,17 +0,0 @@
class Expr extends @expr {
string toString() { none() }
}
class Location extends @location_expr {
string toString() { none() }
}
predicate isExprWithNewBuiltin(Expr expr) {
exists(int kind | exprs(expr, kind, _) | 364 <= kind and kind <= 384)
}
from Expr expr, int kind, int kind_new, Location location
where
exprs(expr, kind, location) and
if isExprWithNewBuiltin(expr) then kind_new = 1 else kind_new = kind
select expr, kind_new, location

View File

@@ -1,3 +0,0 @@
description: Add new builtin operations
compatibility: partial
exprs.rel: run exprs.qlo

View File

@@ -1,3 +0,0 @@
description: description: Support explicit(bool) specifiers
compatibility: full
explicit_specifier_exprs.rel: delete

View File

@@ -1,2 +0,0 @@
description: Support destroying deletes
compatibility: full

View File

@@ -1,3 +0,0 @@
description: Add relation between deduction guides and class templates
compatibility: full
deduction_guide_for_class.rel: delete

View File

@@ -1,26 +1,3 @@
## 1.4.0
### New Features
* A `getTemplateClass` predicate was added to the `DeductionGuide` class to get the class template for which the deduction guide is a guide.
* An `isExplicit` predicate was added to the `Function` class that determines whether the function was declared as explicit.
* A `getExplicitExpr` predicate was added to the `Function` class that yields the constant boolean expression (if any) that conditionally determines whether the function is explicit.
* A `isDestroyingDeleteDeallocation` predicate was added to the `NewOrNewArrayExpr` and `DeleteOrDeleteArrayExpr` classes to indicate whether the deallocation function is a destroying delete.
### Minor Analysis Improvements
* The controlling expression of a `constexpr if` is now always recognized as an unevaluated expression.
* Improved performance of alias analysis of large function bodies. In rare cases, alerts that depend on alias analysis of large function bodies may be affected.
* A `UsingEnumDeclarationEntry` class has been added for C++ `using enum` declarations. As part of this, synthesized `UsingDeclarationEntry`s are no longer emitted for individual enumerators of the referenced enumeration.
## 1.3.0
### New Features
* Models-as-data alert provenance information has been extended to the C/C++ language. Any qltests that include the edges relation in their output (for example, `.qlref`s that reference path-problem queries) will need to be have their expected output updated accordingly.
* Added subclasses of `BuiltInOperations` for `__builtin_has_attribute`, `__builtin_is_corresponding_member`, `__builtin_is_pointer_interconvertible_with_class`, `__is_assignable_no_precondition_check`, `__is_bounded_array`, `__is_convertible`, `__is_corresponding_member`, `__is_nothrow_convertible`, `__is_pointer_interconvertible_with_class`, `__is_referenceable`, `__is_same_as`, `__is_trivially_copy_assignable`, `__is_unbounded_array`, `__is_valid_winrt_type`, `_is_win_class`, `__is_win_interface`, `__reference_binds_to_temporary`, `__reference_constructs_from_temporary`, and `__reference_converts_from_temporary`.
* The class `NewArrayExpr` adds a predicate `getArraySize()` to allow a more convenient way to access the static size of the array when the extent is missing.
## 1.2.0
### New Features

View File

@@ -1,7 +0,0 @@
## 1.3.0
### New Features
* Models-as-data alert provenance information has been extended to the C/C++ language. Any qltests that include the edges relation in their output (for example, `.qlref`s that reference path-problem queries) will need to be have their expected output updated accordingly.
* Added subclasses of `BuiltInOperations` for `__builtin_has_attribute`, `__builtin_is_corresponding_member`, `__builtin_is_pointer_interconvertible_with_class`, `__is_assignable_no_precondition_check`, `__is_bounded_array`, `__is_convertible`, `__is_corresponding_member`, `__is_nothrow_convertible`, `__is_pointer_interconvertible_with_class`, `__is_referenceable`, `__is_same_as`, `__is_trivially_copy_assignable`, `__is_unbounded_array`, `__is_valid_winrt_type`, `_is_win_class`, `__is_win_interface`, `__reference_binds_to_temporary`, `__reference_constructs_from_temporary`, and `__reference_converts_from_temporary`.
* The class `NewArrayExpr` adds a predicate `getArraySize()` to allow a more convenient way to access the static size of the array when the extent is missing.

View File

@@ -1,14 +0,0 @@
## 1.4.0
### New Features
* A `getTemplateClass` predicate was added to the `DeductionGuide` class to get the class template for which the deduction guide is a guide.
* An `isExplicit` predicate was added to the `Function` class that determines whether the function was declared as explicit.
* A `getExplicitExpr` predicate was added to the `Function` class that yields the constant boolean expression (if any) that conditionally determines whether the function is explicit.
* A `isDestroyingDeleteDeallocation` predicate was added to the `NewOrNewArrayExpr` and `DeleteOrDeleteArrayExpr` classes to indicate whether the deallocation function is a destroying delete.
### Minor Analysis Improvements
* The controlling expression of a `constexpr if` is now always recognized as an unevaluated expression.
* Improved performance of alias analysis of large function bodies. In rare cases, alerts that depend on alias analysis of large function bodies may be affected.
* A `UsingEnumDeclarationEntry` class has been added for C++ `using enum` declarations. As part of this, synthesized `UsingDeclarationEntry`s are no longer emitted for individual enumerators of the referenced enumeration.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.4.0
lastReleaseVersion: 1.2.0

View File

@@ -1,14 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*1]", "ReturnValue", "taint", "manual"]
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*2]", "ReturnValue", "taint", "manual"]
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*3]", "ReturnValue", "taint", "manual"]
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*4]", "ReturnValue", "taint", "manual"]
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*5]", "ReturnValue", "taint", "manual"]
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*6]", "ReturnValue", "taint", "manual"]
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*7]", "ReturnValue", "taint", "manual"]
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*8]", "ReturnValue", "taint", "manual"]

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 1.4.1-dev
version: 1.2.1-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -158,26 +158,6 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
*/
predicate isConsteval() { this.hasSpecifier("is_consteval") }
/**
* Holds if this function is declared to be `explicit`.
*/
predicate isExplicit() { this.hasSpecifier("explicit") }
/**
* Gets the constant expression that determines whether the function is explicit.
*
* For example, for the following code the result is the expression `sizeof(T) == 1`:
* ```
* template<typename T> struct C {
* explicit(sizeof(T) == 1)
* C(const T);
* };
* ```
*/
Expr getExplicitExpr() {
explicit_specifier_exprs(underlyingElement(this), unresolveElement(result))
}
/**
* Holds if this function is declared with `__attribute__((naked))` or
* `__declspec(naked)`.
@@ -918,11 +898,4 @@ class UserDefinedLiteral extends Function {
*/
class DeductionGuide extends Function {
DeductionGuide() { functions(underlyingElement(this), _, 8) }
/**
* Gets the class template for which this is a deduction guide.
*/
TemplateClass getTemplateClass() {
deduction_guide_for_class(underlyingElement(this), unresolveElement(result))
}
}

View File

@@ -156,7 +156,7 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl {
* A C++ `using` directive or `using` declaration.
*/
class UsingEntry extends Locatable, @using {
override Location getLocation() { usings(underlyingElement(this), _, result, _) }
override Location getLocation() { usings(underlyingElement(this), _, result) }
}
/**
@@ -166,13 +166,15 @@ class UsingEntry extends Locatable, @using {
* ```
*/
class UsingDeclarationEntry extends UsingEntry {
UsingDeclarationEntry() { usings(underlyingElement(this), _, _, 1) }
UsingDeclarationEntry() {
not exists(Namespace n | usings(underlyingElement(this), unresolveElement(n), _))
}
/**
* Gets the declaration that is referenced by this using declaration. For
* example, `std::string` in `using std::string`.
*/
Declaration getDeclaration() { usings(underlyingElement(this), unresolveElement(result), _, _) }
Declaration getDeclaration() { usings(underlyingElement(this), unresolveElement(result), _) }
override string toString() { result = "using " + this.getDeclaration().getDescription() }
}
@@ -184,36 +186,19 @@ class UsingDeclarationEntry extends UsingEntry {
* ```
*/
class UsingDirectiveEntry extends UsingEntry {
UsingDirectiveEntry() { usings(underlyingElement(this), _, _, 2) }
UsingDirectiveEntry() {
exists(Namespace n | usings(underlyingElement(this), unresolveElement(n), _))
}
/**
* Gets the namespace that is referenced by this using directive. For
* example, `std` in `using namespace std`.
*/
Namespace getNamespace() { usings(underlyingElement(this), unresolveElement(result), _, _) }
Namespace getNamespace() { usings(underlyingElement(this), unresolveElement(result), _) }
override string toString() { result = "using namespace " + this.getNamespace().getFriendlyName() }
}
/**
* A C++ `using enum` declaration. For example:
* ```
* enum class Foo { a, b };
* using enum Foo;
* ```
*/
class UsingEnumDeclarationEntry extends UsingEntry {
UsingEnumDeclarationEntry() { usings(underlyingElement(this), _, _, 3) }
/**
* Gets the enumeration that is referenced by this using directive. For
* example, `Foo` in `using enum Foo`.
*/
Enum getEnum() { usings(underlyingElement(this), unresolveElement(result), _, _) }
override string toString() { result = "using enum " + this.getEnum().getQualifiedName() }
}
/**
* Holds if `g` is an instance of `GlobalNamespace`. This predicate
* is used suppress a warning in `GlobalNamespace.getADeclaration()`

View File

@@ -146,7 +146,7 @@ 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, string model
string output, string kind, string provenance
) {
exists(string row |
sourceModel(row) and
@@ -160,20 +160,16 @@ predicate sourceModel(
row.splitAt(";", 6) = output and
row.splitAt(";", 7) = kind
) and
provenance = "manual" and
model = ""
provenance = "manual"
or
exists(QlBuiltins::ExtensionId madId |
Extensions::sourceModel(namespace, type, subtypes, name, signature, ext, output, kind,
provenance, madId) and
model = "MaD:" + madId.toString()
)
Extensions::sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance,
_)
}
/** 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, string model
string input, string kind, string provenance
) {
exists(string row |
sinkModel(row) and
@@ -187,14 +183,9 @@ predicate sinkModel(
row.splitAt(";", 6) = input and
row.splitAt(";", 7) = kind
) and
provenance = "manual" and
model = ""
provenance = "manual"
or
exists(QlBuiltins::ExtensionId madId |
Extensions::sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance,
madId) and
model = "MaD:" + madId.toString()
)
Extensions::sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance, _)
}
/**
@@ -204,7 +195,7 @@ predicate sinkModel(
*/
private predicate summaryModel0(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, string provenance, string model
string input, string output, string kind, string provenance
) {
exists(string row |
summaryModel(row) and
@@ -219,14 +210,10 @@ private predicate summaryModel0(
row.splitAt(";", 7) = output and
row.splitAt(";", 8) = kind
) and
provenance = "manual" and
model = ""
provenance = "manual"
or
exists(QlBuiltins::ExtensionId madId |
Extensions::summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind,
provenance, madId) and
model = "MaD:" + madId.toString()
)
Extensions::summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind,
provenance, _)
}
/**
@@ -247,20 +234,19 @@ private predicate expandInputAndOutput(
*/
predicate summaryModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, string provenance, string model
string input, string output, string kind, string provenance
) {
exists(string input0, string output0 |
summaryModel0(namespace, type, subtypes, name, signature, ext, input0, output0, kind,
provenance, model) and
summaryModel0(namespace, type, subtypes, name, signature, ext, input0, output0, kind, provenance) and
expandInputAndOutput(input0, input, output0, output,
[0 .. Private::getMaxElementContentIndirectionIndex() - 1])
)
}
private predicate relevantNamespace(string namespace) {
sourceModel(namespace, _, _, _, _, _, _, _, _, _) or
sinkModel(namespace, _, _, _, _, _, _, _, _, _) or
summaryModel(namespace, _, _, _, _, _, _, _, _, _, _)
sourceModel(namespace, _, _, _, _, _, _, _, _) or
sinkModel(namespace, _, _, _, _, _, _, _, _) or
summaryModel(namespace, _, _, _, _, _, _, _, _, _)
}
private predicate namespaceLink(string shortns, string longns) {
@@ -290,17 +276,17 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
part = "source" and
n =
strictcount(string subns, string type, boolean subtypes, string name, string signature,
string ext, string output, string provenance, string model |
string ext, string output, string provenance |
canonicalNamespaceLink(namespace, subns) and
sourceModel(subns, type, subtypes, name, signature, ext, output, kind, provenance, model)
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, string model |
string ext, string input, string provenance |
canonicalNamespaceLink(namespace, subns) and
sinkModel(subns, type, subtypes, name, signature, ext, input, kind, provenance, model)
sinkModel(subns, type, subtypes, name, signature, ext, input, kind, provenance)
)
or
part = "summary" and
@@ -308,7 +294,7 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
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, _)
summaryModel(subns, type, subtypes, name, signature, ext, input, output, kind, provenance)
)
)
}
@@ -317,9 +303,9 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
module CsvValidation {
private string getInvalidModelInput() {
exists(string pred, AccessPath input, string part |
sinkModel(_, _, _, _, _, _, input, _, _, _) and pred = "sink"
sinkModel(_, _, _, _, _, _, input, _, _) and pred = "sink"
or
summaryModel(_, _, _, _, _, _, input, _, _, _, _) and pred = "summary"
summaryModel(_, _, _, _, _, _, input, _, _, _) and pred = "summary"
|
(
invalidSpecComponent(input, part) and
@@ -336,9 +322,9 @@ module CsvValidation {
private string getInvalidModelOutput() {
exists(string pred, string output, string part |
sourceModel(_, _, _, _, _, _, output, _, _, _) and pred = "source"
sourceModel(_, _, _, _, _, _, output, _, _) and pred = "source"
or
summaryModel(_, _, _, _, _, _, _, output, _, _, _) and pred = "summary"
summaryModel(_, _, _, _, _, _, _, output, _, _) and pred = "summary"
|
invalidSpecComponent(output, part) and
not part = "" and
@@ -348,11 +334,11 @@ module CsvValidation {
}
private module KindValConfig implements SharedModelVal::KindValidationConfigSig {
predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _, _) }
predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) }
predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _, _) }
predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) }
predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _, _) }
predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) }
}
private module KindVal = SharedModelVal::KindValidation<KindValConfig>;
@@ -393,11 +379,11 @@ module CsvValidation {
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"
sourceModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "source"
or
sinkModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "sink"
sinkModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "sink"
or
summaryModel(namespace, type, _, name, signature, ext, _, _, _, _, _) and pred = "summary"
summaryModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "summary"
|
not namespace.regexpMatch("[a-zA-Z0-9_\\.:]*") and
result = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
@@ -429,23 +415,18 @@ module CsvValidation {
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, _, _, _, _, _)
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _) or
sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _) or
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _)
}
/** Gets the fully templated version of `f`. */
private Function getFullyTemplatedFunction(Function f) {
private Function getFullyTemplatedMemberFunction(Function f) {
not f.isFromUninstantiatedTemplate(_) and
(
exists(Class c, Class templateClass, int i |
c.isConstructedFrom(templateClass) and
f = c.getAMember(i) and
result = templateClass.getCanonicalMember(i)
)
or
not exists(f.getDeclaringType()) and
f.isConstructedFrom(result)
exists(Class c, Class templateClass, int i |
c.isConstructedFrom(templateClass) and
f = c.getAMember(i) and
result = templateClass.getCanonicalMember(i)
)
}
@@ -469,14 +450,14 @@ string getParameterTypeWithoutTemplateArguments(Function f, int n) {
*/
private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remaining) {
exists(Function templateFunction |
templateFunction = getFullyTemplatedFunction(f) and
templateFunction = getFullyTemplatedMemberFunction(f) and
remaining = templateFunction.getNumberOfTemplateArguments() and
result = getParameterTypeWithoutTemplateArguments(templateFunction, n)
)
or
exists(string mid, TemplateParameter tp, Function templateFunction |
mid = getTypeNameWithoutFunctionTemplates(f, n, remaining + 1) and
templateFunction = getFullyTemplatedFunction(f) and
templateFunction = getFullyTemplatedMemberFunction(f) and
tp = templateFunction.getTemplateArgument(remaining) and
result = mid.replaceAll(tp.getName(), "func:" + remaining.toString())
)
@@ -487,18 +468,12 @@ private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remain
* with `class:N` (where `N` is the index of the template).
*/
private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining) {
// If there is a declaring type then we start by expanding the function templates
exists(Class template |
f.getDeclaringType().isConstructedFrom(template) and
remaining = template.getNumberOfTemplateArguments() and
result = getTypeNameWithoutFunctionTemplates(f, n, 0)
)
or
// If there is no declaring type we're done after expanding the function templates
not exists(f.getDeclaringType()) and
remaining = 0 and
result = getTypeNameWithoutFunctionTemplates(f, n, 0)
or
exists(string mid, TemplateParameter tp, Class template |
mid = getTypeNameWithoutClassTemplates(f, n, remaining + 1) and
f.getDeclaringType().isConstructedFrom(template) and
@@ -581,6 +556,38 @@ private string getSignatureWithoutFunctionTemplateNames(
)
}
private string paramsStringPart(Function c, int i) {
not c.isFromUninstantiatedTemplate(_) and
(
i = -1 and result = "(" and exists(c)
or
exists(int n, string p | getParameterTypeName(c, n) = 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
}
/**
* Holds if `elementSpec(_, type, _, name, signature, _)` holds and
* - `typeArgs` represents the named template parameters supplied to `type`, and
@@ -729,17 +736,17 @@ private predicate elementSpecWithArguments0(
/**
* Holds if `elementSpec(namespace, type, subtypes, name, signature, _)` and
* `func`'s signature matches `signature`.
* `method`'s signature matches `signature`.
*
* `signature` may contain template parameter names that are bound by `type` and `name`.
*/
pragma[nomagic]
private predicate elementSpecMatchesSignature(
Function func, string namespace, string type, boolean subtypes, string name, string signature
Function method, string namespace, string type, boolean subtypes, string name, string signature
) {
elementSpec(namespace, pragma[only_bind_into](type), subtypes, pragma[only_bind_into](name),
pragma[only_bind_into](signature), _) and
signatureMatches(func, signature, type, name, 0)
signatureMatches(method, signature, type, name, 0)
}
/**
@@ -755,22 +762,13 @@ private predicate hasClassAndName(Class classWithMethod, Function method, string
)
}
bindingset[name]
pragma[inline_late]
private predicate funcHasQualifiedName(Function func, string namespace, string name) {
exists(string nameWithoutArgs |
parseAngles(name, nameWithoutArgs, _, "") and
func.hasQualifiedName(namespace, nameWithoutArgs)
)
}
/**
* Holds if `namedClass` is in namespace `namespace` and has
* name `type` (excluding any template parameters).
*/
bindingset[type, namespace]
pragma[inline_late]
private predicate classHasQualifiedName(Class namedClass, string namespace, string type) {
private predicate hasQualifiedName(Class namedClass, string namespace, string type) {
exists(string typeWithoutArgs |
parseAngles(type, typeWithoutArgs, _, "") and
namedClass.hasQualifiedName(namespace, typeWithoutArgs)
@@ -792,16 +790,15 @@ private Element interpretElement0(
string namespace, string type, boolean subtypes, string name, string signature
) {
(
// Non-member functions
elementSpec(namespace, type, subtypes, name, signature, _) and
subtypes = false and
type = "" and
(
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
or
signature = "" and
elementSpec(namespace, type, subtypes, name, "", _) and
funcHasQualifiedName(result, namespace, name)
// 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
@@ -814,7 +811,7 @@ private Element interpretElement0(
elementSpec(namespace, type, subtypes, name, "", _) and
hasClassAndName(classWithMethod, result, name)
) and
classHasQualifiedName(namedClass, namespace, type) and
hasQualifiedName(namedClass, namespace, type) and
(
// member declared in the named type or a subtype of it
subtypes = true and
@@ -870,9 +867,9 @@ private module Cached {
* model.
*/
cached
predicate sourceNode(DataFlow::Node node, string kind, string model) {
predicate sourceNode(DataFlow::Node node, string kind) {
exists(SourceSinkInterpretationInput::InterpretNode n |
isSourceNode(n, kind, model) and n.asNode() = node
isSourceNode(n, kind, _) and n.asNode() = node // TODO
)
}
@@ -881,57 +878,40 @@ private module Cached {
* model.
*/
cached
predicate sinkNode(DataFlow::Node node, string kind, string model) {
predicate sinkNode(DataFlow::Node node, string kind) {
exists(SourceSinkInterpretationInput::InterpretNode n |
isSinkNode(n, kind, model) and n.asNode() = node
isSinkNode(n, kind, _) and n.asNode() = node // TODO
)
}
}
import Cached
/**
* Holds if `node` is specified as a source with the given kind in a MaD flow
* model.
*/
predicate sourceNode(DataFlow::Node node, string kind) { sourceNode(node, kind, _) }
/**
* Holds if `node` is specified as a sink with the given kind in a MaD flow
* model.
*/
predicate sinkNode(DataFlow::Node node, string kind) { sinkNode(node, kind, _) }
private predicate interpretSummary(
Function f, string input, string output, string kind, string provenance, string model
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,
model) and
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, _, _, _, _, _) }
SummarizedCallableAdapter() { interpretSummary(this, _, _, _, _) }
private predicate relevantSummaryElementManual(
string input, string output, string kind, string model
) {
private predicate relevantSummaryElementManual(string input, string output, string kind) {
exists(Provenance provenance |
interpretSummary(this, input, output, kind, provenance, model) and
interpretSummary(this, input, output, kind, provenance) and
provenance.isManual()
)
}
private predicate relevantSummaryElementGenerated(
string input, string output, string kind, string model
) {
private predicate relevantSummaryElementGenerated(string input, string output, string kind) {
exists(Provenance provenance |
interpretSummary(this, input, output, kind, provenance, model) and
interpretSummary(this, input, output, kind, provenance) and
provenance.isGenerated()
)
}
@@ -940,16 +920,35 @@ private class SummarizedCallableAdapter extends SummarizedCallable {
string input, string output, boolean preservesValue, string model
) {
exists(string kind |
this.relevantSummaryElementManual(input, output, kind, model)
this.relevantSummaryElementManual(input, output, kind)
or
not this.relevantSummaryElementManual(_, _, _, _) and
this.relevantSummaryElementGenerated(input, output, kind, model)
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, _)
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

@@ -290,6 +290,14 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate sourceGrouping(Node source, string sourceGroup) {
any(Configuration config).sourceGrouping(source, sourceGroup)
}
predicate sinkGrouping(Node sink, string sinkGroup) {
any(Configuration config).sinkGrouping(sink, sinkGroup)
}
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}

View File

@@ -290,6 +290,14 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate sourceGrouping(Node source, string sourceGroup) {
any(Configuration config).sourceGrouping(source, sourceGroup)
}
predicate sinkGrouping(Node sink, string sinkGroup) {
any(Configuration config).sinkGrouping(sink, sinkGroup)
}
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}

View File

@@ -290,6 +290,14 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate sourceGrouping(Node source, string sourceGroup) {
any(Configuration config).sourceGrouping(source, sourceGroup)
}
predicate sinkGrouping(Node sink, string sinkGroup) {
any(Configuration config).sinkGrouping(sink, sinkGroup)
}
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}

View File

@@ -290,6 +290,14 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate sourceGrouping(Node source, string sourceGroup) {
any(Configuration config).sourceGrouping(source, sourceGroup)
}
predicate sinkGrouping(Node sink, string sinkGroup) {
any(Configuration config).sinkGrouping(sink, sinkGroup)
}
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}

View File

@@ -290,6 +290,14 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate sourceGrouping(Node source, string sourceGroup) {
any(Configuration config).sourceGrouping(source, sourceGroup)
}
predicate sinkGrouping(Node sink, string sinkGroup) {
any(Configuration config).sinkGrouping(sink, sinkGroup)
}
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}

View File

@@ -215,16 +215,19 @@ predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
predicate localMustFlowStep(Node node1, Node node2) { none() }
/** Gets the type of `n` used for type pruning. */
DataFlowType getNodeType(Node n) {
Type getNodeType(Node n) {
exists(n) and
result instanceof VoidType // stub implementation
}
/** Gets a string representation of a type returned by `getNodeType`. */
string ppReprType(Type t) { none() } // stub implementation
/**
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
* a node of type `t1` to a node of type `t2`.
*/
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
predicate compatibleTypes(Type t1, Type t2) {
t1 instanceof VoidType and t2 instanceof VoidType // stub implementation
}
@@ -236,15 +239,21 @@ class CastNode extends Node {
CastNode() { none() } // stub implementation
}
class DataFlowCallable extends Function { }
class DataFlowCallable extends Function {
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCallable c, string file, int startline, int startcolumn |
c.getLocation().hasLocationInfo(file, startline, startcolumn, _, _)
|
c order by file, startline, startcolumn
)
}
}
class DataFlowExpr = Expr;
final private class TypeFinal = Type;
class DataFlowType extends TypeFinal {
string toString() { result = "" }
}
class DataFlowType = Type;
/** A function call relevant for data flow. */
class DataFlowCall extends Expr instanceof Call {
@@ -260,12 +269,24 @@ class DataFlowCall extends Expr instanceof Call {
/** Gets the enclosing callable of this call. */
DataFlowCallable getEnclosingCallable() { result = this.getEnclosingFunction() }
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCall c, int startline, int startcolumn |
c.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
c order by startline, startcolumn
)
}
}
class NodeRegion instanceof Unit {
string toString() { result = "NodeRegion" }
predicate contains(Node n) { none() }
int totalOrder() { result = 1 }
}
predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call) { none() } // stub implementation

View File

@@ -112,8 +112,9 @@ module SourceSinkInterpretationInput implements
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance, model) and
e = interpretElement(namespace, type, subtypes, name, signature, ext)
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance) and
e = interpretElement(namespace, type, subtypes, name, signature, ext) and
model = "" // TODO
)
}
@@ -127,8 +128,9 @@ module SourceSinkInterpretationInput implements
exists(
string package, string type, boolean subtypes, string name, string signature, string ext
|
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance, model) and
e = interpretElement(package, type, subtypes, name, signature, ext)
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance) and
e = interpretElement(package, type, subtypes, name, signature, ext) and
model = "" // TODO
)
}

View File

@@ -383,37 +383,6 @@ class BuiltInOperationIsConvertibleTo extends BuiltInOperation, @isconvtoexpr {
override string getAPrimaryQlClass() { result = "BuiltInOperationIsConvertibleTo" }
}
/**
* A C++ `__is_convertible` built-in operation (used by some implementations
* of the `<type_traits>` header).
*
* Returns `true` if the first type can be converted to the second type.
* ```
* bool v = __is_convertible(MyType, OtherType);
* ```
*/
class BuiltInOperationIsConvertible extends BuiltInOperation, @isconvertible {
override string toString() { result = "__is_convertible" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsConvertible" }
}
/**
* A C++ `__is_nothrow_convertible` built-in operation (used by some implementations
* of the `<type_traits>` header).
*
* Returns `true` if the first type can be converted to the second type and the
* conversion operator has an empty exception specification.
* ```
* bool v = __is_nothrow_convertible(MyType, OtherType);
* ```
*/
class BuiltInOperationIsNothrowConvertible extends BuiltInOperation, @isnothrowconvertible {
override string toString() { result = "__is_nothrow_convertible" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowConvertible" }
}
/**
* A C++ `__is_empty` built-in operation (used by some implementations of the
* `<type_traits>` header).
@@ -678,7 +647,8 @@ class BuiltInOperationIsTriviallyAssignable extends BuiltInOperation, @istrivial
* The `__is_nothrow_assignable` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns true if there exists an assignment operator with an empty exception specification.
* Returns true if there exists a `C::operator =(const D& d) nothrow`
* assignment operator (i.e, with an empty exception specification).
* ```
* bool v = __is_nothrow_assignable(MyType1, MyType2);
* ```
@@ -693,7 +663,8 @@ class BuiltInOperationIsNothrowAssignable extends BuiltInOperation, @isnothrowas
* The `__is_assignable` built-in operation (used by some implementations
* of the `<type_traits>` header).
*
* Returns true if there exists an assignment operator.
* Returns true if there exists a `C::operator =(const D& d)` assignment
* operator.
* ```
* bool v = __is_assignable(MyType1, MyType2);
* ```
@@ -704,25 +675,6 @@ class BuiltInOperationIsAssignable extends BuiltInOperation, @isassignable {
override string getAPrimaryQlClass() { result = "BuiltInOperationIsAssignable" }
}
/**
* The `__is_assignable_no_precondition_check` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns true if there exists an assignment operator.
* ```
* bool v = __is_assignable_no_precondition_check(MyType1, MyType2);
* ```
*/
class BuiltInOperationIsAssignableNoPreconditionCheck extends BuiltInOperation,
@isassignablenopreconditioncheck
{
override string toString() { result = "__is_assignable_no_precondition_check" }
override string getAPrimaryQlClass() {
result = "BuiltInOperationIsAssignableNoPreconditionCheck"
}
}
/**
* The `__is_standard_layout` built-in operation (used by some implementations
* of the `<type_traits>` header).
@@ -756,20 +708,6 @@ class BuiltInOperationIsTriviallyCopyable extends BuiltInOperation, @istrivially
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyCopyable" }
}
/**
* The `__is_trivially_copy_assignable` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns `true` if instances of this type can be copied using a trivial
* copy operator.
*/
class BuiltInOperationIsTriviallyCopyAssignable extends BuiltInOperation, @istriviallycopyassignable
{
override string toString() { result = "__is_trivially_copy_assignable" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyCopyAssignable" }
}
/**
* The `__is_literal_type` built-in operation (used by some implementations of
* the `<type_traits>` header).
@@ -1124,24 +1062,6 @@ class BuiltInOperationIsSame extends BuiltInOperation, @issame {
override string getAPrimaryQlClass() { result = "BuiltInOperationIsSame" }
}
/**
* A C++ `__is_same_as` built-in operation (used by some implementations of the
* `<type_traits>` header).
*
* Returns `true` if two types are the same.
* ```
* template<typename _Tp, typename _Up>
* struct is_same
* : public integral_constant<bool, __is_same_as(_Tp, _Up)>
* { };
* ```
*/
class BuiltInOperationIsSameAs extends BuiltInOperation, @issameas {
override string toString() { result = "__is_same_as" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsSameAs" }
}
/**
* A C++ `__is_function` built-in operation (used by some implementations of the
* `<type_traits>` header).
@@ -1200,87 +1120,6 @@ class BuiltInOperationIsPointerInterconvertibleBaseOf extends BuiltInOperation,
}
}
/**
* A C++ `__is_pointer_interconvertible_with_class` built-in operation (used
* by some implementations of the `<type_traits>` header).
*
* Returns `true` if a member pointer is pointer-interconvertible with a
* class type.
* ```
* template<typename _Tp, typename _Up>
* constexpr bool is_pointer_interconvertible_with_class(_Up _Tp::*mp) noexcept
* = __is_pointer_interconvertible_with_class(_Tp, mp);
* ```
*/
class BuiltInOperationIsPointerInterconvertibleWithClass extends BuiltInOperation,
@ispointerinterconvertiblewithclass
{
override string toString() { result = "__is_pointer_interconvertible_with_class" }
override string getAPrimaryQlClass() {
result = "BuiltInOperationIsPointerInterconvertibleWithClass"
}
}
/**
* A C++ `__builtin_is_pointer_interconvertible_with_class` built-in operation (used
* by some implementations of the `<type_traits>` header).
*
* Returns `true` if a member pointer is pointer-interconvertible with a class type.
* ```
* template<typename _Tp, typename _Up>
* constexpr bool is_pointer_interconvertible_with_class(_Up _Tp::*mp) noexcept
* = __builtin_is_pointer_interconvertible_with_class(mp);
* ```
*/
class BuiltInOperationBuiltInIsPointerInterconvertible extends BuiltInOperation,
@builtinispointerinterconvertiblewithclass
{
override string toString() { result = "__builtin_is_pointer_interconvertible_with_class" }
override string getAPrimaryQlClass() {
result = "BuiltInOperationBuiltInIsPointerInterconvertible"
}
}
/**
* A C++ `__is_corresponding_member` built-in operation (used
* by some implementations of the `<type_traits>` header).
*
* Returns `true` if two member pointers refer to corresponding
* members in the initial sequences of two class types.
* ```
* template<typename _Tp1, typename _Tp2, typename _Up1, typename _Up2>
* constexpr bool is_corresponding_member(_Up1 _Tp1::*mp1, _Up2 _Tp2::*mp2 ) noexcept
* = __is_corresponding_member(_Tp1, _Tp2, mp1, mp2);
* ```
*/
class BuiltInOperationIsCorrespondingMember extends BuiltInOperation, @iscorrespondingmember {
override string toString() { result = "__is_corresponding_member" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsCorrespondingMember" }
}
/**
* A C++ `__builtin_is_corresponding_member` built-in operation (used
* by some implementations of the `<type_traits>` header).
*
* Returns `true` if two member pointers refer to corresponding
* members in the initial sequences of two class types.
* ```
* template<typename _Tp1, typename _Tp2, typename _Up1, typename _Up2>
* constexpr bool is_corresponding_member(_Up1 _Tp1::*mp1, _Up2 _Tp2::*mp2 ) noexcept
* = __builtin_is_corresponding_member(mp1, mp2);
* ```
*/
class BuiltInOperationBuiltInIsCorrespondingMember extends BuiltInOperation,
@builtiniscorrespondingmember
{
override string toString() { result = "__builtin_is_corresponding_member" }
override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInIsCorrespondingMember" }
}
/**
* A C++ `__is_array` built-in operation (used by some implementations of the
* `<type_traits>` header).
@@ -1299,42 +1138,6 @@ class BuiltInOperationIsArray extends BuiltInOperation, @isarray {
override string getAPrimaryQlClass() { result = "BuiltInOperationIsArray" }
}
/**
* A C++ `__is_bounded_array` built-in operation (used by some implementations
* of the `<type_traits>` header).
*
* Returns `true` if a type is a bounded array type.
* ```
* template<typename _Tp>
* struct is_bounded_array
* : public integral_constant<bool, __is_bounded_array(_Tp)>
* { };
* ```
*/
class BuiltInOperationIsBoundedArray extends BuiltInOperation, @isboundedarray {
override string toString() { result = "__is_bounded_array" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsBoundedArray" }
}
/**
* A C++ `__is_unbounded_array` built-in operation (used by some implementations
* of the `<type_traits>` header).
*
* Returns `true` if a type is an unbounded array type.
* ```
* template<typename _Tp>
* struct is_bounded_array
* : public integral_constant<bool, __is_unbounded_array(_Tp)>
* { };
* ```
*/
class BuiltInOperationIsUnboundedArray extends BuiltInOperation, @isunboundedarray {
override string toString() { result = "__is_unbounded_array" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsUnboundedArray" }
}
/**
* A C++ `__array_rank` built-in operation (used by some implementations of the
* `<type_traits>` header).
@@ -1751,10 +1554,10 @@ class BuiltInBitCast extends BuiltInOperation, @builtinbitcast {
*
* Returns `true` if a type is a trivial type.
* ```
* template<typename _Tp>
* struct is_trivial
* : public integral_constant<bool, __is_trivial(_Tp)>
* {};
* template<typename _Tp>
* struct is_trivial
* : public integral_constant<bool, __is_trivial(_Tp)>
* {};
* ```
*/
class BuiltInIsTrivial extends BuiltInOperation, @istrivialexpr {
@@ -1762,126 +1565,3 @@ class BuiltInIsTrivial extends BuiltInOperation, @istrivialexpr {
override string getAPrimaryQlClass() { result = "BuiltInIsTrivial" }
}
/**
* A C++ `__reference_constructs_from_temporary` built-in operation
* (used by some implementations of the `<type_traits>` header).
*
* Returns `true` if a reference type `_Tp` is bound to an expression of
* type `_Up` in direct-initialization, and a temporary object is bound.
* ```
* template<typename _Tp, typename _Up>
* struct reference_constructs_from_temporary
* : public integral_constant<bool, __reference_constructs_from_temporary(_Tp, _Up)>
* {};
* ```
*/
class BuiltInOperationReferenceConstructsFromTemporary extends BuiltInOperation,
@referenceconstructsfromtemporary
{
override string toString() { result = "__reference_constructs_from_temporary" }
override string getAPrimaryQlClass() {
result = "BuiltInOperationReferenceConstructsFromTemporary"
}
}
/**
* A C++ `__reference_converts_from_temporary` built-in operation
* (used by some implementations of the `<type_traits>` header).
*
* Returns `true` if a reference type `_Tp` is bound to an expression of
* type `_Up` in copy-initialization, and a temporary object is bound.
* ```
* template<typename _Tp, typename _Up>
* struct reference_converts_from_temporary
* : public integral_constant<bool, __reference_converts_from_temporary(_Tp, _Up)>
* {};
* ```
*/
class BuiltInOperationReferenceCovertsFromTemporary extends BuiltInOperation,
@referenceconvertsfromtemporary
{
override string toString() { result = "__reference_converts_from_temporary" }
override string getAPrimaryQlClass() { result = "BuiltInOperationReferenceCovertsFromTemporary" }
}
/**
* A C++ `__reference_binds_to_temporary` built-in operation (used by some
* implementations of the `<tuple>` header).
*
* Returns `true` if a reference of type `Type1` is bound to an expression of
* type `Type1`, and a temporary object is bound.
* ```
* __reference_binds_to_temporary(Type1, Type2)
*/
class BuiltInOperationReferenceBindsToTemporary extends BuiltInOperation, @referencebindstotemporary
{
override string toString() { result = "__reference_binds_to_temporary" }
override string getAPrimaryQlClass() { result = "BuiltInOperationReferenceBindsToTemporary" }
}
/**
* A C++ `__builtin_has_attribute` built-in operation.
*
* Returns `true` if a type or expression has been declared with the
* specified attribute.
* ```
* __attribute__ ((aligned(8))) int v;
* bool has_attribute = __builtin_has_attribute(v, aligned);
* ```
*/
class BuiltInOperationHasAttribute extends BuiltInOperation, @builtinhasattribute {
override string toString() { result = "__builtin_has_attribute" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasAttribute" }
}
/**
* A C++ `__is_referenceable` built-in operation.
*
* Returns `true` if a type can be referenced.
* ```
* bool is_referenceable = __is_referenceable(int);
* ```
*/
class BuiltInOperationIsReferenceable extends BuiltInOperation, @isreferenceable {
override string toString() { result = "__is_referenceable" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsReferenceable" }
}
/**
* The `__is_valid_winrt_type` built-in operation. This is a Microsoft extension.
*
* Returns `true` if the type is a valid WinRT type.
*/
class BuiltInOperationIsValidWinRtType extends BuiltInOperation, @isvalidwinrttype {
override string toString() { result = "__is_valid_winrt_type" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsValidWinRtType" }
}
/**
* The `__is_win_class` built-in operation. This is a Microsoft extension.
*
* Returns `true` if the class is a ref class.
*/
class BuiltInOperationIsWinClass extends BuiltInOperation, @iswinclass {
override string toString() { result = "__is_win_class" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsWinClass" }
}
/**
* The `__is_win_class` built-in operation. This is a Microsoft extension.
*
* Returns `true` if the class is an interface class.
*/
class BuiltInOperationIsWinInterface extends BuiltInOperation, @iswininterface {
override string toString() { result = "__is_win_interface" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsWinInterface" }
}

View File

@@ -307,10 +307,6 @@ class Expr extends StmtParent, @expr {
)
or
exists(Decltype d | d.getExpr() = this.getParentWithConversions*())
or
exists(ConstexprIfStmt constIf |
constIf.getControllingExpr() = this.getParentWithConversions*()
)
}
/**
@@ -859,16 +855,6 @@ class NewOrNewArrayExpr extends Expr, @any_new_expr {
)
}
/**
* Holds if the deallocation function is a destroying delete.
*/
predicate isDestroyingDeleteDeallocation() {
exists(int form |
expr_deallocator(underlyingElement(this), _, form) and
form.bitAnd(4) != 0 // Bit two is the "destroying delete" bit
)
}
/**
* Gets the type that is being allocated.
*
@@ -963,16 +949,6 @@ class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr {
* gives nothing, as the 10 is considered part of the type.
*/
Expr getExtent() { result = this.getChild(2) }
/**
* Gets the number of elements in the array, if available.
*
* For example, `new int[]{1,2,3}` has an array size of 3.
*/
int getArraySize() {
result = this.getAllocatedType().(ArrayType).getArraySize() or
result = this.getInitializer().(ArrayAggregateLiteral).getArraySize()
}
}
private class TDeleteOrDeleteArrayExpr = @delete_expr or @delete_array_expr;
@@ -1039,16 +1015,6 @@ class DeleteOrDeleteArrayExpr extends Expr, TDeleteOrDeleteArrayExpr {
)
}
/**
* Holds if the deallocation function is a destroying delete.
*/
predicate isDestroyingDeleteDeallocation() {
exists(int form |
expr_deallocator(underlyingElement(this), _, form) and
form.bitAnd(4) != 0 // Bit two is the "destroying delete" bit
)
}
/**
* Gets the object or array being deleted.
*/

View File

@@ -290,6 +290,14 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate sourceGrouping(Node source, string sourceGroup) {
any(Configuration config).sourceGrouping(source, sourceGroup)
}
predicate sinkGrouping(Node sink, string sinkGroup) {
any(Configuration config).sinkGrouping(sink, sinkGroup)
}
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}

View File

@@ -290,6 +290,14 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate sourceGrouping(Node source, string sourceGroup) {
any(Configuration config).sourceGrouping(source, sourceGroup)
}
predicate sinkGrouping(Node sink, string sinkGroup) {
any(Configuration config).sinkGrouping(sink, sinkGroup)
}
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}

View File

@@ -290,6 +290,14 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate sourceGrouping(Node source, string sourceGroup) {
any(Configuration config).sourceGrouping(source, sourceGroup)
}
predicate sinkGrouping(Node sink, string sinkGroup) {
any(Configuration config).sinkGrouping(sink, sinkGroup)
}
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}

View File

@@ -290,6 +290,14 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate sourceGrouping(Node source, string sourceGroup) {
any(Configuration config).sourceGrouping(source, sourceGroup)
}
predicate sinkGrouping(Node sink, string sinkGroup) {
any(Configuration config).sinkGrouping(sink, sinkGroup)
}
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}

View File

@@ -11,7 +11,6 @@ private import Node0ToString
private import ModelUtil
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as IO
private import semmle.code.cpp.models.interfaces.DataFlow as DF
private import semmle.code.cpp.dataflow.ExternalFlow as External
cached
private module Cached {
@@ -994,6 +993,9 @@ DataFlowType getNodeType(Node n) {
result instanceof VoidType // stub implementation
}
/** Gets a string representation of a type returned by `getNodeType`. */
string ppReprType(DataFlowType t) { none() } // stub implementation
/**
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
* a node of type `t1` to a node of type `t2`.
@@ -1058,6 +1060,16 @@ class DataFlowCallable extends TDataFlowCallable {
result = this.asSummarizedCallable() or // SummarizedCallable = Function (in CPP)
result = this.asSourceCallable()
}
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCallable c, string file, int startline, int startcolumn |
c.getLocation().hasLocationInfo(file, startline, startcolumn, _, _)
|
c order by file, startline, startcolumn
)
}
}
/**
@@ -1094,11 +1106,7 @@ class SummarizedCallable extends DataFlowCallable, TSummarizedCallable {
class DataFlowExpr = Expr;
final private class TypeFinal = Type;
class DataFlowType extends TypeFinal {
string toString() { result = "" }
}
class DataFlowType = Type;
cached
private newtype TDataFlowCall =
@@ -1159,6 +1167,16 @@ class DataFlowCall extends TDataFlowCall {
* Gets the location of this call.
*/
Location getLocation() { none() }
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCall c, int startline, int startcolumn |
c.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
c order by startline, startcolumn
)
}
}
/**
@@ -1251,6 +1269,15 @@ module IsUnreachableInCall {
string toString() { result = "NodeRegion" }
predicate contains(Node n) { this = n.getBasicBlock() }
int totalOrder() {
this =
rank[result](IRBlock b, int startline, int startcolumn |
b.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
b order by startline, startcolumn
)
}
}
predicate isUnreachableInCall(NodeRegion block, DataFlowCall call) {
@@ -1335,9 +1362,9 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
/** Extra data-flow steps needed for lambda flow analysis. */
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
predicate knownSourceModel(Node source, string model) { External::sourceNode(source, _, model) }
predicate knownSourceModel(Node source, string model) { none() }
predicate knownSinkModel(Node sink, string model) { External::sinkNode(sink, _, model) }
predicate knownSinkModel(Node sink, string model) { none() }
/**
* Holds if flow is allowed to pass from parameter `p` and back to itself as a

View File

@@ -104,7 +104,7 @@ predicate hasRawIndirectInstruction(Instruction instr, int indirectionIndex) {
cached
private newtype TDefImpl =
TDefAddressImpl(BaseSourceVariable v) or
TDefAddressImpl(BaseIRVariable v) or
TDirectDefImpl(Operand address, int indirectionIndex) {
isDef(_, _, address, _, _, indirectionIndex)
} or
@@ -325,9 +325,9 @@ private Instruction getInitializationTargetAddress(IRVariable v) {
)
}
/** An initial definition of an SSA variable address. */
abstract private class DefAddressImpl extends DefImpl, TDefAddressImpl {
BaseSourceVariable v;
/** An initial definition of an `IRVariable`'s address. */
private class DefAddressImpl extends DefImpl, TDefAddressImpl {
BaseIRVariable v;
DefAddressImpl() {
this = TDefAddressImpl(v) and
@@ -342,19 +342,6 @@ abstract private class DefAddressImpl extends DefImpl, TDefAddressImpl {
final override Node0Impl getValue() { none() }
override Cpp::Location getLocation() { result = v.getLocation() }
final override SourceVariable getSourceVariable() {
result.getBaseVariable() = v and
result.getIndirection() = 0
}
final override BaseSourceVariable getBaseSourceVariable() { result = v }
}
private class DefVariableAddressImpl extends DefAddressImpl {
override BaseIRVariable v;
final override predicate hasIndexInBlock(IRBlock block, int index) {
exists(IRVariable var | var = v.getIRVariable() |
block.getInstruction(index) = getInitializationTargetAddress(var)
@@ -366,14 +353,15 @@ private class DefVariableAddressImpl extends DefAddressImpl {
index = 0
)
}
}
private class DefCallAddressImpl extends DefAddressImpl {
override BaseCallVariable v;
override Cpp::Location getLocation() { result = v.getIRVariable().getLocation() }
final override predicate hasIndexInBlock(IRBlock block, int index) {
block.getInstruction(index) = v.getCallInstruction()
final override SourceVariable getSourceVariable() {
result.getBaseVariable() = v and
result.getIndirection() = 0
}
final override BaseSourceVariable getBaseSourceVariable() { result = v }
}
private class DirectDef extends DefImpl, TDirectDefImpl {

View File

@@ -40,8 +40,7 @@ predicate ignoreInstruction(Instruction instr) {
instr instanceof AliasedDefinitionInstruction or
instr instanceof AliasedUseInstruction or
instr instanceof InitializeNonLocalInstruction or
instr instanceof ReturnIndirectionInstruction or
instr instanceof UninitializedGroupInstruction
instr instanceof ReturnIndirectionInstruction
)
}

View File

@@ -13,8 +13,7 @@ private newtype TMemoryAccessKind =
TPhiMemoryAccess() or
TUnmodeledMemoryAccess() or
TChiTotalMemoryAccess() or
TChiPartialMemoryAccess() or
TGroupedMemoryAccess()
TChiPartialMemoryAccess()
/**
* Describes the set of memory locations memory accessed by a memory operand or
@@ -100,11 +99,3 @@ class ChiTotalMemoryAccess extends MemoryAccessKind, TChiTotalMemoryAccess {
class ChiPartialMemoryAccess extends MemoryAccessKind, TChiPartialMemoryAccess {
override string toString() { result = "chi(partial)" }
}
/**
* The result of an `UninitializedGroup` instruction, which initializes a set of
* allocations that are each assigned the same virtual variable.
*/
class GroupedMemoryAccess extends MemoryAccessKind, TGroupedMemoryAccess {
override string toString() { result = "group" }
}

View File

@@ -89,7 +89,6 @@ private newtype TOpcode =
TSizedBufferMayWriteSideEffect() or
TInitializeDynamicAllocation() or
TChi() or
TUninitializedGroup() or
TInlineAsm() or
TUnreached() or
TNewObj()
@@ -1238,17 +1237,6 @@ module Opcode {
}
}
/**
* The `Opcode` for a `UninitializedGroup`.
*
* See the `UninitializedGroupInstruction` documentation for more details.
*/
class UninitializedGroup extends Opcode, TUninitializedGroup {
final override string toString() { result = "UninitializedGroup" }
override GroupedMemoryAccess getWriteMemoryAccess() { any() }
}
/**
* The `Opcode` for an `InlineAsmInstruction`.
*

View File

@@ -2142,47 +2142,6 @@ class ChiInstruction extends Instruction {
final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) }
}
/**
* An instruction that initializes a set of allocations that are each assigned
* the same "virtual variable".
*
* As an example, consider the following snippet:
* ```
* int a;
* int b;
* int* p;
* if(b) {
* p = &a;
* } else {
* p = &b;
* }
* *p = 5;
* int x = a;
* ```
*
* Since both the address of `a` and `b` reach `p` at `*p = 5` the IR alias
* analysis will create a region that contains both `a` and `b`. The region
* containing both `a` and `b` are initialized by an `UninitializedGroup`
* instruction in the entry block of the enclosing function.
*/
class UninitializedGroupInstruction extends Instruction {
UninitializedGroupInstruction() { this.getOpcode() instanceof Opcode::UninitializedGroup }
/**
* Gets an `IRVariable` whose memory is initialized by this instruction, if any.
* Note: Allocations that are not represented as `IRVariable`s (such as
* dynamic allocations) are not returned by this predicate even if this
* instruction initializes such memory.
*/
final IRVariable getAnIRVariable() {
result = Construction::getAnUninitializedGroupVariable(this)
}
final override string getImmediateString() {
result = strictconcat(this.getAnIRVariable().toString(), ",")
}
}
/**
* An instruction representing unreachable code.
*

View File

@@ -106,7 +106,8 @@ private predicate operandEscapesDomain(Operand operand) {
not isArgumentForParameter(_, operand, _) and
not isOnlyEscapesViaReturnArgument(operand) and
not operand.getUse() instanceof ReturnValueInstruction and
not operand.getUse() instanceof ReturnIndirectionInstruction
not operand.getUse() instanceof ReturnIndirectionInstruction and
not operand instanceof PhiInputOperand
}
/**
@@ -190,11 +191,6 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset, Instr
// A copy propagates the source value.
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
)
or
operand = instr.(PhiInstruction).getAnInputOperand() and
// Using `unknown` ensures termination since we cannot keep incrementing a bit offset
// through the back edge of a loop (or through recursion).
bitOffset = Ints::unknown()
}
private predicate operandEscapesNonReturn(Operand operand) {
@@ -216,6 +212,9 @@ private predicate operandEscapesNonReturn(Operand operand) {
or
isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse())
or
operand instanceof PhiInputOperand and
resultEscapesNonReturn(operand.getUse())
or
operandEscapesDomain(operand)
}
@@ -237,6 +236,9 @@ private predicate operandMayReachReturn(Operand operand) {
operand.getUse() instanceof ReturnValueInstruction
or
isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse())
or
operand instanceof PhiInputOperand and
resultMayReachReturn(operand.getUse())
}
private predicate operandReturned(Operand operand, IntValue bitOffset) {
@@ -338,56 +340,6 @@ private predicate resultEscapesNonReturn(Instruction instr) {
not instr.isResultModeled()
}
/** Holds if `operand` may (transitively) flow to an `AddressOperand`. */
private predicate consumedAsAddressOperand(Operand operand) {
operand instanceof AddressOperand
or
exists(Operand address |
consumedAsAddressOperand(address) and
operandIsPropagated(operand, _, address.getDef())
)
}
/**
* Holds if `operand` may originate from a base instruction of an allocation,
* and that operand may transitively flow to an `AddressOperand`.
*/
private predicate propagatedFromAllocationBase(Operand operand, Configuration::Allocation allocation) {
consumedAsAddressOperand(operand) and
(
not exists(Configuration::getOldAllocation(allocation)) and
operand.getDef() = allocation.getABaseInstruction()
or
exists(Operand address |
operandIsPropagated(address, _, operand.getDef()) and
propagatedFromAllocationBase(address, allocation)
)
)
}
private predicate propagatedFromNonAllocationBase(Operand operand) {
exists(Instruction def |
def = operand.getDef() and
not operandIsPropagated(_, _, def) and
not def = any(Configuration::Allocation allocation).getABaseInstruction()
)
or
exists(Operand address |
operandIsPropagated(address, _, operand.getDef()) and
propagatedFromNonAllocationBase(address)
)
}
/**
* Holds if we cannot see all producers of an operand for which allocation also flows into.
*/
private predicate operandConsumesEscaped(Configuration::Allocation allocation) {
exists(AddressOperand address |
propagatedFromAllocationBase(address, allocation) and
propagatedFromNonAllocationBase(address)
)
}
/**
* Holds if the address of `allocation` escapes outside the domain of the analysis. This can occur
* either because the allocation's address is taken within the function and escapes, or because the
@@ -396,14 +348,12 @@ private predicate operandConsumesEscaped(Configuration::Allocation allocation) {
predicate allocationEscapes(Configuration::Allocation allocation) {
allocation.alwaysEscapes()
or
exists(IREscapeAnalysisConfiguration config | config.useSoundEscapeAnalysis() |
resultEscapesNonReturn(allocation.getABaseInstruction())
or
operandConsumesEscaped(allocation)
exists(IREscapeAnalysisConfiguration config |
config.useSoundEscapeAnalysis() and resultEscapesNonReturn(allocation.getABaseInstruction())
)
or
Configuration::phaseNeedsSoundEscapeAnalysis() and
(resultEscapesNonReturn(allocation.getABaseInstruction()) or operandConsumesEscaped(allocation))
resultEscapesNonReturn(allocation.getABaseInstruction())
}
/**

View File

@@ -101,8 +101,6 @@ class IndirectParameterAllocation extends Allocation, TIndirectParameterAllocati
final override predicate isAlwaysAllocatedOnStack() { none() }
final override predicate alwaysEscapes() { none() }
final IRAutomaticVariable getIRVariable() { result = var }
}
class DynamicAllocation extends Allocation, TDynamicAllocation {
@@ -146,8 +144,3 @@ class DynamicAllocation extends Allocation, TDynamicAllocation {
}
predicate phaseNeedsSoundEscapeAnalysis() { none() }
UnaliasedSsa::Allocation getOldAllocation(VariableAllocation allocation) {
UnaliasedSsa::canReuseSsaForVariable(allocation.getIRVariable()) and
result = allocation.getIRVariable()
}

View File

@@ -7,8 +7,7 @@ private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConst
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
private import semmle.code.cpp.ir.internal.IntegerInterval as Interval
private import semmle.code.cpp.ir.implementation.internal.OperandTag
import AliasConfiguration
private import codeql.util.Boolean
private import AliasConfiguration
private class IntValue = Ints::IntValue;
@@ -17,196 +16,49 @@ private predicate isIndirectOrBufferMemoryAccess(MemoryAccessKind kind) {
kind instanceof BufferMemoryAccess
}
private predicate hasMemoryAccess(
AddressOperand addrOperand, Allocation var, IntValue startBitOffset, boolean grouped
) {
addressOperandAllocationAndOffset(addrOperand, var, startBitOffset) and
if strictcount(Allocation alloc | addressOperandAllocationAndOffset(addrOperand, alloc, _)) > 1
then grouped = true
else grouped = false
}
private predicate hasResultMemoryAccess(
AddressOperand address, Instruction instr, Allocation var, IRType type,
Language::LanguageType languageType, IntValue startBitOffset, IntValue endBitOffset,
boolean isMayAccess, boolean grouped
Instruction instr, Allocation var, IRType type, Language::LanguageType languageType,
IntValue startBitOffset, IntValue endBitOffset, boolean isMayAccess
) {
address = instr.getResultAddressOperand() and
hasMemoryAccess(address, var, startBitOffset, grouped) and
languageType = instr.getResultLanguageType() and
type = languageType.getIRType() and
isIndirectOrBufferMemoryAccess(instr.getResultMemoryAccess()) and
(if instr.hasResultMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and
if exists(type.getByteSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
else endBitOffset = Ints::unknown()
exists(AddressOperand addrOperand |
addrOperand = instr.getResultAddressOperand() and
addressOperandAllocationAndOffset(addrOperand, var, startBitOffset) and
languageType = instr.getResultLanguageType() and
type = languageType.getIRType() and
isIndirectOrBufferMemoryAccess(instr.getResultMemoryAccess()) and
(if instr.hasResultMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and
if exists(type.getByteSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
else endBitOffset = Ints::unknown()
)
}
private predicate hasOperandMemoryAccess(
AddressOperand address, MemoryOperand operand, Allocation var, IRType type,
Language::LanguageType languageType, IntValue startBitOffset, IntValue endBitOffset,
boolean isMayAccess, boolean grouped
MemoryOperand operand, Allocation var, IRType type, Language::LanguageType languageType,
IntValue startBitOffset, IntValue endBitOffset, boolean isMayAccess
) {
address = operand.getAddressOperand() and
hasMemoryAccess(address, var, startBitOffset, grouped) and
languageType = operand.getLanguageType() and
type = languageType.getIRType() and
isIndirectOrBufferMemoryAccess(operand.getMemoryAccess()) and
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
if exists(type.getByteSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
else endBitOffset = Ints::unknown()
}
private Allocation getAnAllocation(AddressOperand address) {
hasResultMemoryAccess(address, _, result, _, _, _, _, _, true) or
hasOperandMemoryAccess(address, _, result, _, _, _, _, _, true)
}
private module AllocationSet0 =
QlBuiltins::InternSets<AddressOperand, Allocation, getAnAllocation/1>;
/**
* A set of allocations containing at least 2 elements.
*/
private class NonSingletonSets extends AllocationSet0::Set {
NonSingletonSets() { strictcount(Allocation var | this.contains(var)) > 1 }
/** Gets an allocation from this set. */
Allocation getAnAllocation() { this.contains(result) }
/** Gets the string representation of this set. */
string toString() { result = "{" + strictconcat(this.getAnAllocation().toString(), ", ") + "}" }
}
/** Holds the instersection of `s1` and `s2` is non-empty. */
private predicate hasOverlappingElement(NonSingletonSets s1, NonSingletonSets s2) {
exists(Allocation var |
s1.contains(var) and
s2.contains(var)
exists(AddressOperand addrOperand |
addrOperand = operand.getAddressOperand() and
addressOperandAllocationAndOffset(addrOperand, var, startBitOffset) and
languageType = operand.getLanguageType() and
type = languageType.getIRType() and
isIndirectOrBufferMemoryAccess(operand.getMemoryAccess()) and
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
if exists(type.getByteSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
else endBitOffset = Ints::unknown()
)
}
private module AllocationSet =
QlBuiltins::EquivalenceRelation<NonSingletonSets, hasOverlappingElement/2>;
/**
* Holds if `var` is created by the AST element `e`. Furthermore, the value `d`
* represents which branch of the `Allocation` type `var` is from.
*/
private predicate allocationAst(Allocation var, @element e, int d) {
var.(VariableAllocation).getIRVariable().getAst() = e and d = 0
or
var.(IndirectParameterAllocation).getIRVariable().getAst() = e and d = 1
or
var.(DynamicAllocation).getABaseInstruction().getAst() = e and d = 2
}
/** Holds if `x = y` and `x` is an AST element that creates an `Allocation`. */
private predicate id(@element x, @element y) {
allocationAst(_, x, _) and
x = y
}
private predicate idOf(@element x, int y) = equivalenceRelation(id/2)(x, y)
/** Gets a unique integer representation of `var`. */
private int getUniqueAllocationId(Allocation var) {
exists(int r, @element e, int d |
allocationAst(var, e, d) and
idOf(e, r) and
result = 3 * r + d
)
}
/**
* An equivalence class of a set of allocations.
*
* Any `VariableGroup` will be completely disjunct from any other
* `VariableGroup`.
*/
class VariableGroup extends AllocationSet::EquivalenceClass {
/** Gets the location of this set. */
final Location getLocation() { result = this.getIRFunction().getLocation() }
/** Gets the enclosing `IRFunction` of this set. */
final IRFunction getIRFunction() {
result = unique( | | this.getAnAllocation().getEnclosingIRFunction())
}
/** Gets the type of elements contained in this set. */
final Language::LanguageType getType() {
strictcount(Language::LanguageType langType |
exists(Allocation var | var = this.getAnAllocation() |
hasResultMemoryAccess(_, _, var, _, langType, _, _, _, true) or
hasOperandMemoryAccess(_, _, var, _, langType, _, _, _, true)
)
) = 1 and
exists(Allocation var | var = this.getAnAllocation() |
hasResultMemoryAccess(_, _, var, _, result, _, _, _, true) or
hasOperandMemoryAccess(_, _, var, _, result, _, _, _, true)
)
or
strictcount(Language::LanguageType langType |
exists(Allocation var | var = this.getAnAllocation() |
hasResultMemoryAccess(_, _, var, _, langType, _, _, _, true) or
hasOperandMemoryAccess(_, _, var, _, langType, _, _, _, true)
)
) > 1 and
result = any(IRUnknownType type).getCanonicalLanguageType()
}
/** Gets an allocation of this set. */
final Allocation getAnAllocation() {
exists(AllocationSet0::Set set |
this = AllocationSet::getEquivalenceClass(set) and
set.contains(result)
)
}
/** Gets a unique string representing this set. */
final private string getUniqueId() {
result = strictconcat(getUniqueAllocationId(this.getAnAllocation()).toString(), ",")
}
/**
* Gets the order that this set should be initialized in.
*
* Note: This is _not_ the order in which the _members_ of the set should be
* initialized. Rather, it represents the order in which the set should be
* initialized in relation to other sets. That is, if
* ```
* getInitializationOrder() = 2
* ```
* then this set will be initialized as the second (third) set in the
* enclosing function. In order words, the third `UninitializedGroup`
* instruction in the entry block of the enclosing function will initialize
* this set of allocations.
*/
final int getInitializationOrder() {
exists(IRFunction func |
func = this.getIRFunction() and
this =
rank[result + 1](VariableGroup vg, string uniq |
vg.getIRFunction() = func and uniq = vg.getUniqueId()
|
vg order by uniq
)
)
}
string toString() { result = "{" + strictconcat(this.getAnAllocation().toString(), ", ") + "}" }
}
private newtype TMemoryLocation =
TVariableMemoryLocation(
Allocation var, IRType type, Language::LanguageType languageType, IntValue startBitOffset,
IntValue endBitOffset, boolean isMayAccess
) {
(
hasResultMemoryAccess(_, _, var, type, _, startBitOffset, endBitOffset, isMayAccess, false)
hasResultMemoryAccess(_, var, type, _, startBitOffset, endBitOffset, isMayAccess)
or
hasOperandMemoryAccess(_, _, var, type, _, startBitOffset, endBitOffset, isMayAccess, false)
hasOperandMemoryAccess(_, var, type, _, startBitOffset, endBitOffset, isMayAccess)
or
// For a stack variable, always create a memory location for the entire variable.
var.isAlwaysAllocatedOnStack() and
@@ -217,25 +69,31 @@ private newtype TMemoryLocation =
) and
languageType = type.getCanonicalLanguageType()
} or
TEntireAllocationMemoryLocation(Allocation var, Boolean isMayAccess) {
var instanceof IndirectParameterAllocation or
var instanceof DynamicAllocation
TEntireAllocationMemoryLocation(Allocation var, boolean isMayAccess) {
(
var instanceof IndirectParameterAllocation or
var instanceof DynamicAllocation
) and
(isMayAccess = false or isMayAccess = true)
} or
TGroupedMemoryLocation(VariableGroup vg, Boolean isMayAccess, Boolean isAll) or
TUnknownMemoryLocation(IRFunction irFunc, Boolean isMayAccess) or
TAllNonLocalMemory(IRFunction irFunc, Boolean isMayAccess) or
TAllAliasedMemory(IRFunction irFunc, Boolean isMayAccess)
TUnknownMemoryLocation(IRFunction irFunc, boolean isMayAccess) {
isMayAccess = false or isMayAccess = true
} or
TAllNonLocalMemory(IRFunction irFunc, boolean isMayAccess) {
isMayAccess = false or isMayAccess = true
} or
TAllAliasedMemory(IRFunction irFunc, boolean isMayAccess) {
isMayAccess = false or isMayAccess = true
}
/**
* A memory location accessed by a memory operand or memory result. In this implementation, the location is
* Represents the memory location accessed by a memory operand or memory result. In this implementation, the location is
* one of the following:
* - `VariableMemoryLocation` - A location within a known `IRVariable`, at an offset that is either a constant or is
* unknown.
* - `UnknownMemoryLocation` - A location not known to be within a specific `IRVariable`.
*
* Some of these memory locations will be filtered out for performance reasons before being passed to SSA construction.
*/
abstract private class MemoryLocation0 extends TMemoryLocation {
abstract class MemoryLocation extends TMemoryLocation {
final string toString() {
if this.isMayAccess()
then result = "?" + this.toStringInternal()
@@ -258,14 +116,7 @@ abstract private class MemoryLocation0 extends TMemoryLocation {
abstract predicate isMayAccess();
/**
* Gets an allocation associated with this `MemoryLocation`.
*
* This returns zero or one results in all cases except when `this` is an
* instance of `GroupedMemoryLocation`. When `this` is an instance of
* `GroupedMemoryLocation` this predicate always returns two or more results.
*/
Allocation getAnAllocation() { none() }
Allocation getAllocation() { none() }
/**
* Holds if the location cannot be overwritten except by definition of a `MemoryLocation` for
@@ -296,35 +147,30 @@ abstract private class MemoryLocation0 extends TMemoryLocation {
* represented by a `MemoryLocation` that totally overlaps all other
* `MemoryLocations` in the set.
*/
abstract class VirtualVariable extends MemoryLocation0 { }
abstract class VirtualVariable extends MemoryLocation { }
abstract class AllocationMemoryLocation extends MemoryLocation0 {
abstract class AllocationMemoryLocation extends MemoryLocation {
Allocation var;
boolean isMayAccess;
bindingset[isMayAccess]
AllocationMemoryLocation() { any() }
AllocationMemoryLocation() {
this instanceof TMemoryLocation and
isMayAccess = false
or
isMayAccess = true // Just ensures that `isMayAccess` is bound.
}
final override VirtualVariable getVirtualVariable() {
if allocationEscapes(var)
then result = TAllAliasedMemory(var.getEnclosingIRFunction(), false)
else (
// It may be that the grouped memory location contains an escaping
// allocation. In that case, the virtual variable is still the memory
// location that represents all aliased memory. Thus, we need to
// call `getVirtualVariable` on the grouped memory location.
result = getGroupedMemoryLocation(var, false, false).getVirtualVariable()
or
not exists(getGroupedMemoryLocation(var, false, false)) and
result.(AllocationMemoryLocation).getAnAllocation() = var
)
else result.(AllocationMemoryLocation).getAllocation() = var
}
final override IRFunction getIRFunction() { result = var.getEnclosingIRFunction() }
final override Location getLocation() { result = var.getLocation() }
final override Allocation getAnAllocation() { result = var }
final override Allocation getAllocation() { result = var }
final override predicate isMayAccess() { isMayAccess = true }
@@ -365,13 +211,13 @@ class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLo
final override Language::LanguageType getType() {
if
strictcount(Language::LanguageType accessType |
hasResultMemoryAccess(_, _, var, type, accessType, startBitOffset, endBitOffset, _, false) or
hasOperandMemoryAccess(_, _, var, type, accessType, startBitOffset, endBitOffset, _, false)
hasResultMemoryAccess(_, var, type, accessType, startBitOffset, endBitOffset, _) or
hasOperandMemoryAccess(_, var, type, accessType, startBitOffset, endBitOffset, _)
) = 1
then
// All of the accesses have the same `LanguageType`, so just use that.
hasResultMemoryAccess(_, _, var, type, result, startBitOffset, endBitOffset, _, false) or
hasOperandMemoryAccess(_, _, var, type, result, startBitOffset, endBitOffset, _, false)
hasResultMemoryAccess(_, var, type, result, startBitOffset, endBitOffset, _) or
hasOperandMemoryAccess(_, var, type, result, startBitOffset, endBitOffset, _)
else
// There is no single type for all accesses, so just use the canonical one for this `IRType`.
result = type.getCanonicalLanguageType()
@@ -401,89 +247,6 @@ class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLo
}
}
/**
* A group of allocations represented as a single memory location.
*
* If `isAll()` holds then this memory location represents all the enclosing
* allocations, and if `isSome()` holds then this memory location represents
* one or more of the enclosing allocations.
*
* For example, consider the following snippet:
* ```
* int* p;
* int a, b;
* if(b) {
* p = &a;
* } else {
* p = &b;
* }
* *p = 42;
* ```
*
* The write memory location associated with the write to `*p` writes to a
* grouped memory location representing the _some_ allocation in the set
* `{a, b}`, and the subsequent `Chi` instruction merges the new value of
* `{a, b}` into a memory location that represents _all_ of the allocations
* in the set.
*/
class GroupedMemoryLocation extends TGroupedMemoryLocation, MemoryLocation0 {
VariableGroup vg;
boolean isMayAccess;
boolean isAll;
GroupedMemoryLocation() { this = TGroupedMemoryLocation(vg, isMayAccess, isAll) }
final override Location getLocation() { result = vg.getLocation() }
final override IRFunction getIRFunction() { result = vg.getIRFunction() }
final override predicate isMayAccess() { isMayAccess = true }
final override string getUniqueId() {
if this.isAll()
then result = "All{" + strictconcat(vg.getAnAllocation().getUniqueId(), ", ") + "}"
else result = "Some{" + strictconcat(vg.getAnAllocation().getUniqueId(), ", ") + "}"
}
final override string toStringInternal() { result = this.getUniqueId() }
final override Language::LanguageType getType() { result = vg.getType() }
final override VirtualVariable getVirtualVariable() {
if allocationEscapes(this.getAnAllocation())
then result = TAllAliasedMemory(vg.getIRFunction(), false)
else result = TGroupedMemoryLocation(vg, false, true)
}
/** Gets an allocation of this memory location. */
override Allocation getAnAllocation() { result = vg.getAnAllocation() }
/** Gets the set of allocations associated with this memory location. */
VariableGroup getGroup() { result = vg }
/** Holds if this memory location represents all the enclosing allocations. */
predicate isAll() { isAll = true }
/** Holds if this memory location represents one or more of the enclosing allocations. */
predicate isSome() { isAll = false }
}
private GroupedMemoryLocation getGroupedMemoryLocation(
Allocation alloc, boolean isMayAccess, boolean isAll
) {
result.getAnAllocation() = alloc and
(
isMayAccess = true and result.isMayAccess()
or
isMayAccess = false and not result.isMayAccess()
) and
(
isAll = true and result.isAll()
or
isAll = false and result.isSome()
)
}
class EntireAllocationMemoryLocation extends TEntireAllocationMemoryLocation,
AllocationMemoryLocation
{
@@ -519,18 +282,10 @@ class VariableVirtualVariable extends VariableMemoryLocation, VirtualVariable {
}
}
class GroupedVirtualVariable extends GroupedMemoryLocation, VirtualVariable {
GroupedVirtualVariable() {
forex(Allocation var | var = this.getAnAllocation() | not allocationEscapes(var)) and
not this.isMayAccess() and
this.isAll()
}
}
/**
* An access to memory that is not known to be confined to a specific `IRVariable`.
*/
class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation0 {
class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
IRFunction irFunc;
boolean isMayAccess;
@@ -557,7 +312,7 @@ class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation0 {
* An access to memory that is not known to be confined to a specific `IRVariable`, but is known to
* not access memory on the current function's stack frame.
*/
class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation0 {
class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
IRFunction irFunc;
boolean isMayAccess;
@@ -591,7 +346,7 @@ class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation0 {
/**
* An access to all aliased memory.
*/
class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation0 {
class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation {
IRFunction irFunc;
boolean isMayAccess;
@@ -622,7 +377,7 @@ class AliasedVirtualVariable extends AllAliasedMemory, VirtualVariable {
/**
* Gets the overlap relationship between the definition location `def` and the use location `use`.
*/
Overlap getOverlap(MemoryLocation0 def, MemoryLocation0 use) {
Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
exists(Overlap overlap |
// Compute the overlap based only on the extent.
overlap = getExtentOverlap(def, use) and
@@ -650,7 +405,7 @@ Overlap getOverlap(MemoryLocation0 def, MemoryLocation0 use) {
* based only on the set of memory locations accessed. Handling of "may" accesses and read-only
* locations occurs in `getOverlap()`.
*/
private Overlap getExtentOverlap(MemoryLocation0 def, MemoryLocation0 use) {
private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
// The def and the use must have the same virtual variable, or no overlap is possible.
(
// AllAliasedMemory must totally overlap any location within the same virtual variable.
@@ -691,7 +446,7 @@ private Overlap getExtentOverlap(MemoryLocation0 def, MemoryLocation0 use) {
result instanceof MustExactlyOverlap
or
not use instanceof EntireAllocationMemoryLocation and
if def.getAnAllocation() = use.getAnAllocation()
if def.getAllocation() = use.getAllocation()
then
// EntireAllocationMemoryLocation totally overlaps any location within
// the same allocation.
@@ -699,48 +454,11 @@ private Overlap getExtentOverlap(MemoryLocation0 def, MemoryLocation0 use) {
else (
// There is no overlap with a location that's known to belong to a
// different allocation, but all other locations may partially overlap.
not exists(use.getAnAllocation()) and
not exists(use.getAllocation()) and
result instanceof MayPartiallyOverlap
)
)
or
exists(GroupedMemoryLocation group |
group = def and
def.getVirtualVariable() = use.getVirtualVariable()
|
(
use instanceof UnknownMemoryLocation or
use instanceof AllAliasedMemory
) and
result instanceof MayPartiallyOverlap
or
group.isAll() and
(
group.getAnAllocation() =
[
use.(EntireAllocationMemoryLocation).getAnAllocation(),
use.(VariableMemoryLocation).getAnAllocation()
]
or
use.(GroupedMemoryLocation).isSome()
) and
result instanceof MustTotallyOverlap
or
group.isAll() and
use.(GroupedMemoryLocation).isAll() and
result instanceof MustExactlyOverlap
or
group.isSome() and
(
use instanceof EntireAllocationMemoryLocation
or
use instanceof VariableMemoryLocation
or
use instanceof GroupedMemoryLocation
) and
result instanceof MayPartiallyOverlap
)
or
exists(VariableMemoryLocation defVariableLocation |
defVariableLocation = def and
(
@@ -750,8 +468,7 @@ private Overlap getExtentOverlap(MemoryLocation0 def, MemoryLocation0 use) {
(
use instanceof UnknownMemoryLocation or
use instanceof AllAliasedMemory or
use instanceof EntireAllocationMemoryLocation or
use instanceof GroupedMemoryLocation
use instanceof EntireAllocationMemoryLocation
) and
result instanceof MayPartiallyOverlap
or
@@ -817,7 +534,7 @@ private predicate isCoveredOffset(Allocation var, int offsetRank, VariableMemory
exists(int startRank, int endRank, VirtualVariable vvar |
vml.getStartBitOffset() = rank[startRank](IntValue offset_ | isRelevantOffset(vvar, offset_)) and
vml.getEndBitOffset() = rank[endRank](IntValue offset_ | isRelevantOffset(vvar, offset_)) and
var = vml.getAnAllocation() and
var = vml.getAllocation() and
vvar = vml.getVirtualVariable() and
isRelatableMemoryLocation(vml) and
offsetRank in [startRank .. endRank]
@@ -825,7 +542,7 @@ private predicate isCoveredOffset(Allocation var, int offsetRank, VariableMemory
}
private predicate hasUnknownOffset(Allocation var, VariableMemoryLocation vml) {
vml.getAnAllocation() = var and
vml.getAllocation() = var and
(
vml.getStartBitOffset() = Ints::unknown() or
vml.getEndBitOffset() = Ints::unknown()
@@ -840,9 +557,9 @@ private predicate overlappingIRVariableMemoryLocations(
isCoveredOffset(var, offsetRank, use)
)
or
hasUnknownOffset(use.getAnAllocation(), def)
hasUnknownOffset(use.getAllocation(), def)
or
hasUnknownOffset(def.getAnAllocation(), use)
hasUnknownOffset(def.getAllocation(), use)
}
private Overlap getVariableMemoryLocationOverlap(
@@ -863,40 +580,6 @@ predicate canReuseSsaForOldResult(Instruction instr) { OldSsa::canReuseSsaForMem
bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() }
/** Gets the number of overlapping uses of `def`. */
private int numberOfOverlappingUses(MemoryLocation0 def) {
result = strictcount(MemoryLocation0 use | exists(getOverlap(def, use)))
}
/**
* Holds if `def` is a busy definition. That is, it has a large number of
* overlapping uses.
*/
private predicate isBusyDef(MemoryLocation0 def) { numberOfOverlappingUses(def) > 1024 }
/** Holds if `use` is a use that overlaps with a busy definition. */
private predicate useOverlapWithBusyDef(MemoryLocation0 use) {
exists(MemoryLocation0 def |
exists(getOverlap(def, use)) and
isBusyDef(def)
)
}
final private class FinalMemoryLocation = MemoryLocation0;
/**
* A memory location accessed by a memory operand or memory result. In this implementation, the location is
* one of the following:
* - `VariableMemoryLocation` - A location within a known `IRVariable`, at an offset that is either a constant or is
* unknown.
* - `UnknownMemoryLocation` - A location not known to be within a specific `IRVariable`.
*
* Compared to `MemoryLocation0`, this class does not contain memory locations that represent uses of busy definitions.
*/
class MemoryLocation extends FinalMemoryLocation {
MemoryLocation() { not useOverlapWithBusyDef(this) }
}
MemoryLocation getResultMemoryLocation(Instruction instr) {
not canReuseSsaForOldResult(instr) and
exists(MemoryAccessKind kind, boolean isMayAccess |
@@ -905,24 +588,13 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
(
(
isIndirectOrBufferMemoryAccess(kind) and
if hasResultMemoryAccess(_, instr, _, _, _, _, _, _, _)
if hasResultMemoryAccess(instr, _, _, _, _, _, _)
then
exists(
Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset,
boolean grouped
|
hasResultMemoryAccess(_, instr, var, type, _, startBitOffset, endBitOffset, isMayAccess,
grouped)
|
// If the instruction is only associated with one allocation we assign it a `VariableMemoryLocation`
if grouped = false
then
result =
TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset,
unbindBool(isMayAccess))
else
// And otherwise we assign it a memory location that groups all the relevant memory locations into one.
result = getGroupedMemoryLocation(var, unbindBool(isMayAccess), false)
exists(Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset |
hasResultMemoryAccess(instr, var, type, _, startBitOffset, endBitOffset, isMayAccess) and
result =
TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset,
unbindBool(isMayAccess))
)
else result = TUnknownMemoryLocation(instr.getEnclosingIRFunction(), isMayAccess)
)
@@ -941,31 +613,20 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
)
}
private MemoryLocation0 getOperandMemoryLocation0(MemoryOperand operand, boolean isMayAccess) {
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
not canReuseSsaForOldResult(operand.getAnyDef()) and
exists(MemoryAccessKind kind |
exists(MemoryAccessKind kind, boolean isMayAccess |
kind = operand.getMemoryAccess() and
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
(
(
isIndirectOrBufferMemoryAccess(kind) and
if hasOperandMemoryAccess(_, operand, _, _, _, _, _, _, _)
if hasOperandMemoryAccess(operand, _, _, _, _, _, _)
then
exists(
Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset,
boolean grouped
|
hasOperandMemoryAccess(_, operand, var, type, _, startBitOffset, endBitOffset,
isMayAccess, grouped)
|
// If the operand is only associated with one memory location we assign it a `VariableMemoryLocation`
if grouped = false
then
result =
TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset, isMayAccess)
else
// And otherwise we assign it a memory location that groups all relevant memory locations into one.
result = getGroupedMemoryLocation(var, isMayAccess, false)
exists(Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset |
hasOperandMemoryAccess(operand, var, type, _, startBitOffset, endBitOffset, isMayAccess) and
result =
TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset, isMayAccess)
)
else result = TUnknownMemoryLocation(operand.getEnclosingIRFunction(), isMayAccess)
)
@@ -984,19 +645,6 @@ private MemoryLocation0 getOperandMemoryLocation0(MemoryOperand operand, boolean
)
}
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
exists(MemoryLocation0 use0, boolean isMayAccess |
use0 = getOperandMemoryLocation0(operand, isMayAccess)
|
result = use0
or
// If `use0` overlaps with a busy definition we turn it into a use
// of `UnknownMemoryLocation`.
not use0 instanceof MemoryLocation and
result = TUnknownMemoryLocation(operand.getEnclosingIRFunction(), isMayAccess)
)
}
/** Gets the start bit offset of a `MemoryLocation`, if any. */
int getStartBitOffset(VariableMemoryLocation location) {
result = location.getStartBitOffset() and Ints::hasValue(result)

View File

@@ -15,51 +15,6 @@ private class OldInstruction = Reachability::ReachableInstruction;
import Cached
/**
* Holds if `instruction` is the first instruction that may be followed by
* an `UninitializedGroup` instruction, and the enclosing function of
* `instruction` is `func`.
*/
private predicate isFirstInstructionBeforeUninitializedGroup(
Instruction instruction, IRFunction func
) {
instruction = getChi(any(OldIR::InitializeNonLocalInstruction init)) and
func = instruction.getEnclosingIRFunction()
}
/** Gets the `i`'th `UninitializedGroup` instruction in `func`. */
private UninitializedGroupInstruction getInitGroupInstruction(int i, IRFunction func) {
exists(Alias::VariableGroup vg |
vg.getIRFunction() = func and
vg.getInitializationOrder() = i and
result = uninitializedGroup(vg)
)
}
/**
* Holds if `instruction` is the last instruction in the chain of `UninitializedGroup`
* instructions in `func`. The chain of instructions may be empty in which case
* `instruction` satisfies
* ```
* isFirstInstructionBeforeUninitializedGroup(instruction, func)
* ```
*/
predicate isLastInstructionForUninitializedGroups(Instruction instruction, IRFunction func) {
exists(int i |
instruction = getInitGroupInstruction(i, func) and
not exists(getChi(instruction)) and
not exists(getInitGroupInstruction(i + 1, func))
)
or
exists(int i |
instruction = getChi(getInitGroupInstruction(i, func)) and
not exists(getInitGroupInstruction(i + 1, func))
)
or
isFirstInstructionBeforeUninitializedGroup(instruction, func) and
not exists(getInitGroupInstruction(0, func))
}
cached
private module Cached {
cached
@@ -77,11 +32,6 @@ private module Cached {
hasChiNode(_, primaryInstruction)
}
cached
predicate hasChiNodeAfterUninitializedGroup(UninitializedGroupInstruction initGroup) {
hasChiNodeAfterUninitializedGroup(_, initGroup)
}
cached
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
exists(OldIR::Instruction oldInstruction |
@@ -95,8 +45,7 @@ private module Cached {
}
class TStageInstruction =
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction or
TUninitializedGroupInstruction;
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
/**
* If `oldInstruction` is a `Phi` instruction that has exactly one reachable predecessor block,
@@ -129,8 +78,6 @@ private module Cached {
or
instr instanceof TChiInstruction
or
instr instanceof TUninitializedGroupInstruction
or
instr instanceof TUnreachedInstruction
}
@@ -176,8 +123,7 @@ private module Cached {
predicate hasModeledMemoryResult(Instruction instruction) {
canModelResultForOldInstruction(getOldInstruction(instruction)) or
instruction instanceof PhiInstruction or // Phis always have modeled results
instruction instanceof ChiInstruction or // Chis always have modeled results
instruction instanceof UninitializedGroupInstruction // Group initializers always have modeled results
instruction instanceof ChiInstruction // Chis always have modeled results
}
cached
@@ -188,23 +134,16 @@ private module Cached {
or
// Chi instructions track virtual variables, and therefore a chi instruction is
// conflated if it's associated with the aliased virtual variable.
exists(Instruction input | instruction = getChi(input) |
Alias::getResultMemoryLocation(input).getVirtualVariable() instanceof
exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) |
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
Alias::AliasedVirtualVariable
or
// A chi following an `UninitializedGroupInstruction` only happens when the virtual
// variable of the grouped memory location is `{AllAliasedMemory}`.
exists(Alias::GroupedMemoryLocation gml |
input = uninitializedGroup(gml.getGroup()) and
gml.getVirtualVariable() instanceof Alias::AliasedVirtualVariable
)
)
or
// Phi instructions track locations, and therefore a phi instruction is
// conflated if it's associated with a conflated location.
exists(Alias::MemoryLocation location |
instruction = getPhi(_, location) and
not exists(location.getAnAllocation())
not exists(location.getAllocation())
)
}
@@ -266,11 +205,7 @@ private module Cached {
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
)
or
(
instruction = getChi(getOldInstruction(result))
or
instruction = getChi(result.(UninitializedGroupInstruction))
) and
instruction = getChi(getOldInstruction(result)) and
tag instanceof ChiPartialOperandTag and
overlap instanceof MustExactlyOverlap
or
@@ -328,14 +263,6 @@ private module Cached {
)
}
cached
IRVariable getAnUninitializedGroupVariable(UninitializedGroupInstruction init) {
exists(Alias::VariableGroup vg |
init = uninitializedGroup(vg) and
result = vg.getAnAllocation().getABaseInstruction().(VariableInstruction).getIRVariable()
)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
@@ -389,19 +316,6 @@ private module Cached {
result = getNewPhiOperandDefinitionFromOldSsa(instr, newPredecessorBlock, overlap)
}
private ChiInstruction getChiAfterUninitializedGroup(int i, IRFunction func) {
result =
rank[i + 1](VariableGroup vg, UninitializedGroupInstruction initGroup, ChiInstruction chi,
int r |
initGroup.getEnclosingIRFunction() = func and
chi = getChi(initGroup) and
initGroup = uninitializedGroup(vg) and
r = vg.getInitializationOrder()
|
chi order by r
)
}
cached
Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
exists(
@@ -415,19 +329,6 @@ private module Cached {
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, vvar, _)
)
or
exists(UninitializedGroupInstruction initGroup, IRFunction func |
chiInstr = getChi(initGroup) and
func = initGroup.getEnclosingIRFunction()
|
chiInstr = getChiAfterUninitializedGroup(0, func) and
isFirstInstructionBeforeUninitializedGroup(result, func)
or
exists(int i |
chiInstr = getChiAfterUninitializedGroup(i + 1, func) and
result = getChiAfterUninitializedGroup(i, func)
)
)
}
cached
@@ -443,40 +344,14 @@ private module Cached {
)
}
private UninitializedGroupInstruction firstInstructionToUninitializedGroup(
Instruction instruction, EdgeKind kind
) {
exists(IRFunction func |
isFirstInstructionBeforeUninitializedGroup(instruction, func) and
result = getInitGroupInstruction(0, func) and
kind instanceof GotoEdge
)
}
/*
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are
* the new instructions generated from the successors of the old instruction
*/
private Instruction getNextUninitializedGroupInstruction(Instruction instruction, EdgeKind kind) {
exists(int i, IRFunction func |
func = instruction.getEnclosingIRFunction() and
instruction = getInitGroupInstruction(i, func) and
kind instanceof GotoEdge
|
if hasChiNodeAfterUninitializedGroup(_, instruction)
then result = getChi(instruction)
else result = getInitGroupInstruction(i + 1, func)
)
or
exists(int i, IRFunction func, UninitializedGroupInstruction initGroup |
func = instruction.getEnclosingIRFunction() and
instruction = getChi(initGroup) and
initGroup = getInitGroupInstruction(i, func) and
kind instanceof GotoEdge
|
result = getInitGroupInstruction(i + 1, func)
)
}
private Instruction getInstructionSuccessorAfterUninitializedGroup0(
Instruction instruction, EdgeKind kind
) {
cached
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
if hasChiNode(_, getOldInstruction(instruction))
then
result = getChi(getOldInstruction(instruction)) and
@@ -496,107 +371,6 @@ private module Cached {
)
}
private Instruction getInstructionSuccessorAfterUninitializedGroup(
Instruction instruction, EdgeKind kind
) {
exists(IRFunction func, Instruction firstBeforeUninitializedGroup |
isLastInstructionForUninitializedGroups(instruction, func) and
isFirstInstructionBeforeUninitializedGroup(firstBeforeUninitializedGroup, func) and
result = getInstructionSuccessorAfterUninitializedGroup0(firstBeforeUninitializedGroup, kind)
)
}
/**
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are
* the new instructions generated from the successors of the old instruction.
*
* Furthermore, the entry block is augmented with `UninitializedGroup` instructions and `Chi`
* instructions. For example, consider this example:
* ```cpp
* int x, y;
* int* p;
* if(b) {
* p = &x;
* escape(&x);
* } else {
* p = &y;
* }
* *p = 42;
*
* int z, w;
* int* q;
* if(b) {
* q = &z;
* } else {
* q = &w;
* }
* *q = 43;
* ```
*
* the unaliased IR for the entry block of this snippet is:
* ```
* v1(void) = EnterFunction :
* m1(unknown) = AliasedDefinition :
* m2(unknown) = InitializeNonLocal :
* r1(glval<bool>) = VariableAddress[b] :
* m3(bool) = InitializeParameter[b] : &:r1
* r2(glval<int>) = VariableAddress[x] :
* m4(int) = Uninitialized[x] : &:r2
* r3(glval<int>) = VariableAddress[y] :
* m5(int) = Uninitialized[y] : &:r3
* r4(glval<int *>) = VariableAddress[p] :
* m6(int *) = Uninitialized[p] : &:r4
* r5(glval<bool>) = VariableAddress[b] :
* r6(bool) = Load[b] : &:r5, m3
* v2(void) = ConditionalBranch : r6
* ```
* and we need to transform this to aliased IR by inserting an `UninitializedGroup`
* instruction for every `VariableGroup` memory location in the function. Furthermore,
* if the `VariableGroup` memory location contains an allocation that escapes we need
* to insert a `Chi` that writes the memory produced by `UninitializedGroup` into
* `{AllAliasedMemory}`. For the above snippet we then end up with:
* ```
* v1(void) = EnterFunction :
* m2(unknown) = AliasedDefinition :
* m3(unknown) = InitializeNonLocal :
* m4(unknown) = Chi : total:m2, partial:m3
* m5(int) = UninitializedGroup[x,y] :
* m6(unknown) = Chi : total:m4, partial:m5
* m7(int) = UninitializedGroup[w,z] :
* r1(glval<bool>) = VariableAddress[b] :
* m8(bool) = InitializeParameter[b] : &:r1
* r2(glval<int>) = VariableAddress[x] :
* m10(int) = Uninitialized[x] : &:r2
* m11(unknown) = Chi : total:m6, partial:m10
* r3(glval<int>) = VariableAddress[y] :
* m12(int) = Uninitialized[y] : &:r3
* m13(unknown) = Chi : total:m11, partial:m12
* r4(glval<int *>) = VariableAddress[p] :
* m14(int *) = Uninitialized[p] : &:r4
* r5(glval<bool>) = VariableAddress[b] :
* r6(bool) = Load[b] : &:r5, m8
* v2(void) = ConditionalBranch : r6
* ```
*
* Here, the group `{x, y}` contains an allocation that escapes (`x`), so there
* is a `Chi` after the `UninitializedGroup` that initializes the memory for the
* `VariableGroup` containing `x`. None of the allocations in `{w, z}` escape so
* there is no `Chi` following that the `UninitializedGroup` that initializes the
* memory of `{w, z}`.
*/
cached
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
result = firstInstructionToUninitializedGroup(instruction, kind)
or
result = getNextUninitializedGroupInstruction(instruction, kind)
or
result = getInstructionSuccessorAfterUninitializedGroup(instruction, kind)
or
not isFirstInstructionBeforeUninitializedGroup(instruction, _) and
result = getInstructionSuccessorAfterUninitializedGroup0(instruction, kind)
}
cached
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
exists(OldInstruction oldInstruction |
@@ -632,16 +406,6 @@ private module Cached {
exists(IRFunctionBase irFunc |
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction()
)
or
exists(Alias::VariableGroup vg |
instr = uninitializedGroup(vg) and
result = vg.getIRFunction().getFunction()
)
or
exists(UninitializedGroupInstruction initGroup |
instr = chiInstruction(initGroup) and
result = getInstructionAst(initGroup)
)
}
cached
@@ -654,16 +418,9 @@ private module Cached {
)
or
exists(Instruction primaryInstr, Alias::VirtualVariable vvar |
instr = chiInstruction(primaryInstr) and result = vvar.getType()
|
hasChiNode(vvar, primaryInstr)
or
hasChiNodeAfterUninitializedGroup(vvar, primaryInstr)
)
or
exists(Alias::VariableGroup vg |
instr = uninitializedGroup(vg) and
result = vg.getType()
instr = chiInstruction(primaryInstr) and
hasChiNode(vvar, primaryInstr) and
result = vvar.getType()
)
or
instr = reusedPhiInstruction(_) and
@@ -691,8 +448,6 @@ private module Cached {
or
instr = chiInstruction(_) and opcode instanceof Opcode::Chi
or
instr = uninitializedGroup(_) and opcode instanceof Opcode::UninitializedGroup
or
instr = unreachedInstruction(_) and opcode instanceof Opcode::Unreached
}
@@ -705,15 +460,10 @@ private module Cached {
result = blockStartInstr.getEnclosingIRFunction()
)
or
exists(Instruction primaryInstr |
exists(OldInstruction primaryInstr |
instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction()
)
or
exists(Alias::VariableGroup vg |
instr = uninitializedGroup(vg) and
result = vg.getIRFunction()
)
or
instr = unreachedInstruction(result)
}
@@ -728,8 +478,6 @@ private module Cached {
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction)
)
or
instruction = getChi(result.(UninitializedGroupInstruction))
}
}
@@ -737,7 +485,7 @@ private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(
private OldInstruction getOldInstruction(Instruction instr) { instr = result }
private ChiInstruction getChi(Instruction primaryInstr) { result = chiInstruction(primaryInstr) }
private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) }
private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) {
result = phiInstruction(defBlock.getFirstInstruction(), defLocation)
@@ -758,16 +506,6 @@ private predicate hasChiNode(Alias::VirtualVariable vvar, OldInstruction def) {
)
}
private predicate hasChiNodeAfterUninitializedGroup(
Alias::AliasedVirtualVariable vvar, UninitializedGroupInstruction initGroup
) {
exists(Alias::GroupedMemoryLocation defLocation |
initGroup = uninitializedGroup(defLocation.getGroup()) and
defLocation.getVirtualVariable() = vvar and
Alias::getOverlap(defLocation, vvar) instanceof MayPartiallyOverlap
)
}
private import PhiInsertion
/**
@@ -930,37 +668,19 @@ private import DefUse
* potentially very sparse.
*/
module DefUse {
bindingset[index, block]
pragma[inline_late]
private int getNonChiOffset(int index, OldBlock block) {
exists(OldIR::IRFunction func, Instruction i, OldBlock entryBlock |
func = block.getEnclosingIRFunction() and
i = block.getInstruction(index) and
entryBlock = func.getEntryBlock()
|
if
block = entryBlock and
not i instanceof InitializeNonLocalInstruction and
not i instanceof AliasedDefinitionInstruction
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
else result = 2 * index
)
}
bindingset[index, block]
pragma[inline_late]
private int getChiOffset(int index, OldBlock block) { result = getNonChiOffset(index, block) + 1 }
/**
* Gets the `Instruction` for the definition at offset `defOffset` in block `defBlock`.
*/
private Instruction getDefinitionOrChiInstruction0(
Instruction getDefinitionOrChiInstruction(
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
Alias::MemoryLocation actualDefLocation
) {
exists(OldInstruction oldInstr, int oldOffset | oldInstr = defBlock.getInstruction(oldOffset) |
exists(OldInstruction oldInstr, int oldOffset |
oldInstr = defBlock.getInstruction(oldOffset) and
oldOffset >= 0
|
// An odd offset corresponds to the `Chi` instruction.
defOffset = getChiOffset(oldOffset, defBlock) and
defOffset = oldOffset * 2 + 1 and
result = getChi(oldInstr) and
(
defLocation = Alias::getResultMemoryLocation(oldInstr) or
@@ -969,7 +689,7 @@ module DefUse {
actualDefLocation = defLocation.getVirtualVariable()
or
// An even offset corresponds to the original instruction.
defOffset = getNonChiOffset(oldOffset, defBlock) and
defOffset = oldOffset * 2 and
result = getNewInstruction(oldInstr) and
(
defLocation = Alias::getResultMemoryLocation(oldInstr) or
@@ -982,54 +702,6 @@ module DefUse {
hasDefinition(_, defLocation, defBlock, defOffset) and
result = getPhi(defBlock, defLocation) and
actualDefLocation = defLocation
or
exists(
Alias::VariableGroup vg, int index, UninitializedGroupInstruction initGroup,
Alias::GroupedMemoryLocation gml
|
// Add 3 to account for the function prologue:
// v1(void) = EnterFunction
// m1(unknown) = AliasedDefinition
// m2(unknown) = InitializeNonLocal
index = 3 + vg.getInitializationOrder() and
not gml.isMayAccess() and
gml.isSome() and
gml.getGroup() = vg and
vg.getIRFunction().getEntryBlock() = defBlock and
initGroup = uninitializedGroup(vg) and
(defLocation = gml or defLocation = gml.getVirtualVariable())
|
result = initGroup and
defOffset = 2 * index and
actualDefLocation = defLocation
or
result = getChi(initGroup) and
defOffset = 2 * index + 1 and
actualDefLocation = defLocation.getVirtualVariable()
)
}
private ChiInstruction remapGetDefinitionOrChiInstruction(Instruction oldResult) {
exists(IRFunction func |
isFirstInstructionBeforeUninitializedGroup(oldResult, func) and
isLastInstructionForUninitializedGroups(result, func)
)
}
Instruction getDefinitionOrChiInstruction(
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
Alias::MemoryLocation actualDefLocation
) {
exists(Instruction oldResult |
oldResult =
getDefinitionOrChiInstruction0(defBlock, defOffset, defLocation, actualDefLocation) and
(
result = remapGetDefinitionOrChiInstruction(oldResult)
or
not exists(remapGetDefinitionOrChiInstruction(oldResult)) and
result = oldResult
)
)
}
/**
@@ -1170,20 +842,8 @@ module DefUse {
block.getInstruction(index) = def and
overlap = Alias::getOverlap(defLocation, useLocation) and
if overlap instanceof MayPartiallyOverlap
then offset = getChiOffset(index, block) // The use will be connected to the definition on the `Chi` instruction.
else offset = getNonChiOffset(index, block) // The use will be connected to the definition on the original instruction.
)
or
exists(UninitializedGroupInstruction initGroup, int index, Overlap overlap, VariableGroup vg |
initGroup.getEnclosingIRFunction().getEntryBlock() = getNewBlock(block) and
vg = defLocation.(Alias::GroupedMemoryLocation).getGroup() and
// EnterFunction + AliasedDefinition + InitializeNonLocal + index
index = 3 + vg.getInitializationOrder() and
initGroup = uninitializedGroup(vg) and
overlap = Alias::getOverlap(defLocation, useLocation) and
if overlap instanceof MayPartiallyOverlap and hasChiNodeAfterUninitializedGroup(initGroup)
then offset = 2 * index + 1 // The use will be connected to the definition on the `Chi` instruction.
else offset = 2 * index // The use will be connected to the definition on the original instruction.
then offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction.
else offset = index * 2 // The use will be connected to the definition on the original instruction.
)
}
@@ -1244,11 +904,10 @@ module DefUse {
block.getInstruction(index) = use and
(
// A direct use of the location.
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and
offset = getNonChiOffset(index, block)
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and offset = index * 2
or
// A `Chi` instruction will include a use of the virtual variable.
hasChiNode(useLocation, use) and offset = getChiOffset(index, block)
hasChiNode(useLocation, use) and offset = (index * 2) + 1
)
)
}
@@ -1398,9 +1057,5 @@ module Ssa {
predicate hasChiInstruction = Cached::hasChiInstructionCached/1;
predicate hasChiNodeAfterUninitializedGroup = Cached::hasChiNodeAfterUninitializedGroup/1;
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
class VariableGroup = Alias::VariableGroup;
}

View File

@@ -31,7 +31,6 @@ newtype TInstruction =
TUnaliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
UnaliasedSsa::Ssa::hasUnreachedInstruction(irFunc)
} or
TUnaliasedSsaUninitializedGroupInstruction(UnaliasedSsa::Ssa::VariableGroup vg) or
TAliasedSsaPhiInstruction(
TRawInstruction blockStartInstr, AliasedSsa::Ssa::MemoryLocation memoryLocation
) {
@@ -42,12 +41,6 @@ newtype TInstruction =
} or
TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
AliasedSsa::Ssa::hasUnreachedInstruction(irFunc)
} or
TAliasedSsaUninitializedGroupInstruction(AliasedSsa::Ssa::VariableGroup vg) or
TAliasedSsaChiAfterUninitializedGroupInstruction(
TAliasedSsaUninitializedGroupInstruction initGroup
) {
AliasedSsa::Ssa::hasChiNodeAfterUninitializedGroup(initGroup)
}
/**
@@ -69,11 +62,7 @@ module UnaliasedSsaInstructions {
class TChiInstruction = TUnaliasedSsaChiInstruction;
class TUninitializedGroupInstruction = TUnaliasedSsaUninitializedGroupInstruction;
class TRawOrUninitializedGroupInstruction = TRawInstruction or TUninitializedGroupInstruction;
TChiInstruction chiInstruction(TRawOrUninitializedGroupInstruction primaryInstruction) {
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
result = TUnaliasedSsaChiInstruction(primaryInstruction)
}
@@ -82,12 +71,6 @@ module UnaliasedSsaInstructions {
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
result = TUnaliasedSsaUnreachedInstruction(irFunc)
}
class VariableGroup = UnaliasedSsa::Ssa::VariableGroup;
// This really should just be `TUnaliasedSsaUninitializedGroupInstruction`, but that makes the
// compiler realize that certain expressions in `SSAConstruction` are unsatisfiable.
TRawOrUninitializedGroupInstruction uninitializedGroup(VariableGroup vg) { none() }
}
/**
@@ -109,16 +92,10 @@ module AliasedSsaInstructions {
result = TUnaliasedSsaPhiInstruction(blockStartInstr, _)
}
class TChiInstruction =
TAliasedSsaChiInstruction or TAliasedSsaChiAfterUninitializedGroupInstruction;
class TChiInstruction = TAliasedSsaChiInstruction;
class TRawOrInitialzieGroupInstruction =
TRawInstruction or TAliasedSsaUninitializedGroupInstruction;
TChiInstruction chiInstruction(TRawOrInitialzieGroupInstruction primaryInstruction) {
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
result = TAliasedSsaChiInstruction(primaryInstruction)
or
result = TAliasedSsaChiAfterUninitializedGroupInstruction(primaryInstruction)
}
class TUnreachedInstruction = TAliasedSsaUnreachedInstruction;
@@ -126,12 +103,4 @@ module AliasedSsaInstructions {
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
result = TAliasedSsaUnreachedInstruction(irFunc)
}
class VariableGroup = AliasedSsa::Ssa::VariableGroup;
class TUninitializedGroupInstruction = TAliasedSsaUninitializedGroupInstruction;
TUninitializedGroupInstruction uninitializedGroup(VariableGroup vg) {
result = TAliasedSsaUninitializedGroupInstruction(vg)
}
}

View File

@@ -12,9 +12,6 @@ private import semmle.code.cpp.ir.internal.Overlap
* Provides the newtype used to represent operands across all phases of the IR.
*/
private module Internal {
private class TAliasedChiInstruction =
TAliasedSsaChiInstruction or TAliasedSsaChiAfterUninitializedGroupInstruction;
/**
* An IR operand. `TOperand` is shared across all phases of the IR. There are branches of this
* type for operands created directly from the AST (`TRegisterOperand` and `TNonSSAMemoryOperand`),
@@ -55,7 +52,7 @@ private module Internal {
) {
exists(AliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap))
} or
TAliasedChiOperand(TAliasedChiInstruction useInstr, ChiOperandTag tag) { any() }
TAliasedChiOperand(TAliasedSsaChiInstruction useInstr, ChiOperandTag tag) { any() }
}
/**
@@ -201,13 +198,10 @@ module AliasedSsaOperands {
)
}
private class TChiInstruction =
TAliasedSsaChiInstruction or TAliasedSsaChiAfterUninitializedGroupInstruction;
/**
* Returns the Chi operand with the specified parameters.
*/
TChiOperand chiOperand(TChiInstruction useInstr, ChiOperandTag tag) {
TChiOperand chiOperand(TAliasedSsaChiInstruction useInstr, ChiOperandTag tag) {
result = Internal::TAliasedChiOperand(useInstr, tag)
}
}

View File

@@ -2142,47 +2142,6 @@ class ChiInstruction extends Instruction {
final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) }
}
/**
* An instruction that initializes a set of allocations that are each assigned
* the same "virtual variable".
*
* As an example, consider the following snippet:
* ```
* int a;
* int b;
* int* p;
* if(b) {
* p = &a;
* } else {
* p = &b;
* }
* *p = 5;
* int x = a;
* ```
*
* Since both the address of `a` and `b` reach `p` at `*p = 5` the IR alias
* analysis will create a region that contains both `a` and `b`. The region
* containing both `a` and `b` are initialized by an `UninitializedGroup`
* instruction in the entry block of the enclosing function.
*/
class UninitializedGroupInstruction extends Instruction {
UninitializedGroupInstruction() { this.getOpcode() instanceof Opcode::UninitializedGroup }
/**
* Gets an `IRVariable` whose memory is initialized by this instruction, if any.
* Note: Allocations that are not represented as `IRVariable`s (such as
* dynamic allocations) are not returned by this predicate even if this
* instruction initializes such memory.
*/
final IRVariable getAnIRVariable() {
result = Construction::getAnUninitializedGroupVariable(this)
}
final override string getImmediateString() {
result = strictconcat(this.getAnIRVariable().toString(), ",")
}
}
/**
* An instruction representing unreachable code.
*

View File

@@ -407,8 +407,6 @@ predicate hasUnreachedInstruction(IRFunction func) {
)
}
IRVariable getAnUninitializedGroupVariable(UninitializedGroupInstruction instr) { none() }
import CachedForDebugging
cached

View File

@@ -2142,47 +2142,6 @@ class ChiInstruction extends Instruction {
final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) }
}
/**
* An instruction that initializes a set of allocations that are each assigned
* the same "virtual variable".
*
* As an example, consider the following snippet:
* ```
* int a;
* int b;
* int* p;
* if(b) {
* p = &a;
* } else {
* p = &b;
* }
* *p = 5;
* int x = a;
* ```
*
* Since both the address of `a` and `b` reach `p` at `*p = 5` the IR alias
* analysis will create a region that contains both `a` and `b`. The region
* containing both `a` and `b` are initialized by an `UninitializedGroup`
* instruction in the entry block of the enclosing function.
*/
class UninitializedGroupInstruction extends Instruction {
UninitializedGroupInstruction() { this.getOpcode() instanceof Opcode::UninitializedGroup }
/**
* Gets an `IRVariable` whose memory is initialized by this instruction, if any.
* Note: Allocations that are not represented as `IRVariable`s (such as
* dynamic allocations) are not returned by this predicate even if this
* instruction initializes such memory.
*/
final IRVariable getAnIRVariable() {
result = Construction::getAnUninitializedGroupVariable(this)
}
final override string getImmediateString() {
result = strictconcat(this.getAnIRVariable().toString(), ",")
}
}
/**
* An instruction representing unreachable code.
*

View File

@@ -106,7 +106,8 @@ private predicate operandEscapesDomain(Operand operand) {
not isArgumentForParameter(_, operand, _) and
not isOnlyEscapesViaReturnArgument(operand) and
not operand.getUse() instanceof ReturnValueInstruction and
not operand.getUse() instanceof ReturnIndirectionInstruction
not operand.getUse() instanceof ReturnIndirectionInstruction and
not operand instanceof PhiInputOperand
}
/**
@@ -190,11 +191,6 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset, Instr
// A copy propagates the source value.
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
)
or
operand = instr.(PhiInstruction).getAnInputOperand() and
// Using `unknown` ensures termination since we cannot keep incrementing a bit offset
// through the back edge of a loop (or through recursion).
bitOffset = Ints::unknown()
}
private predicate operandEscapesNonReturn(Operand operand) {
@@ -216,6 +212,9 @@ private predicate operandEscapesNonReturn(Operand operand) {
or
isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse())
or
operand instanceof PhiInputOperand and
resultEscapesNonReturn(operand.getUse())
or
operandEscapesDomain(operand)
}
@@ -237,6 +236,9 @@ private predicate operandMayReachReturn(Operand operand) {
operand.getUse() instanceof ReturnValueInstruction
or
isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse())
or
operand instanceof PhiInputOperand and
resultMayReachReturn(operand.getUse())
}
private predicate operandReturned(Operand operand, IntValue bitOffset) {
@@ -338,56 +340,6 @@ private predicate resultEscapesNonReturn(Instruction instr) {
not instr.isResultModeled()
}
/** Holds if `operand` may (transitively) flow to an `AddressOperand`. */
private predicate consumedAsAddressOperand(Operand operand) {
operand instanceof AddressOperand
or
exists(Operand address |
consumedAsAddressOperand(address) and
operandIsPropagated(operand, _, address.getDef())
)
}
/**
* Holds if `operand` may originate from a base instruction of an allocation,
* and that operand may transitively flow to an `AddressOperand`.
*/
private predicate propagatedFromAllocationBase(Operand operand, Configuration::Allocation allocation) {
consumedAsAddressOperand(operand) and
(
not exists(Configuration::getOldAllocation(allocation)) and
operand.getDef() = allocation.getABaseInstruction()
or
exists(Operand address |
operandIsPropagated(address, _, operand.getDef()) and
propagatedFromAllocationBase(address, allocation)
)
)
}
private predicate propagatedFromNonAllocationBase(Operand operand) {
exists(Instruction def |
def = operand.getDef() and
not operandIsPropagated(_, _, def) and
not def = any(Configuration::Allocation allocation).getABaseInstruction()
)
or
exists(Operand address |
operandIsPropagated(address, _, operand.getDef()) and
propagatedFromNonAllocationBase(address)
)
}
/**
* Holds if we cannot see all producers of an operand for which allocation also flows into.
*/
private predicate operandConsumesEscaped(Configuration::Allocation allocation) {
exists(AddressOperand address |
propagatedFromAllocationBase(address, allocation) and
propagatedFromNonAllocationBase(address)
)
}
/**
* Holds if the address of `allocation` escapes outside the domain of the analysis. This can occur
* either because the allocation's address is taken within the function and escapes, or because the
@@ -396,14 +348,12 @@ private predicate operandConsumesEscaped(Configuration::Allocation allocation) {
predicate allocationEscapes(Configuration::Allocation allocation) {
allocation.alwaysEscapes()
or
exists(IREscapeAnalysisConfiguration config | config.useSoundEscapeAnalysis() |
resultEscapesNonReturn(allocation.getABaseInstruction())
or
operandConsumesEscaped(allocation)
exists(IREscapeAnalysisConfiguration config |
config.useSoundEscapeAnalysis() and resultEscapesNonReturn(allocation.getABaseInstruction())
)
or
Configuration::phaseNeedsSoundEscapeAnalysis() and
(resultEscapesNonReturn(allocation.getABaseInstruction()) or operandConsumesEscaped(allocation))
resultEscapesNonReturn(allocation.getABaseInstruction())
}
/**

View File

@@ -1,5 +1,4 @@
private import AliasConfigurationImports
private import codeql.util.Unit
/**
* A memory allocation that can be tracked by the SimpleSSA alias analysis.
@@ -17,5 +16,3 @@ class Allocation extends IRAutomaticVariable {
}
predicate phaseNeedsSoundEscapeAnalysis() { any() }
Unit getOldAllocation(Allocation allocation) { any() }

View File

@@ -15,51 +15,6 @@ private class OldInstruction = Reachability::ReachableInstruction;
import Cached
/**
* Holds if `instruction` is the first instruction that may be followed by
* an `UninitializedGroup` instruction, and the enclosing function of
* `instruction` is `func`.
*/
private predicate isFirstInstructionBeforeUninitializedGroup(
Instruction instruction, IRFunction func
) {
instruction = getChi(any(OldIR::InitializeNonLocalInstruction init)) and
func = instruction.getEnclosingIRFunction()
}
/** Gets the `i`'th `UninitializedGroup` instruction in `func`. */
private UninitializedGroupInstruction getInitGroupInstruction(int i, IRFunction func) {
exists(Alias::VariableGroup vg |
vg.getIRFunction() = func and
vg.getInitializationOrder() = i and
result = uninitializedGroup(vg)
)
}
/**
* Holds if `instruction` is the last instruction in the chain of `UninitializedGroup`
* instructions in `func`. The chain of instructions may be empty in which case
* `instruction` satisfies
* ```
* isFirstInstructionBeforeUninitializedGroup(instruction, func)
* ```
*/
predicate isLastInstructionForUninitializedGroups(Instruction instruction, IRFunction func) {
exists(int i |
instruction = getInitGroupInstruction(i, func) and
not exists(getChi(instruction)) and
not exists(getInitGroupInstruction(i + 1, func))
)
or
exists(int i |
instruction = getChi(getInitGroupInstruction(i, func)) and
not exists(getInitGroupInstruction(i + 1, func))
)
or
isFirstInstructionBeforeUninitializedGroup(instruction, func) and
not exists(getInitGroupInstruction(0, func))
}
cached
private module Cached {
cached
@@ -77,11 +32,6 @@ private module Cached {
hasChiNode(_, primaryInstruction)
}
cached
predicate hasChiNodeAfterUninitializedGroup(UninitializedGroupInstruction initGroup) {
hasChiNodeAfterUninitializedGroup(_, initGroup)
}
cached
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
exists(OldIR::Instruction oldInstruction |
@@ -95,8 +45,7 @@ private module Cached {
}
class TStageInstruction =
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction or
TUninitializedGroupInstruction;
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
/**
* If `oldInstruction` is a `Phi` instruction that has exactly one reachable predecessor block,
@@ -129,8 +78,6 @@ private module Cached {
or
instr instanceof TChiInstruction
or
instr instanceof TUninitializedGroupInstruction
or
instr instanceof TUnreachedInstruction
}
@@ -176,8 +123,7 @@ private module Cached {
predicate hasModeledMemoryResult(Instruction instruction) {
canModelResultForOldInstruction(getOldInstruction(instruction)) or
instruction instanceof PhiInstruction or // Phis always have modeled results
instruction instanceof ChiInstruction or // Chis always have modeled results
instruction instanceof UninitializedGroupInstruction // Group initializers always have modeled results
instruction instanceof ChiInstruction // Chis always have modeled results
}
cached
@@ -188,23 +134,16 @@ private module Cached {
or
// Chi instructions track virtual variables, and therefore a chi instruction is
// conflated if it's associated with the aliased virtual variable.
exists(Instruction input | instruction = getChi(input) |
Alias::getResultMemoryLocation(input).getVirtualVariable() instanceof
exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) |
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
Alias::AliasedVirtualVariable
or
// A chi following an `UninitializedGroupInstruction` only happens when the virtual
// variable of the grouped memory location is `{AllAliasedMemory}`.
exists(Alias::GroupedMemoryLocation gml |
input = uninitializedGroup(gml.getGroup()) and
gml.getVirtualVariable() instanceof Alias::AliasedVirtualVariable
)
)
or
// Phi instructions track locations, and therefore a phi instruction is
// conflated if it's associated with a conflated location.
exists(Alias::MemoryLocation location |
instruction = getPhi(_, location) and
not exists(location.getAnAllocation())
not exists(location.getAllocation())
)
}
@@ -266,11 +205,7 @@ private module Cached {
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
)
or
(
instruction = getChi(getOldInstruction(result))
or
instruction = getChi(result.(UninitializedGroupInstruction))
) and
instruction = getChi(getOldInstruction(result)) and
tag instanceof ChiPartialOperandTag and
overlap instanceof MustExactlyOverlap
or
@@ -328,14 +263,6 @@ private module Cached {
)
}
cached
IRVariable getAnUninitializedGroupVariable(UninitializedGroupInstruction init) {
exists(Alias::VariableGroup vg |
init = uninitializedGroup(vg) and
result = vg.getAnAllocation().getABaseInstruction().(VariableInstruction).getIRVariable()
)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
@@ -389,19 +316,6 @@ private module Cached {
result = getNewPhiOperandDefinitionFromOldSsa(instr, newPredecessorBlock, overlap)
}
private ChiInstruction getChiAfterUninitializedGroup(int i, IRFunction func) {
result =
rank[i + 1](VariableGroup vg, UninitializedGroupInstruction initGroup, ChiInstruction chi,
int r |
initGroup.getEnclosingIRFunction() = func and
chi = getChi(initGroup) and
initGroup = uninitializedGroup(vg) and
r = vg.getInitializationOrder()
|
chi order by r
)
}
cached
Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
exists(
@@ -415,19 +329,6 @@ private module Cached {
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, vvar, _)
)
or
exists(UninitializedGroupInstruction initGroup, IRFunction func |
chiInstr = getChi(initGroup) and
func = initGroup.getEnclosingIRFunction()
|
chiInstr = getChiAfterUninitializedGroup(0, func) and
isFirstInstructionBeforeUninitializedGroup(result, func)
or
exists(int i |
chiInstr = getChiAfterUninitializedGroup(i + 1, func) and
result = getChiAfterUninitializedGroup(i, func)
)
)
}
cached
@@ -443,40 +344,14 @@ private module Cached {
)
}
private UninitializedGroupInstruction firstInstructionToUninitializedGroup(
Instruction instruction, EdgeKind kind
) {
exists(IRFunction func |
isFirstInstructionBeforeUninitializedGroup(instruction, func) and
result = getInitGroupInstruction(0, func) and
kind instanceof GotoEdge
)
}
/*
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are
* the new instructions generated from the successors of the old instruction
*/
private Instruction getNextUninitializedGroupInstruction(Instruction instruction, EdgeKind kind) {
exists(int i, IRFunction func |
func = instruction.getEnclosingIRFunction() and
instruction = getInitGroupInstruction(i, func) and
kind instanceof GotoEdge
|
if hasChiNodeAfterUninitializedGroup(_, instruction)
then result = getChi(instruction)
else result = getInitGroupInstruction(i + 1, func)
)
or
exists(int i, IRFunction func, UninitializedGroupInstruction initGroup |
func = instruction.getEnclosingIRFunction() and
instruction = getChi(initGroup) and
initGroup = getInitGroupInstruction(i, func) and
kind instanceof GotoEdge
|
result = getInitGroupInstruction(i + 1, func)
)
}
private Instruction getInstructionSuccessorAfterUninitializedGroup0(
Instruction instruction, EdgeKind kind
) {
cached
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
if hasChiNode(_, getOldInstruction(instruction))
then
result = getChi(getOldInstruction(instruction)) and
@@ -496,107 +371,6 @@ private module Cached {
)
}
private Instruction getInstructionSuccessorAfterUninitializedGroup(
Instruction instruction, EdgeKind kind
) {
exists(IRFunction func, Instruction firstBeforeUninitializedGroup |
isLastInstructionForUninitializedGroups(instruction, func) and
isFirstInstructionBeforeUninitializedGroup(firstBeforeUninitializedGroup, func) and
result = getInstructionSuccessorAfterUninitializedGroup0(firstBeforeUninitializedGroup, kind)
)
}
/**
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are
* the new instructions generated from the successors of the old instruction.
*
* Furthermore, the entry block is augmented with `UninitializedGroup` instructions and `Chi`
* instructions. For example, consider this example:
* ```cpp
* int x, y;
* int* p;
* if(b) {
* p = &x;
* escape(&x);
* } else {
* p = &y;
* }
* *p = 42;
*
* int z, w;
* int* q;
* if(b) {
* q = &z;
* } else {
* q = &w;
* }
* *q = 43;
* ```
*
* the unaliased IR for the entry block of this snippet is:
* ```
* v1(void) = EnterFunction :
* m1(unknown) = AliasedDefinition :
* m2(unknown) = InitializeNonLocal :
* r1(glval<bool>) = VariableAddress[b] :
* m3(bool) = InitializeParameter[b] : &:r1
* r2(glval<int>) = VariableAddress[x] :
* m4(int) = Uninitialized[x] : &:r2
* r3(glval<int>) = VariableAddress[y] :
* m5(int) = Uninitialized[y] : &:r3
* r4(glval<int *>) = VariableAddress[p] :
* m6(int *) = Uninitialized[p] : &:r4
* r5(glval<bool>) = VariableAddress[b] :
* r6(bool) = Load[b] : &:r5, m3
* v2(void) = ConditionalBranch : r6
* ```
* and we need to transform this to aliased IR by inserting an `UninitializedGroup`
* instruction for every `VariableGroup` memory location in the function. Furthermore,
* if the `VariableGroup` memory location contains an allocation that escapes we need
* to insert a `Chi` that writes the memory produced by `UninitializedGroup` into
* `{AllAliasedMemory}`. For the above snippet we then end up with:
* ```
* v1(void) = EnterFunction :
* m2(unknown) = AliasedDefinition :
* m3(unknown) = InitializeNonLocal :
* m4(unknown) = Chi : total:m2, partial:m3
* m5(int) = UninitializedGroup[x,y] :
* m6(unknown) = Chi : total:m4, partial:m5
* m7(int) = UninitializedGroup[w,z] :
* r1(glval<bool>) = VariableAddress[b] :
* m8(bool) = InitializeParameter[b] : &:r1
* r2(glval<int>) = VariableAddress[x] :
* m10(int) = Uninitialized[x] : &:r2
* m11(unknown) = Chi : total:m6, partial:m10
* r3(glval<int>) = VariableAddress[y] :
* m12(int) = Uninitialized[y] : &:r3
* m13(unknown) = Chi : total:m11, partial:m12
* r4(glval<int *>) = VariableAddress[p] :
* m14(int *) = Uninitialized[p] : &:r4
* r5(glval<bool>) = VariableAddress[b] :
* r6(bool) = Load[b] : &:r5, m8
* v2(void) = ConditionalBranch : r6
* ```
*
* Here, the group `{x, y}` contains an allocation that escapes (`x`), so there
* is a `Chi` after the `UninitializedGroup` that initializes the memory for the
* `VariableGroup` containing `x`. None of the allocations in `{w, z}` escape so
* there is no `Chi` following that the `UninitializedGroup` that initializes the
* memory of `{w, z}`.
*/
cached
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
result = firstInstructionToUninitializedGroup(instruction, kind)
or
result = getNextUninitializedGroupInstruction(instruction, kind)
or
result = getInstructionSuccessorAfterUninitializedGroup(instruction, kind)
or
not isFirstInstructionBeforeUninitializedGroup(instruction, _) and
result = getInstructionSuccessorAfterUninitializedGroup0(instruction, kind)
}
cached
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
exists(OldInstruction oldInstruction |
@@ -632,16 +406,6 @@ private module Cached {
exists(IRFunctionBase irFunc |
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction()
)
or
exists(Alias::VariableGroup vg |
instr = uninitializedGroup(vg) and
result = vg.getIRFunction().getFunction()
)
or
exists(UninitializedGroupInstruction initGroup |
instr = chiInstruction(initGroup) and
result = getInstructionAst(initGroup)
)
}
cached
@@ -654,16 +418,9 @@ private module Cached {
)
or
exists(Instruction primaryInstr, Alias::VirtualVariable vvar |
instr = chiInstruction(primaryInstr) and result = vvar.getType()
|
hasChiNode(vvar, primaryInstr)
or
hasChiNodeAfterUninitializedGroup(vvar, primaryInstr)
)
or
exists(Alias::VariableGroup vg |
instr = uninitializedGroup(vg) and
result = vg.getType()
instr = chiInstruction(primaryInstr) and
hasChiNode(vvar, primaryInstr) and
result = vvar.getType()
)
or
instr = reusedPhiInstruction(_) and
@@ -691,8 +448,6 @@ private module Cached {
or
instr = chiInstruction(_) and opcode instanceof Opcode::Chi
or
instr = uninitializedGroup(_) and opcode instanceof Opcode::UninitializedGroup
or
instr = unreachedInstruction(_) and opcode instanceof Opcode::Unreached
}
@@ -705,15 +460,10 @@ private module Cached {
result = blockStartInstr.getEnclosingIRFunction()
)
or
exists(Instruction primaryInstr |
exists(OldInstruction primaryInstr |
instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction()
)
or
exists(Alias::VariableGroup vg |
instr = uninitializedGroup(vg) and
result = vg.getIRFunction()
)
or
instr = unreachedInstruction(result)
}
@@ -728,8 +478,6 @@ private module Cached {
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction)
)
or
instruction = getChi(result.(UninitializedGroupInstruction))
}
}
@@ -737,7 +485,7 @@ private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(
private OldInstruction getOldInstruction(Instruction instr) { instr = result }
private ChiInstruction getChi(Instruction primaryInstr) { result = chiInstruction(primaryInstr) }
private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) }
private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) {
result = phiInstruction(defBlock.getFirstInstruction(), defLocation)
@@ -758,16 +506,6 @@ private predicate hasChiNode(Alias::VirtualVariable vvar, OldInstruction def) {
)
}
private predicate hasChiNodeAfterUninitializedGroup(
Alias::AliasedVirtualVariable vvar, UninitializedGroupInstruction initGroup
) {
exists(Alias::GroupedMemoryLocation defLocation |
initGroup = uninitializedGroup(defLocation.getGroup()) and
defLocation.getVirtualVariable() = vvar and
Alias::getOverlap(defLocation, vvar) instanceof MayPartiallyOverlap
)
}
private import PhiInsertion
/**
@@ -930,37 +668,19 @@ private import DefUse
* potentially very sparse.
*/
module DefUse {
bindingset[index, block]
pragma[inline_late]
private int getNonChiOffset(int index, OldBlock block) {
exists(OldIR::IRFunction func, Instruction i, OldBlock entryBlock |
func = block.getEnclosingIRFunction() and
i = block.getInstruction(index) and
entryBlock = func.getEntryBlock()
|
if
block = entryBlock and
not i instanceof InitializeNonLocalInstruction and
not i instanceof AliasedDefinitionInstruction
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
else result = 2 * index
)
}
bindingset[index, block]
pragma[inline_late]
private int getChiOffset(int index, OldBlock block) { result = getNonChiOffset(index, block) + 1 }
/**
* Gets the `Instruction` for the definition at offset `defOffset` in block `defBlock`.
*/
private Instruction getDefinitionOrChiInstruction0(
Instruction getDefinitionOrChiInstruction(
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
Alias::MemoryLocation actualDefLocation
) {
exists(OldInstruction oldInstr, int oldOffset | oldInstr = defBlock.getInstruction(oldOffset) |
exists(OldInstruction oldInstr, int oldOffset |
oldInstr = defBlock.getInstruction(oldOffset) and
oldOffset >= 0
|
// An odd offset corresponds to the `Chi` instruction.
defOffset = getChiOffset(oldOffset, defBlock) and
defOffset = oldOffset * 2 + 1 and
result = getChi(oldInstr) and
(
defLocation = Alias::getResultMemoryLocation(oldInstr) or
@@ -969,7 +689,7 @@ module DefUse {
actualDefLocation = defLocation.getVirtualVariable()
or
// An even offset corresponds to the original instruction.
defOffset = getNonChiOffset(oldOffset, defBlock) and
defOffset = oldOffset * 2 and
result = getNewInstruction(oldInstr) and
(
defLocation = Alias::getResultMemoryLocation(oldInstr) or
@@ -982,54 +702,6 @@ module DefUse {
hasDefinition(_, defLocation, defBlock, defOffset) and
result = getPhi(defBlock, defLocation) and
actualDefLocation = defLocation
or
exists(
Alias::VariableGroup vg, int index, UninitializedGroupInstruction initGroup,
Alias::GroupedMemoryLocation gml
|
// Add 3 to account for the function prologue:
// v1(void) = EnterFunction
// m1(unknown) = AliasedDefinition
// m2(unknown) = InitializeNonLocal
index = 3 + vg.getInitializationOrder() and
not gml.isMayAccess() and
gml.isSome() and
gml.getGroup() = vg and
vg.getIRFunction().getEntryBlock() = defBlock and
initGroup = uninitializedGroup(vg) and
(defLocation = gml or defLocation = gml.getVirtualVariable())
|
result = initGroup and
defOffset = 2 * index and
actualDefLocation = defLocation
or
result = getChi(initGroup) and
defOffset = 2 * index + 1 and
actualDefLocation = defLocation.getVirtualVariable()
)
}
private ChiInstruction remapGetDefinitionOrChiInstruction(Instruction oldResult) {
exists(IRFunction func |
isFirstInstructionBeforeUninitializedGroup(oldResult, func) and
isLastInstructionForUninitializedGroups(result, func)
)
}
Instruction getDefinitionOrChiInstruction(
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
Alias::MemoryLocation actualDefLocation
) {
exists(Instruction oldResult |
oldResult =
getDefinitionOrChiInstruction0(defBlock, defOffset, defLocation, actualDefLocation) and
(
result = remapGetDefinitionOrChiInstruction(oldResult)
or
not exists(remapGetDefinitionOrChiInstruction(oldResult)) and
result = oldResult
)
)
}
/**
@@ -1170,20 +842,8 @@ module DefUse {
block.getInstruction(index) = def and
overlap = Alias::getOverlap(defLocation, useLocation) and
if overlap instanceof MayPartiallyOverlap
then offset = getChiOffset(index, block) // The use will be connected to the definition on the `Chi` instruction.
else offset = getNonChiOffset(index, block) // The use will be connected to the definition on the original instruction.
)
or
exists(UninitializedGroupInstruction initGroup, int index, Overlap overlap, VariableGroup vg |
initGroup.getEnclosingIRFunction().getEntryBlock() = getNewBlock(block) and
vg = defLocation.(Alias::GroupedMemoryLocation).getGroup() and
// EnterFunction + AliasedDefinition + InitializeNonLocal + index
index = 3 + vg.getInitializationOrder() and
initGroup = uninitializedGroup(vg) and
overlap = Alias::getOverlap(defLocation, useLocation) and
if overlap instanceof MayPartiallyOverlap and hasChiNodeAfterUninitializedGroup(initGroup)
then offset = 2 * index + 1 // The use will be connected to the definition on the `Chi` instruction.
else offset = 2 * index // The use will be connected to the definition on the original instruction.
then offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction.
else offset = index * 2 // The use will be connected to the definition on the original instruction.
)
}
@@ -1244,11 +904,10 @@ module DefUse {
block.getInstruction(index) = use and
(
// A direct use of the location.
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and
offset = getNonChiOffset(index, block)
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and offset = index * 2
or
// A `Chi` instruction will include a use of the virtual variable.
hasChiNode(useLocation, use) and offset = getChiOffset(index, block)
hasChiNode(useLocation, use) and offset = (index * 2) + 1
)
)
}
@@ -1398,9 +1057,5 @@ module Ssa {
predicate hasChiInstruction = Cached::hasChiInstructionCached/1;
predicate hasChiNodeAfterUninitializedGroup = Cached::hasChiNodeAfterUninitializedGroup/1;
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
class VariableGroup = Alias::VariableGroup;
}

View File

@@ -1,8 +1,7 @@
import AliasAnalysis
private import SimpleSSAImports
import SimpleSSAPublicImports
import AliasConfiguration
private import codeql.util.Unit
private import AliasConfiguration
private predicate isTotalAccess(Allocation var, AddressOperand addrOperand, IRType type) {
exists(Instruction constantBase, int bitOffset |
@@ -49,7 +48,7 @@ predicate canReuseSsaForVariable(IRAutomaticVariable var) {
private newtype TMemoryLocation = MkMemoryLocation(Allocation var) { isVariableModeled(var) }
private MemoryLocation getMemoryLocation(Allocation var) { result.getAnAllocation() = var }
private MemoryLocation getMemoryLocation(Allocation var) { result.getAllocation() = var }
class MemoryLocation extends TMemoryLocation {
Allocation var;
@@ -58,7 +57,7 @@ class MemoryLocation extends TMemoryLocation {
final string toString() { result = var.getAllocationString() }
final Allocation getAnAllocation() { result = var }
final Allocation getAllocation() { result = var }
final Language::Location getLocation() { result = var.getLocation() }
@@ -78,40 +77,6 @@ class MemoryLocation extends TMemoryLocation {
predicate canReuseSsaForOldResult(Instruction instr) { none() }
abstract class VariableGroup extends Unit {
abstract Allocation getAnAllocation();
string toString() { result = "{" + strictconcat(this.getAnAllocation().toString(), ", ") + "}" }
abstract Language::Location getLocation();
abstract IRFunction getIRFunction();
abstract Language::LanguageType getType();
abstract int getInitializationOrder();
}
class GroupedMemoryLocation extends MemoryLocation {
VariableGroup vg;
GroupedMemoryLocation() { none() }
/** Gets an allocation of this memory location. */
Allocation getAnAllocation() { result = vg.getAnAllocation() }
/** Gets the set of allocations associated with this memory location. */
VariableGroup getGroup() { result = vg }
predicate isMayAccess() { none() }
/** Holds if this memory location represents all the enclosing allocations. */
predicate isAll() { none() }
/** Holds if this memory location represents one or more of the enclosing allocations. */
predicate isSome() { none() }
}
/**
* Represents a set of `MemoryLocation`s that cannot overlap with
* `MemoryLocation`s outside of the set. The `VirtualVariable` will be

View File

@@ -27,11 +27,6 @@ private import implementations.StdPair
private import implementations.StdMap
private import implementations.StdSet
private import implementations.StdString
private import implementations.StdFunction
private import implementations.StdException
private import implementations.StdAllocator
private import implementations.StdAlgorithm
private import implementations.StdMath
private import implementations.Swap
private import implementations.GetDelim
private import implementations.SmartPointer

View File

@@ -86,41 +86,6 @@ private class StdIterator extends Iterator, Class {
override Type getValueType() { result = this.getTemplateArgument(1).(Type).getUnderlyingType() }
}
private class StdReverseIterator extends Iterator, Class {
StdReverseIterator() { this.hasQualifiedName(["std", "bsl"], "reverse_iterator") }
override Type getValueType() { result = this.getTemplateArgument(1).(Type).getUnderlyingType() }
}
private class StdIstreamBufIterator extends Iterator, Class {
StdIstreamBufIterator() { this.hasQualifiedName(["std", "bsl"], "istreambuf_iterator") }
override Type getValueType() { result = this.getTemplateArgument(1).(Type).getUnderlyingType() }
}
private class StdIstreambufIteratorConstructor extends Constructor, SideEffectFunction,
AliasFunction
{
StdIstreambufIteratorConstructor() { this.getDeclaringType() instanceof StdIstreamBufIterator }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
buffer = false
}
}
/**
* Gets the `FunctionInput` corresponding to an iterator parameter to
* user-defined operator `op`, at `index`.
@@ -614,43 +579,23 @@ private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMe
override predicate parameterEscapesOnlyViaReturn(int index) { index = -1 }
}
private string beginName() {
result = ["begin", "cbegin", "rbegin", "crbegin", "before_begin", "cbefore_begin"]
}
/**
* A `begin` member function, or a related function, that returns an iterator.
*/
class BeginFunction extends Function {
class BeginFunction extends MemberFunction {
BeginFunction() {
this.getUnspecifiedType() instanceof Iterator and
(
this.hasName(beginName()) and
this instanceof MemberFunction
or
this.hasGlobalOrStdOrBslName(beginName()) and
not this instanceof MemberFunction and
this.getNumberOfParameters() = 1
)
this.hasName(["begin", "cbegin", "rbegin", "crbegin", "before_begin", "cbefore_begin"]) and
this.getType().getUnspecifiedType() instanceof Iterator
}
}
private string endName() { result = ["end", "cend", "rend", "crend"] }
/**
* An `end` member function, or a related function, that returns an iterator.
*/
class EndFunction extends Function {
class EndFunction extends MemberFunction {
EndFunction() {
this.getUnspecifiedType() instanceof Iterator and
(
this.hasName(endName()) and
this instanceof MemberFunction
or
this.hasGlobalOrStdOrBslName(endName()) and
this instanceof MemberFunction and
this.getNumberOfParameters() = 1
)
this.hasName(["end", "cend", "rend", "crend"]) and
this.getType().getUnspecifiedType() instanceof Iterator
}
}
@@ -658,7 +603,7 @@ class EndFunction extends Function {
* A `begin` or `end` member function, or a related member function, that
* returns an iterator.
*/
class BeginOrEndFunction extends Function {
class BeginOrEndFunction extends MemberFunction {
BeginOrEndFunction() {
this instanceof BeginFunction or
this instanceof EndFunction

View File

@@ -7,7 +7,6 @@
import semmle.code.cpp.models.interfaces.FormattingFunction
import semmle.code.cpp.models.interfaces.Alias
import semmle.code.cpp.models.interfaces.SideEffect
/**
* The standard functions `printf`, `wprintf` and their glib variants.
@@ -97,7 +96,7 @@ private class Sprintf extends FormattingFunction {
/**
* Implements `Snprintf`.
*/
private class SnprintfImpl extends Snprintf, AliasFunction, SideEffectFunction {
private class SnprintfImpl extends Snprintf {
SnprintfImpl() {
this instanceof TopLevelFunction and
(
@@ -144,26 +143,6 @@ private class SnprintfImpl extends Snprintf, AliasFunction, SideEffectFunction {
}
override int getSizeParameterIndex() { result = 1 }
override predicate parameterNeverEscapes(int index) {
// We don't know how many parameters are passed to the function since it's varargs, but they also don't escape.
index = this.getFormatParameterIndex()
}
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = this.getOutputParameterIndex(false) and buffer = true and mustWrite = false
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
// We don't know how many parameters are passed to the function since it's varargs, but they also have read side effects.
i = this.getFormatParameterIndex() and buffer = true
}
}
/**

View File

@@ -1,115 +0,0 @@
/**
* Provides models for C++ functions from the `algorithms` header.
*/
import semmle.code.cpp.models.interfaces.Taint
import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.Iterator
import semmle.code.cpp.models.interfaces.SideEffect
import semmle.code.cpp.models.interfaces.Alias
private class StdPartialSort extends Function, SideEffectFunction, AliasFunction {
StdPartialSort() { this.hasGlobalOrStdName("partial_sort") }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = this.getAnIteratorParameterIndex() and buffer = true and mustWrite = false
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = this.getAnIteratorParameterIndex() and
buffer = true and
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
buffer = false
}
private int getAnIteratorParameterIndex() {
this.getParameter(result).getUnspecifiedType() instanceof Iterator
}
override predicate parameterNeverEscapes(int index) {
index = this.getAnIteratorParameterIndex()
or
this.getParameter(index).getUnspecifiedType() instanceof ReferenceType
}
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
}
private class StdSortHeap extends Function, SideEffectFunction, AliasFunction {
StdSortHeap() { this.hasGlobalOrStdName("sort_heap") }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = this.getAnIteratorParameterIndex() and buffer = true and mustWrite = false
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = this.getAnIteratorParameterIndex() and
buffer = true
}
private int getAnIteratorParameterIndex() {
this.getParameter(result).getUnspecifiedType() instanceof Iterator
}
override predicate parameterNeverEscapes(int index) { index = this.getAnIteratorParameterIndex() }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
}
private class StdGenerateN extends Function, SideEffectFunction, AliasFunction {
StdGenerateN() { this.hasGlobalOrStdName("generate_n") }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = this.getAnIteratorParameterIndex() and buffer = true and mustWrite = false
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
}
private int getAnIteratorParameterIndex() {
this.getParameter(result).getUnspecifiedType() instanceof Iterator
}
override predicate parameterNeverEscapes(int index) { index = this.getAnIteratorParameterIndex() }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
}
private class StdFindIfOrIfNot extends Function, SideEffectFunction, AliasFunction {
StdFindIfOrIfNot() { this.hasGlobalOrStdName(["find_if", "find_if_not"]) }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = this.getAnIteratorParameterIndex() and buffer = true
or
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
}
private int getAnIteratorParameterIndex() {
this.getParameter(result).getUnspecifiedType() instanceof Iterator
}
override predicate parameterNeverEscapes(int index) {
this.getParameter(index).getUnspecifiedType() instanceof ReferenceType
}
override predicate parameterEscapesOnlyViaReturn(int index) {
index = this.getAnIteratorParameterIndex()
}
}

View File

@@ -1,256 +0,0 @@
/**
* Provides models for C++ `allocator` and `allocator_traits` classes.
*/
import semmle.code.cpp.models.interfaces.SideEffect
import semmle.code.cpp.models.interfaces.Alias
/** The `std::allocator` class. */
class StdAllocator extends Class {
StdAllocator() { this.hasGlobalOrStdOrBslName("allocator") }
}
/** The `std::allocator_traits` class. */
class StdAllocatorTraits extends Class {
StdAllocatorTraits() { this.hasGlobalOrStdOrBslName("allocator_traits") }
}
private class StdAllocatorConstructor extends Constructor, AliasFunction, SideEffectFunction {
StdAllocatorConstructor() { this.getDeclaringType() instanceof StdAllocator }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and
buffer = false and
mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
}
}
private class StdAllocatorDestructor extends Destructor, AliasFunction, SideEffectFunction {
StdAllocatorDestructor() { this.getDeclaringType() instanceof StdAllocator }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and
buffer = false and
mustWrite = true
}
}
private class StdAllocatorAddress extends MemberFunction, AliasFunction, SideEffectFunction {
StdAllocatorAddress() { this.getClassAndName("address") instanceof StdAllocator }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}
private class StdAllocatorAllocate extends MemberFunction, AliasFunction, SideEffectFunction {
StdAllocatorAllocate() { this.getClassAndName("allocate") instanceof StdAllocator }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}
private class StdAllocatorTraitsAllocate extends MemberFunction, AliasFunction, SideEffectFunction {
StdAllocatorTraitsAllocate() {
this.getClassAndName(["allocate", "allocate_at_least"]) instanceof StdAllocatorTraits
}
override predicate parameterNeverEscapes(int index) {
this.getParameter(index).getUnspecifiedType() instanceof ReferenceType
}
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
}
}
private class StdAllocatorDeallocate extends MemberFunction, AliasFunction, SideEffectFunction {
StdAllocatorDeallocate() { this.getClassAndName("deallocate") instanceof StdAllocator }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = 0 and
buffer = false and
mustWrite = false
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = 0 and
buffer = false
}
}
private class StdAllocatorTraitsDeallocate extends MemberFunction, AliasFunction, SideEffectFunction
{
StdAllocatorTraitsDeallocate() {
this.getClassAndName("deallocate") instanceof StdAllocatorTraits
}
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = 1 and
buffer = false and
mustWrite = false
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = [0, 1] and
buffer = false
}
}
private class StdAllocatorMaxSize extends MemberFunction, AliasFunction, SideEffectFunction {
StdAllocatorMaxSize() { this.getClassAndName("max_size") instanceof StdAllocator }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}
private class StdAllocatTraitsMaxSize extends MemberFunction, AliasFunction, SideEffectFunction {
StdAllocatTraitsMaxSize() { this.getClassAndName("max_size") instanceof StdAllocatorTraits }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}
private class StdAllocatorConstruct extends MemberFunction, AliasFunction, SideEffectFunction {
StdAllocatorConstruct() { this.getClassAndName("construct") instanceof StdAllocator }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = 0 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
}
}
class StdAllocatorTraitsConstruct extends MemberFunction, AliasFunction, SideEffectFunction {
StdAllocatorTraitsConstruct() { this.getClassAndName("construct") instanceof StdAllocatorTraits }
override predicate parameterNeverEscapes(int index) {
index = 1 or this.getParameter(index).getUnspecifiedType() instanceof ReferenceType
}
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = 1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
buffer = false
}
}
class StdAllocatorDestroy extends MemberFunction, AliasFunction, SideEffectFunction {
StdAllocatorDestroy() { this.getClassAndName("destroy") instanceof StdAllocator }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = 0 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = 0 and buffer = false
}
}
class StdAllocatorTraitsDestroy extends MemberFunction, AliasFunction, SideEffectFunction {
StdAllocatorTraitsDestroy() { this.getClassAndName("destroy") instanceof StdAllocatorTraits }
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = 1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = 0 and buffer = false
}
}

View File

@@ -4,8 +4,6 @@
import semmle.code.cpp.models.interfaces.FlowSource
import semmle.code.cpp.models.interfaces.Iterator
import semmle.code.cpp.models.interfaces.SideEffect
import semmle.code.cpp.models.interfaces.Alias
/**
* A sequence container template class (for example, `std::vector`) from the
@@ -60,7 +58,7 @@ private class Vector extends StdSequenceContainer {
/**
* The standard container functions `push_back` and `push_front`.
*/
class StdSequenceContainerPush extends MemberFunction, SideEffectFunction, AliasFunction {
class StdSequenceContainerPush extends MemberFunction {
StdSequenceContainerPush() {
this.getClassAndName("push_back") instanceof Vector or
this.getClassAndName(["push_back", "push_front"]) instanceof Deque or
@@ -76,115 +74,12 @@ class StdSequenceContainerPush extends MemberFunction, SideEffectFunction, Alias
this.getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() =
this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector<T>`
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and
buffer = false and
mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
// the `std::vector<bool>` specialization doesn't take a reference as a
// parameter. So we need to check that the parameter is actually a
// reference.
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
buffer = false
}
}
private class StdSequenceContainerPopFrontOrBack extends MemberFunction, SideEffectFunction,
AliasFunction
{
StdSequenceContainerPopFrontOrBack() {
this.getClassAndName("pop_back") instanceof Vector or
this.getClassAndName("pop_front") instanceof ForwardList or
this.getClassAndName(["pop_front", "pop_back"]) instanceof Deque or
this.getClassAndName(["pop_front", "pop_back"]) instanceof List
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and
buffer = false and
mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and
buffer = false
}
}
private class StdSequenceContainerClear extends MemberFunction, SideEffectFunction, AliasFunction {
StdSequenceContainerClear() {
this.getClassAndName("clear") instanceof Vector or
this.getClassAndName("clear") instanceof Deque or
this.getClassAndName("clear") instanceof ForwardList or
this.getClassAndName("clear") instanceof List
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and
buffer = false and
mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and
buffer = false
}
}
private class StdVectorReserve extends MemberFunction, SideEffectFunction, AliasFunction {
StdVectorReserve() { this.getClassAndName("reserve") instanceof Vector }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and
buffer = false and
mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and
buffer = false
}
}
/**
* The standard container functions `insert` and `insert_after`.
*/
class StdSequenceContainerInsert extends MemberFunction, SideEffectFunction, AliasFunction {
class StdSequenceContainerInsert extends MemberFunction {
StdSequenceContainerInsert() {
this.getClassAndName("insert") instanceof Deque or
this.getClassAndName("insert") instanceof List or
@@ -205,138 +100,17 @@ class StdSequenceContainerInsert extends MemberFunction, SideEffectFunction, Ali
* Gets the index of a parameter to this function that is an iterator.
*/
int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and
buffer = false and
mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
buffer = false
}
}
private class StdSequenceContainerFrontBack extends MemberFunction, SideEffectFunction,
AliasFunction
{
StdSequenceContainerFrontBack() {
this.getClassAndName(["front", "back"]) instanceof Deque or
this.getClassAndName(["front", "back"]) instanceof List or
this.getClassAndName(["front", "back"]) instanceof Vector or
// forward_list does not have a 'back' member function
this.getClassAndName("front") instanceof ForwardList
}
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
}
}
/**
* The standard container functions `at` and `operator[]`.
*/
class StdSequenceContainerAt extends MemberFunction, SideEffectFunction, AliasFunction {
class StdSequenceContainerAt extends MemberFunction {
StdSequenceContainerAt() {
this.getClassAndName(["at", "operator[]"]) instanceof Array or
this.getClassAndName(["at", "operator[]"]) instanceof Deque or
this.getClassAndName(["at", "operator[]"]) instanceof Vector
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
none()
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
private class StdSequenceContainerMemberEquals extends MemberFunction, SideEffectFunction,
AliasFunction
{
StdSequenceContainerMemberEquals() {
this.getClassAndName("operator==") instanceof Array or
this.getClassAndName("operator==") instanceof Deque or
this.getClassAndName("operator==") instanceof Vector
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate parameterNeverEscapes(int index) { index = -1 or index = 0 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
none()
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
or
i = 0 and buffer = false
}
}
private class StdSequenceContainerEquals extends Function, SideEffectFunction, AliasFunction {
StdSequenceContainerEquals() {
this.hasGlobalOrStdOrBslName("operator==") and
not this instanceof MemberFunction and
this.getNumberOfParameters() = 2 and
(
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Vector and
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Vector
or
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof List and
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof List
or
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Deque and
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Deque
)
}
override predicate parameterNeverEscapes(int index) { index = 0 or index = 1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
none()
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = [0, 1] and buffer = false
}
}
/**
@@ -368,115 +142,6 @@ class StdVectorEmplace extends StdSequenceEmplace {
StdVectorEmplace() { this.getDeclaringType() instanceof Vector }
}
private class StdSequenceSize extends MemberFunction, SideEffectFunction, AliasFunction {
StdSequenceSize() {
this.getClassAndName("size") instanceof Vector
or
this.getClassAndName("size") instanceof List
or
this.getClassAndName("size") instanceof Deque
}
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
}
}
private class StdSequenceDestructor extends Destructor, SideEffectFunction, AliasFunction {
StdSequenceDestructor() {
this.getDeclaringType() instanceof Vector
or
this.getDeclaringType() instanceof List
or
this.getDeclaringType() instanceof Deque
}
private Destructor getElementDestructor() {
result.getDeclaringType() = this.getTemplateArgument(0)
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() {
this.getElementDestructor().(SideEffectFunction).hasOnlySpecificReadSideEffects()
or
not exists(this.getElementDestructor())
}
override predicate hasOnlySpecificWriteSideEffects() {
this.getElementDestructor().(SideEffectFunction).hasOnlySpecificWriteSideEffects()
or
not exists(this.getElementDestructor())
}
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
private class StdSequenceConstructor extends Constructor, SideEffectFunction, AliasFunction {
StdSequenceConstructor() {
this.getDeclaringType() instanceof Vector
or
this.getDeclaringType() instanceof List
or
this.getDeclaringType() instanceof Deque
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
buffer = false
}
}
private class InitializerList extends Class {
InitializerList() { this.hasQualifiedName(["std", "bsl"], "initializer_list") }
Type getElementType() { result = this.getTemplateArgument(0) }
}
private class InitializerListConstructor extends Constructor, SideEffectFunction, AliasFunction {
InitializerListConstructor() { this.getDeclaringType() instanceof InitializerList }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
}
/**
* The standard vector `emplace_back` function.
*/

View File

@@ -1,38 +0,0 @@
/**
* Provides models for the C++ `std::exception` class and subclasses.
*/
import semmle.code.cpp.models.interfaces.Taint
import semmle.code.cpp.models.interfaces.Alias
import semmle.code.cpp.models.interfaces.SideEffect
/** The `std::exception` class. */
class StdException extends Class {
StdException() { this.hasGlobalOrStdOrBslName("exception") }
}
/** The `std::bad_alloc` class. */
class StdBadAllocException extends Class {
StdBadAllocException() { this.hasGlobalOrStdOrBslName("bad_alloc") }
}
private class StdBadAllocExceptionConstructor extends Constructor, SideEffectFunction, AliasFunction
{
StdBadAllocExceptionConstructor() { this.getDeclaringType() instanceof StdBadAllocException }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
}
}

View File

@@ -1,53 +0,0 @@
/**
* Provides models for C++ `std::function` class.
*/
import semmle.code.cpp.models.interfaces.SideEffect
import semmle.code.cpp.models.interfaces.Alias
/**
* An instantiation of the `std::function` class template.
*/
class StdFunction extends ClassTemplateInstantiation {
StdFunction() { this.hasGlobalOrStdOrBslName("function") }
}
private class StdFunctionConstructor extends Constructor, SideEffectFunction, AliasFunction {
StdFunctionConstructor() { this.getDeclaringType() instanceof StdFunction }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
}
}
private class StdFunctionDestructor extends Destructor, SideEffectFunction, AliasFunction {
StdFunctionDestructor() { this.getDeclaringType() instanceof StdFunction }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}

View File

@@ -5,8 +5,6 @@
import semmle.code.cpp.models.interfaces.Taint
import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.Iterator
import semmle.code.cpp.models.interfaces.SideEffect
import semmle.code.cpp.models.interfaces.Alias
/**
* The `std::map` and `std::unordered_map` template classes.
@@ -18,9 +16,7 @@ private class MapOrUnorderedMap extends Class {
/**
* Additional model for map constructors using iterator inputs.
*/
private class StdMapConstructor extends Constructor, TaintFunction, AliasFunction,
SideEffectFunction
{
private class StdMapConstructor extends Constructor, TaintFunction {
StdMapConstructor() { this.getDeclaringType() instanceof MapOrUnorderedMap }
/**
@@ -39,23 +35,6 @@ private class StdMapConstructor extends Constructor, TaintFunction, AliasFunctio
output.isQualifierObject()
)
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
buffer = false
}
}
/**
@@ -154,7 +133,7 @@ class StdMapAt extends MemberFunction {
StdMapAt() { this.getClassAndName(["at", "operator[]"]) instanceof MapOrUnorderedMap }
}
private class StdMapAtModels extends StdMapAt, TaintFunction, AliasFunction, SideEffectFunction {
private class StdMapAtModels extends StdMapAt, TaintFunction {
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from qualifier to referenced return value
input.isQualifierObject() and
@@ -165,18 +144,6 @@ private class StdMapAtModels extends StdMapAt, TaintFunction, AliasFunction, Sid
output.isQualifierObject()
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
}
@@ -220,63 +187,3 @@ private class StdMapEqualRange extends TaintFunction {
output.isReturnValue()
}
}
class StdMapDestructor extends Destructor, SideEffectFunction, AliasFunction {
StdMapDestructor() { this.getDeclaringType() instanceof MapOrUnorderedMap }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
private class StdMapClear extends MemberFunction, SideEffectFunction, AliasFunction {
StdMapClear() { this.getClassAndName("clear") instanceof MapOrUnorderedMap }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and
buffer = false and
mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and
buffer = false
}
}
class StdMapSize extends MemberFunction, SideEffectFunction, AliasFunction {
StdMapSize() { this.getClassAndName("size") instanceof MapOrUnorderedMap }
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
}
}

View File

@@ -1,108 +0,0 @@
/**
* Provides models for C++ functions from the `cmath` header.
*/
private import semmle.code.cpp.models.interfaces.SideEffect
private import semmle.code.cpp.models.interfaces.Alias
private class LdExp extends Function, SideEffectFunction {
LdExp() { this.hasGlobalOrStdOrBslName(["ldexp", "ldexpf", "ldexpl"]) }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}
private class Abs extends Function, SideEffectFunction {
Abs() { this.hasGlobalOrStdOrBslName(["abs", "fabs", "fabsf", "fabsl", "llabs", "imaxabs"]) }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}
private class Div extends Function, SideEffectFunction {
Div() { this.hasGlobalOrStdOrBslName(["div", "ldiv", "lldiv", "imaxdiv"]) }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}
private class FMod extends Function, SideEffectFunction {
FMod() { this.hasGlobalOrStdOrBslName(["fmod", "fmodf", "fmodl"]) }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}
private class Remainder extends Function, SideEffectFunction {
Remainder() { this.hasGlobalOrStdOrBslName(["remainder", "remainderf", "remainderl"]) }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}
private class Remquo extends Function, SideEffectFunction {
Remquo() { this.hasGlobalOrStdOrBslName(["remquo", "remquof", "remquol"]) }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
this.getParameter(i).getUnspecifiedType() instanceof PointerType and
buffer = false and
mustWrite = true
}
}
private class Fma extends Function, SideEffectFunction {
Fma() { this.hasGlobalOrStdOrBslName(["fma", "fmaf", "fmal"]) }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}
private class Fmax extends Function, SideEffectFunction {
Fmax() { this.hasGlobalOrStdOrBslName(["fmax", "fmaxf", "fmaxl"]) }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}
private class Fmin extends Function, SideEffectFunction {
Fmin() { this.hasGlobalOrStdOrBslName(["fmin", "fminf", "fminl"]) }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}
private class Fdim extends Function, SideEffectFunction {
Fdim() { this.hasGlobalOrStdOrBslName(["fdim", "fdimf", "fdiml"]) }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}
private class Nan extends Function, SideEffectFunction, AliasFunction {
Nan() { this.hasGlobalOrStdOrBslName(["nan", "nanf", "nanl"]) }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate parameterNeverEscapes(int index) { index = 0 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = 0 and buffer = true
}
}

View File

@@ -3,8 +3,6 @@
*/
import semmle.code.cpp.models.interfaces.Taint
import semmle.code.cpp.models.interfaces.Alias
import semmle.code.cpp.models.interfaces.SideEffect
/**
* An instantiation of `std::pair<T1, T2>`.
@@ -39,9 +37,7 @@ class StdPairCopyishConstructor extends Constructor, TaintFunction {
/**
* Additional model for `std::pair` constructors.
*/
private class StdPairConstructor extends Constructor, TaintFunction, AliasFunction,
SideEffectFunction
{
private class StdPairConstructor extends Constructor, TaintFunction {
StdPairConstructor() { this.getDeclaringType() instanceof StdPair }
/**
@@ -63,77 +59,4 @@ private class StdPairConstructor extends Constructor, TaintFunction, AliasFuncti
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 hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
// All the constructor parameters are references with the exception of this one:
// ```
// template<class... Args1, class... Args2>
// pair(std::piecewise_construct_t, std::tuple<Args1...> first_args, std::tuple<Args2...> second_args);
// ```
// So we need to check that the parameters are actually references
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
buffer = false
}
}
private class StdPairDestructor extends Destructor, AliasFunction, SideEffectFunction {
StdPairDestructor() { this.getDeclaringType() instanceof StdPair }
private Type getFirstType() { result = this.getDeclaringType().getTemplateArgument(0) }
private Type getSecondType() { result = this.getDeclaringType().getTemplateArgument(0) }
private Type getAType() { result = [this.getFirstType(), this.getSecondType()] }
/**
* Gets the destructor associated with the base type of this pair
*/
private Destructor getADestructor() { result.getDeclaringType() = this.getAType() }
override predicate hasOnlySpecificReadSideEffects() {
this.getADestructor().(SideEffectFunction).hasOnlySpecificReadSideEffects()
or
// If there's no declared destructor for the base type then it won't have
// any strange read side effects.
not exists(this.getADestructor())
}
override predicate hasOnlySpecificWriteSideEffects() {
this.getADestructor().(SideEffectFunction).hasOnlySpecificWriteSideEffects()
or
// If there's no declared destructor for the base type then it won't have
// any strange write side effects.
not exists(this.getADestructor())
}
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate parameterNeverEscapes(int index) {
this.getADestructor().(AliasFunction).parameterNeverEscapes(index)
or
// If there's no declared destructor for the base type then it won't cause
// anything to escape.
not exists(this.getADestructor()) and
index = -1
}
}

View File

@@ -7,8 +7,6 @@
import semmle.code.cpp.models.interfaces.Taint
import semmle.code.cpp.models.interfaces.Iterator
import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.SideEffect
import semmle.code.cpp.models.interfaces.Alias
/**
* The `std::basic_string` template class instantiations.
@@ -68,7 +66,7 @@ abstract private class StdStringTaintFunction extends TaintFunction {
* Gets the index of a parameter to this function that is an iterator.
*/
final int getAnIteratorParameterIndex() {
this.getParameter(result).getUnspecifiedType() instanceof Iterator
this.getParameter(result).getType() instanceof Iterator
}
}
@@ -80,9 +78,7 @@ abstract private class StdStringTaintFunction extends TaintFunction {
* std::string b(a.begin(), a.end());
* ```
*/
private class StdStringConstructor extends Constructor, StdStringTaintFunction, SideEffectFunction,
AliasFunction
{
private class StdStringConstructor extends Constructor, StdStringTaintFunction {
StdStringConstructor() { this.getDeclaringType() instanceof StdBasicString }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
@@ -98,42 +94,6 @@ private class StdStringConstructor extends Constructor, StdStringTaintFunction,
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 hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
private class StdStringDestructor extends Destructor, SideEffectFunction, AliasFunction {
StdStringDestructor() { this.getDeclaringType() instanceof StdBasicString }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
/**
@@ -204,7 +164,7 @@ private class StdStringFrontBack extends StdStringTaintFunction {
/**
* The (non-member) `std::string` function `operator+`.
*/
private class StdStringPlus extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
private class StdStringPlus extends StdStringTaintFunction {
StdStringPlus() {
this.hasQualifiedName(["std", "bsl"], "operator+") and
this.getUnspecifiedType() instanceof StdBasicString
@@ -218,22 +178,6 @@ private class StdStringPlus extends StdStringTaintFunction, SideEffectFunction,
) and
output.isReturnValue()
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
buffer = false
or
this.getParameter(i).getUnspecifiedType() instanceof PointerType and
buffer = true
}
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
}
/**
@@ -241,7 +185,7 @@ private class StdStringPlus extends StdStringTaintFunction, SideEffectFunction,
* All of these functions combine the existing string with a new
* string (or character) from one of the arguments.
*/
private class StdStringAppend extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
private class StdStringAppend extends StdStringTaintFunction {
StdStringAppend() {
this.getClassAndName(["operator+=", "append", "replace"]) instanceof StdBasicString
}
@@ -266,22 +210,6 @@ private class StdStringAppend extends StdStringTaintFunction, SideEffectFunction
}
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and mustWrite = false and buffer = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = [-1, 0] and buffer = true
}
override predicate parameterNeverEscapes(int index) { index = [-1, 0] }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
}
/**
@@ -373,7 +301,7 @@ private class StdStringSubstr extends StdStringTaintFunction {
/**
* The `std::string` functions `at` and `operator[]`.
*/
private class StdStringAt extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
private class StdStringAt extends StdStringTaintFunction {
StdStringAt() { this.getClassAndName(["at", "operator[]"]) instanceof StdBasicString }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
@@ -387,22 +315,6 @@ private class StdStringAt extends StdStringTaintFunction, SideEffectFunction, Al
}
override predicate isPartialWrite(FunctionOutput output) { 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 hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
none()
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
/**
@@ -412,54 +324,6 @@ private class StdBasicIStream extends ClassTemplateInstantiation {
StdBasicIStream() { this.hasQualifiedName(["std", "bsl"], "basic_istream") }
}
private class StdBasicIfStream extends ClassTemplateInstantiation {
StdBasicIfStream() { this.hasQualifiedName(["std", "bsl"], "basic_ifstream") }
}
class StdBasicIfStreamConstructor extends Constructor, SideEffectFunction, AliasFunction {
StdBasicIfStreamConstructor() { this.getDeclaringType() instanceof StdBasicIfStream }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
exists(Type t | t = this.getParameter(i).getUnspecifiedType() |
t instanceof PointerType and buffer = true
or
t instanceof ReferenceType and buffer = false
)
}
}
class StdBasicIfStreamDestructor extends Destructor, SideEffectFunction, AliasFunction {
StdBasicIfStreamDestructor() { this.getDeclaringType() instanceof StdBasicIfStream }
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = -1 and buffer = false and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
/**
* The `std::istream` function `operator>>` (defined as a member function).
*/
@@ -678,33 +542,6 @@ private class StdBasicOStream extends ClassTemplateInstantiation {
StdBasicOStream() { this.hasQualifiedName(["std", "bsl"], "basic_ostream") }
}
private class StdStringLessThan extends Function, AliasFunction, SideEffectFunction {
StdStringLessThan() {
this.hasQualifiedName(["std", "bsl"], "operator<") and
this.getNumberOfParameters() = 2 and
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof
StdBasicString and
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof
StdBasicString
}
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
none()
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = [0, 1] and buffer = false
}
}
/**
* The `std::ostream` functions `operator<<` (defined as a member function),
* `put` and `write`.

View File

@@ -409,11 +409,6 @@ function_defaulted(unique int id: @function ref);
function_prototyped(unique int id: @function ref)
deduction_guide_for_class(
int id: @function ref,
int class_template: @usertype ref
)
member_function_this_type(
unique int id: @function ref,
int this_type: @type ref
@@ -490,17 +485,10 @@ namespace_decls(
int bodylocation: @location_default ref
);
case @using.kind of
1 = @using_declaration
| 2 = @using_directive
| 3 = @using_enum_declaration
;
usings(
unique int id: @using,
int element_id: @element ref,
int location: @location_default ref,
int kind: int ref
int location: @location_default ref
);
/** The element which contains the `using` declaration. */
@@ -921,11 +909,6 @@ varspecifiers(
int spec_id: @specifier ref
);
explicit_specifier_exprs(
unique int func_id: @function ref,
int constant: @expr ref
)
attributes(
unique int id: @attribute,
int kind: int ref,
@@ -1375,8 +1358,6 @@ funbind(
@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
/*
Binary encoding of the allocator form.
case @allocator.form of
0 = plain
| 1 = alignment
@@ -1395,13 +1376,11 @@ expr_allocator(
);
/*
Binary encoding of the deallocator form.
case @deallocator.form of
0 = plain
| 1 = size
| 2 = alignment
| 4 = destroying_delete
| 3 = size_and_alignment
;
*/
@@ -1769,25 +1748,6 @@ case @expr.kind of
| 361 = @isvoid
| 362 = @isvolatile
| 363 = @reuseexpr
| 364 = @istriviallycopyassignable
| 365 = @isassignablenopreconditioncheck
| 366 = @referencebindstotemporary
| 367 = @issameas
| 368 = @builtinhasattribute
| 369 = @ispointerinterconvertiblewithclass
| 370 = @builtinispointerinterconvertiblewithclass
| 371 = @iscorrespondingmember
| 372 = @builtiniscorrespondingmember
| 373 = @isboundedarray
| 374 = @isunboundedarray
| 375 = @isreferenceable
| 378 = @isnothrowconvertible
| 379 = @referenceconstructsfromtemporary
| 380 = @referenceconvertsfromtemporary
| 381 = @isconvertible
| 382 = @isvalidwinrttype
| 383 = @iswinclass
| 384 = @iswininterface
;
@var_args_expr = @vastartexpr
@@ -1882,25 +1842,6 @@ case @expr.kind of
| @isunsigned
| @isvoid
| @isvolatile
| @istriviallycopyassignable
| @isassignablenopreconditioncheck
| @referencebindstotemporary
| @issameas
| @builtinhasattribute
| @ispointerinterconvertiblewithclass
| @builtinispointerinterconvertiblewithclass
| @iscorrespondingmember
| @builtiniscorrespondingmember
| @isboundedarray
| @isunboundedarray
| @isreferenceable
| @isnothrowconvertible
| @referenceconstructsfromtemporary
| @referenceconvertsfromtemporary
| @isconvertible
| @isvalidwinrttype
| @iswinclass
| @iswininterface
;
new_allocated_type(

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +0,0 @@
description: Support destroying deletes
compatibility: partial

View File

@@ -1,3 +0,0 @@
description: Support using-enum declarations.
compatibility: partial
usings.rel: run usings.qlo

View File

@@ -1,17 +0,0 @@
class UsingEntry extends @using {
string toString() { none() }
}
class Element extends @element {
string toString() { none() }
}
class Location extends @location_default {
string toString() { none() }
}
from UsingEntry u, Element target, Location loc, int kind
where
usings(u, target, loc) and
if target instanceof @namespace then kind = 2 else kind = 1
select u, target, loc, kind

View File

@@ -1,2 +0,0 @@
description: Add relation between deduction guides and class templates
compatibility: partial

View File

@@ -1,2 +0,0 @@
description: Add new builtin operations
compatibility: backwards

View File

@@ -1,2 +0,0 @@
description: Support explicit(bool) specifiers
compatibility: partial

View File

@@ -1,27 +1,3 @@
## 1.2.0
### Query Metadata Changes
* The precision of `cpp/unsigned-difference-expression-compared-zero` ("Unsigned difference expression compared to zero") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
### Minor Analysis Improvements
* Fixed false positives in the `cpp/memory-may-not-be-freed` ("Memory may not be freed") query involving class methods that returned an allocated field of that class being misidentified as allocators.
* The `cpp/incorrectly-checked-scanf` ("Incorrect return-value check for a 'scanf'-like function") query now produces fewer false positive results.
* The `cpp/incorrect-allocation-error-handling` ("Incorrect allocation-error handling") query no longer produces occasional false positive results inside template instantiations.
* The `cpp/suspicious-allocation-size` ("Not enough memory allocated for array of pointer type") query no longer produces false positives on "variable size" `struct`s.
## 1.1.0
### Query Metadata Changes
* The precision of `cpp/iterator-to-expired-container` ("Iterator to expired container") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
* The precision of `cpp/unsafe-strncat` ("Potentially unsafe call to strncat") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
### Minor Analysis Improvements
* The `cpp/unsigned-difference-expression-compared-zero` ("Unsigned difference expression compared to zero") query now produces fewer false positives.
## 1.0.3
No user-facing changes.

View File

@@ -39,7 +39,7 @@ predicate allocCallOrIndirect(Expr e) {
allocCallOrIndirect(rtn.getExpr())
or
// return variable assigned with alloc
exists(StackVariable v |
exists(Variable v |
v = rtn.getExpr().(VariableAccess).getTarget() and
allocCallOrIndirect(v.getAnAssignedValue()) and
not assignedToFieldOrGlobal(v, _)

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