Compare commits

..

1 Commits

Author SHA1 Message Date
Asger F
0751ef5c72 JS: Use HTTP responses as taint sources 2024-06-13 09:33:06 +02:00
2317 changed files with 56109 additions and 74367 deletions

View File

@@ -10,16 +10,15 @@ common --override_module=semmle_code=%workspace%/misc/bazel/semmle_code_stub
build --repo_env=CC=clang --repo_env=CXX=clang++ build --repo_env=CC=clang --repo_env=CXX=clang++
# we use transitions that break builds of `...`, so for `test` to work with that we need the following build:linux --cxxopt=-std=c++20
test --build_tests_only # we currently cannot built the swift extractor for ARM
build:macos --cxxopt=-std=c++20 --copt=-arch --copt=x86_64 --linkopt=-arch --linkopt=x86_64
build:windows --cxxopt=/std:c++20 --cxxopt=/Zc:preprocessor
# this requires developer mode, but is required to have pack installer functioning # this requires developer mode, but is required to have pack installer functioning
startup --windows_enable_symlinks startup --windows_enable_symlinks
common --enable_runfiles common --enable_runfiles
# with the above, we can avoid building python zips which is the default on windows as that's expensive
build --nobuild_python_zip
common --registry=file:///%workspace%/misc/bazel/registry common --registry=file:///%workspace%/misc/bazel/registry
common --registry=https://bcr.bazel.build common --registry=https://bcr.bazel.build

View File

@@ -1 +1 @@
7.2.1 7.1.2

14
.devcontainer/swift/root.sh Executable file → Normal file
View File

@@ -3,16 +3,6 @@ set -xe
BAZELISK_VERSION=v1.12.0 BAZELISK_VERSION=v1.12.0
BAZELISK_DOWNLOAD_SHA=6b0bcb2ea15bca16fffabe6fda75803440375354c085480fe361d2cbf32501db 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 \
&& wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \
&& sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
apt-get update apt-get update
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
apt-get -y install --no-install-recommends \ apt-get -y install --no-install-recommends \
@@ -20,9 +10,7 @@ apt-get -y install --no-install-recommends \
uuid-dev \ uuid-dev \
python3-distutils \ python3-distutils \
python3-pip \ python3-pip \
bash-completion \ bash-completion
git-lfs \
gh
# Install Bazel # Install Bazel
curl -fSsL -o /usr/local/bin/bazelisk https://github.com/bazelbuild/bazelisk/releases/download/${BAZELISK_VERSION}/bazelisk-linux-amd64 curl -fSsL -o /usr/local/bin/bazelisk https://github.com/bazelbuild/bazelisk/releases/download/${BAZELISK_VERSION}/bazelisk-linux-amd64

View File

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

37
.gitattributes vendored
View File

@@ -50,40 +50,33 @@
*.dll -text *.dll -text
*.pdb -text *.pdb -text
/java/ql/test/stubs/**/*.java linguist-generated=true java/ql/test/stubs/**/*.java linguist-generated=true
/java/ql/test/experimental/stubs/**/*.java linguist-generated=true java/ql/test/experimental/stubs/**/*.java linguist-generated=true
/java/kotlin-extractor/deps/*.jar filter=lfs diff=lfs merge=lfs -text
# Force git not to modify line endings for go or html files under the go/ql directory # Force git not to modify line endings for go or html files under the go/ql directory
/go/ql/**/*.go -text go/ql/**/*.go -text
/go/ql/**/*.html -text go/ql/**/*.html -text
# Force git not to modify line endings for go dbschemes # Force git not to modify line endings for go dbschemes
/go/*.dbscheme -text go/*.dbscheme -text
# Preserve unusual line ending from codeql-go merge # Preserve unusual line ending from codeql-go merge
/go/extractor/opencsv/CSVReader.java -text go/extractor/opencsv/CSVReader.java -text
# For some languages, upgrade script testing references really old dbscheme # For some languages, upgrade script testing references really old dbscheme
# files from legacy upgrades that have CRLF line endings. Since upgrade # files from legacy upgrades that have CRLF line endings. Since upgrade
# resolution relies on object hashes, we must suppress line ending conversion # resolution relies on object hashes, we must suppress line ending conversion
# for those testing dbscheme files. # for those testing dbscheme files.
/*/ql/lib/upgrades/initial/*.dbscheme -text */ql/lib/upgrades/initial/*.dbscheme -text
# Auto-generated modeling for Python # Auto-generated modeling for Python
/python/ql/lib/semmle/python/frameworks/data/internal/subclass-capture/*.yml linguist-generated=true python/ql/lib/semmle/python/frameworks/data/internal/subclass-capture/*.yml linguist-generated=true
# auto-generated bazel lock file # auto-generated bazel lock file
/ruby/extractor/cargo-bazel-lock.json linguist-generated=true ruby/extractor/cargo-bazel-lock.json linguist-generated=true
/ruby/extractor/cargo-bazel-lock.json -merge ruby/extractor/cargo-bazel-lock.json -merge
# auto-generated files for the C# build # auto-generated files for the C# build
/csharp/paket.lock linguist-generated=true csharp/paket.lock linguist-generated=true
# needs eol=crlf, as `paket` touches this file and saves it as crlf # needs eol=crlf, as `paket` touches this file and saves it als crlf
/csharp/.paket/Paket.Restore.targets linguist-generated=true eol=crlf csharp/.paket/Paket.Restore.targets linguist-generated=true eol=crlf
/csharp/paket.main.bzl linguist-generated=true csharp/paket.main.bzl linguist-generated=true
/csharp/paket.main_extension.bzl linguist-generated=true csharp/paket.main_extension.bzl linguist-generated=true
# ripunzip tool
/misc/ripunzip/ripunzip-* filter=lfs diff=lfs merge=lfs -text
# swift prebuilt resources
/swift/third_party/resource-dir/*.zip filter=lfs diff=lfs merge=lfs -text

View File

@@ -65,7 +65,7 @@ jobs:
key: csharp-qltest-${{ matrix.slice }} key: csharp-qltest-${{ matrix.slice }}
- name: Run QL tests - name: Run QL tests
run: | run: |
codeql test run --threads=0 --ram 50000 --slice ${{ matrix.slice }} --search-path "${{ github.workspace }}" --check-databases --check-undefined-labels --check-repeated-labels --check-redefined-labels --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" codeql test run --threads=0 --ram 50000 --slice ${{ matrix.slice }} --search-path extractor-pack --check-databases --check-undefined-labels --check-repeated-labels --check-redefined-labels --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
env: env:
GITHUB_TOKEN: ${{ github.token }} GITHUB_TOKEN: ${{ github.token }}
unit-tests: unit-tests:
@@ -101,6 +101,6 @@ jobs:
# Update existing stubs in the repo with the freshly generated ones # Update existing stubs in the repo with the freshly generated ones
mv "$STUBS_PATH/output/stubs/_frameworks" ql/test/resources/stubs/ mv "$STUBS_PATH/output/stubs/_frameworks" ql/test/resources/stubs/
git status git status
codeql test run --threads=0 --search-path "${{ github.workspace }}" --check-databases --check-undefined-labels --check-repeated-labels --check-redefined-labels --consistency-queries ql/consistency-queries -- ql/test/library-tests/dataflow/flowsources/aspremote codeql test run --threads=0 --search-path extractor-pack --check-databases --check-undefined-labels --check-repeated-labels --check-redefined-labels --consistency-queries ql/consistency-queries -- ql/test/library-tests/dataflow/flowsources/aspremote
env: env:
GITHUB_TOKEN: ${{ github.token }} GITHUB_TOKEN: ${{ github.token }}

View File

@@ -7,9 +7,6 @@ on:
- .github/workflows/go-tests-other-os.yml - .github/workflows/go-tests-other-os.yml
- .github/actions/** - .github/actions/**
- codeql-workspace.yml - codeql-workspace.yml
- MODULE.bazel
- .bazelrc
- misc/bazel/**
permissions: permissions:
contents: read contents: read

View File

@@ -15,9 +15,6 @@ on:
- .github/workflows/go-tests.yml - .github/workflows/go-tests.yml
- .github/actions/** - .github/actions/**
- codeql-workspace.yml - codeql-workspace.yml
- MODULE.bazel
- .bazelrc
- misc/bazel/**
permissions: permissions:
contents: read contents: read

View File

@@ -1,28 +0,0 @@
name: "Kotlin Build"
on:
pull_request:
paths:
- "java/kotlin-extractor/**"
- "misc/bazel/**"
- "misc/codegen/**"
- "*.bazel*"
- .github/workflows/kotlin-build.yml
branches:
- main
- rc/*
- codeql-cli-*
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: |
bazel query //java/kotlin-extractor/...
# only build the default version as a quick check that we can build from `codeql`
# the full official build will be checked by QLucie
bazel build //java/kotlin-extractor

View File

@@ -60,7 +60,7 @@ jobs:
- name: Make database and analyze - name: Make database and analyze
run: | run: |
./ql/target/release/buramu | tee deprecated.blame # Add a blame file for the extractor to parse. ./ql/target/release/buramu | tee deprecated.blame # Add a blame file for the extractor to parse.
${CODEQL} database create -l=ql ${DB} --search-path "${{ github.workspace }}" ${CODEQL} database create -l=ql --search-path ql/extractor-pack ${DB}
${CODEQL} database analyze -j0 --format=sarif-latest --output=ql-for-ql.sarif ${DB} ql/ql/src/codeql-suites/ql-code-scanning.qls --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" ${CODEQL} database analyze -j0 --format=sarif-latest --output=ql-for-ql.sarif ${DB} ql/ql/src/codeql-suites/ql-code-scanning.qls --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
env: env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }} CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}

View File

@@ -53,8 +53,8 @@ jobs:
- name: Create database - name: Create database
run: | run: |
"${CODEQL}" database create \ "${CODEQL}" database create \
--search-path "${{ github.workspace }}" --search-path "ql/extractor-pack" \
--threads 4 \ --threads 4 \
--language ql --source-root "${{ github.workspace }}/repo" \ --language ql --source-root "${{ github.workspace }}/repo" \
"${{ runner.temp }}/database" "${{ runner.temp }}/database"
env: env:

View File

@@ -53,7 +53,7 @@ jobs:
key: ql-for-ql-tests key: ql-for-ql-tests
- name: Run QL tests - name: Run QL tests
run: | run: |
"${CODEQL}" test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}" --consistency-queries ql/ql/consistency-queries --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" ql/ql/test "${CODEQL}" test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}/ql/extractor-pack" --consistency-queries ql/ql/consistency-queries --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" ql/ql/test
env: env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }} CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
@@ -100,7 +100,7 @@ jobs:
- name: Run a single QL tests - Unix - name: Run a single QL tests - Unix
if: runner.os != 'Windows' if: runner.os != 'Windows'
run: | run: |
"${CODEQL}" test run --check-databases --search-path "${{ github.workspace }}" ql/ql/test/queries/style/DeadCode/DeadCode.qlref "${CODEQL}" test run --check-databases --search-path "${{ github.workspace }}/ql/extractor-pack" ql/ql/test/queries/style/DeadCode/DeadCode.qlref
env: env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }} CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
- name: Run a single QL tests - Windows - name: Run a single QL tests - Windows
@@ -108,4 +108,5 @@ jobs:
shell: pwsh shell: pwsh
run: | run: |
$Env:PATH += ";$(dirname ${{ steps.find-codeql.outputs.codeql-path }})" $Env:PATH += ";$(dirname ${{ steps.find-codeql.outputs.codeql-path }})"
codeql test run --check-databases --search-path "${{ github.workspace }}" ql/ql/test/queries/style/DeadCode/DeadCode.qlref codeql test run --check-databases --search-path "${{ github.workspace }}/ql/extractor-pack" ql/ql/test/queries/style/DeadCode/DeadCode.qlref

View File

@@ -7,7 +7,6 @@ on:
- .github/workflows/ruby-build.yml - .github/workflows/ruby-build.yml
- .github/actions/fetch-codeql/action.yml - .github/actions/fetch-codeql/action.yml
- codeql-workspace.yml - codeql-workspace.yml
- "shared/tree-sitter-extractor/**"
branches: branches:
- main - main
- "rc/*" - "rc/*"
@@ -17,7 +16,6 @@ on:
- .github/workflows/ruby-build.yml - .github/workflows/ruby-build.yml
- .github/actions/fetch-codeql/action.yml - .github/actions/fetch-codeql/action.yml
- codeql-workspace.yml - codeql-workspace.yml
- "shared/tree-sitter-extractor/**"
branches: branches:
- main - main
- "rc/*" - "rc/*"

View File

@@ -44,7 +44,7 @@ jobs:
- name: Create database - name: Create database
run: | run: |
codeql database create \ codeql database create \
--search-path "${{ github.workspace }}" \ --search-path "${{ github.workspace }}/ruby/extractor-pack" \
--threads 4 \ --threads 4 \
--language ruby --source-root "${{ github.workspace }}/repo" \ --language ruby --source-root "${{ github.workspace }}/repo" \
"${{ runner.temp }}/database" "${{ runner.temp }}/database"

View File

@@ -68,6 +68,6 @@ jobs:
key: ruby-qltest key: ruby-qltest
- name: Run QL tests - name: Run QL tests
run: | run: |
codeql test run --threads=0 --ram 50000 --search-path "${{ github.workspace }}" --check-databases --check-undefined-labels --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" codeql test run --threads=0 --ram 50000 --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-undefined-labels --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
env: env:
GITHUB_TOKEN: ${{ github.token }} GITHUB_TOKEN: ${{ github.token }}

View File

@@ -68,6 +68,21 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: ./swift/actions/run-ql-tests - uses: ./swift/actions/run-ql-tests
integration-tests-linux:
if: github.repository_owner == 'github'
needs: build-and-test-linux
runs-on: ubuntu-latest-xl
steps:
- uses: actions/checkout@v4
- uses: ./swift/actions/run-integration-tests
integration-tests-macos:
if: ${{ github.repository_owner == 'github' && github.event_name == 'pull_request' }}
needs: build-and-test-macos
runs-on: macos-12-xl
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- uses: ./swift/actions/run-integration-tests
clang-format: clang-format:
if : ${{ github.event_name == 'pull_request' }} if : ${{ github.event_name == 'pull_request' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -1,23 +0,0 @@
name: "Test zipmerge code"
on:
pull_request:
paths:
- "misc/bazel/internal/zipmerge/**"
- "MODULE.bazel"
- ".bazelrc*"
branches:
- main
- "rc/*"
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: |
bazel test //misc/bazel/internal/zipmerge:test --test_output=all

3
.gitignore vendored
View File

@@ -62,6 +62,3 @@ node_modules/
# Temporary folders for working with generated models # Temporary folders for working with generated models
.model-temp .model-temp
# bazel-built in-tree extractor packs
/*/extractor-pack

View File

@@ -2,6 +2,4 @@
# codeql is publicly forked by many users, and we don't want any LFS file polluting their working # codeql is publicly forked by many users, and we don't want any LFS file polluting their working
# copies. We therefore exclude everything by default. # copies. We therefore exclude everything by default.
# For files required by bazel builds, use rules in `misc/bazel/lfs.bzl` to download them on demand. # For files required by bazel builds, use rules in `misc/bazel/lfs.bzl` to download them on demand.
# we go for `fetchinclude` to something not exsiting rather than `fetchexclude = *` because the
# former is easier to override (with `git -c` or a local git config) to fetch something specific
fetchinclude = /nothing fetchinclude = /nothing

View File

@@ -13,45 +13,20 @@ local_path_override(
# see https://registry.bazel.build/ for a list of available packages # see https://registry.bazel.build/ for a list of available packages
bazel_dep(name = "platforms", version = "0.0.10") bazel_dep(name = "platforms", version = "0.0.9")
bazel_dep(name = "rules_go", version = "0.48.0") bazel_dep(name = "rules_go", version = "0.47.0")
bazel_dep(name = "rules_pkg", version = "0.10.1") bazel_dep(name = "rules_pkg", version = "0.10.1")
bazel_dep(name = "rules_nodejs", version = "6.2.0-codeql.1") bazel_dep(name = "rules_nodejs", version = "6.0.3")
bazel_dep(name = "rules_python", version = "0.32.2") bazel_dep(name = "rules_python", version = "0.31.0")
bazel_dep(name = "bazel_skylib", version = "1.6.1") bazel_dep(name = "bazel_skylib", version = "1.5.0")
bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl") 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 = "nlohmann_json", version = "3.11.3", repo_name = "json")
bazel_dep(name = "fmt", version = "10.0.0") 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.36.0")
bazel_dep(name = "gazelle", version = "0.37.0")
bazel_dep(name = "rules_dotnet", version = "0.15.1") 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.46.0")
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True) bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
crate = use_extension(
"@rules_rust//crate_universe:extension.bzl",
"crate",
)
crate.from_cargo(
name = "py_deps",
cargo_lockfile = "//python/extractor/tsg-python:Cargo.lock",
manifests = [
"//python/extractor/tsg-python:Cargo.toml",
"//python/extractor/tsg-python/tsp:Cargo.toml",
],
)
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(crate, "py_deps", "ruby_deps")
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet") dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
dotnet.toolchain(dotnet_version = "8.0.101") dotnet.toolchain(dotnet_version = "8.0.101")
use_repo(dotnet, "dotnet_toolchains") use_repo(dotnet, "dotnet_toolchains")
@@ -85,99 +60,13 @@ use_repo(
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node") node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node")
node.toolchain( node.toolchain(
name = "nodejs", name = "nodejs",
node_urls = [
"https://nodejs.org/dist/v{version}/{filename}",
"https://mirrors.dotsrc.org/nodejs/release/v{version}/{filename}",
],
node_version = "18.15.0", node_version = "18.15.0",
) )
use_repo(node, "nodejs", "nodejs_toolchains") use_repo(node, "nodejs", "nodejs_toolchains")
kotlin_extractor_deps = use_extension("//java/kotlin-extractor:deps.bzl", "kotlin_extractor_deps")
# following list can be kept in sync by running `bazel mod tidy` in `codeql`
use_repo(
kotlin_extractor_deps,
"codeql_kotlin_defaults",
"codeql_kotlin_embeddable",
"kotlin-compiler-1.5.0",
"kotlin-compiler-1.5.10",
"kotlin-compiler-1.5.20",
"kotlin-compiler-1.5.30",
"kotlin-compiler-1.6.0",
"kotlin-compiler-1.6.20",
"kotlin-compiler-1.7.0",
"kotlin-compiler-1.7.20",
"kotlin-compiler-1.8.0",
"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",
"kotlin-compiler-embeddable-1.5.30",
"kotlin-compiler-embeddable-1.6.0",
"kotlin-compiler-embeddable-1.6.20",
"kotlin-compiler-embeddable-1.7.0",
"kotlin-compiler-embeddable-1.7.20",
"kotlin-compiler-embeddable-1.8.0",
"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",
"kotlin-stdlib-1.5.30",
"kotlin-stdlib-1.6.0",
"kotlin-stdlib-1.6.20",
"kotlin-stdlib-1.7.0",
"kotlin-stdlib-1.7.20",
"kotlin-stdlib-1.8.0",
"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 = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
go_sdk.download(version = "1.22.2") 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(
name = "ripunzip-linux",
srcs = ["//misc/ripunzip:ripunzip-linux"],
executable = True,
)
lfs_files(
name = "ripunzip-windows",
srcs = ["//misc/ripunzip:ripunzip-windows.exe"],
executable = True,
)
lfs_files(
name = "ripunzip-macos",
srcs = ["//misc/ripunzip:ripunzip-macos"],
executable = True,
)
lfs_files(
name = "swift-resource-dir-linux",
srcs = ["//swift/third_party/resource-dir:resource-dir-linux.zip"],
)
lfs_files(
name = "swift-resource-dir-macos",
srcs = ["//swift/third_party/resource-dir:resource-dir-macos.zip"],
)
register_toolchains( register_toolchains(
"@nodejs_toolchains//:all", "@nodejs_toolchains//:all",
) )

View File

@@ -6,16 +6,19 @@ provide:
- "*/ql/consistency-queries/qlpack.yml" - "*/ql/consistency-queries/qlpack.yml"
- "*/ql/automodel/src/qlpack.yml" - "*/ql/automodel/src/qlpack.yml"
- "*/ql/automodel/test/qlpack.yml" - "*/ql/automodel/test/qlpack.yml"
- "*/extractor-pack/codeql-extractor.yml"
- "python/extractor/qlpack.yml" - "python/extractor/qlpack.yml"
- "shared/**/qlpack.yml" - "shared/**/qlpack.yml"
- "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml" - "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml"
- "go/ql/config/legacy-support/qlpack.yml" - "go/ql/config/legacy-support/qlpack.yml"
- "go/build/codeql-extractor-go/codeql-extractor.yml"
- "csharp/ql/campaigns/Solorigate/lib/qlpack.yml" - "csharp/ql/campaigns/Solorigate/lib/qlpack.yml"
- "csharp/ql/campaigns/Solorigate/src/qlpack.yml" - "csharp/ql/campaigns/Solorigate/src/qlpack.yml"
- "csharp/ql/campaigns/Solorigate/test/qlpack.yml" - "csharp/ql/campaigns/Solorigate/test/qlpack.yml"
- "misc/legacy-support/*/qlpack.yml" - "misc/legacy-support/*/qlpack.yml"
- "misc/suite-helpers/qlpack.yml" - "misc/suite-helpers/qlpack.yml"
- "ruby/extractor-pack/codeql-extractor.yml"
- "swift/extractor-pack/codeql-extractor.yml"
- "ql/extractor-pack/codeql-extractor.yml"
- ".github/codeql/extensions/**/codeql-pack.yml" - ".github/codeql/extensions/**/codeql-pack.yml"
versionPolicies: versionPolicies:

View File

@@ -28,7 +28,6 @@
"/*- Yaml dbscheme -*/", "/*- Yaml dbscheme -*/",
"/*- Blame dbscheme -*/", "/*- Blame dbscheme -*/",
"/*- JSON dbscheme -*/", "/*- JSON dbscheme -*/",
"/*- Python dbscheme -*/", "/*- Python dbscheme -*/"
"/*- Empty location -*/"
] ]
} }

View File

@@ -61,6 +61,10 @@
"java/ql/src/utils/modelgenerator/internal/CaptureModels.qll", "java/ql/src/utils/modelgenerator/internal/CaptureModels.qll",
"csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll" "csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll"
], ],
"Model as Data Generation Java/C# - CaptureModelsPrinting": [
"java/ql/src/utils/modelgenerator/internal/CaptureModelsPrinting.qll",
"csharp/ql/src/utils/modelgenerator/internal/CaptureModelsPrinting.qll"
],
"Sign Java/C#": [ "Sign Java/C#": [
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll", "java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll" "csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll"
@@ -181,6 +185,11 @@
"cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll",
"cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysisImports.qll" "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysisImports.qll"
], ],
"C++ IR ValueNumberingImports": [
"cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll",
"cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll",
"cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingImports.qll"
],
"IR SSA SSAConstruction": [ "IR SSA SSAConstruction": [
"cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll",
"cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll" "cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll"

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

@@ -6,7 +6,7 @@ pkg_files(
["**"], ["**"],
exclude = ["BUILD.bazel"], exclude = ["BUILD.bazel"],
), ),
prefix = "downgrades", prefix = "cpp/downgrades",
strip_prefix = strip_prefix.from_pkg(), strip_prefix = strip_prefix.from_pkg(),
visibility = ["//cpp:__pkg__"], visibility = ["//cpp:__pkg__"],
) )

View File

@@ -5,9 +5,11 @@ package(default_visibility = ["//cpp:__pkg__"])
pkg_files( pkg_files(
name = "dbscheme", name = "dbscheme",
srcs = ["semmlecode.cpp.dbscheme"], srcs = ["semmlecode.cpp.dbscheme"],
prefix = "cpp",
) )
pkg_files( pkg_files(
name = "dbscheme-stats", name = "dbscheme-stats",
srcs = ["semmlecode.cpp.dbscheme.stats"], srcs = ["semmlecode.cpp.dbscheme.stats"],
prefix = "cpp",
) )

View File

@@ -1,43 +1,3 @@
## 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
* The syntax for models-as-data rows has been extended to make it easier to select sources, sinks, and summaries that involve templated functions and classes. Additionally, the syntax has also been extended to make it easier to specify models with arbitrary levels of indirection. See `dataflow/ExternalFlow.qll` for the updated documentation and specification for the model format.
* It is now possible to extend the classes `AllocationFunction` and `DeallocationFunction` via data extensions. Extensions of these classes should be added to the `lib/ext/allocation` and `lib/ext/deallocation` directories respectively.
### Minor Analysis Improvements
* The queries "Potential double free" (`cpp/double-free`) and "Potential use after free" (`cpp/use-after-free`) now produce fewer false positives.
* The "Guards" library (`semmle.code.cpp.controlflow.Guards`) now also infers guards from calls to the builtin operation `__builtin_expect`. As a result, some queries may produce fewer false positives.
## 1.1.1
No user-facing changes.
## 1.1.0
### New Features
* Data models can now be added with data extensions. In this way source, sink and summary models can be added in extension `.model.yml` files, rather than by writing classes in QL code. New models should be added in the `lib/ext` folder.
### Minor Analysis Improvements
* A partial model for the `Boost.Asio` network library has been added. This includes sources, sinks and summaries for certain functions in `Boost.Asio`, such as `read_until` and `write`.
## 1.0.0
### Breaking Changes
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
## 0.13.1 ## 0.13.1
No user-facing changes. No user-facing changes.

View File

@@ -1,5 +1,4 @@
## 1.0.0 ---
category: breaking
### Breaking Changes ---
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0. * CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.

View File

@@ -1,9 +0,0 @@
## 1.1.0
### New Features
* Data models can now be added with data extensions. In this way source, sink and summary models can be added in extension `.model.yml` files, rather than by writing classes in QL code. New models should be added in the `lib/ext` folder.
### Minor Analysis Improvements
* A partial model for the `Boost.Asio` network library has been added. This includes sources, sinks and summaries for certain functions in `Boost.Asio`, such as `read_until` and `write`.

View File

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

View File

@@ -1,11 +0,0 @@
## 1.2.0
### New Features
* The syntax for models-as-data rows has been extended to make it easier to select sources, sinks, and summaries that involve templated functions and classes. Additionally, the syntax has also been extended to make it easier to specify models with arbitrary levels of indirection. See `dataflow/ExternalFlow.qll` for the updated documentation and specification for the model format.
* It is now possible to extend the classes `AllocationFunction` and `DeallocationFunction` via data extensions. Extensions of these classes should be added to the `lib/ext/allocation` and `lib/ext/deallocation` directories respectively.
### Minor Analysis Improvements
* The queries "Potential double free" (`cpp/double-free`) and "Potential use after free" (`cpp/use-after-free`) now produce fewer false positives.
* The "Guards" library (`semmle.code.cpp.controlflow.Guards`) now also infers guards from calls to the builtin operation `__builtin_expect`. As a result, some queries may produce fewer false positives.

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,2 +1,2 @@
--- ---
lastReleaseVersion: 1.3.0 lastReleaseVersion: 0.13.1

View File

@@ -1,25 +0,0 @@
# partial model of the Boost::Asio network library
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: sourceModel
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
- ["boost::asio", "", False, "read", "", "", "Argument[*1]", "remote", "manual"]
- ["boost::asio", "", False, "read_at", "", "", "Argument[*2]", "remote", "manual"]
- ["boost::asio", "", False, "read_until", "", "", "Argument[*1]", "remote", "manual"]
- ["boost::asio", "", False, "async_read", "", "", "Argument[*1]", "remote", "manual"]
- ["boost::asio", "", False, "async_read_at", "", "", "Argument[*2]", "remote", "manual"]
- ["boost::asio", "", False, "async_read_until", "", "", "Argument[*1]", "remote", "manual"]
- addsTo:
pack: codeql/cpp-all
extensible: sinkModel
data: # namespace, type, subtypes, name, signature, ext, input, kind, provenance
- ["boost::asio", "", False, "write", "", "", "Argument[*1]", "remote-sink", "manual"]
- ["boost::asio", "", False, "write_at", "", "", "Argument[*2]", "remote-sink", "manual"]
- ["boost::asio", "", False, "async_write", "", "", "Argument[*1]", "remote-sink", "manual"]
- ["boost::asio", "", False, "async_write_at", "", "", "Argument[*2]", "remote-sink", "manual"]
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
- ["boost::asio", "", False, "buffer", "", "", "Argument[*0]", "ReturnValue", "taint", "manual"]

View File

@@ -1,7 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: allocationFunctionModel
data:
- ["", "", False, "kmem_alloc", "0", "", "", True]
- ["", "", False, "kmem_zalloc", "0", "", "", True]

View File

@@ -1,7 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: allocationFunctionModel
data:
- ["", "", False, "g_malloc", "0", "", "", True]
- ["", "", False, "g_try_malloc", "0", "", "", True]

View File

@@ -1,10 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: allocationFunctionModel
data:
- ["", "", False, "CRYPTO_malloc", "0", "", "", True]
- ["", "", False, "CRYPTO_zalloc", "0", "", "", True]
- ["", "", False, "CRYPTO_secure_malloc", "0", "", "", True]
- ["", "", False, "CRYPTO_secure_zalloc", "0", "", "", True]

View File

@@ -1,15 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: allocationFunctionModel
data:
- ["", "", False, "malloc", "0", "", "", True]
- ["std", "", False, "malloc", "0", "", "", True]
- ["bsl", "", False, "malloc", "0", "", "", True]
- ["", "", False, "alloca", "0", "", "", False]
- ["", "", False, "__builtin_alloca", "0", "", "", False]
- ["", "", False, "_alloca", "0", "", "", False]
- ["", "", False, "_malloca", "0", "", "", False]
- ["", "", False, "calloc", "1", "0", "", True]
- ["std", "", False, "calloc", "1", "0", "", True]
- ["bsl", "", False, "calloc", "1", "0", "", True]

View File

@@ -1,29 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: allocationFunctionModel
data:
- ["", "", False, "MmAllocateContiguousMemory", "0", "", "", True]
- ["", "", False, "MmAllocateContiguousNodeMemory", "0", "", "", True]
- ["", "", False, "MmAllocateContiguousMemorySpecifyCache", "0", "", "", True]
- ["", "", False, "MmAllocateContiguousMemorySpecifyCacheNode", "0", "", "", True]
- ["", "", False, "MmAllocateNonCachedMemory", "0", "", "", True]
- ["", "", False, "MmAllocateMappingAddress", "0", "", "", True]
- ["", "", False, "CoTaskMemAlloc", "0", "", "", True]
- ["", "", False, "ExAllocatePool", "1", "", "", True]
- ["", "", False, "ExAllocatePool2", "1", "", "", True]
- ["", "", False, "ExAllocatePool3", "1", "", "", True]
- ["", "", False, "ExAllocatePoolWithTag", "1", "", "", True]
- ["", "", False, "ExAllocatePoolWithTagPriority", "1", "", "", True]
- ["", "", False, "ExAllocatePoolWithQuota", "1", "", "", True]
- ["", "", False, "ExAllocatePoolWithQuotaTag", "1", "", "", True]
- ["", "", False, "ExAllocatePoolZero", "1", "", "", True]
- ["", "", False, "IoAllocateMdl", "1", "", "", True]
- ["", "", False, "IoAllocateErrorLogEntry", "1", "", "", True]
- ["", "", False, "LocalAlloc", "1", "", "", True]
- ["", "", False, "GlobalAlloc", "1", "", "", True]
- ["", "", False, "VirtualAlloc", "1", "", "", True]
- ["", "", False, "HeapAlloc", "2", "", "", True]
- ["", "", False, "MmAllocatePagesForMdl", "3", "", "", True]
- ["", "", False, "MmAllocatePagesForMdlEx", "3", "", "", True]
- ["", "", False, "MmAllocateNodePagesForMdlEx", "3", "", "", True]

View File

@@ -1,5 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: allocationFunctionModel
data: []

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
- ["bsl", "array", True, "at", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "array", True, "begin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "array", True, "cbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "array", True, "data", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "array", True, "operator[]", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "array", True, "rbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "array", True, "rcbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "array", True, "front", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "array", True, "back", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]

View File

@@ -1,73 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
- ["bsl", "deque<T,Allocator>", True, "assign", "(size_type,const T &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "assign<InputIt>", "(InputIt,InputIt)", "", "Argument[0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "at", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "back", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "begin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque", True, "cbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque", True, "deque", "(const deque &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "deque", "(deque &&)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace", "", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace", "", "", "Argument[*@2]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace", "", "", "Argument[*@3]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace", "", "", "Argument[*@4]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace", "", "", "Argument[*@5]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_back", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_back", "", "", "Argument[*@0]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_back", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_back", "", "", "Argument[*@1]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_back", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_back", "", "", "Argument[*@2]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_back", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_back", "", "", "Argument[*@3]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_back", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_back", "", "", "Argument[*@4]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_back", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_back", "", "", "Argument[*@5]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_back", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_front", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_front", "", "", "Argument[*@0]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_front", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_front", "", "", "Argument[*@1]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_front", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_front", "", "", "Argument[*@2]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_front", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_front", "", "", "Argument[*@3]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_front", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_front", "", "", "Argument[*@4]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_front", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_front", "", "", "Argument[*@5]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "emplace_front", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "front", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[1].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque", True, "operator=", "", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "operator[]", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "deque", True, "push_back", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "push_front", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque", True, "rbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque", True, "rcbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque<T,Allocator>", True, "deque", "(const deque &,const Allocator &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque<T,Allocator>", True, "deque", "(deque &&,const Allocator &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque<T,Allocator>", True, "deque", "(size_type,const T &,const Allocator &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque<T,Allocator>", True, "deque<InputIterator>", "(InputIterator,InputIterator,const Allocator &)", "", "Argument[0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[*@2]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "deque<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "deque<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]

View File

@@ -1,56 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
- ["bsl", "forward_list", True, "insert_after<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list<T>", True, "insert_after", "(const_iterator,const T &)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list<T>", True, "insert_after", "(const_iterator,size_type,const T &)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list<T,Allocator>", True, "assign", "(size_type,const T &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "assign<InputIt>", "(InputIt,InputIt)", "", "Argument[0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "begin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "cbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_after", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_after", "", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_after", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_after", "", "", "Argument[*@2]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_after", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_after", "", "", "Argument[*@3]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_after", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_after", "", "", "Argument[*@4]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_after", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_after", "", "", "Argument[*@5]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_after", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_front", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_front", "", "", "Argument[*@0]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_front", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_front", "", "", "Argument[*@1]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_front", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_front", "", "", "Argument[*@2]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_front", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_front", "", "", "Argument[*@3]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_front", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_front", "", "", "Argument[*@4]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_front", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_front", "", "", "Argument[*@5]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "forward_list", True, "emplace_front", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "forward_list", True, "forward_list", "(const forward_list &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "forward_list", "(forward_list &&)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "front", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "forward_list", True, "insert_after<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[1].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "insert_after<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "operator=", "", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "push_front", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "rbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list", True, "rcbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list<T,Allocator>", True, "forward_list", "(const forward_list &,const Allocator &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list<T,Allocator>", True, "forward_list", "(forward_list &&,const Allocator &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list<T,Allocator>", True, "forward_list", "(InputIterator,InputIterator,const Allocator &)", "", "Argument[0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list<T,Allocator>", True, "forward_list", "(size_type,const T &,const Allocator &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list<T>", True, "insert_after", "(const_iterator,const T &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list<T>", True, "insert_after", "(const_iterator,const T &)", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list<T>", True, "insert_after", "(const_iterator,size_type,const T &)", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list<T>", True, "insert_after", "(const_iterator,size_type,const T &)", "", "Argument[*@2]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list<T>", True, "insert_after", "(const_iterator,T &&)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "forward_list<T>", True, "insert_after", "(const_iterator,T &&)", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "forward_list<T>", True, "insert_after", "(const_iterator,T &&)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]

View File

@@ -1,71 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
- ["bsl", "list<T,Allocator>", True, "assign", "(size_type,const T &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "assign<InputIt>", "(InputIt,InputIt)", "", "Argument[0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "back", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "begin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "list", True, "cbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace", "", "", "Argument[*@1]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace", "", "", "Argument[*@2]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace", "", "", "Argument[*@3]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace", "", "", "Argument[*@4]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace", "", "", "Argument[*@5]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace_back", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace_back", "", "", "Argument[*@0]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace_back", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace_back", "", "", "Argument[*@1]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace_back", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace_back", "", "", "Argument[*@2]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace_back", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace_back", "", "", "Argument[*@3]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace_back", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace_back", "", "", "Argument[*@4]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace_back", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace_back", "", "", "Argument[*@5]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace_back", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace_front", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace_front", "", "", "Argument[*@0]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace_front", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace_front", "", "", "Argument[*@1]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace_front", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace_front", "", "", "Argument[*@2]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace_front", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace_front", "", "", "Argument[*@3]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace_front", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace_front", "", "", "Argument[*@4]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace_front", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "emplace_front", "", "", "Argument[*@5]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "emplace_front", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "front", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "list", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "list", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[1].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "list", True, "list", "(const list &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "list", "(list &&)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "operator=", "", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "push_back", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "push_front", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list", True, "rbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "list", True, "rcbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "list<T,Allocator>", True, "list", "(const list &,const Allocator &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list<T,Allocator>", True, "list", "(list &&,const Allocator &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list<T,Allocator>", True, "list", "(size_type,const T &,const Allocator &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list<T,Allocator>", True, "list<InputIterator>", "(InputIterator,InputIterator,const Allocator &)", "", "Argument[0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "list<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "list<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[*@2]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "list<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "list<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "list<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "list<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]

View File

@@ -1,60 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
- ["bsl", "vector<T,Allocator>", True, "assign", "(size_type,const T &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "assign<InputIt>", "(InputIt,InputIt)", "", "Argument[0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "at", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "vector", True, "back", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "vector", True, "begin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector", True, "cbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector", True, "data", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "vector", True, "emplace", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace", "", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace", "", "", "Argument[*@2]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace", "", "", "Argument[*@3]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace", "", "", "Argument[*@4]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace", "", "", "Argument[*@5]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace_back", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace_back", "", "", "Argument[*@0]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "vector", True, "emplace_back", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace_back", "", "", "Argument[*@1]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "vector", True, "emplace_back", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace_back", "", "", "Argument[*@2]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "vector", True, "emplace_back", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace_back", "", "", "Argument[*@3]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "vector", True, "emplace_back", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace_back", "", "", "Argument[*@4]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "vector", True, "emplace_back", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "emplace_back", "", "", "Argument[*@5]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "vector", True, "emplace_back", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "vector", True, "front", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "vector", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[1].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector", True, "operator=", "", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "operator[]", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["bsl", "vector", True, "push_back", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "rbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector", True, "rcbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector", True, "vector", "(const vector &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector", True, "vector", "(vector &&)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector<T,Allocator>", True, "vector", "(const vector &,const Allocator &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector<T,Allocator>", True, "vector", "(size_type,const T &,const Allocator &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector<T,Allocator>", True, "vector", "(vector &&,const Allocator &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector<T,Allocator>", True, "vector<InputIterator>", "(InputIterator,InputIterator,const Allocator &)", "", "Argument[0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[*@2]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["bsl", "vector<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["bsl", "vector<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]

View File

@@ -1,8 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: deallocationFunctionModel
data:
- ["", "", False, "pool_put", "1"]
- ["", "", False, "pool_cache_put", "1"]
- ["", "", False, "kmem_free", "0"]

View File

@@ -1,42 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: deallocationFunctionModel
data:
- ["", "", False, "free", "0"]
- ["std", "", False, "free", "0"]
- ["bsl", "", False, "free", "0"]
- ["", "", False, "realloc", "0"]
- ["std", "", False, "realloc", "0"]
- ["bsl", "", False, "realloc", "0"]
- ["", "", False, "CRYPTO_free", "0"]
- ["", "", False, "CRYPTO_secure_free", "0"]
- ["", "", False, "g_free", "0"]
- ["", "", False, "ExFreePool", "0"]
- ["", "", False, "ExFreePoolWithTag", "0"]
- ["", "", False, "ExDeleteTimer", "0"]
- ["", "", False, "IoFreeIrp", "0"]
- ["", "", False, "IoFreeMdl", "0"]
- ["", "", False, "IoFreeErrorLogEntry", "0"]
- ["", "", False, "IoFreeWorkItem", "0"]
- ["", "", False, "MmFreeContiguousMemory", "0"]
- ["", "", False, "MmFreeContiguousMemorySpecifyCache", "0"]
- ["", "", False, "MmFreeNonCachedMemory", "0"]
- ["", "", False, "MmFreeMappingAddress", "0"]
- ["", "", False, "MmFreePagesFromMdl", "0"]
- ["", "", False, "MmUnmapReservedMapping", "0"]
- ["", "", False, "MmUnmapLockedPages", "0"]
- ["", "", False, "NdisFreeGenericObject", "0"]
- ["", "", False, "NdisFreeMemory", "0"]
- ["", "", False, "NdisFreeMemoryWithTag", "0"]
- ["", "", False, "NdisFreeMdl", "0"]
- ["", "", False, "NdisFreeNetBufferListPool", "0"]
- ["", "", False, "NdisFreeNetBufferPool", "0"]
- ["", "", False, "LocalFree", "0"]
- ["", "", False, "GlobalFree", "0"]
- ["", "", False, "LocalReAlloc", "0"]
- ["", "", False, "GlobalReAlloc", "0"]
- ["", "", False, "VirtualFree", "0"]
- ["", "", False, "CoTaskMemFree", "0"]
- ["", "", False, "CoTaskMemRealloc", "0"]
- ["", "", False, "SysFreeString", "0"]

View File

@@ -1,41 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: deallocationFunctionModel
data:
- ["", "", False, "ExFreePool", "0"]
- ["", "", False, "ExFreePoolWithTag", "0"]
- ["", "", False, "ExDeleteTimer", "0"]
- ["", "", False, "IoFreeIrp", "0"]
- ["", "", False, "IoFreeMdl", "0"]
- ["", "", False, "IoFreeErrorLogEntry", "0"]
- ["", "", False, "IoFreeWorkItem", "0"]
- ["", "", False, "MmFreeContiguousMemory", "0"]
- ["", "", False, "MmFreeContiguousMemorySpecifyCache", "0"]
- ["", "", False, "MmFreeNonCachedMemory", "0"]
- ["", "", False, "MmFreeMappingAddress", "0"]
- ["", "", False, "MmFreePagesFromMdl", "0"]
- ["", "", False, "MmUnmapReservedMapping", "0"]
- ["", "", False, "MmUnmapLockedPages", "0"]
- ["", "", False, "NdisFreeGenericObject", "0"]
- ["", "", False, "NdisFreeMemory", "0"]
- ["", "", False, "NdisFreeMemoryWithTag", "0"]
- ["", "", False, "NdisFreeMdl", "0"]
- ["", "", False, "NdisFreeNetBufferListPool", "0"]
- ["", "", False, "NdisFreeNetBufferPool", "0"]
- ["", "", False, "LocalFree", "0"]
- ["", "", False, "GlobalFree", "0"]
- ["", "", False, "LocalReAlloc", "0"]
- ["", "", False, "GlobalReAlloc", "0"]
- ["", "", False, "VirtualFree", "0"]
- ["", "", False, "CoTaskMemFree", "0"]
- ["", "", False, "CoTaskMemRealloc", "0"]
- ["", "", False, "SysFreeString", "0"]
- ["", "", False, "ExFreeToLookasideListEx", "1"]
- ["", "", False, "ExFreeToPagedLookasideList", "1"]
- ["", "", False, "ExFreeToNPagedLookasideList", "1"]
- ["", "", False, "NdisFreeMemoryWithTagPriority", "1"]
- ["", "", False, "StorPortFreeMdl", "1"]
- ["", "", False, "StorPortFreePool", "1"]
- ["", "", False, "HeapFree", "2"]
- ["", "", False, "HeapReAlloc", "2"]

View File

@@ -1,5 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: deallocationFunctionModel
data: []

View File

@@ -1,15 +0,0 @@
extensions:
# Make sure that the extensible model predicates have at least one definition
# to avoid errors about undefined extensionals.
- addsTo:
pack: codeql/cpp-all
extensible: sourceModel
data: []
- addsTo:
pack: codeql/cpp-all
extensible: sinkModel
data: []
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
data: []

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", "array", True, "at", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "array", True, "begin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "array", True, "cbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "array", True, "data", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "array", True, "operator[]", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "array", True, "rbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "array", True, "rcbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "array", True, "front", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "array", True, "back", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]

View File

@@ -1,73 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
- ["std", "deque<T,Allocator>", True, "assign", "(size_type,const T &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "assign<InputIt>", "(InputIt,InputIt)", "", "Argument[0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "at", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "back", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "begin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque", True, "cbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque", True, "deque", "(const deque &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "deque", "(deque &&)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace", "", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace", "", "", "Argument[*@2]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace", "", "", "Argument[*@3]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace", "", "", "Argument[*@4]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace", "", "", "Argument[*@5]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace_back", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace_back", "", "", "Argument[*@0]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "emplace_back", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace_back", "", "", "Argument[*@1]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "emplace_back", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace_back", "", "", "Argument[*@2]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "emplace_back", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace_back", "", "", "Argument[*@3]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "emplace_back", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace_back", "", "", "Argument[*@4]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "emplace_back", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace_back", "", "", "Argument[*@5]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "emplace_back", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "emplace_front", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace_front", "", "", "Argument[*@0]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "emplace_front", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace_front", "", "", "Argument[*@1]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "emplace_front", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace_front", "", "", "Argument[*@2]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "emplace_front", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace_front", "", "", "Argument[*@3]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "emplace_front", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace_front", "", "", "Argument[*@4]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "emplace_front", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "emplace_front", "", "", "Argument[*@5]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "emplace_front", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "front", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[1].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque", True, "operator=", "", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "operator[]", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "deque", True, "push_back", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "push_front", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque", True, "rbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque", True, "rcbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque<T,Allocator>", True, "deque", "(const deque &,const Allocator &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque<T,Allocator>", True, "deque", "(deque &&,const Allocator &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque<T,Allocator>", True, "deque", "(size_type,const T &,const Allocator &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque<T,Allocator>", True, "deque<InputIterator>", "(InputIterator,InputIterator,const Allocator &)", "", "Argument[0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[*@2]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "deque<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "deque<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]

View File

@@ -1,56 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
- ["std", "forward_list", True, "insert_after<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list<T>", True, "insert_after", "(const_iterator,const T &)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list<T>", True, "insert_after", "(const_iterator,size_type,const T &)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list<T,Allocator>", True, "assign", "(size_type,const T &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "assign<InputIt>", "(InputIt,InputIt)", "", "Argument[0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "begin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list", True, "cbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_after", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_after", "", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_after", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_after", "", "", "Argument[*@2]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_after", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_after", "", "", "Argument[*@3]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_after", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_after", "", "", "Argument[*@4]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_after", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_after", "", "", "Argument[*@5]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_after", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_front", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_front", "", "", "Argument[*@0]", "ReturnValue[*@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_front", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_front", "", "", "Argument[*@1]", "ReturnValue[*@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_front", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_front", "", "", "Argument[*@2]", "ReturnValue[*@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_front", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_front", "", "", "Argument[*@3]", "ReturnValue[*@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_front", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_front", "", "", "Argument[*@4]", "ReturnValue[*@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_front", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_front", "", "", "Argument[*@5]", "ReturnValue[*@]", "value", "manual"]
- ["std", "forward_list", True, "emplace_front", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "forward_list", True, "forward_list", "(const forward_list &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "forward_list", "(forward_list &&)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "front", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "forward_list", True, "insert_after<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[1].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "insert_after<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list", True, "operator=", "", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "push_front", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list", True, "rbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list", True, "rcbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list<T,Allocator>", True, "forward_list", "(const forward_list &,const Allocator &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list<T,Allocator>", True, "forward_list", "(forward_list &&,const Allocator &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list<T,Allocator>", True, "forward_list", "(InputIterator,InputIterator,const Allocator &)", "", "Argument[0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list<T,Allocator>", True, "forward_list", "(size_type,const T &,const Allocator &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list<T>", True, "insert_after", "(const_iterator,const T &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list<T>", True, "insert_after", "(const_iterator,const T &)", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list<T>", True, "insert_after", "(const_iterator,size_type,const T &)", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list<T>", True, "insert_after", "(const_iterator,size_type,const T &)", "", "Argument[*@2]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list<T>", True, "insert_after", "(const_iterator,T &&)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "forward_list<T>", True, "insert_after", "(const_iterator,T &&)", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "forward_list<T>", True, "insert_after", "(const_iterator,T &&)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]

View File

@@ -1,11 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
- ["std", "iterator", True, "operator*", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "iterator", True, "operator->", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "iterator", True, "iterator", "", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["__gnu_cxx", "__normal_iterator", True, "operator*", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["__gnu_cxx", "__normal_iterator", True, "operator->", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["__gnu_cxx", "__normal_iterator", True, "__normal_iterator", "", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]

View File

@@ -1,71 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
- ["std", "list<T,Allocator>", True, "assign", "(size_type,const T &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "assign<InputIt>", "(InputIt,InputIt)", "", "Argument[0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "back", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "list", True, "begin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list", True, "cbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list", True, "emplace", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace", "", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list", True, "emplace", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace", "", "", "Argument[*@2]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list", True, "emplace", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace", "", "", "Argument[*@3]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list", True, "emplace", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace", "", "", "Argument[*@4]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list", True, "emplace", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace", "", "", "Argument[*@5]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list", True, "emplace", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list", True, "emplace_back", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace_back", "", "", "Argument[*@0]", "ReturnValue[*@]", "value", "manual"]
- ["std", "list", True, "emplace_back", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace_back", "", "", "Argument[*@1]", "ReturnValue[*@]", "value", "manual"]
- ["std", "list", True, "emplace_back", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace_back", "", "", "Argument[*@2]", "ReturnValue[*@]", "value", "manual"]
- ["std", "list", True, "emplace_back", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace_back", "", "", "Argument[*@3]", "ReturnValue[*@]", "value", "manual"]
- ["std", "list", True, "emplace_back", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace_back", "", "", "Argument[*@4]", "ReturnValue[*@]", "value", "manual"]
- ["std", "list", True, "emplace_back", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace_back", "", "", "Argument[*@5]", "ReturnValue[*@]", "value", "manual"]
- ["std", "list", True, "emplace_back", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "list", True, "emplace_front", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace_front", "", "", "Argument[*@0]", "ReturnValue[*@]", "value", "manual"]
- ["std", "list", True, "emplace_front", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace_front", "", "", "Argument[*@1]", "ReturnValue[*@]", "value", "manual"]
- ["std", "list", True, "emplace_front", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace_front", "", "", "Argument[*@2]", "ReturnValue[*@]", "value", "manual"]
- ["std", "list", True, "emplace_front", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace_front", "", "", "Argument[*@3]", "ReturnValue[*@]", "value", "manual"]
- ["std", "list", True, "emplace_front", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace_front", "", "", "Argument[*@4]", "ReturnValue[*@]", "value", "manual"]
- ["std", "list", True, "emplace_front", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "emplace_front", "", "", "Argument[*@5]", "ReturnValue[*@]", "value", "manual"]
- ["std", "list", True, "emplace_front", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "list", True, "front", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "list", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[1].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list", True, "list", "(const list &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "list", "(list &&)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "operator=", "", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "push_back", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "push_front", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list", True, "rbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list", True, "rcbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list<T,Allocator>", True, "list", "(const list &,const Allocator &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list<T,Allocator>", True, "list", "(list &&,const Allocator &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list<T,Allocator>", True, "list", "(size_type,const T &,const Allocator &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list<T,Allocator>", True, "list<InputIterator>", "(InputIterator,InputIterator,const Allocator &)", "", "Argument[0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[*@2]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "list<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "list<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]

View File

@@ -1,60 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
- ["std", "vector<T,Allocator>", True, "assign", "(size_type,const T &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "assign<InputIt>", "(InputIt,InputIt)", "", "Argument[0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "at", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "vector", True, "back", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "vector", True, "begin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector", True, "cbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector", True, "data", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "vector", True, "emplace", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace", "", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace", "", "", "Argument[*@2]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace", "", "", "Argument[*@3]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace", "", "", "Argument[*@4]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace", "", "", "Argument[*@5]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace_back", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace_back", "", "", "Argument[*@0]", "ReturnValue[*@]", "value", "manual"]
- ["std", "vector", True, "emplace_back", "", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace_back", "", "", "Argument[*@1]", "ReturnValue[*@]", "value", "manual"]
- ["std", "vector", True, "emplace_back", "", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace_back", "", "", "Argument[*@2]", "ReturnValue[*@]", "value", "manual"]
- ["std", "vector", True, "emplace_back", "", "", "Argument[*@3]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace_back", "", "", "Argument[*@3]", "ReturnValue[*@]", "value", "manual"]
- ["std", "vector", True, "emplace_back", "", "", "Argument[*@4]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace_back", "", "", "Argument[*@4]", "ReturnValue[*@]", "value", "manual"]
- ["std", "vector", True, "emplace_back", "", "", "Argument[*@5]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "emplace_back", "", "", "Argument[*@5]", "ReturnValue[*@]", "value", "manual"]
- ["std", "vector", True, "emplace_back", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "vector", True, "front", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "vector", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[1].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "insert<InputIt>", "(const_iterator,InputIt,InputIt)", "", "Argument[1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector", True, "operator=", "", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "operator[]", "", "", "Argument[-1].Element[@]", "ReturnValue[*@]", "value", "manual"]
- ["std", "vector", True, "push_back", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "rbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector", True, "rcbegin", "", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector", True, "vector", "(const vector &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector", True, "vector", "(vector &&)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector<T,Allocator>", True, "vector", "(const vector &,const Allocator &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector<T,Allocator>", True, "vector", "(size_type,const T &,const Allocator &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector<T,Allocator>", True, "vector", "(vector &&,const Allocator &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector<T,Allocator>", True, "vector<InputIterator>", "(InputIterator,InputIterator,const Allocator &)", "", "Argument[0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector<T>", True, "insert", "(const_iterator,const T &)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[*@2]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[*@2]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector<T>", True, "insert", "(const_iterator,size_type,const T &)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[*@1]", "Argument[-1].Element[@]", "value", "manual"]
- ["std", "vector<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[*@1]", "ReturnValue.Element[@]", "value", "manual"]
- ["std", "vector<T>", True, "insert", "(const_iterator,T &&)", "", "Argument[-1].Element[@]", "ReturnValue.Element[@]", "value", "manual"]

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all name: codeql/cpp-all
version: 1.3.0 version: 1.0.0-dev
groups: cpp groups: cpp
dbscheme: semmlecode.cpp.dbscheme dbscheme: semmlecode.cpp.dbscheme
extractor: cpp extractor: cpp
@@ -14,8 +14,4 @@ dependencies:
codeql/tutorial: ${workspace} codeql/tutorial: ${workspace}
codeql/util: ${workspace} codeql/util: ${workspace}
codeql/xml: ${workspace} codeql/xml: ${workspace}
dataExtensions:
- ext/*.model.yml
- ext/deallocation/*.model.yml
- ext/allocation/*.model.yml
warnOnImplicitThis: true warnOnImplicitThis: true

View File

@@ -410,10 +410,6 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
or or
orphaned_variables(underlyingElement(this), unresolveElement(result)) orphaned_variables(underlyingElement(this), unresolveElement(result))
} }
override predicate isStatic() {
super.isStatic() or orphaned_variables(underlyingElement(this), _)
}
} }
/** /**

View File

@@ -59,7 +59,8 @@ class MatchValue extends AbstractValue, TMatchValue {
} }
/** /**
* A Boolean condition in the AST that guards one or more basic blocks. * A Boolean condition in the AST that guards one or more basic blocks. This includes
* operands of logical operators but not switch statements.
*/ */
cached cached
class GuardCondition extends Expr { class GuardCondition extends Expr {
@@ -365,42 +366,15 @@ private predicate nonExcludedIRAndBasicBlock(IRBlock irb, BasicBlock controlled)
} }
/** /**
* A Boolean condition in the IR that guards one or more basic blocks. * A Boolean condition in the IR that guards one or more basic blocks. This includes
* * operands of logical operators but not switch statements. Note that `&&` and `||`
* Note that `&&` and `||` don't have an explicit representation in the IR, * don't have an explicit representation in the IR, and therefore will not appear as
* and therefore will not appear as IRGuardConditions. * IRGuardConditions.
*/ */
cached cached
class IRGuardCondition extends Instruction { class IRGuardCondition extends Instruction {
Instruction branch; Instruction branch;
/*
* An `IRGuardCondition` supports reasoning about four different kinds of
* relations:
* 1. A unary equality relation of the form `e == k`
* 2. A binary equality relation of the form `e1 == e2 + k`
* 3. A unary inequality relation of the form `e < k`
* 4. A binary inequality relation of the form `e1 < e2 + k`
*
* where `k` is a constant.
*
* Furthermore, the unary relations (i.e., case 1 and case 3) are also
* inferred from `switch` statement guards: equality relations are inferred
* from the unique `case` statement, if any, and inequality relations are
* inferred from the [case range](https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html)
* gcc extension.
*
* The implementation of all four follows the same structure: Each relation
* has a cached user-facing predicate that. For example,
* `GuardCondition::comparesEq` calls `compares_eq`. This predicate has
* several cases that recursively decompose the relation to bring it to a
* canonical form (i.e., a relation of the form `e1 == e2 + k`). The base
* case for this relation (i.e., `simple_comparison_eq`) handles
* `CompareEQInstruction`s and `CompareNEInstruction`, and recursive
* predicates (e.g., `complex_eq`) rewrites larger expressions such as
* `e1 + k1 == e2 + k2` into canonical the form `e1 == e2 + (k2 - k1)`.
*/
cached cached
IRGuardCondition() { branch = getBranchForCondition(this) } IRGuardCondition() { branch = getBranchForCondition(this) }
@@ -761,8 +735,6 @@ private predicate compares_eq(
exists(AbstractValue dual | value = dual.getDualValue() | exists(AbstractValue dual | value = dual.getDualValue() |
compares_eq(test.(LogicalNotInstruction).getUnary(), left, right, k, areEqual, dual) compares_eq(test.(LogicalNotInstruction).getUnary(), left, right, k, areEqual, dual)
) )
or
compares_eq(test.(BuiltinExpectCallInstruction).getCondition(), left, right, k, areEqual, value)
} }
/** /**
@@ -804,9 +776,7 @@ private predicate unary_compares_eq(
Instruction test, Operand op, int k, boolean areEqual, boolean inNonZeroCase, AbstractValue value Instruction test, Operand op, int k, boolean areEqual, boolean inNonZeroCase, AbstractValue value
) { ) {
/* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */ /* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */
exists(AbstractValue v | exists(AbstractValue v | unary_simple_comparison_eq(test, op, k, inNonZeroCase, v) |
unary_simple_comparison_eq(test, k, inNonZeroCase, v) and op.getDef() = test
|
areEqual = true and value = v areEqual = true and value = v
or or
areEqual = false and value = v.getDualValue() areEqual = false and value = v.getDualValue()
@@ -832,9 +802,6 @@ private predicate unary_compares_eq(
int_value(const) = k1 and int_value(const) = k1 and
k = k1 + k2 k = k1 + k2
) )
or
unary_compares_eq(test.(BuiltinExpectCallInstruction).getCondition(), op, k, areEqual,
inNonZeroCase, value)
} }
/** Rearrange various simple comparisons into `left == right + k` form. */ /** Rearrange various simple comparisons into `left == right + k` form. */
@@ -854,55 +821,45 @@ private predicate simple_comparison_eq(
value.(BooleanValue).getValue() = false value.(BooleanValue).getValue() = false
} }
/**
* Holds if `test` is an instruction that is part of test that eventually is
* used in a conditional branch.
*/
private predicate relevantUnaryComparison(Instruction test) {
not test instanceof CompareInstruction and
exists(IRType type, ConditionalBranchInstruction branch |
type instanceof IRAddressType or type instanceof IRIntegerType
|
type = test.getResultIRType() and
branch.getCondition() = test
)
or
exists(LogicalNotInstruction logicalNot |
relevantUnaryComparison(logicalNot) and
test = logicalNot.getUnary()
)
}
/** /**
* Rearrange various simple comparisons into `op == k` form. * Rearrange various simple comparisons into `op == k` form.
*/ */
private predicate unary_simple_comparison_eq( private predicate unary_simple_comparison_eq(
Instruction test, int k, boolean inNonZeroCase, AbstractValue value Instruction test, Operand op, int k, boolean inNonZeroCase, AbstractValue value
) { ) {
exists(SwitchInstruction switch, CaseEdge case | exists(SwitchInstruction switch, CaseEdge case |
test = switch.getExpression() and test = switch.getExpression() and
op.getDef() = test and
case = value.(MatchValue).getCase() and case = value.(MatchValue).getCase() and
exists(switch.getSuccessor(case)) and exists(switch.getSuccessor(case)) and
case.getValue().toInt() = k and case.getValue().toInt() = k and
inNonZeroCase = false inNonZeroCase = false
) )
or or
// Any instruction with an integral type could potentially be part of a // There's no implicit CompareInstruction in files compiled as C since C
// check for nullness when used in a guard. So we include all integral // doesn't have implicit boolean conversions. So instead we check whether
// typed instructions here. However, since some of these instructions are // there's a branch on a value of pointer or integer type.
// already included as guards in other cases, we exclude those here. relevantUnaryComparison(test) and
// These are instructions that compute a binary equality or inequality op.getDef() = test and
// relation. For example, the following:
// ```cpp
// if(a == b + 42) { ... }
// ```
// generates the following IR:
// ```
// r1(glval<int>) = VariableAddress[a] :
// r2(int) = Load[a] : &:r1, m1
// r3(glval<int>) = VariableAddress[b] :
// r4(int) = Load[b] : &:r3, m2
// r5(int) = Constant[42] :
// r6(int) = Add : r4, r5
// r7(bool) = CompareEQ : r2, r6
// v1(void) = ConditionalBranch : r7
// ```
// and since `r7` is an integral typed instruction this predicate could
// include a case for when `r7` evaluates to true (in which case we would
// infer that `r6` was non-zero, and a case for when `r7` evaluates to false
// (in which case we would infer that `r6` was zero).
// However, since `a == b + 42` is already supported when reasoning about
// binary equalities we exclude those cases here.
not test.isGLValue() and
not simple_comparison_eq(test, _, _, _, _) and
not simple_comparison_lt(test, _, _, _) and
not test = any(SwitchInstruction switch).getExpression() and
(
test.getResultIRType() instanceof IRAddressType or
test.getResultIRType() instanceof IRIntegerType or
test.getResultIRType() instanceof IRBooleanType
) and
( (
k = 1 and k = 1 and
value.(BooleanValue).getValue() = true and value.(BooleanValue).getValue() = true and
@@ -914,68 +871,12 @@ private predicate unary_simple_comparison_eq(
) )
} }
/** A call to the builtin operation `__builtin_expect`. */
private class BuiltinExpectCallInstruction extends CallInstruction {
BuiltinExpectCallInstruction() { this.getStaticCallTarget().hasName("__builtin_expect") }
/** Gets the condition of this call. */
Instruction getCondition() {
// The first parameter of `__builtin_expect` has type `long`. So we skip
// the conversion when inferring guards.
result = this.getArgument(0).(ConvertInstruction).getUnary()
}
}
/**
* Holds if `left == right + k` is `areEqual` if `cmp` evaluates to `value`,
* and `cmp` is an instruction that compares the value of
* `__builtin_expect(left == right + k, _)` to `0`.
*/
private predicate builtin_expect_eq(
CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, AbstractValue value
) {
exists(BuiltinExpectCallInstruction call, Instruction const, AbstractValue innerValue |
int_value(const) = 0 and
cmp.hasOperands(call.getAUse(), const.getAUse()) and
compares_eq(call.getCondition(), left, right, k, areEqual, innerValue)
|
cmp instanceof CompareNEInstruction and
value = innerValue
or
cmp instanceof CompareEQInstruction and
value.getDualValue() = innerValue
)
}
private predicate complex_eq( private predicate complex_eq(
CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, AbstractValue value CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, AbstractValue value
) { ) {
sub_eq(cmp, left, right, k, areEqual, value) sub_eq(cmp, left, right, k, areEqual, value)
or or
add_eq(cmp, left, right, k, areEqual, value) add_eq(cmp, left, right, k, areEqual, value)
or
builtin_expect_eq(cmp, left, right, k, areEqual, value)
}
/**
* Holds if `op == k` is `areEqual` if `cmp` evaluates to `value`, and `cmp` is
* an instruction that compares the value of `__builtin_expect(op == k, _)` to `0`.
*/
private predicate unary_builtin_expect_eq(
CompareInstruction cmp, Operand op, int k, boolean areEqual, boolean inNonZeroCase,
AbstractValue value
) {
exists(BuiltinExpectCallInstruction call, Instruction const, AbstractValue innerValue |
int_value(const) = 0 and
cmp.hasOperands(call.getAUse(), const.getAUse()) and
unary_compares_eq(call.getCondition(), op, k, areEqual, inNonZeroCase, innerValue)
|
cmp instanceof CompareNEInstruction and
value = innerValue
or
cmp instanceof CompareEQInstruction and
value.getDualValue() = innerValue
)
} }
private predicate unary_complex_eq( private predicate unary_complex_eq(
@@ -984,8 +885,6 @@ private predicate unary_complex_eq(
unary_sub_eq(test, op, k, areEqual, inNonZeroCase, value) unary_sub_eq(test, op, k, areEqual, inNonZeroCase, value)
or or
unary_add_eq(test, op, k, areEqual, inNonZeroCase, value) unary_add_eq(test, op, k, areEqual, inNonZeroCase, value)
or
unary_builtin_expect_eq(test, op, k, areEqual, inNonZeroCase, value)
} }
/* /*
@@ -1014,8 +913,7 @@ private predicate compares_lt(
/** Holds if `op < k` evaluates to `isLt` given that `test` evaluates to `value`. */ /** Holds if `op < k` evaluates to `isLt` given that `test` evaluates to `value`. */
private predicate compares_lt(Instruction test, Operand op, int k, boolean isLt, AbstractValue value) { private predicate compares_lt(Instruction test, Operand op, int k, boolean isLt, AbstractValue value) {
unary_simple_comparison_lt(test, k, isLt, value) and simple_comparison_lt(test, op, k, isLt, value)
op.getDef() = test
or or
complex_lt(test, op, k, isLt, value) complex_lt(test, op, k, isLt, value)
or or
@@ -1062,11 +960,12 @@ private predicate simple_comparison_lt(CompareInstruction cmp, Operand left, Ope
} }
/** Rearrange various simple comparisons into `op < k` form. */ /** Rearrange various simple comparisons into `op < k` form. */
private predicate unary_simple_comparison_lt( private predicate simple_comparison_lt(
Instruction test, int k, boolean isLt, AbstractValue value Instruction test, Operand op, int k, boolean isLt, AbstractValue value
) { ) {
exists(SwitchInstruction switch, CaseEdge case | exists(SwitchInstruction switch, CaseEdge case |
test = switch.getExpression() and test = switch.getExpression() and
op.getDef() = test and
case = value.(MatchValue).getCase() and case = value.(MatchValue).getCase() and
exists(switch.getSuccessor(case)) and exists(switch.getSuccessor(case)) and
case.getMaxValue() > case.getMinValue() case.getMaxValue() > case.getMinValue()

View File

@@ -14,22 +14,16 @@
* The interpretation of a row is similar to API-graphs with a left-to-right * The interpretation of a row is similar to API-graphs with a left-to-right
* reading. * reading.
* 1. The `namespace` column selects a namespace. * 1. The `namespace` column selects a namespace.
* 2. The `type` column selects a type within that namespace. This column can * 2. The `type` column selects a type within that namespace.
* introduce template names that can be mentioned in the `signature` column.
* For example, `vector<T,Allocator>` introduces the template names `T` and
* `Allocator`.
* 3. The `subtypes` is a boolean that indicates whether to jump to an * 3. The `subtypes` is a boolean that indicates whether to jump to an
* arbitrary subtype of that type. Set this to `false` if leaving the `type` * arbitrary subtype of that type. Set this to `false` if leaving the `type`
* blank (for example, a free function). * blank (for example, a free function).
* 4. The `name` column optionally selects a specific named member of the type. * 4. The `name` column optionally selects a specific named member of the type.
* Like the `type` column, this column can introduce template names that can
* be mentioned in the `signature` column. For example, `insert<InputIt>`
* introduces the template name `InputIt`.
* 5. The `signature` column optionally restricts the named member. If * 5. The `signature` column optionally restricts the named member. If
* `signature` is blank then no such filtering is done. The format of the * `signature` is blank then no such filtering is done. The format of the
* signature is a comma-separated list of types enclosed in parentheses. The * signature is a comma-separated list of types enclosed in parentheses. The
* types must be stripped of template names. That is, write `const vector &` * types can be short names or fully qualified names (mixing these two options
* instead of `const vector<T> &`. * is not allowed within a single signature).
* 6. The `ext` column specifies additional API-graph-like edges. Currently * 6. The `ext` column specifies additional API-graph-like edges. Currently
* there is only one valid value: "". * there is only one valid value: "".
* 7. The `input` column specifies how data enters the element selected by the * 7. The `input` column specifies how data enters the element selected by the
@@ -50,9 +44,6 @@
* One or more "*" can be added as an argument to indicate indirection, for * One or more "*" can be added as an argument to indicate indirection, for
* example, "ReturnValue[*]" indicates the first indirection of the return * example, "ReturnValue[*]" indicates the first indirection of the return
* value. * value.
* The special symbol `@` can be used to specify an arbitrary (but fixed)
* number of indirections. For example, the `input` column `Argument[*@0]`
* indicates one or more indirections of the 0th argument.
* *
* An `output` can be either: * An `output` can be either:
* - "": Selects a read of a selected field. * - "": Selects a read of a selected field.
@@ -74,17 +65,6 @@
* One or more "*" can be added as an argument to indicate indirection, for * One or more "*" can be added as an argument to indicate indirection, for
* example, "ReturnValue[*]" indicates the first indirection of the return * example, "ReturnValue[*]" indicates the first indirection of the return
* value. * value.
* The special symbol `@` can be used to specify an arbitrary (but fixed)
* number of indirections. For example, the `output` column
* `ReturnValue[*@0]` indicates one or more indirections of the return
* value.
* Note: The symbol `@` only ever takes a single value across a row. Thus,
* the (`input`, `output`) pair `("Argument[*@0]", "ReturnValue[@]")`
* represents:
* - flow from the _first_ indirection of the 0th argument to the return
* value, and
* - flow from the _second_ indirection of the 0th argument to the first
* indirection of the return value, etc.
* 8. The `kind` column is a tag that can be referenced from QL to determine to * 8. The `kind` column is a tag that can be referenced from QL to determine to
* which classes the interpreted elements should be added. For example, for * which classes the interpreted elements should be added. For example, for
* sources "remote" indicates a default remote flow source, and for summaries * sources "remote" indicates a default remote flow source, and for summaries
@@ -94,13 +74,10 @@
import cpp import cpp
private import new.DataFlow private import new.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as Private
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import internal.FlowSummaryImpl private import internal.FlowSummaryImpl
private import internal.FlowSummaryImpl::Public private import internal.FlowSummaryImpl::Public
private import internal.FlowSummaryImpl::Private private import internal.FlowSummaryImpl::Private
private import internal.FlowSummaryImpl::Private::External private import internal.FlowSummaryImpl::Private::External
private import internal.ExternalFlowExtensions as Extensions
private import codeql.mad.ModelValidation as SharedModelVal private import codeql.mad.ModelValidation as SharedModelVal
private import codeql.util.Unit private import codeql.util.Unit
@@ -146,7 +123,7 @@ predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
/** Holds if a source model exists for the given parameters. */ /** Holds if a source model exists for the given parameters. */
predicate sourceModel( predicate sourceModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext, 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 | exists(string row |
sourceModel(row) and sourceModel(row) and
@@ -160,20 +137,13 @@ predicate sourceModel(
row.splitAt(";", 6) = output and row.splitAt(";", 6) = output and
row.splitAt(";", 7) = kind row.splitAt(";", 7) = kind
) and ) and
provenance = "manual" and provenance = "manual"
model = ""
or
exists(QlBuiltins::ExtensionId madId |
Extensions::sourceModel(namespace, type, subtypes, name, signature, ext, output, kind,
provenance, madId) and
model = "MaD:" + madId.toString()
)
} }
/** Holds if a sink model exists for the given parameters. */ /** Holds if a sink model exists for the given parameters. */
predicate sinkModel( predicate sinkModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext, 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 | exists(string row |
sinkModel(row) and sinkModel(row) and
@@ -187,24 +157,13 @@ predicate sinkModel(
row.splitAt(";", 6) = input and row.splitAt(";", 6) = input and
row.splitAt(";", 7) = kind row.splitAt(";", 7) = kind
) and ) and
provenance = "manual" and provenance = "manual"
model = ""
or
exists(QlBuiltins::ExtensionId madId |
Extensions::sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance,
madId) and
model = "MaD:" + madId.toString()
)
} }
/** /** Holds if a summary model exists for the given parameters. */
* Holds if a summary model exists for the given parameters. predicate summaryModel(
*
* This predicate does not expand `@` to `*`s.
*/
private predicate summaryModel0(
string namespace, string type, boolean subtypes, string name, string signature, string ext, 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 | exists(string row |
summaryModel(row) and summaryModel(row) and
@@ -219,48 +178,13 @@ private predicate summaryModel0(
row.splitAt(";", 7) = output and row.splitAt(";", 7) = output and
row.splitAt(";", 8) = kind row.splitAt(";", 8) = kind
) and ) and
provenance = "manual" and provenance = "manual"
model = ""
or
exists(QlBuiltins::ExtensionId madId |
Extensions::summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind,
provenance, madId) and
model = "MaD:" + madId.toString()
)
}
/**
* Holds if `input` is `input0`, but with all occurrences of `@` replaced
* by `n` repetitions of `*` (and similarly for `output` and `output0`).
*/
bindingset[input0, output0, n]
pragma[inline_late]
private predicate expandInputAndOutput(
string input0, string input, string output0, string output, int n
) {
input = input0.replaceAll("@", repeatStars(n)) and
output = output0.replaceAll("@", repeatStars(n))
}
/**
* Holds if a summary model exists for the given parameters.
*/
predicate summaryModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, string provenance, string model
) {
exists(string input0, string output0 |
summaryModel0(namespace, type, subtypes, name, signature, ext, input0, output0, kind,
provenance, model) and
expandInputAndOutput(input0, input, output0, output,
[0 .. Private::getMaxElementContentIndirectionIndex() - 1])
)
} }
private predicate relevantNamespace(string namespace) { private predicate relevantNamespace(string namespace) {
sourceModel(namespace, _, _, _, _, _, _, _, _, _) or sourceModel(namespace, _, _, _, _, _, _, _, _) or
sinkModel(namespace, _, _, _, _, _, _, _, _, _) or sinkModel(namespace, _, _, _, _, _, _, _, _) or
summaryModel(namespace, _, _, _, _, _, _, _, _, _, _) summaryModel(namespace, _, _, _, _, _, _, _, _, _)
} }
private predicate namespaceLink(string shortns, string longns) { private predicate namespaceLink(string shortns, string longns) {
@@ -279,10 +203,8 @@ private predicate canonicalNamespaceLink(string namespace, string subns) {
} }
/** /**
* Holds if MaD framework coverage of `namespace` is `n` api endpoints of the * Holds if CSV framework coverage of `namespace` is `n` api endpoints of the
* kind `(kind, part)`, and `namespaces` is the number of subnamespaces of * kind `(kind, part)`.
* `namespace` which have MaD framework coverage (including `namespace`
* itself).
*/ */
predicate modelCoverage(string namespace, int namespaces, string kind, string part, int n) { predicate modelCoverage(string namespace, int namespaces, string kind, string part, int n) {
namespaces = strictcount(string subns | canonicalNamespaceLink(namespace, subns)) and namespaces = strictcount(string subns | canonicalNamespaceLink(namespace, subns)) and
@@ -290,17 +212,17 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
part = "source" and part = "source" and
n = n =
strictcount(string subns, string type, boolean subtypes, string name, string signature, 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 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 or
part = "sink" and part = "sink" and
n = n =
strictcount(string subns, string type, boolean subtypes, string name, string signature, 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 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 or
part = "summary" and part = "summary" and
@@ -308,7 +230,7 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
strictcount(string subns, string type, boolean subtypes, string name, string signature, strictcount(string subns, string type, boolean subtypes, string name, string signature,
string ext, string input, string output, string provenance | string ext, string input, string output, string provenance |
canonicalNamespaceLink(namespace, subns) and 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 +239,9 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
module CsvValidation { module CsvValidation {
private string getInvalidModelInput() { private string getInvalidModelInput() {
exists(string pred, AccessPath input, string part | exists(string pred, AccessPath input, string part |
sinkModel(_, _, _, _, _, _, input, _, _, _) and pred = "sink" sinkModel(_, _, _, _, _, _, input, _, _) and pred = "sink"
or or
summaryModel(_, _, _, _, _, _, input, _, _, _, _) and pred = "summary" summaryModel(_, _, _, _, _, _, input, _, _, _) and pred = "summary"
| |
( (
invalidSpecComponent(input, part) and invalidSpecComponent(input, part) and
@@ -336,9 +258,9 @@ module CsvValidation {
private string getInvalidModelOutput() { private string getInvalidModelOutput() {
exists(string pred, string output, string part | exists(string pred, string output, string part |
sourceModel(_, _, _, _, _, _, output, _, _, _) and pred = "source" sourceModel(_, _, _, _, _, _, output, _, _) and pred = "source"
or or
summaryModel(_, _, _, _, _, _, _, output, _, _, _) and pred = "summary" summaryModel(_, _, _, _, _, _, _, output, _, _) and pred = "summary"
| |
invalidSpecComponent(output, part) and invalidSpecComponent(output, part) and
not part = "" and not part = "" and
@@ -348,11 +270,11 @@ module CsvValidation {
} }
private module KindValConfig implements SharedModelVal::KindValidationConfigSig { 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>; private module KindVal = SharedModelVal::KindValidation<KindValConfig>;
@@ -393,16 +315,16 @@ module CsvValidation {
private string getInvalidModelSignature() { private string getInvalidModelSignature() {
exists(string pred, string namespace, string type, string name, string signature, string ext | 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 or
sinkModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "sink" sinkModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "sink"
or 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 not namespace.regexpMatch("[a-zA-Z0-9_\\.]+") and
result = "Dubious namespace \"" + namespace + "\" in " + pred + " model." result = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
or or
not type.regexpMatch("[a-zA-Z0-9_<>,\\+]*") and not type.regexpMatch("[a-zA-Z0-9_<>,\\+]+") and
result = "Dubious type \"" + type + "\" in " + pred + " model." result = "Dubious type \"" + type + "\" in " + pred + " model."
or or
not name.regexpMatch("[a-zA-Z0-9_<>,]*") and not name.regexpMatch("[a-zA-Z0-9_<>,]*") and
@@ -429,160 +351,21 @@ module CsvValidation {
private predicate elementSpec( private predicate elementSpec(
string namespace, string type, boolean subtypes, string name, string signature, string ext string namespace, string type, boolean subtypes, string name, string signature, string ext
) { ) {
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _) or
sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _) or
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _) summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _)
}
/** Gets the fully templated version of `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)
)
}
/**
* Gets the type name of the `n`'th parameter of `f` without any template
* arguments.
*/
bindingset[f]
pragma[inline_late]
string getParameterTypeWithoutTemplateArguments(Function f, int n) {
exists(string s, string base, string specifiers |
s = f.getParameter(n).getType().getName() and
parseAngles(s, base, _, specifiers) and
result = base + specifiers
)
}
/**
* Normalize the `n`'th parameter of `f` by replacing template names
* with `func:N` (where `N` is the index of the template).
*/
private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remaining) {
exists(Function templateFunction |
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 = getFullyTemplatedMemberFunction(f) and
tp = templateFunction.getTemplateArgument(remaining) and
result = mid.replaceAll(tp.getName(), "func:" + remaining.toString())
)
}
/**
* Normalize the `n`'th parameter of `f` by replacing template names
* with `class:N` (where `N` is the index of the template).
*/
private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining) {
exists(Class template |
f.getDeclaringType().isConstructedFrom(template) and
remaining = template.getNumberOfTemplateArguments() 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
tp = template.getTemplateArgument(remaining) and
result = mid.replaceAll(tp.getName(), "class:" + remaining.toString())
)
}
/** Gets the string representation of the `i`'th parameter of `c`. */
private string getParameterTypeName(Function c, int i) {
result = getTypeNameWithoutClassTemplates(c, i, 0)
}
/** Splits `s` by `,` and gets the `i`'th element. */
bindingset[s]
pragma[inline_late]
private string getAtIndex(string s, int i) {
result = s.splitAt(",", i) and
// when `s` is `""` and `i` is `0` we get `result = ""` which we don't want.
not (s = "" and i = 0)
}
/**
* Normalizes `partiallyNormalizedSignature` by replacing the `remaining`
* number of template arguments in `partiallyNormalizedSignature` with their
* index in `typeArgs`.
*/
private string getSignatureWithoutClassTemplateNames(
string partiallyNormalizedSignature, string typeArgs, string nameArgs, int remaining
) {
elementSpecWithArguments0(_, _, _, partiallyNormalizedSignature, typeArgs, nameArgs) and
remaining = count(partiallyNormalizedSignature.indexOf(",")) + 1 and
result = partiallyNormalizedSignature
or
exists(string mid |
mid =
getSignatureWithoutClassTemplateNames(partiallyNormalizedSignature, typeArgs, nameArgs,
remaining + 1)
|
exists(string typeArg |
typeArg = getAtIndex(typeArgs, remaining) and
result = mid.replaceAll(typeArg, "class:" + remaining.toString())
)
or
// Make sure `remaining` is properly bound
remaining = [0 .. count(partiallyNormalizedSignature.indexOf(",")) + 1] and
not exists(getAtIndex(typeArgs, remaining)) and
result = mid
)
}
/**
* Normalizes `partiallyNormalizedSignature` by replacing:
* - _All_ the template arguments in `partiallyNormalizedSignature` that refer to
* template parameters in `typeArgs` with their index in `typeArgs`, and
* - The `remaining` number of template arguments in `partiallyNormalizedSignature`
* with their index in `nameArgs`.
*/
private string getSignatureWithoutFunctionTemplateNames(
string partiallyNormalizedSignature, string typeArgs, string nameArgs, int remaining
) {
remaining = count(partiallyNormalizedSignature.indexOf(",")) + 1 and
result =
getSignatureWithoutClassTemplateNames(partiallyNormalizedSignature, typeArgs, nameArgs, 0)
or
exists(string mid |
mid =
getSignatureWithoutFunctionTemplateNames(partiallyNormalizedSignature, typeArgs, nameArgs,
remaining + 1)
|
exists(string nameArg |
nameArg = getAtIndex(nameArgs, remaining) and
result = mid.replaceAll(nameArg, "func:" + remaining.toString())
)
or
// Make sure `remaining` is properly bound
remaining = [0 .. count(partiallyNormalizedSignature.indexOf(",")) + 1] and
not exists(getAtIndex(nameArgs, remaining)) and
result = mid
)
} }
private string paramsStringPart(Function c, int i) { private string paramsStringPart(Function c, int i) {
not c.isFromUninstantiatedTemplate(_) and i = -1 and result = "(" and exists(c)
( or
i = -1 and result = "(" and exists(c) exists(int n, string p | c.getParameter(n).getType().toString() = p |
i = 2 * n and result = p
or or
exists(int n, string p | getParameterTypeName(c, n) = p | i = 2 * n - 1 and result = "," and n != 0
i = 2 * n and result = p
or
i = 2 * n - 1 and result = "," and n != 0
)
or
i = 2 * c.getNumberOfParameters() and result = ")"
) )
or
i = 2 * c.getNumberOfParameters() and result = ")"
} }
/** /**
@@ -602,193 +385,6 @@ private predicate matchesSignature(Function func, string signature) {
paramsString(func) = signature paramsString(func) = signature
} }
/**
* Holds if `elementSpec(_, type, _, name, signature, _)` holds and
* - `typeArgs` represents the named template parameters supplied to `type`, and
* - `nameArgs` represents the named template parameters supplied to `name`, and
* - `normalizedSignature` is `signature`, except with
* - template parameter names replaced by `func:i` if the template name is
* the `i`'th entry in `nameArgs`, and
* - template parameter names replaced by `class:i` if the template name is
* the `i`'th entry in `typeArgs`.
*
* In other words, the string `normalizedSignature` represents a "normalized"
* signature with no mention of any free template parameters.
*
* For example, consider a summary row such as:
* ```
* elementSpec(_, "MyClass<B, C>", _, myFunc<A>, "(const A &,int,C,B *)", _)
* ```
* In this case, `normalizedSignature` will be `"(const func:0 &,int,class:1,class:0 *)"`.
*/
private predicate elementSpecWithArguments(
string signature, string type, string name, string normalizedSignature, string typeArgs,
string nameArgs
) {
exists(string signatureWithoutParens |
elementSpecWithArguments0(signature, type, name, signatureWithoutParens, typeArgs, nameArgs) and
normalizedSignature =
getSignatureWithoutFunctionTemplateNames(signatureWithoutParens, typeArgs, nameArgs, 0)
)
}
/** Gets the `n`'th normalized signature parameter for the function `name` in class `type`. */
private string getSignatureParameterName(string signature, string type, string name, int n) {
exists(string normalizedSignature |
elementSpecWithArguments(signature, type, name, normalizedSignature, _, _) and
result = getAtIndex(normalizedSignature, n)
)
}
/**
* Holds if the suffix containing the entries in `signature` starting at entry
* `i` matches the suffix containing the parameters of `func` starting at entry `i`.
*
* For example, consider the signature `(int,bool,char)` and a function:
* ```
* void f(int a, bool b, char c);
* ```
* 1. The predicate holds for `i = 2` because the suffix containing all the entries
* in `signature` starting at `2` is `char`, and suffix containing all the parameters
* of `func` starting at `2` is `char`.
* 2. The predicate holds for `i = 1` because the suffix containing all the entries
* in `signature` starting at `1` is `bool,char`, and the suffix containing all the
* parameters of `func` starting at `1` is `bool, char`.
* 3. The predicate holds for `i = 0` because the suffix containing all the entries
* in `signature` starting at `0` is `int,bool,char` and the suffix containing all
* the parameters of `func` starting at `0` is `int, bool, char`.
*
* When `paramsString(func)[i]` is `class:n` then the signature name is
* compared with the `n`'th name in `type`, and when `paramsString(func)[i]`
* is `func:n` then the signature name is compared with the `n`'th name
* in `name`.
*/
private predicate signatureMatches(Function func, string signature, string type, string name, int i) {
exists(string s |
s = getSignatureParameterName(signature, type, name, i) and
s = getParameterTypeName(func, i)
) and
if exists(getParameterTypeName(func, i + 1))
then signatureMatches(func, signature, type, name, i + 1)
else i = count(signature.indexOf(","))
}
/**
* Internal: Do not use.
*
* This module only exists to expose internal predicates for testing purposes.
*/
module ExternalFlowDebug {
/**
* INTERNAL: Do not use.
*
* Exposed for testing purposes.
*/
predicate signatureMatches_debug = signatureMatches/5;
/**
* INTERNAL: Do not use.
*
* Exposed for testing purposes.
*/
predicate getSignatureParameterName_debug = getSignatureParameterName/4;
/**
* INTERNAL: Do not use.
*
* Exposed for testing purposes.
*/
predicate getParameterTypeName_debug = getParameterTypeName/2;
}
/**
* Holds if `s` can be broken into a string of the form
* `beforeAngles<betweenAngles>`,
* or `s = beforeAngles` where `beforeAngles` does not have any brackets.
*/
bindingset[s]
pragma[inline_late]
private predicate parseAngles(
string s, string beforeAngles, string betweenAngles, string afterAngles
) {
beforeAngles = s.regexpCapture("([^<]+)(?:<([^>]+)>(.*))?", 1) and
(
betweenAngles = s.regexpCapture("([^<]+)(?:<([^>]+)>(.*))?", 2) and
afterAngles = s.regexpCapture("([^<]+)(?:<([^>]+)>(.*))?", 3)
or
not exists(s.regexpCapture("([^<]+)(?:<([^>]+)>(.*))?", 2)) and
betweenAngles = "" and
afterAngles = ""
)
}
/** Holds if `s` can be broken into a string of the form `(betweenParens)`. */
bindingset[s]
pragma[inline_late]
private predicate parseParens(string s, string betweenParens) { s = "(" + betweenParens + ")" }
/**
* Holds if `elementSpec(_, type, _, name, signature, _)` and:
* - `type` introduces template parameters `typeArgs`, and
* - `name` introduces template parameters `nameArgs`, and
* - `signatureWithoutParens` equals `signature`, but with the surrounding
* parentheses removed.
*/
private predicate elementSpecWithArguments0(
string signature, string type, string name, string signatureWithoutParens, string typeArgs,
string nameArgs
) {
elementSpec(_, type, _, name, signature, _) and
parseAngles(name, _, nameArgs, "") and
(
type = "" and typeArgs = ""
or
parseAngles(type, _, typeArgs, "")
) and
parseParens(signature, signatureWithoutParens)
}
/**
* Holds if `elementSpec(namespace, type, subtypes, name, signature, _)` and
* `method`'s signature matches `signature`.
*
* `signature` may contain template parameter names that are bound by `type` and `name`.
*/
pragma[nomagic]
private predicate elementSpecMatchesSignature(
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(method, signature, type, name, 0)
}
/**
* Holds if `classWithMethod` has `method` named `name` (excluding any
* template parameters).
*/
bindingset[name]
pragma[inline_late]
private predicate hasClassAndName(Class classWithMethod, Function method, string name) {
exists(string nameWithoutArgs |
parseAngles(name, nameWithoutArgs, _, "") and
classWithMethod = method.getClassAndName(nameWithoutArgs)
)
}
/**
* Holds if `namedClass` is in namespace `namespace` and has
* name `type` (excluding any template parameters).
*/
bindingset[type, namespace]
pragma[inline_late]
private predicate hasQualifiedName(Class namedClass, string namespace, string type) {
exists(string typeWithoutArgs |
parseAngles(type, typeWithoutArgs, _, "") and
namedClass.hasQualifiedName(namespace, typeWithoutArgs)
)
}
/** /**
* Gets the element in module `namespace` that satisfies the following properties: * Gets the element in module `namespace` that satisfies the following properties:
* 1. If the element is a member of a class-like type, then the class-like type has name `type` * 1. If the element is a member of a class-like type, then the class-like type has name `type`
@@ -803,8 +399,8 @@ pragma[nomagic]
private Element interpretElement0( private Element interpretElement0(
string namespace, string type, boolean subtypes, string name, string signature string namespace, string type, boolean subtypes, string name, string signature
) { ) {
elementSpec(namespace, type, subtypes, name, signature, _) and
( (
elementSpec(namespace, type, subtypes, name, signature, _) and
// Non-member functions // Non-member functions
exists(Function func | exists(Function func |
func.hasQualifiedName(namespace, name) and func.hasQualifiedName(namespace, name) and
@@ -816,28 +412,21 @@ private Element interpretElement0(
) )
or or
// Member functions // Member functions
exists(Class namedClass, Class classWithMethod | exists(Class namedClass, Class classWithMethod, Function method |
( classWithMethod = method.getClassAndName(name) and
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature) and namedClass.hasQualifiedName(namespace, type) and
hasClassAndName(classWithMethod, result, name) matchesSignature(method, signature) and
or result = method
signature = "" and |
elementSpec(namespace, type, subtypes, name, "", _) and // member declared in the named type or a subtype of it
hasClassAndName(classWithMethod, result, name) subtypes = true and
) and classWithMethod = namedClass.getADerivedClass*()
hasQualifiedName(namedClass, namespace, type) and or
( // member declared directly in the named type
// member declared in the named type or a subtype of it subtypes = false and
subtypes = true and classWithMethod = namedClass
classWithMethod = namedClass.getADerivedClass*()
or
// member declared directly in the named type
subtypes = false and
classWithMethod = namedClass
)
) )
or or
elementSpec(namespace, type, subtypes, name, signature, _) and
// Member variables // Member variables
signature = "" and signature = "" and
exists(Class namedClass, Class classWithMember, MemberVariable member | exists(Class namedClass, Class classWithMember, MemberVariable member |
@@ -856,7 +445,6 @@ private Element interpretElement0(
) )
or or
// Global or namespace variables // Global or namespace variables
elementSpec(namespace, type, subtypes, name, signature, _) and
signature = "" and signature = "" and
type = "" and type = "" and
subtypes = false and subtypes = false and
@@ -881,9 +469,9 @@ private module Cached {
* model. * model.
*/ */
cached cached
predicate sourceNode(DataFlow::Node node, string kind, string model) { predicate sourceNode(DataFlow::Node node, string kind) {
exists(SourceSinkInterpretationInput::InterpretNode n | exists(SourceSinkInterpretationInput::InterpretNode n |
isSourceNode(n, kind, model) and n.asNode() = node isSourceNode(n, kind, _) and n.asNode() = node // TODO
) )
} }
@@ -892,57 +480,40 @@ private module Cached {
* model. * model.
*/ */
cached cached
predicate sinkNode(DataFlow::Node node, string kind, string model) { predicate sinkNode(DataFlow::Node node, string kind) {
exists(SourceSinkInterpretationInput::InterpretNode n | exists(SourceSinkInterpretationInput::InterpretNode n |
isSinkNode(n, kind, model) and n.asNode() = node isSinkNode(n, kind, _) and n.asNode() = node // TODO
) )
} }
} }
import Cached 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( 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( exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext string namespace, string type, boolean subtypes, string name, string signature, string ext
| |
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance, summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance) and
model) and
f = interpretElement(namespace, type, subtypes, name, signature, ext) f = interpretElement(namespace, type, subtypes, name, signature, ext)
) )
} }
// adapter class for converting Mad summaries to `SummarizedCallable`s // adapter class for converting Mad summaries to `SummarizedCallable`s
private class SummarizedCallableAdapter extends SummarizedCallable { private class SummarizedCallableAdapter extends SummarizedCallable {
SummarizedCallableAdapter() { interpretSummary(this, _, _, _, _, _) } SummarizedCallableAdapter() { interpretSummary(this, _, _, _, _) }
private predicate relevantSummaryElementManual( private predicate relevantSummaryElementManual(string input, string output, string kind) {
string input, string output, string kind, string model
) {
exists(Provenance provenance | exists(Provenance provenance |
interpretSummary(this, input, output, kind, provenance, model) and interpretSummary(this, input, output, kind, provenance) and
provenance.isManual() provenance.isManual()
) )
} }
private predicate relevantSummaryElementGenerated( private predicate relevantSummaryElementGenerated(string input, string output, string kind) {
string input, string output, string kind, string model
) {
exists(Provenance provenance | exists(Provenance provenance |
interpretSummary(this, input, output, kind, provenance, model) and interpretSummary(this, input, output, kind, provenance) and
provenance.isGenerated() provenance.isGenerated()
) )
} }
@@ -951,17 +522,18 @@ private class SummarizedCallableAdapter extends SummarizedCallable {
string input, string output, boolean preservesValue, string model string input, string output, boolean preservesValue, string model
) { ) {
exists(string kind | exists(string kind |
this.relevantSummaryElementManual(input, output, kind, model) this.relevantSummaryElementManual(input, output, kind)
or or
not this.relevantSummaryElementManual(_, _, _, _) and not this.relevantSummaryElementManual(_, _, _) and
this.relevantSummaryElementGenerated(input, output, kind, model) this.relevantSummaryElementGenerated(input, output, kind)
| |
if kind = "value" then preservesValue = true else preservesValue = false if kind = "value" then preservesValue = true else preservesValue = false
) ) and
model = "" // TODO
} }
override predicate hasProvenance(Provenance provenance) { override predicate hasProvenance(Provenance provenance) {
interpretSummary(this, _, _, _, provenance, _) interpretSummary(this, _, _, _, provenance)
} }
} }

View File

@@ -216,7 +216,7 @@ predicate localMustFlowStep(Node node1, Node node2) { none() }
/** Gets the type of `n` used for type pruning. */ /** Gets the type of `n` used for type pruning. */
Type getNodeType(Node n) { Type getNodeType(Node n) {
exists(n) and suppressUnusedNode(n) and
result instanceof VoidType // stub implementation result instanceof VoidType // stub implementation
} }
@@ -227,10 +227,13 @@ string ppReprType(Type t) { none() } // stub implementation
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from * 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`. * a node of type `t1` to a node of type `t2`.
*/ */
pragma[inline]
predicate compatibleTypes(Type t1, Type t2) { predicate compatibleTypes(Type t1, Type t2) {
t1 instanceof VoidType and t2 instanceof VoidType // stub implementation any() // stub implementation
} }
private predicate suppressUnusedNode(Node n) { any() }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Java QL library compatibility wrappers // Java QL library compatibility wrappers
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@@ -239,7 +242,17 @@ class CastNode extends Node {
CastNode() { none() } // stub implementation 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; class DataFlowExpr = Expr;
@@ -259,12 +272,24 @@ class DataFlowCall extends Expr instanceof Call {
/** Gets the enclosing callable of this call. */ /** Gets the enclosing callable of this call. */
DataFlowCallable getEnclosingCallable() { result = this.getEnclosingFunction() } 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 { class NodeRegion instanceof Unit {
string toString() { result = "NodeRegion" } string toString() { result = "NodeRegion" }
predicate contains(Node n) { none() } predicate contains(Node n) { none() }
int totalOrder() { result = 1 }
} }
predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call) { none() } // stub implementation predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call) { none() } // stub implementation

View File

@@ -1,27 +0,0 @@
/**
* This module provides extensible predicates for defining MaD models.
*/
/**
* Holds if an external source model exists for the given parameters.
*/
extensible predicate sourceModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string output, string kind, string provenance, QlBuiltins::ExtensionId madId
);
/**
* Holds if an external sink model exists for the given parameters.
*/
extensible predicate sinkModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string input, string kind, string provenance, QlBuiltins::ExtensionId madId
);
/**
* Holds if an external summary model exists for the given parameters.
*/
extensible predicate summaryModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, string provenance, QlBuiltins::ExtensionId madId
);

View File

@@ -35,22 +35,16 @@ module Input implements InputSig<Location, DataFlowImplSpecific::CppDataFlow> {
result = "Field" and result = "Field" and
arg = repeatStars(c.getIndirectionIndex() - 1) + c.getField().getName() arg = repeatStars(c.getIndirectionIndex() - 1) + c.getField().getName()
) )
or
exists(ElementContent ec |
cs.isSingleton(ec) and
result = "Element" and
arg = repeatStars(ec.getIndirectionIndex() - 1)
)
} }
string encodeWithoutContent(ContentSet c, string arg) { string encodeWithoutContent(ContentSet c, string arg) {
// used for type tracking, not currently used in C/C++. // used for type tracking, not currently used in C/C++.
none() result = "WithoutContent" + c and arg = ""
} }
string encodeWithContent(ContentSet c, string arg) { string encodeWithContent(ContentSet c, string arg) {
// used for type tracking, not currently used in C/C++. // used for type tracking, not currently used in C/C++.
none() result = "WithContent" + c and arg = ""
} }
/** /**
@@ -85,6 +79,25 @@ module Input implements InputSig<Location, DataFlowImplSpecific::CppDataFlow> {
token.getName() = "Parameter" and token.getName() = "Parameter" and
result = decodePosition(token.getAnArgument()) result = decodePosition(token.getAnArgument())
} }
bindingset[token]
ContentSet decodeUnknownContent(AccessPath::AccessPathTokenBase token) {
// field content (no indirection support)
exists(FieldContent c |
result.isSingleton(c) and
token.getName() = c.getField().getName() and
not exists(token.getArgumentList()) and
c.getIndirectionIndex() = 1
)
or
// field content (with indirection support)
exists(FieldContent c |
result.isSingleton(c) and
token.getName() = c.getField().getName() and
// FieldContent indices have 0 for the address, 1 for content, so we need to subtract one.
token.getAnArgument() = repeatStars(c.getIndirectionIndex() - 1)
)
}
} }
private import Make<Location, DataFlowImplSpecific::CppDataFlow, Input> as Impl private import Make<Location, DataFlowImplSpecific::CppDataFlow, Input> as Impl
@@ -112,8 +125,9 @@ module SourceSinkInterpretationInput implements
exists( exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext string namespace, string type, boolean subtypes, string name, string signature, string ext
| |
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance, model) and sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance) and
e = interpretElement(namespace, type, subtypes, name, signature, ext) e = interpretElement(namespace, type, subtypes, name, signature, ext) and
model = "" // TODO
) )
} }
@@ -127,8 +141,9 @@ module SourceSinkInterpretationInput implements
exists( exists(
string package, string type, boolean subtypes, string name, string signature, string ext string package, string type, boolean subtypes, string name, string signature, string ext
| |
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance, model) and sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance) and
e = interpretElement(package, type, subtypes, name, signature, ext) 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" } 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 * A C++ `__is_empty` built-in operation (used by some implementations of the
* `<type_traits>` header). * `<type_traits>` header).
@@ -678,7 +647,8 @@ class BuiltInOperationIsTriviallyAssignable extends BuiltInOperation, @istrivial
* The `__is_nothrow_assignable` built-in operation (used by some * The `__is_nothrow_assignable` built-in operation (used by some
* implementations of the `<type_traits>` header). * 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); * 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 * The `__is_assignable` built-in operation (used by some implementations
* of the `<type_traits>` header). * 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); * bool v = __is_assignable(MyType1, MyType2);
* ``` * ```
@@ -704,25 +675,6 @@ class BuiltInOperationIsAssignable extends BuiltInOperation, @isassignable {
override string getAPrimaryQlClass() { result = "BuiltInOperationIsAssignable" } 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 * The `__is_standard_layout` built-in operation (used by some implementations
* of the `<type_traits>` header). * of the `<type_traits>` header).
@@ -756,20 +708,6 @@ class BuiltInOperationIsTriviallyCopyable extends BuiltInOperation, @istrivially
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyCopyable" } 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 `__is_literal_type` built-in operation (used by some implementations of
* the `<type_traits>` header). * the `<type_traits>` header).
@@ -1124,24 +1062,6 @@ class BuiltInOperationIsSame extends BuiltInOperation, @issame {
override string getAPrimaryQlClass() { result = "BuiltInOperationIsSame" } 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 * A C++ `__is_function` built-in operation (used by some implementations of the
* `<type_traits>` header). * `<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 * A C++ `__is_array` built-in operation (used by some implementations of the
* `<type_traits>` header). * `<type_traits>` header).
@@ -1299,42 +1138,6 @@ class BuiltInOperationIsArray extends BuiltInOperation, @isarray {
override string getAPrimaryQlClass() { result = "BuiltInOperationIsArray" } 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 * A C++ `__array_rank` built-in operation (used by some implementations of the
* `<type_traits>` header). * `<type_traits>` header).
@@ -1751,10 +1554,10 @@ class BuiltInBitCast extends BuiltInOperation, @builtinbitcast {
* *
* Returns `true` if a type is a trivial type. * Returns `true` if a type is a trivial type.
* ``` * ```
* template<typename _Tp> * template<typename _Tp>
* struct is_trivial * struct is_trivial
* : public integral_constant<bool, __is_trivial(_Tp)> * : public integral_constant<bool, __is_trivial(_Tp)>
* {}; * {};
* ``` * ```
*/ */
class BuiltInIsTrivial extends BuiltInOperation, @istrivialexpr { class BuiltInIsTrivial extends BuiltInOperation, @istrivialexpr {
@@ -1762,126 +1565,3 @@ class BuiltInIsTrivial extends BuiltInOperation, @istrivialexpr {
override string getAPrimaryQlClass() { result = "BuiltInIsTrivial" } 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

@@ -949,16 +949,6 @@ class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr {
* gives nothing, as the 10 is considered part of the type. * gives nothing, as the 10 is considered part of the type.
*/ */
Expr getExtent() { result = this.getChild(2) } 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; private class TDeleteOrDeleteArrayExpr = @delete_expr or @delete_array_expr;

View File

@@ -11,7 +11,6 @@ private import Node0ToString
private import ModelUtil private import ModelUtil
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as IO 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.models.interfaces.DataFlow as DF
private import semmle.code.cpp.dataflow.ExternalFlow as External
cached cached
private module Cached { private module Cached {
@@ -413,8 +412,6 @@ class ArgumentPosition = Position;
abstract class Position extends TPosition { abstract class Position extends TPosition {
abstract string toString(); abstract string toString();
abstract int getIndirectionIndex();
} }
class DirectPosition extends Position, TDirectPosition { class DirectPosition extends Position, TDirectPosition {
@@ -424,15 +421,13 @@ class DirectPosition extends Position, TDirectPosition {
override string toString() { override string toString() {
index = -1 and index = -1 and
result = "this pointer" result = "this"
or or
index != -1 and index != -1 and
result = index.toString() result = index.toString()
} }
int getIndex() { result = index } int getIndex() { result = index }
final override int getIndirectionIndex() { result = 0 }
} }
class IndirectionPosition extends Position, TIndirectionPosition { class IndirectionPosition extends Position, TIndirectionPosition {
@@ -443,13 +438,16 @@ class IndirectionPosition extends Position, TIndirectionPosition {
override string toString() { override string toString() {
if argumentIndex = -1 if argumentIndex = -1
then result = repeatStars(indirectionIndex - 1) + "this" then if indirectionIndex > 0 then result = "this indirection" else result = "this"
else result = repeatStars(indirectionIndex) + argumentIndex.toString() else
if indirectionIndex > 0
then result = argumentIndex.toString() + " indirection"
else result = argumentIndex.toString()
} }
int getArgumentIndex() { result = argumentIndex } int getArgumentIndex() { result = argumentIndex }
final override int getIndirectionIndex() { result = indirectionIndex } int getIndirectionIndex() { result = indirectionIndex }
} }
newtype TPosition = newtype TPosition =
@@ -990,7 +988,7 @@ predicate localMustFlowStep(Node node1, Node node2) { none() }
/** Gets the type of `n` used for type pruning. */ /** Gets the type of `n` used for type pruning. */
DataFlowType getNodeType(Node n) { DataFlowType getNodeType(Node n) {
exists(n) and suppressUnusedNode(n) and
result instanceof VoidType // stub implementation result instanceof VoidType // stub implementation
} }
@@ -1001,10 +999,13 @@ string ppReprType(DataFlowType t) { none() } // stub implementation
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from * 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`. * a node of type `t1` to a node of type `t2`.
*/ */
pragma[inline]
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
t1 instanceof VoidType and t2 instanceof VoidType // stub implementation any() // stub implementation
} }
private predicate suppressUnusedNode(Node n) { any() }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Java QL library compatibility wrappers // Java QL library compatibility wrappers
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@@ -1061,6 +1062,16 @@ class DataFlowCallable extends TDataFlowCallable {
result = this.asSummarizedCallable() or // SummarizedCallable = Function (in CPP) result = this.asSummarizedCallable() or // SummarizedCallable = Function (in CPP)
result = this.asSourceCallable() 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
)
}
} }
/** /**
@@ -1158,6 +1169,16 @@ class DataFlowCall extends TDataFlowCall {
* Gets the location of this call. * Gets the location of this call.
*/ */
Location getLocation() { none() } 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
)
}
} }
/** /**
@@ -1250,6 +1271,15 @@ module IsUnreachableInCall {
string toString() { result = "NodeRegion" } string toString() { result = "NodeRegion" }
predicate contains(Node n) { this = n.getBasicBlock() } 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) { predicate isUnreachableInCall(NodeRegion block, DataFlowCall call) {
@@ -1295,7 +1325,7 @@ import IsUnreachableInCall
* Holds if access paths with `c` at their head always should be tracked at high * Holds if access paths with `c` at their head always should be tracked at high
* precision. This disables adaptive access path precision for such access paths. * precision. This disables adaptive access path precision for such access paths.
*/ */
predicate forceHighPrecision(Content c) { c instanceof ElementContent } predicate forceHighPrecision(Content c) { none() }
/** Holds if `n` should be hidden from path explanations. */ /** Holds if `n` should be hidden from path explanations. */
predicate nodeIsHidden(Node n) { predicate nodeIsHidden(Node n) {
@@ -1306,8 +1336,6 @@ predicate nodeIsHidden(Node n) {
n instanceof FinalGlobalValue n instanceof FinalGlobalValue
or or
n instanceof InitialGlobalValue n instanceof InitialGlobalValue
or
n instanceof SsaPhiInputNode
} }
predicate neverSkipInPathGraph(Node n) { predicate neverSkipInPathGraph(Node n) {
@@ -1334,9 +1362,9 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
/** Extra data-flow steps needed for lambda flow analysis. */ /** Extra data-flow steps needed for lambda flow analysis. */
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() } 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 * Holds if flow is allowed to pass from parameter `p` and back to itself as a
@@ -1366,8 +1394,7 @@ private predicate unionHasApproxName(Cpp::Union u, string s) { s = u.getName().c
cached cached
private newtype TContentApprox = private newtype TContentApprox =
TFieldApproxContent(string s) { fieldHasApproxName(_, s) } or TFieldApproxContent(string s) { fieldHasApproxName(_, s) } or
TUnionApproxContent(string s) { unionHasApproxName(_, s) } or TUnionApproxContent(string s) { unionHasApproxName(_, s) }
TElementApproxContent()
/** An approximated `Content`. */ /** An approximated `Content`. */
class ContentApprox extends TContentApprox { class ContentApprox extends TContentApprox {
@@ -1398,10 +1425,6 @@ private class UnionApproxContent extends ContentApprox, TUnionApproxContent {
final override string toString() { result = s } final override string toString() { result = s }
} }
private class ElementApproxContent extends ContentApprox, TElementApproxContent {
final override string toString() { result = "ElementApprox" }
}
/** Gets an approximated value for content `c`. */ /** Gets an approximated value for content `c`. */
pragma[inline] pragma[inline]
ContentApprox getContentApprox(Content c) { ContentApprox getContentApprox(Content c) {
@@ -1416,9 +1439,6 @@ ContentApprox getContentApprox(Content c) {
u = c.(UnionContent).getUnion() and u = c.(UnionContent).getUnion() and
unionHasApproxName(u, prefix) unionHasApproxName(u, prefix)
) )
or
c instanceof ElementContent and
result instanceof ElementApproxContent
} }
/** /**
@@ -1614,8 +1634,6 @@ private Instruction getAnInstruction(Node n) {
or or
result = n.(SsaPhiNode).getPhiNode().getBasicBlock().getFirstInstruction() result = n.(SsaPhiNode).getPhiNode().getBasicBlock().getFirstInstruction()
or or
result = n.(SsaPhiInputNode).getBasicBlock().getFirstInstruction()
or
n.(IndirectInstruction).hasInstructionAndIndirectionIndex(result, _) n.(IndirectInstruction).hasInstructionAndIndirectionIndex(result, _)
or or
not n instanceof IndirectInstruction and not n instanceof IndirectInstruction and
@@ -1678,14 +1696,6 @@ class DataFlowSecondLevelScope extends TDataFlowSecondLevelScope {
/** Gets the second-level scope containing the node `n`, if any. */ /** Gets the second-level scope containing the node `n`, if any. */
DataFlowSecondLevelScope getSecondLevelScope(Node n) { result.getANode() = n } DataFlowSecondLevelScope getSecondLevelScope(Node n) { result.getANode() = n }
/**
* Gets the maximum number of indirections to use for `ElementContent`.
*
* This should be equal to the largest number of stars (i.e., `*`s) in any
* `Element` content across all of our MaD summaries, sources, and sinks.
*/
int getMaxElementContentIndirectionIndex() { result = 5 }
/** /**
* Module that defines flow through iterators. * Module that defines flow through iterators.
* For example, * For example,
@@ -1753,7 +1763,7 @@ module IteratorFlow {
crementCall = def.getValue().asInstruction().(StoreInstruction).getSourceValue() and crementCall = def.getValue().asInstruction().(StoreInstruction).getSourceValue() and
sv = def.getSourceVariable() and sv = def.getSourceVariable() and
bb.getInstruction(i) = crementCall and bb.getInstruction(i) = crementCall and
Ssa::ssaDefReachesReadExt(sv, result.asDef(), bb, i) Ssa::ssaDefReachesRead(sv, result.asDef(), bb, i)
) )
} }
@@ -1787,7 +1797,7 @@ module IteratorFlow {
isIteratorWrite(writeToDeref, address) and isIteratorWrite(writeToDeref, address) and
operandForFullyConvertedCall(address, starCall) and operandForFullyConvertedCall(address, starCall) and
bbStar.getInstruction(iStar) = starCall and bbStar.getInstruction(iStar) = starCall and
Ssa::ssaDefReachesReadExt(_, def.asDef(), bbStar, iStar) and Ssa::ssaDefReachesRead(_, def.asDef(), bbStar, iStar) and
ultimate = getAnUltimateDefinition*(def) and ultimate = getAnUltimateDefinition*(def) and
beginStore = ultimate.getValue().asInstruction() and beginStore = ultimate.getValue().asInstruction() and
operandForFullyConvertedCall(beginStore.getSourceValueOperand(), beginCall) operandForFullyConvertedCall(beginStore.getSourceValueOperand(), beginCall)
@@ -1798,7 +1808,7 @@ module IteratorFlow {
* Holds if `(bb, i)` contains a write to an iterator that may have been obtained * Holds if `(bb, i)` contains a write to an iterator that may have been obtained
* by calling `begin` (or related functions) on the variable `v`. * by calling `begin` (or related functions) on the variable `v`.
*/ */
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { predicate variableWrite(IRBlock bb, int i, SourceVariable v, boolean certain) {
certain = false and certain = false and
exists(GetsIteratorCall beginCall, Instruction writeToDeref, IRBlock bbQual, int iQual | exists(GetsIteratorCall beginCall, Instruction writeToDeref, IRBlock bbQual, int iQual |
isIteratorStoreInstruction(beginCall, writeToDeref) and isIteratorStoreInstruction(beginCall, writeToDeref) and
@@ -1809,7 +1819,7 @@ module IteratorFlow {
} }
/** Holds if `(bb, i)` reads the container variable `v`. */ /** Holds if `(bb, i)` reads the container variable `v`. */
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { predicate variableRead(IRBlock bb, int i, SourceVariable v, boolean certain) {
Ssa::variableRead(bb, i, v, certain) Ssa::variableRead(bb, i, v, certain)
} }
} }

View File

@@ -17,7 +17,6 @@ private import SsaInternals as Ssa
private import DataFlowImplCommon as DataFlowImplCommon private import DataFlowImplCommon as DataFlowImplCommon
private import codeql.util.Unit private import codeql.util.Unit
private import Node0ToString private import Node0ToString
import ExprNodes
/** /**
* The IR dataflow graph consists of the following nodes: * The IR dataflow graph consists of the following nodes:
@@ -46,7 +45,6 @@ private newtype TIRDataFlowNode =
or or
Ssa::isModifiableByCall(operand, indirectionIndex) Ssa::isModifiableByCall(operand, indirectionIndex)
} or } or
TSsaPhiInputNode(Ssa::PhiNode phi, IRBlock input) { phi.hasInputFromBlock(_, _, _, _, input) } or
TSsaPhiNode(Ssa::PhiNode phi) or TSsaPhiNode(Ssa::PhiNode phi) or
TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) { TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
@@ -116,13 +114,6 @@ predicate conversionFlow(
instrTo.(CheckedConvertOrNullInstruction).getUnaryOperand() = opFrom instrTo.(CheckedConvertOrNullInstruction).getUnaryOperand() = opFrom
or or
instrTo.(InheritanceConversionInstruction).getUnaryOperand() = opFrom instrTo.(InheritanceConversionInstruction).getUnaryOperand() = opFrom
or
exists(BuiltInInstruction builtIn |
builtIn = instrTo and
// __builtin_bit_cast
builtIn.getBuiltInOperation() instanceof BuiltInBitCast and
opFrom = builtIn.getAnOperand()
)
) )
or or
additional = true and additional = true and
@@ -167,12 +158,6 @@ class Node extends TIRDataFlowNode {
/** Gets the operands corresponding to this node, if any. */ /** Gets the operands corresponding to this node, if any. */
Operand asOperand() { result = this.(OperandNode).getOperand() } Operand asOperand() { result = this.(OperandNode).getOperand() }
/**
* Gets the operand that is indirectly tracked by this node behind `index`
* number of indirections.
*/
Operand asIndirectOperand(int index) { hasOperandAndIndex(this, result, index) }
/** /**
* Holds if this node is at index `i` in basic block `block`. * Holds if this node is at index `i` in basic block `block`.
* *
@@ -185,9 +170,6 @@ class Node extends TIRDataFlowNode {
or or
this.(SsaPhiNode).getPhiNode().getBasicBlock() = block and i = -1 this.(SsaPhiNode).getPhiNode().getBasicBlock() = block and i = -1
or or
this.(SsaPhiInputNode).getBlock() = block and
i = block.getInstructionCount()
or
this.(RawIndirectOperand).getOperand().getUse() = block.getInstruction(i) this.(RawIndirectOperand).getOperand().getUse() = block.getInstruction(i)
or or
this.(RawIndirectInstruction).getInstruction() = block.getInstruction(i) this.(RawIndirectInstruction).getInstruction() = block.getInstruction(i)
@@ -640,7 +622,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() } final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() }
override string toStringImpl() { result = phi.toString() } override string toStringImpl() { result = "Phi" }
/** /**
* Gets a node that is used as input to this phi node. * Gets a node that is used as input to this phi node.
@@ -649,7 +631,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
*/ */
cached cached
final Node getAnInput(boolean fromBackEdge) { final Node getAnInput(boolean fromBackEdge) {
result.(SsaPhiInputNode).getPhiNode() = phi and localFlowStep(result, this) and
exists(IRBlock bPhi, IRBlock bResult | exists(IRBlock bPhi, IRBlock bResult |
bPhi = phi.getBasicBlock() and bResult = result.getBasicBlock() bPhi = phi.getBasicBlock() and bResult = result.getBasicBlock()
| |
@@ -672,58 +654,6 @@ class SsaPhiNode extends Node, TSsaPhiNode {
predicate isPhiRead() { phi.isPhiRead() } predicate isPhiRead() { phi.isPhiRead() }
} }
/**
* INTERNAL: Do not use.
*
* A node that is used as an input to a phi node.
*
* This class exists to allow more powerful barrier guards. Consider this
* example:
*
* ```cpp
* int x = source();
* if(!safe(x)) {
* x = clear();
* }
* // phi node for x here
* sink(x);
* ```
*
* At the phi node for `x` it is neither the case that `x` is dominated by
* `safe(x)`, or is the case that the phi is dominated by a clearing of `x`.
*
* By inserting a "phi input" node as the last entry in the basic block that
* defines the inputs to the phi we can conclude that each of those inputs are
* safe to pass to `sink`.
*/
class SsaPhiInputNode extends Node, TSsaPhiInputNode {
Ssa::PhiNode phi;
IRBlock block;
SsaPhiInputNode() { this = TSsaPhiInputNode(phi, block) }
/** Gets the phi node associated with this node. */
Ssa::PhiNode getPhiNode() { result = phi }
/** Gets the basic block in which this input originates. */
IRBlock getBlock() { result = block }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
override DataFlowType getType() { result = this.getSourceVariable().getType() }
override predicate isGLValue() { phi.getSourceVariable().isGLValue() }
final override Location getLocationImpl() { result = block.getLastInstruction().getLocation() }
override string toStringImpl() { result = "Phi input" }
/** Gets the source variable underlying this phi node. */
Ssa::SourceVariable getSourceVariable() { result = phi.getSourceVariable() }
}
/** /**
* INTERNAL: do not use. * INTERNAL: do not use.
* *
@@ -1297,6 +1227,466 @@ class UninitializedNode extends Node {
LocalVariable getLocalVariable() { result = v } LocalVariable getLocalVariable() { result = v }
} }
private module GetConvertedResultExpression {
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
private Operand getAnInitializeDynamicAllocationInstructionAddress() {
result = any(InitializeDynamicAllocationInstruction init).getAllocationAddressOperand()
}
/**
* Gets the expression that should be returned as the result expression from `instr`.
*
* Note that this predicate may return multiple results in cases where a conversion belongs to a
* different AST element than its operand.
*/
Expr getConvertedResultExpression(Instruction instr, int n) {
// Only fully converted instructions have a result for `asConvertedExpr`
not conversionFlow(unique(Operand op |
// The address operand of a `InitializeDynamicAllocationInstruction` is
// special: we need to handle it during dataflow (since it's
// effectively a store to an indirection), but it doesn't appear in
// source syntax, so dataflow node <-> expression conversion shouldn't
// care about it.
op = getAUse(instr) and not op = getAnInitializeDynamicAllocationInstructionAddress()
|
op
), _, false, false) and
result = getConvertedResultExpressionImpl(instr) and
n = 0
or
// If the conversion also has a result then we return multiple results
exists(Operand operand | conversionFlow(operand, instr, false, false) |
n = 1 and
result = getConvertedResultExpressionImpl(operand.getDef())
or
result = getConvertedResultExpression(operand.getDef(), n - 1)
)
}
private Expr getConvertedResultExpressionImpl0(Instruction instr) {
// IR construction inserts an additional cast to a `size_t` on the extent
// of a `new[]` expression. The resulting `ConvertInstruction` doesn't have
// a result for `getConvertedResultExpression`. We remap this here so that
// this `ConvertInstruction` maps to the result of the expression that
// represents the extent.
exists(TranslatedNonConstantAllocationSize tas |
result = tas.getExtent().getExpr() and
instr = tas.getInstruction(AllocationExtentConvertTag())
)
or
// There's no instruction that returns `ParenthesisExpr`, but some queries
// expect this
exists(TranslatedTransparentConversion ttc |
result = ttc.getExpr().(ParenthesisExpr) and
instr = ttc.getResult()
)
or
// Certain expressions generate `CopyValueInstruction`s only when they
// are needed. Examples of this include crement operations and compound
// assignment operations. For example:
// ```cpp
// int x = ...
// int y = x++;
// ```
// this generate IR like:
// ```
// r1(glval<int>) = VariableAddress[x] :
// r2(int) = Constant[0] :
// m3(int) = Store[x] : &:r1, r2
// r4(glval<int>) = VariableAddress[y] :
// r5(glval<int>) = VariableAddress[x] :
// r6(int) = Load[x] : &:r5, m3
// r7(int) = Constant[1] :
// r8(int) = Add : r6, r7
// m9(int) = Store[x] : &:r5, r8
// r11(int) = CopyValue : r6
// m12(int) = Store[y] : &:r4, r11
// ```
// When the `CopyValueInstruction` is not generated there is no instruction
// whose `getConvertedResultExpression` maps back to the expression. When
// such an instruction doesn't exist it means that the old value is not
// needed, and in that case the only value that will propagate forward in
// the program is the value that's been updated. So in those cases we just
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
exists(TranslatedCoreExpr tco |
tco.getInstruction(_) = instr and
tco.producesExprResult() and
result = asDefinitionImpl0(instr)
)
}
private Expr getConvertedResultExpressionImpl(Instruction instr) {
result = getConvertedResultExpressionImpl0(instr)
or
not exists(getConvertedResultExpressionImpl0(instr)) and
result = instr.getConvertedResultExpression()
}
/**
* Gets the result for `node.asDefinition()` (when `node` is the instruction
* node that wraps `store`) in the cases where `store.getAst()` should not be
* used to define the result of `node.asDefinition()`.
*/
private Expr asDefinitionImpl0(StoreInstruction store) {
// For an expression such as `i += 2` we pretend that the generated
// `StoreInstruction` contains the result of the expression even though
// this isn't totally aligned with the C/C++ standard.
exists(TranslatedAssignOperation tao |
store = tao.getInstruction(AssignmentStoreTag()) and
result = tao.getExpr()
)
or
// Similarly for `i++` and `++i` we pretend that the generated
// `StoreInstruction` is contains the result of the expression even though
// this isn't totally aligned with the C/C++ standard.
exists(TranslatedCrementOperation tco |
store = tco.getInstruction(CrementStoreTag()) and
result = tco.getExpr()
)
}
/**
* Holds if the expression returned by `store.getAst()` should not be
* returned as the result of `node.asDefinition()` when `node` is the
* instruction node that wraps `store`.
*/
private predicate excludeAsDefinitionResult(StoreInstruction store) {
// Exclude the store to the temporary generated by a ternary expression.
exists(TranslatedConditionalExpr tce |
store = tce.getInstruction(ConditionValueFalseStoreTag())
or
store = tce.getInstruction(ConditionValueTrueStoreTag())
)
}
/**
* Gets the expression that represents the result of `StoreInstruction` for
* dataflow purposes.
*
* For example, consider the following example
* ```cpp
* int x = 42; // 1
* x = 34; // 2
* ++x; // 3
* x++; // 4
* x += 1; // 5
* int y = x += 2; // 6
* ```
* For (1) the result is `42`.
* For (2) the result is `x = 34`.
* For (3) the result is `++x`.
* For (4) the result is `x++`.
* For (5) the result is `x += 1`.
* For (6) there are two results:
* - For the `StoreInstruction` generated by `x += 2` the result
* is `x += 2`
* - For the `StoreInstruction` generated by `int y = ...` the result
* is also `x += 2`
*/
Expr asDefinitionImpl(StoreInstruction store) {
not exists(asDefinitionImpl0(store)) and
not excludeAsDefinitionResult(store) and
result = store.getAst().(Expr).getUnconverted()
or
result = asDefinitionImpl0(store)
}
}
private import GetConvertedResultExpression
/** Holds if `node` is an `OperandNode` that should map `node.asExpr()` to `e`. */
predicate exprNodeShouldBeOperand(OperandNode node, Expr e, int n) {
not exprNodeShouldBeIndirectOperand(_, e, n) and
exists(Instruction def |
unique( | | getAUse(def)) = node.getOperand() and
e = getConvertedResultExpression(def, n)
)
}
/** Holds if `node` should be an `IndirectOperand` that maps `node.asIndirectExpr()` to `e`. */
private predicate indirectExprNodeShouldBeIndirectOperand(
IndirectOperand node, Expr e, int n, int indirectionIndex
) {
exists(Instruction def |
node.hasOperandAndIndirectionIndex(unique( | | getAUse(def)), indirectionIndex) and
e = getConvertedResultExpression(def, n)
)
}
/** Holds if `node` should be an `IndirectOperand` that maps `node.asExpr()` to `e`. */
private predicate exprNodeShouldBeIndirectOperand(IndirectOperand node, Expr e, int n) {
exists(ArgumentOperand operand |
// When an argument (qualifier or positional) is a prvalue and the
// parameter (qualifier or positional) is a (const) reference, IR
// construction introduces a temporary `IRVariable`. The `VariableAddress`
// instruction has the argument as its `getConvertedResultExpression`
// result. However, the instruction actually represents the _address_ of
// the argument. So to fix this mismatch, we have the indirection of the
// `VariableAddressInstruction` map to the expression.
node.hasOperandAndIndirectionIndex(operand, 1) and
e = getConvertedResultExpression(operand.getDef(), n) and
operand.getDef().(VariableAddressInstruction).getIRVariable() instanceof IRTempVariable
)
}
private predicate exprNodeShouldBeIndirectOutNode(IndirectArgumentOutNode node, Expr e, int n) {
exists(CallInstruction call |
call.getStaticCallTarget() instanceof Constructor and
e = getConvertedResultExpression(call, n) and
call.getThisArgumentOperand() = node.getAddressOperand()
)
}
/** Holds if `node` should be an instruction node that maps `node.asExpr()` to `e`. */
predicate exprNodeShouldBeInstruction(Node node, Expr e, int n) {
not exprNodeShouldBeOperand(_, e, n) and
not exprNodeShouldBeIndirectOutNode(_, e, n) and
not exprNodeShouldBeIndirectOperand(_, e, n) and
e = getConvertedResultExpression(node.asInstruction(), n)
}
/** Holds if `node` should be an `IndirectInstruction` that maps `node.asIndirectExpr()` to `e`. */
predicate indirectExprNodeShouldBeIndirectInstruction(
IndirectInstruction node, Expr e, int n, int indirectionIndex
) {
not indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) and
exists(Instruction instr |
node.hasInstructionAndIndirectionIndex(instr, indirectionIndex) and
e = getConvertedResultExpression(instr, n)
)
}
abstract private class ExprNodeBase extends Node {
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
abstract Expr getConvertedExpr(int n);
/** Gets the non-conversion expression corresponding to this node, if any. */
final Expr getExpr(int n) { result = this.getConvertedExpr(n).getUnconverted() }
}
/**
* Holds if there exists a dataflow node whose `asExpr(n)` should evaluate
* to `e`.
*/
private predicate exprNodeShouldBe(Expr e, int n) {
exprNodeShouldBeInstruction(_, e, n) or
exprNodeShouldBeOperand(_, e, n) or
exprNodeShouldBeIndirectOutNode(_, e, n) or
exprNodeShouldBeIndirectOperand(_, e, n)
}
private class InstructionExprNode extends ExprNodeBase, InstructionNode {
InstructionExprNode() {
exists(Expr e, int n |
exprNodeShouldBeInstruction(this, e, n) and
not exists(Expr conv |
exprNodeShouldBe(conv, n + 1) and
conv.getUnconverted() = e.getUnconverted()
)
)
}
final override Expr getConvertedExpr(int n) { exprNodeShouldBeInstruction(this, result, n) }
}
private class OperandExprNode extends ExprNodeBase, OperandNode {
OperandExprNode() {
exists(Expr e, int n |
exprNodeShouldBeOperand(this, e, n) and
not exists(Expr conv |
exprNodeShouldBe(conv, n + 1) and
conv.getUnconverted() = e.getUnconverted()
)
)
}
final override Expr getConvertedExpr(int n) { exprNodeShouldBeOperand(this, result, n) }
}
abstract private class IndirectExprNodeBase extends Node {
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
abstract Expr getConvertedExpr(int n, int indirectionIndex);
/** Gets the non-conversion expression corresponding to this node, if any. */
final Expr getExpr(int n, int indirectionIndex) {
result = this.getConvertedExpr(n, indirectionIndex).getUnconverted()
}
}
/** A signature for converting an indirect node to an expression. */
private signature module IndirectNodeToIndirectExprSig {
/** The indirect node class to be converted to an expression */
class IndirectNode;
/**
* Holds if the indirect expression at indirection index `indirectionIndex`
* of `node` is `e`. The integer `n` specifies how many conversions has been
* applied to `node`.
*/
predicate indirectNodeHasIndirectExpr(IndirectNode node, Expr e, int n, int indirectionIndex);
}
/**
* A module that implements the logic for deciding whether an indirect node
* should be an `IndirectExprNode`.
*/
private module IndirectNodeToIndirectExpr<IndirectNodeToIndirectExprSig Sig> {
import Sig
/**
* This predicate shifts the indirection index by one when `conv` is a
* `ReferenceDereferenceExpr`.
*
* This is necessary because `ReferenceDereferenceExpr` is a conversion
* in the AST, but appears as a `LoadInstruction` in the IR.
*/
bindingset[e, indirectionIndex]
private predicate adjustForReference(
Expr e, int indirectionIndex, Expr conv, int adjustedIndirectionIndex
) {
conv.(ReferenceDereferenceExpr).getExpr() = e and
adjustedIndirectionIndex = indirectionIndex - 1
or
not conv instanceof ReferenceDereferenceExpr and
conv = e and
adjustedIndirectionIndex = indirectionIndex
}
/** Holds if `node` should be an `IndirectExprNode`. */
predicate charpred(IndirectNode node) {
exists(Expr e, int n, int indirectionIndex |
indirectNodeHasIndirectExpr(node, e, n, indirectionIndex) and
not exists(Expr conv, int adjustedIndirectionIndex |
adjustForReference(e, indirectionIndex, conv, adjustedIndirectionIndex) and
indirectExprNodeShouldBe(conv, n + 1, adjustedIndirectionIndex)
)
)
}
}
private predicate indirectExprNodeShouldBe(Expr e, int n, int indirectionIndex) {
indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) or
indirectExprNodeShouldBeIndirectInstruction(_, e, n, indirectionIndex)
}
private module IndirectOperandIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
class IndirectNode = IndirectOperand;
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectOperand/4;
}
module IndirectOperandToIndirectExpr =
IndirectNodeToIndirectExpr<IndirectOperandIndirectExprNodeImpl>;
private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
{
IndirectOperandIndirectExprNode() { IndirectOperandToIndirectExpr::charpred(this) }
final override Expr getConvertedExpr(int n, int index) {
IndirectOperandToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
}
}
private module IndirectInstructionIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
class IndirectNode = IndirectInstruction;
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectInstruction/4;
}
module IndirectInstructionToIndirectExpr =
IndirectNodeToIndirectExpr<IndirectInstructionIndirectExprNodeImpl>;
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction
{
IndirectInstructionIndirectExprNode() { IndirectInstructionToIndirectExpr::charpred(this) }
final override Expr getConvertedExpr(int n, int index) {
IndirectInstructionToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
}
}
private class IndirectArgumentOutExprNode extends ExprNodeBase, IndirectArgumentOutNode {
IndirectArgumentOutExprNode() { exprNodeShouldBeIndirectOutNode(this, _, _) }
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOutNode(this, result, n) }
}
private class IndirectOperandExprNode extends ExprNodeBase instanceof IndirectOperand {
IndirectOperandExprNode() { exprNodeShouldBeIndirectOperand(this, _, _) }
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOperand(this, result, n) }
}
/**
* An expression, viewed as a node in a data flow graph.
*/
class ExprNode extends Node instanceof ExprNodeBase {
/**
* INTERNAL: Do not use.
*/
Expr getExpr(int n) { result = super.getExpr(n) }
/**
* Gets the non-conversion expression corresponding to this node, if any. If
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
* expression.
*/
final Expr getExpr() { result = this.getExpr(_) }
/**
* INTERNAL: Do not use.
*/
Expr getConvertedExpr(int n) { result = super.getConvertedExpr(n) }
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
final Expr getConvertedExpr() { result = this.getConvertedExpr(_) }
}
/**
* An indirect expression, viewed as a node in a data flow graph.
*/
class IndirectExprNode extends Node instanceof IndirectExprNodeBase {
/**
* Gets the non-conversion expression corresponding to this node, if any. If
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
* expression.
*/
final Expr getExpr(int indirectionIndex) { result = this.getExpr(_, indirectionIndex) }
/**
* INTERNAL: Do not use.
*/
Expr getExpr(int n, int indirectionIndex) { result = super.getExpr(n, indirectionIndex) }
/**
* INTERNAL: Do not use.
*/
Expr getConvertedExpr(int n, int indirectionIndex) {
result = super.getConvertedExpr(n, indirectionIndex)
}
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
Expr getConvertedExpr(int indirectionIndex) {
result = this.getConvertedExpr(_, indirectionIndex)
}
}
abstract private class AbstractParameterNode extends Node { abstract private class AbstractParameterNode extends Node {
/** /**
* Holds if this node is the parameter of `f` at the specified position. The * Holds if this node is the parameter of `f` at the specified position. The
@@ -1786,9 +2176,6 @@ private module Cached {
// Def-use/Use-use flow // Def-use/Use-use flow
Ssa::ssaFlow(nodeFrom, nodeTo) Ssa::ssaFlow(nodeFrom, nodeTo)
or or
// Phi input -> Phi
nodeFrom.(SsaPhiInputNode).getPhiNode() = nodeTo.(SsaPhiNode).getPhiNode()
or
IteratorFlow::localFlowStep(nodeFrom, nodeTo) IteratorFlow::localFlowStep(nodeFrom, nodeTo)
or or
// Operand -> Instruction flow // Operand -> Instruction flow
@@ -2083,9 +2470,6 @@ private newtype TContent =
indirectionIndex = indirectionIndex =
[1 .. max(Ssa::getMaxIndirectionsForType(getAFieldWithSize(u, bytes).getUnspecifiedType()))] [1 .. max(Ssa::getMaxIndirectionsForType(getAFieldWithSize(u, bytes).getUnspecifiedType()))]
) )
} or
TElementContent(int indirectionIndex) {
indirectionIndex = [1 .. getMaxElementContentIndirectionIndex()]
} }
/** /**
@@ -2196,25 +2580,6 @@ class UnionContent extends Content, TUnionContent {
} }
} }
/**
* A `Content` that represents one of the elements of a
* container (e.g., `std::vector`).
*/
class ElementContent extends Content, TElementContent {
int indirectionIndex;
ElementContent() { this = TElementContent(indirectionIndex) }
pragma[inline]
override int getIndirectionIndex() {
pragma[only_bind_into](result) = pragma[only_bind_out](indirectionIndex)
}
override predicate impliesClearOf(Content c) { none() }
override string toString() { result = contentStars(this) + "element" }
}
/** /**
* An entity that represents a set of `Content`s. * An entity that represents a set of `Content`s.
* *
@@ -2249,22 +2614,6 @@ class ContentSet instanceof Content {
} }
} }
pragma[nomagic]
private predicate guardControlsPhiInput(
IRGuardCondition g, boolean branch, Ssa::Definition def, IRBlock input, Ssa::PhiNode phi
) {
phi.hasInputFromBlock(def, _, _, _, input) and
(
g.controls(input, branch)
or
exists(EdgeKind kind |
g.getBlock() = input and
kind = getConditionalEdge(branch) and
input.getSuccessor(kind) = phi.getBasicBlock()
)
)
}
/** /**
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`. * Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
* *
@@ -2313,21 +2662,13 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
* *
* NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead. * NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead.
*/ */
Node getABarrierNode() { ExprNode getABarrierNode() {
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge | exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
e = value.getAnInstruction().getConvertedResultExpression() and e = value.getAnInstruction().getConvertedResultExpression() and
result.asConvertedExpr() = e and result.getConvertedExpr() = e and
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
g.controls(result.getBasicBlock(), edge) g.controls(result.getBasicBlock(), edge)
) )
or
exists(
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
|
guardChecks(g, def.getARead().asOperand().getDef().getConvertedResultExpression(), branch) and
guardControlsPhiInput(g, branch, def, input, phi) and
result = TSsaPhiInputNode(phi, input)
)
} }
/** /**
@@ -2363,7 +2704,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
* *
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead. * NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
*/ */
Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) } IndirectExprNode getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
/** /**
* Gets an indirect expression node with indirection index `indirectionIndex` that is * Gets an indirect expression node with indirection index `indirectionIndex` that is
@@ -2399,23 +2740,13 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
* *
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead. * NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
*/ */
Node getAnIndirectBarrierNode(int indirectionIndex) { IndirectExprNode getAnIndirectBarrierNode(int indirectionIndex) {
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge | exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
e = value.getAnInstruction().getConvertedResultExpression() and e = value.getAnInstruction().getConvertedResultExpression() and
result.asIndirectConvertedExpr(indirectionIndex) = e and result.getConvertedExpr(indirectionIndex) = e and
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
g.controls(result.getBasicBlock(), edge) g.controls(result.getBasicBlock(), edge)
) )
or
exists(
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
|
guardChecks(g,
def.getARead().asIndirectOperand(indirectionIndex).getDef().getConvertedResultExpression(),
branch) and
guardControlsPhiInput(g, branch, def, input, phi) and
result = TSsaPhiInputNode(phi, input)
)
} }
} }
@@ -2424,14 +2755,6 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
*/ */
signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction instr, boolean branch); signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction instr, boolean branch);
private EdgeKind getConditionalEdge(boolean branch) {
branch = true and
result instanceof TrueEdge
or
branch = false and
result instanceof FalseEdge
}
/** /**
* Provides a set of barrier nodes for a guard that validates an instruction. * Provides a set of barrier nodes for a guard that validates an instruction.
* *
@@ -2440,20 +2763,12 @@ private EdgeKind getConditionalEdge(boolean branch) {
*/ */
module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> { module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> {
/** Gets a node that is safely guarded by the given guard check. */ /** Gets a node that is safely guarded by the given guard check. */
Node getABarrierNode() { ExprNode getABarrierNode() {
exists(IRGuardCondition g, ValueNumber value, boolean edge, Operand use | exists(IRGuardCondition g, ValueNumber value, boolean edge, Operand use |
instructionGuardChecks(g, value.getAnInstruction(), edge) and instructionGuardChecks(g, value.getAnInstruction(), edge) and
use = value.getAnInstruction().getAUse() and use = value.getAnInstruction().getAUse() and
result.asOperand() = use and result.asOperand() = use and
g.controls(result.getBasicBlock(), edge) g.controls(use.getDef().getBlock(), edge)
)
or
exists(
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
|
instructionGuardChecks(g, def.getARead().asOperand().getDef(), branch) and
guardControlsPhiInput(g, branch, def, input, phi) and
result = TSsaPhiInputNode(phi, input)
) )
} }
} }

View File

@@ -1,518 +0,0 @@
/**
* Provides the classes `ExprNode` and `IndirectExprNode` for converting between `Expr` and `Node`.
*/
private import cpp
private import semmle.code.cpp.ir.IR
private import DataFlowUtil
private import DataFlowPrivate
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
cached
private module Cached {
private Operand getAnInitializeDynamicAllocationInstructionAddress() {
result = any(InitializeDynamicAllocationInstruction init).getAllocationAddressOperand()
}
/**
* Gets the expression that should be returned as the result expression from `instr`.
*
* Note that this predicate may return multiple results in cases where a conversion belongs to a
* different AST element than its operand.
*/
private Expr getConvertedResultExpression(Instruction instr, int n) {
// Only fully converted instructions have a result for `asConvertedExpr`
not conversionFlow(unique(Operand op |
// The address operand of a `InitializeDynamicAllocationInstruction` is
// special: we need to handle it during dataflow (since it's
// effectively a store to an indirection), but it doesn't appear in
// source syntax, so dataflow node <-> expression conversion shouldn't
// care about it.
op = getAUse(instr) and not op = getAnInitializeDynamicAllocationInstructionAddress()
|
op
), _, false, false) and
result = getConvertedResultExpressionImpl(instr) and
n = 0
or
// If the conversion also has a result then we return multiple results
exists(Operand operand | conversionFlow(operand, instr, false, false) |
n = 1 and
result = getConvertedResultExpressionImpl(operand.getDef())
or
result = getConvertedResultExpression(operand.getDef(), n - 1)
)
}
private Expr getConvertedResultExpressionImpl0(Instruction instr) {
// IR construction inserts an additional cast to a `size_t` on the extent
// of a `new[]` expression. The resulting `ConvertInstruction` doesn't have
// a result for `getConvertedResultExpression`. We remap this here so that
// this `ConvertInstruction` maps to the result of the expression that
// represents the extent.
exists(TranslatedNonConstantAllocationSize tas |
result = tas.getExtent().getExpr() and
instr = tas.getInstruction(AllocationExtentConvertTag())
)
or
// There's no instruction that returns `ParenthesisExpr`, but some queries
// expect this
exists(TranslatedTransparentConversion ttc |
result = ttc.getExpr().(ParenthesisExpr) and
instr = ttc.getResult()
)
or
// Certain expressions generate `CopyValueInstruction`s only when they
// are needed. Examples of this include crement operations and compound
// assignment operations. For example:
// ```cpp
// int x = ...
// int y = x++;
// ```
// this generate IR like:
// ```
// r1(glval<int>) = VariableAddress[x] :
// r2(int) = Constant[0] :
// m3(int) = Store[x] : &:r1, r2
// r4(glval<int>) = VariableAddress[y] :
// r5(glval<int>) = VariableAddress[x] :
// r6(int) = Load[x] : &:r5, m3
// r7(int) = Constant[1] :
// r8(int) = Add : r6, r7
// m9(int) = Store[x] : &:r5, r8
// r11(int) = CopyValue : r6
// m12(int) = Store[y] : &:r4, r11
// ```
// When the `CopyValueInstruction` is not generated there is no instruction
// whose `getConvertedResultExpression` maps back to the expression. When
// such an instruction doesn't exist it means that the old value is not
// needed, and in that case the only value that will propagate forward in
// the program is the value that's been updated. So in those cases we just
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
exists(TranslatedCoreExpr tco |
tco.getInstruction(_) = instr and
tco.producesExprResult() and
result = asDefinitionImpl0(instr)
)
}
private Expr getConvertedResultExpressionImpl(Instruction instr) {
result = getConvertedResultExpressionImpl0(instr)
or
not exists(getConvertedResultExpressionImpl0(instr)) and
result = instr.getConvertedResultExpression()
}
/**
* Gets the result for `node.asDefinition()` (when `node` is the instruction
* node that wraps `store`) in the cases where `store.getAst()` should not be
* used to define the result of `node.asDefinition()`.
*/
private Expr asDefinitionImpl0(StoreInstruction store) {
// For an expression such as `i += 2` we pretend that the generated
// `StoreInstruction` contains the result of the expression even though
// this isn't totally aligned with the C/C++ standard.
exists(TranslatedAssignOperation tao |
store = tao.getInstruction(AssignmentStoreTag()) and
result = tao.getExpr()
)
or
// Similarly for `i++` and `++i` we pretend that the generated
// `StoreInstruction` is contains the result of the expression even though
// this isn't totally aligned with the C/C++ standard.
exists(TranslatedCrementOperation tco |
store = tco.getInstruction(CrementStoreTag()) and
result = tco.getExpr()
)
}
/**
* Holds if the expression returned by `store.getAst()` should not be
* returned as the result of `node.asDefinition()` when `node` is the
* instruction node that wraps `store`.
*/
private predicate excludeAsDefinitionResult(StoreInstruction store) {
// Exclude the store to the temporary generated by a ternary expression.
exists(TranslatedConditionalExpr tce |
store = tce.getInstruction(ConditionValueFalseStoreTag())
or
store = tce.getInstruction(ConditionValueTrueStoreTag())
)
}
/**
* Gets the expression that represents the result of `StoreInstruction` for
* dataflow purposes.
*
* For example, consider the following example
* ```cpp
* int x = 42; // 1
* x = 34; // 2
* ++x; // 3
* x++; // 4
* x += 1; // 5
* int y = x += 2; // 6
* ```
* For (1) the result is `42`.
* For (2) the result is `x = 34`.
* For (3) the result is `++x`.
* For (4) the result is `x++`.
* For (5) the result is `x += 1`.
* For (6) there are two results:
* - For the `StoreInstruction` generated by `x += 2` the result
* is `x += 2`
* - For the `StoreInstruction` generated by `int y = ...` the result
* is also `x += 2`
*/
cached
Expr asDefinitionImpl(StoreInstruction store) {
not exists(asDefinitionImpl0(store)) and
not excludeAsDefinitionResult(store) and
result = store.getAst().(Expr).getUnconverted()
or
result = asDefinitionImpl0(store)
}
/** Holds if `node` is an `OperandNode` that should map `node.asExpr()` to `e`. */
private predicate exprNodeShouldBeOperand(OperandNode node, Expr e, int n) {
not exprNodeShouldBeIndirectOperand(_, e, n) and
exists(Instruction def |
unique( | | getAUse(def)) = node.getOperand() and
e = getConvertedResultExpression(def, n)
)
}
/** Holds if `node` should be an `IndirectOperand` that maps `node.asIndirectExpr()` to `e`. */
private predicate indirectExprNodeShouldBeIndirectOperand(
IndirectOperand node, Expr e, int n, int indirectionIndex
) {
exists(Instruction def |
node.hasOperandAndIndirectionIndex(unique( | | getAUse(def)), indirectionIndex) and
e = getConvertedResultExpression(def, n)
)
}
/** Holds if `operand`'s definition is a `VariableAddressInstruction` whose variable is a temporary */
private predicate isIRTempVariable(Operand operand) {
operand.getDef().(VariableAddressInstruction).getIRVariable() instanceof IRTempVariable
}
/**
* Holds if `node` is an indirect operand whose operand is an argument, and
* the `n`'th expression associated with the operand is `e`.
*/
private predicate isIndirectOperandOfArgument(
IndirectOperand node, ArgumentOperand operand, Expr e, int n
) {
node.hasOperandAndIndirectionIndex(operand, 1) and
e = getConvertedResultExpression(operand.getDef(), n)
}
/**
* Holds if `opFrom` is an operand to a conversion, and `opTo` is the unique
* use of the conversion.
*/
private predicate isConversionStep(Operand opFrom, Operand opTo) {
exists(Instruction mid |
conversionFlow(opFrom, mid, false, false) and
opTo = unique( | | getAUse(mid))
)
}
/**
* Holds if an operand that satisfies `isIRTempVariable` flows to `op`
* through a (possibly empty) sequence of conversions.
*/
private predicate irTempOperandConversionFlows(Operand op) {
isIRTempVariable(op)
or
exists(Operand mid |
irTempOperandConversionFlows(mid) and
isConversionStep(mid, op)
)
}
/** Holds if `node` should be an `IndirectOperand` that maps `node.asExpr()` to `e`. */
private predicate exprNodeShouldBeIndirectOperand(IndirectOperand node, Expr e, int n) {
exists(ArgumentOperand operand |
// When an argument (qualifier or positional) is a prvalue and the
// parameter (qualifier or positional) is a (const) reference, IR
// construction introduces a temporary `IRVariable`. The `VariableAddress`
// instruction has the argument as its `getConvertedResultExpression`
// result. However, the instruction actually represents the _address_ of
// the argument. So to fix this mismatch, we have the indirection of the
// `VariableAddressInstruction` map to the expression.
isIndirectOperandOfArgument(node, operand, e, n) and
irTempOperandConversionFlows(operand)
)
}
private predicate exprNodeShouldBeIndirectOutNode(IndirectArgumentOutNode node, Expr e, int n) {
exists(CallInstruction call |
call.getStaticCallTarget() instanceof Constructor and
e = getConvertedResultExpression(call, n) and
call.getThisArgumentOperand() = node.getAddressOperand()
)
}
/** Holds if `node` should be an instruction node that maps `node.asExpr()` to `e`. */
private predicate exprNodeShouldBeInstruction(Node node, Expr e, int n) {
not exprNodeShouldBeOperand(_, e, n) and
not exprNodeShouldBeIndirectOutNode(_, e, n) and
not exprNodeShouldBeIndirectOperand(_, e, n) and
e = getConvertedResultExpression(node.asInstruction(), n)
}
/** Holds if `node` should be an `IndirectInstruction` that maps `node.asIndirectExpr()` to `e`. */
private predicate indirectExprNodeShouldBeIndirectInstruction(
IndirectInstruction node, Expr e, int n, int indirectionIndex
) {
not indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) and
exists(Instruction instr |
node.hasInstructionAndIndirectionIndex(instr, indirectionIndex) and
e = getConvertedResultExpression(instr, n)
)
}
abstract private class ExprNodeBase extends Node {
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
abstract Expr getConvertedExpr(int n);
/** Gets the non-conversion expression corresponding to this node, if any. */
final Expr getExpr(int n) { result = this.getConvertedExpr(n).getUnconverted() }
}
/**
* Holds if there exists a dataflow node whose `asExpr(n)` should evaluate
* to `e`.
*/
private predicate exprNodeShouldBe(Expr e, int n) {
exprNodeShouldBeInstruction(_, e, n) or
exprNodeShouldBeOperand(_, e, n) or
exprNodeShouldBeIndirectOutNode(_, e, n) or
exprNodeShouldBeIndirectOperand(_, e, n)
}
private class InstructionExprNode extends ExprNodeBase, InstructionNode {
InstructionExprNode() {
exists(Expr e, int n |
exprNodeShouldBeInstruction(this, e, n) and
not exists(Expr conv |
exprNodeShouldBe(conv, n + 1) and
conv.getUnconverted() = e.getUnconverted()
)
)
}
final override Expr getConvertedExpr(int n) { exprNodeShouldBeInstruction(this, result, n) }
}
private class OperandExprNode extends ExprNodeBase, OperandNode {
OperandExprNode() {
exists(Expr e, int n |
exprNodeShouldBeOperand(this, e, n) and
not exists(Expr conv |
exprNodeShouldBe(conv, n + 1) and
conv.getUnconverted() = e.getUnconverted()
)
)
}
final override Expr getConvertedExpr(int n) { exprNodeShouldBeOperand(this, result, n) }
}
abstract private class IndirectExprNodeBase extends Node {
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
abstract Expr getConvertedExpr(int n, int indirectionIndex);
/** Gets the non-conversion expression corresponding to this node, if any. */
final Expr getExpr(int n, int indirectionIndex) {
result = this.getConvertedExpr(n, indirectionIndex).getUnconverted()
}
}
/** A signature for converting an indirect node to an expression. */
private signature module IndirectNodeToIndirectExprSig {
/** The indirect node class to be converted to an expression */
class IndirectNode;
/**
* Holds if the indirect expression at indirection index `indirectionIndex`
* of `node` is `e`. The integer `n` specifies how many conversions has been
* applied to `node`.
*/
predicate indirectNodeHasIndirectExpr(IndirectNode node, Expr e, int n, int indirectionIndex);
}
/**
* A module that implements the logic for deciding whether an indirect node
* should be an `IndirectExprNode`.
*/
private module IndirectNodeToIndirectExpr<IndirectNodeToIndirectExprSig Sig> {
import Sig
/**
* This predicate shifts the indirection index by one when `conv` is a
* `ReferenceDereferenceExpr`.
*
* This is necessary because `ReferenceDereferenceExpr` is a conversion
* in the AST, but appears as a `LoadInstruction` in the IR.
*/
bindingset[e, indirectionIndex]
private predicate adjustForReference(
Expr e, int indirectionIndex, Expr conv, int adjustedIndirectionIndex
) {
conv.(ReferenceDereferenceExpr).getExpr() = e and
adjustedIndirectionIndex = indirectionIndex - 1
or
not conv instanceof ReferenceDereferenceExpr and
conv = e and
adjustedIndirectionIndex = indirectionIndex
}
/** Holds if `node` should be an `IndirectExprNode`. */
predicate charpred(IndirectNode node) {
exists(Expr e, int n, int indirectionIndex |
indirectNodeHasIndirectExpr(node, e, n, indirectionIndex) and
not exists(Expr conv, int adjustedIndirectionIndex |
adjustForReference(e, indirectionIndex, conv, adjustedIndirectionIndex) and
indirectExprNodeShouldBe(conv, n + 1, adjustedIndirectionIndex)
)
)
}
}
private predicate indirectExprNodeShouldBe(Expr e, int n, int indirectionIndex) {
indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) or
indirectExprNodeShouldBeIndirectInstruction(_, e, n, indirectionIndex)
}
private module IndirectOperandIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
class IndirectNode = IndirectOperand;
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectOperand/4;
}
module IndirectOperandToIndirectExpr =
IndirectNodeToIndirectExpr<IndirectOperandIndirectExprNodeImpl>;
private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
{
IndirectOperandIndirectExprNode() { IndirectOperandToIndirectExpr::charpred(this) }
final override Expr getConvertedExpr(int n, int index) {
IndirectOperandToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
}
}
private module IndirectInstructionIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
class IndirectNode = IndirectInstruction;
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectInstruction/4;
}
module IndirectInstructionToIndirectExpr =
IndirectNodeToIndirectExpr<IndirectInstructionIndirectExprNodeImpl>;
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction
{
IndirectInstructionIndirectExprNode() { IndirectInstructionToIndirectExpr::charpred(this) }
final override Expr getConvertedExpr(int n, int index) {
IndirectInstructionToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
}
}
private class IndirectArgumentOutExprNode extends ExprNodeBase, IndirectArgumentOutNode {
IndirectArgumentOutExprNode() { exprNodeShouldBeIndirectOutNode(this, _, _) }
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOutNode(this, result, n) }
}
private class IndirectOperandExprNode extends ExprNodeBase instanceof IndirectOperand {
IndirectOperandExprNode() { exprNodeShouldBeIndirectOperand(this, _, _) }
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOperand(this, result, n) }
}
/**
* An expression, viewed as a node in a data flow graph.
*/
cached
class ExprNode extends Node instanceof ExprNodeBase {
/**
* INTERNAL: Do not use.
*/
cached
Expr getExpr(int n) { result = super.getExpr(n) }
/**
* Gets the non-conversion expression corresponding to this node, if any. If
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
* expression.
*/
cached
final Expr getExpr() { result = this.getExpr(_) }
/**
* INTERNAL: Do not use.
*/
cached
Expr getConvertedExpr(int n) { result = super.getConvertedExpr(n) }
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
cached
final Expr getConvertedExpr() { result = this.getConvertedExpr(_) }
}
/**
* An indirect expression, viewed as a node in a data flow graph.
*/
cached
class IndirectExprNode extends Node instanceof IndirectExprNodeBase {
/**
* Gets the non-conversion expression corresponding to this node, if any. If
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
* expression.
*/
cached
final Expr getExpr(int indirectionIndex) { result = this.getExpr(_, indirectionIndex) }
/**
* INTERNAL: Do not use.
*/
cached
Expr getExpr(int n, int indirectionIndex) { result = super.getExpr(n, indirectionIndex) }
/**
* INTERNAL: Do not use.
*/
cached
Expr getConvertedExpr(int n, int indirectionIndex) {
result = super.getConvertedExpr(n, indirectionIndex)
}
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
cached
Expr getConvertedExpr(int indirectionIndex) {
result = this.getConvertedExpr(_, indirectionIndex)
}
}
}
import Cached

View File

@@ -104,7 +104,7 @@ predicate hasRawIndirectInstruction(Instruction instr, int indirectionIndex) {
cached cached
private newtype TDefImpl = private newtype TDefImpl =
TDefAddressImpl(BaseSourceVariable v) or TDefAddressImpl(BaseIRVariable v) or
TDirectDefImpl(Operand address, int indirectionIndex) { TDirectDefImpl(Operand address, int indirectionIndex) {
isDef(_, _, address, _, _, indirectionIndex) isDef(_, _, address, _, _, indirectionIndex)
} or } or
@@ -325,9 +325,9 @@ private Instruction getInitializationTargetAddress(IRVariable v) {
) )
} }
/** An initial definition of an SSA variable address. */ /** An initial definition of an `IRVariable`'s address. */
abstract private class DefAddressImpl extends DefImpl, TDefAddressImpl { private class DefAddressImpl extends DefImpl, TDefAddressImpl {
BaseSourceVariable v; BaseIRVariable v;
DefAddressImpl() { DefAddressImpl() {
this = TDefAddressImpl(v) and this = TDefAddressImpl(v) and
@@ -342,19 +342,6 @@ abstract private class DefAddressImpl extends DefImpl, TDefAddressImpl {
final override Node0Impl getValue() { none() } 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) { final override predicate hasIndexInBlock(IRBlock block, int index) {
exists(IRVariable var | var = v.getIRVariable() | exists(IRVariable var | var = v.getIRVariable() |
block.getInstruction(index) = getInitializationTargetAddress(var) block.getInstruction(index) = getInitializationTargetAddress(var)
@@ -366,14 +353,15 @@ private class DefVariableAddressImpl extends DefAddressImpl {
index = 0 index = 0
) )
} }
}
private class DefCallAddressImpl extends DefAddressImpl { override Cpp::Location getLocation() { result = v.getIRVariable().getLocation() }
override BaseCallVariable v;
final override predicate hasIndexInBlock(IRBlock block, int index) { final override SourceVariable getSourceVariable() {
block.getInstruction(index) = v.getCallInstruction() result.getBaseVariable() = v and
result.getIndirection() = 0
} }
final override BaseSourceVariable getBaseSourceVariable() { result = v }
} }
private class DirectDef extends DefImpl, TDirectDefImpl { private class DirectDef extends DefImpl, TDirectDefImpl {
@@ -669,9 +657,19 @@ class GlobalDefImpl extends DefImpl, TGlobalDefImpl {
*/ */
predicate adjacentDefRead(IRBlock bb1, int i1, SourceVariable sv, IRBlock bb2, int i2) { predicate adjacentDefRead(IRBlock bb1, int i1, SourceVariable sv, IRBlock bb2, int i2) {
adjacentDefReadExt(_, sv, bb1, i1, bb2, i2) adjacentDefReadExt(_, sv, bb1, i1, bb2, i2)
or
exists(PhiNode phi |
lastRefRedefExt(_, sv, bb1, i1, phi) and
phi.definesAt(sv, bb2, i2, _)
)
} }
predicate useToNode(IRBlock bb, int i, SourceVariable sv, Node nodeTo) { predicate useToNode(IRBlock bb, int i, SourceVariable sv, Node nodeTo) {
exists(Phi phi |
phi.asPhi().definesAt(sv, bb, i, _) and
nodeTo = phi.getNode()
)
or
exists(UseImpl use | exists(UseImpl use |
use.hasIndexInBlock(bb, i, sv) and use.hasIndexInBlock(bb, i, sv) and
nodeTo = use.getNode() nodeTo = use.getNode()
@@ -725,26 +723,46 @@ predicate nodeToDefOrUse(Node node, SourceVariable sv, IRBlock bb, int i, boolea
*/ */
private predicate indirectConversionFlowStep(Node nFrom, Node nTo) { private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
not exists(SourceVariable sv, IRBlock bb2, int i2 | not exists(SourceVariable sv, IRBlock bb2, int i2 |
useToNode(bb2, i2, sv, nTo) and nodeToDefOrUse(nTo, sv, bb2, i2, _) and
adjacentDefRead(bb2, i2, sv, _, _) adjacentDefRead(bb2, i2, sv, _, _)
) and ) and
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr | (
hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
hasOperandAndIndex(nTo, op2, pragma[only_bind_into](indirectionIndex)) and hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and
instr = op2.getDef() and hasOperandAndIndex(nTo, op2, pragma[only_bind_into](indirectionIndex)) and
conversionFlow(op1, instr, _, _) instr = op2.getDef() and
conversionFlow(op1, instr, _, _)
)
or
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and
hasOperandAndIndex(nTo, op2, indirectionIndex - 1) and
instr = op2.getDef() and
isDereference(instr, op1, _)
)
) )
} }
/** /**
* Holds if `node` is a phi input node that should receive flow from the * The reason for this predicate is a bit annoying:
* definition to (or use of) `sv` at `(bb1, i1)`. * We cannot mark a `PointerArithmeticInstruction` that computes an offset based on some SSA
* variable `x` as a use of `x` since this creates taint-flow in the following example:
* ```c
* int x = array[source]
* sink(*array)
* ```
* This is because `source` would flow from the operand of `PointerArithmeticInstruction` to the
* result of the instruction, and into the `IndirectOperand` that represents the value of `*array`.
* Then, via use-use flow, flow will arrive at `*array` in `sink(*array)`.
*
* So this predicate recurses back along conversions and `PointerArithmeticInstruction`s to find the
* first use that has provides use-use flow, and uses that target as the target of the `nodeFrom`.
*/ */
private predicate phiToNode(SsaPhiInputNode node, SourceVariable sv, IRBlock bb1, int i1) { private predicate adjustForPointerArith(PostUpdateNode pun, SourceVariable sv, IRBlock bb2, int i2) {
exists(PhiNode phi, IRBlock input | exists(IRBlock bb1, int i1, Node adjusted |
phi.hasInputFromBlock(_, sv, bb1, i1, input) and indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
node.getPhiNode() = phi and nodeToDefOrUse(adjusted, sv, bb1, i1, _) and
node.getBlock() = input adjacentDefRead(bb1, i1, sv, bb2, i2)
) )
} }
@@ -759,14 +777,10 @@ private predicate phiToNode(SsaPhiInputNode node, SourceVariable sv, IRBlock bb1
private predicate ssaFlowImpl( private predicate ssaFlowImpl(
IRBlock bb1, int i1, SourceVariable sv, Node nodeFrom, Node nodeTo, boolean uncertain IRBlock bb1, int i1, SourceVariable sv, Node nodeFrom, Node nodeTo, boolean uncertain
) { ) {
nodeToDefOrUse(nodeFrom, sv, bb1, i1, uncertain) and exists(IRBlock bb2, int i2 |
( nodeToDefOrUse(nodeFrom, sv, bb1, i1, uncertain) and
exists(IRBlock bb2, int i2 | adjacentDefRead(bb1, i1, sv, bb2, i2) and
adjacentDefRead(bb1, i1, sv, bb2, i2) and useToNode(bb2, i2, sv, nodeTo)
useToNode(bb2, i2, sv, nodeTo)
)
or
phiToNode(nodeTo, sv, bb1, i1)
) and ) and
nodeFrom != nodeTo nodeFrom != nodeTo
} }
@@ -775,7 +789,7 @@ private predicate ssaFlowImpl(
private Node getAPriorDefinition(DefinitionExt next) { private Node getAPriorDefinition(DefinitionExt next) {
exists(IRBlock bb, int i, SourceVariable sv | exists(IRBlock bb, int i, SourceVariable sv |
lastRefRedefExt(_, pragma[only_bind_into](sv), pragma[only_bind_into](bb), lastRefRedefExt(_, pragma[only_bind_into](sv), pragma[only_bind_into](bb),
pragma[only_bind_into](i), _, next) and pragma[only_bind_into](i), next) and
nodeToDefOrUse(result, sv, bb, i, _) nodeToDefOrUse(result, sv, bb, i, _)
) )
} }
@@ -882,31 +896,9 @@ private predicate isArgumentOfCallable(DataFlowCall call, Node n) {
* Holds if there is use-use flow from `pun`'s pre-update node to `n`. * Holds if there is use-use flow from `pun`'s pre-update node to `n`.
*/ */
private predicate postUpdateNodeToFirstUse(PostUpdateNode pun, Node n) { private predicate postUpdateNodeToFirstUse(PostUpdateNode pun, Node n) {
// We cannot mark a `PointerArithmeticInstruction` that computes an offset exists(SourceVariable sv, IRBlock bb2, int i2 |
// based on some SSA adjustForPointerArith(pun, sv, bb2, i2) and
// variable `x` as a use of `x` since this creates taint-flow in the useToNode(bb2, i2, sv, n)
// following example:
// ```c
// int x = array[source]
// sink(*array)
// ```
// This is because `source` would flow from the operand of `PointerArithmetic`
// instruction to the result of the instruction, and into the `IndirectOperand`
// that represents the value of `*array`. Then, via use-use flow, flow will
// arrive at `*array` in `sink(*array)`.
// So this predicate recurses back along conversions and `PointerArithmetic`
// instructions to find the first use that has provides use-use flow, and
// uses that target as the target of the `nodeFrom`.
exists(Node adjusted, IRBlock bb1, int i1, SourceVariable sv |
indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
useToNode(bb1, i1, sv, adjusted)
|
exists(IRBlock bb2, int i2 |
adjacentDefRead(bb1, i1, sv, bb2, i2) and
useToNode(bb2, i2, sv, n)
)
or
phiToNode(n, sv, bb1, i1)
) )
} }
@@ -961,16 +953,11 @@ predicate postUpdateFlow(PostUpdateNode pun, Node nodeTo) {
/** Holds if `nodeTo` receives flow from the phi node `nodeFrom`. */ /** Holds if `nodeTo` receives flow from the phi node `nodeFrom`. */
predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) { predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) {
exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1 | exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, IRBlock bb2, int i2 |
phi = nodeFrom.getPhiNode() and phi = nodeFrom.getPhiNode() and
phi.definesAt(sv, bb1, i1, _) phi.definesAt(sv, bb1, i1, _) and
| adjacentDefRead(bb1, i1, sv, bb2, i2) and
exists(IRBlock bb2, int i2 | useToNode(bb2, i2, sv, nodeTo)
adjacentDefRead(bb1, i1, sv, bb2, i2) and
useToNode(bb2, i2, sv, nodeTo)
)
or
phiToNode(nodeTo, sv, bb1, i1)
) )
} }
@@ -993,7 +980,7 @@ private module SsaInput implements SsaImplCommon::InputSig<Location> {
* Holds if the `i`'th write in block `bb` writes to the variable `v`. * Holds if the `i`'th write in block `bb` writes to the variable `v`.
* `certain` is `true` if the write is guaranteed to overwrite the entire variable. * `certain` is `true` if the write is guaranteed to overwrite the entire variable.
*/ */
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { predicate variableWrite(IRBlock bb, int i, SourceVariable v, boolean certain) {
DataFlowImplCommon::forceCachingInSameStage() and DataFlowImplCommon::forceCachingInSameStage() and
( (
exists(DefImpl def | def.hasIndexInBlock(bb, i, v) | exists(DefImpl def | def.hasIndexInBlock(bb, i, v) |
@@ -1011,7 +998,7 @@ private module SsaInput implements SsaImplCommon::InputSig<Location> {
* Holds if the `i`'th read in block `bb` reads to the variable `v`. * Holds if the `i`'th read in block `bb` reads to the variable `v`.
* `certain` is `true` if the read is guaranteed. For C++, this is always the case. * `certain` is `true` if the read is guaranteed. For C++, this is always the case.
*/ */
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { predicate variableRead(IRBlock bb, int i, SourceVariable v, boolean certain) {
exists(UseImpl use | use.hasIndexInBlock(bb, i, v) | exists(UseImpl use | use.hasIndexInBlock(bb, i, v) |
if use.isCertain() then certain = true else certain = false if use.isCertain() then certain = true else certain = false
) )
@@ -1044,26 +1031,22 @@ module SsaCached {
* Holds if the node at index `i` in `bb` is a last reference to SSA definition * Holds if the node at index `i` in `bb` is a last reference to SSA definition
* `def`. The reference is last because it can reach another write `next`, * `def`. The reference is last because it can reach another write `next`,
* without passing through another read or write. * without passing through another read or write.
*
* The path from node `i` in `bb` to `next` goes via basic block `input`,
* which is either a predecessor of the basic block of `next`, or `input` =
* `bb` in case `next` occurs in basic block `bb`.
*/ */
cached cached
predicate lastRefRedefExt( predicate lastRefRedefExt(
DefinitionExt def, SourceVariable sv, IRBlock bb, int i, IRBlock input, DefinitionExt next DefinitionExt def, SourceVariable sv, IRBlock bb, int i, DefinitionExt next
) { ) {
SsaImpl::lastRefRedefExt(def, sv, bb, i, input, next) SsaImpl::lastRefRedefExt(def, sv, bb, i, next)
} }
cached cached
Definition phiHasInputFromBlockExt(PhiNode phi, IRBlock bb) { Definition phiHasInputFromBlock(PhiNode phi, IRBlock bb) {
SsaImpl::phiHasInputFromBlockExt(phi, result, bb) SsaImpl::phiHasInputFromBlock(phi, result, bb)
} }
cached cached
predicate ssaDefReachesReadExt(SourceVariable v, DefinitionExt def, IRBlock bb, int i) { predicate ssaDefReachesRead(SourceVariable v, Definition def, IRBlock bb, int i) {
SsaImpl::ssaDefReachesReadExt(v, def, bb, i) SsaImpl::ssaDefReachesRead(v, def, bb, i)
} }
predicate variableRead = SsaInput::variableRead/4; predicate variableRead = SsaInput::variableRead/4;
@@ -1215,11 +1198,11 @@ class Phi extends TPhi, SsaDef {
final override Location getLocation() { result = phi.getBasicBlock().getLocation() } final override Location getLocation() { result = phi.getBasicBlock().getLocation() }
override string toString() { result = phi.toString() } override string toString() { result = "Phi" }
SsaPhiInputNode getNode(IRBlock block) { result.getPhiNode() = phi and result.getBlock() = block } SsaPhiNode getNode() { result.getPhiNode() = phi }
predicate hasInputFromBlock(Definition inp, IRBlock bb) { inp = phiHasInputFromBlockExt(phi, bb) } predicate hasInputFromBlock(Definition inp, IRBlock bb) { inp = phiHasInputFromBlock(phi, bb) }
final Definition getAnInput() { this.hasInputFromBlock(result, _) } final Definition getAnInput() { this.hasInputFromBlock(result, _) }
} }
@@ -1245,21 +1228,13 @@ class PhiNode extends SsaImpl::DefinitionExt {
*/ */
predicate isPhiRead() { this instanceof SsaImpl::PhiReadNode } predicate isPhiRead() { this instanceof SsaImpl::PhiReadNode }
/** /** Holds if `inp` is an input to this phi node along the edge originating in `bb`. */
* Holds if the node at index `i` in `bb` is a last reference to SSA predicate hasInputFromBlock(Definition inp, IRBlock bb) {
* definition `def` of `sv`. The reference is last because it can reach inp = SsaCached::phiHasInputFromBlock(this, bb)
* this phi node, without passing through another read or write.
*
* The path from node `i` in `bb` to this phi node goes via basic block
* `input`, which is either a predecessor of the basic block of this phi
* node, or `input` = `bb` in case this phi node occurs in basic block `bb`.
*/
predicate hasInputFromBlock(DefinitionExt def, SourceVariable sv, IRBlock bb, int i, IRBlock input) {
SsaCached::lastRefRedefExt(def, sv, bb, i, input, this)
} }
/** Gets a definition that is an input to this phi node. */ /** Gets a definition that is an input to this phi node. */
final Definition getAnInput() { this.hasInputFromBlock(result, _, _, _, _) } final Definition getAnInput() { this.hasInputFromBlock(result, _) }
} }
/** An static single assignment (SSA) definition. */ /** An static single assignment (SSA) definition. */
@@ -1274,15 +1249,6 @@ class DefinitionExt extends SsaImpl::DefinitionExt {
result = this.getAPhiInputOrPriorDefinition*() and result = this.getAPhiInputOrPriorDefinition*() and
not result instanceof PhiNode not result instanceof PhiNode
} }
/** Gets a node that represents a read of this SSA definition. */
Node getARead() {
exists(SourceVariable sv, IRBlock bb, int i | SsaCached::ssaDefReachesReadExt(sv, this, bb, i) |
useToNode(bb, i, sv, result)
or
phiToNode(result, sv, bb, i)
)
}
} }
class Definition = SsaImpl::Definition; class Definition = SsaImpl::Definition;

View File

@@ -40,8 +40,7 @@ predicate ignoreInstruction(Instruction instr) {
instr instanceof AliasedDefinitionInstruction or instr instanceof AliasedDefinitionInstruction or
instr instanceof AliasedUseInstruction or instr instanceof AliasedUseInstruction or
instr instanceof InitializeNonLocalInstruction or instr instanceof InitializeNonLocalInstruction or
instr instanceof ReturnIndirectionInstruction or instr instanceof ReturnIndirectionInstruction
instr instanceof UninitializedGroupInstruction
) )
} }
@@ -758,19 +757,13 @@ import Cached
* between the SSA pruning stage, and the final SSA stage. * between the SSA pruning stage, and the final SSA stage.
*/ */
module InputSigCommon { module InputSigCommon {
class BasicBlock extends IRBlock { class BasicBlock = IRBlock;
ControlFlowNode getNode(int i) { result = this.getInstruction(i) }
int length() { result = this.getInstructionCount() }
}
class ControlFlowNode = Instruction;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) } BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class ExitBasicBlock extends BasicBlock { class ExitBasicBlock extends IRBlock {
ExitBasicBlock() { this.getLastInstruction() instanceof ExitFunctionInstruction } ExitBasicBlock() { this.getLastInstruction() instanceof ExitFunctionInstruction }
} }
} }

View File

@@ -147,10 +147,7 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink, st
* of `c` at sinks and inputs to additional taint steps. * of `c` at sinks and inputs to additional taint steps.
*/ */
bindingset[node] bindingset[node]
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { none() }
node instanceof ArgumentNode and
c.isSingleton(any(ElementContent ec))
}
/** /**
* Holds if `node` should be a sanitizer in all global taint flow configurations * Holds if `node` should be a sanitizer in all global taint flow configurations

View File

@@ -13,8 +13,7 @@ private newtype TMemoryAccessKind =
TPhiMemoryAccess() or TPhiMemoryAccess() or
TUnmodeledMemoryAccess() or TUnmodeledMemoryAccess() or
TChiTotalMemoryAccess() or TChiTotalMemoryAccess() or
TChiPartialMemoryAccess() or TChiPartialMemoryAccess()
TGroupedMemoryAccess()
/** /**
* Describes the set of memory locations memory accessed by a memory operand or * 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 { class ChiPartialMemoryAccess extends MemoryAccessKind, TChiPartialMemoryAccess {
override string toString() { result = "chi(partial)" } 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 TSizedBufferMayWriteSideEffect() or
TInitializeDynamicAllocation() or TInitializeDynamicAllocation() or
TChi() or TChi() or
TUninitializedGroup() or
TInlineAsm() or TInlineAsm() or
TUnreached() or TUnreached() or
TNewObj() 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`. * The `Opcode` for an `InlineAsmInstruction`.
* *

View File

@@ -2142,47 +2142,6 @@ class ChiInstruction extends Instruction {
final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) } 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. * An instruction representing unreachable code.
* *

View File

@@ -106,7 +106,8 @@ private predicate operandEscapesDomain(Operand operand) {
not isArgumentForParameter(_, operand, _) and not isArgumentForParameter(_, operand, _) and
not isOnlyEscapesViaReturnArgument(operand) and not isOnlyEscapesViaReturnArgument(operand) and
not operand.getUse() instanceof ReturnValueInstruction 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. // A copy propagates the source value.
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0 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) { private predicate operandEscapesNonReturn(Operand operand) {
@@ -216,6 +212,9 @@ private predicate operandEscapesNonReturn(Operand operand) {
or or
isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse()) isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse())
or or
operand instanceof PhiInputOperand and
resultEscapesNonReturn(operand.getUse())
or
operandEscapesDomain(operand) operandEscapesDomain(operand)
} }
@@ -237,6 +236,9 @@ private predicate operandMayReachReturn(Operand operand) {
operand.getUse() instanceof ReturnValueInstruction operand.getUse() instanceof ReturnValueInstruction
or or
isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse()) isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse())
or
operand instanceof PhiInputOperand and
resultMayReachReturn(operand.getUse())
} }
private predicate operandReturned(Operand operand, IntValue bitOffset) { private predicate operandReturned(Operand operand, IntValue bitOffset) {

View File

@@ -101,8 +101,6 @@ class IndirectParameterAllocation extends Allocation, TIndirectParameterAllocati
final override predicate isAlwaysAllocatedOnStack() { none() } final override predicate isAlwaysAllocatedOnStack() { none() }
final override predicate alwaysEscapes() { none() } final override predicate alwaysEscapes() { none() }
final IRAutomaticVariable getIRVariable() { result = var }
} }
class DynamicAllocation extends Allocation, TDynamicAllocation { class DynamicAllocation extends Allocation, TDynamicAllocation {

View File

@@ -8,7 +8,6 @@ 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.internal.IntegerInterval as Interval
private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import AliasConfiguration private import AliasConfiguration
private import codeql.util.Boolean
private class IntValue = Ints::IntValue; private class IntValue = Ints::IntValue;
@@ -17,196 +16,49 @@ private predicate isIndirectOrBufferMemoryAccess(MemoryAccessKind kind) {
kind instanceof BufferMemoryAccess 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( private predicate hasResultMemoryAccess(
AddressOperand address, Instruction instr, Allocation var, IRType type, Instruction instr, Allocation var, IRType type, Language::LanguageType languageType,
Language::LanguageType languageType, IntValue startBitOffset, IntValue endBitOffset, IntValue startBitOffset, IntValue endBitOffset, boolean isMayAccess
boolean isMayAccess, boolean grouped
) { ) {
address = instr.getResultAddressOperand() and exists(AddressOperand addrOperand |
hasMemoryAccess(address, var, startBitOffset, grouped) and addrOperand = instr.getResultAddressOperand() and
languageType = instr.getResultLanguageType() and addressOperandAllocationAndOffset(addrOperand, var, startBitOffset) and
type = languageType.getIRType() and languageType = instr.getResultLanguageType() and
isIndirectOrBufferMemoryAccess(instr.getResultMemoryAccess()) and type = languageType.getIRType() and
(if instr.hasResultMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and isIndirectOrBufferMemoryAccess(instr.getResultMemoryAccess()) and
if exists(type.getByteSize()) (if instr.hasResultMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8)) if exists(type.getByteSize())
else endBitOffset = Ints::unknown() then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
else endBitOffset = Ints::unknown()
)
} }
private predicate hasOperandMemoryAccess( private predicate hasOperandMemoryAccess(
AddressOperand address, MemoryOperand operand, Allocation var, IRType type, MemoryOperand operand, Allocation var, IRType type, Language::LanguageType languageType,
Language::LanguageType languageType, IntValue startBitOffset, IntValue endBitOffset, IntValue startBitOffset, IntValue endBitOffset, boolean isMayAccess
boolean isMayAccess, boolean grouped
) { ) {
address = operand.getAddressOperand() and exists(AddressOperand addrOperand |
hasMemoryAccess(address, var, startBitOffset, grouped) and addrOperand = operand.getAddressOperand() and
languageType = operand.getLanguageType() and addressOperandAllocationAndOffset(addrOperand, var, startBitOffset) and
type = languageType.getIRType() and languageType = operand.getLanguageType() and
isIndirectOrBufferMemoryAccess(operand.getMemoryAccess()) and type = languageType.getIRType() and
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and isIndirectOrBufferMemoryAccess(operand.getMemoryAccess()) and
if exists(type.getByteSize()) (if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8)) if exists(type.getByteSize())
else endBitOffset = Ints::unknown() 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)
) )
} }
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 = private newtype TMemoryLocation =
TVariableMemoryLocation( TVariableMemoryLocation(
Allocation var, IRType type, Language::LanguageType languageType, IntValue startBitOffset, Allocation var, IRType type, Language::LanguageType languageType, IntValue startBitOffset,
IntValue endBitOffset, boolean isMayAccess IntValue endBitOffset, boolean isMayAccess
) { ) {
( (
hasResultMemoryAccess(_, _, var, type, _, startBitOffset, endBitOffset, isMayAccess, false) hasResultMemoryAccess(_, var, type, _, startBitOffset, endBitOffset, isMayAccess)
or or
hasOperandMemoryAccess(_, _, var, type, _, startBitOffset, endBitOffset, isMayAccess, false) hasOperandMemoryAccess(_, var, type, _, startBitOffset, endBitOffset, isMayAccess)
or or
// For a stack variable, always create a memory location for the entire variable. // For a stack variable, always create a memory location for the entire variable.
var.isAlwaysAllocatedOnStack() and var.isAlwaysAllocatedOnStack() and
@@ -217,14 +69,22 @@ private newtype TMemoryLocation =
) and ) and
languageType = type.getCanonicalLanguageType() languageType = type.getCanonicalLanguageType()
} or } or
TEntireAllocationMemoryLocation(Allocation var, Boolean isMayAccess) { TEntireAllocationMemoryLocation(Allocation var, boolean isMayAccess) {
var instanceof IndirectParameterAllocation or (
var instanceof DynamicAllocation var instanceof IndirectParameterAllocation or
var instanceof DynamicAllocation
) and
(isMayAccess = false or isMayAccess = true)
} or } or
TGroupedMemoryLocation(VariableGroup vg, Boolean isMayAccess, Boolean isAll) or TUnknownMemoryLocation(IRFunction irFunc, boolean isMayAccess) {
TUnknownMemoryLocation(IRFunction irFunc, Boolean isMayAccess) or isMayAccess = false or isMayAccess = true
TAllNonLocalMemory(IRFunction irFunc, Boolean isMayAccess) or } or
TAllAliasedMemory(IRFunction irFunc, Boolean isMayAccess) TAllNonLocalMemory(IRFunction irFunc, boolean isMayAccess) {
isMayAccess = false or isMayAccess = true
} or
TAllAliasedMemory(IRFunction irFunc, boolean isMayAccess) {
isMayAccess = false or isMayAccess = true
}
/** /**
* Represents the 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
@@ -256,14 +116,7 @@ abstract class MemoryLocation extends TMemoryLocation {
abstract predicate isMayAccess(); abstract predicate isMayAccess();
/** Allocation getAllocation() { none() }
* 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() }
/** /**
* Holds if the location cannot be overwritten except by definition of a `MemoryLocation` for * Holds if the location cannot be overwritten except by definition of a `MemoryLocation` for
@@ -300,29 +153,24 @@ abstract class AllocationMemoryLocation extends MemoryLocation {
Allocation var; Allocation var;
boolean isMayAccess; boolean isMayAccess;
bindingset[isMayAccess] AllocationMemoryLocation() {
AllocationMemoryLocation() { any() } this instanceof TMemoryLocation and
isMayAccess = false
or
isMayAccess = true // Just ensures that `isMayAccess` is bound.
}
final override VirtualVariable getVirtualVariable() { final override VirtualVariable getVirtualVariable() {
if allocationEscapes(var) if allocationEscapes(var)
then result = TAllAliasedMemory(var.getEnclosingIRFunction(), false) then result = TAllAliasedMemory(var.getEnclosingIRFunction(), false)
else ( else result.(AllocationMemoryLocation).getAllocation() = var
// 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
)
} }
final override IRFunction getIRFunction() { result = var.getEnclosingIRFunction() } final override IRFunction getIRFunction() { result = var.getEnclosingIRFunction() }
final override Location getLocation() { result = var.getLocation() } 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 } final override predicate isMayAccess() { isMayAccess = true }
@@ -363,13 +211,13 @@ class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLo
final override Language::LanguageType getType() { final override Language::LanguageType getType() {
if if
strictcount(Language::LanguageType accessType | strictcount(Language::LanguageType accessType |
hasResultMemoryAccess(_, _, var, type, accessType, startBitOffset, endBitOffset, _, false) or hasResultMemoryAccess(_, var, type, accessType, startBitOffset, endBitOffset, _) or
hasOperandMemoryAccess(_, _, var, type, accessType, startBitOffset, endBitOffset, _, false) hasOperandMemoryAccess(_, var, type, accessType, startBitOffset, endBitOffset, _)
) = 1 ) = 1
then then
// All of the accesses have the same `LanguageType`, so just use that. // All of the accesses have the same `LanguageType`, so just use that.
hasResultMemoryAccess(_, _, var, type, result, startBitOffset, endBitOffset, _, false) or hasResultMemoryAccess(_, var, type, result, startBitOffset, endBitOffset, _) or
hasOperandMemoryAccess(_, _, var, type, result, startBitOffset, endBitOffset, _, false) hasOperandMemoryAccess(_, var, type, result, startBitOffset, endBitOffset, _)
else else
// There is no single type for all accesses, so just use the canonical one for this `IRType`. // There is no single type for all accesses, so just use the canonical one for this `IRType`.
result = type.getCanonicalLanguageType() result = type.getCanonicalLanguageType()
@@ -399,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, MemoryLocation {
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, class EntireAllocationMemoryLocation extends TEntireAllocationMemoryLocation,
AllocationMemoryLocation AllocationMemoryLocation
{ {
@@ -517,14 +282,6 @@ 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`. * An access to memory that is not known to be confined to a specific `IRVariable`.
*/ */
@@ -689,7 +446,7 @@ private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
result instanceof MustExactlyOverlap result instanceof MustExactlyOverlap
or or
not use instanceof EntireAllocationMemoryLocation and not use instanceof EntireAllocationMemoryLocation and
if def.getAnAllocation() = use.getAnAllocation() if def.getAllocation() = use.getAllocation()
then then
// EntireAllocationMemoryLocation totally overlaps any location within // EntireAllocationMemoryLocation totally overlaps any location within
// the same allocation. // the same allocation.
@@ -697,48 +454,11 @@ private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
else ( else (
// There is no overlap with a location that's known to belong to a // There is no overlap with a location that's known to belong to a
// different allocation, but all other locations may partially overlap. // different allocation, but all other locations may partially overlap.
not exists(use.getAnAllocation()) and not exists(use.getAllocation()) and
result instanceof MayPartiallyOverlap result instanceof MayPartiallyOverlap
) )
) )
or 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 | exists(VariableMemoryLocation defVariableLocation |
defVariableLocation = def and defVariableLocation = def and
( (
@@ -748,8 +468,7 @@ private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
( (
use instanceof UnknownMemoryLocation or use instanceof UnknownMemoryLocation or
use instanceof AllAliasedMemory or use instanceof AllAliasedMemory or
use instanceof EntireAllocationMemoryLocation or use instanceof EntireAllocationMemoryLocation
use instanceof GroupedMemoryLocation
) and ) and
result instanceof MayPartiallyOverlap result instanceof MayPartiallyOverlap
or or
@@ -815,7 +534,7 @@ private predicate isCoveredOffset(Allocation var, int offsetRank, VariableMemory
exists(int startRank, int endRank, VirtualVariable vvar | exists(int startRank, int endRank, VirtualVariable vvar |
vml.getStartBitOffset() = rank[startRank](IntValue offset_ | isRelevantOffset(vvar, offset_)) and vml.getStartBitOffset() = rank[startRank](IntValue offset_ | isRelevantOffset(vvar, offset_)) and
vml.getEndBitOffset() = rank[endRank](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 vvar = vml.getVirtualVariable() and
isRelatableMemoryLocation(vml) and isRelatableMemoryLocation(vml) and
offsetRank in [startRank .. endRank] offsetRank in [startRank .. endRank]
@@ -823,7 +542,7 @@ private predicate isCoveredOffset(Allocation var, int offsetRank, VariableMemory
} }
private predicate hasUnknownOffset(Allocation var, VariableMemoryLocation vml) { private predicate hasUnknownOffset(Allocation var, VariableMemoryLocation vml) {
vml.getAnAllocation() = var and vml.getAllocation() = var and
( (
vml.getStartBitOffset() = Ints::unknown() or vml.getStartBitOffset() = Ints::unknown() or
vml.getEndBitOffset() = Ints::unknown() vml.getEndBitOffset() = Ints::unknown()
@@ -838,9 +557,9 @@ private predicate overlappingIRVariableMemoryLocations(
isCoveredOffset(var, offsetRank, use) isCoveredOffset(var, offsetRank, use)
) )
or or
hasUnknownOffset(use.getAnAllocation(), def) hasUnknownOffset(use.getAllocation(), def)
or or
hasUnknownOffset(def.getAnAllocation(), use) hasUnknownOffset(def.getAllocation(), use)
} }
private Overlap getVariableMemoryLocationOverlap( private Overlap getVariableMemoryLocationOverlap(
@@ -869,24 +588,13 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
( (
( (
isIndirectOrBufferMemoryAccess(kind) and isIndirectOrBufferMemoryAccess(kind) and
if hasResultMemoryAccess(_, instr, _, _, _, _, _, _, _) if hasResultMemoryAccess(instr, _, _, _, _, _, _)
then then
exists( exists(Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset |
Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset, hasResultMemoryAccess(instr, var, type, _, startBitOffset, endBitOffset, isMayAccess) and
boolean grouped result =
| TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset,
hasResultMemoryAccess(_, instr, var, type, _, startBitOffset, endBitOffset, isMayAccess, unbindBool(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)
) )
else result = TUnknownMemoryLocation(instr.getEnclosingIRFunction(), isMayAccess) else result = TUnknownMemoryLocation(instr.getEnclosingIRFunction(), isMayAccess)
) )
@@ -913,23 +621,12 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
( (
( (
isIndirectOrBufferMemoryAccess(kind) and isIndirectOrBufferMemoryAccess(kind) and
if hasOperandMemoryAccess(_, operand, _, _, _, _, _, _, _) if hasOperandMemoryAccess(operand, _, _, _, _, _, _)
then then
exists( exists(Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset |
Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset, hasOperandMemoryAccess(operand, var, type, _, startBitOffset, endBitOffset, isMayAccess) and
boolean grouped result =
| TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset, isMayAccess)
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)
) )
else result = TUnknownMemoryLocation(operand.getEnclosingIRFunction(), isMayAccess) else result = TUnknownMemoryLocation(operand.getEnclosingIRFunction(), isMayAccess)
) )

View File

@@ -15,51 +15,6 @@ private class OldInstruction = Reachability::ReachableInstruction;
import Cached 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 cached
private module Cached { private module Cached {
cached cached
@@ -77,11 +32,6 @@ private module Cached {
hasChiNode(_, primaryInstruction) hasChiNode(_, primaryInstruction)
} }
cached
predicate hasChiNodeAfterUninitializedGroup(UninitializedGroupInstruction initGroup) {
hasChiNodeAfterUninitializedGroup(_, initGroup)
}
cached cached
predicate hasUnreachedInstructionCached(IRFunction irFunc) { predicate hasUnreachedInstructionCached(IRFunction irFunc) {
exists(OldIR::Instruction oldInstruction | exists(OldIR::Instruction oldInstruction |
@@ -95,8 +45,7 @@ private module Cached {
} }
class TStageInstruction = class TStageInstruction =
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction or TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
TUninitializedGroupInstruction;
/** /**
* If `oldInstruction` is a `Phi` instruction that has exactly one reachable predecessor block, * If `oldInstruction` is a `Phi` instruction that has exactly one reachable predecessor block,
@@ -129,8 +78,6 @@ private module Cached {
or or
instr instanceof TChiInstruction instr instanceof TChiInstruction
or or
instr instanceof TUninitializedGroupInstruction
or
instr instanceof TUnreachedInstruction instr instanceof TUnreachedInstruction
} }
@@ -176,8 +123,7 @@ private module Cached {
predicate hasModeledMemoryResult(Instruction instruction) { predicate hasModeledMemoryResult(Instruction instruction) {
canModelResultForOldInstruction(getOldInstruction(instruction)) or canModelResultForOldInstruction(getOldInstruction(instruction)) or
instruction instanceof PhiInstruction or // Phis always have modeled results instruction instanceof PhiInstruction or // Phis always have modeled results
instruction instanceof ChiInstruction or // Chis always have modeled results instruction instanceof ChiInstruction // Chis always have modeled results
instruction instanceof UninitializedGroupInstruction // Group initializers always have modeled results
} }
cached cached
@@ -188,23 +134,16 @@ private module Cached {
or or
// Chi instructions track virtual variables, and therefore a chi instruction is // Chi instructions track virtual variables, and therefore a chi instruction is
// conflated if it's associated with the aliased virtual variable. // conflated if it's associated with the aliased virtual variable.
exists(Instruction input | instruction = getChi(input) | exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) |
Alias::getResultMemoryLocation(input).getVirtualVariable() instanceof Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
Alias::AliasedVirtualVariable 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 or
// Phi instructions track locations, and therefore a phi instruction is // Phi instructions track locations, and therefore a phi instruction is
// conflated if it's associated with a conflated location. // conflated if it's associated with a conflated location.
exists(Alias::MemoryLocation location | exists(Alias::MemoryLocation location |
instruction = getPhi(_, location) and instruction = getPhi(_, location) and
not exists(location.getAnAllocation()) not exists(location.getAllocation())
) )
} }
@@ -266,11 +205,7 @@ private module Cached {
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
) )
or or
( instruction = getChi(getOldInstruction(result)) and
instruction = getChi(getOldInstruction(result))
or
instruction = getChi(result.(UninitializedGroupInstruction))
) and
tag instanceof ChiPartialOperandTag and tag instanceof ChiPartialOperandTag and
overlap instanceof MustExactlyOverlap overlap instanceof MustExactlyOverlap
or 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 * 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. * through a phi instruction and therefore should be impossible.
@@ -389,19 +316,6 @@ private module Cached {
result = getNewPhiOperandDefinitionFromOldSsa(instr, newPredecessorBlock, overlap) 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 cached
Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) { Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
exists( exists(
@@ -415,19 +329,6 @@ private module Cached {
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, vvar, _) 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 cached
@@ -443,40 +344,14 @@ private module Cached {
) )
} }
private UninitializedGroupInstruction firstInstructionToUninitializedGroup( /*
Instruction instruction, EdgeKind 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
exists(IRFunction func | * the new instructions generated from the successors of the old instruction
isFirstInstructionBeforeUninitializedGroup(instruction, func) and */
result = getInitGroupInstruction(0, func) and
kind instanceof GotoEdge
)
}
private Instruction getNextUninitializedGroupInstruction(Instruction instruction, EdgeKind kind) { cached
exists(int i, IRFunction func | Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
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
) {
if hasChiNode(_, getOldInstruction(instruction)) if hasChiNode(_, getOldInstruction(instruction))
then then
result = getChi(getOldInstruction(instruction)) and 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 cached
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) { Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
exists(OldInstruction oldInstruction | exists(OldInstruction oldInstruction |
@@ -632,16 +406,6 @@ private module Cached {
exists(IRFunctionBase irFunc | exists(IRFunctionBase irFunc |
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction() 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 cached
@@ -654,16 +418,9 @@ private module Cached {
) )
or or
exists(Instruction primaryInstr, Alias::VirtualVariable vvar | exists(Instruction primaryInstr, Alias::VirtualVariable vvar |
instr = chiInstruction(primaryInstr) and result = vvar.getType() instr = chiInstruction(primaryInstr) and
| hasChiNode(vvar, primaryInstr) and
hasChiNode(vvar, primaryInstr) result = vvar.getType()
or
hasChiNodeAfterUninitializedGroup(vvar, primaryInstr)
)
or
exists(Alias::VariableGroup vg |
instr = uninitializedGroup(vg) and
result = vg.getType()
) )
or or
instr = reusedPhiInstruction(_) and instr = reusedPhiInstruction(_) and
@@ -691,8 +448,6 @@ private module Cached {
or or
instr = chiInstruction(_) and opcode instanceof Opcode::Chi instr = chiInstruction(_) and opcode instanceof Opcode::Chi
or or
instr = uninitializedGroup(_) and opcode instanceof Opcode::UninitializedGroup
or
instr = unreachedInstruction(_) and opcode instanceof Opcode::Unreached instr = unreachedInstruction(_) and opcode instanceof Opcode::Unreached
} }
@@ -705,15 +460,10 @@ private module Cached {
result = blockStartInstr.getEnclosingIRFunction() result = blockStartInstr.getEnclosingIRFunction()
) )
or or
exists(Instruction primaryInstr | exists(OldInstruction primaryInstr |
instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction() instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction()
) )
or or
exists(Alias::VariableGroup vg |
instr = uninitializedGroup(vg) and
result = vg.getIRFunction()
)
or
instr = unreachedInstruction(result) instr = unreachedInstruction(result)
} }
@@ -728,8 +478,6 @@ private module Cached {
instruction = getChi(oldInstruction) and instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction) 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 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) { private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) {
result = phiInstruction(defBlock.getFirstInstruction(), 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 private import PhiInsertion
/** /**
@@ -930,33 +668,19 @@ private import DefUse
* potentially very sparse. * potentially very sparse.
*/ */
module DefUse { module DefUse {
bindingset[index, block]
pragma[inline_late]
private int getNonChiOffset(int index, OldBlock block) {
exists(IRFunction func | func = block.getEnclosingIRFunction() |
if
getNewBlock(block) = func.getEntryBlock() and
not block.getInstruction(index) instanceof InitializeNonLocalInstruction and
not block.getInstruction(index) 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`. * Gets the `Instruction` for the definition at offset `defOffset` in block `defBlock`.
*/ */
private Instruction getDefinitionOrChiInstruction0( Instruction getDefinitionOrChiInstruction(
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation, OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
Alias::MemoryLocation actualDefLocation 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. // An odd offset corresponds to the `Chi` instruction.
defOffset = getChiOffset(oldOffset, defBlock) and defOffset = oldOffset * 2 + 1 and
result = getChi(oldInstr) and result = getChi(oldInstr) and
( (
defLocation = Alias::getResultMemoryLocation(oldInstr) or defLocation = Alias::getResultMemoryLocation(oldInstr) or
@@ -965,7 +689,7 @@ module DefUse {
actualDefLocation = defLocation.getVirtualVariable() actualDefLocation = defLocation.getVirtualVariable()
or or
// An even offset corresponds to the original instruction. // An even offset corresponds to the original instruction.
defOffset = getNonChiOffset(oldOffset, defBlock) and defOffset = oldOffset * 2 and
result = getNewInstruction(oldInstr) and result = getNewInstruction(oldInstr) and
( (
defLocation = Alias::getResultMemoryLocation(oldInstr) or defLocation = Alias::getResultMemoryLocation(oldInstr) or
@@ -978,54 +702,6 @@ module DefUse {
hasDefinition(_, defLocation, defBlock, defOffset) and hasDefinition(_, defLocation, defBlock, defOffset) and
result = getPhi(defBlock, defLocation) and result = getPhi(defBlock, defLocation) and
actualDefLocation = defLocation 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
)
)
} }
/** /**
@@ -1166,20 +842,8 @@ module DefUse {
block.getInstruction(index) = def and block.getInstruction(index) = def and
overlap = Alias::getOverlap(defLocation, useLocation) and overlap = Alias::getOverlap(defLocation, useLocation) and
if overlap instanceof MayPartiallyOverlap if overlap instanceof MayPartiallyOverlap
then offset = getChiOffset(index, block) // The use will be connected to the definition on the `Chi` instruction. then offset = (index * 2) + 1 // 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. else offset = index * 2 // 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.
) )
} }
@@ -1240,11 +904,10 @@ module DefUse {
block.getInstruction(index) = use and block.getInstruction(index) = use and
( (
// A direct use of the location. // A direct use of the location.
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and offset = index * 2
offset = getNonChiOffset(index, block)
or or
// A `Chi` instruction will include a use of the virtual variable. // 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
) )
) )
} }
@@ -1394,9 +1057,5 @@ module Ssa {
predicate hasChiInstruction = Cached::hasChiInstructionCached/1; predicate hasChiInstruction = Cached::hasChiInstructionCached/1;
predicate hasChiNodeAfterUninitializedGroup = Cached::hasChiNodeAfterUninitializedGroup/1;
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
class VariableGroup = Alias::VariableGroup;
} }

View File

@@ -31,7 +31,6 @@ newtype TInstruction =
TUnaliasedSsaUnreachedInstruction(IRFunctionBase irFunc) { TUnaliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
UnaliasedSsa::Ssa::hasUnreachedInstruction(irFunc) UnaliasedSsa::Ssa::hasUnreachedInstruction(irFunc)
} or } or
TUnaliasedSsaUninitializedGroupInstruction(UnaliasedSsa::Ssa::VariableGroup vg) or
TAliasedSsaPhiInstruction( TAliasedSsaPhiInstruction(
TRawInstruction blockStartInstr, AliasedSsa::Ssa::MemoryLocation memoryLocation TRawInstruction blockStartInstr, AliasedSsa::Ssa::MemoryLocation memoryLocation
) { ) {
@@ -42,12 +41,6 @@ newtype TInstruction =
} or } or
TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) { TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
AliasedSsa::Ssa::hasUnreachedInstruction(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 TChiInstruction = TUnaliasedSsaChiInstruction;
class TUninitializedGroupInstruction = TUnaliasedSsaUninitializedGroupInstruction; TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
class TRawOrUninitializedGroupInstruction = TRawInstruction or TUninitializedGroupInstruction;
TChiInstruction chiInstruction(TRawOrUninitializedGroupInstruction primaryInstruction) {
result = TUnaliasedSsaChiInstruction(primaryInstruction) result = TUnaliasedSsaChiInstruction(primaryInstruction)
} }
@@ -82,12 +71,6 @@ module UnaliasedSsaInstructions {
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) { TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
result = TUnaliasedSsaUnreachedInstruction(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, _) result = TUnaliasedSsaPhiInstruction(blockStartInstr, _)
} }
class TChiInstruction = class TChiInstruction = TAliasedSsaChiInstruction;
TAliasedSsaChiInstruction or TAliasedSsaChiAfterUninitializedGroupInstruction;
class TRawOrInitialzieGroupInstruction = TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
TRawInstruction or TAliasedSsaUninitializedGroupInstruction;
TChiInstruction chiInstruction(TRawOrInitialzieGroupInstruction primaryInstruction) {
result = TAliasedSsaChiInstruction(primaryInstruction) result = TAliasedSsaChiInstruction(primaryInstruction)
or
result = TAliasedSsaChiAfterUninitializedGroupInstruction(primaryInstruction)
} }
class TUnreachedInstruction = TAliasedSsaUnreachedInstruction; class TUnreachedInstruction = TAliasedSsaUnreachedInstruction;
@@ -126,12 +103,4 @@ module AliasedSsaInstructions {
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) { TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
result = TAliasedSsaUnreachedInstruction(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. * Provides the newtype used to represent operands across all phases of the IR.
*/ */
private module Internal { 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 * 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`), * type for operands created directly from the AST (`TRegisterOperand` and `TNonSSAMemoryOperand`),
@@ -55,7 +52,7 @@ private module Internal {
) { ) {
exists(AliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)) exists(AliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap))
} or } 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. * 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) result = Internal::TAliasedChiOperand(useInstr, tag)
} }
} }

View File

@@ -2142,47 +2142,6 @@ class ChiInstruction extends Instruction {
final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) } 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. * An instruction representing unreachable code.
* *

View File

@@ -1,3 +1,3 @@
import semmle.code.cpp.ir.implementation.raw.IR import semmle.code.cpp.ir.implementation.aliased_ssa.IR
import semmle.code.cpp.ir.internal.Overlap import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language import semmle.code.cpp.ir.internal.IRCppLanguage as Language

View File

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

View File

@@ -3208,20 +3208,9 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) }
/**
* Gets the rnk'th (0-indexed) child for which a `TranslatedElement` exists.
*
* We use this predicate to filter out `TypeName` expressions that sometimes
* occur in builtin operations since the IR doesn't have an instruction to
* represent a reference to a type.
*/
private TranslatedElement getRankedChild(int rnk) {
result = rank[rnk + 1](int id, TranslatedElement te | te = this.getChild(id) | te order by id)
}
final override Instruction getFirstInstruction(EdgeKind kind) { final override Instruction getFirstInstruction(EdgeKind kind) {
if exists(this.getRankedChild(0)) if exists(this.getChild(0))
then result = this.getRankedChild(0).getFirstInstruction(kind) then result = this.getChild(0).getFirstInstruction(kind)
else ( else (
kind instanceof GotoEdge and result = this.getInstruction(OnlyInstructionTag()) kind instanceof GotoEdge and result = this.getInstruction(OnlyInstructionTag())
) )
@@ -3241,11 +3230,11 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
} }
final override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { final override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
exists(int id | child = this.getRankedChild(id) | exists(int id | child = this.getChild(id) |
result = this.getRankedChild(id + 1).getFirstInstruction(kind) result = this.getChild(id + 1).getFirstInstruction(kind)
or or
kind instanceof GotoEdge and kind instanceof GotoEdge and
not exists(this.getRankedChild(id + 1)) and not exists(this.getChild(id + 1)) and
result = this.getInstruction(OnlyInstructionTag()) result = this.getInstruction(OnlyInstructionTag())
) )
} }
@@ -3260,7 +3249,7 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
exists(int index | exists(int index |
operandTag = positionalArgumentOperand(index) and operandTag = positionalArgumentOperand(index) and
result = this.getRankedChild(index).(TranslatedExpr).getResult() result = this.getChild(index).(TranslatedExpr).getResult()
) )
} }

View File

@@ -2142,47 +2142,6 @@ class ChiInstruction extends Instruction {
final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) } 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. * An instruction representing unreachable code.
* *

View File

@@ -1,3 +1,3 @@
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR import semmle.code.cpp.ir.implementation.aliased_ssa.IR
import semmle.code.cpp.ir.internal.Overlap import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language import semmle.code.cpp.ir.internal.IRCppLanguage as Language

View File

@@ -106,7 +106,8 @@ private predicate operandEscapesDomain(Operand operand) {
not isArgumentForParameter(_, operand, _) and not isArgumentForParameter(_, operand, _) and
not isOnlyEscapesViaReturnArgument(operand) and not isOnlyEscapesViaReturnArgument(operand) and
not operand.getUse() instanceof ReturnValueInstruction 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. // A copy propagates the source value.
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0 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) { private predicate operandEscapesNonReturn(Operand operand) {
@@ -216,6 +212,9 @@ private predicate operandEscapesNonReturn(Operand operand) {
or or
isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse()) isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse())
or or
operand instanceof PhiInputOperand and
resultEscapesNonReturn(operand.getUse())
or
operandEscapesDomain(operand) operandEscapesDomain(operand)
} }
@@ -237,6 +236,9 @@ private predicate operandMayReachReturn(Operand operand) {
operand.getUse() instanceof ReturnValueInstruction operand.getUse() instanceof ReturnValueInstruction
or or
isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse()) isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse())
or
operand instanceof PhiInputOperand and
resultMayReachReturn(operand.getUse())
} }
private predicate operandReturned(Operand operand, IntValue bitOffset) { private predicate operandReturned(Operand operand, IntValue bitOffset) {

View File

@@ -15,51 +15,6 @@ private class OldInstruction = Reachability::ReachableInstruction;
import Cached 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 cached
private module Cached { private module Cached {
cached cached
@@ -77,11 +32,6 @@ private module Cached {
hasChiNode(_, primaryInstruction) hasChiNode(_, primaryInstruction)
} }
cached
predicate hasChiNodeAfterUninitializedGroup(UninitializedGroupInstruction initGroup) {
hasChiNodeAfterUninitializedGroup(_, initGroup)
}
cached cached
predicate hasUnreachedInstructionCached(IRFunction irFunc) { predicate hasUnreachedInstructionCached(IRFunction irFunc) {
exists(OldIR::Instruction oldInstruction | exists(OldIR::Instruction oldInstruction |
@@ -95,8 +45,7 @@ private module Cached {
} }
class TStageInstruction = class TStageInstruction =
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction or TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
TUninitializedGroupInstruction;
/** /**
* If `oldInstruction` is a `Phi` instruction that has exactly one reachable predecessor block, * If `oldInstruction` is a `Phi` instruction that has exactly one reachable predecessor block,
@@ -129,8 +78,6 @@ private module Cached {
or or
instr instanceof TChiInstruction instr instanceof TChiInstruction
or or
instr instanceof TUninitializedGroupInstruction
or
instr instanceof TUnreachedInstruction instr instanceof TUnreachedInstruction
} }
@@ -176,8 +123,7 @@ private module Cached {
predicate hasModeledMemoryResult(Instruction instruction) { predicate hasModeledMemoryResult(Instruction instruction) {
canModelResultForOldInstruction(getOldInstruction(instruction)) or canModelResultForOldInstruction(getOldInstruction(instruction)) or
instruction instanceof PhiInstruction or // Phis always have modeled results instruction instanceof PhiInstruction or // Phis always have modeled results
instruction instanceof ChiInstruction or // Chis always have modeled results instruction instanceof ChiInstruction // Chis always have modeled results
instruction instanceof UninitializedGroupInstruction // Group initializers always have modeled results
} }
cached cached
@@ -188,23 +134,16 @@ private module Cached {
or or
// Chi instructions track virtual variables, and therefore a chi instruction is // Chi instructions track virtual variables, and therefore a chi instruction is
// conflated if it's associated with the aliased virtual variable. // conflated if it's associated with the aliased virtual variable.
exists(Instruction input | instruction = getChi(input) | exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) |
Alias::getResultMemoryLocation(input).getVirtualVariable() instanceof Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
Alias::AliasedVirtualVariable 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 or
// Phi instructions track locations, and therefore a phi instruction is // Phi instructions track locations, and therefore a phi instruction is
// conflated if it's associated with a conflated location. // conflated if it's associated with a conflated location.
exists(Alias::MemoryLocation location | exists(Alias::MemoryLocation location |
instruction = getPhi(_, location) and instruction = getPhi(_, location) and
not exists(location.getAnAllocation()) not exists(location.getAllocation())
) )
} }
@@ -266,11 +205,7 @@ private module Cached {
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
) )
or or
( instruction = getChi(getOldInstruction(result)) and
instruction = getChi(getOldInstruction(result))
or
instruction = getChi(result.(UninitializedGroupInstruction))
) and
tag instanceof ChiPartialOperandTag and tag instanceof ChiPartialOperandTag and
overlap instanceof MustExactlyOverlap overlap instanceof MustExactlyOverlap
or 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 * 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. * through a phi instruction and therefore should be impossible.
@@ -389,19 +316,6 @@ private module Cached {
result = getNewPhiOperandDefinitionFromOldSsa(instr, newPredecessorBlock, overlap) 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 cached
Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) { Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
exists( exists(
@@ -415,19 +329,6 @@ private module Cached {
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, vvar, _) 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 cached
@@ -443,40 +344,14 @@ private module Cached {
) )
} }
private UninitializedGroupInstruction firstInstructionToUninitializedGroup( /*
Instruction instruction, EdgeKind 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
exists(IRFunction func | * the new instructions generated from the successors of the old instruction
isFirstInstructionBeforeUninitializedGroup(instruction, func) and */
result = getInitGroupInstruction(0, func) and
kind instanceof GotoEdge
)
}
private Instruction getNextUninitializedGroupInstruction(Instruction instruction, EdgeKind kind) { cached
exists(int i, IRFunction func | Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
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
) {
if hasChiNode(_, getOldInstruction(instruction)) if hasChiNode(_, getOldInstruction(instruction))
then then
result = getChi(getOldInstruction(instruction)) and 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 cached
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) { Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
exists(OldInstruction oldInstruction | exists(OldInstruction oldInstruction |
@@ -632,16 +406,6 @@ private module Cached {
exists(IRFunctionBase irFunc | exists(IRFunctionBase irFunc |
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction() 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 cached
@@ -654,16 +418,9 @@ private module Cached {
) )
or or
exists(Instruction primaryInstr, Alias::VirtualVariable vvar | exists(Instruction primaryInstr, Alias::VirtualVariable vvar |
instr = chiInstruction(primaryInstr) and result = vvar.getType() instr = chiInstruction(primaryInstr) and
| hasChiNode(vvar, primaryInstr) and
hasChiNode(vvar, primaryInstr) result = vvar.getType()
or
hasChiNodeAfterUninitializedGroup(vvar, primaryInstr)
)
or
exists(Alias::VariableGroup vg |
instr = uninitializedGroup(vg) and
result = vg.getType()
) )
or or
instr = reusedPhiInstruction(_) and instr = reusedPhiInstruction(_) and
@@ -691,8 +448,6 @@ private module Cached {
or or
instr = chiInstruction(_) and opcode instanceof Opcode::Chi instr = chiInstruction(_) and opcode instanceof Opcode::Chi
or or
instr = uninitializedGroup(_) and opcode instanceof Opcode::UninitializedGroup
or
instr = unreachedInstruction(_) and opcode instanceof Opcode::Unreached instr = unreachedInstruction(_) and opcode instanceof Opcode::Unreached
} }
@@ -705,15 +460,10 @@ private module Cached {
result = blockStartInstr.getEnclosingIRFunction() result = blockStartInstr.getEnclosingIRFunction()
) )
or or
exists(Instruction primaryInstr | exists(OldInstruction primaryInstr |
instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction() instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction()
) )
or or
exists(Alias::VariableGroup vg |
instr = uninitializedGroup(vg) and
result = vg.getIRFunction()
)
or
instr = unreachedInstruction(result) instr = unreachedInstruction(result)
} }
@@ -728,8 +478,6 @@ private module Cached {
instruction = getChi(oldInstruction) and instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction) 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 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) { private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) {
result = phiInstruction(defBlock.getFirstInstruction(), 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 private import PhiInsertion
/** /**
@@ -930,33 +668,19 @@ private import DefUse
* potentially very sparse. * potentially very sparse.
*/ */
module DefUse { module DefUse {
bindingset[index, block]
pragma[inline_late]
private int getNonChiOffset(int index, OldBlock block) {
exists(IRFunction func | func = block.getEnclosingIRFunction() |
if
getNewBlock(block) = func.getEntryBlock() and
not block.getInstruction(index) instanceof InitializeNonLocalInstruction and
not block.getInstruction(index) 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`. * Gets the `Instruction` for the definition at offset `defOffset` in block `defBlock`.
*/ */
private Instruction getDefinitionOrChiInstruction0( Instruction getDefinitionOrChiInstruction(
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation, OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
Alias::MemoryLocation actualDefLocation 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. // An odd offset corresponds to the `Chi` instruction.
defOffset = getChiOffset(oldOffset, defBlock) and defOffset = oldOffset * 2 + 1 and
result = getChi(oldInstr) and result = getChi(oldInstr) and
( (
defLocation = Alias::getResultMemoryLocation(oldInstr) or defLocation = Alias::getResultMemoryLocation(oldInstr) or
@@ -965,7 +689,7 @@ module DefUse {
actualDefLocation = defLocation.getVirtualVariable() actualDefLocation = defLocation.getVirtualVariable()
or or
// An even offset corresponds to the original instruction. // An even offset corresponds to the original instruction.
defOffset = getNonChiOffset(oldOffset, defBlock) and defOffset = oldOffset * 2 and
result = getNewInstruction(oldInstr) and result = getNewInstruction(oldInstr) and
( (
defLocation = Alias::getResultMemoryLocation(oldInstr) or defLocation = Alias::getResultMemoryLocation(oldInstr) or
@@ -978,54 +702,6 @@ module DefUse {
hasDefinition(_, defLocation, defBlock, defOffset) and hasDefinition(_, defLocation, defBlock, defOffset) and
result = getPhi(defBlock, defLocation) and result = getPhi(defBlock, defLocation) and
actualDefLocation = defLocation 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
)
)
} }
/** /**
@@ -1166,20 +842,8 @@ module DefUse {
block.getInstruction(index) = def and block.getInstruction(index) = def and
overlap = Alias::getOverlap(defLocation, useLocation) and overlap = Alias::getOverlap(defLocation, useLocation) and
if overlap instanceof MayPartiallyOverlap if overlap instanceof MayPartiallyOverlap
then offset = getChiOffset(index, block) // The use will be connected to the definition on the `Chi` instruction. then offset = (index * 2) + 1 // 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. else offset = index * 2 // 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.
) )
} }
@@ -1240,11 +904,10 @@ module DefUse {
block.getInstruction(index) = use and block.getInstruction(index) = use and
( (
// A direct use of the location. // A direct use of the location.
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and offset = index * 2
offset = getNonChiOffset(index, block)
or or
// A `Chi` instruction will include a use of the virtual variable. // 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
) )
) )
} }
@@ -1394,9 +1057,5 @@ module Ssa {
predicate hasChiInstruction = Cached::hasChiInstructionCached/1; predicate hasChiInstruction = Cached::hasChiInstructionCached/1;
predicate hasChiNodeAfterUninitializedGroup = Cached::hasChiNodeAfterUninitializedGroup/1;
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
class VariableGroup = Alias::VariableGroup;
} }

View File

@@ -2,7 +2,6 @@ import AliasAnalysis
private import SimpleSSAImports private import SimpleSSAImports
import SimpleSSAPublicImports import SimpleSSAPublicImports
private import AliasConfiguration private import AliasConfiguration
private import codeql.util.Unit
private predicate isTotalAccess(Allocation var, AddressOperand addrOperand, IRType type) { private predicate isTotalAccess(Allocation var, AddressOperand addrOperand, IRType type) {
exists(Instruction constantBase, int bitOffset | exists(Instruction constantBase, int bitOffset |
@@ -49,7 +48,7 @@ predicate canReuseSsaForVariable(IRAutomaticVariable var) {
private newtype TMemoryLocation = MkMemoryLocation(Allocation var) { isVariableModeled(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 { class MemoryLocation extends TMemoryLocation {
Allocation var; Allocation var;
@@ -58,7 +57,7 @@ class MemoryLocation extends TMemoryLocation {
final string toString() { result = var.getAllocationString() } final string toString() { result = var.getAllocationString() }
final Allocation getAnAllocation() { result = var } final Allocation getAllocation() { result = var }
final Language::Location getLocation() { result = var.getLocation() } final Language::Location getLocation() { result = var.getLocation() }
@@ -78,40 +77,6 @@ class MemoryLocation extends TMemoryLocation {
predicate canReuseSsaForOldResult(Instruction instr) { none() } 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 * Represents a set of `MemoryLocation`s that cannot overlap with
* `MemoryLocation`s outside of the set. The `VirtualVariable` will be * `MemoryLocation`s outside of the set. The `VirtualVariable` will be

View File

@@ -7,6 +7,119 @@
import semmle.code.cpp.models.interfaces.Allocation import semmle.code.cpp.models.interfaces.Allocation
import semmle.code.cpp.models.interfaces.Taint import semmle.code.cpp.models.interfaces.Taint
/**
* An allocation function (such as `malloc`) that has an argument for the size
* in bytes.
*/
private class MallocAllocationFunction extends AllocationFunction {
int sizeArg;
MallocAllocationFunction() {
// --- C library allocation
this.hasGlobalOrStdOrBslName("malloc") and // malloc(size)
sizeArg = 0
or
this.hasGlobalName([
// --- Windows Memory Management for Windows Drivers
"MmAllocateContiguousMemory", // MmAllocateContiguousMemory(size, maxaddress)
"MmAllocateContiguousNodeMemory", // MmAllocateContiguousNodeMemory(size, minaddress, maxaddress, bound, flag, prefer)
"MmAllocateContiguousMemorySpecifyCache", // MmAllocateContiguousMemorySpecifyCache(size, minaddress, maxaddress, bound, type)
"MmAllocateContiguousMemorySpecifyCacheNode", // MmAllocateContiguousMemorySpecifyCacheNode(size, minaddress, maxaddress, bound, type, prefer)
"MmAllocateNonCachedMemory", // MmAllocateNonCachedMemory(size)
"MmAllocateMappingAddress", // MmAllocateMappingAddress(size, tag)
// --- Windows COM allocation
"CoTaskMemAlloc", // CoTaskMemAlloc(size)
// --- Solaris/BSD kernel memory allocator
"kmem_alloc", // kmem_alloc(size, flags)
"kmem_zalloc", // kmem_zalloc(size, flags)
// --- OpenSSL memory allocation
"CRYPTO_malloc", // CRYPTO_malloc(size_t num, const char *file, int line)
"CRYPTO_zalloc", // CRYPTO_zalloc(size_t num, const char *file, int line)
"CRYPTO_secure_malloc", // CRYPTO_secure_malloc(size_t num, const char *file, int line)
"CRYPTO_secure_zalloc", // CRYPTO_secure_zalloc(size_t num, const char *file, int line)
"g_malloc", // g_malloc (n_bytes);
"g_try_malloc" // g_try_malloc(n_bytes);
]) and
sizeArg = 0
or
this.hasGlobalName([
// --- Windows Memory Management for Windows Drivers
"ExAllocatePool", // ExAllocatePool(type, size)
"ExAllocatePool2", // ExAllocatePool2(flags, size, tag)
"ExAllocatePool3", // ExAllocatePool3(flags, size, tag, extparams, extparamscount)
"ExAllocatePoolWithTag", // ExAllocatePool(type, size, tag)
"ExAllocatePoolWithTagPriority", // ExAllocatePoolWithTagPriority(type, size, tag, priority)
"ExAllocatePoolWithQuota", // ExAllocatePoolWithQuota(type, size)
"ExAllocatePoolWithQuotaTag", // ExAllocatePoolWithQuotaTag(type, size, tag)
"ExAllocatePoolZero", // ExAllocatePoolZero(type, size, tag)
"IoAllocateMdl", // IoAllocateMdl(address, size, flag, flag, irp)
"IoAllocateErrorLogEntry", // IoAllocateErrorLogEntry(object, size)
// --- Windows Global / Local legacy allocation
"LocalAlloc", // LocalAlloc(flags, size)
"GlobalAlloc", // GlobalAlloc(flags, size)
// --- Windows System Services allocation
"VirtualAlloc" // VirtualAlloc(address, size, type, flag)
]) and
sizeArg = 1
or
this.hasGlobalName("HeapAlloc") and // HeapAlloc(heap, flags, size)
sizeArg = 2
or
this.hasGlobalName([
// --- Windows Memory Management for Windows Drivers
"MmAllocatePagesForMdl", // MmAllocatePagesForMdl(minaddress, maxaddress, skip, size)
"MmAllocatePagesForMdlEx", // MmAllocatePagesForMdlEx(minaddress, maxaddress, skip, size, type, flags)
"MmAllocateNodePagesForMdlEx" // MmAllocateNodePagesForMdlEx(minaddress, maxaddress, skip, size, type, prefer, flags)
]) and
sizeArg = 3
}
override int getSizeArg() { result = sizeArg }
}
/**
* An allocation function (such as `alloca`) that does not require a
* corresponding free (and has an argument for the size in bytes).
*/
private class AllocaAllocationFunction extends AllocationFunction {
int sizeArg;
AllocaAllocationFunction() {
this.hasGlobalName([
// --- stack allocation
"alloca", // // alloca(size)
"__builtin_alloca", // __builtin_alloca(size)
"_alloca", // _alloca(size)
"_malloca" // _malloca(size)
]) and
sizeArg = 0
}
override int getSizeArg() { result = sizeArg }
override predicate requiresDealloc() { none() }
}
/**
* An allocation function (such as `calloc`) that has an argument for the size
* and another argument for the size of those units (in bytes).
*/
private class CallocAllocationFunction extends AllocationFunction {
int sizeArg;
int multArg;
CallocAllocationFunction() {
// --- C library allocation
this.hasGlobalOrStdOrBslName("calloc") and // calloc(num, size)
sizeArg = 1 and
multArg = 0
}
override int getSizeArg() { result = sizeArg }
override int getSizeMult() { result = multArg }
}
/** /**
* An allocation function (such as `realloc`) that has an argument for the size * An allocation function (such as `realloc`) that has an argument for the size
* in bytes, and an argument for an existing pointer that is to be reallocated. * in bytes, and an argument for an existing pointer that is to be reallocated.
@@ -260,63 +373,6 @@ private class NewArrayAllocationExpr extends AllocationExpr, NewArrayExpr {
override predicate requiresDealloc() { not exists(this.getPlacementPointer()) } override predicate requiresDealloc() { not exists(this.getPlacementPointer()) }
} }
/**
* Holds if `f` is an allocation function according to the
* extensible `allocationFunctionModel` predicate.
*/
private predicate isAllocationFunctionFromModel(
Function f, string namespace, string type, string name
) {
exists(boolean subtypes | allocationFunctionModel(namespace, type, subtypes, name, _, _, _, _) |
if type = ""
then f.hasQualifiedName(namespace, "", name)
else
exists(Class c |
c.hasQualifiedName(namespace, type) and f.hasQualifiedName(namespace, _, name)
|
if subtypes = true
then f = c.getADerivedClass*().getAMemberFunction()
else f = c.getAMemberFunction()
)
)
}
/**
* An allocation function modeled via the extensible `allocationFunctionModel` predicate.
*/
private class AllocationFunctionFromModel extends AllocationFunction {
string namespace;
string type;
string name;
AllocationFunctionFromModel() { isAllocationFunctionFromModel(this, namespace, type, name) }
final override int getSizeArg() {
exists(string sizeArg |
allocationFunctionModel(namespace, type, _, name, sizeArg, _, _, _) and
result = sizeArg.toInt()
)
}
final override int getSizeMult() {
exists(string sizeMult |
allocationFunctionModel(namespace, type, _, name, _, sizeMult, _, _) and
result = sizeMult.toInt()
)
}
final override int getReallocPtrArg() {
exists(string reallocPtrArg |
allocationFunctionModel(namespace, type, _, name, _, _, reallocPtrArg, _) and
result = reallocPtrArg.toInt()
)
}
final override predicate requiresDealloc() {
allocationFunctionModel(namespace, type, _, name, _, _, _, true)
}
}
private module HeuristicAllocation { private module HeuristicAllocation {
/** A class that maps an `AllocationExpr` to an `HeuristicAllocationExpr`. */ /** A class that maps an `AllocationExpr` to an `HeuristicAllocationExpr`. */
private class HeuristicAllocationModeled extends HeuristicAllocationExpr instanceof AllocationExpr private class HeuristicAllocationModeled extends HeuristicAllocationExpr instanceof AllocationExpr

View File

@@ -7,42 +7,61 @@
import semmle.code.cpp.models.interfaces.Deallocation import semmle.code.cpp.models.interfaces.Deallocation
/** /**
* Holds if `f` is an deallocation function according to the * A deallocation function such as `free`.
* extensible `deallocationFunctionModel` predicate.
*/ */
private predicate isDeallocationFunctionFromModel( private class StandardDeallocationFunction extends DeallocationFunction {
Function f, string namespace, string type, string name int freedArg;
) {
exists(boolean subtypes | deallocationFunctionModel(namespace, type, subtypes, name, _) |
if type = ""
then f.hasQualifiedName(namespace, "", name)
else
exists(Class c |
c.hasQualifiedName(namespace, type) and f.hasQualifiedName(namespace, _, name)
|
if subtypes = true
then f = c.getADerivedClass*().getAMemberFunction()
else f = c.getAMemberFunction()
)
)
}
/** StandardDeallocationFunction() {
* A deallocation function modeled via the extensible `deallocationFunctionModel` predicate. this.hasGlobalOrStdOrBslName([
*/ // --- C library allocation
private class DeallocationFunctionFromModel extends DeallocationFunction { "free", "realloc"
string namespace; ]) and
string type; freedArg = 0
string name; or
this.hasGlobalName([
DeallocationFunctionFromModel() { isDeallocationFunctionFromModel(this, namespace, type, name) } // --- OpenSSL memory deallocation
"CRYPTO_free", "CRYPTO_secure_free",
final override int getFreedArg() { // --- glib memory deallocation
exists(string freedArg | "g_free"
deallocationFunctionModel(namespace, type, _, name, freedArg) and ]) and
result = freedArg.toInt() freedArg = 0
) or
this.hasGlobalOrStdName([
// --- Windows Memory Management for Windows Drivers
"ExFreePool", "ExFreePoolWithTag", "ExDeleteTimer", "IoFreeIrp", "IoFreeMdl",
"IoFreeErrorLogEntry", "IoFreeWorkItem", "MmFreeContiguousMemory",
"MmFreeContiguousMemorySpecifyCache", "MmFreeNonCachedMemory", "MmFreeMappingAddress",
"MmFreePagesFromMdl", "MmUnmapReservedMapping", "MmUnmapLockedPages",
"NdisFreeGenericObject", "NdisFreeMemory", "NdisFreeMemoryWithTag", "NdisFreeMdl",
"NdisFreeNetBufferListPool", "NdisFreeNetBufferPool",
// --- Windows Global / Local legacy allocation
"LocalFree", "GlobalFree", "LocalReAlloc", "GlobalReAlloc",
// --- Windows System Services allocation
"VirtualFree",
// --- Windows COM allocation
"CoTaskMemFree", "CoTaskMemRealloc",
// --- Windows Automation
"SysFreeString",
// --- Solaris/BSD kernel memory allocator
"kmem_free"
]) and
freedArg = 0
or
this.hasGlobalOrStdName([
// --- Windows Memory Management for Windows Drivers
"ExFreeToLookasideListEx", "ExFreeToPagedLookasideList", "ExFreeToNPagedLookasideList",
"NdisFreeMemoryWithTagPriority", "StorPortFreeMdl", "StorPortFreePool",
// --- NetBSD pool manager
"pool_put", "pool_cache_put"
]) and
freedArg = 1
or
this.hasGlobalOrStdName(["HeapFree", "HeapReAlloc"]) and
freedArg = 2
} }
override int getFreedArg() { result = freedArg }
} }
/** /**

View File

@@ -2,7 +2,7 @@
* Provides models for C++ containers `std::array`, `std::vector`, `std::deque`, `std::list` and `std::forward_list`. * Provides models for C++ containers `std::array`, `std::vector`, `std::deque`, `std::list` and `std::forward_list`.
*/ */
import semmle.code.cpp.models.interfaces.FlowSource import semmle.code.cpp.models.interfaces.Taint
import semmle.code.cpp.models.interfaces.Iterator import semmle.code.cpp.models.interfaces.Iterator
/** /**
@@ -55,6 +55,73 @@ private class Vector extends StdSequenceContainer {
Vector() { this.hasQualifiedName(["std", "bsl"], "vector") } Vector() { this.hasQualifiedName(["std", "bsl"], "vector") }
} }
/**
* Additional model for standard container constructors that reference the
* value type of the container (that is, the `T` in `std::vector<T>`). For
* example the fill constructor:
* ```
* std::vector<std::string> v(100, potentially_tainted_string);
* ```
*/
private class StdSequenceContainerConstructor extends Constructor, TaintFunction {
StdSequenceContainerConstructor() {
this.getDeclaringType() instanceof Vector or
this.getDeclaringType() instanceof Deque or
this.getDeclaringType() instanceof List or
this.getDeclaringType() instanceof ForwardList
}
/**
* Gets the index of a parameter to this function that is a reference to the
* value type of the container.
*/
int getAValueTypeParameterIndex() {
this.getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() =
this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector<T>`
}
/**
* Gets the index of a parameter to this function that is an iterator.
*/
int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// taint flow from any parameter of the value type to the returned object
(
input.isParameterDeref(this.getAValueTypeParameterIndex()) or
input.isParameter(this.getAnIteratorParameterIndex())
) and
(
output.isReturnValue() // TODO: this is only needed for AST data flow, which treats constructors as returning the new object
or
output.isQualifierObject()
)
}
}
/**
* The standard container function `data`.
*/
private class StdSequenceContainerData extends TaintFunction {
StdSequenceContainerData() {
this.getClassAndName("data") instanceof Array or
this.getClassAndName("data") instanceof Vector
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from container itself (qualifier) to return value
input.isQualifierObject() and
output.isReturnValueDeref()
or
// reverse flow from returned reference to the qualifier (for writes to
// `data`)
input.isReturnValueDeref() and
output.isQualifierObject()
}
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
}
/** /**
* The standard container functions `push_back` and `push_front`. * The standard container functions `push_back` and `push_front`.
*/ */
@@ -76,6 +143,35 @@ class StdSequenceContainerPush extends MemberFunction {
} }
} }
private class StdSequenceContainerPushModel extends StdSequenceContainerPush, TaintFunction {
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from parameter to qualifier
input.isParameterDeref(0) and
output.isQualifierObject()
}
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
}
/**
* The standard container functions `front` and `back`.
*/
private class StdSequenceContainerFrontBack extends TaintFunction {
StdSequenceContainerFrontBack() {
this.getClassAndName(["front", "back"]) instanceof Array or
this.getClassAndName(["front", "back"]) instanceof Deque or
this.getClassAndName("front") instanceof ForwardList or
this.getClassAndName(["front", "back"]) instanceof List or
this.getClassAndName(["front", "back"]) instanceof Vector
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from object to returned reference
input.isQualifierObject() and
output.isReturnValueDeref()
}
}
/** /**
* The standard container functions `insert` and `insert_after`. * The standard container functions `insert` and `insert_after`.
*/ */
@@ -102,6 +198,58 @@ class StdSequenceContainerInsert extends MemberFunction {
int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator } int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator }
} }
private class StdSequenceContainerInsertModel extends StdSequenceContainerInsert, TaintFunction {
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from parameter to container itself (qualifier) and return value
(
input.isQualifierObject() or
input.isParameterDeref(this.getAValueTypeParameterIndex()) or
input.isParameter(this.getAnIteratorParameterIndex())
) and
(
output.isQualifierObject() or
output.isReturnValue()
)
}
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
}
/**
* The standard container function `assign`.
*/
private class StdSequenceContainerAssign extends TaintFunction {
StdSequenceContainerAssign() {
this.getClassAndName("assign") instanceof Deque or
this.getClassAndName("assign") instanceof ForwardList or
this.getClassAndName("assign") instanceof List or
this.getClassAndName("assign") instanceof Vector
}
/**
* Gets the index of a parameter to this function that is a reference to the
* value type of the container.
*/
int getAValueTypeParameterIndex() {
this.getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() =
this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector<T>`
}
/**
* Gets the index of a parameter to this function that is an iterator.
*/
int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from parameter to container itself (qualifier)
(
input.isParameterDeref(this.getAValueTypeParameterIndex()) or
input.isParameter(this.getAnIteratorParameterIndex())
) and
output.isQualifierObject()
}
}
/** /**
* The standard container functions `at` and `operator[]`. * The standard container functions `at` and `operator[]`.
*/ */
@@ -113,6 +261,20 @@ class StdSequenceContainerAt extends MemberFunction {
} }
} }
private class StdSequenceContainerAtModel extends StdSequenceContainerAt, TaintFunction {
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from qualifier to referenced return value
input.isQualifierObject() and
output.isReturnValueDeref()
or
// reverse flow from returned reference to the qualifier
input.isReturnValueDeref() and
output.isQualifierObject()
}
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
}
/** /**
* The standard `emplace` function. * The standard `emplace` function.
*/ */
@@ -135,6 +297,20 @@ class StdSequenceEmplace extends MemberFunction {
} }
} }
private class StdSequenceEmplaceModel extends StdSequenceEmplace, TaintFunction {
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from any parameter except the position iterator to qualifier and return value
// (here we assume taint flow from any constructor parameter to the constructed object)
input.isParameterDeref([1 .. this.getNumberOfParameters() - 1]) and
(
output.isQualifierObject() or
output.isReturnValue()
)
}
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
}
/** /**
* The standard vector `emplace` function. * The standard vector `emplace` function.
*/ */
@@ -164,6 +340,17 @@ class StdSequenceEmplaceBack extends MemberFunction {
} }
} }
private class StdSequenceEmplaceBackModel extends StdSequenceEmplaceBack, TaintFunction {
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from any parameter to qualifier
// (here we assume taint flow from any constructor parameter to the constructed object)
input.isParameterDeref([0 .. this.getNumberOfParameters() - 1]) and
output.isQualifierObject()
}
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
}
/** /**
* The standard vector `emplace_back` function. * The standard vector `emplace_back` function.
*/ */

View File

@@ -66,7 +66,7 @@ abstract private class StdStringTaintFunction extends TaintFunction {
* Gets the index of a parameter to this function that is an iterator. * Gets the index of a parameter to this function that is an iterator.
*/ */
final int getAnIteratorParameterIndex() { final int getAnIteratorParameterIndex() {
this.getParameter(result).getUnspecifiedType() instanceof Iterator this.getParameter(result).getType() instanceof Iterator
} }
} }

View File

@@ -89,14 +89,6 @@ abstract class AllocationFunction extends Function {
predicate requiresDealloc() { any() } predicate requiresDealloc() { any() }
} }
/**
* Holds if an external allocation model exists for the given parameters.
*/
extensible predicate allocationFunctionModel(
string namespace, string type, boolean subtypes, string name, string sizeArg, string multArg,
string reallocPtrArg, boolean requiresDealloc
);
/** /**
* An `operator new` or `operator new[]` function that may be associated with * An `operator new` or `operator new[]` function that may be associated with
* `new` or `new[]` expressions. Note that `new` and `new[]` are not function * `new` or `new[]` expressions. Note that `new` and `new[]` are not function

View File

@@ -34,13 +34,6 @@ abstract class DeallocationFunction extends Function {
int getFreedArg() { none() } int getFreedArg() { none() }
} }
/**
* Holds if an external deallocation model exists for the given parameters.
*/
extensible predicate deallocationFunctionModel(
string namespace, string type, boolean subtypes, string name, string freedArg
);
/** /**
* An `operator delete` or `operator delete[]` function that may be associated * An `operator delete` or `operator delete[]` function that may be associated
* with `delete` or `delete[]` expressions. Note that `delete` and `delete[]` * with `delete` or `delete[]` expressions. Note that `delete` and `delete[]`

View File

@@ -95,7 +95,7 @@ module FlowFromFree<FlowFromFreeParamSig P> {
e = any(StoreInstruction store).getDestinationAddress().getUnconvertedResultExpression() e = any(StoreInstruction store).getDestinationAddress().getUnconvertedResultExpression()
) )
or or
[n.asExpr(), n.asIndirectExpr()] instanceof ArrayExpr n.asExpr() instanceof ArrayExpr
} }
} }

View File

@@ -1748,25 +1748,6 @@ case @expr.kind of
| 361 = @isvoid | 361 = @isvoid
| 362 = @isvolatile | 362 = @isvolatile
| 363 = @reuseexpr | 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 @var_args_expr = @vastartexpr
@@ -1861,25 +1842,6 @@ case @expr.kind of
| @isunsigned | @isunsigned
| @isvoid | @isvoid
| @isvolatile | @isvolatile
| @istriviallycopyassignable
| @isassignablenopreconditioncheck
| @referencebindstotemporary
| @issameas
| @builtinhasattribute
| @ispointerinterconvertiblewithclass
| @builtinispointerinterconvertiblewithclass
| @iscorrespondingmember
| @builtiniscorrespondingmember
| @isboundedarray
| @isunboundedarray
| @isreferenceable
| @isnothrowconvertible
| @referenceconstructsfromtemporary
| @referenceconvertsfromtemporary
| @isconvertible
| @isvalidwinrttype
| @iswinclass
| @iswininterface
; ;
new_allocated_type( new_allocated_type(

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