diff --git a/.bazelrc b/.bazelrc
index 679eeec77a3..8687f4406cb 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -11,6 +11,8 @@ build --compilation_mode opt
common --override_module=semmle_code=%workspace%/misc/bazel/semmle_code_stub
build --repo_env=CC=clang --repo_env=CXX=clang++
+# Disable Android SDK auto-detection (we don't use it, and rules_android has Bazel 9 compatibility issues)
+build --repo_env=ANDROID_HOME=
# print test output, like sembuild does.
# Set to `errors` if this is too verbose.
@@ -34,7 +36,7 @@ common --@rules_dotnet//dotnet/settings:strict_deps=false
common --@rules_rust//rust/toolchain/channel=nightly
# Reduce this eventually to empty, once we've fixed all our usages of java, and https://github.com/bazel-contrib/rules_go/issues/4193 is fixed
-common --incompatible_autoload_externally="+@rules_java,+@rules_shell"
+common --incompatible_autoload_externally="+@rules_cc,+@rules_java,+@rules_shell"
build --java_language_version=17
build --tool_java_language_version=17
diff --git a/.bazelversion b/.bazelversion
index e7fdef7e2e6..f7ee06693c1 100644
--- a/.bazelversion
+++ b/.bazelversion
@@ -1 +1 @@
-8.4.2
+9.0.0
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 60b21a86163..30cb9833a6a 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -45,3 +45,5 @@ updates:
directory: "/"
schedule:
interval: weekly
+ exclude-paths:
+ - "misc/bazel/registry/**"
diff --git a/.github/workflows/compile-queries.yml b/.github/workflows/compile-queries.yml
deleted file mode 100644
index c8f6301bb53..00000000000
--- a/.github/workflows/compile-queries.yml
+++ /dev/null
@@ -1,78 +0,0 @@
-name: "Compile all queries using the latest stable CodeQL CLI"
-
-on:
- push:
- branches: # makes sure the cache gets populated - running on the branches people tend to merge into.
- - main
- - "rc/*"
- - "codeql-cli-*"
- pull_request:
- paths:
- - '**.ql'
- - '**.qll'
- - '**/qlpack.yml'
- - '**.dbscheme'
-
-permissions:
- contents: read
-
-jobs:
- detect-changes:
- if: github.repository_owner == 'github'
- runs-on: ubuntu-latest
- outputs:
- languages: ${{ steps.detect.outputs.languages }}
- steps:
- - uses: actions/checkout@v5
- - name: Detect changed languages
- id: detect
- run: |
- if [[ "${{ github.event_name }}" == "pull_request" ]]; then
- # For PRs, detect which languages have changes
- changed_files=$(gh pr view ${{ github.event.pull_request.number }} --json files --jq '.files.[].path')
- languages=()
- for lang in actions cpp csharp go java javascript python ql ruby rust swift; do
- if echo "$changed_files" | grep -qE "^($lang/|shared/)" ; then
- languages+=("$lang")
- fi
- done
- echo "languages=$(jq -c -n '$ARGS.positional' --args "${languages[@]}")" >> $GITHUB_OUTPUT
- else
- # For pushes to main/rc branches, run all languages
- echo 'languages=["actions","cpp","csharp","go","java","javascript","python","ql","ruby","rust","swift"]' >> $GITHUB_OUTPUT
- fi
- env:
- GH_TOKEN: ${{ github.token }}
-
- compile-queries:
- needs: detect-changes
- if: github.repository_owner == 'github' && needs.detect-changes.outputs.languages != '[]'
- runs-on: ubuntu-latest-xl
- strategy:
- fail-fast: false
- matrix:
- language: ${{ fromJson(needs.detect-changes.outputs.languages) }}
-
- steps:
- - uses: actions/checkout@v5
- - name: Setup CodeQL
- uses: ./.github/actions/fetch-codeql
- with:
- channel: 'release'
- - name: Cache compilation cache
- id: query-cache
- uses: ./.github/actions/cache-query-compilation
- with:
- key: ${{ matrix.language }}-queries
- - name: check formatting
- run: find shared ${{ matrix.language }}/ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 -n 3000 -P 10 codeql query format -q --check-only
- - name: compile queries - check-only
- # run with --check-only if running in a PR (github.sha != main)
- if : ${{ github.event_name == 'pull_request' }}
- shell: bash
- run: codeql query compile -q -j0 ${{ matrix.language }}/ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
- - name: compile queries - full
- # do full compile if running on main - this populates the cache
- if : ${{ github.event_name != 'pull_request' }}
- shell: bash
- run: codeql query compile -q -j0 ${{ matrix.language }}/ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
diff --git a/.github/workflows/ruby-build.yml b/.github/workflows/ruby-build.yml
deleted file mode 100644
index 39aadef0913..00000000000
--- a/.github/workflows/ruby-build.yml
+++ /dev/null
@@ -1,236 +0,0 @@
-name: "Ruby: Build"
-
-on:
- push:
- paths:
- - "ruby/**"
- - .github/workflows/ruby-build.yml
- - .github/actions/fetch-codeql/action.yml
- - codeql-workspace.yml
- - "shared/tree-sitter-extractor/**"
- branches:
- - main
- - "rc/*"
- pull_request:
- paths:
- - "ruby/**"
- - .github/workflows/ruby-build.yml
- - .github/actions/fetch-codeql/action.yml
- - codeql-workspace.yml
- - "shared/tree-sitter-extractor/**"
- branches:
- - main
- - "rc/*"
- workflow_dispatch:
- inputs:
- tag:
- description: "Version tag to create"
- required: false
-
-env:
- CARGO_TERM_COLOR: always
-
-defaults:
- run:
- working-directory: ruby
-
-permissions:
- contents: read
-
-jobs:
- build:
- strategy:
- fail-fast: false
- matrix:
- os: [ubuntu-latest, macos-latest, windows-latest]
-
- runs-on: ${{ matrix.os }}
-
- steps:
- - uses: actions/checkout@v5
- - name: Install GNU tar
- if: runner.os == 'macOS'
- run: |
- brew install gnu-tar
- echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH
- - name: Prepare Windows
- if: runner.os == 'Windows'
- shell: powershell
- run: |
- git config --global core.longpaths true
- - uses: ./.github/actions/os-version
- id: os_version
- - name: Cache entire extractor
- uses: actions/cache@v3
- id: cache-extractor
- with:
- path: |
- target/release/codeql-extractor-ruby
- target/release/codeql-extractor-ruby.exe
- ruby/extractor/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
- key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/Cargo.lock') }}-${{ hashFiles('shared/tree-sitter-extractor') }}-${{ hashFiles('ruby/extractor/**/*.rs') }}
- - uses: actions/cache@v3
- if: steps.cache-extractor.outputs.cache-hit != 'true'
- with:
- path: |
- ~/.cargo/registry
- ~/.cargo/git
- target
- key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-rust-cargo-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/**/Cargo.lock') }}
- - name: Check formatting
- if: steps.cache-extractor.outputs.cache-hit != 'true'
- run: cd extractor && cargo fmt -- --check
- - name: Build
- if: steps.cache-extractor.outputs.cache-hit != 'true'
- run: cd extractor && cargo build --verbose
- - name: Run tests
- if: steps.cache-extractor.outputs.cache-hit != 'true'
- run: cd extractor && cargo test --verbose
- - name: Release build
- if: steps.cache-extractor.outputs.cache-hit != 'true'
- run: cd extractor && cargo build --release
- - name: Generate dbscheme
- if: ${{ matrix.os == 'ubuntu-latest' && steps.cache-extractor.outputs.cache-hit != 'true'}}
- run: ../target/release/codeql-extractor-ruby generate --dbscheme ql/lib/ruby.dbscheme --library ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
- - uses: actions/upload-artifact@v4
- if: ${{ matrix.os == 'ubuntu-latest' }}
- with:
- name: ruby.dbscheme
- path: ruby/ql/lib/ruby.dbscheme
- - uses: actions/upload-artifact@v4
- if: ${{ matrix.os == 'ubuntu-latest' }}
- with:
- name: TreeSitter.qll
- path: ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
- - uses: actions/upload-artifact@v4
- with:
- name: extractor-${{ matrix.os }}
- path: |
- target/release/codeql-extractor-ruby
- target/release/codeql-extractor-ruby.exe
- retention-days: 1
- compile-queries:
- if: github.repository_owner == 'github'
- runs-on: ubuntu-latest-xl
- steps:
- - uses: actions/checkout@v5
- - name: Fetch CodeQL
- uses: ./.github/actions/fetch-codeql
- - name: Cache compilation cache
- id: query-cache
- uses: ./.github/actions/cache-query-compilation
- with:
- key: ruby-build
- - name: Build Query Pack
- run: |
- PACKS=${{ runner.temp }}/query-packs
- rm -rf $PACKS
- codeql pack create ../misc/suite-helpers --output "$PACKS"
- codeql pack create ../shared/regex --output "$PACKS"
- codeql pack create ../shared/ssa --output "$PACKS"
- codeql pack create ../shared/tutorial --output "$PACKS"
- codeql pack create ql/lib --output "$PACKS"
- codeql pack create -j0 ql/src --output "$PACKS" --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
- PACK_FOLDER=$(readlink -f "$PACKS"/codeql/ruby-queries/*)
- codeql generate query-help --format=sarifv2.1.0 --output="${PACK_FOLDER}/rules.sarif" ql/src
- (cd ql/src; find queries \( -name '*.qhelp' -o -name '*.rb' -o -name '*.erb' \) -exec bash -c 'mkdir -p "'"${PACK_FOLDER}"'/$(dirname "{}")"' \; -exec cp "{}" "${PACK_FOLDER}/{}" \;)
- - uses: actions/upload-artifact@v4
- with:
- name: codeql-ruby-queries
- path: |
- ${{ runner.temp }}/query-packs/*
- retention-days: 1
- include-hidden-files: true
-
- package:
- runs-on: ubuntu-latest
- needs: [build, compile-queries]
- steps:
- - uses: actions/checkout@v5
- - uses: actions/download-artifact@v4
- with:
- name: ruby.dbscheme
- path: ruby/ruby
- - uses: actions/download-artifact@v4
- with:
- name: extractor-ubuntu-latest
- path: ruby/linux64
- - uses: actions/download-artifact@v4
- with:
- name: extractor-windows-latest
- path: ruby/win64
- - uses: actions/download-artifact@v4
- with:
- name: extractor-macos-latest
- path: ruby/osx64
- - run: |
- mkdir -p ruby
- cp -r codeql-extractor.yml tools ql/lib/ruby.dbscheme.stats ruby/
- mkdir -p ruby/tools/{linux64,osx64,win64}
- cp linux64/codeql-extractor-ruby ruby/tools/linux64/extractor
- cp osx64/codeql-extractor-ruby ruby/tools/osx64/extractor
- cp win64/codeql-extractor-ruby.exe ruby/tools/win64/extractor.exe
- chmod +x ruby/tools/{linux64,osx64}/extractor
- zip -rq codeql-ruby.zip ruby
- - uses: actions/upload-artifact@v4
- with:
- name: codeql-ruby-pack
- path: ruby/codeql-ruby.zip
- retention-days: 1
- include-hidden-files: true
- - uses: actions/download-artifact@v4
- with:
- name: codeql-ruby-queries
- path: ruby/qlpacks
- - run: |
- echo '{
- "provide": [
- "ruby/codeql-extractor.yml",
- "qlpacks/*/*/*/qlpack.yml"
- ]
- }' > .codeqlmanifest.json
- zip -rq codeql-ruby-bundle.zip .codeqlmanifest.json ruby qlpacks
- - uses: actions/upload-artifact@v4
- with:
- name: codeql-ruby-bundle
- path: ruby/codeql-ruby-bundle.zip
- retention-days: 1
- include-hidden-files: true
-
- test:
- defaults:
- run:
- working-directory: ${{ github.workspace }}
- strategy:
- fail-fast: false
- matrix:
- os: [ubuntu-latest, macos-latest, windows-latest]
-
- runs-on: ${{ matrix.os }}
- needs: [package]
- steps:
- - uses: actions/checkout@v5
- - name: Fetch CodeQL
- uses: ./.github/actions/fetch-codeql
-
- - name: Download Ruby bundle
- uses: actions/download-artifact@v4
- with:
- name: codeql-ruby-bundle
- path: ${{ runner.temp }}
- - name: Unzip Ruby bundle
- shell: bash
- run: unzip -q -d "${{ runner.temp }}/ruby-bundle" "${{ runner.temp }}/codeql-ruby-bundle.zip"
-
- - name: Run QL test
- shell: bash
- run: |
- codeql test run --search-path "${{ runner.temp }}/ruby-bundle" --additional-packs "${{ runner.temp }}/ruby-bundle" ruby/ql/test/library-tests/ast/constants/
- - name: Create database
- shell: bash
- run: |
- codeql database create --search-path "${{ runner.temp }}/ruby-bundle" --language ruby --source-root ruby/ql/test/library-tests/ast/constants/ ../database
- - name: Analyze database
- shell: bash
- run: |
- codeql database analyze --search-path "${{ runner.temp }}/ruby-bundle" --format=sarifv2.1.0 --output=out.sarif ../database ruby-code-scanning.qls
diff --git a/.github/workflows/ruby-dataset-measure.yml b/.github/workflows/ruby-dataset-measure.yml
deleted file mode 100644
index a88b23bf3a1..00000000000
--- a/.github/workflows/ruby-dataset-measure.yml
+++ /dev/null
@@ -1,75 +0,0 @@
-name: "Ruby: Collect database stats"
-
-on:
- push:
- branches:
- - main
- - "rc/*"
- paths:
- - ruby/ql/lib/ruby.dbscheme
- - .github/workflows/ruby-dataset-measure.yml
- pull_request:
- branches:
- - main
- - "rc/*"
- paths:
- - ruby/ql/lib/ruby.dbscheme
- - .github/workflows/ruby-dataset-measure.yml
- workflow_dispatch:
-
-permissions:
- contents: read
-
-jobs:
- measure:
- env:
- CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
- strategy:
- fail-fast: false
- matrix:
- repo: [rails/rails, discourse/discourse, spree/spree, ruby/ruby]
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v5
-
- - uses: ./.github/actions/fetch-codeql
-
- - uses: ./ruby/actions/create-extractor-pack
-
- - name: Checkout ${{ matrix.repo }}
- uses: actions/checkout@v5
- with:
- repository: ${{ matrix.repo }}
- path: ${{ github.workspace }}/repo
- - name: Create database
- run: |
- codeql database create \
- --search-path "${{ github.workspace }}" \
- --threads 4 \
- --language ruby --source-root "${{ github.workspace }}/repo" \
- "${{ runner.temp }}/database"
- - name: Measure database
- run: |
- mkdir -p "stats/${{ matrix.repo }}"
- codeql dataset measure --threads 4 --output "stats/${{ matrix.repo }}/stats.xml" "${{ runner.temp }}/database/db-ruby"
- - uses: actions/upload-artifact@v4
- with:
- name: measurements-${{ hashFiles('stats/**') }}
- path: stats
- retention-days: 1
-
- merge:
- runs-on: ubuntu-latest
- needs: measure
- steps:
- - uses: actions/checkout@v5
- - uses: actions/download-artifact@v4
- with:
- path: stats
- - run: |
- python -m pip install --user lxml
- find stats -name 'stats.xml' | sort | xargs python ruby/scripts/merge_stats.py --output ruby/ql/lib/ruby.dbscheme.stats --normalise ruby_tokeninfo
- - uses: actions/upload-artifact@v4
- with:
- name: ruby.dbscheme.stats
- path: ruby/ql/lib/ruby.dbscheme.stats
diff --git a/.github/workflows/ruby-qltest-rtjo.yml b/.github/workflows/ruby-qltest-rtjo.yml
deleted file mode 100644
index 1d57c465538..00000000000
--- a/.github/workflows/ruby-qltest-rtjo.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-name: "Ruby: Run RTJO Language Tests"
-
-on:
- pull_request:
- types:
- - opened
- - synchronize
- - reopened
- - labeled
-
-env:
- CARGO_TERM_COLOR: always
-
-defaults:
- run:
- working-directory: ruby
-
-permissions:
- contents: read
-
-jobs:
- qltest-rtjo:
- if: "github.repository_owner == 'github' && github.event.label.name == 'Run: RTJO Language Tests'"
- runs-on: ubuntu-latest-xl
- strategy:
- fail-fast: false
- steps:
- - uses: actions/checkout@v5
- - uses: ./.github/actions/fetch-codeql
- - uses: ./ruby/actions/create-extractor-pack
- - name: Cache compilation cache
- id: query-cache
- uses: ./.github/actions/cache-query-compilation
- with:
- key: ruby-qltest
- - name: Run QL tests
- run: |
- codeql test run --dynamic-join-order-mode=all --threads=0 --ram 50000 --search-path "${{ github.workspace }}" --check-databases --check-diff-informed --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:
- GITHUB_TOKEN: ${{ github.token }}
diff --git a/.github/workflows/ruby-qltest.yml b/.github/workflows/ruby-qltest.yml
deleted file mode 100644
index e178a5dfb6e..00000000000
--- a/.github/workflows/ruby-qltest.yml
+++ /dev/null
@@ -1,73 +0,0 @@
-name: "Ruby: Run QL Tests"
-
-on:
- push:
- paths:
- - "ruby/**"
- - "shared/**"
- - .github/workflows/ruby-build.yml
- - .github/actions/fetch-codeql/action.yml
- - codeql-workspace.yml
- branches:
- - main
- - "rc/*"
- pull_request:
- paths:
- - "ruby/**"
- - "shared/**"
- - .github/workflows/ruby-qltest.yml
- - .github/actions/fetch-codeql/action.yml
- - codeql-workspace.yml
- branches:
- - main
- - "rc/*"
-
-env:
- CARGO_TERM_COLOR: always
-
-defaults:
- run:
- working-directory: ruby
-
-permissions:
- contents: read
-
-jobs:
- qlupgrade:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v5
- - uses: ./.github/actions/fetch-codeql
- - name: Check DB upgrade scripts
- run: |
- echo >empty.trap
- codeql dataset import -S ql/lib/upgrades/initial/ruby.dbscheme testdb empty.trap
- codeql dataset upgrade testdb --additional-packs ql/lib
- diff -q testdb/ruby.dbscheme ql/lib/ruby.dbscheme
- - name: Check DB downgrade scripts
- run: |
- echo >empty.trap
- rm -rf testdb; codeql dataset import -S ql/lib/ruby.dbscheme testdb empty.trap
- codeql resolve upgrades --format=lines --allow-downgrades --additional-packs downgrades \
- --dbscheme=ql/lib/ruby.dbscheme --target-dbscheme=downgrades/initial/ruby.dbscheme |
- xargs codeql execute upgrades testdb
- diff -q testdb/ruby.dbscheme downgrades/initial/ruby.dbscheme
- qltest:
- if: github.repository_owner == 'github'
- runs-on: ubuntu-latest-xl
- strategy:
- fail-fast: false
- steps:
- - uses: actions/checkout@v5
- - uses: ./.github/actions/fetch-codeql
- - uses: ./ruby/actions/create-extractor-pack
- - name: Cache compilation cache
- id: query-cache
- uses: ./.github/actions/cache-query-compilation
- with:
- key: ruby-qltest
- - name: Run QL tests
- run: |
- codeql test run --threads=0 --ram 50000 --search-path "${{ github.workspace }}" --check-databases --check-diff-informed --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:
- GITHUB_TOKEN: ${{ github.token }}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index e8eed93499f..0f2906dab31 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -7,9 +7,9 @@ repos:
rev: v3.2.0
hooks:
- id: trailing-whitespace
- exclude: /test/.*$(? bar.md\n | .github/workflows/artifactpoisoning71.yml:9:9:16:6 | Uses Step | .github/workflows/artifactpoisoning71.yml:17:14:18:40 | sed -f config foo.md > bar.md\n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning71.yml:17:14:18:40 | sed -f config foo.md > bar.md\n | sed -f config foo.md > bar.md\n | .github/workflows/artifactpoisoning71.yml:4:5:4:16 | workflow_run | workflow_run |
-| .github/workflows/artifactpoisoning81.yml:31:14:31:27 | python test.py | .github/workflows/artifactpoisoning81.yml:28:9:31:6 | Uses Step | .github/workflows/artifactpoisoning81.yml:31:14:31:27 | python test.py | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning81.yml:31:14:31:27 | python test.py | python test.py | .github/workflows/artifactpoisoning81.yml:3:5:3:23 | pull_request_target | pull_request_target |
-| .github/workflows/artifactpoisoning92.yml:28:9:29:6 | Uses Step | .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/workflows/artifactpoisoning92.yml:28:9:29:6 | Uses Step | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning92.yml:28:9:29:6 | Uses Step | Uses Step | .github/workflows/artifactpoisoning92.yml:3:3:3:14 | workflow_run | workflow_run |
-| .github/workflows/artifactpoisoning92.yml:29:14:29:26 | make snapshot | .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/workflows/artifactpoisoning92.yml:29:14:29:26 | make snapshot | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning92.yml:29:14:29:26 | make snapshot | make snapshot | .github/workflows/artifactpoisoning92.yml:3:3:3:14 | workflow_run | workflow_run |
-| .github/workflows/artifactpoisoning96.yml:18:14:18:24 | npm install | .github/workflows/artifactpoisoning96.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning96.yml:18:14:18:24 | npm install | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning96.yml:18:14:18:24 | npm install | npm install | .github/workflows/artifactpoisoning96.yml:2:3:2:14 | workflow_run | workflow_run |
-| .github/workflows/artifactpoisoning101.yml:17:14:19:59 | PR_NUMBER=$(./get_pull_request_number.sh pr_number.txt)\necho "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT \n | .github/workflows/artifactpoisoning101.yml:10:9:16:6 | Uses Step | .github/workflows/artifactpoisoning101.yml:17:14:19:59 | PR_NUMBER=$(./get_pull_request_number.sh pr_number.txt)\necho "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT \n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning101.yml:17:14:19:59 | PR_NUMBER=$(./get_pull_request_number.sh pr_number.txt)\necho "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT \n | PR_NUMBER=$(./get_pull_request_number.sh pr_number.txt)\necho "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT \n | .github/workflows/artifactpoisoning101.yml:4:3:4:21 | pull_request_target | pull_request_target |
-| .github/workflows/test18.yml:36:15:40:58 | Uses Step | .github/workflows/test18.yml:12:15:33:12 | Uses Step | .github/workflows/test18.yml:36:15:40:58 | Uses Step | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/test18.yml:36:15:40:58 | Uses Step | Uses Step | .github/workflows/test18.yml:3:5:3:16 | workflow_run | workflow_run |
-| .github/workflows/test25.yml:39:14:40:45 | ./gradlew buildScanPublishPrevious\n | .github/workflows/test25.yml:22:9:32:6 | Uses Step: downloadBuildScan | .github/workflows/test25.yml:39:14:40:45 | ./gradlew buildScanPublishPrevious\n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/test25.yml:39:14:40:45 | ./gradlew buildScanPublishPrevious\n | ./gradlew buildScanPublishPrevious\n | .github/workflows/test25.yml:2:3:2:14 | workflow_run | workflow_run |
+| .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/workflows/artifactpoisoning92.yml:28:9:29:6 | Uses Step | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning92.yml:3:3:3:14 | workflow_run | workflow_run |
+| .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/workflows/artifactpoisoning92.yml:29:14:29:26 | make snapshot | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning92.yml:3:3:3:14 | workflow_run | workflow_run |
+| .github/workflows/artifactpoisoning11.yml:13:9:32:6 | Uses Step | .github/workflows/artifactpoisoning11.yml:13:9:32:6 | Uses Step | .github/workflows/artifactpoisoning11.yml:38:11:38:77 | ./sonarcloud-data/x.py build -j$(nproc) --compiler gcc --skip-build | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning11.yml:4:3:4:14 | workflow_run | workflow_run |
+| .github/workflows/artifactpoisoning12.yml:13:9:32:6 | Uses Step | .github/workflows/artifactpoisoning12.yml:13:9:32:6 | Uses Step | .github/workflows/artifactpoisoning12.yml:38:11:38:25 | python foo/x.py | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning12.yml:4:3:4:14 | workflow_run | workflow_run |
+| .github/workflows/artifactpoisoning21.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning21.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning21.yml:19:14:20:21 | sh foo/cmd\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning21.yml:4:3:4:14 | workflow_run | workflow_run |
+| .github/workflows/artifactpoisoning22.yml:13:9:17:6 | Uses Step | .github/workflows/artifactpoisoning22.yml:13:9:17:6 | Uses Step | .github/workflows/artifactpoisoning22.yml:18:14:18:19 | sh cmd | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning22.yml:4:3:4:14 | workflow_run | workflow_run |
+| .github/workflows/artifactpoisoning31.yml:13:9:15:6 | Run Step | .github/workflows/artifactpoisoning31.yml:13:9:15:6 | Run Step | .github/workflows/artifactpoisoning31.yml:19:14:19:22 | ./foo/cmd | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning31.yml:4:3:4:14 | workflow_run | workflow_run |
+| .github/workflows/artifactpoisoning32.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning32.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning32.yml:17:14:18:20 | ./bar/cmd\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning32.yml:4:3:4:14 | workflow_run | workflow_run |
+| .github/workflows/artifactpoisoning33.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning33.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning33.yml:17:14:18:20 | ./bar/cmd\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning33.yml:4:3:4:14 | workflow_run | workflow_run |
+| .github/workflows/artifactpoisoning34.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning34.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning34.yml:20:14:22:23 | npm install\nnpm run lint\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning34.yml:4:3:4:14 | workflow_run | workflow_run |
+| .github/workflows/artifactpoisoning41.yml:13:9:21:6 | Run Step | .github/workflows/artifactpoisoning41.yml:13:9:21:6 | Run Step | .github/workflows/artifactpoisoning41.yml:22:14:22:22 | ./foo/cmd | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning41.yml:4:3:4:14 | workflow_run | workflow_run |
+| .github/workflows/artifactpoisoning42.yml:13:9:21:6 | Run Step | .github/workflows/artifactpoisoning42.yml:13:9:21:6 | Run Step | .github/workflows/artifactpoisoning42.yml:22:14:22:18 | ./cmd | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning42.yml:4:3:4:14 | workflow_run | workflow_run |
+| .github/workflows/artifactpoisoning71.yml:9:9:16:6 | Uses Step | .github/workflows/artifactpoisoning71.yml:9:9:16:6 | Uses Step | .github/workflows/artifactpoisoning71.yml:17:14:18:40 | sed -f config foo.md > bar.md\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning71.yml:4:5:4:16 | workflow_run | workflow_run |
+| .github/workflows/artifactpoisoning81.yml:28:9:31:6 | Uses Step | .github/workflows/artifactpoisoning81.yml:28:9:31:6 | Uses Step | .github/workflows/artifactpoisoning81.yml:31:14:31:27 | python test.py | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning81.yml:3:5:3:23 | pull_request_target | pull_request_target |
+| .github/workflows/artifactpoisoning96.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning96.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning96.yml:18:14:18:24 | npm install | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning96.yml:2:3:2:14 | workflow_run | workflow_run |
+| .github/workflows/artifactpoisoning101.yml:10:9:16:6 | Uses Step | .github/workflows/artifactpoisoning101.yml:10:9:16:6 | Uses Step | .github/workflows/artifactpoisoning101.yml:17:14:19:59 | PR_NUMBER=$(./get_pull_request_number.sh pr_number.txt)\necho "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT \n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning101.yml:4:3:4:21 | pull_request_target | pull_request_target |
+| .github/workflows/test18.yml:12:15:33:12 | Uses Step | .github/workflows/test18.yml:12:15:33:12 | Uses Step | .github/workflows/test18.yml:36:15:40:58 | Uses Step | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/test18.yml:3:5:3:16 | workflow_run | workflow_run |
+| .github/workflows/test25.yml:22:9:32:6 | Uses Step: downloadBuildScan | .github/workflows/test25.yml:22:9:32:6 | Uses Step: downloadBuildScan | .github/workflows/test25.yml:39:14:40:45 | ./gradlew buildScanPublishPrevious\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/test25.yml:2:3:2:14 | workflow_run | workflow_run |
diff --git a/config/add-overlay-annotations.py b/config/add-overlay-annotations.py
index 0a30eee5799..4fbd9a2b7fc 100644
--- a/config/add-overlay-annotations.py
+++ b/config/add-overlay-annotations.py
@@ -199,6 +199,7 @@ def annotate_as_appropriate(filename, lines):
# as overlay[local?]. It is not clear that these heuristics are exactly what we want,
# but they seem to work well enough for now (as determined by speed and accuracy numbers).
if (filename.endswith("Test.qll") or
+ re.search(r"go/ql/lib/semmle/go/security/[^/]+[.]qll$", filename.replace(os.sep, "/")) or
((filename.endswith("Query.qll") or filename.endswith("Config.qll")) and
any("implements DataFlow::ConfigSig" in line for line in lines))):
return None
diff --git a/config/identical-files.json b/config/identical-files.json
index bdaf567ae17..8a5c00a49f8 100644
--- a/config/identical-files.json
+++ b/config/identical-files.json
@@ -172,10 +172,6 @@
"cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/reachability/PrintDominance.qll",
"cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll"
],
- "C# ControlFlowReachability": [
- "csharp/ql/lib/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll",
- "csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ControlFlowReachability.qll"
- ],
"C++ ExternalAPIs": [
"cpp/ql/src/Security/CWE/CWE-020/ExternalAPIs.qll",
"cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIs.qll"
diff --git a/cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/in_trap.ql b/cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/in_trap.ql
new file mode 100644
index 00000000000..5ea4f67776b
--- /dev/null
+++ b/cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/in_trap.ql
@@ -0,0 +1,21 @@
+class Element extends @element {
+ string toString() { none() }
+}
+
+class Trap extends @trap {
+ string toString() { none() }
+}
+
+class Tag extends @tag {
+ string toString() { none() }
+}
+
+from Element e, Trap trap
+where
+ in_trap_or_tag(e, trap)
+ or
+ exists(Tag tag |
+ in_trap_or_tag(e, tag) and
+ trap_uses_tag(trap, tag)
+ )
+select e, trap
diff --git a/cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/old.dbscheme b/cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/old.dbscheme
new file mode 100644
index 00000000000..770002bb023
--- /dev/null
+++ b/cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/old.dbscheme
@@ -0,0 +1,2545 @@
+
+/*- Compilations -*/
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ /**
+ * An invocation of the compiler. Note that more than one file may
+ * be compiled per invocation. For example, this command compiles
+ * three source files:
+ *
+ * gcc -c f1.c f2.c f3.c
+ */
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | *path to extractor*
+ * 1 | `--mimic`
+ * 2 | `/usr/bin/gcc`
+ * 3 | `-c`
+ * 4 | f1.c
+ * 5 | f2.c
+ * 6 | f3.c
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The expanded arguments that were passed to the extractor for a
+ * compiler invocation. This is similar to `compilation_args`, but
+ * for a `@someFile` argument, it includes the arguments from that
+ * file, rather than just taking the argument literally.
+ */
+#keyset[id, num]
+compilation_expanded_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * Optionally, record the build mode for each compilation.
+ */
+compilation_build_mode(
+ unique int id : @compilation ref,
+ int mode : int ref
+);
+
+/*
+case @compilation_build_mode.mode of
+ 0 = @build_mode_none
+| 1 = @build_mode_manual
+| 2 = @build_mode_auto
+;
+*/
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.c
+ * 1 | f2.c
+ * 2 | f3.c
+ *
+ * Note that even if those files `#include` headers, those headers
+ * do not appear as rows.
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+/*- External data -*/
+
+/**
+ * External data, loaded from CSV files during snapshot creation. See
+ * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data)
+ * for more information.
+ */
+externalData(
+ int id : @externalDataElement,
+ string path : string ref,
+ int column: int ref,
+ string value : string ref
+);
+
+/*- Source location prefix -*/
+
+/**
+ * The source location of the snapshot.
+ */
+sourceLocationPrefix(string prefix : string ref);
+
+/*- Files and folders -*/
+
+/**
+ * The location of an element.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref
+);
+
+files(
+ unique int id: @file,
+ string name: string ref
+);
+
+folders(
+ unique int id: @folder,
+ string name: string ref
+);
+
+@container = @file | @folder
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref
+);
+
+/*- Lines of code -*/
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref
+);
+
+/*- Diagnostic messages -*/
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location_default ref
+);
+
+/*- C++ dbscheme -*/
+
+extractor_version(
+ string codeql_version: string ref,
+ string frontend_version: string ref
+)
+
+/**
+ * Gives the TRAP filename that `trap` is associated with.
+ * For debugging only.
+ */
+trap_filename(
+ int trap: @trap,
+ string filename: string ref
+);
+
+/**
+ * Gives the tag name for `tag`.
+ * For debugging only.
+ */
+tag_name(
+ int tag: @tag,
+ string name: string ref
+);
+
+@trap_or_tag = @tag | @trap;
+
+/**
+ * Gives the name for the source file.
+ */
+source_file_name(
+ int sf: @source_file,
+ string name: string ref
+);
+
+/**
+ * In `build-mode: none` overlay mode, indicates that `source_file`
+ * (`/path/to/foo.c`) uses the TRAP file `trap_file`; i.e. it is the
+ * TRAP file corresponding to `foo.c`, something it transitively
+ * includes, or a template instantiation it transitively uses.
+ */
+source_file_uses_trap(
+ int source_file: @source_file ref,
+ int trap_file: @trap ref
+);
+
+/**
+ * In `build-mode: none` overlay mode, indicates that the TRAP file
+ * `trap_file` uses tag `tag`.
+ */
+trap_uses_tag(
+ int trap_file: @trap ref,
+ int tag: @tag ref
+);
+
+/**
+ * Holds if there is a definition of `element` in TRAP file or tag `t`.
+ */
+in_trap_or_tag(
+ int element: @element ref,
+ int t: @trap_or_tag ref
+);
+
+pch_uses(
+ int pch: @pch ref,
+ int compilation: @compilation ref,
+ int id: @file ref
+)
+
+#keyset[pch, compilation]
+pch_creations(
+ int pch: @pch,
+ int compilation: @compilation ref,
+ int from: @file ref
+)
+
+/** An element for which line-count information is available. */
+@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable;
+
+fileannotations(
+ int id: @file ref,
+ int kind: int ref,
+ string name: string ref,
+ string value: string ref
+);
+
+inmacroexpansion(
+ int id: @element ref,
+ int inv: @macroinvocation ref
+);
+
+affectedbymacroexpansion(
+ int id: @element ref,
+ int inv: @macroinvocation ref
+);
+
+case @macroinvocation.kind of
+ 1 = @macro_expansion
+| 2 = @other_macro_reference
+;
+
+macroinvocations(
+ unique int id: @macroinvocation,
+ int macro_id: @ppd_define ref,
+ int location: @location_default ref,
+ int kind: int ref
+);
+
+macroparent(
+ unique int id: @macroinvocation ref,
+ int parent_id: @macroinvocation ref
+);
+
+// a macroinvocation may be part of another location
+// the way to find a constant expression that uses a macro
+// is thus to find a constant expression that has a location
+// to which a macro invocation is bound
+macrolocationbind(
+ int id: @macroinvocation ref,
+ int location: @location_default ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_unexpanded(
+ int invocation: @macroinvocation ref,
+ int argument_index: int ref,
+ string text: string ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_expanded(
+ int invocation: @macroinvocation ref,
+ int argument_index: int ref,
+ string text: string ref
+);
+
+case @function.kind of
+ 0 = @unknown_function
+| 1 = @normal_function
+| 2 = @constructor
+| 3 = @destructor
+| 4 = @conversion_function
+| 5 = @operator
+// ... 6 = @builtin_function deprecated // GCC built-in functions, e.g. __builtin___memcpy_chk
+| 7 = @user_defined_literal
+| 8 = @deduction_guide
+;
+
+functions(
+ unique int id: @function,
+ string name: string ref,
+ int kind: int ref
+);
+
+builtin_functions(
+ int id: @function ref
+)
+
+function_entry_point(
+ int id: @function ref,
+ unique int entry_point: @stmt ref
+);
+
+function_return_type(
+ int id: @function ref,
+ int return_type: @type ref
+);
+
+/**
+ * If `function` is a coroutine, then this gives the `std::experimental::resumable_traits`
+ * instance associated with it, and the variables representing the `handle` and `promise`
+ * for it.
+ */
+coroutine(
+ unique int function: @function ref,
+ int traits: @type ref
+);
+
+/*
+case @coroutine_placeholder_variable.kind of
+ 1 = @handle
+| 2 = @promise
+| 3 = @init_await_resume
+;
+*/
+
+coroutine_placeholder_variable(
+ unique int placeholder_variable: @variable ref,
+ int kind: int ref,
+ int function: @function ref
+)
+
+/** The `new` function used for allocating the coroutine state, if any. */
+coroutine_new(
+ unique int function: @function ref,
+ int new: @function ref
+);
+
+/** The `delete` function used for deallocating the coroutine state, if any. */
+coroutine_delete(
+ unique int function: @function ref,
+ int delete: @function ref
+);
+
+purefunctions(unique int id: @function ref);
+
+function_deleted(unique int id: @function ref);
+
+function_defaulted(unique int id: @function ref);
+
+function_prototyped(unique int id: @function ref)
+
+deduction_guide_for_class(
+ int id: @function ref,
+ int class_template: @usertype ref
+)
+
+member_function_this_type(
+ unique int id: @function ref,
+ int this_type: @type ref
+);
+
+#keyset[id, type_id]
+fun_decls(
+ int id: @fun_decl,
+ int function: @function ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+fun_def(unique int id: @fun_decl ref);
+fun_specialized(unique int id: @fun_decl ref);
+fun_implicit(unique int id: @fun_decl ref);
+fun_decl_specifiers(
+ int id: @fun_decl ref,
+ string name: string ref
+)
+#keyset[fun_decl, index]
+fun_decl_throws(
+ int fun_decl: @fun_decl ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+/* an empty throw specification is different from none */
+fun_decl_empty_throws(unique int fun_decl: @fun_decl ref);
+fun_decl_noexcept(
+ int fun_decl: @fun_decl ref,
+ int constant: @expr ref
+);
+fun_decl_empty_noexcept(int fun_decl: @fun_decl ref);
+fun_decl_typedef_type(
+ unique int fun_decl: @fun_decl ref,
+ int typedeftype_id: @usertype ref
+);
+
+/*
+case @fun_requires.kind of
+ 1 = @template_attached
+| 2 = @function_attached
+;
+*/
+
+fun_requires(
+ int id: @fun_decl ref,
+ int kind: int ref,
+ int constraint: @expr ref
+);
+
+param_decl_bind(
+ unique int id: @var_decl ref,
+ int index: int ref,
+ int fun_decl: @fun_decl ref
+);
+
+#keyset[id, type_id]
+var_decls(
+ int id: @var_decl,
+ int variable: @variable ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+var_def(unique int id: @var_decl ref);
+var_specialized(int id: @var_decl ref);
+var_decl_specifiers(
+ int id: @var_decl ref,
+ string name: string ref
+)
+is_structured_binding(unique int id: @variable ref);
+var_requires(
+ int id: @var_decl ref,
+ int constraint: @expr ref
+);
+
+type_decls(
+ unique int id: @type_decl,
+ int type_id: @type ref,
+ int location: @location_default ref
+);
+type_def(unique int id: @type_decl ref);
+type_decl_top(
+ unique int type_decl: @type_decl ref
+);
+type_requires(
+ int id: @type_decl ref,
+ int constraint: @expr ref
+);
+
+namespace_decls(
+ unique int id: @namespace_decl,
+ int namespace_id: @namespace ref,
+ int location: @location_default ref,
+ int bodylocation: @location_default ref
+);
+
+case @using.kind of
+ 1 = @using_declaration
+| 2 = @using_directive
+| 3 = @using_enum_declaration
+;
+
+usings(
+ unique int id: @using,
+ int element_id: @element ref,
+ int location: @location_default ref,
+ int kind: int ref
+);
+
+/** The element which contains the `using` declaration. */
+using_container(
+ int parent: @element ref,
+ int child: @using ref
+);
+
+static_asserts(
+ unique int id: @static_assert,
+ int condition : @expr ref,
+ string message : string ref,
+ int location: @location_default ref,
+ int enclosing : @element ref
+);
+
+// each function has an ordered list of parameters
+#keyset[id, type_id]
+#keyset[function, index, type_id]
+params(
+ int id: @parameter,
+ int function: @parameterized_element ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+
+overrides(
+ int new: @function ref,
+ int old: @function ref
+);
+
+#keyset[id, type_id]
+membervariables(
+ int id: @membervariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+#keyset[id, type_id]
+globalvariables(
+ int id: @globalvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+#keyset[id, type_id]
+localvariables(
+ int id: @localvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+autoderivation(
+ unique int var: @variable ref,
+ int derivation_type: @type ref
+);
+
+orphaned_variables(
+ int var: @localvariable ref,
+ int function: @function ref
+)
+
+enumconstants(
+ unique int id: @enumconstant,
+ int parent: @usertype ref,
+ int index: int ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+
+@variable = @localscopevariable | @globalvariable | @membervariable;
+
+@localscopevariable = @localvariable | @parameter;
+
+/**
+ * Built-in types are the fundamental types, e.g., integral, floating, and void.
+ */
+case @builtintype.kind of
+ 1 = @errortype
+| 2 = @unknowntype
+| 3 = @void
+| 4 = @boolean
+| 5 = @char
+| 6 = @unsigned_char
+| 7 = @signed_char
+| 8 = @short
+| 9 = @unsigned_short
+| 10 = @signed_short
+| 11 = @int
+| 12 = @unsigned_int
+| 13 = @signed_int
+| 14 = @long
+| 15 = @unsigned_long
+| 16 = @signed_long
+| 17 = @long_long
+| 18 = @unsigned_long_long
+| 19 = @signed_long_long
+// ... 20 Microsoft-specific __int8
+// ... 21 Microsoft-specific __int16
+// ... 22 Microsoft-specific __int32
+// ... 23 Microsoft-specific __int64
+| 24 = @float
+| 25 = @double
+| 26 = @long_double
+| 27 = @complex_float // C99-specific _Complex float
+| 28 = @complex_double // C99-specific _Complex double
+| 29 = @complex_long_double // C99-specific _Complex long double
+| 30 = @imaginary_float // C99-specific _Imaginary float
+| 31 = @imaginary_double // C99-specific _Imaginary double
+| 32 = @imaginary_long_double // C99-specific _Imaginary long double
+| 33 = @wchar_t // Microsoft-specific
+| 34 = @decltype_nullptr // C++11
+| 35 = @int128 // __int128
+| 36 = @unsigned_int128 // unsigned __int128
+| 37 = @signed_int128 // signed __int128
+| 38 = @float128 // __float128
+| 39 = @complex_float128 // _Complex __float128
+// ... 40 _Decimal32
+// ... 41 _Decimal64
+// ... 42 _Decimal128
+| 43 = @char16_t
+| 44 = @char32_t
+| 45 = @std_float32 // _Float32
+| 46 = @float32x // _Float32x
+| 47 = @std_float64 // _Float64
+| 48 = @float64x // _Float64x
+| 49 = @std_float128 // _Float128
+// ... 50 _Float128x
+| 51 = @char8_t
+| 52 = @float16 // _Float16
+| 53 = @complex_float16 // _Complex _Float16
+| 54 = @fp16 // __fp16
+| 55 = @std_bfloat16 // __bf16
+| 56 = @std_float16 // std::float16_t
+| 57 = @complex_std_float32 // _Complex _Float32
+| 58 = @complex_float32x // _Complex _Float32x
+| 59 = @complex_std_float64 // _Complex _Float64
+| 60 = @complex_float64x // _Complex _Float64x
+| 61 = @complex_std_float128 // _Complex _Float128
+| 62 = @mfp8 // __mfp8
+| 63 = @scalable_vector_count // __SVCount_t
+| 64 = @complex_fp16 // _Complex __fp16
+| 65 = @complex_std_bfloat16 // _Complex __bf16
+| 66 = @complex_std_float16 // _Complex std::float16_t
+;
+
+builtintypes(
+ unique int id: @builtintype,
+ string name: string ref,
+ int kind: int ref,
+ int size: int ref,
+ int sign: int ref,
+ int alignment: int ref
+);
+
+/**
+ * Derived types are types that are directly derived from existing types and
+ * point to, refer to, transform type data to return a new type.
+ */
+case @derivedtype.kind of
+ 1 = @pointer
+| 2 = @reference
+| 3 = @type_with_specifiers
+| 4 = @array
+| 5 = @gnu_vector
+| 6 = @routineptr
+| 7 = @routinereference
+| 8 = @rvalue_reference // C++11
+// ... 9 type_conforming_to_protocols deprecated
+| 10 = @block
+| 11 = @scalable_vector // Arm SVE
+;
+
+derivedtypes(
+ unique int id: @derivedtype,
+ string name: string ref,
+ int kind: int ref,
+ int type_id: @type ref
+);
+
+pointerishsize(unique int id: @derivedtype ref,
+ int size: int ref,
+ int alignment: int ref);
+
+arraysizes(
+ unique int id: @derivedtype ref,
+ int num_elements: int ref,
+ int bytesize: int ref,
+ int alignment: int ref
+);
+
+tupleelements(
+ unique int id: @derivedtype ref,
+ int num_elements: int ref
+);
+
+typedefbase(
+ unique int id: @usertype ref,
+ int type_id: @type ref
+);
+
+/**
+ * An instance of the C++11 `decltype` operator or C23 `typeof`/`typeof_unqual`
+ * operator taking an expression as its argument. For example:
+ * ```
+ * int a;
+ * decltype(1+a) b;
+ * typeof(1+a) c;
+ * ```
+ * Here `expr` is `1+a`.
+ *
+ * Sometimes an additional pair of parentheses around the expression
+ * changes the semantics of the decltype, e.g.
+ * ```
+ * struct A { double x; };
+ * const A* a = new A();
+ * decltype( a->x ); // type is double
+ * decltype((a->x)); // type is const double&
+ * ```
+ * (Please consult the C++11 standard for more details).
+ * `parentheses_would_change_meaning` is `true` iff that is the case.
+ */
+
+/*
+case @decltype.kind of
+| 0 = @decltype
+| 1 = @typeof // The frontend does not differentiate between typeof and typeof_unqual
+;
+*/
+
+#keyset[id, expr]
+decltypes(
+ int id: @decltype,
+ int expr: @expr ref,
+ int kind: int ref,
+ int base_type: @type ref,
+ boolean parentheses_would_change_meaning: boolean ref
+);
+
+case @type_operator.kind of
+ 0 = @typeof // The frontend does not differentiate between typeof and typeof_unqual
+| 1 = @underlying_type
+| 2 = @bases
+| 3 = @direct_bases
+| 4 = @add_lvalue_reference
+| 5 = @add_pointer
+| 6 = @add_rvalue_reference
+| 7 = @decay
+| 8 = @make_signed
+| 9 = @make_unsigned
+| 10 = @remove_all_extents
+| 11 = @remove_const
+| 12 = @remove_cv
+| 13 = @remove_cvref
+| 14 = @remove_extent
+| 15 = @remove_pointer
+| 16 = @remove_reference_t
+| 17 = @remove_restrict
+| 18 = @remove_volatile
+| 19 = @remove_reference
+;
+
+type_operators(
+ unique int id: @type_operator,
+ int arg_type: @type ref,
+ int kind: int ref,
+ int base_type: @type ref
+)
+
+case @usertype.kind of
+ 0 = @unknown_usertype
+| 1 = @struct
+| 2 = @class
+| 3 = @union
+| 4 = @enum
+// ... 5 = @typedef deprecated // classic C: typedef typedef type name
+// ... 6 = @template deprecated
+| 7 = @template_parameter
+| 8 = @template_template_parameter
+| 9 = @proxy_class // a proxy class associated with a template parameter
+// ... 10 objc_class deprecated
+// ... 11 objc_protocol deprecated
+// ... 12 objc_category deprecated
+| 13 = @scoped_enum
+// ... 14 = @using_alias deprecated // a using name = type style typedef
+| 15 = @template_struct
+| 16 = @template_class
+| 17 = @template_union
+| 18 = @alias
+;
+
+usertypes(
+ unique int id: @usertype,
+ string name: string ref,
+ int kind: int ref
+);
+
+usertypesize(
+ unique int id: @usertype ref,
+ int size: int ref,
+ int alignment: int ref
+);
+
+usertype_final(unique int id: @usertype ref);
+
+usertype_uuid(
+ unique int id: @usertype ref,
+ string uuid: string ref
+);
+
+/*
+case @usertype.alias_kind of
+| 0 = @typedef
+| 1 = @alias
+*/
+
+usertype_alias_kind(
+ int id: @usertype ref,
+ int alias_kind: int ref
+)
+
+nontype_template_parameters(
+ int id: @expr ref
+);
+
+type_template_type_constraint(
+ int id: @usertype ref,
+ int constraint: @expr ref
+);
+
+mangled_name(
+ unique int id: @declaration ref,
+ int mangled_name : @mangledname,
+ boolean is_complete: boolean ref
+);
+
+is_pod_class(unique int id: @usertype ref);
+is_standard_layout_class(unique int id: @usertype ref);
+
+is_complete(unique int id: @usertype ref);
+
+is_class_template(unique int id: @usertype ref);
+class_instantiation(
+ int to: @usertype ref,
+ int from: @usertype ref
+);
+class_template_argument(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+class_template_argument_value(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+@user_or_decltype = @usertype | @decltype;
+
+is_proxy_class_for(
+ unique int id: @usertype ref,
+ int templ_param_id: @user_or_decltype ref
+);
+
+type_mentions(
+ unique int id: @type_mention,
+ int type_id: @type ref,
+ int location: @location_default ref,
+ // a_symbol_reference_kind from the frontend.
+ int kind: int ref
+);
+
+is_function_template(unique int id: @function ref);
+function_instantiation(
+ unique int to: @function ref,
+ int from: @function ref
+);
+function_template_argument(
+ int function_id: @function ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+function_template_argument_value(
+ int function_id: @function ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+is_variable_template(unique int id: @variable ref);
+variable_instantiation(
+ unique int to: @variable ref,
+ int from: @variable ref
+);
+variable_template_argument(
+ int variable_id: @variable ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+variable_template_argument_value(
+ int variable_id: @variable ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+template_template_instantiation(
+ int to: @usertype ref,
+ int from: @usertype ref
+);
+template_template_argument(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+template_template_argument_value(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+@concept = @concept_template | @concept_id;
+
+concept_templates(
+ unique int concept_id: @concept_template,
+ string name: string ref,
+ int location: @location_default ref
+);
+concept_instantiation(
+ unique int to: @concept_id ref,
+ int from: @concept_template ref
+);
+is_type_constraint(int concept_id: @concept_id ref);
+concept_template_argument(
+ int concept_id: @concept ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+concept_template_argument_value(
+ int concept_id: @concept ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+routinetypes(
+ unique int id: @routinetype,
+ int return_type: @type ref
+);
+
+routinetypeargs(
+ int routine: @routinetype ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+
+ptrtomembers(
+ unique int id: @ptrtomember,
+ int type_id: @type ref,
+ int class_id: @type ref
+);
+
+/*
+ specifiers for types, functions, and variables
+
+ "public",
+ "protected",
+ "private",
+
+ "const",
+ "volatile",
+ "static",
+
+ "pure",
+ "virtual",
+ "sealed", // Microsoft
+ "__interface", // Microsoft
+ "inline",
+ "explicit",
+
+ "near", // near far extension
+ "far", // near far extension
+ "__ptr32", // Microsoft
+ "__ptr64", // Microsoft
+ "__sptr", // Microsoft
+ "__uptr", // Microsoft
+ "dllimport", // Microsoft
+ "dllexport", // Microsoft
+ "thread", // Microsoft
+ "naked", // Microsoft
+ "microsoft_inline", // Microsoft
+ "forceinline", // Microsoft
+ "selectany", // Microsoft
+ "nothrow", // Microsoft
+ "novtable", // Microsoft
+ "noreturn", // Microsoft
+ "noinline", // Microsoft
+ "noalias", // Microsoft
+ "restrict", // Microsoft
+*/
+
+specifiers(
+ unique int id: @specifier,
+ unique string str: string ref
+);
+
+typespecifiers(
+ int type_id: @type ref,
+ int spec_id: @specifier ref
+);
+
+funspecifiers(
+ int func_id: @function ref,
+ int spec_id: @specifier ref
+);
+
+varspecifiers(
+ int var_id: @accessible ref,
+ int spec_id: @specifier ref
+);
+
+explicit_specifier_exprs(
+ unique int func_id: @function ref,
+ int constant: @expr ref
+)
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ string name: string ref,
+ string name_space: string ref,
+ int location: @location_default ref
+);
+
+case @attribute.kind of
+ 0 = @gnuattribute
+| 1 = @stdattribute
+| 2 = @declspec
+| 3 = @msattribute
+| 4 = @alignas
+// ... 5 @objc_propertyattribute deprecated
+;
+
+attribute_args(
+ unique int id: @attribute_arg,
+ int kind: int ref,
+ int attribute: @attribute ref,
+ int index: int ref,
+ int location: @location_default ref
+);
+
+case @attribute_arg.kind of
+ 0 = @attribute_arg_empty
+| 1 = @attribute_arg_token
+| 2 = @attribute_arg_constant
+| 3 = @attribute_arg_type
+| 4 = @attribute_arg_constant_expr
+| 5 = @attribute_arg_expr
+;
+
+attribute_arg_value(
+ unique int arg: @attribute_arg ref,
+ string value: string ref
+);
+attribute_arg_type(
+ unique int arg: @attribute_arg ref,
+ int type_id: @type ref
+);
+attribute_arg_constant(
+ unique int arg: @attribute_arg ref,
+ int constant: @expr ref
+)
+attribute_arg_expr(
+ unique int arg: @attribute_arg ref,
+ int expr: @expr ref
+)
+attribute_arg_name(
+ unique int arg: @attribute_arg ref,
+ string name: string ref
+);
+
+typeattributes(
+ int type_id: @type ref,
+ int spec_id: @attribute ref
+);
+
+funcattributes(
+ int func_id: @function ref,
+ int spec_id: @attribute ref
+);
+
+varattributes(
+ int var_id: @accessible ref,
+ int spec_id: @attribute ref
+);
+
+namespaceattributes(
+ int namespace_id: @namespace ref,
+ int spec_id: @attribute ref
+);
+
+stmtattributes(
+ int stmt_id: @stmt ref,
+ int spec_id: @attribute ref
+);
+
+@type = @builtintype
+ | @derivedtype
+ | @usertype
+ | @routinetype
+ | @ptrtomember
+ | @decltype
+ | @type_operator;
+
+unspecifiedtype(
+ unique int type_id: @type ref,
+ int unspecified_type_id: @type ref
+);
+
+member(
+ int parent: @type ref,
+ int index: int ref,
+ int child: @member ref
+);
+
+@enclosingfunction_child = @usertype | @variable | @namespace
+
+enclosingfunction(
+ unique int child: @enclosingfunction_child ref,
+ int parent: @function ref
+);
+
+derivations(
+ unique int derivation: @derivation,
+ int sub: @type ref,
+ int index: int ref,
+ int super: @type ref,
+ int location: @location_default ref
+);
+
+derspecifiers(
+ int der_id: @derivation ref,
+ int spec_id: @specifier ref
+);
+
+/**
+ * Contains the byte offset of the base class subobject within the derived
+ * class. Only holds for non-virtual base classes, but see table
+ * `virtual_base_offsets` for offsets of virtual base class subobjects.
+ */
+direct_base_offsets(
+ unique int der_id: @derivation ref,
+ int offset: int ref
+);
+
+/**
+ * Contains the byte offset of the virtual base class subobject for class
+ * `super` within a most-derived object of class `sub`. `super` can be either a
+ * direct or indirect base class.
+ */
+#keyset[sub, super]
+virtual_base_offsets(
+ int sub: @usertype ref,
+ int super: @usertype ref,
+ int offset: int ref
+);
+
+frienddecls(
+ unique int id: @frienddecl,
+ int type_id: @type ref,
+ int decl_id: @declaration ref,
+ int location: @location_default ref
+);
+
+@declaredtype = @usertype ;
+
+@declaration = @function
+ | @declaredtype
+ | @variable
+ | @enumconstant
+ | @frienddecl
+ | @concept_template;
+
+@member = @membervariable
+ | @function
+ | @declaredtype
+ | @enumconstant;
+
+@locatable = @diagnostic
+ | @declaration
+ | @ppd_include
+ | @ppd_define
+ | @macroinvocation
+ /*| @funcall*/
+ | @xmllocatable
+ | @attribute
+ | @attribute_arg;
+
+@namedscope = @namespace | @usertype;
+
+@element = @locatable
+ | @file
+ | @folder
+ | @specifier
+ | @type
+ | @expr
+ | @namespace
+ | @initialiser
+ | @stmt
+ | @derivation
+ | @comment
+ | @preprocdirect
+ | @fun_decl
+ | @var_decl
+ | @type_decl
+ | @namespace_decl
+ | @using
+ | @namequalifier
+ | @specialnamequalifyingelement
+ | @static_assert
+ | @type_mention
+ | @lambdacapture;
+
+@exprparent = @element;
+
+comments(
+ unique int id: @comment,
+ string contents: string ref,
+ int location: @location_default ref
+);
+
+commentbinding(
+ int id: @comment ref,
+ int element: @element ref
+);
+
+exprconv(
+ int converted: @expr ref,
+ unique int conversion: @expr ref
+);
+
+compgenerated(unique int id: @element ref);
+
+/**
+ * `destructor_call` destructs the `i`'th entity that should be
+ * destructed following `element`. Note that entities should be
+ * destructed in reverse construction order, so for a given `element`
+ * these should be called from highest to lowest `i`.
+ */
+#keyset[element, destructor_call]
+#keyset[element, i]
+synthetic_destructor_call(
+ int element: @element ref,
+ int i: int ref,
+ int destructor_call: @routineexpr ref
+);
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref
+);
+
+namespace_inline(
+ unique int id: @namespace ref
+);
+
+namespacembrs(
+ int parentid: @namespace ref,
+ unique int memberid: @namespacembr ref
+);
+
+@namespacembr = @declaration | @namespace;
+
+exprparents(
+ int expr_id: @expr ref,
+ int child_index: int ref,
+ int parent_id: @exprparent ref
+);
+
+expr_isload(unique int expr_id: @expr ref);
+
+@cast = @c_style_cast
+ | @const_cast
+ | @dynamic_cast
+ | @reinterpret_cast
+ | @static_cast
+ ;
+
+/*
+case @conversion.kind of
+ 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast
+| 1 = @bool_conversion // conversion to 'bool'
+| 2 = @base_class_conversion // a derived-to-base conversion
+| 3 = @derived_class_conversion // a base-to-derived conversion
+| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member
+| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member
+| 6 = @glvalue_adjust // an adjustment of the type of a glvalue
+| 7 = @prvalue_adjust // an adjustment of the type of a prvalue
+;
+*/
+/**
+ * Describes the semantics represented by a cast expression. This is largely
+ * independent of the source syntax of the cast, so it is separate from the
+ * regular expression kind.
+ */
+conversionkinds(
+ unique int expr_id: @cast ref,
+ int kind: int ref
+);
+
+@conversion = @cast
+ | @array_to_pointer
+ | @parexpr
+ | @reference_to
+ | @ref_indirect
+ | @temp_init
+ | @c11_generic
+ ;
+
+/*
+case @funbindexpr.kind of
+ 0 = @normal_call // a normal call
+| 1 = @virtual_call // a virtual call
+| 2 = @adl_call // a call whose target is only found by ADL
+;
+*/
+iscall(
+ unique int caller: @funbindexpr ref,
+ int kind: int ref
+);
+
+numtemplatearguments(
+ unique int expr_id: @expr ref,
+ int num: int ref
+);
+
+specialnamequalifyingelements(
+ unique int id: @specialnamequalifyingelement,
+ unique string name: string ref
+);
+
+@namequalifiableelement = @expr | @namequalifier;
+@namequalifyingelement = @namespace
+ | @specialnamequalifyingelement
+ | @usertype
+ | @decltype;
+
+namequalifiers(
+ unique int id: @namequalifier,
+ unique int qualifiableelement: @namequalifiableelement ref,
+ int qualifyingelement: @namequalifyingelement ref,
+ int location: @location_default ref
+);
+
+varbind(
+ int expr: @varbindexpr ref,
+ int var: @accessible ref
+);
+
+funbind(
+ int expr: @funbindexpr ref,
+ int fun: @function ref
+);
+
+@any_new_expr = @new_expr
+ | @new_array_expr;
+
+@new_or_delete_expr = @any_new_expr
+ | @delete_expr
+ | @delete_array_expr;
+
+@prefix_crement_expr = @preincrexpr | @predecrexpr;
+
+@postfix_crement_expr = @postincrexpr | @postdecrexpr;
+
+@increment_expr = @preincrexpr | @postincrexpr;
+
+@decrement_expr = @predecrexpr | @postdecrexpr;
+
+@crement_expr = @increment_expr | @decrement_expr;
+
+@un_arith_op_expr = @arithnegexpr
+ | @unaryplusexpr
+ | @conjugation
+ | @realpartexpr
+ | @imagpartexpr
+ | @crement_expr
+ ;
+
+@un_bitwise_op_expr = @complementexpr;
+
+@un_log_op_expr = @notexpr;
+
+@un_op_expr = @address_of
+ | @indirect
+ | @un_arith_op_expr
+ | @un_bitwise_op_expr
+ | @builtinaddressof
+ | @vec_fill
+ | @un_log_op_expr
+ | @co_await
+ | @co_yield
+ ;
+
+@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr;
+
+@cmp_op_expr = @eq_op_expr | @rel_op_expr;
+
+@eq_op_expr = @eqexpr | @neexpr;
+
+@rel_op_expr = @gtexpr
+ | @ltexpr
+ | @geexpr
+ | @leexpr
+ | @spaceshipexpr
+ ;
+
+@bin_bitwise_op_expr = @lshiftexpr
+ | @rshiftexpr
+ | @andexpr
+ | @orexpr
+ | @xorexpr
+ ;
+
+@p_arith_op_expr = @paddexpr
+ | @psubexpr
+ | @pdiffexpr
+ ;
+
+@bin_arith_op_expr = @addexpr
+ | @subexpr
+ | @mulexpr
+ | @divexpr
+ | @remexpr
+ | @jmulexpr
+ | @jdivexpr
+ | @fjaddexpr
+ | @jfaddexpr
+ | @fjsubexpr
+ | @jfsubexpr
+ | @minexpr
+ | @maxexpr
+ | @p_arith_op_expr
+ ;
+
+@bin_op_expr = @bin_arith_op_expr
+ | @bin_bitwise_op_expr
+ | @cmp_op_expr
+ | @bin_log_op_expr
+ ;
+
+@op_expr = @un_op_expr
+ | @bin_op_expr
+ | @assign_expr
+ | @conditionalexpr
+ ;
+
+@assign_arith_expr = @assignaddexpr
+ | @assignsubexpr
+ | @assignmulexpr
+ | @assigndivexpr
+ | @assignremexpr
+ ;
+
+@assign_bitwise_expr = @assignandexpr
+ | @assignorexpr
+ | @assignxorexpr
+ | @assignlshiftexpr
+ | @assignrshiftexpr
+ ;
+
+@assign_pointer_expr = @assignpaddexpr
+ | @assignpsubexpr
+ ;
+
+@assign_op_expr = @assign_arith_expr
+ | @assign_bitwise_expr
+ | @assign_pointer_expr
+ ;
+
+@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
+
+/*
+ Binary encoding of the allocator form.
+
+ case @allocator.form of
+ 0 = plain
+ | 1 = alignment
+ ;
+*/
+
+/**
+ * The allocator function associated with a `new` or `new[]` expression.
+ * The `form` column specified whether the allocation call contains an alignment
+ * argument.
+ */
+expr_allocator(
+ unique int expr: @any_new_expr ref,
+ int func: @function ref,
+ int form: int ref
+);
+
+/*
+ Binary encoding of the deallocator form.
+
+ case @deallocator.form of
+ 0 = plain
+ | 1 = size
+ | 2 = alignment
+ | 4 = destroying_delete
+ ;
+*/
+
+/**
+ * The deallocator function associated with a `delete`, `delete[]`, `new`, or
+ * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the
+ * one used to free memory if the initialization throws an exception.
+ * The `form` column specifies whether the deallocation call contains a size
+ * argument, and alignment argument, or both.
+ */
+expr_deallocator(
+ unique int expr: @new_or_delete_expr ref,
+ int func: @function ref,
+ int form: int ref
+);
+
+/**
+ * Holds if the `@conditionalexpr` is of the two operand form
+ * `guard ? : false`.
+ */
+expr_cond_two_operand(
+ unique int cond: @conditionalexpr ref
+);
+
+/**
+ * The guard of `@conditionalexpr` `guard ? true : false`
+ */
+expr_cond_guard(
+ unique int cond: @conditionalexpr ref,
+ int guard: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` holds. For the two operand form
+ * `guard ?: false` consider using `expr_cond_guard` instead.
+ */
+expr_cond_true(
+ unique int cond: @conditionalexpr ref,
+ int true: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` does not hold.
+ */
+expr_cond_false(
+ unique int cond: @conditionalexpr ref,
+ int false: @expr ref
+);
+
+/** A string representation of the value. */
+values(
+ unique int id: @value,
+ string str: string ref
+);
+
+/** The actual text in the source code for the value, if any. */
+valuetext(
+ unique int id: @value ref,
+ string text: string ref
+);
+
+valuebind(
+ int val: @value ref,
+ unique int expr: @expr ref
+);
+
+fieldoffsets(
+ unique int id: @variable ref,
+ int byteoffset: int ref,
+ int bitoffset: int ref
+);
+
+bitfield(
+ unique int id: @variable ref,
+ int bits: int ref,
+ int declared_bits: int ref
+);
+
+/* TODO
+memberprefix(
+ int member: @expr ref,
+ int prefix: @expr ref
+);
+*/
+
+/*
+ kind(1) = mbrcallexpr
+ kind(2) = mbrptrcallexpr
+ kind(3) = mbrptrmbrcallexpr
+ kind(4) = ptrmbrptrmbrcallexpr
+ kind(5) = mbrreadexpr // x.y
+ kind(6) = mbrptrreadexpr // p->y
+ kind(7) = mbrptrmbrreadexpr // x.*pm
+ kind(8) = mbrptrmbrptrreadexpr // x->*pm
+ kind(9) = staticmbrreadexpr // static x.y
+ kind(10) = staticmbrptrreadexpr // static p->y
+*/
+/* TODO
+memberaccess(
+ int member: @expr ref,
+ int kind: int ref
+);
+*/
+
+initialisers(
+ unique int init: @initialiser,
+ int var: @accessible ref,
+ unique int expr: @expr ref,
+ int location: @location_default ref
+);
+
+braced_initialisers(
+ int init: @initialiser ref
+);
+
+/**
+ * An ancestor for the expression, for cases in which we cannot
+ * otherwise find the expression's parent.
+ */
+expr_ancestor(
+ int exp: @expr ref,
+ int ancestor: @element ref
+);
+
+exprs(
+ unique int id: @expr,
+ int kind: int ref,
+ int location: @location_default ref
+);
+
+expr_reuse(
+ int reuse: @expr ref,
+ int original: @expr ref,
+ int value_category: int ref
+)
+
+/*
+ case @value.category of
+ 1 = prval
+ | 2 = xval
+ | 3 = lval
+ ;
+*/
+expr_types(
+ int id: @expr ref,
+ int typeid: @type ref,
+ int value_category: int ref
+);
+
+case @expr.kind of
+ 1 = @errorexpr
+| 2 = @address_of // & AddressOfExpr
+| 3 = @reference_to // ReferenceToExpr (implicit?)
+| 4 = @indirect // * PointerDereferenceExpr
+| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?)
+// ...
+| 8 = @array_to_pointer // (???)
+| 9 = @vacuous_destructor_call // VacuousDestructorCall
+// ...
+| 11 = @assume // Microsoft
+| 12 = @parexpr
+| 13 = @arithnegexpr
+| 14 = @unaryplusexpr
+| 15 = @complementexpr
+| 16 = @notexpr
+| 17 = @conjugation // GNU ~ operator
+| 18 = @realpartexpr // GNU __real
+| 19 = @imagpartexpr // GNU __imag
+| 20 = @postincrexpr
+| 21 = @postdecrexpr
+| 22 = @preincrexpr
+| 23 = @predecrexpr
+| 24 = @conditionalexpr
+| 25 = @addexpr
+| 26 = @subexpr
+| 27 = @mulexpr
+| 28 = @divexpr
+| 29 = @remexpr
+| 30 = @jmulexpr // C99 mul imaginary
+| 31 = @jdivexpr // C99 div imaginary
+| 32 = @fjaddexpr // C99 add real + imaginary
+| 33 = @jfaddexpr // C99 add imaginary + real
+| 34 = @fjsubexpr // C99 sub real - imaginary
+| 35 = @jfsubexpr // C99 sub imaginary - real
+| 36 = @paddexpr // pointer add (pointer + int or int + pointer)
+| 37 = @psubexpr // pointer sub (pointer - integer)
+| 38 = @pdiffexpr // difference between two pointers
+| 39 = @lshiftexpr
+| 40 = @rshiftexpr
+| 41 = @andexpr
+| 42 = @orexpr
+| 43 = @xorexpr
+| 44 = @eqexpr
+| 45 = @neexpr
+| 46 = @gtexpr
+| 47 = @ltexpr
+| 48 = @geexpr
+| 49 = @leexpr
+| 50 = @minexpr // GNU minimum
+| 51 = @maxexpr // GNU maximum
+| 52 = @assignexpr
+| 53 = @assignaddexpr
+| 54 = @assignsubexpr
+| 55 = @assignmulexpr
+| 56 = @assigndivexpr
+| 57 = @assignremexpr
+| 58 = @assignlshiftexpr
+| 59 = @assignrshiftexpr
+| 60 = @assignandexpr
+| 61 = @assignorexpr
+| 62 = @assignxorexpr
+| 63 = @assignpaddexpr // assign pointer add
+| 64 = @assignpsubexpr // assign pointer sub
+| 65 = @andlogicalexpr
+| 66 = @orlogicalexpr
+| 67 = @commaexpr
+| 68 = @subscriptexpr // access to member of an array, e.g., a[5]
+// ... 69 @objc_subscriptexpr deprecated
+// ... 70 @cmdaccess deprecated
+// ...
+| 73 = @virtfunptrexpr
+| 74 = @callexpr
+// ... 75 @msgexpr_normal deprecated
+// ... 76 @msgexpr_super deprecated
+// ... 77 @atselectorexpr deprecated
+// ... 78 @atprotocolexpr deprecated
+| 79 = @vastartexpr
+| 80 = @vaargexpr
+| 81 = @vaendexpr
+| 82 = @vacopyexpr
+// ... 83 @atencodeexpr deprecated
+| 84 = @varaccess
+| 85 = @thisaccess
+// ... 86 @objc_box_expr deprecated
+| 87 = @new_expr
+| 88 = @delete_expr
+| 89 = @throw_expr
+| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2)
+| 91 = @braced_init_list
+| 92 = @type_id
+| 93 = @runtime_sizeof
+| 94 = @runtime_alignof
+| 95 = @sizeof_pack
+| 96 = @expr_stmt // GNU extension
+| 97 = @routineexpr
+| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....)
+| 99 = @offsetofexpr // offsetof ::= type and field
+| 100 = @hasassignexpr // __has_assign ::= type
+| 101 = @hascopyexpr // __has_copy ::= type
+| 102 = @hasnothrowassign // __has_nothrow_assign ::= type
+| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type
+| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type
+| 105 = @hastrivialassign // __has_trivial_assign ::= type
+| 106 = @hastrivialconstr // __has_trivial_constructor ::= type
+| 107 = @hastrivialcopy // __has_trivial_copy ::= type
+| 108 = @hasuserdestr // __has_user_destructor ::= type
+| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type
+| 110 = @isabstractexpr // __is_abstract ::= type
+| 111 = @isbaseofexpr // __is_base_of ::= type type
+| 112 = @isclassexpr // __is_class ::= type
+| 113 = @isconvtoexpr // __is_convertible_to ::= type type
+| 114 = @isemptyexpr // __is_empty ::= type
+| 115 = @isenumexpr // __is_enum ::= type
+| 116 = @ispodexpr // __is_pod ::= type
+| 117 = @ispolyexpr // __is_polymorphic ::= type
+| 118 = @isunionexpr // __is_union ::= type
+| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type
+| 120 = @intaddrexpr // frontend internal builtin, used to implement offsetof
+// ...
+| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type
+| 123 = @literal
+| 124 = @uuidof
+| 127 = @aggregateliteral
+| 128 = @delete_array_expr
+| 129 = @new_array_expr
+// ... 130 @objc_array_literal deprecated
+// ... 131 @objc_dictionary_literal deprecated
+| 132 = @foldexpr
+// ...
+| 200 = @ctordirectinit
+| 201 = @ctorvirtualinit
+| 202 = @ctorfieldinit
+| 203 = @ctordelegatinginit
+| 204 = @dtordirectdestruct
+| 205 = @dtorvirtualdestruct
+| 206 = @dtorfielddestruct
+// ...
+| 210 = @static_cast
+| 211 = @reinterpret_cast
+| 212 = @const_cast
+| 213 = @dynamic_cast
+| 214 = @c_style_cast
+| 215 = @lambdaexpr
+| 216 = @param_ref
+| 217 = @noopexpr
+// ...
+| 294 = @istriviallyconstructibleexpr
+| 295 = @isdestructibleexpr
+| 296 = @isnothrowdestructibleexpr
+| 297 = @istriviallydestructibleexpr
+| 298 = @istriviallyassignableexpr
+| 299 = @isnothrowassignableexpr
+| 300 = @istrivialexpr
+| 301 = @isstandardlayoutexpr
+| 302 = @istriviallycopyableexpr
+| 303 = @isliteraltypeexpr
+| 304 = @hastrivialmoveconstructorexpr
+| 305 = @hastrivialmoveassignexpr
+| 306 = @hasnothrowmoveassignexpr
+| 307 = @isconstructibleexpr
+| 308 = @isnothrowconstructibleexpr
+| 309 = @hasfinalizerexpr
+| 310 = @isdelegateexpr
+| 311 = @isinterfaceclassexpr
+| 312 = @isrefarrayexpr
+| 313 = @isrefclassexpr
+| 314 = @issealedexpr
+| 315 = @issimplevalueclassexpr
+| 316 = @isvalueclassexpr
+| 317 = @isfinalexpr
+| 319 = @noexceptexpr
+| 320 = @builtinshufflevector
+| 321 = @builtinchooseexpr
+| 322 = @builtinaddressof
+| 323 = @vec_fill
+| 324 = @builtinconvertvector
+| 325 = @builtincomplex
+| 326 = @spaceshipexpr
+| 327 = @co_await
+| 328 = @co_yield
+| 329 = @temp_init
+| 330 = @isassignable
+| 331 = @isaggregate
+| 332 = @hasuniqueobjectrepresentations
+| 333 = @builtinbitcast
+| 334 = @builtinshuffle
+| 335 = @blockassignexpr
+| 336 = @issame
+| 337 = @isfunction
+| 338 = @islayoutcompatible
+| 339 = @ispointerinterconvertiblebaseof
+| 340 = @isarray
+| 341 = @arrayrank
+| 342 = @arrayextent
+| 343 = @isarithmetic
+| 344 = @iscompletetype
+| 345 = @iscompound
+| 346 = @isconst
+| 347 = @isfloatingpoint
+| 348 = @isfundamental
+| 349 = @isintegral
+| 350 = @islvaluereference
+| 351 = @ismemberfunctionpointer
+| 352 = @ismemberobjectpointer
+| 353 = @ismemberpointer
+| 354 = @isobject
+| 355 = @ispointer
+| 356 = @isreference
+| 357 = @isrvaluereference
+| 358 = @isscalar
+| 359 = @issigned
+| 360 = @isunsigned
+| 361 = @isvoid
+| 362 = @isvolatile
+| 363 = @reuseexpr
+| 364 = @istriviallycopyassignable
+| 365 = @isassignablenopreconditioncheck
+| 366 = @referencebindstotemporary
+| 367 = @issameas
+| 368 = @builtinhasattribute
+| 369 = @ispointerinterconvertiblewithclass
+| 370 = @builtinispointerinterconvertiblewithclass
+| 371 = @iscorrespondingmember
+| 372 = @builtiniscorrespondingmember
+| 373 = @isboundedarray
+| 374 = @isunboundedarray
+| 375 = @isreferenceable
+| 378 = @isnothrowconvertible
+| 379 = @referenceconstructsfromtemporary
+| 380 = @referenceconvertsfromtemporary
+| 381 = @isconvertible
+| 382 = @isvalidwinrttype
+| 383 = @iswinclass
+| 384 = @iswininterface
+| 385 = @istriviallyequalitycomparable
+| 386 = @isscopedenum
+| 387 = @istriviallyrelocatable
+| 388 = @datasizeof
+| 389 = @c11_generic
+| 390 = @requires_expr
+| 391 = @nested_requirement
+| 392 = @compound_requirement
+| 393 = @concept_id
+| 394 = @isinvocable
+| 395 = @isnothrowinvocable
+| 396 = @isbitwisecloneable
+;
+
+@var_args_expr = @vastartexpr
+ | @vaendexpr
+ | @vaargexpr
+ | @vacopyexpr
+ ;
+
+@builtin_op = @var_args_expr
+ | @noopexpr
+ | @offsetofexpr
+ | @intaddrexpr
+ | @hasassignexpr
+ | @hascopyexpr
+ | @hasnothrowassign
+ | @hasnothrowconstr
+ | @hasnothrowcopy
+ | @hastrivialassign
+ | @hastrivialconstr
+ | @hastrivialcopy
+ | @hastrivialdestructor
+ | @hasuserdestr
+ | @hasvirtualdestr
+ | @isabstractexpr
+ | @isbaseofexpr
+ | @isclassexpr
+ | @isconvtoexpr
+ | @isemptyexpr
+ | @isenumexpr
+ | @ispodexpr
+ | @ispolyexpr
+ | @isunionexpr
+ | @typescompexpr
+ | @builtinshufflevector
+ | @builtinconvertvector
+ | @builtinaddressof
+ | @istriviallyconstructibleexpr
+ | @isdestructibleexpr
+ | @isnothrowdestructibleexpr
+ | @istriviallydestructibleexpr
+ | @istriviallyassignableexpr
+ | @isnothrowassignableexpr
+ | @istrivialexpr
+ | @isstandardlayoutexpr
+ | @istriviallycopyableexpr
+ | @isliteraltypeexpr
+ | @hastrivialmoveconstructorexpr
+ | @hastrivialmoveassignexpr
+ | @hasnothrowmoveassignexpr
+ | @isconstructibleexpr
+ | @isnothrowconstructibleexpr
+ | @hasfinalizerexpr
+ | @isdelegateexpr
+ | @isinterfaceclassexpr
+ | @isrefarrayexpr
+ | @isrefclassexpr
+ | @issealedexpr
+ | @issimplevalueclassexpr
+ | @isvalueclassexpr
+ | @isfinalexpr
+ | @builtinchooseexpr
+ | @builtincomplex
+ | @isassignable
+ | @isaggregate
+ | @hasuniqueobjectrepresentations
+ | @builtinbitcast
+ | @builtinshuffle
+ | @issame
+ | @isfunction
+ | @islayoutcompatible
+ | @ispointerinterconvertiblebaseof
+ | @isarray
+ | @arrayrank
+ | @arrayextent
+ | @isarithmetic
+ | @iscompletetype
+ | @iscompound
+ | @isconst
+ | @isfloatingpoint
+ | @isfundamental
+ | @isintegral
+ | @islvaluereference
+ | @ismemberfunctionpointer
+ | @ismemberobjectpointer
+ | @ismemberpointer
+ | @isobject
+ | @ispointer
+ | @isreference
+ | @isrvaluereference
+ | @isscalar
+ | @issigned
+ | @isunsigned
+ | @isvoid
+ | @isvolatile
+ | @istriviallycopyassignable
+ | @isassignablenopreconditioncheck
+ | @referencebindstotemporary
+ | @issameas
+ | @builtinhasattribute
+ | @ispointerinterconvertiblewithclass
+ | @builtinispointerinterconvertiblewithclass
+ | @iscorrespondingmember
+ | @builtiniscorrespondingmember
+ | @isboundedarray
+ | @isunboundedarray
+ | @isreferenceable
+ | @isnothrowconvertible
+ | @referenceconstructsfromtemporary
+ | @referenceconvertsfromtemporary
+ | @isconvertible
+ | @isvalidwinrttype
+ | @iswinclass
+ | @iswininterface
+ | @istriviallyequalitycomparable
+ | @isscopedenum
+ | @istriviallyrelocatable
+ | @isinvocable
+ | @isnothrowinvocable
+ | @isbitwisecloneable
+ ;
+
+compound_requirement_is_noexcept(
+ int expr: @compound_requirement ref
+);
+
+new_allocated_type(
+ unique int expr: @new_expr ref,
+ int type_id: @type ref
+);
+
+new_array_allocated_type(
+ unique int expr: @new_array_expr ref,
+ int type_id: @type ref
+);
+
+param_ref_to_this(
+ int expr: @param_ref ref
+)
+
+/**
+ * The field being initialized by an initializer expression within an aggregate
+ * initializer for a class/struct/union. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_field_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int field: @membervariable ref,
+ int position: int ref,
+ boolean is_designated: boolean ref
+);
+
+/**
+ * The index of the element being initialized by an initializer expression
+ * within an aggregate initializer for an array. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_array_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int element_index: int ref,
+ int position: int ref,
+ boolean is_designated: boolean ref
+);
+
+@ctorinit = @ctordirectinit
+ | @ctorvirtualinit
+ | @ctorfieldinit
+ | @ctordelegatinginit;
+@dtordestruct = @dtordirectdestruct
+ | @dtorvirtualdestruct
+ | @dtorfielddestruct;
+
+
+condition_decl_bind(
+ unique int expr: @condition_decl ref,
+ unique int decl: @declaration ref
+);
+
+typeid_bind(
+ unique int expr: @type_id ref,
+ int type_id: @type ref
+);
+
+uuidof_bind(
+ unique int expr: @uuidof ref,
+ int type_id: @type ref
+);
+
+@sizeof_or_alignof = @runtime_sizeof | @runtime_alignof | @datasizeof | @sizeof_pack;
+
+sizeof_bind(
+ unique int expr: @sizeof_or_alignof ref,
+ int type_id: @type ref
+);
+
+code_block(
+ unique int block: @literal ref,
+ unique int routine: @function ref
+);
+
+lambdas(
+ unique int expr: @lambdaexpr ref,
+ string default_capture: string ref,
+ boolean has_explicit_return_type: boolean ref,
+ boolean has_explicit_parameter_list: boolean ref
+);
+
+lambda_capture(
+ unique int id: @lambdacapture,
+ int lambda: @lambdaexpr ref,
+ int index: int ref,
+ int field: @membervariable ref,
+ boolean captured_by_reference: boolean ref,
+ boolean is_implicit: boolean ref,
+ int location: @location_default ref
+);
+
+@funbindexpr = @routineexpr
+ | @new_expr
+ | @delete_expr
+ | @delete_array_expr
+ | @ctordirectinit
+ | @ctorvirtualinit
+ | @ctordelegatinginit
+ | @dtordirectdestruct
+ | @dtorvirtualdestruct;
+
+@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct;
+@addressable = @function | @variable ;
+@accessible = @addressable | @enumconstant ;
+
+@access = @varaccess | @routineexpr ;
+
+fold(
+ int expr: @foldexpr ref,
+ string operator: string ref,
+ boolean is_left_fold: boolean ref
+);
+
+stmts(
+ unique int id: @stmt,
+ int kind: int ref,
+ int location: @location_default ref
+);
+
+case @stmt.kind of
+ 1 = @stmt_expr
+| 2 = @stmt_if
+| 3 = @stmt_while
+| 4 = @stmt_goto
+| 5 = @stmt_label
+| 6 = @stmt_return
+| 7 = @stmt_block
+| 8 = @stmt_end_test_while // do { ... } while ( ... )
+| 9 = @stmt_for
+| 10 = @stmt_switch_case
+| 11 = @stmt_switch
+| 13 = @stmt_asm // "asm" statement or the body of an asm function
+| 15 = @stmt_try_block
+| 16 = @stmt_microsoft_try // Microsoft
+| 17 = @stmt_decl
+| 18 = @stmt_set_vla_size // C99
+| 19 = @stmt_vla_decl // C99
+| 25 = @stmt_assigned_goto // GNU
+| 26 = @stmt_empty
+| 27 = @stmt_continue
+| 28 = @stmt_break
+| 29 = @stmt_range_based_for // C++11
+// ... 30 @stmt_at_autoreleasepool_block deprecated
+// ... 31 @stmt_objc_for_in deprecated
+// ... 32 @stmt_at_synchronized deprecated
+| 33 = @stmt_handler
+// ... 34 @stmt_finally_end deprecated
+| 35 = @stmt_constexpr_if
+| 37 = @stmt_co_return
+| 38 = @stmt_consteval_if
+| 39 = @stmt_not_consteval_if
+| 40 = @stmt_leave
+;
+
+type_vla(
+ int type_id: @type ref,
+ int decl: @stmt_vla_decl ref
+);
+
+variable_vla(
+ int var: @variable ref,
+ int decl: @stmt_vla_decl ref
+);
+
+type_is_vla(unique int type_id: @derivedtype ref)
+
+if_initialization(
+ unique int if_stmt: @stmt_if ref,
+ int init_id: @stmt ref
+);
+
+if_then(
+ unique int if_stmt: @stmt_if ref,
+ int then_id: @stmt ref
+);
+
+if_else(
+ unique int if_stmt: @stmt_if ref,
+ int else_id: @stmt ref
+);
+
+constexpr_if_initialization(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int init_id: @stmt ref
+);
+
+constexpr_if_then(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int then_id: @stmt ref
+);
+
+constexpr_if_else(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int else_id: @stmt ref
+);
+
+@stmt_consteval_or_not_consteval_if = @stmt_consteval_if | @stmt_not_consteval_if;
+
+consteval_if_then(
+ unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref,
+ int then_id: @stmt ref
+);
+
+consteval_if_else(
+ unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref,
+ int else_id: @stmt ref
+);
+
+while_body(
+ unique int while_stmt: @stmt_while ref,
+ int body_id: @stmt ref
+);
+
+do_body(
+ unique int do_stmt: @stmt_end_test_while ref,
+ int body_id: @stmt ref
+);
+
+switch_initialization(
+ unique int switch_stmt: @stmt_switch ref,
+ int init_id: @stmt ref
+);
+
+#keyset[switch_stmt, index]
+switch_case(
+ int switch_stmt: @stmt_switch ref,
+ int index: int ref,
+ int case_id: @stmt_switch_case ref
+);
+
+switch_body(
+ unique int switch_stmt: @stmt_switch ref,
+ int body_id: @stmt ref
+);
+
+@stmt_for_or_range_based_for = @stmt_for
+ | @stmt_range_based_for;
+
+for_initialization(
+ unique int for_stmt: @stmt_for_or_range_based_for ref,
+ int init_id: @stmt ref
+);
+
+for_condition(
+ unique int for_stmt: @stmt_for ref,
+ int condition_id: @expr ref
+);
+
+for_update(
+ unique int for_stmt: @stmt_for ref,
+ int update_id: @expr ref
+);
+
+for_body(
+ unique int for_stmt: @stmt_for ref,
+ int body_id: @stmt ref
+);
+
+@stmtparent = @stmt | @expr_stmt ;
+stmtparents(
+ unique int id: @stmt ref,
+ int index: int ref,
+ int parent: @stmtparent ref
+);
+
+ishandler(unique int block: @stmt_block ref);
+
+@cfgnode = @stmt | @expr | @function | @initialiser ;
+
+stmt_decl_bind(
+ int stmt: @stmt_decl ref,
+ int num: int ref,
+ int decl: @declaration ref
+);
+
+stmt_decl_entry_bind(
+ int stmt: @stmt_decl ref,
+ int num: int ref,
+ int decl_entry: @element ref
+);
+
+@parameterized_element = @function | @stmt_block | @requires_expr;
+
+blockscope(
+ unique int block: @stmt_block ref,
+ int enclosing: @parameterized_element ref
+);
+
+@jump = @stmt_goto | @stmt_break | @stmt_continue | @stmt_leave;
+
+@jumporlabel = @jump | @stmt_label | @literal;
+
+jumpinfo(
+ unique int id: @jumporlabel ref,
+ string str: string ref,
+ int target: @stmt ref
+);
+
+preprocdirects(
+ unique int id: @preprocdirect,
+ int kind: int ref,
+ int location: @location_default ref
+);
+case @preprocdirect.kind of
+ 0 = @ppd_if
+| 1 = @ppd_ifdef
+| 2 = @ppd_ifndef
+| 3 = @ppd_elif
+| 4 = @ppd_else
+| 5 = @ppd_endif
+| 6 = @ppd_plain_include
+| 7 = @ppd_define
+| 8 = @ppd_undef
+| 9 = @ppd_line
+| 10 = @ppd_error
+| 11 = @ppd_pragma
+| 12 = @ppd_objc_import
+| 13 = @ppd_include_next
+| 14 = @ppd_ms_import
+| 15 = @ppd_elifdef
+| 16 = @ppd_elifndef
+| 17 = @ppd_embed
+| 18 = @ppd_warning
+;
+
+@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next | @ppd_ms_import;
+
+@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif | @ppd_elifdef | @ppd_elifndef;
+
+preprocpair(
+ int begin : @ppd_branch ref,
+ int elseelifend : @preprocdirect ref
+);
+
+preproctrue(int branch : @ppd_branch ref);
+preprocfalse(int branch : @ppd_branch ref);
+
+preproctext(
+ unique int id: @preprocdirect ref,
+ string head: string ref,
+ string body: string ref
+);
+
+includes(
+ unique int id: @ppd_include ref,
+ int included: @file ref
+);
+
+embeds(
+ unique int id: @ppd_embed ref,
+ int included: @file ref
+);
+
+link_targets(
+ int id: @link_target,
+ int binary: @file ref
+);
+
+link_parent(
+ int element : @element ref,
+ int link_target : @link_target ref
+);
+
+/*- Database metadata -*/
+
+/**
+ * The CLI will automatically emit applicable tuples for this table,
+ * such as `databaseMetadata("isOverlay", "true")` when building an
+ * overlay database.
+ */
+databaseMetadata(
+ string metadataKey: string ref,
+ string value: string ref
+);
+
+/*- Overlay support -*/
+
+/**
+ * The CLI will automatically emit tuples for each new/modified/deleted file
+ * when building an overlay database.
+ */
+overlayChangedFiles(
+ string path: string ref
+);
+
+/*- XML Files -*/
+
+xmlEncoding(
+ unique int id: @file ref,
+ string encoding: string ref
+);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref
+);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref
+);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref
+);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref
+);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref
+);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref
+);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref
+);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref
+);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
diff --git a/cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/semmlecode.dbscheme b/cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/semmlecode.dbscheme
new file mode 100644
index 00000000000..7e7c2f55670
--- /dev/null
+++ b/cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/semmlecode.dbscheme
@@ -0,0 +1,2517 @@
+
+/*- Compilations -*/
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ /**
+ * An invocation of the compiler. Note that more than one file may
+ * be compiled per invocation. For example, this command compiles
+ * three source files:
+ *
+ * gcc -c f1.c f2.c f3.c
+ */
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | *path to extractor*
+ * 1 | `--mimic`
+ * 2 | `/usr/bin/gcc`
+ * 3 | `-c`
+ * 4 | f1.c
+ * 5 | f2.c
+ * 6 | f3.c
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The expanded arguments that were passed to the extractor for a
+ * compiler invocation. This is similar to `compilation_args`, but
+ * for a `@someFile` argument, it includes the arguments from that
+ * file, rather than just taking the argument literally.
+ */
+#keyset[id, num]
+compilation_expanded_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * Optionally, record the build mode for each compilation.
+ */
+compilation_build_mode(
+ unique int id : @compilation ref,
+ int mode : int ref
+);
+
+/*
+case @compilation_build_mode.mode of
+ 0 = @build_mode_none
+| 1 = @build_mode_manual
+| 2 = @build_mode_auto
+;
+*/
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.c
+ * 1 | f2.c
+ * 2 | f3.c
+ *
+ * Note that even if those files `#include` headers, those headers
+ * do not appear as rows.
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+/*- External data -*/
+
+/**
+ * External data, loaded from CSV files during snapshot creation. See
+ * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data)
+ * for more information.
+ */
+externalData(
+ int id : @externalDataElement,
+ string path : string ref,
+ int column: int ref,
+ string value : string ref
+);
+
+/*- Source location prefix -*/
+
+/**
+ * The source location of the snapshot.
+ */
+sourceLocationPrefix(string prefix : string ref);
+
+/*- Files and folders -*/
+
+/**
+ * The location of an element.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref
+);
+
+files(
+ unique int id: @file,
+ string name: string ref
+);
+
+folders(
+ unique int id: @folder,
+ string name: string ref
+);
+
+@container = @file | @folder
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref
+);
+
+/*- Lines of code -*/
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref
+);
+
+/*- Diagnostic messages -*/
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location_default ref
+);
+
+/*- C++ dbscheme -*/
+
+extractor_version(
+ string codeql_version: string ref,
+ string frontend_version: string ref
+)
+
+/**
+ * Gives the TRAP filename that `trap` is associated with.
+ * For debugging only.
+ */
+trap_filename(
+ int trap: @trap,
+ string filename: string ref
+);
+
+/**
+ * In `build-mode: none` overlay mode, indicates that `source_file`
+ * (`/path/to/foo.c`) uses the TRAP file `trap_file`; i.e. it is the
+ * TRAP file corresponding to `foo.c`, something it transitively
+ * includes, or a template instantiation it transitively uses.
+ */
+source_file_uses_trap(
+ string source_file: string ref,
+ int trap_file: @trap ref
+);
+
+/**
+ * Holds if there is a definition of `element` in TRAP file `trap_file`.
+ */
+in_trap(
+ int element: @element ref,
+ int trap_file: @trap ref
+);
+
+pch_uses(
+ int pch: @pch ref,
+ int compilation: @compilation ref,
+ int id: @file ref
+)
+
+#keyset[pch, compilation]
+pch_creations(
+ int pch: @pch,
+ int compilation: @compilation ref,
+ int from: @file ref
+)
+
+/** An element for which line-count information is available. */
+@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable;
+
+fileannotations(
+ int id: @file ref,
+ int kind: int ref,
+ string name: string ref,
+ string value: string ref
+);
+
+inmacroexpansion(
+ int id: @element ref,
+ int inv: @macroinvocation ref
+);
+
+affectedbymacroexpansion(
+ int id: @element ref,
+ int inv: @macroinvocation ref
+);
+
+case @macroinvocation.kind of
+ 1 = @macro_expansion
+| 2 = @other_macro_reference
+;
+
+macroinvocations(
+ unique int id: @macroinvocation,
+ int macro_id: @ppd_define ref,
+ int location: @location_default ref,
+ int kind: int ref
+);
+
+macroparent(
+ unique int id: @macroinvocation ref,
+ int parent_id: @macroinvocation ref
+);
+
+// a macroinvocation may be part of another location
+// the way to find a constant expression that uses a macro
+// is thus to find a constant expression that has a location
+// to which a macro invocation is bound
+macrolocationbind(
+ int id: @macroinvocation ref,
+ int location: @location_default ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_unexpanded(
+ int invocation: @macroinvocation ref,
+ int argument_index: int ref,
+ string text: string ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_expanded(
+ int invocation: @macroinvocation ref,
+ int argument_index: int ref,
+ string text: string ref
+);
+
+case @function.kind of
+ 0 = @unknown_function
+| 1 = @normal_function
+| 2 = @constructor
+| 3 = @destructor
+| 4 = @conversion_function
+| 5 = @operator
+// ... 6 = @builtin_function deprecated // GCC built-in functions, e.g. __builtin___memcpy_chk
+| 7 = @user_defined_literal
+| 8 = @deduction_guide
+;
+
+functions(
+ unique int id: @function,
+ string name: string ref,
+ int kind: int ref
+);
+
+builtin_functions(
+ int id: @function ref
+)
+
+function_entry_point(
+ int id: @function ref,
+ unique int entry_point: @stmt ref
+);
+
+function_return_type(
+ int id: @function ref,
+ int return_type: @type ref
+);
+
+/**
+ * If `function` is a coroutine, then this gives the `std::experimental::resumable_traits`
+ * instance associated with it, and the variables representing the `handle` and `promise`
+ * for it.
+ */
+coroutine(
+ unique int function: @function ref,
+ int traits: @type ref
+);
+
+/*
+case @coroutine_placeholder_variable.kind of
+ 1 = @handle
+| 2 = @promise
+| 3 = @init_await_resume
+;
+*/
+
+coroutine_placeholder_variable(
+ unique int placeholder_variable: @variable ref,
+ int kind: int ref,
+ int function: @function ref
+)
+
+/** The `new` function used for allocating the coroutine state, if any. */
+coroutine_new(
+ unique int function: @function ref,
+ int new: @function ref
+);
+
+/** The `delete` function used for deallocating the coroutine state, if any. */
+coroutine_delete(
+ unique int function: @function ref,
+ int delete: @function ref
+);
+
+purefunctions(unique int id: @function ref);
+
+function_deleted(unique int id: @function ref);
+
+function_defaulted(unique int id: @function ref);
+
+function_prototyped(unique int id: @function ref)
+
+deduction_guide_for_class(
+ int id: @function ref,
+ int class_template: @usertype ref
+)
+
+member_function_this_type(
+ unique int id: @function ref,
+ int this_type: @type ref
+);
+
+#keyset[id, type_id]
+fun_decls(
+ int id: @fun_decl,
+ int function: @function ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+fun_def(unique int id: @fun_decl ref);
+fun_specialized(unique int id: @fun_decl ref);
+fun_implicit(unique int id: @fun_decl ref);
+fun_decl_specifiers(
+ int id: @fun_decl ref,
+ string name: string ref
+)
+#keyset[fun_decl, index]
+fun_decl_throws(
+ int fun_decl: @fun_decl ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+/* an empty throw specification is different from none */
+fun_decl_empty_throws(unique int fun_decl: @fun_decl ref);
+fun_decl_noexcept(
+ int fun_decl: @fun_decl ref,
+ int constant: @expr ref
+);
+fun_decl_empty_noexcept(int fun_decl: @fun_decl ref);
+fun_decl_typedef_type(
+ unique int fun_decl: @fun_decl ref,
+ int typedeftype_id: @usertype ref
+);
+
+/*
+case @fun_requires.kind of
+ 1 = @template_attached
+| 2 = @function_attached
+;
+*/
+
+fun_requires(
+ int id: @fun_decl ref,
+ int kind: int ref,
+ int constraint: @expr ref
+);
+
+param_decl_bind(
+ unique int id: @var_decl ref,
+ int index: int ref,
+ int fun_decl: @fun_decl ref
+);
+
+#keyset[id, type_id]
+var_decls(
+ int id: @var_decl,
+ int variable: @variable ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+var_def(unique int id: @var_decl ref);
+var_specialized(int id: @var_decl ref);
+var_decl_specifiers(
+ int id: @var_decl ref,
+ string name: string ref
+)
+is_structured_binding(unique int id: @variable ref);
+var_requires(
+ int id: @var_decl ref,
+ int constraint: @expr ref
+);
+
+type_decls(
+ unique int id: @type_decl,
+ int type_id: @type ref,
+ int location: @location_default ref
+);
+type_def(unique int id: @type_decl ref);
+type_decl_top(
+ unique int type_decl: @type_decl ref
+);
+type_requires(
+ int id: @type_decl ref,
+ int constraint: @expr ref
+);
+
+namespace_decls(
+ unique int id: @namespace_decl,
+ int namespace_id: @namespace ref,
+ int location: @location_default ref,
+ int bodylocation: @location_default ref
+);
+
+case @using.kind of
+ 1 = @using_declaration
+| 2 = @using_directive
+| 3 = @using_enum_declaration
+;
+
+usings(
+ unique int id: @using,
+ int element_id: @element ref,
+ int location: @location_default ref,
+ int kind: int ref
+);
+
+/** The element which contains the `using` declaration. */
+using_container(
+ int parent: @element ref,
+ int child: @using ref
+);
+
+static_asserts(
+ unique int id: @static_assert,
+ int condition : @expr ref,
+ string message : string ref,
+ int location: @location_default ref,
+ int enclosing : @element ref
+);
+
+// each function has an ordered list of parameters
+#keyset[id, type_id]
+#keyset[function, index, type_id]
+params(
+ int id: @parameter,
+ int function: @parameterized_element ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+
+overrides(
+ int new: @function ref,
+ int old: @function ref
+);
+
+#keyset[id, type_id]
+membervariables(
+ int id: @membervariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+#keyset[id, type_id]
+globalvariables(
+ int id: @globalvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+#keyset[id, type_id]
+localvariables(
+ int id: @localvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+autoderivation(
+ unique int var: @variable ref,
+ int derivation_type: @type ref
+);
+
+orphaned_variables(
+ int var: @localvariable ref,
+ int function: @function ref
+)
+
+enumconstants(
+ unique int id: @enumconstant,
+ int parent: @usertype ref,
+ int index: int ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+
+@variable = @localscopevariable | @globalvariable | @membervariable;
+
+@localscopevariable = @localvariable | @parameter;
+
+/**
+ * Built-in types are the fundamental types, e.g., integral, floating, and void.
+ */
+case @builtintype.kind of
+ 1 = @errortype
+| 2 = @unknowntype
+| 3 = @void
+| 4 = @boolean
+| 5 = @char
+| 6 = @unsigned_char
+| 7 = @signed_char
+| 8 = @short
+| 9 = @unsigned_short
+| 10 = @signed_short
+| 11 = @int
+| 12 = @unsigned_int
+| 13 = @signed_int
+| 14 = @long
+| 15 = @unsigned_long
+| 16 = @signed_long
+| 17 = @long_long
+| 18 = @unsigned_long_long
+| 19 = @signed_long_long
+// ... 20 Microsoft-specific __int8
+// ... 21 Microsoft-specific __int16
+// ... 22 Microsoft-specific __int32
+// ... 23 Microsoft-specific __int64
+| 24 = @float
+| 25 = @double
+| 26 = @long_double
+| 27 = @complex_float // C99-specific _Complex float
+| 28 = @complex_double // C99-specific _Complex double
+| 29 = @complex_long_double // C99-specific _Complex long double
+| 30 = @imaginary_float // C99-specific _Imaginary float
+| 31 = @imaginary_double // C99-specific _Imaginary double
+| 32 = @imaginary_long_double // C99-specific _Imaginary long double
+| 33 = @wchar_t // Microsoft-specific
+| 34 = @decltype_nullptr // C++11
+| 35 = @int128 // __int128
+| 36 = @unsigned_int128 // unsigned __int128
+| 37 = @signed_int128 // signed __int128
+| 38 = @float128 // __float128
+| 39 = @complex_float128 // _Complex __float128
+// ... 40 _Decimal32
+// ... 41 _Decimal64
+// ... 42 _Decimal128
+| 43 = @char16_t
+| 44 = @char32_t
+| 45 = @std_float32 // _Float32
+| 46 = @float32x // _Float32x
+| 47 = @std_float64 // _Float64
+| 48 = @float64x // _Float64x
+| 49 = @std_float128 // _Float128
+// ... 50 _Float128x
+| 51 = @char8_t
+| 52 = @float16 // _Float16
+| 53 = @complex_float16 // _Complex _Float16
+| 54 = @fp16 // __fp16
+| 55 = @std_bfloat16 // __bf16
+| 56 = @std_float16 // std::float16_t
+| 57 = @complex_std_float32 // _Complex _Float32
+| 58 = @complex_float32x // _Complex _Float32x
+| 59 = @complex_std_float64 // _Complex _Float64
+| 60 = @complex_float64x // _Complex _Float64x
+| 61 = @complex_std_float128 // _Complex _Float128
+| 62 = @mfp8 // __mfp8
+| 63 = @scalable_vector_count // __SVCount_t
+| 64 = @complex_fp16 // _Complex __fp16
+| 65 = @complex_std_bfloat16 // _Complex __bf16
+| 66 = @complex_std_float16 // _Complex std::float16_t
+;
+
+builtintypes(
+ unique int id: @builtintype,
+ string name: string ref,
+ int kind: int ref,
+ int size: int ref,
+ int sign: int ref,
+ int alignment: int ref
+);
+
+/**
+ * Derived types are types that are directly derived from existing types and
+ * point to, refer to, transform type data to return a new type.
+ */
+case @derivedtype.kind of
+ 1 = @pointer
+| 2 = @reference
+| 3 = @type_with_specifiers
+| 4 = @array
+| 5 = @gnu_vector
+| 6 = @routineptr
+| 7 = @routinereference
+| 8 = @rvalue_reference // C++11
+// ... 9 type_conforming_to_protocols deprecated
+| 10 = @block
+| 11 = @scalable_vector // Arm SVE
+;
+
+derivedtypes(
+ unique int id: @derivedtype,
+ string name: string ref,
+ int kind: int ref,
+ int type_id: @type ref
+);
+
+pointerishsize(unique int id: @derivedtype ref,
+ int size: int ref,
+ int alignment: int ref);
+
+arraysizes(
+ unique int id: @derivedtype ref,
+ int num_elements: int ref,
+ int bytesize: int ref,
+ int alignment: int ref
+);
+
+tupleelements(
+ unique int id: @derivedtype ref,
+ int num_elements: int ref
+);
+
+typedefbase(
+ unique int id: @usertype ref,
+ int type_id: @type ref
+);
+
+/**
+ * An instance of the C++11 `decltype` operator or C23 `typeof`/`typeof_unqual`
+ * operator taking an expression as its argument. For example:
+ * ```
+ * int a;
+ * decltype(1+a) b;
+ * typeof(1+a) c;
+ * ```
+ * Here `expr` is `1+a`.
+ *
+ * Sometimes an additional pair of parentheses around the expression
+ * changes the semantics of the decltype, e.g.
+ * ```
+ * struct A { double x; };
+ * const A* a = new A();
+ * decltype( a->x ); // type is double
+ * decltype((a->x)); // type is const double&
+ * ```
+ * (Please consult the C++11 standard for more details).
+ * `parentheses_would_change_meaning` is `true` iff that is the case.
+ */
+
+/*
+case @decltype.kind of
+| 0 = @decltype
+| 1 = @typeof // The frontend does not differentiate between typeof and typeof_unqual
+;
+*/
+
+#keyset[id, expr]
+decltypes(
+ int id: @decltype,
+ int expr: @expr ref,
+ int kind: int ref,
+ int base_type: @type ref,
+ boolean parentheses_would_change_meaning: boolean ref
+);
+
+case @type_operator.kind of
+ 0 = @typeof // The frontend does not differentiate between typeof and typeof_unqual
+| 1 = @underlying_type
+| 2 = @bases
+| 3 = @direct_bases
+| 4 = @add_lvalue_reference
+| 5 = @add_pointer
+| 6 = @add_rvalue_reference
+| 7 = @decay
+| 8 = @make_signed
+| 9 = @make_unsigned
+| 10 = @remove_all_extents
+| 11 = @remove_const
+| 12 = @remove_cv
+| 13 = @remove_cvref
+| 14 = @remove_extent
+| 15 = @remove_pointer
+| 16 = @remove_reference_t
+| 17 = @remove_restrict
+| 18 = @remove_volatile
+| 19 = @remove_reference
+;
+
+type_operators(
+ unique int id: @type_operator,
+ int arg_type: @type ref,
+ int kind: int ref,
+ int base_type: @type ref
+)
+
+case @usertype.kind of
+ 0 = @unknown_usertype
+| 1 = @struct
+| 2 = @class
+| 3 = @union
+| 4 = @enum
+// ... 5 = @typedef deprecated // classic C: typedef typedef type name
+// ... 6 = @template deprecated
+| 7 = @template_parameter
+| 8 = @template_template_parameter
+| 9 = @proxy_class // a proxy class associated with a template parameter
+// ... 10 objc_class deprecated
+// ... 11 objc_protocol deprecated
+// ... 12 objc_category deprecated
+| 13 = @scoped_enum
+// ... 14 = @using_alias deprecated // a using name = type style typedef
+| 15 = @template_struct
+| 16 = @template_class
+| 17 = @template_union
+| 18 = @alias
+;
+
+usertypes(
+ unique int id: @usertype,
+ string name: string ref,
+ int kind: int ref
+);
+
+usertypesize(
+ unique int id: @usertype ref,
+ int size: int ref,
+ int alignment: int ref
+);
+
+usertype_final(unique int id: @usertype ref);
+
+usertype_uuid(
+ unique int id: @usertype ref,
+ string uuid: string ref
+);
+
+/*
+case @usertype.alias_kind of
+| 0 = @typedef
+| 1 = @alias
+*/
+
+usertype_alias_kind(
+ int id: @usertype ref,
+ int alias_kind: int ref
+)
+
+nontype_template_parameters(
+ int id: @expr ref
+);
+
+type_template_type_constraint(
+ int id: @usertype ref,
+ int constraint: @expr ref
+);
+
+mangled_name(
+ unique int id: @declaration ref,
+ int mangled_name : @mangledname,
+ boolean is_complete: boolean ref
+);
+
+is_pod_class(unique int id: @usertype ref);
+is_standard_layout_class(unique int id: @usertype ref);
+
+is_complete(unique int id: @usertype ref);
+
+is_class_template(unique int id: @usertype ref);
+class_instantiation(
+ int to: @usertype ref,
+ int from: @usertype ref
+);
+class_template_argument(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+class_template_argument_value(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+@user_or_decltype = @usertype | @decltype;
+
+is_proxy_class_for(
+ unique int id: @usertype ref,
+ int templ_param_id: @user_or_decltype ref
+);
+
+type_mentions(
+ unique int id: @type_mention,
+ int type_id: @type ref,
+ int location: @location_default ref,
+ // a_symbol_reference_kind from the frontend.
+ int kind: int ref
+);
+
+is_function_template(unique int id: @function ref);
+function_instantiation(
+ unique int to: @function ref,
+ int from: @function ref
+);
+function_template_argument(
+ int function_id: @function ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+function_template_argument_value(
+ int function_id: @function ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+is_variable_template(unique int id: @variable ref);
+variable_instantiation(
+ unique int to: @variable ref,
+ int from: @variable ref
+);
+variable_template_argument(
+ int variable_id: @variable ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+variable_template_argument_value(
+ int variable_id: @variable ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+template_template_instantiation(
+ int to: @usertype ref,
+ int from: @usertype ref
+);
+template_template_argument(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+template_template_argument_value(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+@concept = @concept_template | @concept_id;
+
+concept_templates(
+ unique int concept_id: @concept_template,
+ string name: string ref,
+ int location: @location_default ref
+);
+concept_instantiation(
+ unique int to: @concept_id ref,
+ int from: @concept_template ref
+);
+is_type_constraint(int concept_id: @concept_id ref);
+concept_template_argument(
+ int concept_id: @concept ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+concept_template_argument_value(
+ int concept_id: @concept ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+routinetypes(
+ unique int id: @routinetype,
+ int return_type: @type ref
+);
+
+routinetypeargs(
+ int routine: @routinetype ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+
+ptrtomembers(
+ unique int id: @ptrtomember,
+ int type_id: @type ref,
+ int class_id: @type ref
+);
+
+/*
+ specifiers for types, functions, and variables
+
+ "public",
+ "protected",
+ "private",
+
+ "const",
+ "volatile",
+ "static",
+
+ "pure",
+ "virtual",
+ "sealed", // Microsoft
+ "__interface", // Microsoft
+ "inline",
+ "explicit",
+
+ "near", // near far extension
+ "far", // near far extension
+ "__ptr32", // Microsoft
+ "__ptr64", // Microsoft
+ "__sptr", // Microsoft
+ "__uptr", // Microsoft
+ "dllimport", // Microsoft
+ "dllexport", // Microsoft
+ "thread", // Microsoft
+ "naked", // Microsoft
+ "microsoft_inline", // Microsoft
+ "forceinline", // Microsoft
+ "selectany", // Microsoft
+ "nothrow", // Microsoft
+ "novtable", // Microsoft
+ "noreturn", // Microsoft
+ "noinline", // Microsoft
+ "noalias", // Microsoft
+ "restrict", // Microsoft
+*/
+
+specifiers(
+ unique int id: @specifier,
+ unique string str: string ref
+);
+
+typespecifiers(
+ int type_id: @type ref,
+ int spec_id: @specifier ref
+);
+
+funspecifiers(
+ int func_id: @function ref,
+ int spec_id: @specifier ref
+);
+
+varspecifiers(
+ int var_id: @accessible ref,
+ int spec_id: @specifier ref
+);
+
+explicit_specifier_exprs(
+ unique int func_id: @function ref,
+ int constant: @expr ref
+)
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ string name: string ref,
+ string name_space: string ref,
+ int location: @location_default ref
+);
+
+case @attribute.kind of
+ 0 = @gnuattribute
+| 1 = @stdattribute
+| 2 = @declspec
+| 3 = @msattribute
+| 4 = @alignas
+// ... 5 @objc_propertyattribute deprecated
+;
+
+attribute_args(
+ unique int id: @attribute_arg,
+ int kind: int ref,
+ int attribute: @attribute ref,
+ int index: int ref,
+ int location: @location_default ref
+);
+
+case @attribute_arg.kind of
+ 0 = @attribute_arg_empty
+| 1 = @attribute_arg_token
+| 2 = @attribute_arg_constant
+| 3 = @attribute_arg_type
+| 4 = @attribute_arg_constant_expr
+| 5 = @attribute_arg_expr
+;
+
+attribute_arg_value(
+ unique int arg: @attribute_arg ref,
+ string value: string ref
+);
+attribute_arg_type(
+ unique int arg: @attribute_arg ref,
+ int type_id: @type ref
+);
+attribute_arg_constant(
+ unique int arg: @attribute_arg ref,
+ int constant: @expr ref
+)
+attribute_arg_expr(
+ unique int arg: @attribute_arg ref,
+ int expr: @expr ref
+)
+attribute_arg_name(
+ unique int arg: @attribute_arg ref,
+ string name: string ref
+);
+
+typeattributes(
+ int type_id: @type ref,
+ int spec_id: @attribute ref
+);
+
+funcattributes(
+ int func_id: @function ref,
+ int spec_id: @attribute ref
+);
+
+varattributes(
+ int var_id: @accessible ref,
+ int spec_id: @attribute ref
+);
+
+namespaceattributes(
+ int namespace_id: @namespace ref,
+ int spec_id: @attribute ref
+);
+
+stmtattributes(
+ int stmt_id: @stmt ref,
+ int spec_id: @attribute ref
+);
+
+@type = @builtintype
+ | @derivedtype
+ | @usertype
+ | @routinetype
+ | @ptrtomember
+ | @decltype
+ | @type_operator;
+
+unspecifiedtype(
+ unique int type_id: @type ref,
+ int unspecified_type_id: @type ref
+);
+
+member(
+ int parent: @type ref,
+ int index: int ref,
+ int child: @member ref
+);
+
+@enclosingfunction_child = @usertype | @variable | @namespace
+
+enclosingfunction(
+ unique int child: @enclosingfunction_child ref,
+ int parent: @function ref
+);
+
+derivations(
+ unique int derivation: @derivation,
+ int sub: @type ref,
+ int index: int ref,
+ int super: @type ref,
+ int location: @location_default ref
+);
+
+derspecifiers(
+ int der_id: @derivation ref,
+ int spec_id: @specifier ref
+);
+
+/**
+ * Contains the byte offset of the base class subobject within the derived
+ * class. Only holds for non-virtual base classes, but see table
+ * `virtual_base_offsets` for offsets of virtual base class subobjects.
+ */
+direct_base_offsets(
+ unique int der_id: @derivation ref,
+ int offset: int ref
+);
+
+/**
+ * Contains the byte offset of the virtual base class subobject for class
+ * `super` within a most-derived object of class `sub`. `super` can be either a
+ * direct or indirect base class.
+ */
+#keyset[sub, super]
+virtual_base_offsets(
+ int sub: @usertype ref,
+ int super: @usertype ref,
+ int offset: int ref
+);
+
+frienddecls(
+ unique int id: @frienddecl,
+ int type_id: @type ref,
+ int decl_id: @declaration ref,
+ int location: @location_default ref
+);
+
+@declaredtype = @usertype ;
+
+@declaration = @function
+ | @declaredtype
+ | @variable
+ | @enumconstant
+ | @frienddecl
+ | @concept_template;
+
+@member = @membervariable
+ | @function
+ | @declaredtype
+ | @enumconstant;
+
+@locatable = @diagnostic
+ | @declaration
+ | @ppd_include
+ | @ppd_define
+ | @macroinvocation
+ /*| @funcall*/
+ | @xmllocatable
+ | @attribute
+ | @attribute_arg;
+
+@namedscope = @namespace | @usertype;
+
+@element = @locatable
+ | @file
+ | @folder
+ | @specifier
+ | @type
+ | @expr
+ | @namespace
+ | @initialiser
+ | @stmt
+ | @derivation
+ | @comment
+ | @preprocdirect
+ | @fun_decl
+ | @var_decl
+ | @type_decl
+ | @namespace_decl
+ | @using
+ | @namequalifier
+ | @specialnamequalifyingelement
+ | @static_assert
+ | @type_mention
+ | @lambdacapture;
+
+@exprparent = @element;
+
+comments(
+ unique int id: @comment,
+ string contents: string ref,
+ int location: @location_default ref
+);
+
+commentbinding(
+ int id: @comment ref,
+ int element: @element ref
+);
+
+exprconv(
+ int converted: @expr ref,
+ unique int conversion: @expr ref
+);
+
+compgenerated(unique int id: @element ref);
+
+/**
+ * `destructor_call` destructs the `i`'th entity that should be
+ * destructed following `element`. Note that entities should be
+ * destructed in reverse construction order, so for a given `element`
+ * these should be called from highest to lowest `i`.
+ */
+#keyset[element, destructor_call]
+#keyset[element, i]
+synthetic_destructor_call(
+ int element: @element ref,
+ int i: int ref,
+ int destructor_call: @routineexpr ref
+);
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref
+);
+
+namespace_inline(
+ unique int id: @namespace ref
+);
+
+namespacembrs(
+ int parentid: @namespace ref,
+ unique int memberid: @namespacembr ref
+);
+
+@namespacembr = @declaration | @namespace;
+
+exprparents(
+ int expr_id: @expr ref,
+ int child_index: int ref,
+ int parent_id: @exprparent ref
+);
+
+expr_isload(unique int expr_id: @expr ref);
+
+@cast = @c_style_cast
+ | @const_cast
+ | @dynamic_cast
+ | @reinterpret_cast
+ | @static_cast
+ ;
+
+/*
+case @conversion.kind of
+ 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast
+| 1 = @bool_conversion // conversion to 'bool'
+| 2 = @base_class_conversion // a derived-to-base conversion
+| 3 = @derived_class_conversion // a base-to-derived conversion
+| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member
+| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member
+| 6 = @glvalue_adjust // an adjustment of the type of a glvalue
+| 7 = @prvalue_adjust // an adjustment of the type of a prvalue
+;
+*/
+/**
+ * Describes the semantics represented by a cast expression. This is largely
+ * independent of the source syntax of the cast, so it is separate from the
+ * regular expression kind.
+ */
+conversionkinds(
+ unique int expr_id: @cast ref,
+ int kind: int ref
+);
+
+@conversion = @cast
+ | @array_to_pointer
+ | @parexpr
+ | @reference_to
+ | @ref_indirect
+ | @temp_init
+ | @c11_generic
+ ;
+
+/*
+case @funbindexpr.kind of
+ 0 = @normal_call // a normal call
+| 1 = @virtual_call // a virtual call
+| 2 = @adl_call // a call whose target is only found by ADL
+;
+*/
+iscall(
+ unique int caller: @funbindexpr ref,
+ int kind: int ref
+);
+
+numtemplatearguments(
+ unique int expr_id: @expr ref,
+ int num: int ref
+);
+
+specialnamequalifyingelements(
+ unique int id: @specialnamequalifyingelement,
+ unique string name: string ref
+);
+
+@namequalifiableelement = @expr | @namequalifier;
+@namequalifyingelement = @namespace
+ | @specialnamequalifyingelement
+ | @usertype
+ | @decltype;
+
+namequalifiers(
+ unique int id: @namequalifier,
+ unique int qualifiableelement: @namequalifiableelement ref,
+ int qualifyingelement: @namequalifyingelement ref,
+ int location: @location_default ref
+);
+
+varbind(
+ int expr: @varbindexpr ref,
+ int var: @accessible ref
+);
+
+funbind(
+ int expr: @funbindexpr ref,
+ int fun: @function ref
+);
+
+@any_new_expr = @new_expr
+ | @new_array_expr;
+
+@new_or_delete_expr = @any_new_expr
+ | @delete_expr
+ | @delete_array_expr;
+
+@prefix_crement_expr = @preincrexpr | @predecrexpr;
+
+@postfix_crement_expr = @postincrexpr | @postdecrexpr;
+
+@increment_expr = @preincrexpr | @postincrexpr;
+
+@decrement_expr = @predecrexpr | @postdecrexpr;
+
+@crement_expr = @increment_expr | @decrement_expr;
+
+@un_arith_op_expr = @arithnegexpr
+ | @unaryplusexpr
+ | @conjugation
+ | @realpartexpr
+ | @imagpartexpr
+ | @crement_expr
+ ;
+
+@un_bitwise_op_expr = @complementexpr;
+
+@un_log_op_expr = @notexpr;
+
+@un_op_expr = @address_of
+ | @indirect
+ | @un_arith_op_expr
+ | @un_bitwise_op_expr
+ | @builtinaddressof
+ | @vec_fill
+ | @un_log_op_expr
+ | @co_await
+ | @co_yield
+ ;
+
+@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr;
+
+@cmp_op_expr = @eq_op_expr | @rel_op_expr;
+
+@eq_op_expr = @eqexpr | @neexpr;
+
+@rel_op_expr = @gtexpr
+ | @ltexpr
+ | @geexpr
+ | @leexpr
+ | @spaceshipexpr
+ ;
+
+@bin_bitwise_op_expr = @lshiftexpr
+ | @rshiftexpr
+ | @andexpr
+ | @orexpr
+ | @xorexpr
+ ;
+
+@p_arith_op_expr = @paddexpr
+ | @psubexpr
+ | @pdiffexpr
+ ;
+
+@bin_arith_op_expr = @addexpr
+ | @subexpr
+ | @mulexpr
+ | @divexpr
+ | @remexpr
+ | @jmulexpr
+ | @jdivexpr
+ | @fjaddexpr
+ | @jfaddexpr
+ | @fjsubexpr
+ | @jfsubexpr
+ | @minexpr
+ | @maxexpr
+ | @p_arith_op_expr
+ ;
+
+@bin_op_expr = @bin_arith_op_expr
+ | @bin_bitwise_op_expr
+ | @cmp_op_expr
+ | @bin_log_op_expr
+ ;
+
+@op_expr = @un_op_expr
+ | @bin_op_expr
+ | @assign_expr
+ | @conditionalexpr
+ ;
+
+@assign_arith_expr = @assignaddexpr
+ | @assignsubexpr
+ | @assignmulexpr
+ | @assigndivexpr
+ | @assignremexpr
+ ;
+
+@assign_bitwise_expr = @assignandexpr
+ | @assignorexpr
+ | @assignxorexpr
+ | @assignlshiftexpr
+ | @assignrshiftexpr
+ ;
+
+@assign_pointer_expr = @assignpaddexpr
+ | @assignpsubexpr
+ ;
+
+@assign_op_expr = @assign_arith_expr
+ | @assign_bitwise_expr
+ | @assign_pointer_expr
+ ;
+
+@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
+
+/*
+ Binary encoding of the allocator form.
+
+ case @allocator.form of
+ 0 = plain
+ | 1 = alignment
+ ;
+*/
+
+/**
+ * The allocator function associated with a `new` or `new[]` expression.
+ * The `form` column specified whether the allocation call contains an alignment
+ * argument.
+ */
+expr_allocator(
+ unique int expr: @any_new_expr ref,
+ int func: @function ref,
+ int form: int ref
+);
+
+/*
+ Binary encoding of the deallocator form.
+
+ case @deallocator.form of
+ 0 = plain
+ | 1 = size
+ | 2 = alignment
+ | 4 = destroying_delete
+ ;
+*/
+
+/**
+ * The deallocator function associated with a `delete`, `delete[]`, `new`, or
+ * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the
+ * one used to free memory if the initialization throws an exception.
+ * The `form` column specifies whether the deallocation call contains a size
+ * argument, and alignment argument, or both.
+ */
+expr_deallocator(
+ unique int expr: @new_or_delete_expr ref,
+ int func: @function ref,
+ int form: int ref
+);
+
+/**
+ * Holds if the `@conditionalexpr` is of the two operand form
+ * `guard ? : false`.
+ */
+expr_cond_two_operand(
+ unique int cond: @conditionalexpr ref
+);
+
+/**
+ * The guard of `@conditionalexpr` `guard ? true : false`
+ */
+expr_cond_guard(
+ unique int cond: @conditionalexpr ref,
+ int guard: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` holds. For the two operand form
+ * `guard ?: false` consider using `expr_cond_guard` instead.
+ */
+expr_cond_true(
+ unique int cond: @conditionalexpr ref,
+ int true: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` does not hold.
+ */
+expr_cond_false(
+ unique int cond: @conditionalexpr ref,
+ int false: @expr ref
+);
+
+/** A string representation of the value. */
+values(
+ unique int id: @value,
+ string str: string ref
+);
+
+/** The actual text in the source code for the value, if any. */
+valuetext(
+ unique int id: @value ref,
+ string text: string ref
+);
+
+valuebind(
+ int val: @value ref,
+ unique int expr: @expr ref
+);
+
+fieldoffsets(
+ unique int id: @variable ref,
+ int byteoffset: int ref,
+ int bitoffset: int ref
+);
+
+bitfield(
+ unique int id: @variable ref,
+ int bits: int ref,
+ int declared_bits: int ref
+);
+
+/* TODO
+memberprefix(
+ int member: @expr ref,
+ int prefix: @expr ref
+);
+*/
+
+/*
+ kind(1) = mbrcallexpr
+ kind(2) = mbrptrcallexpr
+ kind(3) = mbrptrmbrcallexpr
+ kind(4) = ptrmbrptrmbrcallexpr
+ kind(5) = mbrreadexpr // x.y
+ kind(6) = mbrptrreadexpr // p->y
+ kind(7) = mbrptrmbrreadexpr // x.*pm
+ kind(8) = mbrptrmbrptrreadexpr // x->*pm
+ kind(9) = staticmbrreadexpr // static x.y
+ kind(10) = staticmbrptrreadexpr // static p->y
+*/
+/* TODO
+memberaccess(
+ int member: @expr ref,
+ int kind: int ref
+);
+*/
+
+initialisers(
+ unique int init: @initialiser,
+ int var: @accessible ref,
+ unique int expr: @expr ref,
+ int location: @location_default ref
+);
+
+braced_initialisers(
+ int init: @initialiser ref
+);
+
+/**
+ * An ancestor for the expression, for cases in which we cannot
+ * otherwise find the expression's parent.
+ */
+expr_ancestor(
+ int exp: @expr ref,
+ int ancestor: @element ref
+);
+
+exprs(
+ unique int id: @expr,
+ int kind: int ref,
+ int location: @location_default ref
+);
+
+expr_reuse(
+ int reuse: @expr ref,
+ int original: @expr ref,
+ int value_category: int ref
+)
+
+/*
+ case @value.category of
+ 1 = prval
+ | 2 = xval
+ | 3 = lval
+ ;
+*/
+expr_types(
+ int id: @expr ref,
+ int typeid: @type ref,
+ int value_category: int ref
+);
+
+case @expr.kind of
+ 1 = @errorexpr
+| 2 = @address_of // & AddressOfExpr
+| 3 = @reference_to // ReferenceToExpr (implicit?)
+| 4 = @indirect // * PointerDereferenceExpr
+| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?)
+// ...
+| 8 = @array_to_pointer // (???)
+| 9 = @vacuous_destructor_call // VacuousDestructorCall
+// ...
+| 11 = @assume // Microsoft
+| 12 = @parexpr
+| 13 = @arithnegexpr
+| 14 = @unaryplusexpr
+| 15 = @complementexpr
+| 16 = @notexpr
+| 17 = @conjugation // GNU ~ operator
+| 18 = @realpartexpr // GNU __real
+| 19 = @imagpartexpr // GNU __imag
+| 20 = @postincrexpr
+| 21 = @postdecrexpr
+| 22 = @preincrexpr
+| 23 = @predecrexpr
+| 24 = @conditionalexpr
+| 25 = @addexpr
+| 26 = @subexpr
+| 27 = @mulexpr
+| 28 = @divexpr
+| 29 = @remexpr
+| 30 = @jmulexpr // C99 mul imaginary
+| 31 = @jdivexpr // C99 div imaginary
+| 32 = @fjaddexpr // C99 add real + imaginary
+| 33 = @jfaddexpr // C99 add imaginary + real
+| 34 = @fjsubexpr // C99 sub real - imaginary
+| 35 = @jfsubexpr // C99 sub imaginary - real
+| 36 = @paddexpr // pointer add (pointer + int or int + pointer)
+| 37 = @psubexpr // pointer sub (pointer - integer)
+| 38 = @pdiffexpr // difference between two pointers
+| 39 = @lshiftexpr
+| 40 = @rshiftexpr
+| 41 = @andexpr
+| 42 = @orexpr
+| 43 = @xorexpr
+| 44 = @eqexpr
+| 45 = @neexpr
+| 46 = @gtexpr
+| 47 = @ltexpr
+| 48 = @geexpr
+| 49 = @leexpr
+| 50 = @minexpr // GNU minimum
+| 51 = @maxexpr // GNU maximum
+| 52 = @assignexpr
+| 53 = @assignaddexpr
+| 54 = @assignsubexpr
+| 55 = @assignmulexpr
+| 56 = @assigndivexpr
+| 57 = @assignremexpr
+| 58 = @assignlshiftexpr
+| 59 = @assignrshiftexpr
+| 60 = @assignandexpr
+| 61 = @assignorexpr
+| 62 = @assignxorexpr
+| 63 = @assignpaddexpr // assign pointer add
+| 64 = @assignpsubexpr // assign pointer sub
+| 65 = @andlogicalexpr
+| 66 = @orlogicalexpr
+| 67 = @commaexpr
+| 68 = @subscriptexpr // access to member of an array, e.g., a[5]
+// ... 69 @objc_subscriptexpr deprecated
+// ... 70 @cmdaccess deprecated
+// ...
+| 73 = @virtfunptrexpr
+| 74 = @callexpr
+// ... 75 @msgexpr_normal deprecated
+// ... 76 @msgexpr_super deprecated
+// ... 77 @atselectorexpr deprecated
+// ... 78 @atprotocolexpr deprecated
+| 79 = @vastartexpr
+| 80 = @vaargexpr
+| 81 = @vaendexpr
+| 82 = @vacopyexpr
+// ... 83 @atencodeexpr deprecated
+| 84 = @varaccess
+| 85 = @thisaccess
+// ... 86 @objc_box_expr deprecated
+| 87 = @new_expr
+| 88 = @delete_expr
+| 89 = @throw_expr
+| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2)
+| 91 = @braced_init_list
+| 92 = @type_id
+| 93 = @runtime_sizeof
+| 94 = @runtime_alignof
+| 95 = @sizeof_pack
+| 96 = @expr_stmt // GNU extension
+| 97 = @routineexpr
+| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....)
+| 99 = @offsetofexpr // offsetof ::= type and field
+| 100 = @hasassignexpr // __has_assign ::= type
+| 101 = @hascopyexpr // __has_copy ::= type
+| 102 = @hasnothrowassign // __has_nothrow_assign ::= type
+| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type
+| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type
+| 105 = @hastrivialassign // __has_trivial_assign ::= type
+| 106 = @hastrivialconstr // __has_trivial_constructor ::= type
+| 107 = @hastrivialcopy // __has_trivial_copy ::= type
+| 108 = @hasuserdestr // __has_user_destructor ::= type
+| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type
+| 110 = @isabstractexpr // __is_abstract ::= type
+| 111 = @isbaseofexpr // __is_base_of ::= type type
+| 112 = @isclassexpr // __is_class ::= type
+| 113 = @isconvtoexpr // __is_convertible_to ::= type type
+| 114 = @isemptyexpr // __is_empty ::= type
+| 115 = @isenumexpr // __is_enum ::= type
+| 116 = @ispodexpr // __is_pod ::= type
+| 117 = @ispolyexpr // __is_polymorphic ::= type
+| 118 = @isunionexpr // __is_union ::= type
+| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type
+| 120 = @intaddrexpr // frontend internal builtin, used to implement offsetof
+// ...
+| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type
+| 123 = @literal
+| 124 = @uuidof
+| 127 = @aggregateliteral
+| 128 = @delete_array_expr
+| 129 = @new_array_expr
+// ... 130 @objc_array_literal deprecated
+// ... 131 @objc_dictionary_literal deprecated
+| 132 = @foldexpr
+// ...
+| 200 = @ctordirectinit
+| 201 = @ctorvirtualinit
+| 202 = @ctorfieldinit
+| 203 = @ctordelegatinginit
+| 204 = @dtordirectdestruct
+| 205 = @dtorvirtualdestruct
+| 206 = @dtorfielddestruct
+// ...
+| 210 = @static_cast
+| 211 = @reinterpret_cast
+| 212 = @const_cast
+| 213 = @dynamic_cast
+| 214 = @c_style_cast
+| 215 = @lambdaexpr
+| 216 = @param_ref
+| 217 = @noopexpr
+// ...
+| 294 = @istriviallyconstructibleexpr
+| 295 = @isdestructibleexpr
+| 296 = @isnothrowdestructibleexpr
+| 297 = @istriviallydestructibleexpr
+| 298 = @istriviallyassignableexpr
+| 299 = @isnothrowassignableexpr
+| 300 = @istrivialexpr
+| 301 = @isstandardlayoutexpr
+| 302 = @istriviallycopyableexpr
+| 303 = @isliteraltypeexpr
+| 304 = @hastrivialmoveconstructorexpr
+| 305 = @hastrivialmoveassignexpr
+| 306 = @hasnothrowmoveassignexpr
+| 307 = @isconstructibleexpr
+| 308 = @isnothrowconstructibleexpr
+| 309 = @hasfinalizerexpr
+| 310 = @isdelegateexpr
+| 311 = @isinterfaceclassexpr
+| 312 = @isrefarrayexpr
+| 313 = @isrefclassexpr
+| 314 = @issealedexpr
+| 315 = @issimplevalueclassexpr
+| 316 = @isvalueclassexpr
+| 317 = @isfinalexpr
+| 319 = @noexceptexpr
+| 320 = @builtinshufflevector
+| 321 = @builtinchooseexpr
+| 322 = @builtinaddressof
+| 323 = @vec_fill
+| 324 = @builtinconvertvector
+| 325 = @builtincomplex
+| 326 = @spaceshipexpr
+| 327 = @co_await
+| 328 = @co_yield
+| 329 = @temp_init
+| 330 = @isassignable
+| 331 = @isaggregate
+| 332 = @hasuniqueobjectrepresentations
+| 333 = @builtinbitcast
+| 334 = @builtinshuffle
+| 335 = @blockassignexpr
+| 336 = @issame
+| 337 = @isfunction
+| 338 = @islayoutcompatible
+| 339 = @ispointerinterconvertiblebaseof
+| 340 = @isarray
+| 341 = @arrayrank
+| 342 = @arrayextent
+| 343 = @isarithmetic
+| 344 = @iscompletetype
+| 345 = @iscompound
+| 346 = @isconst
+| 347 = @isfloatingpoint
+| 348 = @isfundamental
+| 349 = @isintegral
+| 350 = @islvaluereference
+| 351 = @ismemberfunctionpointer
+| 352 = @ismemberobjectpointer
+| 353 = @ismemberpointer
+| 354 = @isobject
+| 355 = @ispointer
+| 356 = @isreference
+| 357 = @isrvaluereference
+| 358 = @isscalar
+| 359 = @issigned
+| 360 = @isunsigned
+| 361 = @isvoid
+| 362 = @isvolatile
+| 363 = @reuseexpr
+| 364 = @istriviallycopyassignable
+| 365 = @isassignablenopreconditioncheck
+| 366 = @referencebindstotemporary
+| 367 = @issameas
+| 368 = @builtinhasattribute
+| 369 = @ispointerinterconvertiblewithclass
+| 370 = @builtinispointerinterconvertiblewithclass
+| 371 = @iscorrespondingmember
+| 372 = @builtiniscorrespondingmember
+| 373 = @isboundedarray
+| 374 = @isunboundedarray
+| 375 = @isreferenceable
+| 378 = @isnothrowconvertible
+| 379 = @referenceconstructsfromtemporary
+| 380 = @referenceconvertsfromtemporary
+| 381 = @isconvertible
+| 382 = @isvalidwinrttype
+| 383 = @iswinclass
+| 384 = @iswininterface
+| 385 = @istriviallyequalitycomparable
+| 386 = @isscopedenum
+| 387 = @istriviallyrelocatable
+| 388 = @datasizeof
+| 389 = @c11_generic
+| 390 = @requires_expr
+| 391 = @nested_requirement
+| 392 = @compound_requirement
+| 393 = @concept_id
+| 394 = @isinvocable
+| 395 = @isnothrowinvocable
+| 396 = @isbitwisecloneable
+;
+
+@var_args_expr = @vastartexpr
+ | @vaendexpr
+ | @vaargexpr
+ | @vacopyexpr
+ ;
+
+@builtin_op = @var_args_expr
+ | @noopexpr
+ | @offsetofexpr
+ | @intaddrexpr
+ | @hasassignexpr
+ | @hascopyexpr
+ | @hasnothrowassign
+ | @hasnothrowconstr
+ | @hasnothrowcopy
+ | @hastrivialassign
+ | @hastrivialconstr
+ | @hastrivialcopy
+ | @hastrivialdestructor
+ | @hasuserdestr
+ | @hasvirtualdestr
+ | @isabstractexpr
+ | @isbaseofexpr
+ | @isclassexpr
+ | @isconvtoexpr
+ | @isemptyexpr
+ | @isenumexpr
+ | @ispodexpr
+ | @ispolyexpr
+ | @isunionexpr
+ | @typescompexpr
+ | @builtinshufflevector
+ | @builtinconvertvector
+ | @builtinaddressof
+ | @istriviallyconstructibleexpr
+ | @isdestructibleexpr
+ | @isnothrowdestructibleexpr
+ | @istriviallydestructibleexpr
+ | @istriviallyassignableexpr
+ | @isnothrowassignableexpr
+ | @istrivialexpr
+ | @isstandardlayoutexpr
+ | @istriviallycopyableexpr
+ | @isliteraltypeexpr
+ | @hastrivialmoveconstructorexpr
+ | @hastrivialmoveassignexpr
+ | @hasnothrowmoveassignexpr
+ | @isconstructibleexpr
+ | @isnothrowconstructibleexpr
+ | @hasfinalizerexpr
+ | @isdelegateexpr
+ | @isinterfaceclassexpr
+ | @isrefarrayexpr
+ | @isrefclassexpr
+ | @issealedexpr
+ | @issimplevalueclassexpr
+ | @isvalueclassexpr
+ | @isfinalexpr
+ | @builtinchooseexpr
+ | @builtincomplex
+ | @isassignable
+ | @isaggregate
+ | @hasuniqueobjectrepresentations
+ | @builtinbitcast
+ | @builtinshuffle
+ | @issame
+ | @isfunction
+ | @islayoutcompatible
+ | @ispointerinterconvertiblebaseof
+ | @isarray
+ | @arrayrank
+ | @arrayextent
+ | @isarithmetic
+ | @iscompletetype
+ | @iscompound
+ | @isconst
+ | @isfloatingpoint
+ | @isfundamental
+ | @isintegral
+ | @islvaluereference
+ | @ismemberfunctionpointer
+ | @ismemberobjectpointer
+ | @ismemberpointer
+ | @isobject
+ | @ispointer
+ | @isreference
+ | @isrvaluereference
+ | @isscalar
+ | @issigned
+ | @isunsigned
+ | @isvoid
+ | @isvolatile
+ | @istriviallycopyassignable
+ | @isassignablenopreconditioncheck
+ | @referencebindstotemporary
+ | @issameas
+ | @builtinhasattribute
+ | @ispointerinterconvertiblewithclass
+ | @builtinispointerinterconvertiblewithclass
+ | @iscorrespondingmember
+ | @builtiniscorrespondingmember
+ | @isboundedarray
+ | @isunboundedarray
+ | @isreferenceable
+ | @isnothrowconvertible
+ | @referenceconstructsfromtemporary
+ | @referenceconvertsfromtemporary
+ | @isconvertible
+ | @isvalidwinrttype
+ | @iswinclass
+ | @iswininterface
+ | @istriviallyequalitycomparable
+ | @isscopedenum
+ | @istriviallyrelocatable
+ | @isinvocable
+ | @isnothrowinvocable
+ | @isbitwisecloneable
+ ;
+
+compound_requirement_is_noexcept(
+ int expr: @compound_requirement ref
+);
+
+new_allocated_type(
+ unique int expr: @new_expr ref,
+ int type_id: @type ref
+);
+
+new_array_allocated_type(
+ unique int expr: @new_array_expr ref,
+ int type_id: @type ref
+);
+
+param_ref_to_this(
+ int expr: @param_ref ref
+)
+
+/**
+ * The field being initialized by an initializer expression within an aggregate
+ * initializer for a class/struct/union. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_field_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int field: @membervariable ref,
+ int position: int ref,
+ boolean is_designated: boolean ref
+);
+
+/**
+ * The index of the element being initialized by an initializer expression
+ * within an aggregate initializer for an array. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_array_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int element_index: int ref,
+ int position: int ref,
+ boolean is_designated: boolean ref
+);
+
+@ctorinit = @ctordirectinit
+ | @ctorvirtualinit
+ | @ctorfieldinit
+ | @ctordelegatinginit;
+@dtordestruct = @dtordirectdestruct
+ | @dtorvirtualdestruct
+ | @dtorfielddestruct;
+
+
+condition_decl_bind(
+ unique int expr: @condition_decl ref,
+ unique int decl: @declaration ref
+);
+
+typeid_bind(
+ unique int expr: @type_id ref,
+ int type_id: @type ref
+);
+
+uuidof_bind(
+ unique int expr: @uuidof ref,
+ int type_id: @type ref
+);
+
+@sizeof_or_alignof = @runtime_sizeof | @runtime_alignof | @datasizeof | @sizeof_pack;
+
+sizeof_bind(
+ unique int expr: @sizeof_or_alignof ref,
+ int type_id: @type ref
+);
+
+code_block(
+ unique int block: @literal ref,
+ unique int routine: @function ref
+);
+
+lambdas(
+ unique int expr: @lambdaexpr ref,
+ string default_capture: string ref,
+ boolean has_explicit_return_type: boolean ref,
+ boolean has_explicit_parameter_list: boolean ref
+);
+
+lambda_capture(
+ unique int id: @lambdacapture,
+ int lambda: @lambdaexpr ref,
+ int index: int ref,
+ int field: @membervariable ref,
+ boolean captured_by_reference: boolean ref,
+ boolean is_implicit: boolean ref,
+ int location: @location_default ref
+);
+
+@funbindexpr = @routineexpr
+ | @new_expr
+ | @delete_expr
+ | @delete_array_expr
+ | @ctordirectinit
+ | @ctorvirtualinit
+ | @ctordelegatinginit
+ | @dtordirectdestruct
+ | @dtorvirtualdestruct;
+
+@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct;
+@addressable = @function | @variable ;
+@accessible = @addressable | @enumconstant ;
+
+@access = @varaccess | @routineexpr ;
+
+fold(
+ int expr: @foldexpr ref,
+ string operator: string ref,
+ boolean is_left_fold: boolean ref
+);
+
+stmts(
+ unique int id: @stmt,
+ int kind: int ref,
+ int location: @location_default ref
+);
+
+case @stmt.kind of
+ 1 = @stmt_expr
+| 2 = @stmt_if
+| 3 = @stmt_while
+| 4 = @stmt_goto
+| 5 = @stmt_label
+| 6 = @stmt_return
+| 7 = @stmt_block
+| 8 = @stmt_end_test_while // do { ... } while ( ... )
+| 9 = @stmt_for
+| 10 = @stmt_switch_case
+| 11 = @stmt_switch
+| 13 = @stmt_asm // "asm" statement or the body of an asm function
+| 15 = @stmt_try_block
+| 16 = @stmt_microsoft_try // Microsoft
+| 17 = @stmt_decl
+| 18 = @stmt_set_vla_size // C99
+| 19 = @stmt_vla_decl // C99
+| 25 = @stmt_assigned_goto // GNU
+| 26 = @stmt_empty
+| 27 = @stmt_continue
+| 28 = @stmt_break
+| 29 = @stmt_range_based_for // C++11
+// ... 30 @stmt_at_autoreleasepool_block deprecated
+// ... 31 @stmt_objc_for_in deprecated
+// ... 32 @stmt_at_synchronized deprecated
+| 33 = @stmt_handler
+// ... 34 @stmt_finally_end deprecated
+| 35 = @stmt_constexpr_if
+| 37 = @stmt_co_return
+| 38 = @stmt_consteval_if
+| 39 = @stmt_not_consteval_if
+| 40 = @stmt_leave
+;
+
+type_vla(
+ int type_id: @type ref,
+ int decl: @stmt_vla_decl ref
+);
+
+variable_vla(
+ int var: @variable ref,
+ int decl: @stmt_vla_decl ref
+);
+
+type_is_vla(unique int type_id: @derivedtype ref)
+
+if_initialization(
+ unique int if_stmt: @stmt_if ref,
+ int init_id: @stmt ref
+);
+
+if_then(
+ unique int if_stmt: @stmt_if ref,
+ int then_id: @stmt ref
+);
+
+if_else(
+ unique int if_stmt: @stmt_if ref,
+ int else_id: @stmt ref
+);
+
+constexpr_if_initialization(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int init_id: @stmt ref
+);
+
+constexpr_if_then(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int then_id: @stmt ref
+);
+
+constexpr_if_else(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int else_id: @stmt ref
+);
+
+@stmt_consteval_or_not_consteval_if = @stmt_consteval_if | @stmt_not_consteval_if;
+
+consteval_if_then(
+ unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref,
+ int then_id: @stmt ref
+);
+
+consteval_if_else(
+ unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref,
+ int else_id: @stmt ref
+);
+
+while_body(
+ unique int while_stmt: @stmt_while ref,
+ int body_id: @stmt ref
+);
+
+do_body(
+ unique int do_stmt: @stmt_end_test_while ref,
+ int body_id: @stmt ref
+);
+
+switch_initialization(
+ unique int switch_stmt: @stmt_switch ref,
+ int init_id: @stmt ref
+);
+
+#keyset[switch_stmt, index]
+switch_case(
+ int switch_stmt: @stmt_switch ref,
+ int index: int ref,
+ int case_id: @stmt_switch_case ref
+);
+
+switch_body(
+ unique int switch_stmt: @stmt_switch ref,
+ int body_id: @stmt ref
+);
+
+@stmt_for_or_range_based_for = @stmt_for
+ | @stmt_range_based_for;
+
+for_initialization(
+ unique int for_stmt: @stmt_for_or_range_based_for ref,
+ int init_id: @stmt ref
+);
+
+for_condition(
+ unique int for_stmt: @stmt_for ref,
+ int condition_id: @expr ref
+);
+
+for_update(
+ unique int for_stmt: @stmt_for ref,
+ int update_id: @expr ref
+);
+
+for_body(
+ unique int for_stmt: @stmt_for ref,
+ int body_id: @stmt ref
+);
+
+@stmtparent = @stmt | @expr_stmt ;
+stmtparents(
+ unique int id: @stmt ref,
+ int index: int ref,
+ int parent: @stmtparent ref
+);
+
+ishandler(unique int block: @stmt_block ref);
+
+@cfgnode = @stmt | @expr | @function | @initialiser ;
+
+stmt_decl_bind(
+ int stmt: @stmt_decl ref,
+ int num: int ref,
+ int decl: @declaration ref
+);
+
+stmt_decl_entry_bind(
+ int stmt: @stmt_decl ref,
+ int num: int ref,
+ int decl_entry: @element ref
+);
+
+@parameterized_element = @function | @stmt_block | @requires_expr;
+
+blockscope(
+ unique int block: @stmt_block ref,
+ int enclosing: @parameterized_element ref
+);
+
+@jump = @stmt_goto | @stmt_break | @stmt_continue | @stmt_leave;
+
+@jumporlabel = @jump | @stmt_label | @literal;
+
+jumpinfo(
+ unique int id: @jumporlabel ref,
+ string str: string ref,
+ int target: @stmt ref
+);
+
+preprocdirects(
+ unique int id: @preprocdirect,
+ int kind: int ref,
+ int location: @location_default ref
+);
+case @preprocdirect.kind of
+ 0 = @ppd_if
+| 1 = @ppd_ifdef
+| 2 = @ppd_ifndef
+| 3 = @ppd_elif
+| 4 = @ppd_else
+| 5 = @ppd_endif
+| 6 = @ppd_plain_include
+| 7 = @ppd_define
+| 8 = @ppd_undef
+| 9 = @ppd_line
+| 10 = @ppd_error
+| 11 = @ppd_pragma
+| 12 = @ppd_objc_import
+| 13 = @ppd_include_next
+| 14 = @ppd_ms_import
+| 15 = @ppd_elifdef
+| 16 = @ppd_elifndef
+| 17 = @ppd_embed
+| 18 = @ppd_warning
+;
+
+@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next | @ppd_ms_import;
+
+@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif | @ppd_elifdef | @ppd_elifndef;
+
+preprocpair(
+ int begin : @ppd_branch ref,
+ int elseelifend : @preprocdirect ref
+);
+
+preproctrue(int branch : @ppd_branch ref);
+preprocfalse(int branch : @ppd_branch ref);
+
+preproctext(
+ unique int id: @preprocdirect ref,
+ string head: string ref,
+ string body: string ref
+);
+
+includes(
+ unique int id: @ppd_include ref,
+ int included: @file ref
+);
+
+embeds(
+ unique int id: @ppd_embed ref,
+ int included: @file ref
+);
+
+link_targets(
+ int id: @link_target,
+ int binary: @file ref
+);
+
+link_parent(
+ int element : @element ref,
+ int link_target : @link_target ref
+);
+
+/*- Database metadata -*/
+
+/**
+ * The CLI will automatically emit applicable tuples for this table,
+ * such as `databaseMetadata("isOverlay", "true")` when building an
+ * overlay database.
+ */
+databaseMetadata(
+ string metadataKey: string ref,
+ string value: string ref
+);
+
+/*- Overlay support -*/
+
+/**
+ * The CLI will automatically emit tuples for each new/modified/deleted file
+ * when building an overlay database.
+ */
+overlayChangedFiles(
+ string path: string ref
+);
+
+/*- XML Files -*/
+
+xmlEncoding(
+ unique int id: @file ref,
+ string encoding: string ref
+);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref
+);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref
+);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref
+);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref
+);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref
+);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref
+);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref
+);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref
+);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
diff --git a/cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/source_file_uses_trap.ql b/cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/source_file_uses_trap.ql
new file mode 100644
index 00000000000..7e91f4e0b86
--- /dev/null
+++ b/cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/source_file_uses_trap.ql
@@ -0,0 +1,13 @@
+class SourceFile extends @source_file {
+ string toString() { none() }
+}
+
+class Trap extends @trap {
+ string toString() { none() }
+}
+
+from SourceFile source_file, string name, Trap trap
+where
+ source_file_uses_trap(source_file, trap) and
+ source_file_name(source_file, name)
+select name, trap
diff --git a/cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/upgrade.properties b/cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/upgrade.properties
new file mode 100644
index 00000000000..8b75a52f182
--- /dev/null
+++ b/cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/upgrade.properties
@@ -0,0 +1,8 @@
+description: Add source_file_name
+compatibility: backwards
+source_file_uses_trap.rel: run source_file_uses_trap.ql
+source_file_name.rel: delete
+tag_name.rel: delete
+trap_uses_tag.rel: delete
+in_trap.rel: run in_trap.ql
+in_trap_or_tag.rel: delete
diff --git a/cpp/ql/integration-tests/query-suite/cpp-code-scanning.qls.expected b/cpp/ql/integration-tests/query-suite/cpp-code-scanning.qls.expected
index 33c02079fff..d4b80599950 100644
--- a/cpp/ql/integration-tests/query-suite/cpp-code-scanning.qls.expected
+++ b/cpp/ql/integration-tests/query-suite/cpp-code-scanning.qls.expected
@@ -7,10 +7,12 @@ ql/cpp/ql/src/Diagnostics/ExtractedFiles.ql
ql/cpp/ql/src/Diagnostics/ExtractionWarnings.ql
ql/cpp/ql/src/Diagnostics/FailedExtractorInvocations.ql
ql/cpp/ql/src/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql
+ql/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql
ql/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
ql/cpp/ql/src/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql
ql/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql
ql/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql
+ql/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
ql/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql
ql/cpp/ql/src/Likely Bugs/Memory Management/PointerOverflow.ql
ql/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql
@@ -28,6 +30,7 @@ ql/cpp/ql/src/Security/CWE/CWE-120/VeryLikelyOverrunWrite.ql
ql/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
ql/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql
ql/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql
+ql/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
ql/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql
ql/cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql
ql/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql
@@ -40,6 +43,7 @@ ql/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql
ql/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.ql
ql/cpp/ql/src/Security/CWE/CWE-416/UseOfStringAfterLifetimeEnds.ql
ql/cpp/ql/src/Security/CWE/CWE-416/UseOfUniquePointerAfterLifetimeEnds.ql
+ql/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql
ql/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql
ql/cpp/ql/src/Security/CWE/CWE-611/XXE.ql
ql/cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.ql
@@ -52,5 +56,6 @@ ql/cpp/ql/src/Summary/LinesOfUserCode.ql
ql/cpp/ql/src/Telemetry/CompilerErrors.ql
ql/cpp/ql/src/Telemetry/DatabaseQuality.ql
ql/cpp/ql/src/Telemetry/ExtractionMetrics.ql
+ql/cpp/ql/src/Telemetry/ExtractorInformation.ql
ql/cpp/ql/src/Telemetry/MissingIncludes.ql
ql/cpp/ql/src/Telemetry/SucceededIncludes.ql
diff --git a/cpp/ql/integration-tests/query-suite/cpp-security-and-quality.qls.expected b/cpp/ql/integration-tests/query-suite/cpp-security-and-quality.qls.expected
index 9ef67d525cd..cb4e5f7b305 100644
--- a/cpp/ql/integration-tests/query-suite/cpp-security-and-quality.qls.expected
+++ b/cpp/ql/integration-tests/query-suite/cpp-security-and-quality.qls.expected
@@ -160,6 +160,7 @@ ql/cpp/ql/src/Summary/LinesOfUserCode.ql
ql/cpp/ql/src/Telemetry/CompilerErrors.ql
ql/cpp/ql/src/Telemetry/DatabaseQuality.ql
ql/cpp/ql/src/Telemetry/ExtractionMetrics.ql
+ql/cpp/ql/src/Telemetry/ExtractorInformation.ql
ql/cpp/ql/src/Telemetry/MissingIncludes.ql
ql/cpp/ql/src/Telemetry/SucceededIncludes.ql
ql/cpp/ql/src/jsf/4.06 Pre-Processing Directives/AV Rule 32.ql
diff --git a/cpp/ql/integration-tests/query-suite/cpp-security-extended.qls.expected b/cpp/ql/integration-tests/query-suite/cpp-security-extended.qls.expected
index f014b6d5dc5..7c5e3d98c5c 100644
--- a/cpp/ql/integration-tests/query-suite/cpp-security-extended.qls.expected
+++ b/cpp/ql/integration-tests/query-suite/cpp-security-extended.qls.expected
@@ -93,5 +93,6 @@ ql/cpp/ql/src/Summary/LinesOfUserCode.ql
ql/cpp/ql/src/Telemetry/CompilerErrors.ql
ql/cpp/ql/src/Telemetry/DatabaseQuality.ql
ql/cpp/ql/src/Telemetry/ExtractionMetrics.ql
+ql/cpp/ql/src/Telemetry/ExtractorInformation.ql
ql/cpp/ql/src/Telemetry/MissingIncludes.ql
ql/cpp/ql/src/Telemetry/SucceededIncludes.ql
diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md
index 6f256c9499b..2cd1bcede35 100644
--- a/cpp/ql/lib/CHANGELOG.md
+++ b/cpp/ql/lib/CHANGELOG.md
@@ -1,3 +1,69 @@
+## 10.0.0
+
+### Breaking Changes
+
+* The deprecated `NonThrowingFunction` class has been removed, use `NonCppThrowingFunction` instead.
+* The deprecated `ThrowingFunction` class has been removed, use `AlwaysSehThrowingFunction` instead.
+
+### New Features
+
+* Added a subclass `AutoconfConfigureTestFile` of `ConfigurationTestFile` that represents files created by GNU autoconf configure scripts to test the build configuration.
+
+## 9.0.0
+
+### Breaking Changes
+
+* The `SourceModelCsv`, `SinkModelCsv`, and `SummaryModelCsv` classes and the associated CSV parsing infrastructure have been removed from `ExternalFlow.qll`. New models should be added as `.model.yml` files in the `ext/` directory.
+
+### New Features
+
+* Added a subclass `MesonPrivateTestFile` of `ConfigurationTestFile` that represents files created by Meson to test the build configuration.
+* Added a class `ConstructorDirectFieldInit` to represent field initializations that occur in member initializer lists.
+* Added a class `ConstructorDefaultFieldInit` to represent default field initializations.
+* Added a class `DataFlow::IndirectParameterNode` to represent the indirection of a parameter as a dataflow node.
+* Added a predicate `Node::asIndirectInstruction` which returns the `Instruction` that defines the indirect dataflow node, if any.
+* Added a class `IndirectUninitializedNode` to represent the indirection of an uninitialized local variable as a dataflow node.
+
+### Minor Analysis Improvements
+
+* Added `HttpReceiveHttpRequest`, `HttpReceiveRequestEntityBody`, and `HttpReceiveClientCertificate` from Win32's `http.h` as remote flow sources.
+* Added dataflow through members initialized via non-static data member initialization (NSDMI).
+
+## 8.0.3
+
+No user-facing changes.
+
+## 8.0.2
+
+No user-facing changes.
+
+## 8.0.1
+
+### Minor Analysis Improvements
+
+* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.
+
+## 8.0.0
+
+### Breaking Changes
+
+* CodeQL version 2.24.2 accidentally introduced a syntactical breaking change to `BarrierGuard<...>::getAnIndirectBarrierNode` and `InstructionBarrierGuard<...>::getAnIndirectBarrierNode`. These breaking changes have now been reverted so that the original code compiles again.
+* `MustFlow`, the inter-procedural must-flow data flow analysis library, has been re-worked to use parameterized modules. Like in the case of data flow and taint tracking, instead of extending the `MustFlowConfiguration` class, the user should now implement a module with the `MustFlow::ConfigSig` signature, and instantiate the `MustFlow::Global` parameterized module with the implemented module.
+
+### Minor Analysis Improvements
+
+* Refactored the "Year field changed using an arithmetic operation without checking for leap year" query (`cpp/leap-year/unchecked-after-arithmetic-year-modification`) to address large numbers of false positive results.
+
+### Bug Fixes
+
+* The `allowInterproceduralFlow` predicate of must-flow data flow configurations now correctly handles direct recursion.
+
+## 7.1.1
+
+### Minor Analysis Improvements
+
+* Added remote flow source models for the `winhttp.h` windows header and the Azure SDK core library for C/C++.
+
## 7.1.0
### New Features
diff --git a/cpp/ql/lib/change-notes/2026-02-03-windows-remote-flow-sources.md b/cpp/ql/lib/change-notes/2026-02-03-windows-remote-flow-sources.md
deleted file mode 100644
index 0a884df065a..00000000000
--- a/cpp/ql/lib/change-notes/2026-02-03-windows-remote-flow-sources.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Added remote flow source models for the `winhttp.h` windows header and the Azure SDK core library for C/C++.
\ No newline at end of file
diff --git a/cpp/ql/lib/change-notes/2026-03-20-data-extensions-barriers.md b/cpp/ql/lib/change-notes/2026-03-20-data-extensions-barriers.md
new file mode 100644
index 00000000000..30f0092a4e9
--- /dev/null
+++ b/cpp/ql/lib/change-notes/2026-03-20-data-extensions-barriers.md
@@ -0,0 +1,4 @@
+---
+category: feature
+---
+* Data flow barriers and barrier guards can now be added using data extensions. For more information see [Customizing library models for C and C++](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-cpp/).
diff --git a/cpp/ql/lib/change-notes/released/10.0.0.md b/cpp/ql/lib/change-notes/released/10.0.0.md
new file mode 100644
index 00000000000..af591bd1a0a
--- /dev/null
+++ b/cpp/ql/lib/change-notes/released/10.0.0.md
@@ -0,0 +1,10 @@
+## 10.0.0
+
+### Breaking Changes
+
+* The deprecated `NonThrowingFunction` class has been removed, use `NonCppThrowingFunction` instead.
+* The deprecated `ThrowingFunction` class has been removed, use `AlwaysSehThrowingFunction` instead.
+
+### New Features
+
+* Added a subclass `AutoconfConfigureTestFile` of `ConfigurationTestFile` that represents files created by GNU autoconf configure scripts to test the build configuration.
diff --git a/cpp/ql/lib/change-notes/released/7.1.1.md b/cpp/ql/lib/change-notes/released/7.1.1.md
new file mode 100644
index 00000000000..16bba7ca508
--- /dev/null
+++ b/cpp/ql/lib/change-notes/released/7.1.1.md
@@ -0,0 +1,5 @@
+## 7.1.1
+
+### Minor Analysis Improvements
+
+* Added remote flow source models for the `winhttp.h` windows header and the Azure SDK core library for C/C++.
diff --git a/cpp/ql/lib/change-notes/released/8.0.0.md b/cpp/ql/lib/change-notes/released/8.0.0.md
new file mode 100644
index 00000000000..36d58d9bd99
--- /dev/null
+++ b/cpp/ql/lib/change-notes/released/8.0.0.md
@@ -0,0 +1,14 @@
+## 8.0.0
+
+### Breaking Changes
+
+* CodeQL version 2.24.2 accidentally introduced a syntactical breaking change to `BarrierGuard<...>::getAnIndirectBarrierNode` and `InstructionBarrierGuard<...>::getAnIndirectBarrierNode`. These breaking changes have now been reverted so that the original code compiles again.
+* `MustFlow`, the inter-procedural must-flow data flow analysis library, has been re-worked to use parameterized modules. Like in the case of data flow and taint tracking, instead of extending the `MustFlowConfiguration` class, the user should now implement a module with the `MustFlow::ConfigSig` signature, and instantiate the `MustFlow::Global` parameterized module with the implemented module.
+
+### Minor Analysis Improvements
+
+* Refactored the "Year field changed using an arithmetic operation without checking for leap year" query (`cpp/leap-year/unchecked-after-arithmetic-year-modification`) to address large numbers of false positive results.
+
+### Bug Fixes
+
+* The `allowInterproceduralFlow` predicate of must-flow data flow configurations now correctly handles direct recursion.
diff --git a/cpp/ql/lib/change-notes/released/8.0.1.md b/cpp/ql/lib/change-notes/released/8.0.1.md
new file mode 100644
index 00000000000..46866df058a
--- /dev/null
+++ b/cpp/ql/lib/change-notes/released/8.0.1.md
@@ -0,0 +1,5 @@
+## 8.0.1
+
+### Minor Analysis Improvements
+
+* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.
diff --git a/cpp/ql/lib/change-notes/released/8.0.2.md b/cpp/ql/lib/change-notes/released/8.0.2.md
new file mode 100644
index 00000000000..8119db7ca7b
--- /dev/null
+++ b/cpp/ql/lib/change-notes/released/8.0.2.md
@@ -0,0 +1,3 @@
+## 8.0.2
+
+No user-facing changes.
diff --git a/cpp/ql/lib/change-notes/released/8.0.3.md b/cpp/ql/lib/change-notes/released/8.0.3.md
new file mode 100644
index 00000000000..de146c6309e
--- /dev/null
+++ b/cpp/ql/lib/change-notes/released/8.0.3.md
@@ -0,0 +1,3 @@
+## 8.0.3
+
+No user-facing changes.
diff --git a/cpp/ql/lib/change-notes/released/9.0.0.md b/cpp/ql/lib/change-notes/released/9.0.0.md
new file mode 100644
index 00000000000..2f97209a02d
--- /dev/null
+++ b/cpp/ql/lib/change-notes/released/9.0.0.md
@@ -0,0 +1,19 @@
+## 9.0.0
+
+### Breaking Changes
+
+* The `SourceModelCsv`, `SinkModelCsv`, and `SummaryModelCsv` classes and the associated CSV parsing infrastructure have been removed from `ExternalFlow.qll`. New models should be added as `.model.yml` files in the `ext/` directory.
+
+### New Features
+
+* Added a subclass `MesonPrivateTestFile` of `ConfigurationTestFile` that represents files created by Meson to test the build configuration.
+* Added a class `ConstructorDirectFieldInit` to represent field initializations that occur in member initializer lists.
+* Added a class `ConstructorDefaultFieldInit` to represent default field initializations.
+* Added a class `DataFlow::IndirectParameterNode` to represent the indirection of a parameter as a dataflow node.
+* Added a predicate `Node::asIndirectInstruction` which returns the `Instruction` that defines the indirect dataflow node, if any.
+* Added a class `IndirectUninitializedNode` to represent the indirection of an uninitialized local variable as a dataflow node.
+
+### Minor Analysis Improvements
+
+* Added `HttpReceiveHttpRequest`, `HttpReceiveRequestEntityBody`, and `HttpReceiveClientCertificate` from Win32's `http.h` as remote flow sources.
+* Added dataflow through members initialized via non-static data member initialization (NSDMI).
diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml
index dcaaa76112a..28758256b94 100644
--- a/cpp/ql/lib/codeql-pack.release.yml
+++ b/cpp/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 7.1.0
+lastReleaseVersion: 10.0.0
diff --git a/cpp/ql/lib/ext/Windows.model.yml b/cpp/ql/lib/ext/Windows.model.yml
index a2ec30d95bd..6794e9a8664 100644
--- a/cpp/ql/lib/ext/Windows.model.yml
+++ b/cpp/ql/lib/ext/Windows.model.yml
@@ -31,6 +31,9 @@ extensions:
- ["", "", False, "WinHttpQueryHeadersEx", "", "", "Argument[*5]", "remote", "manual"]
- ["", "", False, "WinHttpQueryHeadersEx", "", "", "Argument[*6]", "remote", "manual"]
- ["", "", False, "WinHttpQueryHeadersEx", "", "", "Argument[**8]", "remote", "manual"]
+ - ["", "", False, "HttpReceiveHttpRequest", "", "", "Argument[*3]", "remote", "manual"]
+ - ["", "", False, "HttpReceiveRequestEntityBody", "", "", "Argument[*3]", "remote", "manual"]
+ - ["", "", False, "HttpReceiveClientCertificate", "", "", "Argument[*3]", "remote", "manual"]
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
diff --git a/cpp/ql/lib/ext/ZMQ.model.yml b/cpp/ql/lib/ext/ZMQ.model.yml
new file mode 100644
index 00000000000..62c3bb1a3bf
--- /dev/null
+++ b/cpp/ql/lib/ext/ZMQ.model.yml
@@ -0,0 +1,22 @@
+# ZeroMQ networking library models
+extensions:
+ - addsTo:
+ pack: codeql/cpp-all
+ extensible: sourceModel
+ data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
+ - ["", "", False, "zmq_recv", "", "", "Argument[*1]", "remote", "manual"]
+ - ["", "", False, "zmq_recvmsg", "", "", "Argument[*1]", "remote", "manual"]
+ - ["", "", False, "zmq_msg_recv", "", "", "Argument[*0]", "remote", "manual"]
+ - addsTo:
+ pack: codeql/cpp-all
+ extensible: sinkModel
+ data: # namespace, type, subtypes, name, signature, ext, input, kind, provenance
+ - ["", "", False, "zmq_send", "", "", "Argument[*1]", "remote-sink", "manual"]
+ - ["", "", False, "zmq_sendmsg", "", "", "Argument[*1]", "remote-sink", "manual"]
+ - ["", "", False, "zmq_msg_send", "", "", "Argument[*0]", "remote-sink", "manual"]
+ - addsTo:
+ pack: codeql/cpp-all
+ extensible: summaryModel
+ data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
+ - ["", "", False, "zmq_msg_init_data", "", "", "Argument[*1]", "Argument[*0]", "taint", "manual"]
+ - ["", "", False, "zmq_msg_data", "", "", "Argument[*0]", "ReturnValue[*]", "taint", "manual"]
diff --git a/cpp/ql/lib/ext/allocation/Std.allocation.model.yml b/cpp/ql/lib/ext/allocation/Std.allocation.model.yml
index 16b3d5bceba..227cc4176c0 100644
--- a/cpp/ql/lib/ext/allocation/Std.allocation.model.yml
+++ b/cpp/ql/lib/ext/allocation/Std.allocation.model.yml
@@ -12,4 +12,7 @@ extensions:
- ["", "", False, "_malloca", "0", "", "", False]
- ["", "", False, "calloc", "1", "0", "", True]
- ["std", "", False, "calloc", "1", "0", "", True]
- - ["bsl", "", False, "calloc", "1", "0", "", True]
\ No newline at end of file
+ - ["bsl", "", False, "calloc", "1", "0", "", True]
+ - ["", "", False, "aligned_alloc", "1", "", "", True]
+ - ["std", "", False, "aligned_alloc", "1", "", "", True]
+ - ["bsl", "", False, "aligned_alloc", "1", "", "", True]
diff --git a/cpp/ql/lib/ext/getc.model.yml b/cpp/ql/lib/ext/getc.model.yml
new file mode 100644
index 00000000000..43958205e0b
--- /dev/null
+++ b/cpp/ql/lib/ext/getc.model.yml
@@ -0,0 +1,19 @@
+# Models for getc and similar character-reading functions
+extensions:
+ - addsTo:
+ pack: codeql/cpp-all
+ extensible: sourceModel
+ data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
+ - ["", "", False, "getc", "", "", "ReturnValue", "remote", "manual"]
+ - ["", "", False, "getwc", "", "", "ReturnValue", "remote", "manual"]
+ - ["", "", False, "_getc_nolock", "", "", "ReturnValue", "remote", "manual"]
+ - ["", "", False, "_getwc_nolock", "", "", "ReturnValue", "remote", "manual"]
+ - ["", "", False, "getch", "", "", "ReturnValue", "local", "manual"]
+ - ["", "", False, "_getch", "", "", "ReturnValue", "local", "manual"]
+ - ["", "", False, "_getwch", "", "", "ReturnValue", "local", "manual"]
+ - ["", "", False, "_getch_nolock", "", "", "ReturnValue", "local", "manual"]
+ - ["", "", False, "_getwch_nolock", "", "", "ReturnValue", "local", "manual"]
+ - ["", "", False, "getchar", "", "", "ReturnValue", "local", "manual"]
+ - ["", "", False, "getwchar", "", "", "ReturnValue", "local", "manual"]
+ - ["", "", False, "_getchar_nolock", "", "", "ReturnValue", "local", "manual"]
+ - ["", "", False, "_getwchar_nolock", "", "", "ReturnValue", "local", "manual"]
diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml
index eeb5d0adf08..8a9d60a7fa9 100644
--- a/cpp/ql/lib/qlpack.yml
+++ b/cpp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-all
-version: 7.1.1-dev
+version: 10.0.1-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
diff --git a/cpp/ql/lib/semmle/code/cpp/ConfigurationTestFile.qll b/cpp/ql/lib/semmle/code/cpp/ConfigurationTestFile.qll
index fe89a556f74..ae90caa0e63 100644
--- a/cpp/ql/lib/semmle/code/cpp/ConfigurationTestFile.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ConfigurationTestFile.qll
@@ -26,3 +26,26 @@ class CmakeTryCompileFile extends ConfigurationTestFile {
)
}
}
+
+/**
+ * A file created by Meson to test the system configuration.
+ */
+class MesonPrivateTestFile extends ConfigurationTestFile {
+ MesonPrivateTestFile() {
+ this.getBaseName() = "testfile.c" and
+ exists(Folder folder, Folder parent |
+ folder = this.getParentContainer() and
+ parent = folder.getParentContainer()
+ |
+ folder.getBaseName().matches("tmp%") and
+ parent.getBaseName() = "meson-private"
+ )
+ }
+}
+
+/**
+ * A file created by a GNU autoconf configure script to test the system configuration.
+ */
+class AutoconfConfigureTestFile extends ConfigurationTestFile {
+ AutoconfConfigureTestFile() { this.getBaseName().regexpMatch("conftest[0-9]*\\.c(pp)?") }
+}
diff --git a/cpp/ql/lib/semmle/code/cpp/Function.qll b/cpp/ql/lib/semmle/code/cpp/Function.qll
index 10b156e3fb6..8d93ac0f2a3 100644
--- a/cpp/ql/lib/semmle/code/cpp/Function.qll
+++ b/cpp/ql/lib/semmle/code/cpp/Function.qll
@@ -524,6 +524,12 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
not exists(NewOrNewArrayExpr new | e = new.getAllocatorCall().getArgument(0))
)
}
+
+ /**
+ * Holds if this function has an ambiguous return type, meaning that zero or multiple return
+ * types for this function are present in the database (this can occur in `build-mode: none`).
+ */
+ predicate hasAmbiguousReturnType() { count(this.getType()) != 1 }
}
pragma[noinline]
diff --git a/cpp/ql/lib/semmle/code/cpp/commons/DateTime.qll b/cpp/ql/lib/semmle/code/cpp/commons/DateTime.qll
index c67bf7cf96e..a4022161076 100644
--- a/cpp/ql/lib/semmle/code/cpp/commons/DateTime.qll
+++ b/cpp/ql/lib/semmle/code/cpp/commons/DateTime.qll
@@ -14,7 +14,9 @@ class PackedTimeType extends Type {
}
}
-private predicate timeType(string typeName) { typeName = ["_SYSTEMTIME", "SYSTEMTIME", "tm"] }
+private predicate timeType(string typeName) {
+ typeName = ["_SYSTEMTIME", "SYSTEMTIME", "tm", "TIME_FIELDS", "_TIME_FIELDS", "PTIME_FIELDS"]
+}
/**
* A type that is used to represent times and dates in an 'unpacked' form, that is,
@@ -95,3 +97,24 @@ class StructTmMonthFieldAccess extends MonthFieldAccess {
class StructTmYearFieldAccess extends YearFieldAccess {
StructTmYearFieldAccess() { this.getTarget().getName() = "tm_year" }
}
+
+/**
+ * A `DayFieldAccess` for the `TIME_FIELDS` struct.
+ */
+class TimeFieldsDayFieldAccess extends DayFieldAccess {
+ TimeFieldsDayFieldAccess() { this.getTarget().getName() = "Day" }
+}
+
+/**
+ * A `MonthFieldAccess` for the `TIME_FIELDS` struct.
+ */
+class TimeFieldsMonthFieldAccess extends MonthFieldAccess {
+ TimeFieldsMonthFieldAccess() { this.getTarget().getName() = "Month" }
+}
+
+/**
+ * A `YearFieldAccess` for the `TIME_FIELDS` struct.
+ */
+class TimeFieldsYearFieldAccess extends YearFieldAccess {
+ TimeFieldsYearFieldAccess() { this.getTarget().getName() = "Year" }
+}
diff --git a/cpp/ql/lib/semmle/code/cpp/commons/Printf.qll b/cpp/ql/lib/semmle/code/cpp/commons/Printf.qll
index 023ce09c5c1..624465761c2 100644
--- a/cpp/ql/lib/semmle/code/cpp/commons/Printf.qll
+++ b/cpp/ql/lib/semmle/code/cpp/commons/Printf.qll
@@ -163,12 +163,23 @@ predicate primitiveVariadicFormatter(
)
}
+/**
+ * Gets a function call whose target is a variadic formatter with the given
+ * `type`, `format` parameter index and `output` parameter index.
+ *
+ * Join-order helper for `callsVariadicFormatter`.
+ */
+pragma[nomagic]
+private predicate callsVariadicFormatterCall(FunctionCall fc, string type, int format, int output) {
+ variadicFormatter(fc.getTarget(), type, format, output)
+}
+
private predicate callsVariadicFormatter(
Function f, string type, int formatParamIndex, int outputParamIndex
) {
// calls a variadic formatter with `formatParamIndex`, `outputParamIndex` linked
exists(FunctionCall fc, int format, int output |
- variadicFormatter(pragma[only_bind_into](fc.getTarget()), type, format, output) and
+ callsVariadicFormatterCall(fc, type, format, output) and
fc.getEnclosingFunction() = f and
fc.getArgument(format) = f.getParameter(formatParamIndex).getAnAccess() and
fc.getArgument(output) = f.getParameter(outputParamIndex).getAnAccess()
@@ -176,7 +187,7 @@ private predicate callsVariadicFormatter(
or
// calls a variadic formatter with only `formatParamIndex` linked
exists(FunctionCall fc, string calledType, int format, int output |
- variadicFormatter(pragma[only_bind_into](fc.getTarget()), calledType, format, output) and
+ callsVariadicFormatterCall(fc, calledType, format, output) and
fc.getEnclosingFunction() = f and
fc.getArgument(format) = f.getParameter(formatParamIndex).getAnAccess() and
not fc.getArgument(output) = f.getParameter(_).getAnAccess() and
@@ -448,6 +459,13 @@ class FormatLiteral extends Literal instanceof StringLiteral {
*/
int getConvSpecOffset(int n) { result = this.getFormat().indexOf("%", n, 0) }
+ /**
+ * Gets the nth conversion specifier string.
+ */
+ private string getConvSpecString(int n) {
+ n >= 0 and result = "%" + this.getFormat().splitAt("%", n + 1)
+ }
+
/*
* Each of these predicates gets a regular expressions to match each individual
* parts of a conversion specifier.
@@ -513,22 +531,20 @@ class FormatLiteral extends Literal instanceof StringLiteral {
int n, string spec, string params, string flags, string width, string prec, string len,
string conv
) {
- exists(int offset, string fmt, string rst, string regexp |
- offset = this.getConvSpecOffset(n) and
- fmt = this.getFormat() and
- rst = fmt.substring(offset, fmt.length()) and
+ exists(string convSpec, string regexp |
+ convSpec = this.getConvSpecString(n) and
regexp = this.getConvSpecRegexp() and
(
- spec = rst.regexpCapture(regexp, 1) and
- params = rst.regexpCapture(regexp, 2) and
- flags = rst.regexpCapture(regexp, 3) and
- width = rst.regexpCapture(regexp, 4) and
- prec = rst.regexpCapture(regexp, 5) and
- len = rst.regexpCapture(regexp, 6) and
- conv = rst.regexpCapture(regexp, 7)
+ spec = convSpec.regexpCapture(regexp, 1) and
+ params = convSpec.regexpCapture(regexp, 2) and
+ flags = convSpec.regexpCapture(regexp, 3) and
+ width = convSpec.regexpCapture(regexp, 4) and
+ prec = convSpec.regexpCapture(regexp, 5) and
+ len = convSpec.regexpCapture(regexp, 6) and
+ conv = convSpec.regexpCapture(regexp, 7)
or
- spec = rst.regexpCapture(regexp, 1) and
- not exists(rst.regexpCapture(regexp, 2)) and
+ spec = convSpec.regexpCapture(regexp, 1) and
+ not exists(convSpec.regexpCapture(regexp, 2)) and
params = "" and
flags = "" and
width = "" and
@@ -543,12 +559,10 @@ class FormatLiteral extends Literal instanceof StringLiteral {
* Gets the nth conversion specifier (including the initial `%`).
*/
string getConvSpec(int n) {
- exists(int offset, string fmt, string rst, string regexp |
- offset = this.getConvSpecOffset(n) and
- fmt = this.getFormat() and
- rst = fmt.substring(offset, fmt.length()) and
+ exists(string convSpec, string regexp |
+ convSpec = this.getConvSpecString(n) and
regexp = this.getConvSpecRegexp() and
- result = rst.regexpCapture(regexp, 1)
+ result = convSpec.regexpCapture(regexp, 1)
)
}
diff --git a/cpp/ql/lib/semmle/code/cpp/commons/Scanf.qll b/cpp/ql/lib/semmle/code/cpp/commons/Scanf.qll
index f032ba4749e..98280a522cf 100644
--- a/cpp/ql/lib/semmle/code/cpp/commons/Scanf.qll
+++ b/cpp/ql/lib/semmle/code/cpp/commons/Scanf.qll
@@ -194,6 +194,13 @@ class ScanfFormatLiteral extends Expr {
)
}
+ /**
+ * Gets the nth conversion specifier string.
+ */
+ private string getConvSpecString(int n) {
+ n >= 0 and result = "%" + this.getFormat().splitAt("%", n + 1)
+ }
+
/**
* Gets the regular expression to match each individual part of a conversion specifier.
*/
@@ -227,16 +234,14 @@ class ScanfFormatLiteral extends Expr {
* specifier.
*/
predicate parseConvSpec(int n, string spec, string width, string len, string conv) {
- exists(int offset, string fmt, string rst, string regexp |
- offset = this.getConvSpecOffset(n) and
- fmt = this.getFormat() and
- rst = fmt.substring(offset, fmt.length()) and
+ exists(string convSpec, string regexp |
+ convSpec = this.getConvSpecString(n) and
regexp = this.getConvSpecRegexp() and
(
- spec = rst.regexpCapture(regexp, 1) and
- width = rst.regexpCapture(regexp, 2) and
- len = rst.regexpCapture(regexp, 3) and
- conv = rst.regexpCapture(regexp, 4)
+ spec = convSpec.regexpCapture(regexp, 1) and
+ width = convSpec.regexpCapture(regexp, 2) and
+ len = convSpec.regexpCapture(regexp, 3) and
+ conv = convSpec.regexpCapture(regexp, 4)
)
)
}
diff --git a/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll b/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll
index 211be2aa432..dad011d9391 100644
--- a/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll
+++ b/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll
@@ -1663,7 +1663,7 @@ private module Cached {
private predicate compares_ge(
ValueNumber test, Operand left, Operand right, int k, boolean isGe, GuardValue value
) {
- exists(int onemk | k = 1 - onemk | compares_lt(test, right, left, onemk, isGe, value))
+ compares_lt(test, right, left, 1 - k, isGe, value)
}
/** Rearrange various simple comparisons into `left < right + k` form. */
diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll
index cf8f01e6944..fb2108c2ac5 100644
--- a/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll
+++ b/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll
@@ -1,15 +1,20 @@
/**
* INTERNAL use only. This is an experimental API subject to change without notice.
*
- * Provides classes and predicates for dealing with flow models specified in CSV format.
+ * Provides classes and predicates for dealing with flow models specified
+ * in data extension files.
*
- * The CSV specification has the following columns:
+ * The extensible relations have the following columns:
* - Sources:
- * `namespace; type; subtypes; name; signature; ext; output; kind`
+ * `namespace; type; subtypes; name; signature; ext; output; kind; provenance`
* - Sinks:
- * `namespace; type; subtypes; name; signature; ext; input; kind`
+ * `namespace; type; subtypes; name; signature; ext; input; kind; provenance`
* - Summaries:
- * `namespace; type; subtypes; name; signature; ext; input; output; kind`
+ * `namespace; type; subtypes; name; signature; ext; input; output; kind; provenance`
+ * - Barriers:
+ * `namespace; type; subtypes; name; signature; ext; output; kind; provenance`
+ * - BarrierGuards:
+ * `namespace; type; subtypes; name; signature; ext; input; acceptingValue; kind; provenance`
*
* The interpretation of a row is similar to API-graphs with a left-to-right
* reading.
@@ -86,11 +91,23 @@
* 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 `acceptingValue` column of barrier guard models specifies the condition
+ * under which the guard blocks flow. It can be one of "true" or "false". In
+ * the future "no-exception", "not-zero", "null", "not-null" may be supported.
+ * 9. The `kind` column is a tag that can be referenced from QL to determine to
* which classes the interpreted elements should be added. For example, for
* sources "remote" indicates a default remote flow source, and for summaries
* "taint" indicates a default additional taint step and "value" indicates a
* globally applicable value-preserving step.
+ * 10. The `provenance` column is a tag to indicate the origin and verification of a model.
+ * The format is {origin}-{verification} or just "manual" where the origin describes
+ * the origin of the model and verification describes how the model has been verified.
+ * Some examples are:
+ * - "df-generated": The model has been generated by the model generator tool.
+ * - "df-manual": The model has been generated by the model generator and verified by a human.
+ * - "manual": The model has been written by hand.
+ * This information is used in a heuristic for dataflow analysis to determine, if a
+ * model or source code should be used for determining flow.
*/
import cpp
@@ -104,117 +121,9 @@ private import internal.FlowSummaryImpl::Private
private import internal.FlowSummaryImpl::Private::External
private import internal.ExternalFlowExtensions::Extensions as Extensions
private import codeql.mad.ModelValidation as SharedModelVal
-private import codeql.util.Unit
private import codeql.mad.static.ModelsAsData as SharedMaD
-/**
- * A unit class for adding additional source model rows.
- *
- * Extend this class to add additional source definitions.
- */
-class SourceModelCsv extends Unit {
- /** Holds if `row` specifies a source definition. */
- abstract predicate row(string row);
-}
-
-/**
- * A unit class for adding additional sink model rows.
- *
- * Extend this class to add additional sink definitions.
- */
-class SinkModelCsv extends Unit {
- /** Holds if `row` specifies a sink definition. */
- abstract predicate row(string row);
-}
-
-/**
- * A unit class for adding additional summary model rows.
- *
- * Extend this class to add additional flow summary definitions.
- */
-class SummaryModelCsv extends Unit {
- /** Holds if `row` specifies a summary definition. */
- abstract predicate row(string row);
-}
-
-/** Holds if `row` is a source model. */
-predicate sourceModel(string row) { any(SourceModelCsv s).row(row) }
-
-/** Holds if `row` is a sink model. */
-predicate sinkModel(string row) { any(SinkModelCsv s).row(row) }
-
-/** Holds if `row` is a summary model. */
-predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
-
private module MadInput implements SharedMaD::InputSig {
- /** Holds if a source model exists for the given parameters. */
- predicate additionalSourceModel(
- string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string output, string kind, string provenance, string model
- ) {
- exists(string row |
- sourceModel(row) and
- row.splitAt(";", 0) = namespace and
- row.splitAt(";", 1) = type and
- row.splitAt(";", 2) = subtypes.toString() and
- subtypes = [true, false] and
- row.splitAt(";", 3) = name and
- row.splitAt(";", 4) = signature and
- row.splitAt(";", 5) = ext and
- row.splitAt(";", 6) = output and
- row.splitAt(";", 7) = kind
- ) and
- provenance = "manual" and
- model = ""
- }
-
- /** Holds if a sink model exists for the given parameters. */
- predicate additionalSinkModel(
- string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string input, string kind, string provenance, string model
- ) {
- exists(string row |
- sinkModel(row) and
- row.splitAt(";", 0) = namespace and
- row.splitAt(";", 1) = type and
- row.splitAt(";", 2) = subtypes.toString() and
- subtypes = [true, false] and
- row.splitAt(";", 3) = name and
- row.splitAt(";", 4) = signature and
- row.splitAt(";", 5) = ext and
- row.splitAt(";", 6) = input and
- row.splitAt(";", 7) = kind
- ) and
- provenance = "manual" and
- model = ""
- }
-
- /**
- * Holds if a summary model exists for the given parameters.
- *
- * This predicate does not expand `@` to `*`s.
- */
- predicate additionalSummaryModel(
- string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string input, string output, string kind, string provenance, string model
- ) {
- exists(string row |
- summaryModel(row) and
- row.splitAt(";", 0) = namespace and
- row.splitAt(";", 1) = type and
- row.splitAt(";", 2) = subtypes.toString() and
- subtypes = [true, false] and
- row.splitAt(";", 3) = name and
- row.splitAt(";", 4) = signature and
- row.splitAt(";", 5) = ext and
- row.splitAt(";", 6) = input and
- row.splitAt(";", 7) = output and
- row.splitAt(";", 8) = kind
- ) and
- provenance = "manual" and
- model = ""
- }
-
string namespaceSegmentSeparator() { result = "::" }
}
@@ -250,8 +159,8 @@ predicate summaryModel(
)
}
-/** Provides a query predicate to check the CSV data for validation errors. */
-module CsvValidation {
+/** Provides a query predicate to check the data for validation errors. */
+module ModelValidation {
private string getInvalidModelInput() {
exists(string pred, AccessPath input, string part |
sinkModel(_, _, _, _, _, _, input, _, _, _) and pred = "sink"
@@ -294,40 +203,6 @@ module CsvValidation {
private module KindVal = SharedModelVal::KindValidation;
- private string getInvalidModelSubtype() {
- exists(string pred, string row |
- sourceModel(row) and pred = "source"
- or
- sinkModel(row) and pred = "sink"
- or
- summaryModel(row) and pred = "summary"
- |
- exists(string b |
- b = row.splitAt(";", 2) and
- not b = ["true", "false"] and
- result = "Invalid boolean \"" + b + "\" in " + pred + " model."
- )
- )
- }
-
- private string getInvalidModelColumnCount() {
- exists(string pred, string row, int expect |
- sourceModel(row) and expect = 8 and pred = "source"
- or
- sinkModel(row) and expect = 8 and pred = "sink"
- or
- summaryModel(row) and expect = 9 and pred = "summary"
- |
- exists(int cols |
- cols = 1 + max(int n | exists(row.splitAt(";", n))) and
- cols != expect and
- result =
- "Wrong number of columns in " + pred + " model row, expected " + expect + ", got " + cols +
- "."
- )
- )
- }
-
private string getInvalidModelSignature() {
exists(string pred, string namespace, string type, string name, string signature, string ext |
sourceModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "source"
@@ -353,12 +228,25 @@ module CsvValidation {
)
}
- /** Holds if some row in a CSV-based flow model appears to contain typos. */
+ private string getIncorrectConstructorSummaryOutput() {
+ exists(string namespace, string type, string name, string output |
+ type = name or
+ type = name + "<" + any(string s)
+ |
+ summaryModel(namespace, type, _, name, _, _, _, output, _, _, _) and
+ output.matches("ReturnValue%") and
+ result =
+ "Constructor model for " + namespace + "." + type +
+ " should use `Argument[this]` in the output, not `ReturnValue`."
+ )
+ }
+
+ /** Holds if some row in a MaD flow model appears to contain typos. */
query predicate invalidModelRow(string msg) {
msg =
[
getInvalidModelSignature(), getInvalidModelInput(), getInvalidModelOutput(),
- getInvalidModelSubtype(), getInvalidModelColumnCount(), KindVal::getInvalidModelKind()
+ KindVal::getInvalidModelKind(), getIncorrectConstructorSummaryOutput()
]
}
}
@@ -555,6 +443,7 @@ private Locatable getSupportedFunctionTemplateArgument(Function templateFunction
* Normalize the `n`'th parameter of `f` by replacing template names
* with `func:N` (where `N` is the index of the template).
*/
+pragma[nomagic]
private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remaining) {
exists(Function templateFunction |
templateFunction = getFullyTemplatedFunction(f) and
@@ -1011,7 +900,7 @@ private module Cached {
}
/**
- * Holds if `node` is specified as a source with the given kind in a CSV flow
+ * Holds if `node` is specified as a source with the given kind in a MaD flow
* model.
*/
cached
@@ -1022,7 +911,7 @@ private module Cached {
}
/**
- * Holds if `node` is specified as a sink with the given kind in a CSV flow
+ * Holds if `node` is specified as a sink with the given kind in a MaD flow
* model.
*/
cached
@@ -1058,13 +947,13 @@ private module Cached {
private predicate barrierGuardChecks(IRGuardCondition g, Expr e, boolean gv, TKindModelPair kmp) {
exists(
- SourceSinkInterpretationInput::InterpretNode n, Public::AcceptingValue acceptingvalue,
+ SourceSinkInterpretationInput::InterpretNode n, Public::AcceptingValue acceptingValue,
string kind, string model
|
- isBarrierGuardNode(n, acceptingvalue, kind, model) and
+ isBarrierGuardNode(n, acceptingValue, kind, model) and
n.asNode().asExpr() = e and
kmp = TMkPair(kind, model) and
- gv = convertAcceptingValue(acceptingvalue).asBooleanValue() and
+ gv = convertAcceptingValue(acceptingValue).asBooleanValue() and
n.asNode().(Private::ArgumentNode).getCall().asCallInstruction() = g
)
}
@@ -1081,14 +970,14 @@ private module Cached {
) {
exists(
SourceSinkInterpretationInput::InterpretNode interpretNode,
- Public::AcceptingValue acceptingvalue, string kind, string model, int indirectionIndex,
+ Public::AcceptingValue acceptingValue, string kind, string model, int indirectionIndex,
Private::ArgumentNode arg
|
- isBarrierGuardNode(interpretNode, acceptingvalue, kind, model) and
+ isBarrierGuardNode(interpretNode, acceptingValue, kind, model) and
arg = interpretNode.asNode() and
arg.asIndirectExpr(indirectionIndex) = e and
kmp = MkKindModelPairIntPair(TMkPair(kind, model), indirectionIndex) and
- gv = convertAcceptingValue(acceptingvalue).asBooleanValue() and
+ gv = convertAcceptingValue(acceptingValue).asBooleanValue() and
arg.getCall().asCallInstruction() = g
)
}
diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/ExternalFlowExtensions.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/ExternalFlowExtensions.qll
index 1a572c221d9..22c74c2aa71 100644
--- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/ExternalFlowExtensions.qll
+++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/ExternalFlowExtensions.qll
@@ -33,7 +33,7 @@ extensible predicate barrierModel(
*/
extensible predicate barrierGuardModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string input, string acceptingvalue, string kind, string provenance, QlBuiltins::ExtensionId madId
+ string input, string acceptingValue, string kind, string provenance, QlBuiltins::ExtensionId madId
);
/**
diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll
index af3e25ba734..d91dc41febe 100644
--- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll
+++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll
@@ -162,13 +162,13 @@ module SourceSinkInterpretationInput implements
}
predicate barrierGuardElement(
- Element e, string input, Public::AcceptingValue acceptingvalue, string kind,
+ Element e, string input, Public::AcceptingValue acceptingValue, string kind,
Public::Provenance provenance, string model
) {
exists(
string package, string type, boolean subtypes, string name, string signature, string ext
|
- barrierGuardModel(package, type, subtypes, name, signature, ext, input, acceptingvalue, kind,
+ barrierGuardModel(package, type, subtypes, name, signature, ext, input, acceptingValue, kind,
provenance, model) and
e = interpretElement(package, type, subtypes, name, signature, ext)
)
@@ -201,7 +201,7 @@ module SourceSinkInterpretationInput implements
string toString() {
result = this.asElement().toString()
or
- result = this.asNode().toString()
+ result = this.asNode().toStringImpl()
or
result = this.asCall().toString()
}
diff --git a/cpp/ql/lib/semmle/code/cpp/exprs/Call.qll b/cpp/ql/lib/semmle/code/cpp/exprs/Call.qll
index 4ef241e3d25..66a89490dd0 100644
--- a/cpp/ql/lib/semmle/code/cpp/exprs/Call.qll
+++ b/cpp/ql/lib/semmle/code/cpp/exprs/Call.qll
@@ -585,12 +585,15 @@ class ConstructorDelegationInit extends ConstructorBaseInit, @ctordelegatinginit
/**
* An initialization of a member variable performed as part of a
- * constructor's explicit initializer list or implicit actions.
+ * constructor's initializer list or by default initialization.
+ *
* In the example below, member variable `b` is being initialized by
- * constructor parameter `a`:
+ * constructor parameter `a`, and `c` is initialized by default
+ * initialization:
* ```
* struct S {
* int b;
+ * int c = 3;
* S(int a): b(a) {}
* } s(2);
* ```
@@ -616,6 +619,28 @@ class ConstructorFieldInit extends ConstructorInit, @ctorfieldinit {
override predicate mayBeGloballyImpure() { this.getExpr().mayBeGloballyImpure() }
}
+/**
+ * An initialization of a member variable performed as part of a
+ * constructor's explicit initializer list.
+ */
+class ConstructorDirectFieldInit extends ConstructorFieldInit {
+ ConstructorDirectFieldInit() { exists(this.getChild(0)) }
+
+ override string getAPrimaryQlClass() { result = "ConstructorDirectFieldInit" }
+}
+
+/**
+ * An initialization of a member variable performed by default
+ * initialization.
+ */
+class ConstructorDefaultFieldInit extends ConstructorFieldInit {
+ ConstructorDefaultFieldInit() {
+ not exists(this.getChild(0)) and exists(this.getTarget().getInitializer())
+ }
+
+ override string getAPrimaryQlClass() { result = "ConstructorDefaultFieldInit" }
+}
+
/**
* A call to a destructor of a base class or field as part of a destructor's
* compiler-generated actions.
diff --git a/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll b/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll
index 7e98177f323..e93bf578921 100644
--- a/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll
+++ b/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll
@@ -6,85 +6,67 @@ private import OverlayXml
/**
* Holds always for the overlay variant and never for the base variant.
- * This local predicate is used to define local predicates that behave
- * differently for the base and overlay variant.
*/
overlay[local]
predicate isOverlay() { databaseMetadata("isOverlay", "true") }
-overlay[local]
-private string getLocationFilePath(@location_default loc) {
- exists(@file file | locations_default(loc, file, _, _, _, _) | files(file, result))
-}
-
/**
- * Gets the file path for an element with a single location.
+ * Holds if the TRAP file or tag `t` is reachable from source file `sourceFile`
+ * in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant.
*/
overlay[local]
-private string getSingleLocationFilePath(@element e) {
- exists(@location_default loc |
- var_decls(e, _, _, _, loc)
- or
- fun_decls(e, _, _, _, loc)
- or
- type_decls(e, _, loc)
- or
- namespace_decls(e, _, loc, _)
- or
- macroinvocations(e, _, loc, _)
- or
- preprocdirects(e, _, loc)
- |
- result = getLocationFilePath(loc)
+private predicate locallyReachableTrapOrTag(
+ boolean isOverlayVariant, string sourceFile, @trap_or_tag t
+) {
+ exists(@source_file sf, @trap trap |
+ (if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and
+ source_file_uses_trap(sf, trap) and
+ source_file_name(sf, sourceFile) and
+ (t = trap or trap_uses_tag(trap, t))
)
}
/**
- * Gets the file path for an element with potentially multiple locations.
+ * Holds if element `e` is in TRAP file or tag `t`
+ * in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant.
*/
overlay[local]
-private string getMultiLocationFilePath(@element e) {
- exists(@location_default loc |
- var_decls(_, e, _, _, loc)
- or
- fun_decls(_, e, _, _, loc)
- or
- type_decls(_, e, loc)
- or
- namespace_decls(_, e, loc, _)
- |
- result = getLocationFilePath(loc)
- )
-}
-
-/**
- * A local helper predicate that holds in the base variant and never in the
- * overlay variant.
- */
-overlay[local]
-private predicate isBase() { not isOverlay() }
-
-/**
- * Holds if `path` was extracted in the overlay database.
- */
-overlay[local]
-private predicate overlayHasFile(string path) {
- isOverlay() and
- files(_, path) and
- path != ""
+private predicate locallyInTrapOrTag(boolean isOverlayVariant, @element e, @trap_or_tag t) {
+ (if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and
+ in_trap_or_tag(e, t)
}
/**
* Discards an element from the base variant if:
- * - It has a single location in a file extracted in the overlay, or
- * - All of its locations are in files extracted in the overlay.
+ * - We have knowledge about what TRAP file or tag it is in (in the base).
+ * - It is not in any overlay TRAP file or tag that is reachable from an overlay source file.
+ * - For every base TRAP file or tag that contains it and is reachable from a base source file,
+ * either the source file has changed, or the overlay has redefined the TRAP file or tag,
+ * or the overlay runner has re-extracted the same source file.
*/
overlay[discard_entity]
private predicate discardElement(@element e) {
- isBase() and
- (
- overlayHasFile(getSingleLocationFilePath(e))
- or
- forex(string path | path = getMultiLocationFilePath(e) | overlayHasFile(path))
+ // If we don't have any knowledge about what TRAP file something
+ // is in, then we don't want to discard it, so we only consider
+ // entities that are known to be in a base TRAP file or tag.
+ locallyInTrapOrTag(false, e, _) and
+ // Anything that is reachable from an overlay source file should
+ // not be discarded.
+ not exists(@trap_or_tag t | locallyInTrapOrTag(true, e, t) |
+ locallyReachableTrapOrTag(true, _, t)
+ ) and
+ // Finally, we have to make sure the base variant does not retain it.
+ // If it is reachable from a base source file, then that is
+ // sufficient unless either the base source file has changed (in
+ // particular, been deleted), or the overlay has redefined the TRAP
+ // file or tag it is in, or the overlay runner has re-extracted the same
+ // source file (e.g. because a header it includes has changed).
+ forall(@trap_or_tag t, string sourceFile |
+ locallyInTrapOrTag(false, e, t) and
+ locallyReachableTrapOrTag(false, sourceFile, t)
+ |
+ overlayChangedFiles(sourceFile) or
+ locallyReachableTrapOrTag(true, _, t) or
+ locallyReachableTrapOrTag(true, sourceFile, _)
)
}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/MustFlow.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/MustFlow.qll
index b085440f6bc..2b61190fb71 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/MustFlow.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/MustFlow.qll
@@ -8,81 +8,143 @@ private import cpp
private import semmle.code.cpp.ir.IR
/**
- * A configuration of a data flow analysis that performs must-flow analysis. This is different
- * from `DataFlow.qll` which performs may-flow analysis (i.e., it finds paths where the source _may_
- * flow to the sink).
- *
- * Like in `DataFlow.qll`, each use of the `MustFlow.qll` library must define its own unique extension
- * of this abstract class. To create a configuration, extend this class with a subclass whose
- * characteristic predicate is a unique singleton string and override `isSource`, `isSink` (and
- * `isAdditionalFlowStep` if additional steps are required).
+ * Provides an inter-procedural must-flow data flow analysis.
*/
-abstract class MustFlowConfiguration extends string {
- bindingset[this]
- MustFlowConfiguration() { any() }
-
+module MustFlow {
/**
- * Holds if `source` is a relevant data flow source.
+ * An input configuration of a data flow analysis that performs must-flow analysis. This is different
+ * from `DataFlow.qll` which performs may-flow analysis (i.e., it finds paths where the source _may_
+ * flow to the sink).
*/
- abstract predicate isSource(Instruction source);
+ signature module ConfigSig {
+ /**
+ * Holds if `source` is a relevant data flow source.
+ */
+ predicate isSource(Instruction source);
- /**
- * Holds if `sink` is a relevant data flow sink.
- */
- abstract predicate isSink(Operand sink);
+ /**
+ * Holds if `sink` is a relevant data flow sink.
+ */
+ predicate isSink(Operand sink);
- /**
- * Holds if data flow through `instr` is prohibited.
- */
- predicate isBarrier(Instruction instr) { none() }
+ /**
+ * Holds if data flow through `instr` is prohibited.
+ */
+ default predicate isBarrier(Instruction instr) { none() }
- /**
- * Holds if the additional flow step from `node1` to `node2` must be taken
- * into account in the analysis.
- */
- predicate isAdditionalFlowStep(Operand node1, Instruction node2) { none() }
+ /**
+ * Holds if the additional flow step from `node1` to `node2` must be taken
+ * into account in the analysis.
+ */
+ default predicate isAdditionalFlowStep(Operand node1, Instruction node2) { none() }
- /** Holds if this configuration allows flow from arguments to parameters. */
- predicate allowInterproceduralFlow() { any() }
-
- /**
- * Holds if data must flow from `source` to `sink` for this configuration.
- *
- * The corresponding paths are generated from the end-points and the graph
- * included in the module `PathGraph`.
- */
- final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) {
- this.isSource(source.getInstruction()) and
- source.getASuccessor*() = sink
+ /** Holds if this configuration allows flow from arguments to parameters. */
+ default predicate allowInterproceduralFlow() { any() }
}
-}
-/** Holds if `node` flows from a source. */
-pragma[nomagic]
-private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) {
- not config.isBarrier(node) and
- (
- config.isSource(node)
- or
- exists(Instruction mid |
- step(mid, node, config) and
- flowsFromSource(mid, pragma[only_bind_into](config))
- )
- )
-}
+ /**
+ * Constructs a global must-flow computation.
+ */
+ module Global {
+ import Config
-/** Holds if `node` flows to a sink. */
-pragma[nomagic]
-private predicate flowsToSink(Instruction node, MustFlowConfiguration config) {
- flowsFromSource(node, pragma[only_bind_into](config)) and
- (
- config.isSink(node.getAUse())
- or
- exists(Instruction mid |
- step(node, mid, config) and
- flowsToSink(mid, pragma[only_bind_into](config))
- )
- )
+ /**
+ * Holds if data must flow from `source` to `sink`.
+ *
+ * The corresponding paths are generated from the end-points and the graph
+ * included in the module `PathGraph`.
+ */
+ predicate flowPath(PathNode source, PathSink sink) {
+ isSource(source.getInstruction()) and
+ source.getASuccessor*() = sink
+ }
+
+ /** Holds if `node` flows from a source. */
+ pragma[nomagic]
+ private predicate flowsFromSource(Instruction node) {
+ not isBarrier(node) and
+ (
+ isSource(node)
+ or
+ exists(Instruction mid |
+ step(mid, node) and
+ flowsFromSource(mid)
+ )
+ )
+ }
+
+ /** Holds if `node` flows to a sink. */
+ pragma[nomagic]
+ private predicate flowsToSink(Instruction node) {
+ flowsFromSource(node) and
+ (
+ isSink(node.getAUse())
+ or
+ exists(Instruction mid |
+ step(node, mid) and
+ flowsToSink(mid)
+ )
+ )
+ }
+
+ /** Holds if `nodeFrom` flows to `nodeTo`. */
+ private predicate step(Instruction nodeFrom, Instruction nodeTo) {
+ Cached::localStep(nodeFrom, nodeTo)
+ or
+ allowInterproceduralFlow() and
+ Cached::flowThroughCallable(nodeFrom, nodeTo)
+ or
+ isAdditionalFlowStep(nodeFrom.getAUse(), nodeTo)
+ }
+
+ private newtype TLocalPathNode =
+ MkLocalPathNode(Instruction n) {
+ flowsToSink(n) and
+ (
+ isSource(n)
+ or
+ exists(PathNode mid | step(mid.getInstruction(), n))
+ )
+ }
+
+ /** A `Node` that is in a path from a source to a sink. */
+ class PathNode extends TLocalPathNode {
+ Instruction n;
+
+ PathNode() { this = MkLocalPathNode(n) }
+
+ /** Gets the underlying node. */
+ Instruction getInstruction() { result = n }
+
+ /** Gets a textual representation of this node. */
+ string toString() { result = n.getAst().toString() }
+
+ /** Gets the location of this element. */
+ Location getLocation() { result = n.getLocation() }
+
+ /** Gets a successor node, if any. */
+ PathNode getASuccessor() { step(this.getInstruction(), result.getInstruction()) }
+ }
+
+ private class PathSink extends PathNode {
+ PathSink() { isSink(this.getInstruction().getAUse()) }
+ }
+
+ /**
+ * Provides the query predicates needed to include a graph in a path-problem query.
+ */
+ module PathGraph {
+ private predicate reach(PathNode n) { n instanceof PathSink or reach(n.getASuccessor()) }
+
+ /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
+ query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(b) }
+
+ /** Holds if `n` is a node in the graph of data flow path explanations. */
+ query predicate nodes(PathNode n, string key, string val) {
+ reach(n) and key = "semmle.label" and val = n.toString()
+ }
+ }
+ }
}
cached
@@ -102,7 +164,7 @@ private module Cached {
not f.isVirtual() and
call.getPositionalArgument(n) = instr and
f = call.getStaticCallTarget() and
- getEnclosingNonVirtualFunctionInitializeParameter(init, f) and
+ isEnclosingNonVirtualFunctionInitializeParameter(init, f) and
init.getParameter().getIndex() = pragma[only_bind_into](pragma[only_bind_out](n))
}
@@ -111,7 +173,7 @@ private module Cached {
* corresponding initialization instruction that receives the value of `instr` in `f`.
*/
pragma[noinline]
- private predicate getPositionalArgumentInitParam(
+ private predicate isPositionalArgumentInitParam(
CallInstruction call, Instruction instr, InitializeParameterInstruction init, Function f
) {
exists(int n |
@@ -126,18 +188,18 @@ private module Cached {
* `instr` in `f`.
*/
pragma[noinline]
- private predicate getThisArgumentInitParam(
+ private predicate isThisArgumentInitParam(
CallInstruction call, Instruction instr, InitializeParameterInstruction init, Function f
) {
not f.isVirtual() and
call.getStaticCallTarget() = f and
- getEnclosingNonVirtualFunctionInitializeParameter(init, f) and
+ isEnclosingNonVirtualFunctionInitializeParameter(init, f) and
call.getThisArgument() = instr and
init.getIRVariable() instanceof IRThisVariable
}
/** Holds if `f` is the enclosing non-virtual function of `init`. */
- private predicate getEnclosingNonVirtualFunctionInitializeParameter(
+ private predicate isEnclosingNonVirtualFunctionInitializeParameter(
InitializeParameterInstruction init, Function f
) {
not f.isVirtual() and
@@ -145,7 +207,7 @@ private module Cached {
}
/** Holds if `f` is the enclosing non-virtual function of `init`. */
- private predicate getEnclosingNonVirtualFunctionInitializeIndirection(
+ private predicate isEnclosingNonVirtualFunctionInitializeIndirection(
InitializeIndirectionInstruction init, Function f
) {
not f.isVirtual() and
@@ -153,15 +215,16 @@ private module Cached {
}
/**
- * Holds if `instr` is an argument (or argument indirection) to a call, and
- * `succ` is the corresponding initialization instruction in the call target.
+ * Holds if `argument` is an argument (or argument indirection) to a call, and
+ * `parameter` is the corresponding initialization instruction in the call target.
*/
- private predicate flowThroughCallable(Instruction argument, Instruction parameter) {
+ cached
+ predicate flowThroughCallable(Instruction argument, Instruction parameter) {
// Flow from an argument to a parameter
exists(CallInstruction call, InitializeParameterInstruction init | init = parameter |
- getPositionalArgumentInitParam(call, argument, init, call.getStaticCallTarget())
+ isPositionalArgumentInitParam(call, argument, init, call.getStaticCallTarget())
or
- getThisArgumentInitParam(call, argument, init, call.getStaticCallTarget())
+ isThisArgumentInitParam(call, argument, init, call.getStaticCallTarget())
)
or
// Flow from argument indirection to parameter indirection
@@ -170,7 +233,7 @@ private module Cached {
|
init = parameter and
read.getPrimaryInstruction() = call and
- getEnclosingNonVirtualFunctionInitializeIndirection(init, call.getStaticCallTarget())
+ isEnclosingNonVirtualFunctionInitializeIndirection(init, call.getStaticCallTarget())
|
exists(int n |
read.getSideEffectOperand().getAnyDef() = argument and
@@ -205,92 +268,10 @@ private module Cached {
}
cached
- predicate step(Instruction nodeFrom, Instruction nodeTo) {
+ predicate localStep(Instruction nodeFrom, Instruction nodeTo) {
exists(Operand mid |
instructionToOperandStep(nodeFrom, mid) and
operandToInstructionStep(mid, nodeTo)
)
- or
- flowThroughCallable(nodeFrom, nodeTo)
- }
-}
-
-/**
- * Gets the enclosing callable of `n`. Unlike `n.getEnclosingCallable()`, this
- * predicate ensures that joins go from `n` to the result instead of the other
- * way around.
- */
-pragma[inline]
-private IRFunction getEnclosingCallable(Instruction n) {
- pragma[only_bind_into](result) = pragma[only_bind_out](n).getEnclosingIRFunction()
-}
-
-/** Holds if `nodeFrom` flows to `nodeTo`. */
-private predicate step(Instruction nodeFrom, Instruction nodeTo, MustFlowConfiguration config) {
- exists(config) and
- Cached::step(pragma[only_bind_into](nodeFrom), pragma[only_bind_into](nodeTo)) and
- (
- config.allowInterproceduralFlow()
- or
- getEnclosingCallable(nodeFrom) = getEnclosingCallable(nodeTo)
- )
- or
- config.isAdditionalFlowStep(nodeFrom.getAUse(), nodeTo)
-}
-
-private newtype TLocalPathNode =
- MkLocalPathNode(Instruction n, MustFlowConfiguration config) {
- flowsToSink(n, config) and
- (
- config.isSource(n)
- or
- exists(MustFlowPathNode mid | step(mid.getInstruction(), n, config))
- )
- }
-
-/** A `Node` that is in a path from a source to a sink. */
-class MustFlowPathNode extends TLocalPathNode {
- Instruction n;
-
- MustFlowPathNode() { this = MkLocalPathNode(n, _) }
-
- /** Gets the underlying node. */
- Instruction getInstruction() { result = n }
-
- /** Gets a textual representation of this node. */
- string toString() { result = n.getAst().toString() }
-
- /** Gets the location of this element. */
- Location getLocation() { result = n.getLocation() }
-
- /** Gets a successor node, if any. */
- MustFlowPathNode getASuccessor() {
- step(this.getInstruction(), result.getInstruction(), this.getConfiguration())
- }
-
- /** Gets the associated configuration. */
- MustFlowConfiguration getConfiguration() { this = MkLocalPathNode(_, result) }
-}
-
-private class MustFlowPathSink extends MustFlowPathNode {
- MustFlowPathSink() { this.getConfiguration().isSink(this.getInstruction().getAUse()) }
-}
-
-/**
- * Provides the query predicates needed to include a graph in a path-problem query.
- */
-module PathGraph {
- private predicate reach(MustFlowPathNode n) {
- n instanceof MustFlowPathSink or reach(n.getASuccessor())
- }
-
- /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
- query predicate edges(MustFlowPathNode a, MustFlowPathNode b) {
- a.getASuccessor() = b and reach(b)
- }
-
- /** Holds if `n` is a node in the graph of data flow path explanations. */
- query predicate nodes(MustFlowPathNode n, string key, string val) {
- reach(n) and key = "semmle.label" and val = n.toString()
}
}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll
index 0d63558c956..bce93655276 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll
@@ -238,7 +238,12 @@ private module TrackVirtualDispatch {
private import TypeTracking::TypeTrack::Graph
- private predicate edgePlus(PathNode n1, PathNode n2) = fastTC(edges/2)(n1, n2)
+ private predicate isSource(PathNode n) { n.isSource() }
+
+ private predicate isSink(PathNode n) { n.isSink() }
+
+ private predicate edgePlus(PathNode n1, PathNode n2) =
+ doublyBoundedFastTC(edges/2, isSource/1, isSink/1)(n1, n2)
/**
* Gets the most specific implementation of `mf` that may be called when the
@@ -255,6 +260,15 @@ private module TrackVirtualDispatch {
)
}
+ pragma[nomagic]
+ private MemberFunction mostSpecificForSource(PathNode p1, MemberFunction mf) {
+ p1.isSource() and
+ exists(Class derived |
+ qualifierSourceImpl(p1.getNode(), derived) and
+ result = mostSpecific(mf, derived)
+ )
+ }
+
/**
* Gets a possible pair of end-points `(p1, p2)` where:
* - `p1` is a derived-to-base conversion that converts from some
@@ -264,16 +278,16 @@ private module TrackVirtualDispatch {
* - `callable` is the most specific implementation that may be called when
* the qualifier has type `derived`.
*/
+ bindingset[p1, p2]
+ pragma[inline_late]
private predicate pairCand(
PathNode p1, PathNode p2, DataFlowPrivate::DataFlowCallable callable,
DataFlowPrivate::DataFlowCall call
) {
- exists(Class derived, MemberFunction mf |
- qualifierSourceImpl(p1.getNode(), derived) and
+ p2.isSink() and
+ exists(MemberFunction mf |
qualifierOfVirtualCallImpl(p2.getNode(), call.asCallInstruction(), mf) and
- p1.isSource() and
- p2.isSink() and
- callable.asSourceCallable() = mostSpecific(mf, derived)
+ callable.asSourceCallable() = mostSpecificForSource(p1, mf)
)
}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll
new file mode 100644
index 00000000000..bcf6a0d512c
--- /dev/null
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll
@@ -0,0 +1,1881 @@
+private import cpp
+private import semmle.code.cpp.ir.ValueNumbering
+private import semmle.code.cpp.ir.IR
+private import semmle.code.cpp.models.interfaces.DataFlow
+private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
+private import DataFlowPrivate
+private import DataFlowUtil
+private import ModelUtil
+private import SsaImpl as SsaImpl
+private import DataFlowImplCommon as DataFlowImplCommon
+private import codeql.util.Unit
+private import Node0ToString
+
+/**
+ * A canonical representation of a field.
+ *
+ * For performance reasons we want a unique `Content` that represents
+ * a given field across any template instantiation of a class.
+ *
+ * This is possible in _almost_ all cases, but there are cases where it is
+ * not possible to map between a field in the uninstantiated template to a
+ * field in the instantiated template. This happens in the case of local class
+ * definitions (because the local class is not the template that constructs
+ * the instantiation - it is the enclosing function). So this abstract class
+ * has two implementations: a non-local case (where we can represent a
+ * canonical field as the field declaration from an uninstantiated class
+ * template or a non-templated class), and a local case (where we simply use
+ * the field from the instantiated class).
+ */
+abstract class CanonicalField extends Field {
+ /** Gets a field represented by this canonical field. */
+ abstract Field getAField();
+
+ /**
+ * Gets a class that declares a field represented by this canonical field.
+ */
+ abstract Class getADeclaringType();
+
+ /**
+ * Gets a type that this canonical field may have. Note that this may
+ * not be a unique type. For example, consider this case:
+ * ```
+ * template
+ * struct S { T x; };
+ *
+ * S s1;
+ * S s2;
+ * ```
+ * In this case the canonical field corresponding to `S::x` has two types:
+ * `int` and `char`.
+ */
+ Type getAType() { result = this.getAField().getType() }
+
+ Type getAnUnspecifiedType() { result = this.getAType().getUnspecifiedType() }
+}
+
+private class NonLocalCanonicalField extends CanonicalField {
+ Class declaringType;
+
+ NonLocalCanonicalField() {
+ declaringType = this.getDeclaringType() and
+ not declaringType.isFromTemplateInstantiation(_) and
+ not declaringType.isLocal() // handled in LocalCanonicalField
+ }
+
+ override Field getAField() {
+ exists(Class c | result.getDeclaringType() = c |
+ // Either the declaring class of the field is a template instantiation
+ // that has been constructed from this canonical declaration
+ c.isConstructedFrom(declaringType) and
+ pragma[only_bind_out](result.getName()) = pragma[only_bind_out](this.getName())
+ or
+ // or this canonical declaration is not a template.
+ not c.isConstructedFrom(_) and
+ result = this
+ )
+ }
+
+ override Class getADeclaringType() {
+ result = this.getDeclaringType()
+ or
+ result.isConstructedFrom(this.getDeclaringType())
+ }
+}
+
+private class LocalCanonicalField extends CanonicalField {
+ Class declaringType;
+
+ LocalCanonicalField() {
+ declaringType = this.getDeclaringType() and
+ declaringType.isLocal()
+ }
+
+ override Field getAField() { result = this }
+
+ override Class getADeclaringType() { result = declaringType }
+}
+
+/**
+ * A canonical representation of a `Union`. See `CanonicalField` for the explanation for
+ * why we need a canonical representation.
+ */
+abstract class CanonicalUnion extends Union {
+ /** Gets a union represented by this canonical union. */
+ abstract Union getAUnion();
+
+ /** Gets a canonical field of this canonical union. */
+ CanonicalField getACanonicalField() { result.getDeclaringType() = this }
+}
+
+private class NonLocalCanonicalUnion extends CanonicalUnion {
+ NonLocalCanonicalUnion() { not this.isFromTemplateInstantiation(_) and not this.isLocal() }
+
+ override Union getAUnion() {
+ result = this
+ or
+ result.isConstructedFrom(this)
+ }
+}
+
+private class LocalCanonicalUnion extends CanonicalUnion {
+ LocalCanonicalUnion() { this.isLocal() }
+
+ override Union getAUnion() { result = this }
+}
+
+bindingset[f]
+pragma[inline_late]
+int getFieldSize(CanonicalField f) { result = max(f.getAType().getSize()) }
+
+/**
+ * Gets a field in the union `u` whose size
+ * is `bytes` number of bytes.
+ */
+private CanonicalField getAFieldWithSize(CanonicalUnion u, int bytes) {
+ result = u.getACanonicalField() and
+ bytes = getFieldSize(result)
+}
+
+cached
+private module Cached {
+ cached
+ newtype TContent =
+ TNonUnionContent(CanonicalField f, int indirectionIndex) {
+ // the indirection index for field content starts at 1 (because `TNonUnionContent` is thought of as
+ // the address of the field, `FieldAddress` in the IR).
+ indirectionIndex = [1 .. max(SsaImpl::getMaxIndirectionsForType(f.getAnUnspecifiedType()))] and
+ // Reads and writes of union fields are tracked using `UnionContent`.
+ not f.getDeclaringType() instanceof Union
+ } or
+ TUnionContent(CanonicalUnion u, int bytes, int indirectionIndex) {
+ exists(CanonicalField f |
+ f = u.getACanonicalField() and
+ bytes = getFieldSize(f) and
+ // We key `UnionContent` by the union instead of its fields since a write to one
+ // field can be read by any read of the union's fields. Again, the indirection index
+ // is 1-based (because 0 is considered the address).
+ indirectionIndex =
+ [1 .. max(SsaImpl::getMaxIndirectionsForType(getAFieldWithSize(u, bytes)
+ .getAnUnspecifiedType())
+ )]
+ )
+ } or
+ TElementContent(int indirectionIndex) {
+ indirectionIndex = [1 .. getMaxElementContentIndirectionIndex()]
+ }
+
+ /**
+ * The IR dataflow graph consists of the following nodes:
+ * - `Node0`, which injects most instructions and operands directly into the
+ * dataflow graph.
+ * - `VariableNode`, which is used to model flow through global variables.
+ * - `PostUpdateNodeImpl`, which is used to model the state of an object after
+ * an update after a number of loads.
+ * - `SsaSynthNode`, which represents synthesized nodes as computed by the shared SSA
+ * library.
+ * - `RawIndirectOperand`, which represents the value of `operand` after
+ * loading the address a number of times.
+ * - `RawIndirectInstruction`, which represents the value of `instr` after
+ * loading the address a number of times.
+ */
+ cached
+ newtype TIRDataFlowNode =
+ TNode0(Node0Impl node) { DataFlowImplCommon::forceCachingInSameStage() } or
+ TGlobalLikeVariableNode(GlobalLikeVariable var, int indirectionIndex) {
+ indirectionIndex =
+ [getMinIndirectionsForType(var.getUnspecifiedType()) .. SsaImpl::getMaxIndirectionsForType(var.getUnspecifiedType())]
+ } or
+ TPostUpdateNodeImpl(Operand operand, int indirectionIndex) {
+ isPostUpdateNodeImpl(operand, indirectionIndex)
+ } or
+ TSsaSynthNode(SsaImpl::SynthNode n) or
+ TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
+ TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
+ SsaImpl::hasRawIndirectOperand(node.asOperand(), indirectionIndex)
+ } or
+ TRawIndirectInstruction0(Node0Impl node, int indirectionIndex) {
+ not exists(node.asOperand()) and
+ SsaImpl::hasRawIndirectInstruction(node.asInstruction(), indirectionIndex)
+ } or
+ TFinalParameterNode(Parameter p, int indirectionIndex) {
+ exists(SsaImpl::FinalParameterUse use |
+ use.getParameter() = p and
+ use.getIndirectionIndex() = indirectionIndex
+ )
+ } or
+ TFinalGlobalValue(SsaImpl::GlobalUse globalUse) or
+ TInitialGlobalValue(SsaImpl::GlobalDef globalUse) or
+ TBodyLessParameterNodeImpl(Parameter p, int indirectionIndex) {
+ // Rule out parameters of catch blocks.
+ not exists(p.getCatchBlock()) and
+ // We subtract one because `getMaxIndirectionsForType` returns the maximum
+ // indirection for a glvalue of a given type, and this doesn't apply to
+ // parameters.
+ indirectionIndex = [0 .. SsaImpl::getMaxIndirectionsForType(p.getUnspecifiedType()) - 1] and
+ not any(InitializeParameterInstruction init).getParameter() = p
+ } or
+ TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn)
+}
+
+import Cached
+
+/**
+ * An operand that is defined by a `FieldAddressInstruction`.
+ */
+class FieldAddress extends Operand {
+ FieldAddressInstruction fai;
+
+ FieldAddress() { fai = this.getDef() and not SsaImpl::ignoreOperand(this) }
+
+ /** Gets the field associated with this instruction. */
+ Field getField() { result = fai.getField() }
+
+ /** Gets the instruction whose result provides the address of the object containing the field. */
+ Instruction getObjectAddress() { result = fai.getObjectAddress() }
+
+ /** Gets the operand that provides the address of the object containing the field. */
+ Operand getObjectAddressOperand() { result = fai.getObjectAddressOperand() }
+}
+
+/**
+ * Holds if `opFrom` is an operand whose value flows to the result of `instrTo`.
+ *
+ * `isPointerArith` is `true` if `instrTo` is a `PointerArithmeticInstruction` and `opFrom`
+ * is the left operand.
+ *
+ * `additional` is `true` if the conversion is supplied by an implementation of the
+ * `Indirection` class. It is sometimes useful to exclude such conversions.
+ */
+predicate conversionFlow(
+ Operand opFrom, Instruction instrTo, boolean isPointerArith, boolean additional
+) {
+ isPointerArith = false and
+ (
+ additional = false and
+ (
+ instrTo.(CopyValueInstruction).getSourceValueOperand() = opFrom
+ or
+ instrTo.(ConvertInstruction).getUnaryOperand() = opFrom
+ or
+ instrTo.(CheckedConvertOrNullInstruction).getUnaryOperand() = opFrom
+ or
+ instrTo.(InheritanceConversionInstruction).getUnaryOperand() = opFrom
+ or
+ exists(BuiltInInstruction builtIn |
+ builtIn = instrTo and
+ // __builtin_bit_cast
+ builtIn.getBuiltInOperation() instanceof BuiltInBitCast and
+ opFrom = builtIn.getAnOperand()
+ )
+ )
+ or
+ additional = true and
+ SsaImpl::isAdditionalConversionFlow(opFrom, instrTo)
+ )
+ or
+ isPointerArith = true and
+ additional = false and
+ instrTo.(PointerArithmeticInstruction).getLeftOperand() = opFrom
+}
+
+module Public {
+ import ExprNodes
+
+ /**
+ * A node in a data flow graph.
+ *
+ * A node can be either an expression, a parameter, or an uninitialized local
+ * variable. Such nodes are created with `DataFlow::exprNode`,
+ * `DataFlow::parameterNode`, and `DataFlow::uninitializedNode` respectively.
+ */
+ class Node extends TIRDataFlowNode {
+ /**
+ * INTERNAL: Do not use.
+ */
+ DataFlowCallable getEnclosingCallable() { none() } // overridden in subclasses
+
+ /** Gets the function to which this node belongs, if any. */
+ Declaration getFunction() { none() } // overridden in subclasses
+
+ /** Holds if this node represents a glvalue. */
+ predicate isGLValue() { none() }
+
+ /**
+ * Gets the type of this node.
+ *
+ * If `isGLValue()` holds, then the type of this node
+ * should be thought of as "pointer to `getType()`".
+ */
+ Type getType() { none() } // overridden in subclasses
+
+ /** Gets the instruction corresponding to this node, if any. */
+ Instruction asInstruction() { result = this.(InstructionNode).getInstruction() }
+
+ /** Gets the operands corresponding to this node, if any. */
+ 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) }
+
+ /**
+ * Gets the instruction that is indirectly tracked by this node behind
+ * `index` number of indirections.
+ */
+ Instruction asIndirectInstruction(int index) { hasInstructionAndIndex(this, result, index) }
+
+ /**
+ * Holds if this node is at index `i` in basic block `block`.
+ *
+ * Note: Phi nodes are considered to be at index `-1`.
+ */
+ final predicate hasIndexInBlock(IRBlock block, int i) {
+ this.asInstruction() = block.getInstruction(i)
+ or
+ this.asOperand().getUse() = block.getInstruction(i)
+ or
+ exists(SsaImpl::SynthNode ssaNode |
+ this.(SsaSynthNode).getSynthNode() = ssaNode and
+ ssaNode.getBasicBlock() = block and
+ ssaNode.getIndex() = i
+ )
+ or
+ this.(RawIndirectOperand).getOperand().getUse() = block.getInstruction(i)
+ or
+ this.(RawIndirectInstruction).getInstruction() = block.getInstruction(i)
+ or
+ this.(PostUpdateNode).getPreUpdateNode().hasIndexInBlock(block, i)
+ }
+
+ /** Gets the basic block of this node, if any. */
+ final IRBlock getBasicBlock() { this.hasIndexInBlock(result, _) }
+
+ /**
+ * Gets the non-conversion expression corresponding to this node, if any.
+ * This predicate only has a result on nodes that represent the value of
+ * evaluating the expression. For data flowing _out of_ an expression, like
+ * when an argument is passed by reference, use `asDefiningArgument` instead
+ * of `asExpr`.
+ *
+ * If this node strictly (in the sense of `asConvertedExpr`) corresponds to
+ * a `Conversion`, then the result is the underlying non-`Conversion` base
+ * expression.
+ */
+ Expr asExpr() { result = this.asExpr(_) }
+
+ /**
+ * INTERNAL: Do not use.
+ */
+ Expr asExpr(int n) { result = this.(ExprNode).getExpr(n) }
+
+ /**
+ * INTERNAL: Do not use.
+ */
+ Expr asIndirectExpr(int n, int index) { result = this.(IndirectExprNode).getExpr(n, index) }
+
+ /**
+ * Gets the non-conversion expression that's indirectly tracked by this node
+ * under `index` number of indirections.
+ */
+ Expr asIndirectExpr(int index) { result = this.asIndirectExpr(_, index) }
+
+ /**
+ * Gets the non-conversion expression that's indirectly tracked by this node
+ * behind a number of indirections.
+ */
+ Expr asIndirectExpr() { result = this.asIndirectExpr(_) }
+
+ /**
+ * Gets the expression corresponding to this node, if any. The returned
+ * expression may be a `Conversion`.
+ */
+ Expr asConvertedExpr() { result = this.asConvertedExpr(_) }
+
+ /**
+ * Gets the expression corresponding to this node, if any. The returned
+ * expression may be a `Conversion`.
+ */
+ Expr asConvertedExpr(int n) { result = this.(ExprNode).getConvertedExpr(n) }
+
+ private Expr asIndirectConvertedExpr(int n, int index) {
+ result = this.(IndirectExprNode).getConvertedExpr(n, index)
+ }
+
+ /**
+ * Gets the expression that's indirectly tracked by this node
+ * behind `index` number of indirections.
+ */
+ Expr asIndirectConvertedExpr(int index) { result = this.asIndirectConvertedExpr(_, index) }
+
+ /**
+ * Gets the expression that's indirectly tracked by this node behind a
+ * number of indirections.
+ */
+ Expr asIndirectConvertedExpr() { result = this.asIndirectConvertedExpr(_) }
+
+ /**
+ * Gets the argument that defines this `DefinitionByReferenceNode`, if any.
+ * This predicate should be used instead of `asExpr` when referring to the
+ * value of a reference argument _after_ the call has returned. For example,
+ * in `f(&x)`, this predicate will have `&x` as its result for the `Node`
+ * that represents the new value of `x`.
+ */
+ Expr asDefiningArgument() { result = this.asDefiningArgument(_) }
+
+ /**
+ * Gets the definition associated with this node, if any.
+ *
+ * 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 definition generated by `x += 2` the result is `x += 2`
+ * - For the definition generated by `int y = ...` the result is
+ * also `x += 2`.
+ *
+ * For assignments, `node.asDefinition()` and `node.asExpr()` will both exist
+ * for the same dataflow node. However, for expression such as `x++` that
+ * both write to `x` and read the current value of `x`, `node.asDefinition()`
+ * will give the node corresponding to the value after the increment, and
+ * `node.asExpr()` will give the node corresponding to the value before the
+ * increment. For an example of this, consider the following:
+ *
+ * ```cpp
+ * sink(x++);
+ * ```
+ * in the above program, there will not be flow from a node `n` such that
+ * `n.asDefinition() instanceof IncrementOperation` to the argument of `sink`
+ * since the value passed to `sink` is the value before to the increment.
+ * However, there will be dataflow from a node `n` such that
+ * `n.asExpr() instanceof IncrementOperation` since the result of evaluating
+ * the expression `x++` is passed to `sink`.
+ */
+ Expr asDefinition() { result = this.asDefinition(_) }
+
+ private predicate isCertainStore() {
+ exists(SsaImpl::Definition def |
+ SsaImpl::defToNode(this, def, _) and
+ def.isCertain()
+ )
+ }
+
+ /**
+ * Gets the definition associated with this node, if any.
+ *
+ * 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 definition generated by `x += 2` the result is `x += 2`
+ * - For the definition generated by `int y = ...` the result is
+ * also `x += 2`.
+ *
+ * For assignments, `node.asDefinition(_)` and `node.asExpr()` will both exist
+ * for the same dataflow node. However, for expression such as `x++` that
+ * both write to `x` and read the current value of `x`, `node.asDefinition(_)`
+ * will give the node corresponding to the value after the increment, and
+ * `node.asExpr()` will give the node corresponding to the value before the
+ * increment. For an example of this, consider the following:
+ *
+ * ```cpp
+ * sink(x++);
+ * ```
+ * in the above program, there will not be flow from a node `n` such that
+ * `n.asDefinition(_) instanceof IncrementOperation` to the argument of `sink`
+ * since the value passed to `sink` is the value before to the increment.
+ * However, there will be dataflow from a node `n` such that
+ * `n.asExpr() instanceof IncrementOperation` since the result of evaluating
+ * the expression `x++` is passed to `sink`.
+ *
+ * If `uncertain = false` then the definition is guaranteed to overwrite
+ * the entire buffer pointed to by the destination address of the definition.
+ * Otherwise, `uncertain = true`.
+ *
+ * For example, the write `int x; x = 42;` is guaranteed to overwrite all the
+ * bytes allocated to `x`, while the assignment `int p[10]; p[3] = 42;` has
+ * `uncertain = true` since the write will not overwrite the entire buffer
+ * pointed to by `p`.
+ */
+ Expr asDefinition(boolean uncertain) {
+ exists(StoreInstruction store |
+ store = this.asInstruction() and
+ result = asDefinitionImpl(store) and
+ if this.isCertainStore() then uncertain = false else uncertain = true
+ )
+ }
+
+ /**
+ * Gets the definition associated with this node, if this node is a certain definition.
+ *
+ * See `Node.asDefinition/1` for a description of certain and uncertain definitions.
+ */
+ Expr asCertainDefinition() { result = this.asDefinition(false) }
+
+ /**
+ * Gets the definition associated with this node, if this node is an uncertain definition.
+ *
+ * See `Node.asDefinition/1` for a description of certain and uncertain definitions.
+ */
+ Expr asUncertainDefinition() { result = this.asDefinition(true) }
+
+ /**
+ * Gets the indirect definition at a given indirection corresponding to this
+ * node, if any.
+ *
+ * See the comments on `Node.asDefinition` for examples.
+ */
+ Expr asIndirectDefinition(int indirectionIndex) {
+ exists(StoreInstruction store |
+ this.(IndirectInstruction).hasInstructionAndIndirectionIndex(store, indirectionIndex) and
+ result = asDefinitionImpl(store)
+ )
+ }
+
+ /**
+ * Gets the indirect definition at some indirection corresponding to this
+ * node, if any.
+ */
+ Expr asIndirectDefinition() { result = this.asIndirectDefinition(_) }
+
+ /**
+ * Gets the argument that defines this `DefinitionByReferenceNode`, if any.
+ *
+ * Unlike `Node::asDefiningArgument/0`, this predicate gets the node representing
+ * the value of the `index`'th indirection after leaving a function. For example,
+ * in:
+ * ```cpp
+ * void f(int**);
+ * ...
+ * int** x = ...;
+ * f(x);
+ * ```
+ * The node `n` such that `n.asDefiningArgument(1)` is the argument `x` will
+ * contain the value of `*x` after `f` has returned, and the node `n` such that
+ * `n.asDefiningArgument(2)` is the argument `x` will contain the value of `**x`
+ * after the `f` has returned.
+ */
+ Expr asDefiningArgument(int index) {
+ this.(DefinitionByReferenceNode).getIndirectionIndex() = index and
+ result = this.(DefinitionByReferenceNode).getArgument()
+ }
+
+ /**
+ * Gets the the argument going into a function for a node that represents
+ * the indirect value of the argument after `index` loads. For example, in:
+ * ```cpp
+ * void f(int**);
+ * ...
+ * int** x = ...;
+ * f(x);
+ * ```
+ * The node `n` such that `n.asIndirectArgument(1)` represents the value of
+ * `*x` going into `f`, and the node `n` such that `n.asIndirectArgument(2)`
+ * represents the value of `**x` going into `f`.
+ */
+ Expr asIndirectArgument(int index) {
+ this.(SideEffectOperandNode).hasAddressOperandAndIndirectionIndex(_, index) and
+ result = this.(SideEffectOperandNode).getArgument()
+ }
+
+ /**
+ * Gets the the argument going into a function for a node that represents
+ * the indirect value of the argument after any non-zero number of loads.
+ */
+ Expr asIndirectArgument() { result = this.asIndirectArgument(_) }
+
+ /** Gets the positional parameter corresponding to this node, if any. */
+ Parameter asParameter() {
+ exists(int indirectionIndex | result = this.asParameter(indirectionIndex) |
+ if result.getUnspecifiedType() instanceof ReferenceType
+ then indirectionIndex = 1
+ else indirectionIndex = 0
+ )
+ }
+
+ /**
+ * Gets the uninitialized local variable corresponding to this node, if
+ * any.
+ */
+ LocalVariable asUninitialized() { result = this.(UninitializedNode).getLocalVariable() }
+
+ /**
+ * Gets the uninitialized local variable corresponding to this node behind
+ * `index` number of indirections, if any.
+ */
+ LocalVariable asIndirectUninitialized(int index) {
+ exists(IndirectUninitializedNode indirectUninitializedNode |
+ this = indirectUninitializedNode and
+ indirectUninitializedNode.getIndirectionIndex() = index
+ |
+ result = indirectUninitializedNode.getLocalVariable()
+ )
+ }
+
+ /**
+ * Gets the uninitialized local variable corresponding to this node behind
+ * a number indirections, if any.
+ */
+ LocalVariable asIndirectUninitialized() { result = this.asIndirectUninitialized(_) }
+
+ /**
+ * Gets the positional parameter corresponding to the node that represents
+ * the value of the parameter after `index` number of loads, if any. For
+ * example, in:
+ * ```cpp
+ * void f(int** x) { ... }
+ * ```
+ * - The node `n` such that `n.asParameter(0)` is the parameter `x` represents
+ * the value of `x`.
+ * - The node `n` such that `n.asParameter(1)` is the parameter `x` represents
+ * the value of `*x`.
+ * - The node `n` such that `n.asParameter(2)` is the parameter `x` represents
+ * the value of `**x`.
+ */
+ Parameter asParameter(int index) {
+ index = 0 and
+ result = this.(ExplicitParameterNode).getParameter()
+ or
+ this.(IndirectParameterNode).getIndirectionIndex() = index and
+ result = this.(IndirectParameterNode).getParameter()
+ }
+
+ /**
+ * Holds if this node represents the `indirectionIndex`'th indirection of
+ * the value of an output parameter `p` just before reaching the end of a function.
+ */
+ predicate isFinalValueOfParameter(Parameter p, int indirectionIndex) {
+ exists(FinalParameterNode n | n = this |
+ p = n.getParameter() and
+ indirectionIndex = n.getIndirectionIndex()
+ )
+ }
+
+ /**
+ * Holds if this node represents the value of an output parameter `p`
+ * just before reaching the end of a function.
+ */
+ predicate isFinalValueOfParameter(Parameter p) { this.isFinalValueOfParameter(p, _) }
+
+ /**
+ * Gets the variable corresponding to this node, if any. This can be used for
+ * modeling flow in and out of global variables.
+ */
+ Variable asVariable() {
+ this = TGlobalLikeVariableNode(result, getMinIndirectionsForType(result.getUnspecifiedType()))
+ }
+
+ /**
+ * Gets the `indirectionIndex`'th indirection of this node's underlying variable, if any.
+ *
+ * This can be used for modeling flow in and out of global variables.
+ */
+ Variable asIndirectVariable(int indirectionIndex) {
+ indirectionIndex > getMinIndirectionsForType(result.getUnspecifiedType()) and
+ this = TGlobalLikeVariableNode(result, indirectionIndex)
+ }
+
+ /** Gets an indirection of this node's underlying variable, if any. */
+ Variable asIndirectVariable() { result = this.asIndirectVariable(_) }
+
+ /**
+ * Gets the expression that is partially defined by this node, if any.
+ *
+ * Partial definitions are created for field stores (`x.y = taint();` is a partial
+ * definition of `x`), and for calls that may change the value of an object (so
+ * `x.set(taint())` is a partial definition of `x`, and `transfer(&x, taint())` is
+ * a partial definition of `&x`).
+ */
+ Expr asPartialDefinition() {
+ exists(PartialDefinitionNode pdn | this = pdn |
+ pdn.getIndirectionIndex() > 0 and
+ result = pdn.getDefinedExpr()
+ )
+ }
+
+ /**
+ * Gets an upper bound on the type of this node.
+ */
+ Type getTypeBound() { result = this.getType() }
+
+ /** Gets the location of this element. */
+ final Location getLocation() { result = getLocationCached(this) }
+
+ /** INTERNAL: Do not use. */
+ Location getLocationImpl() {
+ none() // overridden by subclasses
+ }
+
+ /** Gets a textual representation of this element. */
+ final string toString() { result = toStringCached(this) }
+
+ /** INTERNAL: Do not use. */
+ string toStringImpl() {
+ none() // overridden by subclasses
+ }
+ }
+
+ /**
+ * An instruction, viewed as a node in a data flow graph.
+ */
+ class InstructionNode extends Node0 {
+ override InstructionNode0 node;
+ Instruction instr;
+
+ InstructionNode() { instr = node.getInstruction() }
+
+ /** Gets the instruction corresponding to this node. */
+ Instruction getInstruction() { result = instr }
+ }
+
+ /**
+ * An operand, viewed as a node in a data flow graph.
+ */
+ class OperandNode extends Node, Node0 {
+ override OperandNode0 node;
+ Operand op;
+
+ OperandNode() { op = node.getOperand() }
+
+ /** Gets the operand corresponding to this node. */
+ Operand getOperand() { result = op }
+ }
+
+ /**
+ * A node associated with an object after an operation that might have
+ * changed its state.
+ *
+ * This can be either the argument to a callable after the callable returns
+ * (which might have mutated the argument), or the qualifier of a field after
+ * an update to the field.
+ *
+ * Nodes corresponding to AST elements, for example `ExprNode`, usually refer
+ * to the value before the update with the exception of `ClassInstanceExpr`,
+ * which represents the value after the constructor has run.
+ */
+ abstract class PostUpdateNode extends Node {
+ /**
+ * Gets the node before the state update.
+ */
+ abstract Node getPreUpdateNode();
+
+ final override Type getType() { result = this.getPreUpdateNode().getType() }
+ }
+
+ abstract private class AbstractUninitializedNode extends Node {
+ LocalVariable v;
+ int indirectionIndex;
+
+ AbstractUninitializedNode() {
+ exists(SsaImpl::Definition def, SsaImpl::SourceVariable sv |
+ def.getIndirectionIndex() = indirectionIndex and
+ def.getValue().asInstruction() instanceof UninitializedInstruction and
+ SsaImpl::defToNode(this, def, sv) and
+ v = sv.getBaseVariable().(SsaImpl::BaseIRVariable).getIRVariable().getAst()
+ )
+ }
+
+ /** Gets the uninitialized local variable corresponding to this node. */
+ LocalVariable getLocalVariable() { result = v }
+ }
+
+ /**
+ * The value of an uninitialized local variable, viewed as a node in a data
+ * flow graph.
+ */
+ class UninitializedNode extends AbstractUninitializedNode {
+ UninitializedNode() { indirectionIndex = 0 }
+ }
+
+ /**
+ * The value of an uninitialized local variable behind one or more levels of
+ * indirection, viewed as a node in a data flow graph.
+ */
+ class IndirectUninitializedNode extends AbstractUninitializedNode {
+ IndirectUninitializedNode() { indirectionIndex > 0 }
+
+ /** Gets the indirection index of this node. */
+ int getIndirectionIndex() { result = indirectionIndex }
+ }
+
+ /**
+ * The value of a parameter at function entry, viewed as a node in a data
+ * flow graph. This includes both explicit parameters such as `x` in `f(x)`
+ * and implicit parameters such as `this` in `x.f()`.
+ *
+ * To match a specific kind of parameter, consider using one of the subclasses
+ * `ExplicitParameterNode`, `ThisParameterNode`, or
+ * `ParameterIndirectionNode`.
+ */
+ final class ParameterNode = AbstractParameterNode;
+
+ /** An explicit positional parameter, including `this`, but not `...`. */
+ final class DirectParameterNode = AbstractDirectParameterNode;
+
+ /**
+ * A node representing an indirection of a positional parameter,
+ * including `*this`, but not `*...`.
+ */
+ final class IndirectParameterNode = AbstractIndirectParameterNode;
+
+ final class ExplicitParameterNode = AbstractExplicitParameterNode;
+
+ /** An implicit `this` parameter. */
+ class ThisParameterInstructionNode extends AbstractExplicitParameterNode,
+ InstructionDirectParameterNode
+ {
+ ThisParameterInstructionNode() { instr.getIRVariable() instanceof IRThisVariable }
+
+ override string toStringImpl() { result = "this" }
+ }
+
+ /**
+ * A node that represents the value of a variable after a function call that
+ * may have changed the variable because it's passed by reference.
+ *
+ * A typical example would be a call `f(&x)`. Firstly, there will be flow into
+ * `x` from previous definitions of `x`. Secondly, there will be a
+ * `DefinitionByReferenceNode` to represent the value of `x` after the call has
+ * returned. This node will have its `getArgument()` equal to `&x` and its
+ * `getVariableAccess()` equal to `x`.
+ */
+ class DefinitionByReferenceNode extends IndirectArgumentOutNode {
+ DefinitionByReferenceNode() { this.getIndirectionIndex() > 0 }
+
+ /** Gets the unconverted argument corresponding to this node. */
+ Expr getArgument() {
+ result = this.getAddressOperand().getDef().getUnconvertedResultExpression()
+ }
+
+ /** Gets the parameter through which this value is assigned. */
+ Parameter getParameter() {
+ result =
+ this.getCallInstruction()
+ .getStaticCallTarget()
+ .(Function)
+ .getParameter(this.getArgumentIndex())
+ }
+ }
+
+ /**
+ * A `Node` corresponding to a global (or `static` local) variable in the
+ * program, as opposed to the value of that variable at some particular point.
+ * This is used to model flow through global variables (and `static` local
+ * variables).
+ *
+ * There is no `VariableNode` for non-`static` local variables.
+ */
+ class VariableNode extends Node, TGlobalLikeVariableNode {
+ Variable v;
+ int indirectionIndex;
+
+ VariableNode() { this = TGlobalLikeVariableNode(v, indirectionIndex) }
+
+ /** Gets the variable corresponding to this node. */
+ Variable getVariable() { result = v }
+
+ /** Gets the indirection index of this node. */
+ int getIndirectionIndex() { result = indirectionIndex }
+
+ override Declaration getFunction() { none() }
+
+ override DataFlowCallable getEnclosingCallable() {
+ // When flow crosses from one _enclosing callable_ to another, the
+ // interprocedural data-flow library discards call contexts and inserts a
+ // node in the big-step relation used for human-readable path explanations.
+ // Therefore we want a distinct enclosing callable for each `VariableNode`,
+ // and that can be the `Variable` itself.
+ result.asSourceCallable() = v
+ }
+
+ override Type getType() { result = getTypeImpl(v.getUnderlyingType(), indirectionIndex - 1) }
+
+ final override Location getLocationImpl() {
+ // Certain variables (such as parameters) can have multiple locations.
+ // When there's a unique location we use that one, but if multiple locations
+ // exist we default to an unknown location.
+ result = unique( | | v.getLocation())
+ or
+ not exists(unique( | | v.getLocation())) and
+ result instanceof UnknownLocation
+ }
+
+ override string toStringImpl() { result = stars(this) + v.toString() }
+ }
+
+ /**
+ * Gets the node corresponding to `instr`.
+ */
+ InstructionNode instructionNode(Instruction instr) { result.getInstruction() = instr }
+
+ /**
+ * Gets the node corresponding to `operand`.
+ */
+ OperandNode operandNode(Operand operand) { result.getOperand() = operand }
+
+ /**
+ * Gets the `Node` corresponding to the value of evaluating `e` or any of its
+ * conversions. There is no result if `e` is a `Conversion`. For data flowing
+ * _out of_ an expression, like when an argument is passed by reference, use
+ * `definitionByReferenceNodeFromArgument` instead.
+ */
+ ExprNode exprNode(Expr e) { result.getExpr(_) = e }
+
+ /**
+ * Gets the `Node` corresponding to the value of evaluating `e`. Here, `e` may
+ * be a `Conversion`. For data flowing _out of_ an expression, like when an
+ * argument is passed by reference, use
+ * `definitionByReferenceNodeFromArgument` instead.
+ */
+ ExprNode convertedExprNode(Expr e) { result.getConvertedExpr(_) = e }
+
+ /**
+ * Gets the `Node` corresponding to the value of `p` at function entry.
+ */
+ ExplicitParameterNode parameterNode(Parameter p) { result.getParameter() = p }
+
+ /**
+ * Gets the `Node` corresponding to a definition by reference of the variable
+ * that is passed as unconverted `argument` of a call.
+ */
+ DefinitionByReferenceNode definitionByReferenceNodeFromArgument(Expr argument) {
+ result.getArgument() = argument
+ }
+
+ /** Gets the `VariableNode` corresponding to the variable `v`. */
+ VariableNode variableNode(Variable v) {
+ result.getVariable() = v and result.getIndirectionIndex() = 1
+ }
+
+ /**
+ * Gets the `Node` corresponding to the value of an uninitialized local
+ * variable `v`.
+ */
+ Node uninitializedNode(LocalVariable v) { result.asUninitialized() = v }
+
+ /**
+ * Holds if `indirectOperand` is the dataflow node that represents the
+ * indirection of `operand` with indirection index `indirectionIndex`.
+ */
+ predicate hasOperandAndIndex(
+ IndirectOperand indirectOperand, Operand operand, int indirectionIndex
+ ) {
+ indirectOperand.hasOperandAndIndirectionIndex(operand, indirectionIndex)
+ }
+
+ /**
+ * Holds if `indirectInstr` is the dataflow node that represents the
+ * indirection of `instr` with indirection index `indirectionIndex`.
+ */
+ predicate hasInstructionAndIndex(
+ IndirectInstruction indirectInstr, Instruction instr, int indirectionIndex
+ ) {
+ indirectInstr.hasInstructionAndIndirectionIndex(instr, indirectionIndex)
+ }
+}
+
+private import Public
+
+/**
+ * A class that lifts pre-SSA dataflow nodes to regular dataflow nodes.
+ */
+private class Node0 extends Node, TNode0 {
+ Node0Impl node;
+
+ Node0() { this = TNode0(node) }
+
+ override DataFlowCallable getEnclosingCallable() {
+ result.asSourceCallable() = node.getEnclosingCallable()
+ }
+
+ override Declaration getFunction() { result = node.getFunction() }
+
+ override Location getLocationImpl() { result = node.getLocation() }
+
+ override string toStringImpl() { result = node.toStringImpl() }
+
+ override Type getType() { result = node.getType() }
+
+ override predicate isGLValue() { node.isGLValue() }
+}
+
+class PostUpdateNodeImpl extends PartialDefinitionNode, TPostUpdateNodeImpl {
+ int indirectionIndex;
+ Operand operand;
+
+ PostUpdateNodeImpl() { this = TPostUpdateNodeImpl(operand, indirectionIndex) }
+
+ override Declaration getFunction() { result = operand.getUse().getEnclosingFunction() }
+
+ override DataFlowCallable getEnclosingCallable() {
+ result = this.getPreUpdateNode().getEnclosingCallable()
+ }
+
+ /** Gets the operand associated with this node. */
+ Operand getOperand() { result = operand }
+
+ /** Gets the indirection index associated with this node. */
+ override int getIndirectionIndex() { result = indirectionIndex }
+
+ override Location getLocationImpl() { result = operand.getLocation() }
+
+ final override Node getPreUpdateNode() {
+ indirectionIndex > 0 and
+ hasOperandAndIndex(result, operand, indirectionIndex)
+ or
+ indirectionIndex = 0 and
+ result.asOperand() = operand
+ }
+
+ final override Expr getDefinedExpr() {
+ result = operand.getDef().getUnconvertedResultExpression()
+ }
+}
+
+/**
+ * The node representing the value of a field after it has been updated.
+ */
+class PostFieldUpdateNode extends PostUpdateNodeImpl {
+ FieldAddress fieldAddress;
+
+ PostFieldUpdateNode() { operand = fieldAddress.getObjectAddressOperand() }
+
+ FieldAddress getFieldAddress() { result = fieldAddress }
+
+ Field getUpdatedField() { result = this.getFieldAddress().getField() }
+
+ override string toStringImpl() {
+ result = this.getPreUpdateNode().toStringImpl() + " [post update]"
+ }
+}
+
+/**
+ * The base class for nodes that perform "partial definitions".
+ *
+ * In contrast to a normal "definition", which provides a new value for
+ * something, a partial definition is an expression that may affect a
+ * value, but does not necessarily replace it entirely. For example:
+ * ```
+ * x.y = 1; // a partial definition of the object `x`.
+ * x.y.z = 1; // a partial definition of the object `x.y` and `x`.
+ * x.setY(1); // a partial definition of the object `x`.
+ * setY(&x); // a partial definition of the object `x`.
+ * ```
+ */
+abstract private class PartialDefinitionNode extends PostUpdateNode {
+ /** Gets the indirection index of this node. */
+ abstract int getIndirectionIndex();
+
+ /** Gets the expression that is partially defined by this node. */
+ abstract Expr getDefinedExpr();
+}
+
+/**
+ * A node representing the indirection of a value after it
+ * has been returned from a function.
+ */
+class IndirectArgumentOutNode extends PostUpdateNodeImpl {
+ override ArgumentOperand operand;
+
+ /**
+ * Gets the index of the argument that is associated with this post-
+ * update node.
+ */
+ int getArgumentIndex() {
+ exists(CallInstruction call | call.getArgumentOperand(result) = operand)
+ }
+
+ /**
+ * Gets the `Operand` that represents the address of the value that is being
+ * updated.
+ */
+ Operand getAddressOperand() { result = operand }
+
+ /**
+ * Gets the `CallInstruction` that represents the call that updated the
+ * argument.
+ */
+ CallInstruction getCallInstruction() { result.getAnArgumentOperand() = operand }
+
+ /**
+ * Gets the `Function` that the call targets, if this is statically known.
+ */
+ Declaration getStaticCallTarget() { result = this.getCallInstruction().getStaticCallTarget() }
+
+ override string toStringImpl() {
+ exists(string prefix | if indirectionIndex > 0 then prefix = "" else prefix = "pointer to " |
+ // This string should be unique enough to be helpful but common enough to
+ // avoid storing too many different strings.
+ result = prefix + this.getStaticCallTarget().getName() + " output argument"
+ or
+ not exists(this.getStaticCallTarget()) and
+ result = prefix + "output argument"
+ )
+ }
+}
+
+/**
+ * Holds if `node` is an indirect operand with columns `(operand, indirectionIndex)`, and
+ * `operand` represents a use of the fully converted value of `call`.
+ */
+private predicate hasOperand(Node node, CallInstruction call, int indirectionIndex, Operand operand) {
+ operandForFullyConvertedCall(operand, call) and
+ hasOperandAndIndex(node, operand, indirectionIndex)
+}
+
+/**
+ * Holds if `node` is an indirect instruction with columns `(instr, indirectionIndex)`, and
+ * `instr` represents a use of the fully converted value of `call`.
+ *
+ * Note that `hasOperand(node, _, _, _)` implies `not hasInstruction(node, _, _, _)`.
+ */
+private predicate hasInstruction(
+ Node node, CallInstruction call, int indirectionIndex, Instruction instr
+) {
+ instructionForFullyConvertedCall(instr, call) and
+ hasInstructionAndIndex(node, instr, indirectionIndex)
+}
+
+/**
+ * A node representing the indirect value of a function call (i.e., a value hidden
+ * behind a number of indirections).
+ */
+class IndirectReturnOutNode extends Node {
+ CallInstruction call;
+ int indirectionIndex;
+
+ IndirectReturnOutNode() {
+ // Annoyingly, we need to pick the fully converted value as the output of the function to
+ // make flow through in the shared dataflow library work correctly.
+ hasOperand(this, call, indirectionIndex, _)
+ or
+ hasInstruction(this, call, indirectionIndex, _)
+ }
+
+ CallInstruction getCallInstruction() { result = call }
+
+ int getIndirectionIndex() { result = indirectionIndex }
+
+ /** Gets the operand associated with this node, if any. */
+ Operand getOperand() { hasOperand(this, call, indirectionIndex, result) }
+
+ /** Gets the instruction associated with this node, if any. */
+ Instruction getInstruction() { hasInstruction(this, call, indirectionIndex, result) }
+}
+
+/**
+ * An `IndirectReturnOutNode` which is used as a destination of a store operation.
+ * When it's used for a store operation it's useful to have this be a `PostUpdateNode` for
+ * the shared dataflow library's flow-through mechanism to detect flow in cases such as:
+ * ```cpp
+ * struct MyInt {
+ * int i;
+ * int& getRef() { return i; }
+ * };
+ * ...
+ * MyInt mi;
+ * mi.getRef() = source(); // this is detected as a store to `i` via flow-through.
+ * sink(mi.i);
+ * ```
+ */
+private class PostIndirectReturnOutNode extends IndirectReturnOutNode, PostUpdateNode {
+ PostIndirectReturnOutNode() {
+ any(StoreInstruction store).getDestinationAddressOperand() = this.getOperand()
+ }
+
+ override Node getPreUpdateNode() { result = this }
+}
+
+/**
+ * A node that represents the indirect value of an operand in the IR
+ * after `index` number of loads.
+ */
+private class RawIndirectOperand0 extends Node, TRawIndirectOperand0 {
+ Node0Impl node;
+ int indirectionIndex;
+
+ RawIndirectOperand0() { this = TRawIndirectOperand0(node, indirectionIndex) }
+
+ /** Gets the underlying instruction. */
+ Operand getOperand() { result = node.asOperand() }
+
+ /** Gets the underlying indirection index. */
+ int getIndirectionIndex() { result = indirectionIndex }
+
+ override Declaration getFunction() { result = node.getFunction() }
+
+ override DataFlowCallable getEnclosingCallable() {
+ result.asSourceCallable() = node.getEnclosingCallable()
+ }
+
+ override predicate isGLValue() { this.getOperand().isGLValue() }
+
+ override Type getType() {
+ exists(int sub, Type type, boolean isGLValue |
+ type = getOperandType(this.getOperand(), isGLValue) and
+ if isGLValue = true then sub = 1 else sub = 0
+ |
+ result = getTypeImpl(type.getUnderlyingType(), indirectionIndex - sub)
+ )
+ }
+
+ final override Location getLocationImpl() {
+ if exists(this.getOperand().getLocation())
+ then result = this.getOperand().getLocation()
+ else result instanceof UnknownLocation
+ }
+
+ override string toStringImpl() { result = stars(this) + operandToString(this.getOperand()) }
+}
+
+/**
+ * A node that represents the indirect value of an instruction in the IR
+ * after `index` number of loads.
+ */
+private class RawIndirectInstruction0 extends Node, TRawIndirectInstruction0 {
+ Node0Impl node;
+ int indirectionIndex;
+
+ RawIndirectInstruction0() { this = TRawIndirectInstruction0(node, indirectionIndex) }
+
+ /** Gets the underlying instruction. */
+ Instruction getInstruction() { result = node.asInstruction() }
+
+ /** Gets the underlying indirection index. */
+ int getIndirectionIndex() { result = indirectionIndex }
+
+ override Declaration getFunction() { result = node.getFunction() }
+
+ override DataFlowCallable getEnclosingCallable() {
+ result.asSourceCallable() = node.getEnclosingCallable()
+ }
+
+ override predicate isGLValue() { this.getInstruction().isGLValue() }
+
+ override Type getType() {
+ exists(int sub, Type type, boolean isGLValue |
+ type = getInstructionType(this.getInstruction(), isGLValue) and
+ if isGLValue = true then sub = 1 else sub = 0
+ |
+ result = getTypeImpl(type.getUnderlyingType(), indirectionIndex - sub)
+ )
+ }
+
+ final override Location getLocationImpl() {
+ if exists(this.getInstruction().getLocation())
+ then result = this.getInstruction().getLocation()
+ else result instanceof UnknownLocation
+ }
+
+ override string toStringImpl() {
+ result = stars(this) + instructionToString(this.getInstruction())
+ }
+}
+
+/**
+ * A node that represents the indirect value of an operand in the IR
+ * after a number of loads.
+ */
+class RawIndirectOperand extends Node {
+ int indirectionIndex;
+ Operand operand;
+
+ RawIndirectOperand() {
+ exists(Node0Impl node | operand = node.asOperand() |
+ this = TRawIndirectOperand0(node, indirectionIndex)
+ or
+ this = TRawIndirectInstruction0(node, indirectionIndex)
+ )
+ }
+
+ /** Gets the operand associated with this node. */
+ Operand getOperand() { result = operand }
+
+ /** Gets the underlying indirection index. */
+ int getIndirectionIndex() { result = indirectionIndex }
+}
+
+/**
+ * A node that represents the indirect value of an instruction in the IR
+ * after a number of loads.
+ */
+class RawIndirectInstruction extends Node {
+ int indirectionIndex;
+ Instruction instr;
+
+ RawIndirectInstruction() {
+ exists(Node0Impl node | instr = node.asInstruction() |
+ this = TRawIndirectOperand0(node, indirectionIndex)
+ or
+ this = TRawIndirectInstruction0(node, indirectionIndex)
+ )
+ }
+
+ /** Gets the instruction associated with this node. */
+ Instruction getInstruction() { result = instr }
+
+ /** Gets the underlying indirection index. */
+ int getIndirectionIndex() { result = indirectionIndex }
+}
+
+/**
+ * A synthesized SSA node produced by the shared SSA library, viewed as a node
+ * in a data flow graph.
+ */
+class SsaSynthNode extends Node, TSsaSynthNode {
+ SsaImpl::SynthNode node;
+
+ SsaSynthNode() { this = TSsaSynthNode(node) }
+
+ /** Gets the synthesized SSA node associated with this node. */
+ SsaImpl::SynthNode getSynthNode() { result = node }
+
+ override DataFlowCallable getEnclosingCallable() {
+ result.asSourceCallable() = this.getFunction()
+ }
+
+ override Declaration getFunction() { result = node.getBasicBlock().getEnclosingFunction() }
+
+ override Type getType() { result = node.getSourceVariable().getType() }
+
+ override predicate isGLValue() { node.getSourceVariable().isGLValue() }
+
+ final override Location getLocationImpl() { result = node.getLocation() }
+
+ override string toStringImpl() { result = node.toString() }
+}
+
+/**
+ * Dataflow nodes necessary for iterator flow
+ */
+class SsaIteratorNode extends Node, TSsaIteratorNode {
+ IteratorFlow::IteratorFlowNode node;
+
+ SsaIteratorNode() { this = TSsaIteratorNode(node) }
+
+ /** Gets the phi node associated with this node. */
+ IteratorFlow::IteratorFlowNode getIteratorFlowNode() { result = node }
+
+ override DataFlowCallable getEnclosingCallable() {
+ result.asSourceCallable() = this.getFunction()
+ }
+
+ override Declaration getFunction() { result = node.getFunction() }
+
+ override Type getType() { result = node.getType() }
+
+ final override Location getLocationImpl() { result = node.getLocation() }
+
+ override string toStringImpl() { result = node.toString() }
+}
+
+/**
+ * A node representing a value after leaving a function.
+ */
+class SideEffectOperandNode extends Node instanceof IndirectOperand {
+ CallInstruction call;
+ int argumentIndex;
+ ArgumentOperand arg;
+
+ SideEffectOperandNode() {
+ arg = call.getArgumentOperand(argumentIndex) and
+ IndirectOperand.super.hasOperandAndIndirectionIndex(arg, _)
+ }
+
+ CallInstruction getCallInstruction() { result = call }
+
+ /** Gets the underlying operand and the underlying indirection index. */
+ predicate hasAddressOperandAndIndirectionIndex(Operand operand, int indirectionIndex) {
+ IndirectOperand.super.hasOperandAndIndirectionIndex(operand, indirectionIndex)
+ }
+
+ int getArgumentIndex() { result = argumentIndex }
+
+ override DataFlowCallable getEnclosingCallable() {
+ result.asSourceCallable() = this.getFunction()
+ }
+
+ override Declaration getFunction() { result = call.getEnclosingFunction() }
+
+ Expr getArgument() { result = call.getArgument(argumentIndex).getUnconvertedResultExpression() }
+}
+
+/**
+ * A node representing the value of a global variable just before returning
+ * from a function body.
+ */
+class FinalGlobalValue extends Node, TFinalGlobalValue {
+ SsaImpl::GlobalUse globalUse;
+
+ FinalGlobalValue() { this = TFinalGlobalValue(globalUse) }
+
+ /** Gets the underlying SSA use. */
+ SsaImpl::GlobalUse getGlobalUse() { result = globalUse }
+
+ override DataFlowCallable getEnclosingCallable() {
+ result.asSourceCallable() = this.getFunction()
+ }
+
+ override Declaration getFunction() { result = globalUse.getIRFunction().getFunction() }
+
+ override Type getType() {
+ exists(int indirectionIndex |
+ indirectionIndex = globalUse.getIndirectionIndex() and
+ result = getTypeImpl(globalUse.getUnderlyingType(), indirectionIndex)
+ )
+ }
+
+ final override Location getLocationImpl() { result = globalUse.getLocation() }
+
+ override string toStringImpl() { result = globalUse.toString() }
+}
+
+/**
+ * A node representing the value of a global variable just after entering
+ * a function body.
+ */
+class InitialGlobalValue extends Node, TInitialGlobalValue {
+ SsaImpl::GlobalDef globalDef;
+
+ InitialGlobalValue() { this = TInitialGlobalValue(globalDef) }
+
+ /** Gets the underlying SSA definition. */
+ SsaImpl::GlobalDef getGlobalDef() { result = globalDef }
+
+ override DataFlowCallable getEnclosingCallable() {
+ result.asSourceCallable() = this.getFunction()
+ }
+
+ override Declaration getFunction() { result = globalDef.getFunction() }
+
+ final override predicate isGLValue() { globalDef.getIndirectionIndex() = 0 }
+
+ override Type getType() { result = globalDef.getUnderlyingType() }
+
+ final override Location getLocationImpl() { result = globalDef.getLocation() }
+
+ override string toStringImpl() { result = globalDef.toString() }
+}
+
+/**
+ * A node representing a parameter for a function with no body.
+ */
+class BodyLessParameterNodeImpl extends Node, TBodyLessParameterNodeImpl {
+ Parameter p;
+ int indirectionIndex;
+
+ BodyLessParameterNodeImpl() { this = TBodyLessParameterNodeImpl(p, indirectionIndex) }
+
+ override DataFlowCallable getEnclosingCallable() {
+ result.asSourceCallable() = this.getFunction()
+ }
+
+ override Declaration getFunction() { result = p.getFunction() }
+
+ /** Gets the indirection index of this node. */
+ int getIndirectionIndex() { result = indirectionIndex }
+
+ override Type getType() {
+ result = getTypeImpl(p.getUnderlyingType(), this.getIndirectionIndex())
+ }
+
+ final override Location getLocationImpl() {
+ result = unique( | | p.getLocation())
+ or
+ count(p.getLocation()) != 1 and
+ result instanceof UnknownLocation
+ }
+
+ final override string toStringImpl() {
+ exists(string prefix | prefix = stars(this) | result = prefix + p.toString())
+ }
+}
+
+/**
+ * A data-flow node used to model flow summaries. That is, a dataflow node
+ * that is synthesized to represent a parameter, return value, or other part
+ * of a models-as-data modeled function.
+ */
+class FlowSummaryNode extends Node, TFlowSummaryNode {
+ /**
+ * Gets the models-as-data `SummaryNode` associated with this dataflow
+ * `FlowSummaryNode`.
+ */
+ FlowSummaryImpl::Private::SummaryNode getSummaryNode() { this = TFlowSummaryNode(result) }
+
+ /**
+ * Gets the summarized callable that this node belongs to.
+ */
+ FlowSummaryImpl::Public::SummarizedCallable getSummarizedCallable() {
+ result = this.getSummaryNode().getSummarizedCallable()
+ }
+
+ /**
+ * Gets the enclosing callable. For a `FlowSummaryNode` this is always the
+ * summarized function this node is part of.
+ */
+ override DataFlowCallable getEnclosingCallable() {
+ result.asSummarizedCallable() = this.getSummarizedCallable()
+ }
+
+ override Location getLocationImpl() { result = this.getSummarizedCallable().getLocation() }
+
+ override string toStringImpl() { result = this.getSummaryNode().toString() }
+}
+
+/**
+ * A node representing the indirection of a value that is
+ * about to be returned from a function.
+ */
+class IndirectReturnNode extends Node {
+ IndirectReturnNode() {
+ this instanceof FinalParameterNode
+ or
+ this.(IndirectOperand)
+ .hasOperandAndIndirectionIndex(any(ReturnValueInstruction ret).getReturnAddressOperand(), _)
+ }
+
+ override SourceCallable getEnclosingCallable() { result.asSourceCallable() = this.getFunction() }
+
+ /**
+ * Holds if this node represents the value that is returned to the caller
+ * through a `return` statement.
+ */
+ predicate isNormalReturn() { this instanceof IndirectOperand }
+
+ /**
+ * Holds if this node represents the value that is returned to the caller
+ * by writing to the `argumentIndex`'th argument of the call.
+ */
+ predicate isParameterReturn(int argumentIndex) {
+ this.(FinalParameterNode).getArgumentIndex() = argumentIndex
+ }
+
+ /** Gets the indirection index of this indirect return node. */
+ int getIndirectionIndex() {
+ result = this.(FinalParameterNode).getIndirectionIndex()
+ or
+ this.(IndirectOperand).hasOperandAndIndirectionIndex(_, result)
+ }
+}
+
+/**
+ * A node representing the value of an output parameter
+ * just before reaching the end of a function.
+ */
+class FinalParameterNode extends Node, TFinalParameterNode {
+ Parameter p;
+ int indirectionIndex;
+
+ FinalParameterNode() { this = TFinalParameterNode(p, indirectionIndex) }
+
+ /** Gets the parameter associated with this final use. */
+ Parameter getParameter() { result = p }
+
+ /** Gets the underlying indirection index. */
+ int getIndirectionIndex() { result = indirectionIndex }
+
+ /** Gets the argument index associated with this final use. */
+ final int getArgumentIndex() { result = p.getIndex() }
+
+ override Declaration getFunction() { result = p.getFunction() }
+
+ override DataFlowCallable getEnclosingCallable() {
+ result.asSourceCallable() = this.getFunction()
+ }
+
+ override Type getType() { result = getTypeImpl(p.getUnderlyingType(), indirectionIndex) }
+
+ final override Location getLocationImpl() {
+ // Parameters can have multiple locations. When there's a unique location we use
+ // that one, but if multiple locations exist we default to an unknown location.
+ result = unique( | | p.getLocation())
+ or
+ not exists(unique( | | p.getLocation())) and
+ result instanceof UnknownLocation
+ }
+
+ override string toStringImpl() { result = stars(this) + p.toString() }
+}
+
+abstract private class AbstractParameterNode extends Node {
+ /**
+ * Holds if this node is the parameter of `f` at the specified position. The
+ * implicit `this` parameter is considered to have position `-1`, and
+ * pointer-indirection parameters are at further negative positions.
+ */
+ predicate isSourceParameterOf(Declaration f, ParameterPosition pos) { none() }
+
+ /**
+ * Holds if this node is the parameter of `sc` at the specified position. The
+ * implicit `this` parameter is considered to have position `-1`, and
+ * pointer-indirection parameters are at further negative positions.
+ */
+ predicate isSummaryParameterOf(
+ FlowSummaryImpl::Public::SummarizedCallable sc, ParameterPosition pos
+ ) {
+ none()
+ }
+
+ /**
+ * Holds if this node is the parameter of `c` at the specified position. The
+ * implicit `this` parameter is considered to have position `-1`, and
+ * pointer-indirection parameters are at further negative positions.
+ */
+ final predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
+ this.isSummaryParameterOf(c.asSummarizedCallable(), pos)
+ or
+ this.isSourceParameterOf(c.asSourceCallable(), pos)
+ }
+
+ /** Gets the `Parameter` associated with this node, if it exists. */
+ Parameter getParameter() { none() } // overridden by subclasses
+
+ /**
+ * Holds if this node represents an implicit `this` parameter, if it exists.
+ */
+ predicate isThis() { none() } // overridden by subclasses
+}
+
+abstract private class AbstractIndirectParameterNode extends AbstractParameterNode {
+ /** Gets the indirection index of this parameter node. */
+ abstract int getIndirectionIndex();
+}
+
+pragma[noinline]
+private predicate indirectParameterNodeHasArgumentIndexAndIndex(
+ IndirectInstructionParameterNode node, int argumentIndex, int indirectionIndex
+) {
+ node.hasInstructionAndIndirectionIndex(_, indirectionIndex) and
+ node.getArgumentIndex() = argumentIndex
+}
+
+pragma[noinline]
+private predicate indirectPositionHasArgumentIndexAndIndex(
+ IndirectionPosition pos, int argumentIndex, int indirectionIndex
+) {
+ pos.getArgumentIndex() = argumentIndex and
+ pos.getIndirectionIndex() = indirectionIndex
+}
+
+private class IndirectInstructionParameterNode extends AbstractIndirectParameterNode instanceof IndirectInstruction
+{
+ InitializeParameterInstruction init;
+
+ IndirectInstructionParameterNode() {
+ IndirectInstruction.super.hasInstructionAndIndirectionIndex(init, _) and
+ // We don't model catch parameters as parameter nodes
+ not exists(init.getParameter().getCatchBlock())
+ }
+
+ int getArgumentIndex() { init.hasIndex(result) }
+
+ override string toStringImpl() {
+ exists(string prefix | prefix = stars(this) |
+ result = prefix + this.getParameter().toString()
+ or
+ not exists(this.getParameter()) and
+ result = prefix + "this"
+ )
+ }
+
+ override Parameter getParameter() { result = init.getParameter() }
+
+ override predicate isThis() { init.hasIndex(-1) }
+
+ override DataFlowCallable getEnclosingCallable() {
+ result.asSourceCallable() = this.getFunction()
+ }
+
+ override Declaration getFunction() { result = init.getEnclosingFunction() }
+
+ override predicate isSourceParameterOf(Declaration f, ParameterPosition pos) {
+ this.getFunction() = f and
+ exists(int argumentIndex, int indirectionIndex |
+ indirectPositionHasArgumentIndexAndIndex(pos, argumentIndex, indirectionIndex) and
+ indirectParameterNodeHasArgumentIndexAndIndex(this, argumentIndex, indirectionIndex)
+ )
+ }
+
+ /** Gets the underlying operand and the underlying indirection index. */
+ predicate hasInstructionAndIndirectionIndex(Instruction instr, int index) {
+ IndirectInstruction.super.hasInstructionAndIndirectionIndex(instr, index)
+ }
+
+ final override int getIndirectionIndex() { this.hasInstructionAndIndirectionIndex(init, result) }
+}
+
+abstract private class AbstractDirectParameterNode extends AbstractParameterNode { }
+
+/**
+ * A non-indirect parameter node that is represented as an `Instruction`.
+ */
+abstract class InstructionDirectParameterNode extends InstructionNode, AbstractDirectParameterNode {
+ final override InitializeParameterInstruction instr;
+
+ /**
+ * Gets the `IRVariable` that this parameter references.
+ */
+ final IRVariable getIRVariable() { result = instr.getIRVariable() }
+
+ override predicate isThis() { instr.hasIndex(-1) }
+
+ override Parameter getParameter() { result = instr.getParameter() }
+
+ override predicate isSourceParameterOf(Declaration f, ParameterPosition pos) {
+ this.getFunction() = f and
+ exists(int argumentIndex |
+ pos.(DirectPosition).getArgumentIndex() = argumentIndex and
+ instr.hasIndex(argumentIndex)
+ )
+ }
+}
+
+abstract private class AbstractExplicitParameterNode extends AbstractDirectParameterNode { }
+
+/** An explicit positional parameter, not including `this` or `...`. */
+private class ExplicitParameterInstructionNode extends AbstractExplicitParameterNode,
+ InstructionDirectParameterNode
+{
+ ExplicitParameterInstructionNode() {
+ // We don't model catch parameters as parameter nodes.
+ exists(instr.getParameter().getFunction())
+ }
+
+ override string toStringImpl() { result = instr.getParameter().toString() }
+}
+
+/**
+ * A parameter node that is part of a summary.
+ */
+class SummaryParameterNode extends AbstractParameterNode, FlowSummaryNode {
+ SummaryParameterNode() {
+ FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), _)
+ }
+
+ private ParameterPosition getPosition() {
+ FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), result)
+ }
+
+ override predicate isSummaryParameterOf(
+ FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition p
+ ) {
+ c = this.getSummarizedCallable() and
+ p = this.getPosition()
+ }
+}
+
+private class DirectBodyLessParameterNode extends AbstractExplicitParameterNode,
+ BodyLessParameterNodeImpl
+{
+ DirectBodyLessParameterNode() { indirectionIndex = 0 }
+
+ override predicate isSourceParameterOf(Declaration f, ParameterPosition pos) {
+ this.getFunction() = f and
+ f.(Function).getParameter(pos.(DirectPosition).getArgumentIndex()) = p
+ }
+
+ override Parameter getParameter() { result = p }
+}
+
+private class IndirectBodyLessParameterNode extends AbstractIndirectParameterNode,
+ BodyLessParameterNodeImpl
+{
+ IndirectBodyLessParameterNode() { not this instanceof DirectBodyLessParameterNode }
+
+ override predicate isSourceParameterOf(Declaration f, ParameterPosition pos) {
+ exists(int argumentPosition |
+ this.getFunction() = f and
+ f.(Function).getParameter(argumentPosition) = p and
+ indirectPositionHasArgumentIndexAndIndex(pos, argumentPosition, indirectionIndex)
+ )
+ }
+
+ override int getIndirectionIndex() {
+ result = BodyLessParameterNodeImpl.super.getIndirectionIndex()
+ }
+
+ override Parameter getParameter() { result = p }
+}
+
+/**
+ * A `PostUpdateNode` that is part of a flow summary. These are synthesized,
+ * for example, when a models-as-data summary models a write to a field since
+ * the write needs to target a `PostUpdateNode`.
+ */
+class SummaryPostUpdateNode extends FlowSummaryNode, PostUpdateNode {
+ SummaryPostUpdateNode() {
+ FlowSummaryImpl::Private::summaryPostUpdateNode(this.getSummaryNode(), _)
+ }
+
+ override Node getPreUpdateNode() {
+ FlowSummaryImpl::Private::summaryPostUpdateNode(this.getSummaryNode(),
+ result.(FlowSummaryNode).getSummaryNode())
+ }
+}
+
+/**
+ * Returns `t`, but stripped of the outermost pointer, reference, etc.
+ *
+ * For example, `stripPointers(int*&)` is `int*` and `stripPointers(int*)` is `int`.
+ */
+private Type stripPointer(Type t) {
+ result = any(SsaImpl::Indirection ind | ind.getType() = t).getBaseType()
+ or
+ result = t.(PointerToMemberType).getBaseType()
+ or
+ result = t.(FunctionPointerIshType).getBaseType()
+}
+
+/**
+ * Returns `t`, but stripped of the outer-most `indirectionIndex` number of indirections.
+ */
+private Type getTypeImpl0(Type t, int indirectionIndex) {
+ indirectionIndex = 0 and
+ result = t
+ or
+ indirectionIndex > 0 and
+ exists(Type stripped |
+ stripped = stripPointer(t.stripTopLevelSpecifiers()) and
+ stripped.getUnspecifiedType() != t.getUnspecifiedType() and
+ result = getTypeImpl0(stripped, indirectionIndex - 1)
+ )
+}
+
+/**
+ * Returns `t`, but stripped of the outer-most `indirectionIndex` number of indirections.
+ *
+ * If `indirectionIndex` cannot be stripped off `t`, an `UnknownType` is returned.
+ */
+bindingset[t, indirectionIndex]
+pragma[inline_late]
+Type getTypeImpl(Type t, int indirectionIndex) {
+ result = getTypeImpl0(t, indirectionIndex)
+ or
+ not exists(getTypeImpl0(t, indirectionIndex)) and
+ result instanceof UnknownType
+}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
index 88d7dd9faf1..83f240ddae5 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
@@ -1,5 +1,6 @@
private import cpp as Cpp
private import DataFlowUtil
+private import DataFlowNodes
private import semmle.code.cpp.ir.IR
private import DataFlowDispatch
private import semmle.code.cpp.ir.internal.IRCppLanguage
@@ -16,28 +17,42 @@ private import semmle.code.cpp.dataflow.ExternalFlow as External
cached
private module Cached {
cached
- module Nodes0 {
- cached
- newtype TIRDataFlowNode0 =
- TInstructionNode0(Instruction i) {
- not Ssa::ignoreInstruction(i) and
- not exists(Operand op |
- not Ssa::ignoreOperand(op) and i = Ssa::getIRRepresentationOfOperand(op)
- ) and
- // We exclude `void`-typed instructions because they cannot contain data.
- // However, if the instruction is a glvalue, and their type is `void`, then the result
- // type of the instruction is really `void*`, and thus we still want to have a dataflow
- // node for it.
- (not i.getResultType() instanceof VoidType or i.isGLValue())
- } or
- TMultipleUseOperandNode0(Operand op) {
- not Ssa::ignoreOperand(op) and not exists(Ssa::getIRRepresentationOfOperand(op))
- } or
- TSingleUseOperandNode0(Operand op) {
- not Ssa::ignoreOperand(op) and exists(Ssa::getIRRepresentationOfOperand(op))
- }
+ newtype TIRDataFlowNode0 =
+ TInstructionNode0(Instruction i) {
+ not Ssa::ignoreInstruction(i) and
+ not exists(Operand op |
+ not Ssa::ignoreOperand(op) and i = Ssa::getIRRepresentationOfOperand(op)
+ ) and
+ // We exclude `void`-typed instructions because they cannot contain data.
+ // However, if the instruction is a glvalue, and their type is `void`, then the result
+ // type of the instruction is really `void*`, and thus we still want to have a dataflow
+ // node for it.
+ (not i.getResultType() instanceof VoidType or i.isGLValue())
+ } or
+ TMultipleUseOperandNode0(Operand op) {
+ not Ssa::ignoreOperand(op) and not exists(Ssa::getIRRepresentationOfOperand(op))
+ } or
+ TSingleUseOperandNode0(Operand op) {
+ not Ssa::ignoreOperand(op) and exists(Ssa::getIRRepresentationOfOperand(op))
+ }
+
+ cached
+ string toStringCached(Node n) {
+ result = toExprString(n)
+ or
+ not exists(toExprString(n)) and
+ result = n.toStringImpl()
}
+ cached
+ Location getLocationCached(Node n) { result = n.getLocationImpl() }
+
+ cached
+ newtype TContentApprox =
+ TFieldApproxContent(string s) { fieldHasApproxName(_, s) } or
+ TUnionApproxContent(string s) { unionHasApproxName(_, s) } or
+ TElementApproxContent()
+
/**
* Gets an additional term that is added to the `join` and `branch` computations to reflect
* an additional forward or backwards branching factor that is not taken into account
@@ -59,38 +74,174 @@ private module Cached {
result = countNumberOfBranchesUsingParameter(switch, p)
)
}
-}
-import Cached
-private import Nodes0
+ cached
+ newtype TDataFlowCallable =
+ TSourceCallable(Cpp::Declaration decl) or
+ TSummarizedCallable(FlowSummaryImpl::Public::SummarizedCallable c)
-/**
- * A module for calculating the number of stars (i.e., `*`s) needed for various
- * dataflow node `toString` predicates.
- */
-module NodeStars {
- private int getNumberOfIndirections(Node n) {
- result = n.(RawIndirectOperand).getIndirectionIndex()
+ cached
+ newtype TDataFlowCall =
+ TNormalCall(CallInstruction call) or
+ TSummaryCall(
+ FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
+ ) {
+ FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
+ }
+
+ /**
+ * Holds if data can flow from `node1` to `node2` in a way that loses the
+ * calling context. For example, this would happen with flow through a
+ * global or static variable.
+ */
+ cached
+ predicate jumpStep(Node n1, Node n2) {
+ exists(GlobalLikeVariable v |
+ exists(Ssa::GlobalUse globalUse |
+ v = globalUse.getVariable() and
+ n1.(FinalGlobalValue).getGlobalUse() = globalUse
+ |
+ globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
+ v = n2.asVariable()
+ or
+ v = n2.asIndirectVariable(globalUse.getIndirection())
+ )
+ or
+ exists(Ssa::GlobalDef globalDef |
+ v = globalDef.getVariable() and
+ n2.(InitialGlobalValue).getGlobalDef() = globalDef
+ |
+ globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
+ v = n1.asVariable()
+ or
+ v = n1.asIndirectVariable(globalDef.getIndirection())
+ )
+ )
or
- result = n.(RawIndirectInstruction).getIndirectionIndex()
- or
- result = n.(VariableNode).getIndirectionIndex()
- or
- result = n.(PostUpdateNodeImpl).getIndirectionIndex()
- or
- result = n.(FinalParameterNode).getIndirectionIndex()
- or
- result = n.(BodyLessParameterNodeImpl).getIndirectionIndex()
+ // models-as-data summarized flow
+ FlowSummaryImpl::Private::Steps::summaryJumpStep(n1.(FlowSummaryNode).getSummaryNode(),
+ n2.(FlowSummaryNode).getSummaryNode())
}
/**
- * Gets the number of stars (i.e., `*`s) needed to produce the `toString`
- * output for `n`.
+ * Holds if data can flow from `node1` to `node2` via an assignment to `f`.
+ * Thus, `node2` references an object with a field `f` that contains the
+ * value of `node1`.
+ *
+ * The boolean `certain` is true if the destination address does not involve
+ * any pointer arithmetic, and false otherwise.
*/
- string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
+ cached
+ predicate storeStepImpl(Node node1, Content c, Node node2, boolean certain) {
+ exists(
+ PostFieldUpdateNode postFieldUpdate, int indirectionIndex1, int numberOfLoads,
+ StoreInstruction store, FieldContent fc
+ |
+ postFieldUpdate = node2 and
+ fc = c and
+ nodeHasInstruction(node1, pragma[only_bind_into](store),
+ pragma[only_bind_into](indirectionIndex1)) and
+ postFieldUpdate.getIndirectionIndex() = 1 and
+ numberOfLoadsFromOperand(postFieldUpdate.getFieldAddress(),
+ store.getDestinationAddressOperand(), numberOfLoads, certain) and
+ fc.getAField() = postFieldUpdate.getUpdatedField() and
+ getIndirectionIndexLate(fc) = 1 + indirectionIndex1 + numberOfLoads
+ )
+ or
+ // models-as-data summarized flow
+ FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
+ node2.(FlowSummaryNode).getSummaryNode()) and
+ certain = true
+ }
+
+ /**
+ * Holds if data can flow from `node1` to `node2` via an assignment to `f`.
+ * Thus, `node2` references an object with a field `f` that contains the
+ * value of `node1`.
+ */
+ cached
+ predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepImpl(node1, c, node2, _) }
+
+ /**
+ * Holds if data can flow from `node1` to `node2` via a read of `f`.
+ * Thus, `node1` references an object with a field `f` whose value ends up in
+ * `node2`.
+ */
+ cached
+ predicate readStep(Node node1, ContentSet c, Node node2) {
+ exists(
+ FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2, FieldContent fc
+ |
+ fc = c and
+ nodeHasOperand(node2, operand, indirectionIndex2) and
+ // The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct
+ // in `storeStep`.
+ nodeHasOperand(node1, fa1.getObjectAddressOperand(), 1) and
+ numberOfLoadsFromOperand(fa1, operand, numberOfLoads, _) and
+ fc.getAField() = fa1.getField() and
+ getIndirectionIndexLate(fc) = indirectionIndex2 + numberOfLoads
+ )
+ or
+ // models-as-data summarized flow
+ FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c,
+ node2.(FlowSummaryNode).getSummaryNode())
+ }
+
+ /**
+ * Holds if values stored inside content `c` are cleared at node `n`.
+ */
+ cached
+ predicate clearsContent(Node n, ContentSet c) {
+ n =
+ any(PostUpdateNode pun, Content d |
+ d.impliesClearOf(c) and storeStepImpl(_, d, pun, true)
+ |
+ pun
+ ).getPreUpdateNode() and
+ (
+ not exists(Operand op, Cpp::Operation p |
+ n.(IndirectOperand).hasOperandAndIndirectionIndex(op, _) and
+ (
+ p instanceof Cpp::AssignPointerAddExpr or
+ p instanceof Cpp::AssignPointerSubExpr or
+ p instanceof Cpp::CrementOperation
+ )
+ |
+ p.getAnOperand() = op.getUse().getAst()
+ )
+ or
+ forex(PostUpdateNode pun, Content d |
+ pragma[only_bind_into](d).impliesClearOf(pragma[only_bind_into](c)) and
+ storeStepImpl(_, d, pun, true) and
+ pun.getPreUpdateNode() = n
+ |
+ c.(Content).getIndirectionIndex() = d.getIndirectionIndex()
+ )
+ )
+ }
}
-import NodeStars
+import Cached
+
+private int getNumberOfIndirections(Node n) {
+ result = n.(RawIndirectOperand).getIndirectionIndex()
+ or
+ result = n.(RawIndirectInstruction).getIndirectionIndex()
+ or
+ result = n.(VariableNode).getIndirectionIndex()
+ or
+ result = n.(PostUpdateNodeImpl).getIndirectionIndex()
+ or
+ result = n.(FinalParameterNode).getIndirectionIndex()
+ or
+ result = n.(BodyLessParameterNodeImpl).getIndirectionIndex()
+}
+
+/**
+ * Gets the number of stars (i.e., `*`s) needed to produce the `toString`
+ * output for `n`.
+ */
+string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
/**
* A cut-down `DataFlow::Node` class that does not depend on the output of SSA.
@@ -828,85 +979,10 @@ private int getMinIndirectionForGlobalDef(Ssa::GlobalDef def) {
result = getMinIndirectionsForType(def.getUnspecifiedType())
}
-/**
- * Holds if data can flow from `node1` to `node2` in a way that loses the
- * calling context. For example, this would happen with flow through a
- * global or static variable.
- */
-predicate jumpStep(Node n1, Node n2) {
- exists(GlobalLikeVariable v |
- exists(Ssa::GlobalUse globalUse |
- v = globalUse.getVariable() and
- n1.(FinalGlobalValue).getGlobalUse() = globalUse
- |
- globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
- v = n2.asVariable()
- or
- v = n2.asIndirectVariable(globalUse.getIndirection())
- )
- or
- exists(Ssa::GlobalDef globalDef |
- v = globalDef.getVariable() and
- n2.(InitialGlobalValue).getGlobalDef() = globalDef
- |
- globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
- v = n1.asVariable()
- or
- v = n1.asIndirectVariable(globalDef.getIndirection())
- )
- )
- or
- // models-as-data summarized flow
- FlowSummaryImpl::Private::Steps::summaryJumpStep(n1.(FlowSummaryNode).getSummaryNode(),
- n2.(FlowSummaryNode).getSummaryNode())
-}
-
bindingset[c]
pragma[inline_late]
private int getIndirectionIndexLate(Content c) { result = c.getIndirectionIndex() }
-/**
- * Holds if data can flow from `node1` to `node2` via an assignment to `f`.
- * Thus, `node2` references an object with a field `f` that contains the
- * value of `node1`.
- *
- * The boolean `certain` is true if the destination address does not involve
- * any pointer arithmetic, and false otherwise. This has to do with whether a
- * store step can be used to clear a field (see `clearsContent`).
- */
-predicate storeStepImpl(Node node1, Content c, Node node2, boolean certain) {
- exists(
- PostFieldUpdateNode postFieldUpdate, int indirectionIndex1, int numberOfLoads,
- StoreInstruction store, FieldContent fc
- |
- postFieldUpdate = node2 and
- fc = c and
- nodeHasInstruction(node1, pragma[only_bind_into](store),
- pragma[only_bind_into](indirectionIndex1)) and
- postFieldUpdate.getIndirectionIndex() = 1 and
- numberOfLoadsFromOperand(postFieldUpdate.getFieldAddress(),
- store.getDestinationAddressOperand(), numberOfLoads, certain) and
- fc.getAField() = postFieldUpdate.getUpdatedField() and
- getIndirectionIndexLate(fc) = 1 + indirectionIndex1 + numberOfLoads
- )
- or
- // models-as-data summarized flow
- FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
- node2.(FlowSummaryNode).getSummaryNode()) and
- certain = true
-}
-
-/**
- * Holds if data can flow from `node1` to `node2` via an assignment to `f`.
- * Thus, `node2` references an object with a field `f` that contains the
- * value of `node1`.
- */
-predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepImpl(node1, c, node2, _) }
-
-/**
- * Holds if `operandFrom` flows to `operandTo` using a sequence of conversion-like
- * operations and exactly `n` `LoadInstruction` operations.
- */
private predicate numberOfLoadsFromOperandRec(
Operand operandFrom, Operand operandTo, int ind, boolean certain
) {
@@ -957,63 +1033,6 @@ predicate nodeHasInstruction(Node node, Instruction instr, int indirectionIndex)
hasInstructionAndIndex(node, instr, indirectionIndex)
}
-/**
- * Holds if data can flow from `node1` to `node2` via a read of `f`.
- * Thus, `node1` references an object with a field `f` whose value ends up in
- * `node2`.
- */
-predicate readStep(Node node1, ContentSet c, Node node2) {
- exists(
- FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2, FieldContent fc
- |
- fc = c and
- nodeHasOperand(node2, operand, indirectionIndex2) and
- // The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct
- // in `storeStep`.
- nodeHasOperand(node1, fa1.getObjectAddressOperand(), 1) and
- numberOfLoadsFromOperand(fa1, operand, numberOfLoads, _) and
- fc.getAField() = fa1.getField() and
- getIndirectionIndexLate(fc) = indirectionIndex2 + numberOfLoads
- )
- or
- // models-as-data summarized flow
- FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c,
- node2.(FlowSummaryNode).getSummaryNode())
-}
-
-/**
- * Holds if values stored inside content `c` are cleared at node `n`.
- */
-predicate clearsContent(Node n, ContentSet c) {
- n =
- any(PostUpdateNode pun, Content d | d.impliesClearOf(c) and storeStepImpl(_, d, pun, true) | pun)
- .getPreUpdateNode() and
- (
- // The crement operations and pointer addition and subtraction self-assign. We do not
- // want to clear the contents if it is indirectly pointed at by any of these operations,
- // as part of the contents might still be accessible afterwards. If there is no such
- // indirection clearing the contents is safe.
- not exists(Operand op, Cpp::Operation p |
- n.(IndirectOperand).hasOperandAndIndirectionIndex(op, _) and
- (
- p instanceof Cpp::AssignPointerAddExpr or
- p instanceof Cpp::AssignPointerSubExpr or
- p instanceof Cpp::CrementOperation
- )
- |
- p.getAnOperand() = op.getUse().getAst()
- )
- or
- forex(PostUpdateNode pun, Content d |
- pragma[only_bind_into](d).impliesClearOf(pragma[only_bind_into](c)) and
- storeStepImpl(_, d, pun, true) and
- pun.getPreUpdateNode() = n
- |
- c.(Content).getIndirectionIndex() = d.getIndirectionIndex()
- )
- )
-}
-
/**
* Holds if the value that is being tracked is expected to be stored inside content `c`
* at node `n`.
@@ -1046,11 +1065,6 @@ class CastNode extends Node {
CastNode() { none() } // stub implementation
}
-cached
-private newtype TDataFlowCallable =
- TSourceCallable(Cpp::Declaration decl) or
- TSummarizedCallable(FlowSummaryImpl::Public::SummarizedCallable c)
-
/**
* A callable, which may be:
* - a function (that may contain code)
@@ -1134,15 +1148,6 @@ class DataFlowType extends TypeFinal {
string toString() { result = "" }
}
-cached
-private newtype TDataFlowCall =
- TNormalCall(CallInstruction call) or
- TSummaryCall(
- FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
- ) {
- FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
- }
-
private predicate summarizedCallableIsManual(SummarizedCallable sc) {
sc.asSummarizedCallable().hasManualModel()
}
@@ -1165,7 +1170,7 @@ class DataFlowCall extends TDataFlowCall {
/**
* Gets the `Function` that the call targets, if this is statically known.
*/
- Function getStaticCallSourceTarget() { none() }
+ Declaration getStaticCallSourceTarget() { none() }
/**
* Gets the target of this call. We use the following strategy for deciding
@@ -1177,7 +1182,7 @@ class DataFlowCall extends TDataFlowCall {
* whether is it manual or generated.
*/
final DataFlowCallable getStaticCallTarget() {
- exists(Function target | target = this.getStaticCallSourceTarget() |
+ exists(Declaration target | target = this.getStaticCallSourceTarget() |
// Don't use the source callable if there is a manual model for the
// target
not exists(SummarizedCallable sc |
@@ -1237,7 +1242,7 @@ private class NormalCall extends DataFlowCall, TNormalCall {
override CallTargetOperand getCallTargetOperand() { result = call.getCallTargetOperand() }
- override Function getStaticCallSourceTarget() { result = call.getStaticCallTarget() }
+ override Declaration getStaticCallSourceTarget() { result = call.getStaticCallTarget() }
override ArgumentOperand getArgumentOperand(int index) { result = call.getArgumentOperand(index) }
@@ -1523,12 +1528,6 @@ private predicate fieldHasApproxName(Field f, string s) {
private predicate unionHasApproxName(Cpp::Union u, string s) { s = u.getName().charAt(0) }
-cached
-private newtype TContentApprox =
- TFieldApproxContent(string s) { fieldHasApproxName(_, s) } or
- TUnionApproxContent(string s) { unionHasApproxName(_, s) } or
- TElementApproxContent()
-
/** An approximated `Content`. */
class ContentApprox extends TContentApprox {
string toString() { none() } // overridden in subclasses
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index 9bc3a80e3e0..d42d959f56e 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -3,14 +3,12 @@
*/
private import cpp
-// The `ValueNumbering` library has to be imported right after `cpp` to ensure
-// that the cached IR gets the same checksum here as it does in queries that use
-// `ValueNumbering` without `DataFlow`.
private import semmle.code.cpp.ir.ValueNumbering
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.controlflow.IRGuards
private import semmle.code.cpp.models.interfaces.DataFlow
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
+private import TaintTrackingUtil as TaintTrackingUtil
private import DataFlowPrivate
private import ModelUtil
private import SsaImpl as SsaImpl
@@ -18,1702 +16,8 @@ private import DataFlowImplCommon as DataFlowImplCommon
private import codeql.util.Unit
private import Node0ToString
private import DataFlowDispatch as DataFlowDispatch
-import ExprNodes
-
-/**
- * The IR dataflow graph consists of the following nodes:
- * - `Node0`, which injects most instructions and operands directly into the
- * dataflow graph.
- * - `VariableNode`, which is used to model flow through global variables.
- * - `PostUpdateNodeImpl`, which is used to model the state of an object after
- * an update after a number of loads.
- * - `SsaSynthNode`, which represents synthesized nodes as computed by the shared SSA
- * library.
- * - `RawIndirectOperand`, which represents the value of `operand` after
- * loading the address a number of times.
- * - `RawIndirectInstruction`, which represents the value of `instr` after
- * loading the address a number of times.
- */
-cached
-private newtype TIRDataFlowNode =
- TNode0(Node0Impl node) { DataFlowImplCommon::forceCachingInSameStage() } or
- TGlobalLikeVariableNode(GlobalLikeVariable var, int indirectionIndex) {
- indirectionIndex =
- [getMinIndirectionsForType(var.getUnspecifiedType()) .. SsaImpl::getMaxIndirectionsForType(var.getUnspecifiedType())]
- } or
- TPostUpdateNodeImpl(Operand operand, int indirectionIndex) {
- isPostUpdateNodeImpl(operand, indirectionIndex)
- } or
- TSsaSynthNode(SsaImpl::SynthNode n) or
- TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
- TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
- SsaImpl::hasRawIndirectOperand(node.asOperand(), indirectionIndex)
- } or
- TRawIndirectInstruction0(Node0Impl node, int indirectionIndex) {
- not exists(node.asOperand()) and
- SsaImpl::hasRawIndirectInstruction(node.asInstruction(), indirectionIndex)
- } or
- TFinalParameterNode(Parameter p, int indirectionIndex) {
- exists(SsaImpl::FinalParameterUse use |
- use.getParameter() = p and
- use.getIndirectionIndex() = indirectionIndex
- )
- } or
- TFinalGlobalValue(SsaImpl::GlobalUse globalUse) or
- TInitialGlobalValue(SsaImpl::GlobalDef globalUse) or
- TBodyLessParameterNodeImpl(Parameter p, int indirectionIndex) {
- // Rule out parameters of catch blocks.
- not exists(p.getCatchBlock()) and
- // We subtract one because `getMaxIndirectionsForType` returns the maximum
- // indirection for a glvalue of a given type, and this doesn't apply to
- // parameters.
- indirectionIndex = [0 .. SsaImpl::getMaxIndirectionsForType(p.getUnspecifiedType()) - 1] and
- not any(InitializeParameterInstruction init).getParameter() = p
- } or
- TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn)
-
-/**
- * An operand that is defined by a `FieldAddressInstruction`.
- */
-class FieldAddress extends Operand {
- FieldAddressInstruction fai;
-
- FieldAddress() { fai = this.getDef() and not SsaImpl::ignoreOperand(this) }
-
- /** Gets the field associated with this instruction. */
- Field getField() { result = fai.getField() }
-
- /** Gets the instruction whose result provides the address of the object containing the field. */
- Instruction getObjectAddress() { result = fai.getObjectAddress() }
-
- /** Gets the operand that provides the address of the object containing the field. */
- Operand getObjectAddressOperand() { result = fai.getObjectAddressOperand() }
-}
-
-/**
- * Holds if `opFrom` is an operand whose value flows to the result of `instrTo`.
- *
- * `isPointerArith` is `true` if `instrTo` is a `PointerArithmeticInstruction` and `opFrom`
- * is the left operand.
- *
- * `additional` is `true` if the conversion is supplied by an implementation of the
- * `Indirection` class. It is sometimes useful to exclude such conversions.
- */
-predicate conversionFlow(
- Operand opFrom, Instruction instrTo, boolean isPointerArith, boolean additional
-) {
- isPointerArith = false and
- (
- additional = false and
- (
- instrTo.(CopyValueInstruction).getSourceValueOperand() = opFrom
- or
- instrTo.(ConvertInstruction).getUnaryOperand() = opFrom
- or
- instrTo.(CheckedConvertOrNullInstruction).getUnaryOperand() = opFrom
- or
- instrTo.(InheritanceConversionInstruction).getUnaryOperand() = opFrom
- or
- exists(BuiltInInstruction builtIn |
- builtIn = instrTo and
- // __builtin_bit_cast
- builtIn.getBuiltInOperation() instanceof BuiltInBitCast and
- opFrom = builtIn.getAnOperand()
- )
- )
- or
- additional = true and
- SsaImpl::isAdditionalConversionFlow(opFrom, instrTo)
- )
- or
- isPointerArith = true and
- additional = false and
- instrTo.(PointerArithmeticInstruction).getLeftOperand() = opFrom
-}
-
-/**
- * A node in a data flow graph.
- *
- * A node can be either an expression, a parameter, or an uninitialized local
- * variable. Such nodes are created with `DataFlow::exprNode`,
- * `DataFlow::parameterNode`, and `DataFlow::uninitializedNode` respectively.
- */
-class Node extends TIRDataFlowNode {
- /**
- * INTERNAL: Do not use.
- */
- DataFlowCallable getEnclosingCallable() { none() } // overridden in subclasses
-
- /** Gets the function to which this node belongs, if any. */
- Declaration getFunction() { none() } // overridden in subclasses
-
- /** Holds if this node represents a glvalue. */
- predicate isGLValue() { none() }
-
- /**
- * Gets the type of this node.
- *
- * If `isGLValue()` holds, then the type of this node
- * should be thought of as "pointer to `getType()`".
- */
- Type getType() { none() } // overridden in subclasses
-
- /** Gets the instruction corresponding to this node, if any. */
- Instruction asInstruction() { result = this.(InstructionNode).getInstruction() }
-
- /** Gets the operands corresponding to this node, if any. */
- 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`.
- *
- * Note: Phi nodes are considered to be at index `-1`.
- */
- final predicate hasIndexInBlock(IRBlock block, int i) {
- this.asInstruction() = block.getInstruction(i)
- or
- this.asOperand().getUse() = block.getInstruction(i)
- or
- exists(SsaImpl::SynthNode ssaNode |
- this.(SsaSynthNode).getSynthNode() = ssaNode and
- ssaNode.getBasicBlock() = block and
- ssaNode.getIndex() = i
- )
- or
- this.(RawIndirectOperand).getOperand().getUse() = block.getInstruction(i)
- or
- this.(RawIndirectInstruction).getInstruction() = block.getInstruction(i)
- or
- this.(PostUpdateNode).getPreUpdateNode().hasIndexInBlock(block, i)
- }
-
- /** Gets the basic block of this node, if any. */
- final IRBlock getBasicBlock() { this.hasIndexInBlock(result, _) }
-
- /**
- * Gets the non-conversion expression corresponding to this node, if any.
- * This predicate only has a result on nodes that represent the value of
- * evaluating the expression. For data flowing _out of_ an expression, like
- * when an argument is passed by reference, use `asDefiningArgument` instead
- * of `asExpr`.
- *
- * If this node strictly (in the sense of `asConvertedExpr`) corresponds to
- * a `Conversion`, then the result is the underlying non-`Conversion` base
- * expression.
- */
- Expr asExpr() { result = this.asExpr(_) }
-
- /**
- * INTERNAL: Do not use.
- */
- Expr asExpr(int n) { result = this.(ExprNode).getExpr(n) }
-
- /**
- * INTERNAL: Do not use.
- */
- Expr asIndirectExpr(int n, int index) { result = this.(IndirectExprNode).getExpr(n, index) }
-
- /**
- * Gets the non-conversion expression that's indirectly tracked by this node
- * under `index` number of indirections.
- */
- Expr asIndirectExpr(int index) { result = this.asIndirectExpr(_, index) }
-
- /**
- * Gets the non-conversion expression that's indirectly tracked by this node
- * behind a number of indirections.
- */
- Expr asIndirectExpr() { result = this.asIndirectExpr(_) }
-
- /**
- * Gets the expression corresponding to this node, if any. The returned
- * expression may be a `Conversion`.
- */
- Expr asConvertedExpr() { result = this.asConvertedExpr(_) }
-
- /**
- * Gets the expression corresponding to this node, if any. The returned
- * expression may be a `Conversion`.
- */
- Expr asConvertedExpr(int n) { result = this.(ExprNode).getConvertedExpr(n) }
-
- /**
- * INTERNAL: Do not use.
- */
- Expr asIndirectConvertedExpr(int n, int index) {
- result = this.(IndirectExprNode).getConvertedExpr(n, index)
- }
-
- /**
- * Gets the expression that's indirectly tracked by this node
- * behind `index` number of indirections.
- */
- Expr asIndirectConvertedExpr(int index) { result = this.asIndirectConvertedExpr(_, index) }
-
- /**
- * Gets the expression that's indirectly tracked by this node behind a
- * number of indirections.
- */
- Expr asIndirectConvertedExpr() { result = this.asIndirectConvertedExpr(_) }
-
- /**
- * Gets the argument that defines this `DefinitionByReferenceNode`, if any.
- * This predicate should be used instead of `asExpr` when referring to the
- * value of a reference argument _after_ the call has returned. For example,
- * in `f(&x)`, this predicate will have `&x` as its result for the `Node`
- * that represents the new value of `x`.
- */
- Expr asDefiningArgument() { result = this.asDefiningArgument(_) }
-
- /**
- * Gets the definition associated with this node, if any.
- *
- * 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 definition generated by `x += 2` the result is `x += 2`
- * - For the definition generated by `int y = ...` the result is
- * also `x += 2`.
- *
- * For assignments, `node.asDefinition()` and `node.asExpr()` will both exist
- * for the same dataflow node. However, for expression such as `x++` that
- * both write to `x` and read the current value of `x`, `node.asDefinition()`
- * will give the node corresponding to the value after the increment, and
- * `node.asExpr()` will give the node corresponding to the value before the
- * increment. For an example of this, consider the following:
- *
- * ```cpp
- * sink(x++);
- * ```
- * in the above program, there will not be flow from a node `n` such that
- * `n.asDefinition() instanceof IncrementOperation` to the argument of `sink`
- * since the value passed to `sink` is the value before to the increment.
- * However, there will be dataflow from a node `n` such that
- * `n.asExpr() instanceof IncrementOperation` since the result of evaluating
- * the expression `x++` is passed to `sink`.
- */
- Expr asDefinition() { result = this.asDefinition(_) }
-
- private predicate isCertainStore() {
- exists(SsaImpl::Definition def |
- SsaImpl::defToNode(this, def, _) and
- def.isCertain()
- )
- }
-
- /**
- * Gets the definition associated with this node, if any.
- *
- * 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 definition generated by `x += 2` the result is `x += 2`
- * - For the definition generated by `int y = ...` the result is
- * also `x += 2`.
- *
- * For assignments, `node.asDefinition(_)` and `node.asExpr()` will both exist
- * for the same dataflow node. However, for expression such as `x++` that
- * both write to `x` and read the current value of `x`, `node.asDefinition(_)`
- * will give the node corresponding to the value after the increment, and
- * `node.asExpr()` will give the node corresponding to the value before the
- * increment. For an example of this, consider the following:
- *
- * ```cpp
- * sink(x++);
- * ```
- * in the above program, there will not be flow from a node `n` such that
- * `n.asDefinition(_) instanceof IncrementOperation` to the argument of `sink`
- * since the value passed to `sink` is the value before to the increment.
- * However, there will be dataflow from a node `n` such that
- * `n.asExpr() instanceof IncrementOperation` since the result of evaluating
- * the expression `x++` is passed to `sink`.
- *
- * If `uncertain = false` then the definition is guaranteed to overwrite
- * the entire buffer pointed to by the destination address of the definition.
- * Otherwise, `uncertain = true`.
- *
- * For example, the write `int x; x = 42;` is guaranteed to overwrite all the
- * bytes allocated to `x`, while the assignment `int p[10]; p[3] = 42;` has
- * `uncertain = true` since the write will not overwrite the entire buffer
- * pointed to by `p`.
- */
- Expr asDefinition(boolean uncertain) {
- exists(StoreInstruction store |
- store = this.asInstruction() and
- result = asDefinitionImpl(store) and
- if this.isCertainStore() then uncertain = false else uncertain = true
- )
- }
-
- /**
- * Gets the definition associated with this node, if this node is a certain definition.
- *
- * See `Node.asDefinition/1` for a description of certain and uncertain definitions.
- */
- Expr asCertainDefinition() { result = this.asDefinition(false) }
-
- /**
- * Gets the definition associated with this node, if this node is an uncertain definition.
- *
- * See `Node.asDefinition/1` for a description of certain and uncertain definitions.
- */
- Expr asUncertainDefinition() { result = this.asDefinition(true) }
-
- /**
- * Gets the indirect definition at a given indirection corresponding to this
- * node, if any.
- *
- * See the comments on `Node.asDefinition` for examples.
- */
- Expr asIndirectDefinition(int indirectionIndex) {
- exists(StoreInstruction store |
- this.(IndirectInstruction).hasInstructionAndIndirectionIndex(store, indirectionIndex) and
- result = asDefinitionImpl(store)
- )
- }
-
- /**
- * Gets the indirect definition at some indirection corresponding to this
- * node, if any.
- */
- Expr asIndirectDefinition() { result = this.asIndirectDefinition(_) }
-
- /**
- * Gets the argument that defines this `DefinitionByReferenceNode`, if any.
- *
- * Unlike `Node::asDefiningArgument/0`, this predicate gets the node representing
- * the value of the `index`'th indirection after leaving a function. For example,
- * in:
- * ```cpp
- * void f(int**);
- * ...
- * int** x = ...;
- * f(x);
- * ```
- * The node `n` such that `n.asDefiningArgument(1)` is the argument `x` will
- * contain the value of `*x` after `f` has returned, and the node `n` such that
- * `n.asDefiningArgument(2)` is the argument `x` will contain the value of `**x`
- * after the `f` has returned.
- */
- Expr asDefiningArgument(int index) {
- this.(DefinitionByReferenceNode).getIndirectionIndex() = index and
- result = this.(DefinitionByReferenceNode).getArgument()
- }
-
- /**
- * Gets the the argument going into a function for a node that represents
- * the indirect value of the argument after `index` loads. For example, in:
- * ```cpp
- * void f(int**);
- * ...
- * int** x = ...;
- * f(x);
- * ```
- * The node `n` such that `n.asIndirectArgument(1)` represents the value of
- * `*x` going into `f`, and the node `n` such that `n.asIndirectArgument(2)`
- * represents the value of `**x` going into `f`.
- */
- Expr asIndirectArgument(int index) {
- this.(SideEffectOperandNode).hasAddressOperandAndIndirectionIndex(_, index) and
- result = this.(SideEffectOperandNode).getArgument()
- }
-
- /**
- * Gets the the argument going into a function for a node that represents
- * the indirect value of the argument after any non-zero number of loads.
- */
- Expr asIndirectArgument() { result = this.asIndirectArgument(_) }
-
- /** Gets the positional parameter corresponding to this node, if any. */
- Parameter asParameter() {
- exists(int indirectionIndex | result = this.asParameter(indirectionIndex) |
- if result.getUnspecifiedType() instanceof ReferenceType
- then indirectionIndex = 1
- else indirectionIndex = 0
- )
- }
-
- /**
- * Gets the uninitialized local variable corresponding to this node, if
- * any.
- */
- LocalVariable asUninitialized() { result = this.(UninitializedNode).getLocalVariable() }
-
- /**
- * Gets the positional parameter corresponding to the node that represents
- * the value of the parameter after `index` number of loads, if any. For
- * example, in:
- * ```cpp
- * void f(int** x) { ... }
- * ```
- * - The node `n` such that `n.asParameter(0)` is the parameter `x` represents
- * the value of `x`.
- * - The node `n` such that `n.asParameter(1)` is the parameter `x` represents
- * the value of `*x`.
- * - The node `n` such that `n.asParameter(2)` is the parameter `x` represents
- * the value of `**x`.
- */
- Parameter asParameter(int index) {
- index = 0 and
- result = this.(ExplicitParameterNode).getParameter()
- or
- this.(IndirectParameterNode).getIndirectionIndex() = index and
- result = this.(IndirectParameterNode).getParameter()
- }
-
- /**
- * Holds if this node represents the `indirectionIndex`'th indirection of
- * the value of an output parameter `p` just before reaching the end of a function.
- */
- predicate isFinalValueOfParameter(Parameter p, int indirectionIndex) {
- exists(FinalParameterNode n | n = this |
- p = n.getParameter() and
- indirectionIndex = n.getIndirectionIndex()
- )
- }
-
- /**
- * Holds if this node represents the value of an output parameter `p`
- * just before reaching the end of a function.
- */
- predicate isFinalValueOfParameter(Parameter p) { this.isFinalValueOfParameter(p, _) }
-
- /**
- * Gets the variable corresponding to this node, if any. This can be used for
- * modeling flow in and out of global variables.
- */
- Variable asVariable() {
- this = TGlobalLikeVariableNode(result, getMinIndirectionsForType(result.getUnspecifiedType()))
- }
-
- /**
- * Gets the `indirectionIndex`'th indirection of this node's underlying variable, if any.
- *
- * This can be used for modeling flow in and out of global variables.
- */
- Variable asIndirectVariable(int indirectionIndex) {
- indirectionIndex > getMinIndirectionsForType(result.getUnspecifiedType()) and
- this = TGlobalLikeVariableNode(result, indirectionIndex)
- }
-
- /** Gets an indirection of this node's underlying variable, if any. */
- Variable asIndirectVariable() { result = this.asIndirectVariable(_) }
-
- /**
- * Gets the expression that is partially defined by this node, if any.
- *
- * Partial definitions are created for field stores (`x.y = taint();` is a partial
- * definition of `x`), and for calls that may change the value of an object (so
- * `x.set(taint())` is a partial definition of `x`, and `transfer(&x, taint())` is
- * a partial definition of `&x`).
- */
- Expr asPartialDefinition() {
- exists(PartialDefinitionNode pdn | this = pdn |
- pdn.getIndirectionIndex() > 0 and
- result = pdn.getDefinedExpr()
- )
- }
-
- /**
- * Gets an upper bound on the type of this node.
- */
- Type getTypeBound() { result = this.getType() }
-
- /** Gets the location of this element. */
- cached
- final Location getLocation() { result = this.getLocationImpl() }
-
- /** INTERNAL: Do not use. */
- Location getLocationImpl() {
- none() // overridden by subclasses
- }
-
- /** Gets a textual representation of this element. */
- cached
- final string toString() {
- result = toExprString(this)
- or
- not exists(toExprString(this)) and
- result = this.toStringImpl()
- }
-
- /** INTERNAL: Do not use. */
- string toStringImpl() {
- none() // overridden by subclasses
- }
-}
-
-/**
- * A class that lifts pre-SSA dataflow nodes to regular dataflow nodes.
- */
-private class Node0 extends Node, TNode0 {
- Node0Impl node;
-
- Node0() { this = TNode0(node) }
-
- override DataFlowCallable getEnclosingCallable() {
- result.asSourceCallable() = node.getEnclosingCallable()
- }
-
- override Declaration getFunction() { result = node.getFunction() }
-
- override Location getLocationImpl() { result = node.getLocation() }
-
- override string toStringImpl() { result = node.toString() }
-
- override Type getType() { result = node.getType() }
-
- override predicate isGLValue() { node.isGLValue() }
-}
-
-/**
- * An instruction, viewed as a node in a data flow graph.
- */
-class InstructionNode extends Node0 {
- override InstructionNode0 node;
- Instruction instr;
-
- InstructionNode() { instr = node.getInstruction() }
-
- /** Gets the instruction corresponding to this node. */
- Instruction getInstruction() { result = instr }
-}
-
-/**
- * An operand, viewed as a node in a data flow graph.
- */
-class OperandNode extends Node, Node0 {
- override OperandNode0 node;
- Operand op;
-
- OperandNode() { op = node.getOperand() }
-
- /** Gets the operand corresponding to this node. */
- Operand getOperand() { result = op }
-}
-
-/**
- * INTERNAL: Do not use.
- *
- * Returns `t`, but stripped of the outermost pointer, reference, etc.
- *
- * For example, `stripPointers(int*&)` is `int*` and `stripPointers(int*)` is `int`.
- */
-Type stripPointer(Type t) {
- result = any(SsaImpl::Indirection ind | ind.getType() = t).getBaseType()
- or
- result = t.(PointerToMemberType).getBaseType()
- or
- result = t.(FunctionPointerIshType).getBaseType()
-}
-
-/**
- * INTERNAL: Do not use.
- */
-class PostUpdateNodeImpl extends PartialDefinitionNode, TPostUpdateNodeImpl {
- int indirectionIndex;
- Operand operand;
-
- PostUpdateNodeImpl() { this = TPostUpdateNodeImpl(operand, indirectionIndex) }
-
- override Declaration getFunction() { result = operand.getUse().getEnclosingFunction() }
-
- override DataFlowCallable getEnclosingCallable() {
- result = this.getPreUpdateNode().getEnclosingCallable()
- }
-
- /** Gets the operand associated with this node. */
- Operand getOperand() { result = operand }
-
- /** Gets the indirection index associated with this node. */
- override int getIndirectionIndex() { result = indirectionIndex }
-
- override Location getLocationImpl() { result = operand.getLocation() }
-
- final override Node getPreUpdateNode() {
- indirectionIndex > 0 and
- hasOperandAndIndex(result, operand, indirectionIndex)
- or
- indirectionIndex = 0 and
- result.asOperand() = operand
- }
-
- final override Expr getDefinedExpr() {
- result = operand.getDef().getUnconvertedResultExpression()
- }
-}
-
-/**
- * INTERNAL: do not use.
- *
- * The node representing the value of a field after it has been updated.
- */
-class PostFieldUpdateNode extends PostUpdateNodeImpl {
- FieldAddress fieldAddress;
-
- PostFieldUpdateNode() { operand = fieldAddress.getObjectAddressOperand() }
-
- FieldAddress getFieldAddress() { result = fieldAddress }
-
- Field getUpdatedField() { result = this.getFieldAddress().getField() }
-
- override string toStringImpl() { result = this.getPreUpdateNode() + " [post update]" }
-}
-
-/**
- * INTERNAL: do not use.
- *
- * A synthesized SSA node produced by the shared SSA library, viewed as a node
- * in a data flow graph.
- */
-class SsaSynthNode extends Node, TSsaSynthNode {
- SsaImpl::SynthNode node;
-
- SsaSynthNode() { this = TSsaSynthNode(node) }
-
- /** Gets the synthesized SSA node associated with this node. */
- SsaImpl::SynthNode getSynthNode() { result = node }
-
- override DataFlowCallable getEnclosingCallable() {
- result.asSourceCallable() = this.getFunction()
- }
-
- override Declaration getFunction() { result = node.getBasicBlock().getEnclosingFunction() }
-
- override Type getType() { result = node.getSourceVariable().getType() }
-
- override predicate isGLValue() { node.getSourceVariable().isGLValue() }
-
- final override Location getLocationImpl() { result = node.getLocation() }
-
- override string toStringImpl() { result = node.toString() }
-}
-
-/**
- * INTERNAL: do not use.
- *
- * Dataflow nodes necessary for iterator flow
- */
-class SsaIteratorNode extends Node, TSsaIteratorNode {
- IteratorFlow::IteratorFlowNode node;
-
- SsaIteratorNode() { this = TSsaIteratorNode(node) }
-
- /** Gets the phi node associated with this node. */
- IteratorFlow::IteratorFlowNode getIteratorFlowNode() { result = node }
-
- override DataFlowCallable getEnclosingCallable() {
- result.asSourceCallable() = this.getFunction()
- }
-
- override Declaration getFunction() { result = node.getFunction() }
-
- override Type getType() { result = node.getType() }
-
- final override Location getLocationImpl() { result = node.getLocation() }
-
- override string toStringImpl() { result = node.toString() }
-}
-
-/**
- * INTERNAL: do not use.
- *
- * A node representing a value after leaving a function.
- */
-class SideEffectOperandNode extends Node instanceof IndirectOperand {
- CallInstruction call;
- int argumentIndex;
- ArgumentOperand arg;
-
- SideEffectOperandNode() {
- arg = call.getArgumentOperand(argumentIndex) and
- IndirectOperand.super.hasOperandAndIndirectionIndex(arg, _)
- }
-
- CallInstruction getCallInstruction() { result = call }
-
- /** Gets the underlying operand and the underlying indirection index. */
- predicate hasAddressOperandAndIndirectionIndex(Operand operand, int indirectionIndex) {
- IndirectOperand.super.hasOperandAndIndirectionIndex(operand, indirectionIndex)
- }
-
- int getArgumentIndex() { result = argumentIndex }
-
- override DataFlowCallable getEnclosingCallable() {
- result.asSourceCallable() = this.getFunction()
- }
-
- override Declaration getFunction() { result = call.getEnclosingFunction() }
-
- Expr getArgument() { result = call.getArgument(argumentIndex).getUnconvertedResultExpression() }
-}
-
-/**
- * INTERNAL: do not use.
- *
- * A node representing the value of a global variable just before returning
- * from a function body.
- */
-class FinalGlobalValue extends Node, TFinalGlobalValue {
- SsaImpl::GlobalUse globalUse;
-
- FinalGlobalValue() { this = TFinalGlobalValue(globalUse) }
-
- /** Gets the underlying SSA use. */
- SsaImpl::GlobalUse getGlobalUse() { result = globalUse }
-
- override DataFlowCallable getEnclosingCallable() {
- result.asSourceCallable() = this.getFunction()
- }
-
- override Declaration getFunction() { result = globalUse.getIRFunction().getFunction() }
-
- override Type getType() {
- exists(int indirectionIndex |
- indirectionIndex = globalUse.getIndirectionIndex() and
- result = getTypeImpl(globalUse.getUnderlyingType(), indirectionIndex)
- )
- }
-
- final override Location getLocationImpl() { result = globalUse.getLocation() }
-
- override string toStringImpl() { result = globalUse.toString() }
-}
-
-/**
- * INTERNAL: do not use.
- *
- * A node representing the value of a global variable just after entering
- * a function body.
- */
-class InitialGlobalValue extends Node, TInitialGlobalValue {
- SsaImpl::GlobalDef globalDef;
-
- InitialGlobalValue() { this = TInitialGlobalValue(globalDef) }
-
- /** Gets the underlying SSA definition. */
- SsaImpl::GlobalDef getGlobalDef() { result = globalDef }
-
- override DataFlowCallable getEnclosingCallable() {
- result.asSourceCallable() = this.getFunction()
- }
-
- override Declaration getFunction() { result = globalDef.getFunction() }
-
- final override predicate isGLValue() { globalDef.getIndirectionIndex() = 0 }
-
- override Type getType() { result = globalDef.getUnderlyingType() }
-
- final override Location getLocationImpl() { result = globalDef.getLocation() }
-
- override string toStringImpl() { result = globalDef.toString() }
-}
-
-/**
- * INTERNAL: do not use.
- *
- * A node representing a parameter for a function with no body.
- */
-class BodyLessParameterNodeImpl extends Node, TBodyLessParameterNodeImpl {
- Parameter p;
- int indirectionIndex;
-
- BodyLessParameterNodeImpl() { this = TBodyLessParameterNodeImpl(p, indirectionIndex) }
-
- override DataFlowCallable getEnclosingCallable() {
- result.asSourceCallable() = this.getFunction()
- }
-
- override Declaration getFunction() { result = p.getFunction() }
-
- /** Gets the indirection index of this node. */
- int getIndirectionIndex() { result = indirectionIndex }
-
- override Type getType() {
- result = getTypeImpl(p.getUnderlyingType(), this.getIndirectionIndex())
- }
-
- final override Location getLocationImpl() {
- result = unique( | | p.getLocation())
- or
- count(p.getLocation()) != 1 and
- result instanceof UnknownLocation
- }
-
- final override string toStringImpl() {
- exists(string prefix | prefix = stars(this) | result = prefix + p.toString())
- }
-}
-
-/**
- * A data-flow node used to model flow summaries. That is, a dataflow node
- * that is synthesized to represent a parameter, return value, or other part
- * of a models-as-data modeled function.
- */
-class FlowSummaryNode extends Node, TFlowSummaryNode {
- /**
- * Gets the models-as-data `SummaryNode` associated with this dataflow
- * `FlowSummaryNode`.
- */
- FlowSummaryImpl::Private::SummaryNode getSummaryNode() { this = TFlowSummaryNode(result) }
-
- /**
- * Gets the summarized callable that this node belongs to.
- */
- FlowSummaryImpl::Public::SummarizedCallable getSummarizedCallable() {
- result = this.getSummaryNode().getSummarizedCallable()
- }
-
- /**
- * Gets the enclosing callable. For a `FlowSummaryNode` this is always the
- * summarized function this node is part of.
- */
- override DataFlowCallable getEnclosingCallable() {
- result.asSummarizedCallable() = this.getSummarizedCallable()
- }
-
- override Location getLocationImpl() { result = this.getSummarizedCallable().getLocation() }
-
- override string toStringImpl() { result = this.getSummaryNode().toString() }
-}
-
-/**
- * INTERNAL: do not use.
- *
- * A node representing the indirection of a value that is
- * about to be returned from a function.
- */
-class IndirectReturnNode extends Node {
- IndirectReturnNode() {
- this instanceof FinalParameterNode
- or
- this.(IndirectOperand)
- .hasOperandAndIndirectionIndex(any(ReturnValueInstruction ret).getReturnAddressOperand(), _)
- }
-
- override SourceCallable getEnclosingCallable() { result.asSourceCallable() = this.getFunction() }
-
- /**
- * Holds if this node represents the value that is returned to the caller
- * through a `return` statement.
- */
- predicate isNormalReturn() { this instanceof IndirectOperand }
-
- /**
- * Holds if this node represents the value that is returned to the caller
- * by writing to the `argumentIndex`'th argument of the call.
- */
- predicate isParameterReturn(int argumentIndex) {
- this.(FinalParameterNode).getArgumentIndex() = argumentIndex
- }
-
- /** Gets the indirection index of this indirect return node. */
- int getIndirectionIndex() {
- result = this.(FinalParameterNode).getIndirectionIndex()
- or
- this.(IndirectOperand).hasOperandAndIndirectionIndex(_, result)
- }
-}
-
-/**
- * INTERNAL: do not use.
- *
- * A node representing the indirection of a value after it
- * has been returned from a function.
- */
-class IndirectArgumentOutNode extends PostUpdateNodeImpl {
- override ArgumentOperand operand;
-
- int getArgumentIndex() {
- exists(CallInstruction call | call.getArgumentOperand(result) = operand)
- }
-
- Operand getAddressOperand() { result = operand }
-
- CallInstruction getCallInstruction() { result.getAnArgumentOperand() = operand }
-
- /**
- * Gets the `Function` that the call targets, if this is statically known.
- */
- Function getStaticCallTarget() { result = this.getCallInstruction().getStaticCallTarget() }
-
- override string toStringImpl() {
- exists(string prefix | if indirectionIndex > 0 then prefix = "" else prefix = "pointer to " |
- // This string should be unique enough to be helpful but common enough to
- // avoid storing too many different strings.
- result = prefix + this.getStaticCallTarget().getName() + " output argument"
- or
- not exists(this.getStaticCallTarget()) and
- result = prefix + "output argument"
- )
- }
-}
-
-/**
- * Holds if `node` is an indirect operand with columns `(operand, indirectionIndex)`, and
- * `operand` represents a use of the fully converted value of `call`.
- */
-private predicate hasOperand(Node node, CallInstruction call, int indirectionIndex, Operand operand) {
- operandForFullyConvertedCall(operand, call) and
- hasOperandAndIndex(node, operand, indirectionIndex)
-}
-
-/**
- * Holds if `node` is an indirect instruction with columns `(instr, indirectionIndex)`, and
- * `instr` represents a use of the fully converted value of `call`.
- *
- * Note that `hasOperand(node, _, _, _)` implies `not hasInstruction(node, _, _, _)`.
- */
-private predicate hasInstruction(
- Node node, CallInstruction call, int indirectionIndex, Instruction instr
-) {
- instructionForFullyConvertedCall(instr, call) and
- hasInstructionAndIndex(node, instr, indirectionIndex)
-}
-
-/**
- * INTERNAL: do not use.
- *
- * A node representing the indirect value of a function call (i.e., a value hidden
- * behind a number of indirections).
- */
-class IndirectReturnOutNode extends Node {
- CallInstruction call;
- int indirectionIndex;
-
- IndirectReturnOutNode() {
- // Annoyingly, we need to pick the fully converted value as the output of the function to
- // make flow through in the shared dataflow library work correctly.
- hasOperand(this, call, indirectionIndex, _)
- or
- hasInstruction(this, call, indirectionIndex, _)
- }
-
- CallInstruction getCallInstruction() { result = call }
-
- int getIndirectionIndex() { result = indirectionIndex }
-
- /** Gets the operand associated with this node, if any. */
- Operand getOperand() { hasOperand(this, call, indirectionIndex, result) }
-
- /** Gets the instruction associated with this node, if any. */
- Instruction getInstruction() { hasInstruction(this, call, indirectionIndex, result) }
-}
-
-/**
- * An `IndirectReturnOutNode` which is used as a destination of a store operation.
- * When it's used for a store operation it's useful to have this be a `PostUpdateNode` for
- * the shared dataflow library's flow-through mechanism to detect flow in cases such as:
- * ```cpp
- * struct MyInt {
- * int i;
- * int& getRef() { return i; }
- * };
- * ...
- * MyInt mi;
- * mi.getRef() = source(); // this is detected as a store to `i` via flow-through.
- * sink(mi.i);
- * ```
- */
-private class PostIndirectReturnOutNode extends IndirectReturnOutNode, PostUpdateNode {
- PostIndirectReturnOutNode() {
- any(StoreInstruction store).getDestinationAddressOperand() = this.getOperand()
- }
-
- override Node getPreUpdateNode() { result = this }
-}
-
-/**
- * INTERNAL: Do not use.
- *
- * Returns `t`, but stripped of the outer-most `indirectionIndex` number of indirections.
- */
-private Type getTypeImpl0(Type t, int indirectionIndex) {
- indirectionIndex = 0 and
- result = t
- or
- indirectionIndex > 0 and
- exists(Type stripped |
- stripped = stripPointer(t.stripTopLevelSpecifiers()) and
- // We need to avoid the case where `stripPointer(t) = t` (which can happen
- // on iterators that specify a `value_type` that is the iterator itself).
- // Such a type would create an infinite loop otherwise. For these cases we
- // simply don't produce a result for `getTypeImpl`.
- // To be on the safe side, we check whether the _unspecified_ type has
- // changed since this also prevents an infinite loop when `stripped` and
- // `t` only differ by const'ness or volatile'ness.
- stripped.getUnspecifiedType() != t.getUnspecifiedType() and
- result = getTypeImpl0(stripped, indirectionIndex - 1)
- )
-}
-
-/**
- * INTERNAL: Do not use.
- *
- * Returns `t`, but stripped of the outer-most `indirectionIndex` number of indirections.
- *
- * If `indirectionIndex` cannot be stripped off `t`, an `UnknownType` is returned.
- */
-bindingset[t, indirectionIndex]
-pragma[inline_late]
-Type getTypeImpl(Type t, int indirectionIndex) {
- result = getTypeImpl0(t, indirectionIndex)
- or
- // If we cannot produce the right type we return an error type.
- // This can sometimes happen when we don't know the real
- // type of a void pointer.
- not exists(getTypeImpl0(t, indirectionIndex)) and
- result instanceof UnknownType
-}
-
-private module RawIndirectNodes {
- /**
- * INTERNAL: Do not use.
- *
- * A node that represents the indirect value of an operand in the IR
- * after `index` number of loads.
- */
- private class RawIndirectOperand0 extends Node, TRawIndirectOperand0 {
- Node0Impl node;
- int indirectionIndex;
-
- RawIndirectOperand0() { this = TRawIndirectOperand0(node, indirectionIndex) }
-
- /** Gets the underlying instruction. */
- Operand getOperand() { result = node.asOperand() }
-
- /** Gets the underlying indirection index. */
- int getIndirectionIndex() { result = indirectionIndex }
-
- override Declaration getFunction() { result = node.getFunction() }
-
- override DataFlowCallable getEnclosingCallable() {
- result.asSourceCallable() = node.getEnclosingCallable()
- }
-
- override predicate isGLValue() { this.getOperand().isGLValue() }
-
- override Type getType() {
- exists(int sub, Type type, boolean isGLValue |
- type = getOperandType(this.getOperand(), isGLValue) and
- if isGLValue = true then sub = 1 else sub = 0
- |
- result = getTypeImpl(type.getUnderlyingType(), indirectionIndex - sub)
- )
- }
-
- final override Location getLocationImpl() {
- if exists(this.getOperand().getLocation())
- then result = this.getOperand().getLocation()
- else result instanceof UnknownLocation
- }
-
- override string toStringImpl() {
- result = stars(this) + operandNode(this.getOperand()).toStringImpl()
- }
- }
-
- /**
- * INTERNAL: Do not use.
- *
- * A node that represents the indirect value of an instruction in the IR
- * after `index` number of loads.
- */
- private class RawIndirectInstruction0 extends Node, TRawIndirectInstruction0 {
- Node0Impl node;
- int indirectionIndex;
-
- RawIndirectInstruction0() { this = TRawIndirectInstruction0(node, indirectionIndex) }
-
- /** Gets the underlying instruction. */
- Instruction getInstruction() { result = node.asInstruction() }
-
- /** Gets the underlying indirection index. */
- int getIndirectionIndex() { result = indirectionIndex }
-
- override Declaration getFunction() { result = node.getFunction() }
-
- override DataFlowCallable getEnclosingCallable() {
- result.asSourceCallable() = node.getEnclosingCallable()
- }
-
- override predicate isGLValue() { this.getInstruction().isGLValue() }
-
- override Type getType() {
- exists(int sub, Type type, boolean isGLValue |
- type = getInstructionType(this.getInstruction(), isGLValue) and
- if isGLValue = true then sub = 1 else sub = 0
- |
- result = getTypeImpl(type.getUnderlyingType(), indirectionIndex - sub)
- )
- }
-
- final override Location getLocationImpl() {
- if exists(this.getInstruction().getLocation())
- then result = this.getInstruction().getLocation()
- else result instanceof UnknownLocation
- }
-
- override string toStringImpl() {
- result = stars(this) + instructionNode(this.getInstruction()).toStringImpl()
- }
- }
-
- /**
- * INTERNAL: Do not use.
- *
- * A node that represents the indirect value of an operand in the IR
- * after a number of loads.
- */
- class RawIndirectOperand extends Node {
- int indirectionIndex;
- Operand operand;
-
- RawIndirectOperand() {
- exists(Node0Impl node | operand = node.asOperand() |
- this = TRawIndirectOperand0(node, indirectionIndex)
- or
- this = TRawIndirectInstruction0(node, indirectionIndex)
- )
- }
-
- /** Gets the operand associated with this node. */
- Operand getOperand() { result = operand }
-
- /** Gets the underlying indirection index. */
- int getIndirectionIndex() { result = indirectionIndex }
- }
-
- /**
- * INTERNAL: Do not use.
- *
- * A node that represents the indirect value of an instruction in the IR
- * after a number of loads.
- */
- class RawIndirectInstruction extends Node {
- int indirectionIndex;
- Instruction instr;
-
- RawIndirectInstruction() {
- exists(Node0Impl node | instr = node.asInstruction() |
- this = TRawIndirectOperand0(node, indirectionIndex)
- or
- this = TRawIndirectInstruction0(node, indirectionIndex)
- )
- }
-
- /** Gets the instruction associated with this node. */
- Instruction getInstruction() { result = instr }
-
- /** Gets the underlying indirection index. */
- int getIndirectionIndex() { result = indirectionIndex }
- }
-}
-
-import RawIndirectNodes
-
-/**
- * INTERNAL: do not use.
- *
- * A node representing the value of an output parameter
- * just before reaching the end of a function.
- */
-class FinalParameterNode extends Node, TFinalParameterNode {
- Parameter p;
- int indirectionIndex;
-
- FinalParameterNode() { this = TFinalParameterNode(p, indirectionIndex) }
-
- /** Gets the parameter associated with this final use. */
- Parameter getParameter() { result = p }
-
- /** Gets the underlying indirection index. */
- int getIndirectionIndex() { result = indirectionIndex }
-
- /** Gets the argument index associated with this final use. */
- final int getArgumentIndex() { result = p.getIndex() }
-
- override Declaration getFunction() { result = p.getFunction() }
-
- override DataFlowCallable getEnclosingCallable() {
- result.asSourceCallable() = this.getFunction()
- }
-
- override Type getType() { result = getTypeImpl(p.getUnderlyingType(), indirectionIndex) }
-
- final override Location getLocationImpl() {
- // Parameters can have multiple locations. When there's a unique location we use
- // that one, but if multiple locations exist we default to an unknown location.
- result = unique( | | p.getLocation())
- or
- not exists(unique( | | p.getLocation())) and
- result instanceof UnknownLocation
- }
-
- override string toStringImpl() { result = stars(this) + p.toString() }
-}
-
-/**
- * The value of an uninitialized local variable, viewed as a node in a data
- * flow graph.
- */
-class UninitializedNode extends Node {
- LocalVariable v;
-
- UninitializedNode() {
- exists(SsaImpl::Definition def, SsaImpl::SourceVariable sv |
- def.getIndirectionIndex() = 0 and
- def.getValue().asInstruction() instanceof UninitializedInstruction and
- SsaImpl::defToNode(this, def, sv) and
- v = sv.getBaseVariable().(SsaImpl::BaseIRVariable).getIRVariable().getAst()
- )
- }
-
- /** Gets the uninitialized local variable corresponding to this node. */
- LocalVariable getLocalVariable() { result = v }
-}
-
-abstract private class AbstractParameterNode extends Node {
- /**
- * Holds if this node is the parameter of `f` at the specified position. The
- * implicit `this` parameter is considered to have position `-1`, and
- * pointer-indirection parameters are at further negative positions.
- */
- predicate isSourceParameterOf(Function f, ParameterPosition pos) { none() }
-
- /**
- * Holds if this node is the parameter of `sc` at the specified position. The
- * implicit `this` parameter is considered to have position `-1`, and
- * pointer-indirection parameters are at further negative positions.
- */
- predicate isSummaryParameterOf(
- FlowSummaryImpl::Public::SummarizedCallable sc, ParameterPosition pos
- ) {
- none()
- }
-
- /**
- * Holds if this node is the parameter of `c` at the specified position. The
- * implicit `this` parameter is considered to have position `-1`, and
- * pointer-indirection parameters are at further negative positions.
- */
- final predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
- this.isSummaryParameterOf(c.asSummarizedCallable(), pos)
- or
- this.isSourceParameterOf(c.asSourceCallable(), pos)
- }
-
- /** Gets the `Parameter` associated with this node, if it exists. */
- Parameter getParameter() { none() } // overridden by subclasses
-}
-
-abstract private class AbstractIndirectParameterNode extends AbstractParameterNode {
- /** Gets the indirection index of this parameter node. */
- abstract int getIndirectionIndex();
-}
-
-/**
- * INTERNAL: do not use.
- *
- * A node representing an indirection of a parameter.
- */
-final class IndirectParameterNode = AbstractIndirectParameterNode;
-
-pragma[noinline]
-private predicate indirectParameterNodeHasArgumentIndexAndIndex(
- IndirectInstructionParameterNode node, int argumentIndex, int indirectionIndex
-) {
- node.hasInstructionAndIndirectionIndex(_, indirectionIndex) and
- node.getArgumentIndex() = argumentIndex
-}
-
-pragma[noinline]
-private predicate indirectPositionHasArgumentIndexAndIndex(
- IndirectionPosition pos, int argumentIndex, int indirectionIndex
-) {
- pos.getArgumentIndex() = argumentIndex and
- pos.getIndirectionIndex() = indirectionIndex
-}
-
-private class IndirectInstructionParameterNode extends AbstractIndirectParameterNode instanceof IndirectInstruction
-{
- InitializeParameterInstruction init;
-
- IndirectInstructionParameterNode() {
- IndirectInstruction.super.hasInstructionAndIndirectionIndex(init, _)
- }
-
- int getArgumentIndex() { init.hasIndex(result) }
-
- override string toStringImpl() {
- exists(string prefix | prefix = stars(this) |
- result = prefix + this.getParameter().toString()
- or
- not exists(this.getParameter()) and
- result = prefix + "this"
- )
- }
-
- /** Gets the parameter whose indirection is initialized. */
- override Parameter getParameter() { result = init.getParameter() }
-
- override DataFlowCallable getEnclosingCallable() {
- result.asSourceCallable() = this.getFunction()
- }
-
- override Declaration getFunction() { result = init.getEnclosingFunction() }
-
- override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
- this.getFunction() = f and
- exists(int argumentIndex, int indirectionIndex |
- indirectPositionHasArgumentIndexAndIndex(pos, argumentIndex, indirectionIndex) and
- indirectParameterNodeHasArgumentIndexAndIndex(this, argumentIndex, indirectionIndex)
- )
- }
-
- /** Gets the underlying operand and the underlying indirection index. */
- predicate hasInstructionAndIndirectionIndex(Instruction instr, int index) {
- IndirectInstruction.super.hasInstructionAndIndirectionIndex(instr, index)
- }
-
- final override int getIndirectionIndex() { this.hasInstructionAndIndirectionIndex(init, result) }
-}
-
-/**
- * The value of a parameter at function entry, viewed as a node in a data
- * flow graph. This includes both explicit parameters such as `x` in `f(x)`
- * and implicit parameters such as `this` in `x.f()`.
- *
- * To match a specific kind of parameter, consider using one of the subclasses
- * `ExplicitParameterNode`, `ThisParameterNode`, or
- * `ParameterIndirectionNode`.
- */
-final class ParameterNode = AbstractParameterNode;
-
-abstract private class AbstractDirectParameterNode extends AbstractParameterNode { }
-
-/** An explicit positional parameter, including `this`, but not `...`. */
-final class DirectParameterNode = AbstractDirectParameterNode;
-
-/**
- * INTERNAL: Do not use.
- *
- * A non-indirect parameter node that is represented as an `Instruction`.
- */
-abstract class InstructionDirectParameterNode extends InstructionNode, AbstractDirectParameterNode {
- final override InitializeParameterInstruction instr;
-
- /**
- * INTERNAL: Do not use.
- *
- * Gets the `IRVariable` that this parameter references.
- */
- final IRVariable getIRVariable() { result = instr.getIRVariable() }
-}
-
-abstract private class AbstractExplicitParameterNode extends AbstractDirectParameterNode { }
-
-final class ExplicitParameterNode = AbstractExplicitParameterNode;
-
-/** An explicit positional parameter, not including `this` or `...`. */
-private class ExplicitParameterInstructionNode extends AbstractExplicitParameterNode,
- InstructionDirectParameterNode
-{
- ExplicitParameterInstructionNode() { exists(instr.getParameter()) }
-
- override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
- f.getParameter(pos.(DirectPosition).getArgumentIndex()) = instr.getParameter()
- }
-
- override string toStringImpl() { result = instr.getParameter().toString() }
-
- override Parameter getParameter() { result = instr.getParameter() }
-}
-
-/** An implicit `this` parameter. */
-class ThisParameterInstructionNode extends AbstractExplicitParameterNode,
- InstructionDirectParameterNode
-{
- ThisParameterInstructionNode() { instr.getIRVariable() instanceof IRThisVariable }
-
- override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
- pos.(DirectPosition).getArgumentIndex() = -1 and
- instr.getEnclosingFunction() = f
- }
-
- override string toStringImpl() { result = "this" }
-}
-
-/**
- * A parameter node that is part of a summary.
- */
-class SummaryParameterNode extends AbstractParameterNode, FlowSummaryNode {
- SummaryParameterNode() {
- FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), _)
- }
-
- private ParameterPosition getPosition() {
- FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), result)
- }
-
- override predicate isSummaryParameterOf(
- FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition p
- ) {
- c = this.getSummarizedCallable() and
- p = this.getPosition()
- }
-}
-
-private class DirectBodyLessParameterNode extends AbstractExplicitParameterNode,
- BodyLessParameterNodeImpl
-{
- DirectBodyLessParameterNode() { indirectionIndex = 0 }
-
- override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
- this.getFunction() = f and
- f.getParameter(pos.(DirectPosition).getArgumentIndex()) = p
- }
-
- override Parameter getParameter() { result = p }
-}
-
-private class IndirectBodyLessParameterNode extends AbstractIndirectParameterNode,
- BodyLessParameterNodeImpl
-{
- IndirectBodyLessParameterNode() { not this instanceof DirectBodyLessParameterNode }
-
- override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
- exists(int argumentPosition |
- this.getFunction() = f and
- f.getParameter(argumentPosition) = p and
- indirectPositionHasArgumentIndexAndIndex(pos, argumentPosition, indirectionIndex)
- )
- }
-
- override int getIndirectionIndex() {
- result = BodyLessParameterNodeImpl.super.getIndirectionIndex()
- }
-
- override Parameter getParameter() { result = p }
-}
-
-/**
- * A node associated with an object after an operation that might have
- * changed its state.
- *
- * This can be either the argument to a callable after the callable returns
- * (which might have mutated the argument), or the qualifier of a field after
- * an update to the field.
- *
- * Nodes corresponding to AST elements, for example `ExprNode`, usually refer
- * to the value before the update with the exception of `ClassInstanceExpr`,
- * which represents the value after the constructor has run.
- */
-abstract class PostUpdateNode extends Node {
- /**
- * Gets the node before the state update.
- */
- abstract Node getPreUpdateNode();
-
- final override Type getType() { result = this.getPreUpdateNode().getType() }
-}
-
-/**
- * The base class for nodes that perform "partial definitions".
- *
- * In contrast to a normal "definition", which provides a new value for
- * something, a partial definition is an expression that may affect a
- * value, but does not necessarily replace it entirely. For example:
- * ```
- * x.y = 1; // a partial definition of the object `x`.
- * x.y.z = 1; // a partial definition of the object `x.y` and `x`.
- * x.setY(1); // a partial definition of the object `x`.
- * setY(&x); // a partial definition of the object `x`.
- * ```
- */
-abstract private class PartialDefinitionNode extends PostUpdateNode {
- /** Gets the indirection index of this node. */
- abstract int getIndirectionIndex();
-
- /** Gets the expression that is partially defined by this node. */
- abstract Expr getDefinedExpr();
-}
-
-/**
- * A `PostUpdateNode` that is part of a flow summary. These are synthesized,
- * for example, when a models-as-data summary models a write to a field since
- * the write needs to target a `PostUpdateNode`.
- */
-class SummaryPostUpdateNode extends FlowSummaryNode, PostUpdateNode {
- SummaryPostUpdateNode() {
- FlowSummaryImpl::Private::summaryPostUpdateNode(this.getSummaryNode(), _)
- }
-
- override Node getPreUpdateNode() {
- FlowSummaryImpl::Private::summaryPostUpdateNode(this.getSummaryNode(),
- result.(FlowSummaryNode).getSummaryNode())
- }
-}
-
-/**
- * A node that represents the value of a variable after a function call that
- * may have changed the variable because it's passed by reference.
- *
- * A typical example would be a call `f(&x)`. Firstly, there will be flow into
- * `x` from previous definitions of `x`. Secondly, there will be a
- * `DefinitionByReferenceNode` to represent the value of `x` after the call has
- * returned. This node will have its `getArgument()` equal to `&x` and its
- * `getVariableAccess()` equal to `x`.
- */
-class DefinitionByReferenceNode extends IndirectArgumentOutNode {
- DefinitionByReferenceNode() { this.getIndirectionIndex() > 0 }
-
- /** Gets the unconverted argument corresponding to this node. */
- Expr getArgument() { result = this.getAddressOperand().getDef().getUnconvertedResultExpression() }
-
- /** Gets the parameter through which this value is assigned. */
- Parameter getParameter() {
- result = this.getCallInstruction().getStaticCallTarget().getParameter(this.getArgumentIndex())
- }
-}
-
-/**
- * A `Node` corresponding to a global (or `static` local) variable in the
- * program, as opposed to the value of that variable at some particular point.
- * This is used to model flow through global variables (and `static` local
- * variables).
- *
- * There is no `VariableNode` for non-`static` local variables.
- */
-class VariableNode extends Node, TGlobalLikeVariableNode {
- Variable v;
- int indirectionIndex;
-
- VariableNode() { this = TGlobalLikeVariableNode(v, indirectionIndex) }
-
- /** Gets the variable corresponding to this node. */
- Variable getVariable() { result = v }
-
- /** Gets the indirection index of this node. */
- int getIndirectionIndex() { result = indirectionIndex }
-
- override Declaration getFunction() { none() }
-
- override DataFlowCallable getEnclosingCallable() {
- // When flow crosses from one _enclosing callable_ to another, the
- // interprocedural data-flow library discards call contexts and inserts a
- // node in the big-step relation used for human-readable path explanations.
- // Therefore we want a distinct enclosing callable for each `VariableNode`,
- // and that can be the `Variable` itself.
- result.asSourceCallable() = v
- }
-
- override Type getType() { result = getTypeImpl(v.getUnderlyingType(), indirectionIndex - 1) }
-
- final override Location getLocationImpl() {
- // Certain variables (such as parameters) can have multiple locations.
- // When there's a unique location we use that one, but if multiple locations
- // exist we default to an unknown location.
- result = unique( | | v.getLocation())
- or
- not exists(unique( | | v.getLocation())) and
- result instanceof UnknownLocation
- }
-
- override string toStringImpl() { result = stars(this) + v.toString() }
-}
-
-/**
- * Gets the node corresponding to `instr`.
- */
-InstructionNode instructionNode(Instruction instr) { result.getInstruction() = instr }
-
-/**
- * Gets the node corresponding to `operand`.
- */
-OperandNode operandNode(Operand operand) { result.getOperand() = operand }
-
-/**
- * Gets the `Node` corresponding to the value of evaluating `e` or any of its
- * conversions. There is no result if `e` is a `Conversion`. For data flowing
- * _out of_ an expression, like when an argument is passed by reference, use
- * `definitionByReferenceNodeFromArgument` instead.
- */
-ExprNode exprNode(Expr e) { result.getExpr(_) = e }
-
-/**
- * Gets the `Node` corresponding to the value of evaluating `e`. Here, `e` may
- * be a `Conversion`. For data flowing _out of_ an expression, like when an
- * argument is passed by reference, use
- * `definitionByReferenceNodeFromArgument` instead.
- */
-ExprNode convertedExprNode(Expr e) { result.getConvertedExpr(_) = e }
-
-/**
- * Gets the `Node` corresponding to the value of `p` at function entry.
- */
-ExplicitParameterNode parameterNode(Parameter p) { result.getParameter() = p }
-
-/**
- * Gets the `Node` corresponding to a definition by reference of the variable
- * that is passed as unconverted `argument` of a call.
- */
-DefinitionByReferenceNode definitionByReferenceNodeFromArgument(Expr argument) {
- result.getArgument() = argument
-}
-
-/** Gets the `VariableNode` corresponding to the variable `v`. */
-VariableNode variableNode(Variable v) {
- result.getVariable() = v and result.getIndirectionIndex() = 1
-}
-
-/**
- * DEPRECATED: See UninitializedNode.
- *
- * Gets the `Node` corresponding to the value of an uninitialized local
- * variable `v`.
- */
-Node uninitializedNode(LocalVariable v) { none() }
-
-predicate hasOperandAndIndex(IndirectOperand indirectOperand, Operand operand, int indirectionIndex) {
- indirectOperand.hasOperandAndIndirectionIndex(operand, indirectionIndex)
-}
-
-predicate hasInstructionAndIndex(
- IndirectInstruction indirectInstr, Instruction instr, int indirectionIndex
-) {
- indirectInstr.hasInstructionAndIndirectionIndex(instr, indirectionIndex)
-}
+private import DataFlowNodes
+import DataFlowNodes::Public
cached
private module Cached {
@@ -1818,6 +122,7 @@ private module Cached {
cached
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
(
+ TaintTrackingUtil::forceCachingInSameStage() and
// Def-use/Use-use flow
SsaImpl::ssaFlow(nodeFrom, nodeTo)
or
@@ -1919,35 +224,7 @@ private module Cached {
)
)
}
-}
-import Cached
-
-/**
- * Holds if data flows from `source` to `sink` in zero or more local
- * (intra-procedural) steps.
- */
-pragma[inline]
-predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
-
-/**
- * Holds if data can flow from `i1` to `i2` in zero or more
- * local (intra-procedural) steps.
- */
-pragma[inline]
-predicate localInstructionFlow(Instruction e1, Instruction e2) {
- localFlow(instructionNode(e1), instructionNode(e2))
-}
-
-/**
- * INTERNAL: Do not use.
- *
- * Ideally this module would be private, but the `asExprInternal` predicate is
- * needed in `DefaultTaintTrackingImpl`. Once `DefaultTaintTrackingImpl` is gone
- * we can make this module private.
- */
-cached
-module ExprFlowCached {
/**
* Holds if `n` is an indirect operand of a `PointerArithmeticInstruction`, and
* `e` is the result of loading from the `PointerArithmeticInstruction`.
@@ -1997,8 +274,7 @@ module ExprFlowCached {
* `x[i]` steps to the expression `x[i - 1]` without traversing the
* entire chain.
*/
- cached
- Expr asExprInternal(Node n) {
+ private Expr asExprInternal(Node n) {
isIndirectBaseOfArrayAccess(n, result)
or
not isIndirectBaseOfArrayAccess(n, _) and
@@ -2060,7 +336,23 @@ module ExprFlowCached {
predicate localExprFlowStep(Expr e1, Expr e2) { localExprFlowStepImpl(_, e1, _, e2) }
}
-import ExprFlowCached
+import Cached
+
+/**
+ * Holds if data flows from `source` to `sink` in zero or more local
+ * (intra-procedural) steps.
+ */
+pragma[inline]
+predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
+
+/**
+ * Holds if data can flow from `i1` to `i2` in zero or more
+ * local (intra-procedural) steps.
+ */
+pragma[inline]
+predicate localInstructionFlow(Instruction e1, Instruction e2) {
+ localFlow(instructionNode(e1), instructionNode(e2))
+}
/**
* Holds if data can flow from `e1` to `e2` in one or more
@@ -2080,158 +372,6 @@ predicate localExprFlow(Expr e1, Expr e2) {
localExprFlowPlus(e1, e2)
}
-/**
- * A canonical representation of a field.
- *
- * For performance reasons we want a unique `Content` that represents
- * a given field across any template instantiation of a class.
- *
- * This is possible in _almost_ all cases, but there are cases where it is
- * not possible to map between a field in the uninstantiated template to a
- * field in the instantiated template. This happens in the case of local class
- * definitions (because the local class is not the template that constructs
- * the instantiation - it is the enclosing function). So this abstract class
- * has two implementations: a non-local case (where we can represent a
- * canonical field as the field declaration from an uninstantiated class
- * template or a non-templated class), and a local case (where we simply use
- * the field from the instantiated class).
- */
-abstract private class CanonicalField extends Field {
- /** Gets a field represented by this canonical field. */
- abstract Field getAField();
-
- /**
- * Gets a class that declares a field represented by this canonical field.
- */
- abstract Class getADeclaringType();
-
- /**
- * Gets a type that this canonical field may have. Note that this may
- * not be a unique type. For example, consider this case:
- * ```
- * template
- * struct S { T x; };
- *
- * S s1;
- * S s2;
- * ```
- * In this case the canonical field corresponding to `S::x` has two types:
- * `int` and `char`.
- */
- Type getAType() { result = this.getAField().getType() }
-
- Type getAnUnspecifiedType() { result = this.getAType().getUnspecifiedType() }
-}
-
-private class NonLocalCanonicalField extends CanonicalField {
- Class declaringType;
-
- NonLocalCanonicalField() {
- declaringType = this.getDeclaringType() and
- not declaringType.isFromTemplateInstantiation(_) and
- not declaringType.isLocal() // handled in LocalCanonicalField
- }
-
- override Field getAField() {
- exists(Class c | result.getDeclaringType() = c |
- // Either the declaring class of the field is a template instantiation
- // that has been constructed from this canonical declaration
- c.isConstructedFrom(declaringType) and
- pragma[only_bind_out](result.getName()) = pragma[only_bind_out](this.getName())
- or
- // or this canonical declaration is not a template.
- not c.isConstructedFrom(_) and
- result = this
- )
- }
-
- override Class getADeclaringType() {
- result = this.getDeclaringType()
- or
- result.isConstructedFrom(this.getDeclaringType())
- }
-}
-
-private class LocalCanonicalField extends CanonicalField {
- Class declaringType;
-
- LocalCanonicalField() {
- declaringType = this.getDeclaringType() and
- declaringType.isLocal()
- }
-
- override Field getAField() { result = this }
-
- override Class getADeclaringType() { result = declaringType }
-}
-
-/**
- * A canonical representation of a `Union`. See `CanonicalField` for the explanation for
- * why we need a canonical representation.
- */
-abstract private class CanonicalUnion extends Union {
- /** Gets a union represented by this canonical union. */
- abstract Union getAUnion();
-
- /** Gets a canonical field of this canonical union. */
- CanonicalField getACanonicalField() { result.getDeclaringType() = this }
-}
-
-private class NonLocalCanonicalUnion extends CanonicalUnion {
- NonLocalCanonicalUnion() { not this.isFromTemplateInstantiation(_) and not this.isLocal() }
-
- override Union getAUnion() {
- result = this
- or
- result.isConstructedFrom(this)
- }
-}
-
-private class LocalCanonicalUnion extends CanonicalUnion {
- LocalCanonicalUnion() { this.isLocal() }
-
- override Union getAUnion() { result = this }
-}
-
-bindingset[f]
-pragma[inline_late]
-private int getFieldSize(CanonicalField f) { result = max(f.getAType().getSize()) }
-
-/**
- * Gets a field in the union `u` whose size
- * is `bytes` number of bytes.
- */
-private CanonicalField getAFieldWithSize(CanonicalUnion u, int bytes) {
- result = u.getACanonicalField() and
- bytes = getFieldSize(result)
-}
-
-cached
-private newtype TContent =
- TNonUnionContent(CanonicalField f, int indirectionIndex) {
- // the indirection index for field content starts at 1 (because `TNonUnionContent` is thought of as
- // the address of the field, `FieldAddress` in the IR).
- indirectionIndex = [1 .. max(SsaImpl::getMaxIndirectionsForType(f.getAnUnspecifiedType()))] and
- // Reads and writes of union fields are tracked using `UnionContent`.
- not f.getDeclaringType() instanceof Union
- } or
- TUnionContent(CanonicalUnion u, int bytes, int indirectionIndex) {
- exists(CanonicalField f |
- f = u.getACanonicalField() and
- bytes = getFieldSize(f) and
- // We key `UnionContent` by the union instead of its fields since a write to one
- // field can be read by any read of the union's fields. Again, the indirection index
- // is 1-based (because 0 is considered the address).
- indirectionIndex =
- [1 .. max(SsaImpl::getMaxIndirectionsForType(getAFieldWithSize(u, bytes)
- .getAnUnspecifiedType())
- )]
- )
- } or
- TElementContent(int indirectionIndex) {
- indirectionIndex = [1 .. getMaxElementContentIndirectionIndex()]
- }
-
/**
* A description of the way data may be stored inside an object. Examples
* include instance fields, the contents of a collection object, or the contents
@@ -2641,7 +781,54 @@ module BarrierGuard {
exists(unit)
}
- import ParameterizedBarrierGuard
+ private module P = ParameterizedBarrierGuard;
+
+ predicate getABarrierNode = P::getABarrierNode/0;
+
+ /**
+ * Gets an indirect expression node with indirection index `indirectionIndex` that is
+ * safely guarded by the given guard check.
+ *
+ * For example, given the following code:
+ * ```cpp
+ * int* p;
+ * // ...
+ * *p = source();
+ * if(is_safe_pointer(p)) {
+ * sink(*p);
+ * }
+ * ```
+ * and the following barrier guard check:
+ * ```ql
+ * predicate myGuardChecks(IRGuardCondition g, Expr e, boolean branch) {
+ * exists(Call call |
+ * g.getUnconvertedResultExpression() = call and
+ * call.getTarget().hasName("is_safe_pointer") and
+ * e = call.getAnArgument() and
+ * branch = true
+ * )
+ * }
+ * ```
+ * implementing `isBarrier` as:
+ * ```ql
+ * predicate isBarrier(DataFlow::Node barrier) {
+ * barrier = DataFlow::BarrierGuard::getAnIndirectBarrierNode(1)
+ * }
+ * ```
+ * will block flow from `x = source()` to `sink(x)`.
+ *
+ * NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
+ */
+ Node getAnIndirectBarrierNode(int indirectionIndex) {
+ result = P::getAnIndirectBarrierNode(indirectionIndex, _)
+ }
+
+ /**
+ * Gets an indirect expression node that is safely guarded by the given guard check.
+ *
+ * See `getAnIndirectBarrierNode/1` for examples.
+ */
+ Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
}
private module InstrWithParam {
@@ -2752,7 +939,20 @@ module InstructionBarrierGuard
+ private module P = ParameterizedInstructionBarrierGuard;
+
+ predicate getABarrierNode = P::getABarrierNode/0;
+
+ /**
+ * Gets an indirect node with indirection index `indirectionIndex` that is
+ * safely guarded by the given guard check.
+ */
+ Node getAnIndirectBarrierNode(int indirectionIndex) {
+ result = P::getAnIndirectBarrierNode(indirectionIndex, _)
+ }
+
+ /** Gets an indirect node that is safely guarded by the given guard check. */
+ Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
}
/**
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ExprNodes.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ExprNodes.qll
index 6d69dd11e80..927d2ea9028 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ExprNodes.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ExprNodes.qll
@@ -6,8 +6,8 @@ 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
+private import DataFlowNodes
+private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
cached
private module Cached {
@@ -73,17 +73,9 @@ private module Cached {
// 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())
- )
+ result = IRConstruction::Raw::getAllocationExtentConvertExpr(instr)
or
- // There's no instruction that returns `ParenthesisExpr`, but some queries
- // expect this
- exists(TranslatedTransparentConversion ttc |
- result = ttc.getExpr().(ParenthesisExpr) and
- instr = ttc.getResult()
- )
+ result = IRConstruction::Raw::getTransparentConversionParenthesisExpr(instr)
or
// Certain expressions generate `CopyValueInstruction`s only when they
// are needed. Examples of this include crement operations and compound
@@ -112,10 +104,10 @@ private module Cached {
// 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)
+ exists(StoreInstruction store |
+ store = instr and
+ IRConstruction::Raw::instructionProducesExprResult(store) and
+ result = asDefinitionImpl0(store)
)
or
// IR construction breaks an array aggregate literal `{1, 2, 3}` into a
@@ -145,18 +137,9 @@ private module Cached {
// 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()
- )
+ result = IRConstruction::Raw::getAssignOperationStoreExpr(store)
or
- // Similarly for `i++` and `++i` 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(TranslatedCrementOperation tco |
- store = tco.getInstruction(CrementStoreTag()) and
- result = tco.getExpr()
- )
+ result = IRConstruction::Raw::getCrementOperationStoreExpr(store)
}
/**
@@ -166,11 +149,7 @@ private module Cached {
*/
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())
- )
+ IRConstruction::Raw::isConditionalExprTempStore(store)
}
/**
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll
index f880bee1c1c..5fd7bb4567b 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll
@@ -6,6 +6,7 @@
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
private import DataFlowUtil
+private import DataFlowNodes
private import DataFlowPrivate
private import SsaImpl as Ssa
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRFieldFlowSteps.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRFieldFlowSteps.qll
index c0976f8c3e9..93d4ddfda68 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRFieldFlowSteps.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRFieldFlowSteps.qll
@@ -6,6 +6,7 @@ private import cpp
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
+private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
private import PrintIRUtilities
/** A property provider for local IR dataflow store steps. */
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRLocalFlow.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRLocalFlow.qll
index e310db31931..2c741e244d1 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRLocalFlow.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRLocalFlow.qll
@@ -2,6 +2,7 @@ private import cpp
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
+private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
private import SsaImpl as Ssa
private import PrintIRUtilities
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRUtilities.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRUtilities.qll
index 5dfe53c946b..2e092851b3b 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRUtilities.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRUtilities.qll
@@ -6,6 +6,7 @@ private import cpp
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
+private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
private Instruction getInstruction(Node n, string stars) {
result = [n.asInstruction(), n.(RawIndirectInstruction).getInstruction()] and
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImpl.qll
index 80b440fff22..f1bdd6b8c52 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImpl.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImpl.qll
@@ -10,8 +10,9 @@ private import semmle.code.cpp.models.interfaces.PartialFlow as PartialFlow
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as FIO
private import semmle.code.cpp.ir.internal.IRCppLanguage
private import semmle.code.cpp.ir.dataflow.internal.ModelUtil
-private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedInitialization
+private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
private import DataFlowPrivate
+private import DataFlowNodes
import SsaImplCommon
private module SourceVariables {
@@ -438,10 +439,7 @@ private predicate sourceVariableHasBaseAndIndex(SourceVariable v, BaseSourceVari
* initialize `v`.
*/
private Instruction getInitializationTargetAddress(IRVariable v) {
- exists(TranslatedVariableInitialization init |
- init.getIRVariable() = v and
- result = init.getTargetAddress()
- )
+ result = IRConstruction::Raw::getInitializationTargetAddress(v)
}
/** An initial definition of an SSA variable address. */
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll
index 10ebfdb5be0..e4734f285fa 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll
@@ -4,75 +4,25 @@ import semmle.code.cpp.ir.internal.IRCppLanguage
private import semmle.code.cpp.ir.implementation.raw.internal.SideEffects as SideEffects
private import DataFlowImplCommon as DataFlowImplCommon
private import DataFlowUtil
+private import DataFlowNodes
private import semmle.code.cpp.models.interfaces.PointerWrapper
private import DataFlowPrivate
private import TypeFlow
private import semmle.code.cpp.ir.ValueNumbering
/**
- * Holds if `operand` is an operand that is not used by the dataflow library.
- * Ignored operands are not recognized as uses by SSA, and they don't have a
- * corresponding `(Indirect)OperandNode`.
- */
-predicate ignoreOperand(Operand operand) {
- operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand() or
- operand = any(Instruction instr | ignoreInstruction(instr)).getAUse() or
- operand instanceof MemoryOperand
-}
-
-/**
- * Holds if `instr` is an instruction that is not used by the dataflow library.
- * Ignored instructions are not recognized as reads/writes by SSA, and they
- * don't have a corresponding `(Indirect)InstructionNode`.
- */
-predicate ignoreInstruction(Instruction instr) {
- DataFlowImplCommon::forceCachingInSameStage() and
- (
- instr instanceof CallSideEffectInstruction or
- instr instanceof CallReadSideEffectInstruction or
- instr instanceof ExitFunctionInstruction or
- instr instanceof EnterFunctionInstruction or
- instr instanceof WriteSideEffectInstruction or
- instr instanceof PhiInstruction or
- instr instanceof ReadSideEffectInstruction or
- instr instanceof ChiInstruction or
- instr instanceof InitializeIndirectionInstruction or
- instr instanceof AliasedDefinitionInstruction or
- instr instanceof AliasedUseInstruction or
- instr instanceof InitializeNonLocalInstruction or
- instr instanceof ReturnIndirectionInstruction or
- instr instanceof UninitializedGroupInstruction
- )
-}
-
-/**
- * Gets the C++ type of `this` in the member function `f`.
+ * Gets the C++ type of `this` in an `IRFunction` generated from `f`.
* The result is a glvalue if `isGLValue` is true, and
* a prvalue if `isGLValue` is false.
*/
bindingset[isGLValue]
-private CppType getThisType(Cpp::MemberFunction f, boolean isGLValue) {
- result.hasType(f.getTypeOfThis(), isGLValue)
-}
-
-/**
- * Gets the C++ type of the instruction `i`.
- *
- * This is equivalent to `i.getResultLanguageType()` with the exception
- * of instructions that directly references a `this` IRVariable. In this
- * case, `i.getResultLanguageType()` gives an unknown type, whereas the
- * predicate gives the expected type (i.e., a potentially cv-qualified
- * type `A*` where `A` is the declaring type of the member function that
- * contains `i`).
- */
-cached
-CppType getResultLanguageType(Instruction i) {
- if i.(VariableAddressInstruction).getIRVariable() instanceof IRThisVariable
- then
- if i.isGLValue()
- then result = getThisType(i.getEnclosingFunction(), true)
- else result = getThisType(i.getEnclosingFunction(), false)
- else result = i.getResultLanguageType()
+private CppType getThisType(Cpp::Declaration f, boolean isGLValue) {
+ result.hasType(f.(Cpp::MemberFunction).getTypeOfThis(), isGLValue)
+ or
+ exists(Cpp::PointerType pt |
+ pt.getBaseType() = f.(Cpp::Field).getDeclaringType() and
+ result.hasType(pt, isGLValue)
+ )
}
/**
@@ -230,7 +180,8 @@ private class PointerWrapperTypeIndirection extends Indirection instanceof Point
override predicate isAdditionalDereference(Instruction deref, Operand address) {
exists(CallInstruction call |
operandForFullyConvertedCall(getAUse(deref), call) and
- this = call.getStaticCallTarget().getClassAndName(["operator*", "operator->", "get"]) and
+ this =
+ call.getStaticCallTarget().(Function).getClassAndName(["operator*", "operator->", "get"]) and
address = call.getThisArgumentOperand()
)
}
@@ -249,7 +200,7 @@ private module IteratorIndirections {
override predicate isAdditionalWrite(Node0Impl value, Operand address, boolean certain) {
exists(CallInstruction call | call.getArgumentOperand(0) = value.asOperand() |
- this = call.getStaticCallTarget().getClassAndName("operator=") and
+ this = call.getStaticCallTarget().(Function).getClassAndName("operator=") and
address = call.getThisArgumentOperand() and
certain = false
)
@@ -347,10 +298,6 @@ predicate isWrite(Node0Impl value, Operand address, boolean certain) {
)
}
-predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
- any(Indirection ind).isAdditionalConversionFlow(opFrom, instrTo)
-}
-
newtype TBaseSourceVariable =
// Each IR variable gets its own source variable
TBaseIRVariable(IRVariable var) or
@@ -572,6 +519,69 @@ private class BaseCallInstruction extends BaseSourceVariableInstruction, CallIns
cached
private module Cached {
+ /**
+ * Holds if `operand` is an operand that is not used by the dataflow library.
+ * Ignored operands are not recognized as uses by SSA, and they don't have a
+ * corresponding `(Indirect)OperandNode`.
+ */
+ cached
+ predicate ignoreOperand(Operand operand) {
+ operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand() or
+ operand = any(Instruction instr | ignoreInstruction(instr)).getAUse() or
+ operand instanceof MemoryOperand
+ }
+
+ /**
+ * Holds if `instr` is an instruction that is not used by the dataflow library.
+ * Ignored instructions are not recognized as reads/writes by SSA, and they
+ * don't have a corresponding `(Indirect)InstructionNode`.
+ */
+ cached
+ predicate ignoreInstruction(Instruction instr) {
+ DataFlowImplCommon::forceCachingInSameStage() and
+ (
+ instr instanceof CallSideEffectInstruction or
+ instr instanceof CallReadSideEffectInstruction or
+ instr instanceof ExitFunctionInstruction or
+ instr instanceof EnterFunctionInstruction or
+ instr instanceof WriteSideEffectInstruction or
+ instr instanceof PhiInstruction or
+ instr instanceof ReadSideEffectInstruction or
+ instr instanceof ChiInstruction or
+ instr instanceof InitializeIndirectionInstruction or
+ instr instanceof AliasedDefinitionInstruction or
+ instr instanceof AliasedUseInstruction or
+ instr instanceof InitializeNonLocalInstruction or
+ instr instanceof ReturnIndirectionInstruction or
+ instr instanceof UninitializedGroupInstruction
+ )
+ }
+
+ cached
+ predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
+ any(Indirection ind).isAdditionalConversionFlow(opFrom, instrTo)
+ }
+
+ /**
+ * Gets the C++ type of the instruction `i`.
+ *
+ * This is equivalent to `i.getResultLanguageType()` with the exception
+ * of instructions that directly references a `this` IRVariable. In this
+ * case, `i.getResultLanguageType()` gives an unknown type, whereas the
+ * predicate gives the expected type (i.e., a potentially cv-qualified
+ * type `A*` where `A` is the declaring type of the member function that
+ * contains `i`).
+ */
+ cached
+ CppType getResultLanguageType(Instruction i) {
+ if i.(VariableAddressInstruction).getIRVariable() instanceof IRThisVariable
+ then
+ if i.isGLValue()
+ then result = getThisType(i.getEnclosingFunction(), true)
+ else result = getThisType(i.getEnclosingFunction(), false)
+ else result = i.getResultLanguageType()
+ }
+
/** Holds if `op` is the only use of its defining instruction, and that op is used in a conversation */
private predicate isConversion(Operand op) {
exists(Instruction def, Operand use |
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll
index f190569330f..3e85489b126 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll
@@ -5,64 +5,81 @@ private import semmle.code.cpp.models.interfaces.DataFlow
private import semmle.code.cpp.models.interfaces.SideEffect
private import DataFlowUtil
private import DataFlowPrivate
+private import DataFlowNodes
private import SsaImpl as Ssa
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.cpp.ir.dataflow.FlowSteps
-/**
- * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
- * (intra-procedural) step. This relation is only used for local taint flow
- * (for example `TaintTracking::localTaint(source, sink)`) so it may contain
- * special cases that should only apply to local taint flow.
- */
-predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
- // dataflow step
- DataFlow::localFlowStep(nodeFrom, nodeTo)
- or
- // taint flow step
- localAdditionalTaintStep(nodeFrom, nodeTo, _)
- or
- // models-as-data summarized flow for local data flow (i.e. special case for flow
- // through calls to modeled functions, without relying on global dataflow to join
- // the dots).
- FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(nodeFrom, nodeTo, _)
+cached
+private module Cached {
+ private import DataFlowImplCommon as DataFlowImplCommon
+
+ /**
+ * This predicate exists to collapse the `cached` predicates in this module with the
+ * `cached` predicates in other C/C++ dataflow files, which is then collapsed
+ * with the `cached` predicates in `DataFlowImplCommon.qll`.
+ */
+ cached
+ predicate forceCachingInSameStage() { DataFlowImplCommon::forceCachingInSameStage() }
+
+ /**
+ * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
+ * (intra-procedural) step. This relation is only used for local taint flow
+ * (for example `TaintTracking::localTaint(source, sink)`) so it may contain
+ * special cases that should only apply to local taint flow.
+ */
+ cached
+ predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
+ // dataflow step
+ DataFlow::localFlowStep(nodeFrom, nodeTo)
+ or
+ // taint flow step
+ localAdditionalTaintStep(nodeFrom, nodeTo, _)
+ or
+ // models-as-data summarized flow for local data flow (i.e. special case for flow
+ // through calls to modeled functions, without relying on global dataflow to join
+ // the dots).
+ FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(nodeFrom, nodeTo, _)
+ }
+
+ /**
+ * Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
+ * local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
+ * different objects.
+ */
+ cached
+ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) {
+ operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction()) and
+ model = ""
+ or
+ modeledTaintStep(nodeFrom, nodeTo, model)
+ or
+ // Flow from (the indirection of) an operand of a pointer arithmetic instruction to the
+ // indirection of the pointer arithmetic instruction. This provides flow from `source`
+ // in `x[source]` to the result of the associated load instruction.
+ exists(PointerArithmeticInstruction pai, int indirectionIndex |
+ nodeHasOperand(nodeFrom, pai.getAnOperand(), pragma[only_bind_into](indirectionIndex)) and
+ hasInstructionAndIndex(nodeTo, pai, indirectionIndex + 1)
+ ) and
+ model = ""
+ or
+ any(Ssa::Indirection ind).isAdditionalTaintStep(nodeFrom, nodeTo) and
+ model = ""
+ or
+ // models-as-data summarized flow
+ FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
+ nodeTo.(FlowSummaryNode).getSummaryNode(), false, model)
+ or
+ // object->field conflation for content that is a `TaintInheritingContent`.
+ exists(DataFlow::ContentSet f |
+ readStep(nodeFrom, f, nodeTo) and
+ f.getAReadContent() instanceof TaintInheritingContent
+ ) and
+ model = ""
+ }
}
-/**
- * Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
- * local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
- * different objects.
- */
-cached
-predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) {
- operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction()) and
- model = ""
- or
- modeledTaintStep(nodeFrom, nodeTo, model)
- or
- // Flow from (the indirection of) an operand of a pointer arithmetic instruction to the
- // indirection of the pointer arithmetic instruction. This provides flow from `source`
- // in `x[source]` to the result of the associated load instruction.
- exists(PointerArithmeticInstruction pai, int indirectionIndex |
- nodeHasOperand(nodeFrom, pai.getAnOperand(), pragma[only_bind_into](indirectionIndex)) and
- hasInstructionAndIndex(nodeTo, pai, indirectionIndex + 1)
- ) and
- model = ""
- or
- any(Ssa::Indirection ind).isAdditionalTaintStep(nodeFrom, nodeTo) and
- model = ""
- or
- // models-as-data summarized flow
- FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
- nodeTo.(FlowSummaryNode).getSummaryNode(), false, model)
- or
- // object->field conflation for content that is a `TaintInheritingContent`.
- exists(DataFlow::ContentSet f |
- readStep(nodeFrom, f, nodeTo) and
- f.getAReadContent() instanceof TaintInheritingContent
- ) and
- model = ""
-}
+import Cached
/**
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
@@ -196,7 +213,7 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut, string
// Taint flow from a pointer argument to an output, when the model specifies flow from the deref
// to that output, but the deref is not modeled in the IR for the caller.
exists(
- CallInstruction call, DataFlow::SideEffectOperandNode indirectArgument, Function func,
+ CallInstruction call, SideEffectOperandNode indirectArgument, Function func,
FunctionInput modelIn, FunctionOutput modelOut
|
indirectArgument = callInput(call, modelIn) and
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll
index 8d3e960c3f8..b7dcd4d8f75 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll
@@ -495,7 +495,7 @@ class FieldInstruction extends Instruction {
* `FunctionAddress` instruction.
*/
class FunctionInstruction extends Instruction {
- Language::Function funcSymbol;
+ Language::Declaration funcSymbol;
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
@@ -504,7 +504,7 @@ class FunctionInstruction extends Instruction {
/**
* Gets the function that this instruction references.
*/
- final Language::Function getFunctionSymbol() { result = funcSymbol }
+ final Language::Declaration getFunctionSymbol() { result = funcSymbol }
}
/**
@@ -1678,7 +1678,7 @@ class CallInstruction extends Instruction {
/**
* Gets the `Function` that the call targets, if this is statically known.
*/
- final Language::Function getStaticCallTarget() {
+ final Language::Declaration getStaticCallTarget() {
result = this.getCallTarget().(FunctionAddressInstruction).getFunctionSymbol()
}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll
index 8d3e960c3f8..b7dcd4d8f75 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll
@@ -495,7 +495,7 @@ class FieldInstruction extends Instruction {
* `FunctionAddress` instruction.
*/
class FunctionInstruction extends Instruction {
- Language::Function funcSymbol;
+ Language::Declaration funcSymbol;
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
@@ -504,7 +504,7 @@ class FunctionInstruction extends Instruction {
/**
* Gets the function that this instruction references.
*/
- final Language::Function getFunctionSymbol() { result = funcSymbol }
+ final Language::Declaration getFunctionSymbol() { result = funcSymbol }
}
/**
@@ -1678,7 +1678,7 @@ class CallInstruction extends Instruction {
/**
* Gets the `Function` that the call targets, if this is statically known.
*/
- final Language::Function getStaticCallTarget() {
+ final Language::Declaration getStaticCallTarget() {
result = this.getCallTarget().(FunctionAddressInstruction).getFunctionSymbol()
}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll
index 594e37b668d..da8c394c845 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll
@@ -15,6 +15,8 @@ private import TranslatedCall
private import TranslatedStmt
private import TranslatedFunction
private import TranslatedGlobalVar
+private import TranslatedNonStaticDataMember
+private import TranslatedInitialization
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
instruction = TRawInstruction(result, _)
@@ -44,6 +46,9 @@ module Raw {
or
not var.isFromUninstantiatedTemplate(_) and
var instanceof StaticInitializedStaticLocalVariable
+ or
+ not var.isFromUninstantiatedTemplate(_) and
+ var instanceof Field
) and
var.hasInitializer() and
(
@@ -63,6 +68,8 @@ module Raw {
getTranslatedFunction(decl).hasUserVariable(var, type)
or
getTranslatedVarInit(decl).hasUserVariable(var, type)
+ or
+ getTranslatedFieldInit(decl).hasUserVariable(var, type)
}
cached
@@ -109,7 +116,7 @@ module Raw {
}
cached
- Function getInstructionFunction(Instruction instruction) {
+ Declaration getInstructionFunction(Instruction instruction) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionFunction(getInstructionTag(instruction))
@@ -194,6 +201,89 @@ module Raw {
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
result = getInstructionConvertedResultExpression(instruction).getUnconverted()
}
+
+ /**
+ * Gets the expression associated with the instruction `instr` that computes
+ * the `Convert` instruction on the extent expression of an allocation.
+ */
+ cached
+ Expr getAllocationExtentConvertExpr(Instruction instr) {
+ exists(TranslatedNonConstantAllocationSize tas |
+ instr = tas.getInstruction(AllocationExtentConvertTag()) and
+ result = tas.getExtent().getExpr()
+ )
+ }
+
+ /**
+ * Gets the `ParenthesisExpr` associated with a transparent conversion
+ * instruction, if any.
+ */
+ cached
+ ParenthesisExpr getTransparentConversionParenthesisExpr(Instruction instr) {
+ exists(TranslatedTransparentConversion ttc |
+ result = ttc.getExpr() and
+ instr = ttc.getResult()
+ )
+ }
+
+ /**
+ * Holds if `instr` belongs to a `TranslatedCoreExpr` that produces an
+ * expression result. This indicates that the instruction represents a
+ * definition whose result should be mapped back to the expression.
+ */
+ cached
+ predicate instructionProducesExprResult(Instruction instr) {
+ exists(TranslatedCoreExpr tco |
+ tco.getInstruction(_) = instr and
+ tco.producesExprResult()
+ )
+ }
+
+ /**
+ * Gets the expression associated with a `StoreInstruction` generated
+ * by an `TranslatedAssignOperation`.
+ */
+ cached
+ Expr getAssignOperationStoreExpr(StoreInstruction store) {
+ exists(TranslatedAssignOperation tao |
+ store = tao.getInstruction(AssignmentStoreTag()) and
+ result = tao.getExpr()
+ )
+ }
+
+ /**
+ * Gets the expression associated with a `StoreInstruction` generated
+ * by an `TranslatedCrementOperation`.
+ */
+ cached
+ Expr getCrementOperationStoreExpr(StoreInstruction store) {
+ exists(TranslatedCrementOperation tco |
+ store = tco.getInstruction(CrementStoreTag()) and
+ result = tco.getExpr()
+ )
+ }
+
+ /**
+ * Holds if `store` is a `StoreInstruction` that defines the temporary
+ * `IRVariable` generated as part of the translation of a ternary expression.
+ */
+ cached
+ predicate isConditionalExprTempStore(StoreInstruction store) {
+ exists(TranslatedConditionalExpr tce |
+ store = tce.getInstruction(ConditionValueFalseStoreTag())
+ or
+ store = tce.getInstruction(ConditionValueTrueStoreTag())
+ )
+ }
+
+ /** Gets the instruction that computes the address used to initialize `v`. */
+ cached
+ Instruction getInitializationTargetAddress(IRVariable v) {
+ exists(TranslatedVariableInitialization init |
+ init.getIRVariable() = v and
+ result = init.getTargetAddress()
+ )
+ }
}
class TStageInstruction = TRawInstruction or TRawUnreachedInstruction;
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll
index 00863781257..c6214bf5e4f 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll
@@ -130,27 +130,31 @@ private predicate hasDefaultSideEffect(Call call, ParameterIndex i, boolean buff
}
/**
- * A `Call` or `NewOrNewArrayExpr` or `DeleteOrDeleteArrayExpr`.
+ * An expression that can have call side effects.
*
- * All kinds of expression invoke a function as part of their evaluation. This class provides a
- * way to treat both kinds of function similarly, and to get the invoked `Function`.
+ * All kinds of expressions invoke a function as part of their evaluation. This class provides a
+ * way to treat those expressions similarly, and to get the invoked `Declaration`.
*/
-class CallOrAllocationExpr extends Expr {
- CallOrAllocationExpr() {
+class ExprWithCallSideEffects extends Expr {
+ ExprWithCallSideEffects() {
this instanceof Call
or
this instanceof NewOrNewArrayExpr
or
this instanceof DeleteOrDeleteArrayExpr
+ or
+ this instanceof ConstructorDefaultFieldInit
}
- /** Gets the `Function` invoked by this expression, if known. */
- final Function getTarget() {
+ /** Gets the `Declaration` invoked by this expression, if known. */
+ final Declaration getTarget() {
result = this.(Call).getTarget()
or
result = this.(NewOrNewArrayExpr).getAllocator()
or
result = this.(DeleteOrDeleteArrayExpr).getDeallocator()
+ or
+ result = this.(ConstructorDefaultFieldInit).getTarget()
}
}
@@ -158,7 +162,7 @@ class CallOrAllocationExpr extends Expr {
* Returns the side effect opcode, if any, that represents any side effects not specifically modeled
* by an argument side effect.
*/
-Opcode getCallSideEffectOpcode(CallOrAllocationExpr expr) {
+Opcode getCallSideEffectOpcode(ExprWithCallSideEffects expr) {
not exists(expr.getTarget().(SideEffectFunction)) and result instanceof Opcode::CallSideEffect
or
exists(SideEffectFunction sideEffectFunction |
@@ -175,7 +179,7 @@ Opcode getCallSideEffectOpcode(CallOrAllocationExpr expr) {
/**
* Returns a side effect opcode for parameter index `i` of the specified call.
*
- * This predicate will return at most two results: one read side effect, and one write side effect.
+ * This predicate will yield at most two results: one read side effect, and one write side effect.
*/
Opcode getASideEffectOpcode(Call call, ParameterIndex i) {
exists(boolean buffer |
@@ -228,3 +232,14 @@ Opcode getASideEffectOpcode(Call call, ParameterIndex i) {
)
)
}
+
+/**
+ * Returns a side effect opcode for a default field initialization.
+ *
+ * This predicate will yield two results: one read side effect, and one write side effect.
+ */
+Opcode getDefaultFieldInitSideEffectOpcode() {
+ result instanceof Opcode::IndirectReadSideEffect
+ or
+ result instanceof Opcode::IndirectMayWriteSideEffect
+}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll
index 1a5c65d364d..bd012d4b9b4 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll
@@ -10,6 +10,7 @@ private import SideEffects
private import TranslatedElement
private import TranslatedExpr
private import TranslatedFunction
+private import TranslatedInitialization
private import DefaultOptions as DefaultOptions
/**
@@ -348,7 +349,7 @@ class TranslatedExprCall extends TranslatedCallExpr {
class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
override FunctionCall expr;
- override Function getInstructionFunction(InstructionTag tag) {
+ override Declaration getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and result = expr.getTarget()
}
@@ -429,6 +430,9 @@ class TranslatedCallSideEffects extends TranslatedSideEffects, TTranslatedCallSi
or
expr instanceof DeleteOrDeleteArrayExpr and
result = getTranslatedDeleteOrDeleteArray(expr).getInstruction(CallTag())
+ or
+ expr instanceof ConstructorDefaultFieldInit and
+ result = getTranslatedConstructorFieldInitialization(expr).getInstruction(CallTag())
}
}
@@ -504,11 +508,25 @@ abstract class TranslatedSideEffect extends TranslatedElement {
abstract predicate sideEffectInstruction(Opcode opcode, CppType type);
}
+private class CallOrDefaultFieldInit extends Expr {
+ CallOrDefaultFieldInit() {
+ this instanceof Call
+ or
+ this instanceof ConstructorDefaultFieldInit
+ }
+
+ Declaration getTarget() {
+ result = this.(Call).getTarget()
+ or
+ result = this.(ConstructorDefaultFieldInit).getTarget()
+ }
+}
+
/**
* The IR translation of a single argument side effect for a call.
*/
abstract class TranslatedArgumentSideEffect extends TranslatedSideEffect {
- Call call;
+ CallOrDefaultFieldInit callOrInit;
int index;
SideEffectOpcode sideEffectOpcode;
@@ -524,7 +542,7 @@ abstract class TranslatedArgumentSideEffect extends TranslatedSideEffect {
result = "(read side effect for " + this.getArgString() + ")"
}
- override Call getPrimaryExpr() { result = call }
+ override Expr getPrimaryExpr() { result = callOrInit }
override predicate sortOrder(int group, int indexInGroup) {
indexInGroup = index and
@@ -586,9 +604,10 @@ abstract class TranslatedArgumentSideEffect extends TranslatedSideEffect {
tag instanceof OnlyInstructionTag and
operandTag instanceof BufferSizeOperandTag and
result =
- getTranslatedExpr(call.getArgument(call.getTarget()
- .(SideEffectFunction)
- .getParameterSizeIndex(index)).getFullyConverted()).getResult()
+ getTranslatedExpr(callOrInit
+ .(Call)
+ .getArgument(callOrInit.getTarget().(SideEffectFunction).getParameterSizeIndex(index))
+ .getFullyConverted()).getResult()
}
/** Holds if this side effect is a write side effect, rather than a read side effect. */
@@ -616,7 +635,7 @@ class TranslatedArgumentExprSideEffect extends TranslatedArgumentSideEffect,
Expr arg;
TranslatedArgumentExprSideEffect() {
- this = TTranslatedArgumentExprSideEffect(call, arg, index, sideEffectOpcode)
+ this = TTranslatedArgumentExprSideEffect(callOrInit, arg, index, sideEffectOpcode)
}
final override Locatable getAst() { result = arg }
@@ -640,28 +659,31 @@ class TranslatedArgumentExprSideEffect extends TranslatedArgumentSideEffect,
* The IR translation of an argument side effect for `*this` on a call, where there is no `Expr`
* object that represents the `this` argument.
*
- * The applies only to constructor calls, as the AST has exploit qualifier `Expr`s for all other
- * calls to non-static member functions.
+ * This applies to constructor calls and default field initializations, as the AST has explicit
+ * qualifier `Expr`s for all other calls to non-static member functions.
*/
-class TranslatedStructorQualifierSideEffect extends TranslatedArgumentSideEffect,
- TTranslatedStructorQualifierSideEffect
+class TranslatedImplicitThisQualifierSideEffect extends TranslatedArgumentSideEffect,
+ TTranslatedImplicitThisQualifierSideEffect
{
- TranslatedStructorQualifierSideEffect() {
- this = TTranslatedStructorQualifierSideEffect(call, sideEffectOpcode) and
+ TranslatedImplicitThisQualifierSideEffect() {
+ this = TTranslatedImplicitThisQualifierSideEffect(callOrInit, sideEffectOpcode) and
index = -1
}
- final override Locatable getAst() { result = call }
+ final override Locatable getAst() { result = callOrInit }
- final override Type getIndirectionType() { result = call.getTarget().getDeclaringType() }
+ final override Type getIndirectionType() { result = callOrInit.getTarget().getDeclaringType() }
final override string getArgString() { result = "this" }
final override Instruction getArgInstruction() {
exists(TranslatedStructorCall structorCall |
- structorCall.getExpr() = call and
+ structorCall.getExpr() = callOrInit and
result = structorCall.getQualifierResult()
)
+ or
+ callOrInit instanceof ConstructorDefaultFieldInit and
+ result = getTranslatedFunction(callOrInit.getEnclosingFunction()).getLoadThisInstruction()
}
}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll
index ff8867db696..be8bff5b05c 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll
@@ -36,7 +36,8 @@ abstract class TranslatedCondition extends TranslatedElement {
final override Declaration getFunction() {
result = getEnclosingFunction(expr) or
result = getEnclosingVariable(expr).(GlobalOrNamespaceVariable) or
- result = getEnclosingVariable(expr).(StaticInitializedStaticLocalVariable)
+ result = getEnclosingVariable(expr).(StaticInitializedStaticLocalVariable) or
+ result = getEnclosingVariable(expr).(Field)
}
final Type getResultType() { result = expr.getUnspecifiedType() }
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll
index c0fe9cd2207..6de5c1ba21f 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll
@@ -34,8 +34,11 @@ abstract class TranslatedDeclarationEntry extends TranslatedElement, TTranslated
or
result = entry.getDeclaration().(GlobalOrNamespaceVariable)
or
+ result = entry.getDeclaration().(Field)
+ or
not entry.getDeclaration() instanceof StaticInitializedStaticLocalVariable and
not entry.getDeclaration() instanceof GlobalOrNamespaceVariable and
+ not entry.getDeclaration() instanceof Field and
result = stmt.getEnclosingFunction()
)
}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll
index 9829388ef17..58456476f6a 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll
@@ -767,7 +767,7 @@ newtype TTranslatedElement =
expr = initList.getFieldExpr(field, position).getFullyConverted()
)
or
- exists(ConstructorFieldInit init |
+ exists(ConstructorDirectFieldInit init |
not ignoreExpr(init) and
ast = init and
field = init.getTarget() and
@@ -775,6 +775,14 @@ newtype TTranslatedElement =
position = -1
)
} or
+ // The initialization of a field via a default member initializer.
+ TTranslatedDefaultFieldInitialization(Expr ast, Field field) {
+ exists(ConstructorDefaultFieldInit init |
+ not ignoreExpr(init) and
+ ast = init and
+ field = init.getTarget()
+ )
+ } or
// The value initialization of a field due to an omitted member of an
// initializer list.
TTranslatedFieldValueInitialization(Expr ast, Field field) {
@@ -871,7 +879,7 @@ newtype TTranslatedElement =
// The declaration/initialization part of a `ConditionDeclExpr`
TTranslatedConditionDecl(ConditionDeclExpr expr) { not ignoreExpr(expr) } or
// The side effects of a `Call`
- TTranslatedCallSideEffects(CallOrAllocationExpr expr) {
+ TTranslatedCallSideEffects(ExprWithCallSideEffects expr) {
not ignoreExpr(expr) and
not ignoreSideEffects(expr)
} or
@@ -910,15 +918,23 @@ newtype TTranslatedElement =
} or
// Constructor calls lack a qualifier (`this`) expression, so we need to handle the side effects
// on `*this` without an `Expr`.
- TTranslatedStructorQualifierSideEffect(Call call, SideEffectOpcode opcode) {
+ TTranslatedImplicitThisQualifierSideEffect(ExprWithCallSideEffects call, SideEffectOpcode opcode) {
not ignoreExpr(call) and
not ignoreSideEffects(call) and
- call instanceof ConstructorCall and
- opcode = getASideEffectOpcode(call, -1)
+ (
+ call instanceof ConstructorCall and
+ opcode = getASideEffectOpcode(call, -1)
+ or
+ call instanceof ConstructorFieldInit and
+ opcode = getDefaultFieldInitSideEffectOpcode()
+ )
} or
// The side effect that initializes newly-allocated memory.
TTranslatedAllocationSideEffect(AllocationExpr expr) { not ignoreSideEffects(expr) } or
- TTranslatedStaticStorageDurationVarInit(Variable var) { Raw::varHasIRFunc(var) } or
+ TTranslatedStaticStorageDurationVarInit(Variable var) {
+ Raw::varHasIRFunc(var) and not var instanceof Field
+ } or
+ TTranslatedNonStaticDataMemberVarInit(Field var) { Raw::varHasIRFunc(var) } or
TTranslatedAssertionOperand(MacroInvocation mi, int index) { hasAssertionOperand(mi, index) }
/**
@@ -1179,7 +1195,7 @@ abstract class TranslatedElement extends TTranslatedElement {
* If the instruction specified by `tag` is a `FunctionInstruction`, gets the
* `Function` for that instruction.
*/
- Function getInstructionFunction(InstructionTag tag) { none() }
+ Declaration getInstructionFunction(InstructionTag tag) { none() }
/**
* If the instruction specified by `tag` is a `VariableInstruction`, gets the
@@ -1297,5 +1313,7 @@ abstract class TranslatedRootElement extends TranslatedElement {
this instanceof TTranslatedFunction
or
this instanceof TTranslatedStaticStorageDurationVarInit
+ or
+ this instanceof TTranslatedNonStaticDataMemberVarInit
}
}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll
index 2f7ffa636da..9a437b90538 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll
@@ -14,6 +14,7 @@ private import TranslatedFunction
private import TranslatedInitialization
private import TranslatedStmt
private import TranslatedGlobalVar
+private import TranslatedNonStaticDataMember
private import IRConstruction
import TranslatedCall
@@ -138,6 +139,8 @@ abstract class TranslatedExpr extends TranslatedElement {
result = getTranslatedFunction(getEnclosingFunction(expr))
or
result = getTranslatedVarInit(getEnclosingVariable(expr))
+ or
+ result = getTranslatedFieldInit(getEnclosingVariable(expr))
}
}
@@ -153,7 +156,10 @@ Declaration getEnclosingDeclaration0(Expr e) {
i.getExpr().getFullyConverted() = e and
v = i.getDeclaration()
|
- if v instanceof StaticInitializedStaticLocalVariable or v instanceof GlobalOrNamespaceVariable
+ if
+ v instanceof StaticInitializedStaticLocalVariable or
+ v instanceof GlobalOrNamespaceVariable or
+ v instanceof Field
then result = v
else result = e.getEnclosingDeclaration()
)
@@ -173,7 +179,10 @@ Variable getEnclosingVariable0(Expr e) {
i.getExpr().getFullyConverted() = e and
v = i.getDeclaration()
|
- if v instanceof StaticInitializedStaticLocalVariable or v instanceof GlobalOrNamespaceVariable
+ if
+ v instanceof StaticInitializedStaticLocalVariable or
+ v instanceof GlobalOrNamespaceVariable or
+ v instanceof Field
then result = v
else result = e.getEnclosingVariable()
)
@@ -826,6 +835,46 @@ class TranslatedPostfixCrementOperation extends TranslatedCrementOperation {
override Instruction getResult() { result = this.getLoadedOperand().getResult() }
}
+class TranslatedParamAccessForType extends TranslatedNonConstantExpr {
+ override ParamAccessForType expr;
+
+ TranslatedParamAccessForType() {
+ // Currently only needed for this parameter accesses.
+ expr.isThisAccess()
+ }
+
+ final override Instruction getFirstInstruction(EdgeKind kind) {
+ result = this.getInstruction(OnlyInstructionTag()) and
+ kind instanceof GotoEdge
+ }
+
+ override Instruction getALastInstructionInternal() {
+ result = this.getInstruction(OnlyInstructionTag())
+ }
+
+ final override TranslatedElement getChildInternal(int id) { none() }
+
+ override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
+ tag = OnlyInstructionTag() and
+ result = this.getParent().getChildSuccessor(this, kind)
+ }
+
+ override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) }
+
+ override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
+ tag = OnlyInstructionTag() and
+ opcode instanceof Opcode::CopyValue and
+ resultType = getTypeForPRValue(expr.getType())
+ }
+
+ override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
+ tag = OnlyInstructionTag() and
+ operandTag instanceof UnaryOperandTag and
+ result =
+ this.getEnclosingFunction().(TranslatedNonStaticDataMemberVarInit).getLoadThisInstruction()
+ }
+}
+
/**
* IR translation of an array access expression (e.g. `a[i]`). The array being accessed will either
* be a prvalue of pointer type (possibly due to an implicit array-to-pointer conversion), or a
@@ -1215,7 +1264,7 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
resultType = this.getResultType()
}
- override Function getInstructionFunction(InstructionTag tag) {
+ override Declaration getInstructionFunction(InstructionTag tag) {
tag = OnlyInstructionTag() and
result = expr.getTarget()
}
@@ -2498,7 +2547,7 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect
any()
}
- override Function getInstructionFunction(InstructionTag tag) {
+ override Declaration getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and result = expr.getAllocator()
}
@@ -2581,7 +2630,7 @@ class TranslatedDeleteOrDeleteArrayExpr extends TranslatedNonConstantExpr, Trans
result = this.getFirstArgumentOrCallInstruction(kind)
}
- override Function getInstructionFunction(InstructionTag tag) {
+ override Declaration getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and result = expr.getDeallocator()
}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll
index b280dd7bc70..10c03313122 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll
@@ -148,7 +148,8 @@ abstract class TranslatedInitialization extends TranslatedElement, TTranslatedIn
final override Declaration getFunction() {
result = getEnclosingFunction(expr) or
result = getEnclosingVariable(expr).(GlobalOrNamespaceVariable) or
- result = getEnclosingVariable(expr).(StaticInitializedStaticLocalVariable)
+ result = getEnclosingVariable(expr).(StaticInitializedStaticLocalVariable) or
+ result = getEnclosingVariable(expr).(Field)
}
final override Locatable getAst() { result = expr }
@@ -514,8 +515,8 @@ TranslatedFieldInitialization getTranslatedConstructorFieldInitialization(Constr
}
/**
- * Represents the IR translation of the initialization of a field from an
- * element of an initializer list.
+ * The IR translation of the initialization of a field from an element of
+ * an initializer list.
*/
abstract class TranslatedFieldInitialization extends TranslatedElement {
Expr ast;
@@ -528,13 +529,11 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
final override Declaration getFunction() {
result = getEnclosingFunction(ast) or
result = getEnclosingVariable(ast).(GlobalOrNamespaceVariable) or
- result = getEnclosingVariable(ast).(StaticInitializedStaticLocalVariable)
+ result = getEnclosingVariable(ast).(StaticInitializedStaticLocalVariable) or
+ result = getEnclosingVariable(ast).(Field)
}
- final override Instruction getFirstInstruction(EdgeKind kind) {
- result = this.getInstruction(this.getFieldAddressTag()) and
- kind instanceof GotoEdge
- }
+ final Field getField() { result = field }
/**
* Gets the zero-based index describing the order in which this field is to be
@@ -542,6 +541,20 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
*/
final int getOrder() { result = field.getInitializationOrder() }
+ /** Gets the position in the initializer list, or `-1` if the initialization is implicit. */
+ int getPosition() { result = -1 }
+}
+
+/**
+ * The IR translation of the initialization of a field from an element of an initializer
+ * list where default initialization is not used.
+ */
+abstract class TranslatedNonDefaultFieldInitialization extends TranslatedFieldInitialization {
+ final override Instruction getFirstInstruction(EdgeKind kind) {
+ result = this.getInstruction(this.getFieldAddressTag()) and
+ kind instanceof GotoEdge
+ }
+
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = this.getFieldAddressTag() and
opcode instanceof Opcode::FieldAddress and
@@ -559,18 +572,13 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
}
final InstructionTag getFieldAddressTag() { result = InitializerFieldAddressTag() }
-
- final Field getField() { result = field }
-
- /** Gets the position in the initializer list, or `-1` if the initialization is implicit. */
- int getPosition() { result = -1 }
}
/**
- * Represents the IR translation of the initialization of a field from an
- * explicit element in an initializer list.
+ * The IR translation of the initialization of a field from an explicit element in
+ * an initializer list.
*/
-class TranslatedExplicitFieldInitialization extends TranslatedFieldInitialization,
+class TranslatedExplicitFieldInitialization extends TranslatedNonDefaultFieldInitialization,
InitializationContext, TTranslatedExplicitFieldInitialization
{
Expr expr;
@@ -610,15 +618,81 @@ class TranslatedExplicitFieldInitialization extends TranslatedFieldInitializatio
override int getPosition() { result = position }
}
+/**
+ * The IR translation of the initialization of a field from an element of an initializer
+ * list where default initialization is used.
+ */
+class TranslatedDefaultFieldInitialization extends TranslatedFieldInitialization,
+ TTranslatedDefaultFieldInitialization
+{
+ TranslatedDefaultFieldInitialization() {
+ this = TTranslatedDefaultFieldInitialization(ast, field)
+ }
+
+ final override Instruction getFirstInstruction(EdgeKind kind) {
+ result = this.getInstruction(CallTargetTag()) and
+ kind instanceof GotoEdge
+ }
+
+ override Instruction getALastInstructionInternal() {
+ result = this.getSideEffects().getALastInstruction()
+ }
+
+ override TranslatedElement getLastChild() { result = this.getSideEffects() }
+
+ override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
+ tag = CallTargetTag() and
+ result = this.getInstruction(CallTag())
+ or
+ tag = CallTag() and
+ result = this.getSideEffects().getFirstInstruction(kind)
+ }
+
+ override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
+ child = this.getSideEffects() and
+ result = this.getParent().getChildSuccessor(this, kind)
+ }
+
+ override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
+ tag = CallTargetTag() and
+ opcode instanceof Opcode::FunctionAddress and
+ resultType = getFunctionGLValueType()
+ or
+ tag = CallTag() and
+ opcode instanceof Opcode::Call and
+ resultType = getVoidType()
+ }
+
+ override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
+ tag = CallTag() and
+ (
+ operandTag instanceof CallTargetOperandTag and
+ result = this.getInstruction(CallTargetTag())
+ or
+ operandTag instanceof ThisArgumentOperandTag and
+ result = getTranslatedFunction(this.getFunction()).getLoadThisInstruction()
+ )
+ }
+
+ override Declaration getInstructionFunction(InstructionTag tag) {
+ tag = CallTargetTag() and
+ result = field
+ }
+
+ override TranslatedElement getChild(int id) { id = 0 and result = this.getSideEffects() }
+
+ final TranslatedSideEffects getSideEffects() { result.getExpr() = ast }
+}
+
private string getZeroValue(Type type) {
if type instanceof FloatingPointType then result = "0.0" else result = "0"
}
/**
- * Represents the IR translation of the initialization of a field without a
- * corresponding element in the initializer list.
+ * The IR translation of the initialization of a field without a corresponding
+ * element in the initializer list.
*/
-class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
+class TranslatedFieldValueInitialization extends TranslatedNonDefaultFieldInitialization,
TTranslatedFieldValueInitialization
{
TranslatedFieldValueInitialization() { this = TTranslatedFieldValueInitialization(ast, field) }
@@ -628,7 +702,7 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
- TranslatedFieldInitialization.super.hasInstruction(opcode, tag, resultType)
+ TranslatedNonDefaultFieldInitialization.super.hasInstruction(opcode, tag, resultType)
or
tag = this.getFieldDefaultValueTag() and
opcode instanceof Opcode::Constant and
@@ -659,7 +733,8 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
}
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
- result = TranslatedFieldInitialization.super.getInstructionRegisterOperand(tag, operandTag)
+ result =
+ TranslatedNonDefaultFieldInitialization.super.getInstructionRegisterOperand(tag, operandTag)
or
tag = this.getFieldDefaultValueStoreTag() and
(
@@ -683,8 +758,8 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
}
/**
- * Represents the IR translation of the initialization of an array element from
- * an element of an initializer list.
+ * The IR translation of the initialization of an array element from an element
+ * of an initializer list.
*/
abstract class TranslatedElementInitialization extends TranslatedElement {
ArrayOrVectorAggregateLiteral initList;
@@ -701,6 +776,8 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
result = getEnclosingVariable(initList).(GlobalOrNamespaceVariable)
or
result = getEnclosingVariable(initList).(StaticInitializedStaticLocalVariable)
+ or
+ result = getEnclosingVariable(initList).(Field)
}
final override Instruction getFirstInstruction(EdgeKind kind) {
@@ -759,8 +836,8 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
}
/**
- * Represents the IR translation of the initialization of an array element from
- * an explicit element in an initializer list.
+ * The IR translation of the initialization of an array element from an explicit
+ * element in an initializer list.
*/
class TranslatedExplicitElementInitialization extends TranslatedElementInitialization,
TTranslatedExplicitElementInitialization, InitializationContext
@@ -808,8 +885,8 @@ class TranslatedExplicitElementInitialization extends TranslatedElementInitializ
}
/**
- * Represents the IR translation of the initialization of a range of array
- * elements without corresponding elements in the initializer list.
+ * The IR translation of the initialization of a range of array elements without
+ * corresponding elements in the initializer list.
*/
class TranslatedElementValueInitialization extends TranslatedElementInitialization,
TTranslatedElementValueInitialization
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedNonStaticDataMember.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedNonStaticDataMember.qll
new file mode 100644
index 00000000000..ff06ff3198e
--- /dev/null
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedNonStaticDataMember.qll
@@ -0,0 +1,217 @@
+import semmle.code.cpp.ir.implementation.raw.internal.TranslatedElement
+private import TranslatedExpr
+private import cpp
+private import semmle.code.cpp.ir.implementation.internal.OperandTag
+private import semmle.code.cpp.ir.internal.TempVariableTag
+private import semmle.code.cpp.ir.internal.CppType
+private import TranslatedInitialization
+private import InstructionTag
+private import semmle.code.cpp.ir.internal.IRUtilities
+
+class TranslatedNonStaticDataMemberVarInit extends TranslatedRootElement,
+ TTranslatedNonStaticDataMemberVarInit, InitializationContext
+{
+ Field field;
+ Class cls;
+
+ TranslatedNonStaticDataMemberVarInit() {
+ this = TTranslatedNonStaticDataMemberVarInit(field) and
+ cls.getAMember() = field
+ }
+
+ override string toString() { result = cls.toString() + "::" + field.toString() }
+
+ final override Field getAst() { result = field }
+
+ final override Declaration getFunction() { result = field }
+
+ override Instruction getFirstInstruction(EdgeKind kind) {
+ result = this.getInstruction(EnterFunctionTag()) and
+ kind instanceof GotoEdge
+ }
+
+ override Instruction getALastInstructionInternal() {
+ result = this.getInstruction(ExitFunctionTag())
+ }
+
+ override TranslatedElement getChild(int n) {
+ n = 1 and
+ result = getTranslatedInitialization(field.getInitializer().getExpr().getFullyConverted())
+ }
+
+ override predicate hasInstruction(Opcode op, InstructionTag tag, CppType type) {
+ op instanceof Opcode::EnterFunction and
+ tag = EnterFunctionTag() and
+ type = getVoidType()
+ or
+ op instanceof Opcode::AliasedDefinition and
+ tag = AliasedDefinitionTag() and
+ type = getUnknownType()
+ or
+ op instanceof Opcode::InitializeNonLocal and
+ tag = InitializeNonLocalTag() and
+ type = getUnknownType()
+ or
+ tag = ThisAddressTag() and
+ op instanceof Opcode::VariableAddress and
+ type = getTypeForGLValue(any(UnknownType t))
+ or
+ tag = InitializerStoreTag() and
+ op instanceof Opcode::InitializeParameter and
+ type = this.getThisType()
+ or
+ tag = ThisLoadTag() and
+ op instanceof Opcode::Load and
+ type = this.getThisType()
+ or
+ tag = InitializerIndirectStoreTag() and
+ op instanceof Opcode::InitializeIndirection and
+ type = getTypeForPRValue(cls)
+ or
+ op instanceof Opcode::FieldAddress and
+ tag = InitializerFieldAddressTag() and
+ type = getTypeForGLValue(field.getType())
+ or
+ op instanceof Opcode::ReturnVoid and
+ tag = ReturnTag() and
+ type = getVoidType()
+ or
+ op instanceof Opcode::AliasedUse and
+ tag = AliasedUseTag() and
+ type = getVoidType()
+ or
+ op instanceof Opcode::ExitFunction and
+ tag = ExitFunctionTag() and
+ type = getVoidType()
+ }
+
+ override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
+ kind instanceof GotoEdge and
+ (
+ tag = EnterFunctionTag() and
+ result = this.getInstruction(AliasedDefinitionTag())
+ or
+ tag = AliasedDefinitionTag() and
+ result = this.getInstruction(InitializeNonLocalTag())
+ or
+ tag = InitializeNonLocalTag() and
+ result = this.getInstruction(ThisAddressTag())
+ or
+ tag = ThisAddressTag() and
+ result = this.getInstruction(InitializerStoreTag())
+ or
+ tag = InitializerStoreTag() and
+ result = this.getInstruction(ThisLoadTag())
+ or
+ tag = ThisLoadTag() and
+ result = this.getInstruction(InitializerIndirectStoreTag())
+ or
+ tag = InitializerIndirectStoreTag() and
+ result = this.getInstruction(InitializerFieldAddressTag())
+ )
+ or
+ tag = InitializerFieldAddressTag() and
+ result = this.getChild(1).getFirstInstruction(kind)
+ or
+ kind instanceof GotoEdge and
+ (
+ tag = ReturnTag() and
+ result = this.getInstruction(AliasedUseTag())
+ or
+ tag = AliasedUseTag() and
+ result = this.getInstruction(ExitFunctionTag())
+ )
+ }
+
+ override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
+ child = this.getChild(1) and
+ result = this.getInstruction(ReturnTag()) and
+ kind instanceof GotoEdge
+ }
+
+ final override CppType getInstructionMemoryOperandType(
+ InstructionTag tag, TypedOperandTag operandTag
+ ) {
+ tag = AliasedUseTag() and
+ operandTag instanceof SideEffectOperandTag and
+ result = getUnknownType()
+ }
+
+ override IRVariable getInstructionVariable(InstructionTag tag) {
+ (
+ tag = ThisAddressTag() or
+ tag = InitializerStoreTag() or
+ tag = InitializerIndirectStoreTag()
+ ) and
+ result = getIRTempVariable(field, ThisTempVar())
+ }
+
+ override Field getInstructionField(InstructionTag tag) {
+ tag = InitializerFieldAddressTag() and
+ result = field
+ }
+
+ override predicate hasTempVariable(TempVariableTag tag, CppType type) {
+ tag = ThisTempVar() and
+ type = this.getThisType()
+ }
+
+ /**
+ * Holds if this variable defines or accesses variable `var` with type `type`. This includes all
+ * parameters and local variables, plus any global variables or static data members that are
+ * directly accessed by the function.
+ */
+ final predicate hasUserVariable(Variable varUsed, CppType type) {
+ (
+ (
+ varUsed instanceof GlobalOrNamespaceVariable
+ or
+ varUsed instanceof StaticLocalVariable
+ or
+ varUsed instanceof MemberVariable and not varUsed instanceof Field
+ ) and
+ exists(VariableAccess access |
+ access.getTarget() = varUsed and
+ getEnclosingVariable(access) = field
+ )
+ or
+ field = varUsed
+ or
+ varUsed.(LocalScopeVariable).getEnclosingElement*() = field
+ or
+ varUsed.(Parameter).getCatchBlock().getEnclosingElement*() = field
+ ) and
+ type = getTypeForPRValue(getVariableType(varUsed))
+ }
+
+ override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
+ (
+ tag = InitializerStoreTag()
+ or
+ tag = ThisLoadTag()
+ ) and
+ operandTag instanceof AddressOperandTag and
+ result = this.getInstruction(ThisAddressTag())
+ or
+ (
+ tag = InitializerIndirectStoreTag() and
+ operandTag instanceof AddressOperandTag
+ or
+ tag = InitializerFieldAddressTag() and
+ operandTag instanceof UnaryOperandTag
+ ) and
+ result = this.getInstruction(ThisLoadTag())
+ }
+
+ override Instruction getTargetAddress() {
+ result = this.getInstruction(InitializerFieldAddressTag())
+ }
+
+ override Type getTargetType() { result = field.getUnspecifiedType() }
+
+ final Instruction getLoadThisInstruction() { result = this.getInstruction(ThisLoadTag()) }
+
+ private CppType getThisType() { result = getTypeForGLValue(cls) }
+}
+
+TranslatedNonStaticDataMemberVarInit getTranslatedFieldInit(Field field) { result.getAst() = field }
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll
index 8d3e960c3f8..b7dcd4d8f75 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll
@@ -495,7 +495,7 @@ class FieldInstruction extends Instruction {
* `FunctionAddress` instruction.
*/
class FunctionInstruction extends Instruction {
- Language::Function funcSymbol;
+ Language::Declaration funcSymbol;
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
@@ -504,7 +504,7 @@ class FunctionInstruction extends Instruction {
/**
* Gets the function that this instruction references.
*/
- final Language::Function getFunctionSymbol() { result = funcSymbol }
+ final Language::Declaration getFunctionSymbol() { result = funcSymbol }
}
/**
@@ -1678,7 +1678,7 @@ class CallInstruction extends Instruction {
/**
* Gets the `Function` that the call targets, if this is statically known.
*/
- final Language::Function getStaticCallTarget() {
+ final Language::Declaration getStaticCallTarget() {
result = this.getCallTarget().(FunctionAddressInstruction).getFunctionSymbol()
}
diff --git a/cpp/ql/lib/semmle/code/cpp/models/Models.qll b/cpp/ql/lib/semmle/code/cpp/models/Models.qll
index 09f0a0df966..54dc0fa0ff6 100644
--- a/cpp/ql/lib/semmle/code/cpp/models/Models.qll
+++ b/cpp/ql/lib/semmle/code/cpp/models/Models.qll
@@ -48,7 +48,6 @@ private import implementations.SqLite3
private import implementations.PostgreSql
private import implementations.System
private import implementations.StructuredExceptionHandling
-private import implementations.ZMQ
private import implementations.Win32CommandExecution
private import implementations.CA2AEX
private import implementations.CComBSTR
@@ -58,3 +57,4 @@ private import implementations.CAtlFileMapping
private import implementations.CAtlTemporaryFile
private import implementations.CRegKey
private import implementations.WinHttp
+private import implementations.Http
diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/Gets.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/Gets.qll
index b5d12083035..c0e2c0c4538 100644
--- a/cpp/ql/lib/semmle/code/cpp/models/implementations/Gets.qll
+++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/Gets.qll
@@ -112,21 +112,3 @@ private class GetsFunction extends DataFlowFunction, ArrayFunction, AliasFunctio
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
}
-
-/**
- * A model for `getc` and similar functions that are flow sources.
- */
-private class GetcSource extends SourceModelCsv {
- override predicate row(string row) {
- row =
- [
- ";;false;getc;;;ReturnValue;remote", ";;false;getwc;;;ReturnValue;remote",
- ";;false;_getc_nolock;;;ReturnValue;remote", ";;false;_getwc_nolock;;;ReturnValue;remote",
- ";;false;getch;;;ReturnValue;local", ";;false;_getch;;;ReturnValue;local",
- ";;false;_getwch;;;ReturnValue;local", ";;false;_getch_nolock;;;ReturnValue;local",
- ";;false;_getwch_nolock;;;ReturnValue;local", ";;false;getchar;;;ReturnValue;local",
- ";;false;getwchar;;;ReturnValue;local", ";;false;_getchar_nolock;;;ReturnValue;local",
- ";;false;_getwchar_nolock;;;ReturnValue;local",
- ]
- }
-}
diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/Http.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/Http.qll
new file mode 100644
index 00000000000..a5fdd07c31f
--- /dev/null
+++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/Http.qll
@@ -0,0 +1,193 @@
+private import cpp
+private import semmle.code.cpp.ir.dataflow.FlowSteps
+private import semmle.code.cpp.dataflow.new.DataFlow
+
+private class HttpRequest extends Class {
+ HttpRequest() { this.hasGlobalName("_HTTP_REQUEST_V1") }
+}
+
+private class HttpRequestInheritingContent extends TaintInheritingContent, DataFlow::FieldContent {
+ HttpRequestInheritingContent() {
+ this.getAField().getDeclaringType() instanceof HttpRequest and
+ (
+ this.getAField().hasName("pRawUrl") and
+ this.getIndirectionIndex() = 2
+ or
+ this.getAField().hasName("CookedUrl") and
+ this.getIndirectionIndex() = 1
+ or
+ this.getAField().hasName("Headers") and
+ this.getIndirectionIndex() = 1
+ or
+ this.getAField().hasName("pEntityChunks") and
+ this.getIndirectionIndex() = 2
+ or
+ this.getAField().hasName("pSslInfo") and
+ this.getIndirectionIndex() = 2
+ )
+ }
+}
+
+private class HttpCookedUrl extends Class {
+ HttpCookedUrl() { this.hasGlobalName("_HTTP_COOKED_URL") }
+}
+
+private class HttpCookedUrlInheritingContent extends TaintInheritingContent, DataFlow::FieldContent {
+ HttpCookedUrlInheritingContent() {
+ this.getAField().getDeclaringType() instanceof HttpCookedUrl and
+ this.getAField().hasName(["pFullUrl", "pHost", "pAbsPath", "pQueryString"]) and
+ this.getIndirectionIndex() = 2
+ }
+}
+
+private class HttpRequestHeaders extends Class {
+ HttpRequestHeaders() { this.hasGlobalName("_HTTP_REQUEST_HEADERS") }
+}
+
+private class HttpRequestHeadersInheritingContent extends TaintInheritingContent,
+ DataFlow::FieldContent
+{
+ HttpRequestHeadersInheritingContent() {
+ this.getAField().getDeclaringType() instanceof HttpRequestHeaders and
+ (
+ this.getAField().hasName("KnownHeaders") and
+ this.getIndirectionIndex() = 1
+ or
+ this.getAField().hasName("pUnknownHeaders") and
+ this.getIndirectionIndex() = 2
+ )
+ }
+}
+
+private class HttpKnownHeader extends Class {
+ HttpKnownHeader() { this.hasGlobalName("_HTTP_KNOWN_HEADER") }
+}
+
+private class HttpKnownHeaderInheritingContent extends TaintInheritingContent,
+ DataFlow::FieldContent
+{
+ HttpKnownHeaderInheritingContent() {
+ this.getAField().getDeclaringType() instanceof HttpKnownHeader and
+ this.getAField().hasName("pRawValue") and
+ this.getIndirectionIndex() = 2
+ }
+}
+
+private class HttpUnknownHeader extends Class {
+ HttpUnknownHeader() { this.hasGlobalName("_HTTP_UNKNOWN_HEADER") }
+}
+
+private class HttpUnknownHeaderInheritingContent extends TaintInheritingContent,
+ DataFlow::FieldContent
+{
+ HttpUnknownHeaderInheritingContent() {
+ this.getAField().getDeclaringType() instanceof HttpUnknownHeader and
+ this.getAField().hasName(["pName", "pRawValue"]) and
+ this.getIndirectionIndex() = 2
+ }
+}
+
+private class HttpDataChunk extends Class {
+ HttpDataChunk() { this.hasGlobalName("_HTTP_DATA_CHUNK") }
+}
+
+private class HttpDataChunkInheritingContent extends TaintInheritingContent, DataFlow::FieldContent {
+ HttpDataChunkInheritingContent() {
+ this.getAField().getDeclaringType().(Union).getDeclaringType() instanceof HttpDataChunk and
+ (
+ this.getAField().hasName("FromMemory") and
+ this.getIndirectionIndex() = 1
+ or
+ this.getAField().hasName("FromFileHandle") and
+ this.getIndirectionIndex() = 1
+ or
+ this.getAField().hasName("FromFragmentCache") and
+ this.getIndirectionIndex() = 1
+ or
+ this.getAField().hasName("FromFragmentCacheEx") and
+ this.getIndirectionIndex() = 1
+ or
+ this.getAField().hasName("Trailers") and
+ this.getIndirectionIndex() = 1
+ )
+ }
+}
+
+private class FromMemory extends Class {
+ FromMemory() {
+ this.getDeclaringType().(Union).getDeclaringType() instanceof HttpDataChunk and
+ this.getAField().hasName("pBuffer")
+ }
+}
+
+private class FromMemoryInheritingContent extends TaintInheritingContent, DataFlow::FieldContent {
+ FromMemoryInheritingContent() {
+ this.getAField().getDeclaringType() instanceof FromMemory and
+ this.getAField().hasName("pBuffer") and
+ this.getIndirectionIndex() = 2
+ }
+}
+
+private class FromFileHandle extends Class {
+ FromFileHandle() {
+ this.getDeclaringType().(Union).getDeclaringType() instanceof HttpDataChunk and
+ this.getAField().hasName("FileHandle")
+ }
+}
+
+private class FromFileHandleInheritingContent extends TaintInheritingContent, DataFlow::FieldContent
+{
+ FromFileHandleInheritingContent() {
+ this.getAField().getDeclaringType() instanceof FromFileHandle and
+ this.getIndirectionIndex() = 1 and
+ this.getAField().hasName("FileHandle")
+ }
+}
+
+private class FromFragmentCacheOrCacheEx extends Class {
+ FromFragmentCacheOrCacheEx() {
+ this.getDeclaringType().(Union).getDeclaringType() instanceof HttpDataChunk and
+ this.getAField().hasName("pFragmentName")
+ }
+}
+
+private class FromFragmentCacheInheritingContent extends TaintInheritingContent,
+ DataFlow::FieldContent
+{
+ FromFragmentCacheInheritingContent() {
+ this.getAField().getDeclaringType() instanceof FromFragmentCacheOrCacheEx and
+ this.getIndirectionIndex() = 2 and
+ this.getAField().hasName("pFragmentName")
+ }
+}
+
+private class HttpSslInfo extends Class {
+ HttpSslInfo() { this.hasGlobalName("_HTTP_SSL_INFO") }
+}
+
+private class HttpSslInfoInheritingContent extends TaintInheritingContent, DataFlow::FieldContent {
+ HttpSslInfoInheritingContent() {
+ this.getAField().getDeclaringType() instanceof HttpSslInfo and
+ this.getAField().hasName(["pServerCertIssuer", "pServerCertSubject", "pClientCertInfo"]) and
+ this.getIndirectionIndex() = 2
+ }
+}
+
+private class HttpSslClientCertInfo extends Class {
+ HttpSslClientCertInfo() { this.hasGlobalName("_HTTP_SSL_CLIENT_CERT_INFO") }
+}
+
+private class HttpSslClientCertInfoInheritingContent extends TaintInheritingContent,
+ DataFlow::FieldContent
+{
+ HttpSslClientCertInfoInheritingContent() {
+ this.getAField().getDeclaringType() instanceof HttpSslClientCertInfo and
+ (
+ this.getAField().hasName("pCertEncoded") and
+ this.getIndirectionIndex() = 2
+ or
+ this.getAField().hasName("Token") and
+ this.getIndirectionIndex() = 1
+ )
+ }
+}
diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/ZMQ.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/ZMQ.qll
deleted file mode 100644
index 22f04cb9c82..00000000000
--- a/cpp/ql/lib/semmle/code/cpp/models/implementations/ZMQ.qll
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Provides implementation classes modeling the ZeroMQ networking library.
- */
-
-import semmle.code.cpp.models.interfaces.FlowSource
-
-/**
- * Remote flow sources.
- */
-private class ZmqSource extends SourceModelCsv {
- override predicate row(string row) {
- row =
- [
- ";;false;zmq_recv;;;Argument[*1];remote", ";;false;zmq_recvmsg;;;Argument[*1];remote",
- ";;false;zmq_msg_recv;;;Argument[*0];remote",
- ]
- }
-}
-
-/**
- * Remote flow sinks.
- */
-private class ZmqSinks extends SinkModelCsv {
- override predicate row(string row) {
- row =
- [
- ";;false;zmq_send;;;Argument[*1];remote-sink",
- ";;false;zmq_sendmsg;;;Argument[*1];remote-sink",
- ";;false;zmq_msg_send;;;Argument[*0];remote-sink",
- ]
- }
-}
-
-/**
- * Flow steps.
- */
-private class ZmqSummaries extends SummaryModelCsv {
- override predicate row(string row) {
- row =
- [
- ";;false;zmq_msg_init_data;;;Argument[*1];Argument[*0];taint",
- ";;false;zmq_msg_data;;;Argument[*0];ReturnValue[*];taint",
- ]
- }
-}
diff --git a/cpp/ql/lib/semmle/code/cpp/models/interfaces/NonThrowing.qll b/cpp/ql/lib/semmle/code/cpp/models/interfaces/NonThrowing.qll
index 85b9b66cd66..04826a487ca 100644
--- a/cpp/ql/lib/semmle/code/cpp/models/interfaces/NonThrowing.qll
+++ b/cpp/ql/lib/semmle/code/cpp/models/interfaces/NonThrowing.qll
@@ -11,10 +11,3 @@ import semmle.code.cpp.models.Models
* The function may still raise a structured exception handling (SEH) exception.
*/
abstract class NonCppThrowingFunction extends Function { }
-
-/**
- * A function that is guaranteed to never throw.
- *
- * DEPRECATED: use `NonCppThrowingFunction` instead.
- */
-deprecated class NonThrowingFunction = NonCppThrowingFunction;
diff --git a/cpp/ql/lib/semmle/code/cpp/models/interfaces/Throwing.qll b/cpp/ql/lib/semmle/code/cpp/models/interfaces/Throwing.qll
index 111b9953395..a781bab07c3 100644
--- a/cpp/ql/lib/semmle/code/cpp/models/interfaces/Throwing.qll
+++ b/cpp/ql/lib/semmle/code/cpp/models/interfaces/Throwing.qll
@@ -10,19 +10,6 @@ import semmle.code.cpp.Function
import semmle.code.cpp.models.Models
import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
-/**
- * A function that is known to raise an exception.
- *
- * DEPRECATED: use `AlwaysSehThrowingFunction` instead.
- */
-abstract deprecated class ThrowingFunction extends Function {
- /**
- * Holds if this function may throw an exception during evaluation.
- * If `unconditional` is `true` the function always throws an exception.
- */
- abstract predicate mayThrowException(boolean unconditional);
-}
-
/**
* A function that unconditionally raises a structured exception handling (SEH) exception.
*/
diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll
index 2423a3a71a0..03dbc56dc99 100644
--- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll
+++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll
@@ -404,7 +404,7 @@ predicate cmpWithLinearBound(
* For example, if `t` is a signed 32-bit type then holds if `lb` is
* `-2^31` and `ub` is `2^31 - 1`.
*/
-private predicate typeBounds(ArithmeticType t, float lb, float ub) {
+private predicate typeBounds0(ArithmeticType t, float lb, float ub) {
exists(IntegralType integralType, float limit |
integralType = t and limit = 2.pow(8 * integralType.getSize())
|
@@ -423,6 +423,42 @@ private predicate typeBounds(ArithmeticType t, float lb, float ub) {
t instanceof FloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
}
+/**
+ * Gets the underlying type for an enumeration `e`.
+ *
+ * If the enumeration does not have an explicit type we approximate it using
+ * the following rules:
+ * - The result type is always `signed`, and
+ * - if the largest value fits in an `int` the result is `int`. Otherwise, the
+ * result is `long`.
+ */
+private IntegralType getUnderlyingTypeForEnum(Enum e) {
+ result = e.getExplicitUnderlyingType()
+ or
+ not e.hasExplicitUnderlyingType() and
+ result.isSigned() and
+ exists(IntType intType |
+ if max(e.getAnEnumConstant().getValue().toFloat()) >= 2.pow(8 * intType.getSize() - 1)
+ then result instanceof LongType
+ else result = intType
+ )
+}
+
+/**
+ * Holds if `lb` and `ub` are the lower and upper bounds of the unspecified
+ * type `t`.
+ *
+ * For example, if `t` is a signed 32-bit type then holds if `lb` is
+ * `-2^31` and `ub` is `2^31 - 1`.
+ *
+ * Unlike `typeBounds0`, this predicate also handles `Enum` types.
+ */
+private predicate typeBounds(Type t, float lb, float ub) {
+ typeBounds0(t, lb, ub)
+ or
+ typeBounds0(getUnderlyingTypeForEnum(t), lb, ub)
+}
+
private Type stripReference(Type t) {
if t instanceof ReferenceType then result = t.(ReferenceType).getBaseType() else result = t
}
diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll
index c3c3c2dd3e7..86753abc5b7 100644
--- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll
+++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll
@@ -512,8 +512,8 @@ private module BoundsEstimate {
*/
float getBoundsLimit() {
// This limit is arbitrary, but low enough that it prevents timeouts on
- // specific observed customer databases (and the in the tests).
- result = 2.0.pow(40)
+ // specific observed customer databases (and in the tests).
+ result = 2.0.pow(29)
}
/** Gets the maximum number of bounds possible for `t` when widening is used. */
@@ -552,34 +552,47 @@ private module BoundsEstimate {
private float nrOfBoundsPhiGuard(RangeSsaDefinition def, StackVariable v) {
// If we have
//
+ // if (x < c) { e1 } else { e2 }
+ // e3
+ //
+ // then `{ e1 }` and `{ e2 }` are both guard phi nodes guarded by `x < c`.
+ // The range analysis propagates bounds on `x` into both branches, filtered
+ // by the condition. In this case all lower bounds flow to `{ e1 }` and only
+ // lower bounds that are smaller than `c` flow to `{ e2 }`.
+ //
+ // The largest number of bounds possible for `e3` is the number of bounds on `x` plus
+ // one. This happens when all bounds flow from `x` to `e1` to `e3` and the
+ // bound `c` can flow to `e2` to `e3`.
+ //
+ // We want to optimize our bounds estimate for `e3`, as that is the estimate
+ // that can continue propagating forward. We don't know how the existing
+ // bounds will be split between the different branches. That depends on
+ // whether the range analysis is tracking lower bounds or upper bounds, and
+ // on the meaning of the condition.
+ //
+ // As a heuristic we divide the number of bounds on `x` by 2 to "average"
+ // the effect of the condition and add 1 to account for the bound from the
+ // condition itself. This will approximate estimates inside the branches,
+ // but will give a good estimate after the branches are merged.
+ //
+ // This also handles cases such as this one
+ //
// if (x < c) { e1 }
- // e2
+ // e3
//
- // then `e2` is both a guard phi node (guarded by `x < c`) and a normal
- // phi node (control is merged after the `if` statement).
- //
- // Assume `x` has `n` bounds. Then `n` bounds are propagated to the guard
- // phi node `{ e1 }` and, since `{ e1 }` is input to `e2` as a normal phi
- // node, `n` bounds are propagated to `e2`. If we also propagate the `n`
- // bounds to `e2` as a guard phi node, then we square the number of
- // bounds.
- //
- // However in practice `x < c` is going to cut down the number of bounds:
- // The tracked bounds can't flow to both branches as that would require
- // them to simultaneously be greater and smaller than `c`. To approximate
- // this better, the contribution from a guard phi node that is also a
- // normal phi node is 1.
- exists(def.getAPhiInput(v)) and
- isGuardPhiWithBound(def, v, _) and
- result = 1
- or
- not exists(def.getAPhiInput(v)) and
- // If there's different `access`es, then they refer to the same variable
- // with the same lower bounds. Hence adding these guards make no sense (the
- // implementation will take the union, but they'll be removed by
- // deduplication). Hence we use `max` as an approximation.
- result =
- max(VariableAccess access | isGuardPhiWithBound(def, v, access) | nrOfBoundsExpr(access))
+ // where `e3` is both a guard phi node (guarded by `x < c`) and a normal
+ // phi node (control is merged after the `if` statement). Here half of the
+ // bounds flow into the branch and then to `e3` as a normal phi node and the
+ // "other" half flow from the condition to `e3` as a guard phi node.
+ exists(float varBounds |
+ // If there's different `access`es, then they refer to the same
+ // variable with the same lower bounds. Hence adding these guards makes no
+ // sense (the implementation will take the union, but they'll be removed by
+ // deduplication). Hence we use `max` as an approximation.
+ varBounds =
+ max(VariableAccess access | isGuardPhiWithBound(def, v, access) | nrOfBoundsExpr(access)) and
+ result = (varBounds + 1) / 2
+ )
or
def.isPhiNode(v) and
not isGuardPhiWithBound(def, v, _) and
@@ -2180,6 +2193,16 @@ module SimpleRangeAnalysisInternal {
/** Gets the estimate of the number of bounds for `e`. */
float estimateNrOfBounds(Expr e) { result = BoundsEstimate::nrOfBoundsExpr(e) }
+
+ /** Counts the numbers of lower bounds that are computed internally for `e`. */
+ float countNrOfLowerBounds(Expr e) {
+ result = strictcount(float lb | lb = getLowerBoundsImpl(e) | lb)
+ }
+
+ /** Counts the numbers of upper bounds that are computed internally for `e`. */
+ float countNrOfUpperBounds(Expr e) {
+ result = strictcount(float ub | ub = getUpperBoundsImpl(e) | ub)
+ }
}
/** Provides predicates for debugging the simple range analysis library. */
@@ -2208,7 +2231,7 @@ private module Debug {
*/
predicate countGetLowerBoundsImpl(Expr e, int n) {
e = getRelevantLocatable() and
- n = strictcount(float lb | lb = getLowerBoundsImpl(e) | lb)
+ n = SimpleRangeAnalysisInternal::countNrOfLowerBounds(e)
}
float debugNrOfBounds(Expr e) {
diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme b/cpp/ql/lib/semmlecode.cpp.dbscheme
index 7e7c2f55670..770002bb023 100644
--- a/cpp/ql/lib/semmlecode.cpp.dbscheme
+++ b/cpp/ql/lib/semmlecode.cpp.dbscheme
@@ -245,6 +245,25 @@ trap_filename(
string filename: string ref
);
+/**
+ * Gives the tag name for `tag`.
+ * For debugging only.
+ */
+tag_name(
+ int tag: @tag,
+ string name: string ref
+);
+
+@trap_or_tag = @tag | @trap;
+
+/**
+ * Gives the name for the source file.
+ */
+source_file_name(
+ int sf: @source_file,
+ string name: string ref
+);
+
/**
* In `build-mode: none` overlay mode, indicates that `source_file`
* (`/path/to/foo.c`) uses the TRAP file `trap_file`; i.e. it is the
@@ -252,16 +271,25 @@ trap_filename(
* includes, or a template instantiation it transitively uses.
*/
source_file_uses_trap(
- string source_file: string ref,
+ int source_file: @source_file ref,
int trap_file: @trap ref
);
/**
- * Holds if there is a definition of `element` in TRAP file `trap_file`.
+ * In `build-mode: none` overlay mode, indicates that the TRAP file
+ * `trap_file` uses tag `tag`.
*/
-in_trap(
+trap_uses_tag(
+ int trap_file: @trap ref,
+ int tag: @tag ref
+);
+
+/**
+ * Holds if there is a definition of `element` in TRAP file or tag `t`.
+ */
+in_trap_or_tag(
int element: @element ref,
- int trap_file: @trap ref
+ int t: @trap_or_tag ref
);
pch_uses(
diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme.stats b/cpp/ql/lib/semmlecode.cpp.dbscheme.stats
index 1c53061ef50..ab81be3fa7c 100644
--- a/cpp/ql/lib/semmlecode.cpp.dbscheme.stats
+++ b/cpp/ql/lib/semmlecode.cpp.dbscheme.stats
@@ -2,7 +2,7 @@
@compilation
- 12592
+ 12591
@externalDataElement
@@ -10,11 +10,11 @@
@file
- 64952
+ 64946
@folder
- 12340
+ 12339
@diagnostic
@@ -25,16 +25,24 @@
1
- @location_default
- 46837429
+ @tag
+ 1
+
+
+ @source_file
+ 1
@pch
248
+
+ @location_default
+ 46837435
+
@macro_expansion
- 40306124
+ 40309769
@other_macro_reference
@@ -42,7 +50,7 @@
@normal_function
- 2734381
+ 2734631
@unknown_function
@@ -50,7 +58,7 @@
@constructor
- 694333
+ 694343
@destructor
@@ -74,11 +82,11 @@
@fun_decl
- 4193664
+ 4193416
@var_decl
- 9368481
+ 9367984
@type_decl
@@ -86,11 +94,11 @@
@namespace_decl
- 407977
+ 408755
@using_declaration
- 266868
+ 266845
@using_directive
@@ -102,15 +110,15 @@
@static_assert
- 172750
+ 172739
@parameter
- 7010805
+ 7011801
@membervariable
- 1500528
+ 1502766
@globalvariable
@@ -118,11 +126,11 @@
@localvariable
- 724674
+ 724688
@enumconstant
- 347955
+ 348040
@errortype
@@ -370,7 +378,7 @@
@routineptr
- 679846
+ 679857
@reference
@@ -396,6 +404,10 @@
@scalable_vector
1
+
+ @decltype
+ 101757
+
@typeof
811
@@ -476,13 +488,9 @@
@remove_reference
5705
-
- @decltype
- 101757
-
@struct
- 976682
+ 976600
@union
@@ -490,15 +498,15 @@
@enum
- 41554
+ 41605
@template_parameter
- 864494
+ 864421
@alias
- 1755899
+ 1755750
@unknown_usertype
@@ -510,11 +518,11 @@
@template_template_parameter
- 6091
+ 6090
@proxy_class
- 48246
+ 48241
@scoped_enum
@@ -522,7 +530,7 @@
@template_struct
- 211194
+ 211176
@template_class
@@ -534,11 +542,11 @@
@mangledname
- 6349610
+ 6349611
@type_mention
- 5911109
+ 5913261
@concept_template
@@ -546,11 +554,11 @@
@routinetype
- 600577
+ 600586
@ptrtomember
- 9678
+ 9677
@specifier
@@ -566,7 +574,7 @@
@declspec
- 330310
+ 330396
@msattribute
@@ -578,11 +586,11 @@
@attribute_arg_token
- 16584
+ 16585
@attribute_arg_constant_expr
- 71632
+ 71626
@attribute_arg_expr
@@ -602,19 +610,19 @@
@derivation
- 473787
+ 473794
@frienddecl
- 767814
+ 767534
@comment
- 11208576
+ 11208578
@namespace
- 8616
+ 8615
@specialnamequalifyingelement
@@ -622,15 +630,15 @@
@namequalifier
- 3042541
+ 3042471
@value
- 13541563
+ 13541565
@initialiser
- 2244830
+ 2245206
@address_of
@@ -646,7 +654,7 @@
@parexpr
- 4915711
+ 4915712
@arithnegexpr
@@ -666,7 +674,7 @@
@postincrexpr
- 84579
+ 84573
@postdecrexpr
@@ -698,11 +706,11 @@
@divexpr
- 52392
+ 52388
@remexpr
- 15907
+ 15908
@paddexpr
@@ -710,7 +718,7 @@
@psubexpr
- 68022
+ 68017
@pdiffexpr
@@ -726,7 +734,7 @@
@andexpr
- 483234
+ 483235
@orexpr
@@ -734,7 +742,7 @@
@xorexpr
- 73958
+ 73953
@eqexpr
@@ -754,7 +762,7 @@
@geexpr
- 81365
+ 81360
@leexpr
@@ -762,7 +770,7 @@
@assignexpr
- 1281279
+ 1281280
@assignaddexpr
@@ -822,7 +830,7 @@
@commaexpr
- 167880
+ 167881
@subscriptexpr
@@ -830,11 +838,11 @@
@callexpr
- 238856
+ 238860
@vastartexpr
- 4964
+ 4963
@vaargexpr
@@ -850,7 +858,7 @@
@varaccess
- 8255502
+ 8255503
@runtime_sizeof
@@ -858,7 +866,7 @@
@runtime_alignof
- 49551
+ 49552
@expr_stmt
@@ -866,11 +874,11 @@
@routineexpr
- 5726119
+ 5725988
@type_operand
- 1405527
+ 1405528
@offsetofexpr
@@ -882,7 +890,7 @@
@literal
- 7985002
+ 7991777
@aggregateliteral
@@ -890,23 +898,23 @@
@c_style_cast
- 6027721
+ 6027720
@temp_init
- 980663
+ 980525
@errorexpr
- 45185
+ 45186
@reference_to
- 1880187
+ 1880002
@ref_indirect
- 2094067
+ 2094099
@vacuous_destructor_call
@@ -914,7 +922,7 @@
@assume
- 4138
+ 4137
@conjugation
@@ -966,7 +974,7 @@
@thisaccess
- 1553675
+ 1553582
@new_expr
@@ -978,11 +986,11 @@
@throw_expr
- 23840
+ 23817
@condition_decl
- 407678
+ 407669
@braced_init_list
@@ -990,7 +998,7 @@
@type_id
- 47588
+ 47589
@sizeof_pack
@@ -1082,7 +1090,7 @@
@uuidof
- 26691
+ 26787
@delete_array_expr
@@ -1098,7 +1106,7 @@
@ctordirectinit
- 112100
+ 112102
@ctorvirtualinit
@@ -1114,7 +1122,7 @@
@dtordirectdestruct
- 39194
+ 39195
@dtorvirtualdestruct
@@ -1122,7 +1130,7 @@
@dtorfielddestruct
- 39566
+ 39567
@static_cast
@@ -1130,7 +1138,7 @@
@reinterpret_cast
- 39964
+ 39962
@const_cast
@@ -1138,15 +1146,15 @@
@dynamic_cast
- 789
+ 788
@lambdaexpr
- 18998
+ 18997
@param_ref
- 162180
+ 162057
@noopexpr
@@ -1250,7 +1258,7 @@
@noexceptexpr
- 28138
+ 28017
@builtinshufflevector
@@ -1422,7 +1430,7 @@
@reuseexpr
- 844466
+ 844446
@istriviallycopyassignable
@@ -1522,7 +1530,7 @@
@requires_expr
- 16453
+ 16452
@nested_requirement
@@ -1534,7 +1542,7 @@
@concept_id
- 90159
+ 90157
@isinvocable
@@ -1550,11 +1558,11 @@
@lambdacapture
- 31866
+ 31864
@stmt_expr
- 2031828
+ 2031829
@stmt_if
@@ -1566,15 +1574,15 @@
@stmt_goto
- 157278
+ 157265
@stmt_label
- 77734
+ 77727
@stmt_return
- 1238238
+ 1238112
@stmt_block
@@ -1590,11 +1598,11 @@
@stmt_switch_case
- 833612
+ 833592
@stmt_switch
- 410617
+ 410607
@stmt_asm
@@ -1602,11 +1610,11 @@
@stmt_decl
- 770031
+ 769985
@stmt_empty
- 428121
+ 428111
@stmt_continue
@@ -1614,11 +1622,11 @@
@stmt_break
- 137507
+ 137498
@stmt_try_block
- 26372
+ 26379
@stmt_microsoft_try
@@ -1642,7 +1650,7 @@
@stmt_handler
- 43218
+ 43224
@stmt_constexpr_if
@@ -1674,11 +1682,11 @@
@ppd_ifndef
- 160444
+ 160487
@ppd_elif
- 21829
+ 21827
@ppd_else
@@ -1690,7 +1698,7 @@
@ppd_plain_include
- 317291
+ 317265
@ppd_define
@@ -1772,11 +1780,11 @@
compilations
- 12592
+ 12591
id
- 12592
+ 12591
cwd
@@ -1794,7 +1802,7 @@
1
2
- 12592
+ 12591
@@ -1820,11 +1828,11 @@
compilation_args
- 1008169
+ 1008084
id
- 12592
+ 12591
num
@@ -1832,7 +1840,7 @@
arg
- 29151
+ 29149
@@ -1891,7 +1899,7 @@
98
99
- 1336
+ 1335
100
@@ -2160,12 +2168,12 @@
1
2
- 13350
+ 13349
2
3
- 12634
+ 12633
3
@@ -2191,7 +2199,7 @@
1
2
- 19304
+ 19303
2
@@ -2211,11 +2219,11 @@
compilation_expanded_args
- 1008169
+ 1008084
id
- 12592
+ 12591
num
@@ -2223,7 +2231,7 @@
arg
- 29151
+ 29149
@@ -2282,7 +2290,7 @@
98
99
- 1336
+ 1335
100
@@ -2551,12 +2559,12 @@
1
2
- 13350
+ 13349
2
3
- 12634
+ 12633
3
@@ -2582,7 +2590,7 @@
1
2
- 19304
+ 19303
2
@@ -2650,11 +2658,11 @@
compilation_compiling_files
- 15739
+ 15738
id
- 2723
+ 2722
num
@@ -2662,7 +2670,7 @@
file
- 13669
+ 13668
@@ -2850,7 +2858,7 @@
1
2
- 12308
+ 12307
2
@@ -2876,7 +2884,7 @@
1
2
- 12526
+ 12525
2
@@ -2896,11 +2904,11 @@
compilation_time
- 62957
+ 62953
id
- 2723
+ 2722
num
@@ -2912,7 +2920,7 @@
seconds
- 15412
+ 16990
@@ -2977,7 +2985,7 @@
4
5
- 2723
+ 2722
@@ -2993,21 +3001,21 @@
3
4
- 1034
+ 381
4
5
- 326
+ 980
5
- 7
- 163
+ 9
+ 217
- 8
- 9
+ 9
+ 10
163
@@ -3017,24 +3025,24 @@
11
- 13
- 217
-
-
- 14
- 17
+ 15
217
17
- 21
+ 20
217
- 24
- 94
+ 20
+ 26
217
+
+ 44
+ 132
+ 163
+
@@ -3101,12 +3109,12 @@
3
4
- 1143
+ 871
4
5
- 1252
+ 1579
5
@@ -3116,33 +3124,33 @@
6
7
- 653
+ 326
7
+ 8
+ 435
+
+
+ 8
9
- 217
+ 163
9
- 10
+ 11
+ 381
+
+
+ 11
+ 30
+ 381
+
+
+ 40
+ 95
217
-
- 10
- 15
- 381
-
-
- 16
- 45
- 381
-
-
- 50
- 94
- 108
-
@@ -3189,21 +3197,16 @@
4
5
+ 108
+
+
+ 177
+ 178
54
- 5
- 6
- 54
-
-
- 148
- 149
- 54
-
-
- 160
- 161
+ 183
+ 184
54
@@ -3220,21 +3223,21 @@
1
2
- 9421
+ 10020
2
3
- 3104
+ 3975
3
4
- 1797
+ 1906
4
- 44
+ 47
1089
@@ -3251,32 +3254,27 @@
1
2
- 8604
+ 9639
2
3
- 2668
+ 3757
3
4
- 1851
+ 1579
4
5
- 925
+ 1143
5
- 15
- 1198
-
-
- 43
- 73
- 163
+ 72
+ 871
@@ -3292,12 +3290,12 @@
1
2
- 13560
+ 13941
2
3
- 1851
+ 3049
@@ -3573,19 +3571,19 @@
compilation_finished
- 12592
+ 12591
id
- 12592
+ 12591
cpu_seconds
- 9489
+ 9593
elapsed_seconds
- 231
+ 210
@@ -3599,7 +3597,7 @@
1
2
- 12592
+ 12591
@@ -3615,7 +3613,7 @@
1
2
- 12592
+ 12591
@@ -3631,17 +3629,17 @@
1
2
- 7953
+ 8289
2
3
- 1052
+ 967
3
- 29
- 483
+ 33
+ 336
@@ -3657,12 +3655,12 @@
1
2
- 8847
+ 9004
2
3
- 641
+ 589
@@ -3678,16 +3676,21 @@
1
2
- 73
+ 31
2
- 5
- 21
+ 3
+ 31
5
- 9
+ 6
+ 10
+
+
+ 7
+ 8
21
@@ -3696,28 +3699,48 @@
21
- 12
+ 13
14
- 21
+ 10
- 19
+ 14
+ 15
+ 10
+
+
+ 16
+ 17
+ 10
+
+
+ 32
33
- 21
+ 10
- 60
- 179
- 21
+ 69
+ 70
+ 10
- 233
- 293
- 21
+ 182
+ 183
+ 10
- 312
- 313
+ 216
+ 217
+ 10
+
+
+ 288
+ 289
+ 10
+
+
+ 319
+ 320
10
@@ -3734,46 +3757,76 @@
1
2
- 73
+ 31
2
- 5
- 21
+ 3
+ 31
5
- 9
+ 6
+ 10
+
+
+ 7
+ 8
21
+
+ 9
+ 10
+ 10
+
10
11
- 21
+ 10
- 12
+ 13
14
- 21
+ 10
- 18
- 32
- 21
+ 14
+ 15
+ 10
- 59
- 154
- 21
+ 16
+ 17
+ 10
- 168
- 219
- 21
+ 32
+ 33
+ 10
- 245
- 246
+ 67
+ 68
+ 10
+
+
+ 163
+ 164
+ 10
+
+
+ 170
+ 171
+ 10
+
+
+ 206
+ 207
+ 10
+
+
+ 240
+ 241
10
@@ -4011,11 +4064,11 @@
locations_default
- 46837429
+ 46837435
id
- 46837429
+ 46837435
file
@@ -4023,7 +4076,7 @@
beginLine
- 7483211
+ 7483212
beginColumn
@@ -4031,7 +4084,7 @@
endLine
- 7484207
+ 7484208
endColumn
@@ -4049,7 +4102,7 @@
1
2
- 46837429
+ 46837435
@@ -4065,7 +4118,7 @@
1
2
- 46837429
+ 46837435
@@ -4081,7 +4134,7 @@
1
2
- 46837429
+ 46837435
@@ -4097,7 +4150,7 @@
1
2
- 46837429
+ 46837435
@@ -4113,7 +4166,7 @@
1
2
- 46837429
+ 46837435
@@ -4514,7 +4567,7 @@
1
2
- 4945831
+ 4945832
2
@@ -4555,7 +4608,7 @@
1
2
- 5008055
+ 5008056
2
@@ -4591,12 +4644,12 @@
1
2
- 5629551
+ 5629552
2
3
- 483108
+ 483109
3
@@ -4627,12 +4680,12 @@
1
2
- 7018147
+ 7018148
2
85
- 465063
+ 465064
@@ -5110,7 +5163,7 @@
1
2
- 5005068
+ 5005069
2
@@ -5146,7 +5199,7 @@
1
2
- 7035321
+ 7035322
2
@@ -5167,7 +5220,7 @@
1
2
- 5628182
+ 5628183
2
@@ -5203,7 +5256,7 @@
1
2
- 5012784
+ 5012785
2
@@ -5223,7 +5276,7 @@
12
72
- 561635
+ 561636
72
@@ -5543,15 +5596,15 @@
files
- 64952
+ 64946
id
- 64952
+ 64946
name
- 64952
+ 64946
@@ -5565,7 +5618,7 @@
1
2
- 64952
+ 64946
@@ -5581,7 +5634,7 @@
1
2
- 64952
+ 64946
@@ -5591,15 +5644,15 @@
folders
- 12340
+ 12339
id
- 12340
+ 12339
name
- 12340
+ 12339
@@ -5613,7 +5666,7 @@
1
2
- 12340
+ 12339
@@ -5629,7 +5682,7 @@
1
2
- 12340
+ 12339
@@ -5639,15 +5692,15 @@
containerparent
- 77271
+ 77264
parent
- 12340
+ 12339
child
- 77271
+ 77264
@@ -5661,7 +5714,7 @@
1
2
- 6007
+ 6006
2
@@ -5696,7 +5749,7 @@
44
151
- 263
+ 262
@@ -5712,7 +5765,7 @@
1
2
- 77271
+ 77264
@@ -6864,6 +6917,102 @@
+
+ tag_name
+ 1
+
+
+ tag
+ 1
+
+
+ name
+ 1
+
+
+
+
+ tag
+ name
+
+
+ 12
+
+
+ 1
+ 2
+ 1
+
+
+
+
+
+
+ name
+ tag
+
+
+ 12
+
+
+ 1
+ 2
+ 1
+
+
+
+
+
+
+
+
+ source_file_name
+ 1
+
+
+ sf
+ 1
+
+
+ name
+ 1
+
+
+
+
+ sf
+ name
+
+
+ 12
+
+
+ 1
+ 2
+ 1
+
+
+
+
+
+
+ name
+ sf
+
+
+ 12
+
+
+ 1
+ 2
+ 1
+
+
+
+
+
+
+
source_file_uses_trap
1
@@ -6913,22 +7062,22 @@
- in_trap
+ trap_uses_tag
1
- element
+ trap_file
1
- trap_file
+ tag
1
- element
- trap_file
+ trap_file
+ tag
12
@@ -6943,7 +7092,55 @@
- trap_file
+ tag
+ trap_file
+
+
+ 12
+
+
+ 1
+ 2
+ 1
+
+
+
+
+
+
+
+
+ in_trap_or_tag
+ 1
+
+
+ element
+ 1
+
+
+ t
+ 1
+
+
+
+
+ element
+ t
+
+
+ 12
+
+
+ 1
+ 2
+ 1
+
+
+
+
+
+
+ t
element
@@ -7344,11 +7541,11 @@
fileannotations
- 4183771
+ 4183417
id
- 5744
+ 5743
kind
@@ -7356,11 +7553,11 @@
name
- 58482
+ 58477
value
- 39356
+ 39353
@@ -7379,7 +7576,7 @@
2
3
- 5544
+ 5543
@@ -7605,7 +7802,7 @@
1
2
- 10983
+ 10982
2
@@ -7615,7 +7812,7 @@
3
5
- 5039
+ 5038
5
@@ -7625,12 +7822,12 @@
7
9
- 4576
+ 4575
9
16
- 4313
+ 4312
16
@@ -7645,7 +7842,7 @@
27
47
- 4818
+ 4817
47
@@ -7676,7 +7873,7 @@
1
2
- 58482
+ 58477
@@ -7692,7 +7889,7 @@
1
2
- 11540
+ 11539
2
@@ -7707,7 +7904,7 @@
4
6
- 4050
+ 4049
6
@@ -7737,7 +7934,7 @@
41
95
- 4450
+ 4449
95
@@ -7768,7 +7965,7 @@
4
5
- 3177
+ 3176
5
@@ -7778,7 +7975,7 @@
8
14
- 2956
+ 2955
14
@@ -7793,7 +7990,7 @@
24
51
- 3524
+ 3523
51
@@ -7839,7 +8036,7 @@
1
2
- 39345
+ 39342
2
@@ -7885,7 +8082,7 @@
14
18
- 3440
+ 3439
18
@@ -7895,7 +8092,7 @@
28
34
- 3135
+ 3134
34
@@ -7905,7 +8102,7 @@
41
66
- 2977
+ 2976
66
@@ -7915,7 +8112,7 @@
92
113
- 2977
+ 2976
113
@@ -7935,11 +8132,11 @@
inmacroexpansion
- 150011419
+ 150011437
id
- 24673500
+ 24673503
inv
@@ -7972,12 +8169,12 @@
6
7
- 6583219
+ 6583220
7
8
- 8719893
+ 8719894
8
@@ -8013,7 +8210,7 @@
3
4
- 481561
+ 481562
4
@@ -8038,7 +8235,7 @@
10
11
- 444695
+ 444696
11
@@ -8063,11 +8260,11 @@
affectedbymacroexpansion
- 48740832
+ 48740838
id
- 7045463
+ 7045464
inv
@@ -8146,7 +8343,7 @@
9
12
- 342973
+ 342974
12
@@ -8181,7 +8378,7 @@
18
20
- 344290
+ 344291
20
@@ -8201,19 +8398,19 @@
macroinvocations
- 40387489
+ 40391183
id
- 40387489
+ 40391183
macro_id
- 182555
+ 182706
location
- 5925541
+ 5926766
kind
@@ -8231,7 +8428,7 @@
1
2
- 40387489
+ 40391183
@@ -8247,7 +8444,7 @@
1
2
- 40387489
+ 40391183
@@ -8263,7 +8460,7 @@
1
2
- 40387489
+ 40391183
@@ -8279,17 +8476,17 @@
1
2
- 61106
+ 61156
2
3
- 27666
+ 27664
3
4
- 17972
+ 18080
4
@@ -8299,27 +8496,27 @@
5
7
- 13833
+ 13832
7
13
- 14704
+ 14703
13
33
- 13724
+ 13723
33
182
- 13724
+ 13723
- 185
- 72208
- 9803
+ 186
+ 72214
+ 9802
@@ -8335,42 +8532,42 @@
1
2
- 77607
+ 77765
2
3
- 30661
+ 30659
3
4
- 14377
+ 14376
4
5
- 10293
+ 10292
5
8
- 14051
+ 14050
8
18
- 14214
+ 14213
18
90
- 13778
+ 13723
90
- 12205
- 7570
+ 12207
+ 7624
@@ -8386,7 +8583,7 @@
1
2
- 178035
+ 178186
2
@@ -8407,17 +8604,17 @@
1
2
- 5261599
+ 5262706
2
4
- 429484
+ 429618
4
- 72208
- 234457
+ 72214
+ 234441
@@ -8433,12 +8630,12 @@
1
2
- 5903376
+ 5904602
2
37
- 22165
+ 22164
@@ -8454,7 +8651,7 @@
1
2
- 5925541
+ 5926766
@@ -8468,13 +8665,13 @@
12
- 1494
- 1495
+ 1495
+ 1496
54
- 740082
- 740083
+ 740200
+ 740201
54
@@ -8494,8 +8691,8 @@
54
- 3146
- 3147
+ 3149
+ 3150
54
@@ -8510,13 +8707,13 @@
12
- 1076
- 1077
+ 1077
+ 1078
54
- 107726
- 107727
+ 107755
+ 107756
54
@@ -8527,15 +8724,15 @@
macroparent
- 33684452
+ 33686920
id
- 33684452
+ 33686920
parent_id
- 15941266
+ 15942726
@@ -8549,7 +8746,7 @@
1
2
- 33684452
+ 33686920
@@ -8565,27 +8762,27 @@
1
2
- 7815090
+ 7816185
2
3
- 1595836
+ 1595835
3
4
- 4707397
+ 4707507
4
5
- 1296896
+ 1297133
5
205
- 526045
+ 526063
@@ -8595,15 +8792,15 @@
macrolocationbind
- 6022573
+ 6023015
id
- 4208559
+ 4209042
location
- 2272360
+ 2272308
@@ -8617,12 +8814,12 @@
1
2
- 3285153
+ 3285657
2
3
- 489021
+ 489010
3
@@ -8632,7 +8829,7 @@
4
5
- 412633
+ 412624
5
@@ -8653,12 +8850,12 @@
1
2
- 1332200
+ 1332170
2
3
- 481406
+ 481395
3
@@ -8668,7 +8865,7 @@
4
5
- 426920
+ 426910
5
@@ -8683,11 +8880,11 @@
macro_argument_unexpanded
- 82174179
+ 82169670
invocation
- 26181675
+ 26181901
argument_index
@@ -8695,7 +8892,7 @@
text
- 341898
+ 341869
@@ -8709,22 +8906,22 @@
1
2
- 9641676
+ 9643301
2
3
- 9734381
+ 9733558
3
4
- 4982956
+ 4982534
4
67
- 1822661
+ 1822507
@@ -8740,22 +8937,22 @@
1
2
- 9823583
+ 9825192
2
3
- 9751897
+ 9751073
3
4
- 4826877
+ 4826468
4
67
- 1779317
+ 1779167
@@ -8780,7 +8977,7 @@
646904
- 2488685
+ 2488917
31
@@ -8823,52 +9020,52 @@
1
2
- 39545
+ 39542
2
3
- 62080
+ 62074
3
4
- 20935
+ 20933
4
5
- 34443
+ 34440
5
6
- 39093
+ 39090
6
9
- 30750
+ 30748
9
15
- 28878
+ 28875
15
26
- 25774
+ 25772
26
57
- 27026
+ 27024
57
517
- 25911
+ 25909
518
@@ -8889,17 +9086,17 @@
1
2
- 242208
+ 242188
2
3
- 89517
+ 89509
3
9
- 10173
+ 10172
@@ -8909,11 +9106,11 @@
macro_argument_expanded
- 82174179
+ 82169670
invocation
- 26181675
+ 26181901
argument_index
@@ -8921,7 +9118,7 @@
text
- 207070
+ 207053
@@ -8935,22 +9132,22 @@
1
2
- 9641676
+ 9643301
2
3
- 9734381
+ 9733558
3
4
- 4982956
+ 4982534
4
67
- 1822661
+ 1822507
@@ -8966,22 +9163,22 @@
1
2
- 12589703
+ 12591079
2
3
- 8396895
+ 8396184
3
4
- 4208641
+ 4208285
4
9
- 986434
+ 986351
@@ -9006,7 +9203,7 @@
646904
- 2488685
+ 2488917
31
@@ -9049,22 +9246,22 @@
1
2
- 21745
+ 21743
2
3
- 26753
+ 26750
3
4
- 43301
+ 43297
4
5
- 15843
+ 15842
5
@@ -9074,32 +9271,32 @@
6
7
- 18326
+ 18324
7
10
- 18883
+ 18882
10
19
- 18252
+ 18251
19
51
- 15696
+ 15694
51
251
- 15548
+ 15547
251
- 1169416
- 9468
+ 1169648
+ 9467
@@ -9115,17 +9312,17 @@
1
2
- 104634
+ 104625
2
3
- 88559
+ 88552
3
66
- 13876
+ 13875
@@ -9135,11 +9332,11 @@
functions
- 4042957
+ 4043207
id
- 4042957
+ 4043207
name
@@ -9161,7 +9358,7 @@
1
2
- 4042957
+ 4043207
@@ -9177,7 +9374,7 @@
1
2
- 4042957
+ 4043207
@@ -9193,12 +9390,12 @@
1
2
- 1441611
+ 1441362
2
4
- 140128
+ 140377
4
@@ -9268,8 +9465,8 @@
124
- 21972
- 21973
+ 21974
+ 21975
124
@@ -9326,26 +9523,26 @@
builtin_functions
- 30803
+ 30800
id
- 30803
+ 30800
function_entry_point
- 1134646
+ 1134663
id
- 1130923
+ 1130940
entry_point
- 1134646
+ 1134663
@@ -9359,7 +9556,7 @@
1
2
- 1127741
+ 1127758
2
@@ -9380,7 +9577,7 @@
1
2
- 1134646
+ 1134663
@@ -9390,11 +9587,11 @@
function_return_type
- 4060256
+ 4060505
id
- 4042957
+ 4043207
return_type
@@ -9412,7 +9609,7 @@
1
2
- 4025659
+ 4025908
2
@@ -9733,44 +9930,44 @@
purefunctions
- 131546
+ 131903
id
- 131546
+ 131903
function_deleted
- 87799
+ 87797
id
- 87799
+ 87797
function_defaulted
- 51525
+ 51524
id
- 51525
+ 51524
function_prototyped
- 4041464
+ 4041713
id
- 4041464
+ 4041713
@@ -9928,15 +10125,15 @@
fun_decls
- 4199638
+ 4199390
id
- 4193664
+ 4193416
function
- 4018441
+ 4018690
type_id
@@ -9948,7 +10145,7 @@
location
- 2806437
+ 2806438
@@ -9962,7 +10159,7 @@
1
2
- 4193664
+ 4193416
@@ -9978,7 +10175,7 @@
1
2
- 4187691
+ 4187442
2
@@ -9999,7 +10196,7 @@
1
2
- 4193664
+ 4193416
@@ -10015,7 +10212,7 @@
1
2
- 4193664
+ 4193416
@@ -10031,12 +10228,12 @@
1
2
- 3857778
+ 3858525
2
5
- 160662
+ 160165
@@ -10052,7 +10249,7 @@
1
2
- 4000147
+ 4000396
2
@@ -10073,7 +10270,7 @@
1
2
- 4018441
+ 4018690
@@ -10089,12 +10286,12 @@
1
2
- 3877814
+ 3878437
2
4
- 140626
+ 140253
@@ -10129,7 +10326,7 @@
364
- 10296
+ 10294
1244
@@ -10146,7 +10343,7 @@
1
2
- 304400
+ 304401
2
@@ -10164,7 +10361,7 @@
45797
- 1483
+ 1485
9907
248
@@ -10254,12 +10451,12 @@
3
11
- 129426
+ 129550
11
3169
- 36587
+ 36463
@@ -10275,12 +10472,12 @@
1
2
- 1441113
+ 1440864
2
4
- 140626
+ 140875
4
@@ -10348,12 +10545,12 @@
1
2
- 2413180
+ 2413305
2
3
- 252132
+ 252008
3
@@ -10374,12 +10571,12 @@
1
2
- 2431847
+ 2431972
2
3
- 233963
+ 233838
3
@@ -10421,7 +10618,7 @@
1
2
- 2767360
+ 2767361
2
@@ -10473,7 +10670,7 @@
id
- 1744269
+ 1744270
name
@@ -10703,26 +10900,26 @@
fun_decl_empty_throws
- 420764
+ 421590
fun_decl
- 420764
+ 421590
fun_decl_noexcept
- 140904
+ 140906
fun_decl
- 140904
+ 140906
constant
- 140464
+ 140466
@@ -10736,7 +10933,7 @@
1
2
- 140904
+ 140906
@@ -10752,7 +10949,7 @@
1
2
- 140024
+ 140026
2
@@ -10767,11 +10964,11 @@
fun_decl_empty_noexcept
- 1160979
+ 1160855
fun_decl
- 1160979
+ 1160855
@@ -10876,11 +11073,11 @@
fun_requires
- 29023
+ 29022
id
- 10082
+ 10081
kind
@@ -10888,7 +11085,7 @@
constraint
- 28787
+ 28786
@@ -11006,7 +11203,7 @@
1
2
- 28551
+ 28550
2
@@ -11027,7 +11224,7 @@
1
2
- 28787
+ 28786
@@ -11037,11 +11234,11 @@
param_decl_bind
- 7295169
+ 7294672
id
- 7295169
+ 7294672
index
@@ -11049,7 +11246,7 @@
fun_decl
- 3524256
+ 3524008
@@ -11063,7 +11260,7 @@
1
2
- 7295169
+ 7294672
@@ -11079,7 +11276,7 @@
1
2
- 7295169
+ 7294672
@@ -11114,12 +11311,12 @@
343
- 16219
+ 16218
622
- 28319
- 28320
+ 28317
+ 28318
124
@@ -11155,12 +11352,12 @@
343
- 16219
+ 16218
622
- 28319
- 28320
+ 28317
+ 28318
124
@@ -11177,7 +11374,7 @@
1
2
- 1505951
+ 1505826
2
@@ -11187,7 +11384,7 @@
3
4
- 600837
+ 600712
4
@@ -11213,7 +11410,7 @@
1
2
- 1505951
+ 1505826
2
@@ -11223,7 +11420,7 @@
3
4
- 600837
+ 600712
4
@@ -11243,15 +11440,15 @@
var_decls
- 9374952
+ 9374456
id
- 9368481
+ 9367984
variable
- 9026372
+ 9027369
type_id
@@ -11259,11 +11456,11 @@
name
- 850480
+ 850481
location
- 6259509
+ 6259510
@@ -11277,7 +11474,7 @@
1
2
- 9368481
+ 9367984
@@ -11293,7 +11490,7 @@
1
2
- 9362010
+ 9361513
2
@@ -11314,7 +11511,7 @@
1
2
- 9368481
+ 9367984
@@ -11330,7 +11527,7 @@
1
2
- 9368481
+ 9367984
@@ -11346,12 +11543,12 @@
1
2
- 8701686
+ 8704176
2
5
- 324686
+ 323192
@@ -11367,7 +11564,7 @@
1
2
- 8973357
+ 8974354
2
@@ -11388,7 +11585,7 @@
1
2
- 8921213
+ 8922210
2
@@ -11409,12 +11606,12 @@
1
2
- 8780711
+ 8783076
2
4
- 245661
+ 244292
@@ -11466,7 +11663,7 @@
1
2
- 868525
+ 868526
2
@@ -11485,7 +11682,7 @@
11
- 2870
+ 2872
80891
@@ -11593,7 +11790,7 @@
25
- 27138
+ 27137
31236
@@ -11610,12 +11807,12 @@
1
2
- 476015
+ 475766
2
3
- 164769
+ 164894
3
@@ -11625,7 +11822,7 @@
4
8
- 72055
+ 72180
8
@@ -11718,16 +11915,16 @@
1
2
- 5758231
+ 5758605
2
20
- 471161
+ 470788
20
- 2942
+ 2941
30116
@@ -11744,12 +11941,12 @@
1
2
- 5838873
+ 5839247
2
2935
- 420635
+ 420262
@@ -11765,7 +11962,7 @@
1
2
- 5961704
+ 5961705
2
@@ -11801,11 +11998,11 @@
var_def
- 3763197
+ 3763198
id
- 3763197
+ 3763198
@@ -11967,7 +12164,7 @@
location
- 1543658
+ 1543659
@@ -12034,7 +12231,7 @@
1
2
- 1594433
+ 1594434
2
@@ -12102,18 +12299,18 @@
type_decl_top
- 675760
+ 676476
type_decl
- 675760
+ 676476
type_requires
- 7658
+ 7657
id
@@ -12171,7 +12368,7 @@
1
2
- 7615
+ 7614
2
@@ -12186,11 +12383,11 @@
namespace_decls
- 407977
+ 408755
id
- 407977
+ 408755
namespace_id
@@ -12198,11 +12395,11 @@
location
- 407977
+ 408755
bodylocation
- 407977
+ 408755
@@ -12216,7 +12413,7 @@
1
2
- 407977
+ 408755
@@ -12232,7 +12429,7 @@
1
2
- 407977
+ 408755
@@ -12248,7 +12445,7 @@
1
2
- 407977
+ 408755
@@ -12308,12 +12505,12 @@
263
- 1509
+ 1517
145
- 1882
- 12507
+ 1890
+ 12533
40
@@ -12374,12 +12571,12 @@
263
- 1509
+ 1517
145
- 1882
- 12507
+ 1890
+ 12533
40
@@ -12440,12 +12637,12 @@
263
- 1509
+ 1517
145
- 1882
- 12507
+ 1890
+ 12533
40
@@ -12462,7 +12659,7 @@
1
2
- 407977
+ 408755
@@ -12478,7 +12675,7 @@
1
2
- 407977
+ 408755
@@ -12494,7 +12691,7 @@
1
2
- 407977
+ 408755
@@ -12510,7 +12707,7 @@
1
2
- 407977
+ 408755
@@ -12526,7 +12723,7 @@
1
2
- 407977
+ 408755
@@ -12542,7 +12739,7 @@
1
2
- 407977
+ 408755
@@ -12552,19 +12749,19 @@
usings
- 271002
+ 270979
id
- 271002
+ 270979
element_id
- 58818
+ 58813
location
- 26742
+ 26740
kind
@@ -12582,7 +12779,7 @@
1
2
- 271002
+ 270979
@@ -12598,7 +12795,7 @@
1
2
- 271002
+ 270979
@@ -12614,7 +12811,7 @@
1
2
- 271002
+ 270979
@@ -12630,12 +12827,12 @@
1
2
- 51118
+ 51113
2
5
- 5365
+ 5364
5
@@ -12656,12 +12853,12 @@
1
2
- 51118
+ 51113
2
5
- 5365
+ 5364
5
@@ -12682,7 +12879,7 @@
1
2
- 58818
+ 58813
@@ -12698,7 +12895,7 @@
1
2
- 21093
+ 21091
2
@@ -12729,7 +12926,7 @@
1
2
- 21093
+ 21091
2
@@ -12760,7 +12957,7 @@
1
2
- 26742
+ 26740
@@ -12833,15 +13030,15 @@
using_container
- 577847
+ 577799
parent
- 21808
+ 21806
child
- 271002
+ 270979
@@ -12885,7 +13082,7 @@
145
146
- 2609
+ 2608
146
@@ -12906,27 +13103,27 @@
1
2
- 96218
+ 96210
2
3
- 119805
+ 119794
3
4
- 20020
+ 20018
4
5
- 26605
+ 26603
5
65
- 8353
+ 8352
@@ -12936,23 +13133,23 @@
static_asserts
- 172750
+ 172739
id
- 172750
+ 172739
condition
- 172750
+ 172739
message
- 38652
+ 38650
location
- 22585
+ 22584
enclosing
@@ -12970,7 +13167,7 @@
1
2
- 172750
+ 172739
@@ -12986,7 +13183,7 @@
1
2
- 172750
+ 172739
@@ -13002,7 +13199,7 @@
1
2
- 172750
+ 172739
@@ -13018,7 +13215,7 @@
1
2
- 172750
+ 172739
@@ -13034,7 +13231,7 @@
1
2
- 172750
+ 172739
@@ -13050,7 +13247,7 @@
1
2
- 172750
+ 172739
@@ -13066,7 +13263,7 @@
1
2
- 172750
+ 172739
@@ -13082,7 +13279,7 @@
1
2
- 172750
+ 172739
@@ -13098,7 +13295,7 @@
1
2
- 28416
+ 28414
2
@@ -13139,7 +13336,7 @@
1
2
- 28416
+ 28414
2
@@ -13180,7 +13377,7 @@
1
2
- 35818
+ 35816
2
@@ -13201,7 +13398,7 @@
1
2
- 30222
+ 30220
2
@@ -13211,12 +13408,12 @@
3
4
- 3385
+ 3384
4
12
- 1903
+ 1902
12
@@ -13242,7 +13439,7 @@
2
3
- 3717
+ 3716
3
@@ -13257,7 +13454,7 @@
5
6
- 4721
+ 4720
6
@@ -13267,7 +13464,7 @@
14
15
- 2640
+ 2639
16
@@ -13277,7 +13474,7 @@
17
18
- 4381
+ 4380
19
@@ -13303,7 +13500,7 @@
2
3
- 3717
+ 3716
3
@@ -13318,7 +13515,7 @@
5
6
- 4721
+ 4720
6
@@ -13328,7 +13525,7 @@
14
15
- 2640
+ 2639
16
@@ -13338,7 +13535,7 @@
17
18
- 4381
+ 4380
19
@@ -13359,7 +13556,7 @@
1
2
- 6940
+ 6939
2
@@ -13369,7 +13566,7 @@
3
4
- 7758
+ 7757
4
@@ -13390,7 +13587,7 @@
1
2
- 5053
+ 5052
2
@@ -13415,7 +13612,7 @@
13
14
- 2640
+ 2639
16
@@ -13436,7 +13633,7 @@
1
2
- 5709
+ 5708
2
@@ -13467,7 +13664,7 @@
1
2
- 5709
+ 5708
2
@@ -13498,7 +13695,7 @@
1
2
- 5863
+ 5862
2
@@ -13544,15 +13741,15 @@
params
- 7051250
+ 7052247
id
- 7010805
+ 7011801
function
- 3400056
+ 3400306
index
@@ -13574,7 +13771,7 @@
1
2
- 7010805
+ 7011801
@@ -13590,7 +13787,7 @@
1
2
- 7010805
+ 7011801
@@ -13606,7 +13803,7 @@
1
2
- 6970359
+ 6971355
2
@@ -13632,7 +13829,7 @@
2
3
- 924652
+ 924776
3
@@ -13647,7 +13844,7 @@
5
65
- 145853
+ 145978
@@ -13668,7 +13865,7 @@
2
3
- 924652
+ 924776
3
@@ -13683,7 +13880,7 @@
5
65
- 145853
+ 145978
@@ -13704,7 +13901,7 @@
2
3
- 1029188
+ 1029313
3
@@ -13714,7 +13911,7 @@
4
11
- 154813
+ 154938
@@ -13748,13 +13945,13 @@
622
- 321
- 15503
+ 322
+ 15505
622
- 27321
- 27322
+ 27323
+ 27324
124
@@ -13789,13 +13986,13 @@
622
- 321
- 15503
+ 322
+ 15505
622
- 27321
- 27322
+ 27323
+ 27324
124
@@ -13853,7 +14050,7 @@
1
2
- 735614
+ 735615
2
@@ -13945,15 +14142,15 @@
overrides
- 159153
+ 159143
new
- 150383
+ 150374
old
- 17799
+ 17798
@@ -13967,12 +14164,12 @@
1
2
- 141620
+ 141612
2
4
- 8762
+ 8761
@@ -13988,7 +14185,7 @@
1
2
- 9685
+ 9684
2
@@ -14023,19 +14220,19 @@
membervariables
- 1502979
+ 1505217
id
- 1500528
+ 1502766
type_id
- 457641
+ 457991
name
- 642756
+ 644237
@@ -14049,7 +14246,7 @@
1
2
- 1498186
+ 1500425
2
@@ -14070,7 +14267,7 @@
1
2
- 1500528
+ 1502766
@@ -14086,22 +14283,22 @@
1
2
- 339459
+ 339817
2
3
- 72597
+ 72592
3
10
- 35454
+ 35397
10
4445
- 10129
+ 10183
@@ -14117,17 +14314,17 @@
1
2
- 357050
+ 357407
2
3
- 64754
+ 64750
3
57
- 34365
+ 34362
60
@@ -14148,22 +14345,22 @@
1
2
- 422023
+ 423356
2
3
- 122484
+ 122584
3
5
- 58056
+ 58106
5
664
- 40192
+ 40189
@@ -14179,17 +14376,17 @@
1
2
- 525010
+ 526390
2
3
- 73196
+ 73300
3
668
- 44549
+ 44546
@@ -14385,19 +14582,19 @@
localvariables
- 724674
+ 724688
id
- 724674
+ 724688
type_id
- 53296
+ 53301
name
- 101406
+ 101408
@@ -14411,7 +14608,7 @@
1
2
- 724674
+ 724688
@@ -14427,7 +14624,7 @@
1
2
- 724674
+ 724688
@@ -14443,7 +14640,7 @@
1
2
- 28788
+ 28793
2
@@ -14489,12 +14686,12 @@
1
2
- 38247
+ 38252
2
3
- 6703
+ 6704
3
@@ -14520,7 +14717,7 @@
1
2
- 62400
+ 62401
2
@@ -14561,12 +14758,12 @@
1
2
- 84396
+ 84398
2
3
- 8392
+ 8393
3
@@ -14654,15 +14851,15 @@
orphaned_variables
- 44034
+ 44035
var
- 44034
+ 44035
function
- 40785
+ 40786
@@ -14676,7 +14873,7 @@
1
2
- 44034
+ 44035
@@ -14707,19 +14904,19 @@
enumconstants
- 347955
+ 348040
id
- 347955
+ 348040
parent
- 41554
+ 41605
index
- 13942
+ 13941
type_id
@@ -14727,11 +14924,11 @@
name
- 347574
+ 347659
location
- 320561
+ 320648
@@ -14745,7 +14942,7 @@
1
2
- 347955
+ 348040
@@ -14761,7 +14958,7 @@
1
2
- 347955
+ 348040
@@ -14777,7 +14974,7 @@
1
2
- 347955
+ 348040
@@ -14793,7 +14990,7 @@
1
2
- 347955
+ 348040
@@ -14809,7 +15006,7 @@
1
2
- 347955
+ 348040
@@ -14830,7 +15027,7 @@
2
3
- 5772
+ 5826
3
@@ -14840,7 +15037,7 @@
4
5
- 5555
+ 5554
5
@@ -14865,7 +15062,7 @@
10
15
- 3431
+ 3430
15
@@ -14875,7 +15072,7 @@
33
257
- 1307
+ 1306
@@ -14896,7 +15093,7 @@
2
3
- 5772
+ 5826
3
@@ -14906,7 +15103,7 @@
4
5
- 5555
+ 5554
5
@@ -14931,7 +15128,7 @@
10
15
- 3431
+ 3430
15
@@ -14941,7 +15138,7 @@
33
257
- 1307
+ 1306
@@ -14957,7 +15154,7 @@
1
2
- 41554
+ 41605
@@ -14978,7 +15175,7 @@
2
3
- 5772
+ 5826
3
@@ -14988,7 +15185,7 @@
4
5
- 5555
+ 5554
5
@@ -15013,7 +15210,7 @@
10
15
- 3431
+ 3430
15
@@ -15023,7 +15220,7 @@
33
257
- 1307
+ 1306
@@ -15039,17 +15236,17 @@
1
2
- 2124
+ 2123
2
3
- 5990
+ 6044
3
4
- 8768
+ 8767
4
@@ -15144,7 +15341,7 @@
64
- 764
+ 765
980
@@ -15200,7 +15397,7 @@
64
- 764
+ 765
980
@@ -15217,7 +15414,7 @@
1
2
- 13942
+ 13941
@@ -15272,7 +15469,7 @@
64
- 761
+ 762
980
@@ -15328,7 +15525,7 @@
64
- 764
+ 765
980
@@ -15343,8 +15540,8 @@
12
- 6389
- 6390
+ 6391
+ 6392
54
@@ -15359,8 +15556,8 @@
12
- 763
- 764
+ 764
+ 765
54
@@ -15391,8 +15588,8 @@
12
- 6382
- 6383
+ 6384
+ 6385
54
@@ -15407,8 +15604,8 @@
12
- 5886
- 5887
+ 5888
+ 5889
54
@@ -15425,7 +15622,7 @@
1
2
- 347193
+ 347278
2
@@ -15446,7 +15643,7 @@
1
2
- 347193
+ 347278
2
@@ -15467,7 +15664,7 @@
1
2
- 347574
+ 347659
@@ -15483,7 +15680,7 @@
1
2
- 347574
+ 347659
@@ -15499,7 +15696,7 @@
1
2
- 347193
+ 347278
2
@@ -15520,7 +15717,7 @@
1
2
- 319526
+ 319613
2
@@ -15541,7 +15738,7 @@
1
2
- 320561
+ 320648
@@ -15557,7 +15754,7 @@
1
2
- 319526
+ 319613
2
@@ -15578,7 +15775,7 @@
1
2
- 320561
+ 320648
@@ -15594,7 +15791,7 @@
1
2
- 319526
+ 319613
2
@@ -16301,11 +16498,11 @@
derivedtypes
- 3023724
+ 3023725
id
- 3023724
+ 3023725
name
@@ -16317,7 +16514,7 @@
type_id
- 1942142
+ 1942143
@@ -16331,7 +16528,7 @@
1
2
- 3023724
+ 3023725
@@ -16347,7 +16544,7 @@
1
2
- 3023724
+ 3023725
@@ -16363,7 +16560,7 @@
1
2
- 3023724
+ 3023725
@@ -16642,7 +16839,7 @@
3
4
- 123203
+ 123204
4
@@ -16657,11 +16854,11 @@
pointerishsize
- 2242063
+ 2242064
id
- 2242063
+ 2242064
size
@@ -16683,7 +16880,7 @@
1
2
- 2242063
+ 2242064
@@ -16699,7 +16896,7 @@
1
2
- 2242063
+ 2242064
@@ -17222,15 +17419,15 @@
typedefbase
- 1755899
+ 1755750
id
- 1755899
+ 1755750
type_id
- 834290
+ 834219
@@ -17244,7 +17441,7 @@
1
2
- 1755899
+ 1755750
@@ -17260,22 +17457,22 @@
1
2
- 659390
+ 659334
2
3
- 80764
+ 80757
3
6
- 63921
+ 63915
6
4525
- 30214
+ 30211
@@ -17749,7 +17946,7 @@
base_type
- 5234
+ 5233
@@ -18049,15 +18246,15 @@
usertypes
- 4137871
+ 4137521
id
- 4137871
+ 4137521
name
- 915412
+ 915335
kind
@@ -18075,7 +18272,7 @@
1
2
- 4137871
+ 4137521
@@ -18091,7 +18288,7 @@
1
2
- 4137871
+ 4137521
@@ -18107,22 +18304,22 @@
1
2
- 652110
+ 652055
2
3
- 158098
+ 158085
3
8
- 70349
+ 70343
8
32667
- 34853
+ 34850
@@ -18138,12 +18335,12 @@
1
2
- 863873
+ 863800
2
10
- 51538
+ 51534
@@ -18295,11 +18492,11 @@
usertypesize
- 1359715
+ 1359600
id
- 1359715
+ 1359600
size
@@ -18321,7 +18518,7 @@
1
2
- 1359715
+ 1359600
@@ -18337,7 +18534,7 @@
1
2
- 1359715
+ 1359600
@@ -18542,15 +18739,15 @@
usertype_uuid
- 47795
+ 47930
id
- 47795
+ 47930
uuid
- 47252
+ 47387
@@ -18564,7 +18761,7 @@
1
2
- 47795
+ 47930
@@ -18580,7 +18777,7 @@
1
2
- 46710
+ 46845
2
@@ -18595,11 +18792,11 @@
usertype_alias_kind
- 1755899
+ 1755750
id
- 1755899
+ 1755750
alias_kind
@@ -18617,7 +18814,7 @@
1
2
- 1755899
+ 1755750
@@ -18648,18 +18845,18 @@
nontype_template_parameters
- 761282
+ 761293
id
- 761282
+ 761293
type_template_type_constraint
- 27071
+ 27070
id
@@ -18667,7 +18864,7 @@
constraint
- 25934
+ 25933
@@ -18717,7 +18914,7 @@
1
2
- 24797
+ 24796
2
@@ -18732,15 +18929,15 @@
mangled_name
- 7910194
+ 7910444
id
- 7910194
+ 7910444
mangled_name
- 6349610
+ 6349611
is_complete
@@ -18758,7 +18955,7 @@
1
2
- 7910194
+ 7910444
@@ -18774,7 +18971,7 @@
1
2
- 7910194
+ 7910444
@@ -18790,12 +18987,12 @@
1
2
- 6016461
+ 6016213
2
1120
- 333148
+ 333397
@@ -18811,7 +19008,7 @@
1
2
- 6349610
+ 6349611
@@ -18830,8 +19027,8 @@
124
- 63556
- 63557
+ 63558
+ 63559
124
@@ -18863,59 +19060,59 @@
is_pod_class
- 590965
+ 590973
id
- 590965
+ 590973
is_standard_layout_class
- 1120631
+ 1120536
id
- 1120631
+ 1120536
is_complete
- 1341620
+ 1341507
id
- 1341620
+ 1341507
is_class_template
- 231204
+ 231184
id
- 231204
+ 231184
class_instantiation
- 1122283
+ 1122188
to
- 1119253
+ 1119158
from
- 71527
+ 71521
@@ -18929,12 +19126,12 @@
1
2
- 1117128
+ 1117033
2
8
- 2125
+ 2124
@@ -18950,12 +19147,12 @@
1
2
- 20388
+ 20386
2
3
- 12834
+ 12833
3
@@ -18980,12 +19177,12 @@
10
17
- 5891
+ 5890
17
51
- 5365
+ 5364
51
@@ -19000,11 +19197,11 @@
class_template_argument
- 2887609
+ 2887364
type_id
- 1362314
+ 1362199
index
@@ -19012,7 +19209,7 @@
arg_type
- 818825
+ 818756
@@ -19026,27 +19223,27 @@
1
2
- 577774
+ 577725
2
3
- 408671
+ 408636
3
4
- 249962
+ 249940
4
7
- 102688
+ 102679
7
113
- 23218
+ 23216
@@ -19062,22 +19259,22 @@
1
2
- 606210
+ 606159
2
3
- 422610
+ 422574
3
4
- 250793
+ 250771
4
113
- 82699
+ 82692
@@ -19185,22 +19382,22 @@
1
2
- 511601
+ 511558
2
3
- 166904
+ 166890
3
5
- 74925
+ 74919
5
46
- 61417
+ 61412
46
@@ -19221,17 +19418,17 @@
1
2
- 720934
+ 720873
2
3
- 79596
+ 79589
3
22
- 18294
+ 18293
@@ -19241,11 +19438,11 @@
class_template_argument_value
- 506788
+ 506795
type_id
- 204502
+ 204505
index
@@ -19253,7 +19450,7 @@
arg_value
- 506652
+ 506660
@@ -19267,12 +19464,12 @@
1
2
- 154815
+ 154817
2
3
- 43086
+ 43087
3
@@ -19293,7 +19490,7 @@
1
2
- 146996
+ 146998
2
@@ -19436,7 +19633,7 @@
1
2
- 506517
+ 506524
2
@@ -19457,7 +19654,7 @@
1
2
- 506652
+ 506660
@@ -19467,15 +19664,15 @@
is_proxy_class_for
- 48246
+ 48241
id
- 48246
+ 48241
templ_param_id
- 45584
+ 45580
@@ -19489,7 +19686,7 @@
1
2
- 48246
+ 48241
@@ -19505,7 +19702,7 @@
1
2
- 44869
+ 44865
2
@@ -19520,19 +19717,19 @@
type_mentions
- 5911109
+ 5913261
id
- 5911109
+ 5913261
type_id
- 277863
+ 278007
location
- 5854796
+ 5856951
kind
@@ -19550,7 +19747,7 @@
1
2
- 5911109
+ 5913261
@@ -19566,7 +19763,7 @@
1
2
- 5911109
+ 5913261
@@ -19582,7 +19779,7 @@
1
2
- 5911109
+ 5913261
@@ -19598,42 +19795,42 @@
1
2
- 137297
+ 137451
2
3
- 31206
+ 31204
3
4
- 11654
+ 11653
4
5
- 14976
+ 14975
5
7
- 19932
+ 19931
7
12
- 21839
+ 21783
12
28
- 21022
+ 21020
28
8941
- 19932
+ 19986
@@ -19649,42 +19846,42 @@
1
2
- 137297
+ 137451
2
3
- 31206
+ 31204
3
4
- 11654
+ 11653
4
5
- 14976
+ 14975
5
7
- 19932
+ 19931
7
12
- 21839
+ 21783
12
28
- 21022
+ 21020
28
8941
- 19932
+ 19986
@@ -19700,7 +19897,7 @@
1
2
- 277863
+ 278007
@@ -19716,12 +19913,12 @@
1
2
- 5809102
+ 5811261
2
4
- 45693
+ 45690
@@ -19737,12 +19934,12 @@
1
2
- 5809102
+ 5811261
2
4
- 45693
+ 45690
@@ -19758,7 +19955,7 @@
1
2
- 5854796
+ 5856951
@@ -19772,8 +19969,8 @@
12
- 108537
- 108538
+ 108584
+ 108585
54
@@ -19788,8 +19985,8 @@
12
- 5102
- 5103
+ 5105
+ 5106
54
@@ -19804,8 +20001,8 @@
12
- 107503
- 107504
+ 107550
+ 107551
54
@@ -19827,15 +20024,15 @@
function_instantiation
- 967578
+ 967592
to
- 967578
+ 967592
from
- 181520
+ 181523
@@ -19849,7 +20046,7 @@
1
2
- 967578
+ 967592
@@ -19865,12 +20062,12 @@
1
2
- 109832
+ 109834
2
3
- 42545
+ 42546
3
@@ -19895,11 +20092,11 @@
function_template_argument
- 2468684
+ 2468721
function_id
- 1443870
+ 1443892
index
@@ -19907,7 +20104,7 @@
arg_type
- 296057
+ 296062
@@ -19921,22 +20118,22 @@
1
2
- 777934
+ 777946
2
3
- 410494
+ 410500
3
4
- 170689
+ 170691
4
15
- 84752
+ 84753
@@ -19952,22 +20149,22 @@
1
2
- 796956
+ 796968
2
3
- 408598
+ 408604
3
4
- 168523
+ 168525
4
9
- 69792
+ 69793
@@ -20105,7 +20302,7 @@
1
2
- 173634
+ 173636
2
@@ -20130,7 +20327,7 @@
11
76
- 23218
+ 23219
79
@@ -20151,12 +20348,12 @@
1
2
- 255137
+ 255140
2
3
- 31917
+ 31918
3
@@ -20171,11 +20368,11 @@
function_template_argument_value
- 449824
+ 449830
function_id
- 195499
+ 195502
index
@@ -20183,7 +20380,7 @@
arg_value
- 447150
+ 447156
@@ -20197,7 +20394,7 @@
1
2
- 150415
+ 150417
2
@@ -20223,7 +20420,7 @@
1
2
- 143544
+ 143546
2
@@ -20376,7 +20573,7 @@
1
2
- 444476
+ 444482
2
@@ -20397,7 +20594,7 @@
1
2
- 447150
+ 447156
@@ -20976,11 +21173,11 @@
template_template_argument
- 9636
+ 9635
type_id
- 6091
+ 6090
index
@@ -20988,7 +21185,7 @@
arg_type
- 9047
+ 9046
@@ -21002,7 +21199,7 @@
1
2
- 4997
+ 4996
2
@@ -21033,7 +21230,7 @@
1
2
- 5018
+ 5017
2
@@ -21207,7 +21404,7 @@
1
2
- 9026
+ 9025
2
@@ -21454,11 +21651,11 @@
concept_instantiation
- 90159
+ 90157
to
- 90159
+ 90157
from
@@ -21476,7 +21673,7 @@
1
2
- 90159
+ 90157
@@ -21572,22 +21769,22 @@
is_type_constraint
- 36788
+ 36787
concept_id
- 36788
+ 36787
concept_template_argument
- 112704
+ 112701
concept_id
- 76151
+ 76149
index
@@ -21595,7 +21792,7 @@
arg_type
- 21365
+ 21364
@@ -21609,12 +21806,12 @@
1
2
- 46334
+ 46333
2
3
- 24604
+ 24603
3
@@ -21635,12 +21832,12 @@
1
2
- 49938
+ 49937
2
3
- 22309
+ 22308
3
@@ -21794,7 +21991,7 @@
1
2
- 17976
+ 17975
2
@@ -21945,15 +22142,15 @@
routinetypes
- 600577
+ 600586
id
- 600577
+ 600586
return_type
- 282011
+ 282015
@@ -21967,7 +22164,7 @@
1
2
- 600577
+ 600586
@@ -21983,12 +22180,12 @@
1
2
- 232561
+ 232564
2
3
- 34997
+ 34998
3
@@ -22003,11 +22200,11 @@
routinetypeargs
- 1178605
+ 1178524
routine
- 416032
+ 416004
index
@@ -22015,7 +22212,7 @@
type_id
- 112082
+ 112074
@@ -22029,32 +22226,32 @@
1
2
- 82945
+ 82939
2
3
- 126078
+ 126070
3
4
- 107888
+ 107881
4
5
- 49287
+ 49284
5
7
- 33167
+ 33164
7
19
- 16665
+ 16664
@@ -22070,27 +22267,27 @@
1
2
- 88935
+ 88929
2
3
- 138713
+ 138704
3
4
- 114641
+ 114633
4
5
- 40737
+ 40734
5
10
- 32894
+ 32892
10
@@ -22288,32 +22485,32 @@
1
2
- 33276
+ 33273
2
3
- 15576
+ 15574
3
4
- 13288
+ 13287
4
5
- 9803
+ 9802
5
6
- 6372
+ 6371
6
8
- 9476
+ 9475
8
@@ -22323,7 +22520,7 @@
13
26
- 8659
+ 8658
26
@@ -22344,22 +22541,22 @@
1
2
- 79405
+ 79399
2
3
- 17536
+ 17535
3
5
- 9476
+ 9475
5
17
- 5664
+ 5663
@@ -22369,11 +22566,11 @@
ptrtomembers
- 9678
+ 9677
id
- 9678
+ 9677
type_id
@@ -22395,7 +22592,7 @@
1
2
- 9678
+ 9677
@@ -22411,7 +22608,7 @@
1
2
- 9678
+ 9677
@@ -22427,7 +22624,7 @@
1
2
- 7732
+ 7731
2
@@ -22448,7 +22645,7 @@
1
2
- 7732
+ 7731
2
@@ -22686,11 +22883,11 @@
funspecifiers
- 9693167
+ 9694786
func_id
- 4002387
+ 4002636
spec_id
@@ -22708,17 +22905,17 @@
1
2
- 1527356
+ 1526111
2
3
- 504514
+ 506132
3
4
- 1034166
+ 1034042
4
@@ -22822,8 +23019,8 @@
124
- 15135
- 15136
+ 15137
+ 15138
124
@@ -22832,8 +23029,8 @@
124
- 22767
- 22768
+ 22778
+ 22779
124
@@ -24086,11 +24283,11 @@
attribute_arg_value
- 16584
+ 16585
arg
- 16584
+ 16585
value
@@ -24108,7 +24305,7 @@
1
2
- 16584
+ 16585
@@ -24242,15 +24439,15 @@
attribute_arg_constant
- 71632
+ 71626
arg
- 71632
+ 71626
constant
- 71632
+ 71626
@@ -24264,7 +24461,7 @@
1
2
- 71632
+ 71626
@@ -24280,7 +24477,7 @@
1
2
- 71632
+ 71626
@@ -24701,11 +24898,11 @@
unspecifiedtype
- 7228465
+ 7228466
type_id
- 7228465
+ 7228466
unspecified_type_id
@@ -24723,7 +24920,7 @@
1
2
- 7228465
+ 7228466
@@ -24764,7 +24961,7 @@
member
- 4182091
+ 4182340
parent
@@ -24776,7 +24973,7 @@
child
- 4177486
+ 4177735
@@ -24825,7 +25022,7 @@
9
13
- 41067
+ 41068
13
@@ -25054,7 +25251,7 @@
1
2
- 4177486
+ 4177735
@@ -25070,7 +25267,7 @@
1
2
- 4172881
+ 4173131
2
@@ -25085,15 +25282,15 @@
enclosingfunction
- 114986
+ 114977
child
- 114986
+ 114977
parent
- 69097
+ 69091
@@ -25107,7 +25304,7 @@
1
2
- 114986
+ 114977
@@ -25123,12 +25320,12 @@
1
2
- 37473
+ 37470
2
3
- 24480
+ 24478
3
@@ -25148,15 +25345,15 @@
derivations
- 473787
+ 473794
derivation
- 473787
+ 473794
sub
- 452193
+ 452200
index
@@ -25164,11 +25361,11 @@
super
- 234016
+ 234020
location
- 35166
+ 35167
@@ -25182,7 +25379,7 @@
1
2
- 473787
+ 473794
@@ -25198,7 +25395,7 @@
1
2
- 473787
+ 473794
@@ -25214,7 +25411,7 @@
1
2
- 473787
+ 473794
@@ -25230,7 +25427,7 @@
1
2
- 473787
+ 473794
@@ -25246,7 +25443,7 @@
1
2
- 435777
+ 435784
2
@@ -25267,7 +25464,7 @@
1
2
- 435777
+ 435784
2
@@ -25288,7 +25485,7 @@
1
2
- 435777
+ 435784
2
@@ -25309,7 +25506,7 @@
1
2
- 435777
+ 435784
2
@@ -25469,12 +25666,12 @@
1
2
- 224268
+ 224272
2
1655
- 9747
+ 9748
@@ -25490,12 +25687,12 @@
1
2
- 224268
+ 224272
2
1655
- 9747
+ 9748
@@ -25511,7 +25708,7 @@
1
2
- 233576
+ 233580
2
@@ -25532,12 +25729,12 @@
1
2
- 228702
+ 228706
2
81
- 5313
+ 5314
@@ -25553,7 +25750,7 @@
1
2
- 26332
+ 26333
2
@@ -25589,7 +25786,7 @@
1
2
- 26332
+ 26333
2
@@ -25625,7 +25822,7 @@
1
2
- 35166
+ 35167
@@ -25641,7 +25838,7 @@
1
2
- 28532
+ 28533
2
@@ -25666,11 +25863,11 @@
derspecifiers
- 475547
+ 475554
der_id
- 473347
+ 473354
spec_id
@@ -25688,7 +25885,7 @@
1
2
- 471147
+ 471154
2
@@ -25734,11 +25931,11 @@
direct_base_offsets
- 447048
+ 447055
der_id
- 447048
+ 447055
offset
@@ -25756,7 +25953,7 @@
1
2
- 447048
+ 447055
@@ -25953,23 +26150,23 @@
frienddecls
- 767814
+ 767534
id
- 767814
+ 767534
type_id
- 54357
+ 54340
decl_id
- 100728
+ 100695
location
- 6058
+ 6056
@@ -25983,7 +26180,7 @@
1
2
- 767814
+ 767534
@@ -25999,7 +26196,7 @@
1
2
- 767814
+ 767534
@@ -26015,7 +26212,7 @@
1
2
- 767814
+ 767534
@@ -26031,37 +26228,37 @@
1
2
- 5584
+ 5582
2
3
- 24978
+ 25004
3
8
- 4806
+ 4770
8
17
- 4738
+ 4737
17
27
- 4467
+ 4466
27
45
- 4298
+ 4297
45
81
- 4738
+ 4737
102
@@ -26082,37 +26279,37 @@
1
2
- 5584
+ 5582
2
3
- 24978
+ 25004
3
8
- 4806
+ 4770
8
17
- 4738
+ 4737
17
27
- 4467
+ 4466
27
45
- 4298
+ 4297
45
81
- 4738
+ 4737
102
@@ -26133,7 +26330,7 @@
1
2
- 53004
+ 52987
2
@@ -26154,27 +26351,27 @@
1
2
- 67490
+ 67502
2
3
- 8157
+ 8120
3
9
- 9206
+ 9203
9
24
- 7615
+ 7613
24
136
- 7649
+ 7646
136
@@ -26195,27 +26392,27 @@
1
2
- 67490
+ 67502
2
3
- 8157
+ 8120
3
9
- 9206
+ 9203
9
24
- 7615
+ 7613
24
136
- 7649
+ 7646
136
@@ -26236,7 +26433,7 @@
1
2
- 99509
+ 99477
2
@@ -26257,11 +26454,11 @@
1
2
- 5686
+ 5684
2
- 22496
+ 22495
372
@@ -26278,7 +26475,7 @@
1
2
- 5923
+ 5921
2
@@ -26299,7 +26496,7 @@
1
2
- 5720
+ 5718
2
@@ -26314,19 +26511,19 @@
comments
- 11208576
+ 11208578
id
- 11208576
+ 11208578
contents
- 4294965
+ 4294966
location
- 11208576
+ 11208578
@@ -26340,7 +26537,7 @@
1
2
- 11208576
+ 11208578
@@ -26356,7 +26553,7 @@
1
2
- 11208576
+ 11208578
@@ -26424,7 +26621,7 @@
1
2
- 11208576
+ 11208578
@@ -26440,7 +26637,7 @@
1
2
- 11208576
+ 11208578
@@ -26450,7 +26647,7 @@
commentbinding
- 3905317
+ 3905318
id
@@ -26458,7 +26655,7 @@
element
- 3740174
+ 3740175
@@ -26472,7 +26669,7 @@
1
2
- 3281208
+ 3281209
2
@@ -26508,15 +26705,15 @@
exprconv
- 9634074
+ 9634075
converted
- 9633969
+ 9633970
conversion
- 9634074
+ 9634075
@@ -26530,7 +26727,7 @@
1
2
- 9633863
+ 9633864
2
@@ -26551,7 +26748,7 @@
1
2
- 9634074
+ 9634075
@@ -26561,22 +26758,22 @@
compgenerated
- 9923438
+ 9923218
id
- 9923438
+ 9923218
synthetic_destructor_call
- 1666623
+ 1666585
element
- 1241183
+ 1241154
i
@@ -26584,7 +26781,7 @@
destructor_call
- 1666623
+ 1666585
@@ -26598,12 +26795,12 @@
1
2
- 826168
+ 826149
2
3
- 408236
+ 408226
3
@@ -26624,12 +26821,12 @@
1
2
- 826168
+ 826149
2
3
- 408236
+ 408226
3
@@ -26782,7 +26979,7 @@
1
2
- 1666623
+ 1666585
@@ -26798,7 +26995,7 @@
1
2
- 1666623
+ 1666585
@@ -26808,15 +27005,15 @@
namespaces
- 8616
+ 8615
id
- 8616
+ 8615
name
- 4555
+ 4554
@@ -26830,7 +27027,7 @@
1
2
- 8616
+ 8615
@@ -26846,12 +27043,12 @@
1
2
- 3724
+ 3723
2
3
- 526
+ 525
3
@@ -26985,11 +27182,11 @@
exprparents
- 19456296
+ 19456298
expr_id
- 19456296
+ 19456298
child_index
@@ -26997,7 +27194,7 @@
parent_id
- 12941380
+ 12941382
@@ -27011,7 +27208,7 @@
1
2
- 19456296
+ 19456298
@@ -27027,7 +27224,7 @@
1
2
- 19456296
+ 19456298
@@ -27145,7 +27342,7 @@
1
2
- 7395565
+ 7395566
2
@@ -27171,7 +27368,7 @@
1
2
- 7395565
+ 7395566
2
@@ -27191,22 +27388,22 @@
expr_isload
- 6898025
+ 6897613
expr_id
- 6898025
+ 6897613
conversionkinds
- 6051177
+ 6051176
expr_id
- 6051177
+ 6051176
kind
@@ -27224,7 +27421,7 @@
1
2
- 6051177
+ 6051176
@@ -27268,8 +27465,8 @@
1
- 5832067
- 5832068
+ 5832066
+ 5832067
1
@@ -27280,11 +27477,11 @@
iscall
- 5790730
+ 5790597
caller
- 5790730
+ 5790597
kind
@@ -27302,7 +27499,7 @@
1
2
- 5790730
+ 5790597
@@ -27464,23 +27661,23 @@
namequalifiers
- 3042541
+ 3042471
id
- 3042541
+ 3042471
qualifiableelement
- 3042541
+ 3042471
qualifyingelement
- 47728
+ 47727
location
- 554597
+ 554584
@@ -27494,7 +27691,7 @@
1
2
- 3042541
+ 3042471
@@ -27510,7 +27707,7 @@
1
2
- 3042541
+ 3042471
@@ -27526,7 +27723,7 @@
1
2
- 3042541
+ 3042471
@@ -27542,7 +27739,7 @@
1
2
- 3042541
+ 3042471
@@ -27558,7 +27755,7 @@
1
2
- 3042541
+ 3042471
@@ -27574,7 +27771,7 @@
1
2
- 3042541
+ 3042471
@@ -27590,7 +27787,7 @@
1
2
- 31447
+ 31446
2
@@ -27600,7 +27797,7 @@
3
5
- 4140
+ 4139
5
@@ -27626,7 +27823,7 @@
1
2
- 31447
+ 31446
2
@@ -27636,7 +27833,7 @@
3
5
- 4140
+ 4139
5
@@ -27662,7 +27859,7 @@
1
2
- 34665
+ 34664
2
@@ -27693,22 +27890,22 @@
1
2
- 79412
+ 79410
2
6
- 41014
+ 41013
6
7
- 397789
+ 397780
7
192
- 36381
+ 36380
@@ -27724,22 +27921,22 @@
1
2
- 79412
+ 79410
2
6
- 41014
+ 41013
6
7
- 397789
+ 397780
7
192
- 36381
+ 36380
@@ -27755,22 +27952,22 @@
1
2
- 114956
+ 114953
2
4
- 13321
+ 13320
4
5
- 414049
+ 414040
5
33
- 12270
+ 12269
@@ -27780,15 +27977,15 @@
varbind
- 8255502
+ 8255503
expr
- 8255502
+ 8255503
var
- 1050486
+ 1050487
@@ -27802,7 +27999,7 @@
1
2
- 8255502
+ 8255503
@@ -27873,15 +28070,15 @@
funbind
- 5806003
+ 5805870
expr
- 5803536
+ 5803403
fun
- 275282
+ 275275
@@ -27895,7 +28092,7 @@
1
2
- 5801069
+ 5800937
2
@@ -27916,12 +28113,12 @@
1
2
- 181068
+ 181064
2
3
- 38311
+ 38310
3
@@ -27931,7 +28128,7 @@
4
8
- 22931
+ 22930
8
@@ -27946,11 +28143,11 @@
expr_allocator
- 44948
+ 44949
expr
- 44948
+ 44949
func
@@ -27972,7 +28169,7 @@
1
2
- 44948
+ 44949
@@ -27988,7 +28185,7 @@
1
2
- 44948
+ 44949
@@ -28072,11 +28269,11 @@
expr_deallocator
- 53477
+ 53478
expr
- 53477
+ 53478
func
@@ -28098,7 +28295,7 @@
1
2
- 53477
+ 53478
@@ -28114,7 +28311,7 @@
1
2
- 53477
+ 53478
@@ -28363,11 +28560,11 @@
values
- 13541563
+ 13541565
id
- 13541563
+ 13541565
str
@@ -28385,7 +28582,7 @@
1
2
- 13541563
+ 13541565
@@ -28431,11 +28628,11 @@
valuetext
- 6637568
+ 6637657
id
- 6637568
+ 6637657
text
@@ -28453,7 +28650,7 @@
1
2
- 6637568
+ 6637657
@@ -28483,7 +28680,7 @@
7
- 593723
+ 593719
27872
@@ -28494,15 +28691,15 @@
valuebind
- 13649714
+ 13649715
val
- 13541563
+ 13541565
expr
- 13649714
+ 13649715
@@ -28516,7 +28713,7 @@
1
2
- 13451406
+ 13451407
2
@@ -28537,7 +28734,7 @@
1
2
- 13649714
+ 13649715
@@ -28547,15 +28744,15 @@
fieldoffsets
- 1500528
+ 1502766
id
- 1500528
+ 1502766
byteoffset
- 31369
+ 31367
bitoffset
@@ -28573,7 +28770,7 @@
1
2
- 1500528
+ 1502766
@@ -28589,7 +28786,7 @@
1
2
- 1500528
+ 1502766
@@ -28605,7 +28802,7 @@
1
2
- 17700
+ 17698
2
@@ -28620,22 +28817,22 @@
5
12
- 2614
+ 2613
12
35
- 2450
-
-
- 35
- 211
2396
- 250
- 5971
- 1089
+ 35
+ 200
+ 2396
+
+
+ 210
+ 5988
+ 1143
@@ -28651,7 +28848,7 @@
1
2
- 30335
+ 30333
2
@@ -28680,13 +28877,13 @@
54
- 45
- 46
+ 46
+ 47
54
- 46
- 47
+ 47
+ 48
54
@@ -28695,18 +28892,18 @@
54
- 65
- 66
+ 67
+ 68
54
- 82
- 83
+ 84
+ 85
54
- 27193
- 27194
+ 27230
+ 27231
54
@@ -28939,23 +29136,23 @@
initialisers
- 2244830
+ 2245206
init
- 2244830
+ 2245206
var
- 978850
+ 979091
expr
- 2244830
+ 2245206
location
- 515724
+ 515984
@@ -28969,7 +29166,7 @@
1
2
- 2244830
+ 2245206
@@ -28985,7 +29182,7 @@
1
2
- 2244830
+ 2245206
@@ -29001,7 +29198,7 @@
1
2
- 2244830
+ 2245206
@@ -29017,17 +29214,17 @@
1
2
- 868820
+ 869052
2
15
- 37292
+ 37306
16
25
- 72737
+ 72733
@@ -29043,17 +29240,17 @@
1
2
- 868820
+ 869052
2
15
- 37292
+ 37306
16
25
- 72737
+ 72733
@@ -29069,7 +29266,7 @@
1
2
- 978842
+ 979083
2
@@ -29090,7 +29287,7 @@
1
2
- 2244830
+ 2245206
@@ -29106,7 +29303,7 @@
1
2
- 2244830
+ 2245206
@@ -29122,7 +29319,7 @@
1
2
- 2244830
+ 2245206
@@ -29138,22 +29335,22 @@
1
2
- 414197
+ 414456
2
3
- 33502
+ 33500
3
13
- 41940
+ 41937
13
- 111925
- 26084
+ 111939
+ 26090
@@ -29169,17 +29366,17 @@
1
2
- 443423
+ 443688
2
3
- 34409
+ 34407
3
- 12247
- 37891
+ 12248
+ 37889
@@ -29195,22 +29392,22 @@
1
2
- 414197
+ 414456
2
3
- 33502
+ 33500
3
13
- 41940
+ 41937
13
- 111925
- 26084
+ 111939
+ 26090
@@ -29220,26 +29417,26 @@
braced_initialisers
- 67652
+ 67650
init
- 67652
+ 67650
expr_ancestor
- 1672586
+ 1672548
exp
- 1672586
+ 1672548
ancestor
- 837108
+ 837089
@@ -29253,7 +29450,7 @@
1
2
- 1672586
+ 1672548
@@ -29269,17 +29466,17 @@
1
2
- 17032
+ 17031
2
3
- 810037
+ 810018
3
19
- 10039
+ 10038
@@ -29289,11 +29486,11 @@
exprs
- 25213262
+ 25213265
id
- 25213262
+ 25213265
kind
@@ -29301,7 +29498,7 @@
location
- 10586811
+ 10586812
@@ -29315,7 +29512,7 @@
1
2
- 25213262
+ 25213265
@@ -29331,7 +29528,7 @@
1
2
- 25213262
+ 25213265
@@ -29509,7 +29706,7 @@
1
2
- 8904644
+ 8904645
2
@@ -29540,7 +29737,7 @@
1
2
- 9044063
+ 9044064
2
@@ -29560,15 +29757,15 @@
expr_reuse
- 844466
+ 844446
reuse
- 844466
+ 844446
original
- 844466
+ 844446
value_category
@@ -29586,7 +29783,7 @@
1
2
- 844466
+ 844446
@@ -29602,7 +29799,7 @@
1
2
- 844466
+ 844446
@@ -29618,7 +29815,7 @@
1
2
- 844466
+ 844446
@@ -29634,7 +29831,7 @@
1
2
- 844466
+ 844446
@@ -29686,11 +29883,11 @@
expr_types
- 25213262
+ 25213265
id
- 25213262
+ 25213265
typeid
@@ -29712,7 +29909,7 @@
1
2
- 25213262
+ 25213265
@@ -29728,7 +29925,7 @@
1
2
- 25213262
+ 25213265
@@ -29759,7 +29956,7 @@
4
5
- 14530
+ 14531
5
@@ -29881,7 +30078,7 @@
type_id
- 27212
+ 27213
@@ -29916,7 +30113,7 @@
2
3
- 14384
+ 14385
3
@@ -31341,15 +31538,15 @@
condition_decl_bind
- 407678
+ 407669
expr
- 407678
+ 407669
decl
- 407678
+ 407669
@@ -31363,7 +31560,7 @@
1
2
- 407678
+ 407669
@@ -31379,7 +31576,7 @@
1
2
- 407678
+ 407669
@@ -31389,11 +31586,11 @@
typeid_bind
- 47588
+ 47589
expr
- 47588
+ 47589
type_id
@@ -31411,7 +31608,7 @@
1
2
- 47588
+ 47589
@@ -31447,15 +31644,15 @@
uuidof_bind
- 26691
+ 26787
expr
- 26691
+ 26787
type_id
- 26440
+ 26536
@@ -31469,7 +31666,7 @@
1
2
- 26691
+ 26787
@@ -31485,7 +31682,7 @@
1
2
- 26229
+ 26325
2
@@ -31631,11 +31828,11 @@
lambdas
- 18998
+ 18997
expr
- 18998
+ 18997
default_capture
@@ -31661,7 +31858,7 @@
1
2
- 18998
+ 18997
@@ -31677,7 +31874,7 @@
1
2
- 18998
+ 18997
@@ -31693,7 +31890,7 @@
1
2
- 18998
+ 18997
@@ -31877,15 +32074,15 @@
lambda_capture
- 31866
+ 31864
id
- 31866
+ 31864
lambda
- 15443
+ 15442
index
@@ -31893,7 +32090,7 @@
field
- 31866
+ 31864
captured_by_reference
@@ -31905,7 +32102,7 @@
location
- 17888
+ 17887
@@ -31919,7 +32116,7 @@
1
2
- 31866
+ 31864
@@ -31935,7 +32132,7 @@
1
2
- 31866
+ 31864
@@ -31951,7 +32148,7 @@
1
2
- 31866
+ 31864
@@ -31967,7 +32164,7 @@
1
2
- 31866
+ 31864
@@ -31983,7 +32180,7 @@
1
2
- 31866
+ 31864
@@ -31999,7 +32196,7 @@
1
2
- 31866
+ 31864
@@ -32015,7 +32212,7 @@
1
2
- 8187
+ 8186
2
@@ -32025,7 +32222,7 @@
3
4
- 1652
+ 1651
4
@@ -32051,7 +32248,7 @@
1
2
- 8187
+ 8186
2
@@ -32061,7 +32258,7 @@
3
4
- 1652
+ 1651
4
@@ -32087,7 +32284,7 @@
1
2
- 8187
+ 8186
2
@@ -32097,7 +32294,7 @@
3
4
- 1652
+ 1651
4
@@ -32123,12 +32320,12 @@
1
2
- 14204
+ 14203
2
3
- 1239
+ 1238
@@ -32144,7 +32341,7 @@
1
2
- 15321
+ 15320
2
@@ -32165,7 +32362,7 @@
1
2
- 8778
+ 8777
2
@@ -32627,7 +32824,7 @@
1
2
- 31866
+ 31864
@@ -32643,7 +32840,7 @@
1
2
- 31866
+ 31864
@@ -32659,7 +32856,7 @@
1
2
- 31866
+ 31864
@@ -32675,7 +32872,7 @@
1
2
- 31866
+ 31864
@@ -32691,7 +32888,7 @@
1
2
- 31866
+ 31864
@@ -32707,7 +32904,7 @@
1
2
- 31866
+ 31864
@@ -32965,7 +33162,7 @@
1
2
- 15645
+ 15644
2
@@ -32991,7 +33188,7 @@
1
2
- 16220
+ 16219
2
@@ -33017,7 +33214,7 @@
1
2
- 17200
+ 17199
2
@@ -33038,7 +33235,7 @@
1
2
- 15645
+ 15644
2
@@ -33064,7 +33261,7 @@
1
2
- 17864
+ 17863
2
@@ -33085,7 +33282,7 @@
1
2
- 17888
+ 17887
@@ -33221,11 +33418,11 @@
stmts
- 6349665
+ 6349367
id
- 6349665
+ 6349367
kind
@@ -33233,7 +33430,7 @@
location
- 2676171
+ 2676092
@@ -33247,7 +33444,7 @@
1
2
- 6349665
+ 6349367
@@ -33263,7 +33460,7 @@
1
2
- 6349665
+ 6349367
@@ -33362,13 +33559,13 @@
8
- 119906
- 119907
+ 119911
+ 119912
8
- 200140
- 200141
+ 200145
+ 200146
8
@@ -33473,13 +33670,13 @@
8
- 49040
- 49041
+ 49045
+ 49046
8
- 86406
- 86407
+ 86411
+ 86412
8
@@ -33501,22 +33698,22 @@
1
2
- 2218098
+ 2218046
2
3
- 181666
+ 181655
3
10
- 201547
+ 201535
10
1789
- 74859
+ 74855
@@ -33532,12 +33729,12 @@
1
2
- 2593464
+ 2593391
2
10
- 82706
+ 82701
@@ -33750,15 +33947,15 @@
if_else
- 435779
+ 435769
if_stmt
- 435779
+ 435769
else_id
- 435779
+ 435769
@@ -33772,7 +33969,7 @@
1
2
- 435779
+ 435769
@@ -33788,7 +33985,7 @@
1
2
- 435779
+ 435769
@@ -34182,11 +34379,11 @@
switch_case
- 833612
+ 833592
switch_stmt
- 410617
+ 410607
index
@@ -34194,7 +34391,7 @@
case_id
- 833612
+ 833592
@@ -34213,7 +34410,7 @@
2
3
- 407742
+ 407733
3
@@ -34239,7 +34436,7 @@
2
3
- 407742
+ 407733
3
@@ -34402,7 +34599,7 @@
1
2
- 833612
+ 833592
@@ -34418,7 +34615,7 @@
1
2
- 833612
+ 833592
@@ -34428,15 +34625,15 @@
switch_body
- 410617
+ 410607
switch_stmt
- 410617
+ 410607
body_id
- 410617
+ 410607
@@ -34450,7 +34647,7 @@
1
2
- 410617
+ 410607
@@ -34466,7 +34663,7 @@
1
2
- 410617
+ 410607
@@ -34668,19 +34865,19 @@
stmtparents
- 5611103
+ 5610809
id
- 5611103
+ 5610809
index
- 15726
+ 15725
parent
- 2374344
+ 2374243
@@ -34694,7 +34891,7 @@
1
2
- 5611103
+ 5610809
@@ -34710,7 +34907,7 @@
1
2
- 5611103
+ 5610809
@@ -34770,7 +34967,7 @@
78
- 209703
+ 209708
898
@@ -34831,7 +35028,7 @@
78
- 209703
+ 209708
898
@@ -34848,32 +35045,32 @@
1
2
- 1355059
+ 1355019
2
3
- 515764
+ 515733
3
4
- 151047
+ 151038
4
6
- 155242
+ 155232
6
16
- 178313
+ 178303
16
1943
- 18917
+ 18916
@@ -34889,32 +35086,32 @@
1
2
- 1355059
+ 1355019
2
3
- 515764
+ 515733
3
4
- 151047
+ 151038
4
6
- 155242
+ 155232
6
16
- 178313
+ 178303
16
1943
- 18917
+ 18916
@@ -34924,22 +35121,22 @@
ishandler
- 43218
+ 43224
block
- 43218
+ 43224
stmt_decl_bind
- 723620
+ 723577
stmt
- 713084
+ 713042
num
@@ -34947,7 +35144,7 @@
decl
- 723620
+ 723577
@@ -34961,12 +35158,12 @@
1
2
- 705642
+ 705600
2
10
- 7442
+ 7441
@@ -34982,12 +35179,12 @@
1
2
- 705642
+ 705600
2
10
- 7442
+ 7441
@@ -35115,7 +35312,7 @@
1
2
- 723620
+ 723577
@@ -35131,7 +35328,7 @@
1
2
- 723620
+ 723577
@@ -35141,11 +35338,11 @@
stmt_decl_entry_bind
- 723620
+ 723577
stmt
- 713084
+ 713042
num
@@ -35153,7 +35350,7 @@
decl_entry
- 723620
+ 723577
@@ -35167,12 +35364,12 @@
1
2
- 705642
+ 705600
2
10
- 7442
+ 7441
@@ -35188,12 +35385,12 @@
1
2
- 705642
+ 705600
2
10
- 7442
+ 7441
@@ -35321,7 +35518,7 @@
1
2
- 723620
+ 723577
@@ -35337,7 +35534,7 @@
1
2
- 723620
+ 723577
@@ -35385,7 +35582,7 @@
1
2
- 1291401
+ 1291402
2
@@ -35586,11 +35783,11 @@
preprocdirects
- 5395214
+ 5395215
id
- 5395214
+ 5395215
kind
@@ -35598,7 +35795,7 @@
location
- 5392103
+ 5392104
@@ -35612,7 +35809,7 @@
1
2
- 5395214
+ 5395215
@@ -35628,7 +35825,7 @@
1
2
- 5395214
+ 5395215
@@ -35797,7 +35994,7 @@
1
2
- 5392103
+ 5392104
@@ -35887,11 +36084,11 @@
preproctext
- 4341758
+ 4341759
id
- 4341758
+ 4341759
head
@@ -35913,7 +36110,7 @@
1
2
- 4341758
+ 4341759
@@ -35929,7 +36126,7 @@
1
2
- 4341758
+ 4341759
@@ -35950,7 +36147,7 @@
2
798
- 198121
+ 198122
@@ -35987,7 +36184,7 @@
1
2
- 1531462
+ 1531463
2
@@ -36033,15 +36230,15 @@
includes
- 317365
+ 317338
id
- 317365
+ 317338
included
- 58461
+ 58456
@@ -36055,7 +36252,7 @@
1
2
- 317365
+ 317338
@@ -36071,17 +36268,17 @@
1
2
- 28930
+ 28928
2
3
- 9405
+ 9404
3
4
- 4934
+ 4933
4
@@ -36207,11 +36404,11 @@
link_parent
- 30224721
+ 30225171
element
- 3843710
+ 3843767
link_target
@@ -36229,17 +36426,17 @@
1
2
- 527062
+ 527070
2
9
- 26772
+ 26773
9
10
- 3289875
+ 3289924
diff --git a/cpp/ql/lib/upgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/in_trap_or_tag.ql b/cpp/ql/lib/upgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/in_trap_or_tag.ql
new file mode 100644
index 00000000000..331806e01fd
--- /dev/null
+++ b/cpp/ql/lib/upgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/in_trap_or_tag.ql
@@ -0,0 +1,11 @@
+class Element extends @element {
+ string toString() { none() }
+}
+
+class Trap extends @trap {
+ string toString() { none() }
+}
+
+from Element e, Trap trap
+where in_trap(e, trap)
+select e, trap
diff --git a/cpp/ql/lib/upgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/old.dbscheme b/cpp/ql/lib/upgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/old.dbscheme
new file mode 100644
index 00000000000..7e7c2f55670
--- /dev/null
+++ b/cpp/ql/lib/upgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/old.dbscheme
@@ -0,0 +1,2517 @@
+
+/*- Compilations -*/
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ /**
+ * An invocation of the compiler. Note that more than one file may
+ * be compiled per invocation. For example, this command compiles
+ * three source files:
+ *
+ * gcc -c f1.c f2.c f3.c
+ */
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | *path to extractor*
+ * 1 | `--mimic`
+ * 2 | `/usr/bin/gcc`
+ * 3 | `-c`
+ * 4 | f1.c
+ * 5 | f2.c
+ * 6 | f3.c
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The expanded arguments that were passed to the extractor for a
+ * compiler invocation. This is similar to `compilation_args`, but
+ * for a `@someFile` argument, it includes the arguments from that
+ * file, rather than just taking the argument literally.
+ */
+#keyset[id, num]
+compilation_expanded_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * Optionally, record the build mode for each compilation.
+ */
+compilation_build_mode(
+ unique int id : @compilation ref,
+ int mode : int ref
+);
+
+/*
+case @compilation_build_mode.mode of
+ 0 = @build_mode_none
+| 1 = @build_mode_manual
+| 2 = @build_mode_auto
+;
+*/
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.c
+ * 1 | f2.c
+ * 2 | f3.c
+ *
+ * Note that even if those files `#include` headers, those headers
+ * do not appear as rows.
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+/*- External data -*/
+
+/**
+ * External data, loaded from CSV files during snapshot creation. See
+ * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data)
+ * for more information.
+ */
+externalData(
+ int id : @externalDataElement,
+ string path : string ref,
+ int column: int ref,
+ string value : string ref
+);
+
+/*- Source location prefix -*/
+
+/**
+ * The source location of the snapshot.
+ */
+sourceLocationPrefix(string prefix : string ref);
+
+/*- Files and folders -*/
+
+/**
+ * The location of an element.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref
+);
+
+files(
+ unique int id: @file,
+ string name: string ref
+);
+
+folders(
+ unique int id: @folder,
+ string name: string ref
+);
+
+@container = @file | @folder
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref
+);
+
+/*- Lines of code -*/
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref
+);
+
+/*- Diagnostic messages -*/
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location_default ref
+);
+
+/*- C++ dbscheme -*/
+
+extractor_version(
+ string codeql_version: string ref,
+ string frontend_version: string ref
+)
+
+/**
+ * Gives the TRAP filename that `trap` is associated with.
+ * For debugging only.
+ */
+trap_filename(
+ int trap: @trap,
+ string filename: string ref
+);
+
+/**
+ * In `build-mode: none` overlay mode, indicates that `source_file`
+ * (`/path/to/foo.c`) uses the TRAP file `trap_file`; i.e. it is the
+ * TRAP file corresponding to `foo.c`, something it transitively
+ * includes, or a template instantiation it transitively uses.
+ */
+source_file_uses_trap(
+ string source_file: string ref,
+ int trap_file: @trap ref
+);
+
+/**
+ * Holds if there is a definition of `element` in TRAP file `trap_file`.
+ */
+in_trap(
+ int element: @element ref,
+ int trap_file: @trap ref
+);
+
+pch_uses(
+ int pch: @pch ref,
+ int compilation: @compilation ref,
+ int id: @file ref
+)
+
+#keyset[pch, compilation]
+pch_creations(
+ int pch: @pch,
+ int compilation: @compilation ref,
+ int from: @file ref
+)
+
+/** An element for which line-count information is available. */
+@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable;
+
+fileannotations(
+ int id: @file ref,
+ int kind: int ref,
+ string name: string ref,
+ string value: string ref
+);
+
+inmacroexpansion(
+ int id: @element ref,
+ int inv: @macroinvocation ref
+);
+
+affectedbymacroexpansion(
+ int id: @element ref,
+ int inv: @macroinvocation ref
+);
+
+case @macroinvocation.kind of
+ 1 = @macro_expansion
+| 2 = @other_macro_reference
+;
+
+macroinvocations(
+ unique int id: @macroinvocation,
+ int macro_id: @ppd_define ref,
+ int location: @location_default ref,
+ int kind: int ref
+);
+
+macroparent(
+ unique int id: @macroinvocation ref,
+ int parent_id: @macroinvocation ref
+);
+
+// a macroinvocation may be part of another location
+// the way to find a constant expression that uses a macro
+// is thus to find a constant expression that has a location
+// to which a macro invocation is bound
+macrolocationbind(
+ int id: @macroinvocation ref,
+ int location: @location_default ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_unexpanded(
+ int invocation: @macroinvocation ref,
+ int argument_index: int ref,
+ string text: string ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_expanded(
+ int invocation: @macroinvocation ref,
+ int argument_index: int ref,
+ string text: string ref
+);
+
+case @function.kind of
+ 0 = @unknown_function
+| 1 = @normal_function
+| 2 = @constructor
+| 3 = @destructor
+| 4 = @conversion_function
+| 5 = @operator
+// ... 6 = @builtin_function deprecated // GCC built-in functions, e.g. __builtin___memcpy_chk
+| 7 = @user_defined_literal
+| 8 = @deduction_guide
+;
+
+functions(
+ unique int id: @function,
+ string name: string ref,
+ int kind: int ref
+);
+
+builtin_functions(
+ int id: @function ref
+)
+
+function_entry_point(
+ int id: @function ref,
+ unique int entry_point: @stmt ref
+);
+
+function_return_type(
+ int id: @function ref,
+ int return_type: @type ref
+);
+
+/**
+ * If `function` is a coroutine, then this gives the `std::experimental::resumable_traits`
+ * instance associated with it, and the variables representing the `handle` and `promise`
+ * for it.
+ */
+coroutine(
+ unique int function: @function ref,
+ int traits: @type ref
+);
+
+/*
+case @coroutine_placeholder_variable.kind of
+ 1 = @handle
+| 2 = @promise
+| 3 = @init_await_resume
+;
+*/
+
+coroutine_placeholder_variable(
+ unique int placeholder_variable: @variable ref,
+ int kind: int ref,
+ int function: @function ref
+)
+
+/** The `new` function used for allocating the coroutine state, if any. */
+coroutine_new(
+ unique int function: @function ref,
+ int new: @function ref
+);
+
+/** The `delete` function used for deallocating the coroutine state, if any. */
+coroutine_delete(
+ unique int function: @function ref,
+ int delete: @function ref
+);
+
+purefunctions(unique int id: @function ref);
+
+function_deleted(unique int id: @function ref);
+
+function_defaulted(unique int id: @function ref);
+
+function_prototyped(unique int id: @function ref)
+
+deduction_guide_for_class(
+ int id: @function ref,
+ int class_template: @usertype ref
+)
+
+member_function_this_type(
+ unique int id: @function ref,
+ int this_type: @type ref
+);
+
+#keyset[id, type_id]
+fun_decls(
+ int id: @fun_decl,
+ int function: @function ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+fun_def(unique int id: @fun_decl ref);
+fun_specialized(unique int id: @fun_decl ref);
+fun_implicit(unique int id: @fun_decl ref);
+fun_decl_specifiers(
+ int id: @fun_decl ref,
+ string name: string ref
+)
+#keyset[fun_decl, index]
+fun_decl_throws(
+ int fun_decl: @fun_decl ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+/* an empty throw specification is different from none */
+fun_decl_empty_throws(unique int fun_decl: @fun_decl ref);
+fun_decl_noexcept(
+ int fun_decl: @fun_decl ref,
+ int constant: @expr ref
+);
+fun_decl_empty_noexcept(int fun_decl: @fun_decl ref);
+fun_decl_typedef_type(
+ unique int fun_decl: @fun_decl ref,
+ int typedeftype_id: @usertype ref
+);
+
+/*
+case @fun_requires.kind of
+ 1 = @template_attached
+| 2 = @function_attached
+;
+*/
+
+fun_requires(
+ int id: @fun_decl ref,
+ int kind: int ref,
+ int constraint: @expr ref
+);
+
+param_decl_bind(
+ unique int id: @var_decl ref,
+ int index: int ref,
+ int fun_decl: @fun_decl ref
+);
+
+#keyset[id, type_id]
+var_decls(
+ int id: @var_decl,
+ int variable: @variable ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+var_def(unique int id: @var_decl ref);
+var_specialized(int id: @var_decl ref);
+var_decl_specifiers(
+ int id: @var_decl ref,
+ string name: string ref
+)
+is_structured_binding(unique int id: @variable ref);
+var_requires(
+ int id: @var_decl ref,
+ int constraint: @expr ref
+);
+
+type_decls(
+ unique int id: @type_decl,
+ int type_id: @type ref,
+ int location: @location_default ref
+);
+type_def(unique int id: @type_decl ref);
+type_decl_top(
+ unique int type_decl: @type_decl ref
+);
+type_requires(
+ int id: @type_decl ref,
+ int constraint: @expr ref
+);
+
+namespace_decls(
+ unique int id: @namespace_decl,
+ int namespace_id: @namespace ref,
+ int location: @location_default ref,
+ int bodylocation: @location_default ref
+);
+
+case @using.kind of
+ 1 = @using_declaration
+| 2 = @using_directive
+| 3 = @using_enum_declaration
+;
+
+usings(
+ unique int id: @using,
+ int element_id: @element ref,
+ int location: @location_default ref,
+ int kind: int ref
+);
+
+/** The element which contains the `using` declaration. */
+using_container(
+ int parent: @element ref,
+ int child: @using ref
+);
+
+static_asserts(
+ unique int id: @static_assert,
+ int condition : @expr ref,
+ string message : string ref,
+ int location: @location_default ref,
+ int enclosing : @element ref
+);
+
+// each function has an ordered list of parameters
+#keyset[id, type_id]
+#keyset[function, index, type_id]
+params(
+ int id: @parameter,
+ int function: @parameterized_element ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+
+overrides(
+ int new: @function ref,
+ int old: @function ref
+);
+
+#keyset[id, type_id]
+membervariables(
+ int id: @membervariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+#keyset[id, type_id]
+globalvariables(
+ int id: @globalvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+#keyset[id, type_id]
+localvariables(
+ int id: @localvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+autoderivation(
+ unique int var: @variable ref,
+ int derivation_type: @type ref
+);
+
+orphaned_variables(
+ int var: @localvariable ref,
+ int function: @function ref
+)
+
+enumconstants(
+ unique int id: @enumconstant,
+ int parent: @usertype ref,
+ int index: int ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+
+@variable = @localscopevariable | @globalvariable | @membervariable;
+
+@localscopevariable = @localvariable | @parameter;
+
+/**
+ * Built-in types are the fundamental types, e.g., integral, floating, and void.
+ */
+case @builtintype.kind of
+ 1 = @errortype
+| 2 = @unknowntype
+| 3 = @void
+| 4 = @boolean
+| 5 = @char
+| 6 = @unsigned_char
+| 7 = @signed_char
+| 8 = @short
+| 9 = @unsigned_short
+| 10 = @signed_short
+| 11 = @int
+| 12 = @unsigned_int
+| 13 = @signed_int
+| 14 = @long
+| 15 = @unsigned_long
+| 16 = @signed_long
+| 17 = @long_long
+| 18 = @unsigned_long_long
+| 19 = @signed_long_long
+// ... 20 Microsoft-specific __int8
+// ... 21 Microsoft-specific __int16
+// ... 22 Microsoft-specific __int32
+// ... 23 Microsoft-specific __int64
+| 24 = @float
+| 25 = @double
+| 26 = @long_double
+| 27 = @complex_float // C99-specific _Complex float
+| 28 = @complex_double // C99-specific _Complex double
+| 29 = @complex_long_double // C99-specific _Complex long double
+| 30 = @imaginary_float // C99-specific _Imaginary float
+| 31 = @imaginary_double // C99-specific _Imaginary double
+| 32 = @imaginary_long_double // C99-specific _Imaginary long double
+| 33 = @wchar_t // Microsoft-specific
+| 34 = @decltype_nullptr // C++11
+| 35 = @int128 // __int128
+| 36 = @unsigned_int128 // unsigned __int128
+| 37 = @signed_int128 // signed __int128
+| 38 = @float128 // __float128
+| 39 = @complex_float128 // _Complex __float128
+// ... 40 _Decimal32
+// ... 41 _Decimal64
+// ... 42 _Decimal128
+| 43 = @char16_t
+| 44 = @char32_t
+| 45 = @std_float32 // _Float32
+| 46 = @float32x // _Float32x
+| 47 = @std_float64 // _Float64
+| 48 = @float64x // _Float64x
+| 49 = @std_float128 // _Float128
+// ... 50 _Float128x
+| 51 = @char8_t
+| 52 = @float16 // _Float16
+| 53 = @complex_float16 // _Complex _Float16
+| 54 = @fp16 // __fp16
+| 55 = @std_bfloat16 // __bf16
+| 56 = @std_float16 // std::float16_t
+| 57 = @complex_std_float32 // _Complex _Float32
+| 58 = @complex_float32x // _Complex _Float32x
+| 59 = @complex_std_float64 // _Complex _Float64
+| 60 = @complex_float64x // _Complex _Float64x
+| 61 = @complex_std_float128 // _Complex _Float128
+| 62 = @mfp8 // __mfp8
+| 63 = @scalable_vector_count // __SVCount_t
+| 64 = @complex_fp16 // _Complex __fp16
+| 65 = @complex_std_bfloat16 // _Complex __bf16
+| 66 = @complex_std_float16 // _Complex std::float16_t
+;
+
+builtintypes(
+ unique int id: @builtintype,
+ string name: string ref,
+ int kind: int ref,
+ int size: int ref,
+ int sign: int ref,
+ int alignment: int ref
+);
+
+/**
+ * Derived types are types that are directly derived from existing types and
+ * point to, refer to, transform type data to return a new type.
+ */
+case @derivedtype.kind of
+ 1 = @pointer
+| 2 = @reference
+| 3 = @type_with_specifiers
+| 4 = @array
+| 5 = @gnu_vector
+| 6 = @routineptr
+| 7 = @routinereference
+| 8 = @rvalue_reference // C++11
+// ... 9 type_conforming_to_protocols deprecated
+| 10 = @block
+| 11 = @scalable_vector // Arm SVE
+;
+
+derivedtypes(
+ unique int id: @derivedtype,
+ string name: string ref,
+ int kind: int ref,
+ int type_id: @type ref
+);
+
+pointerishsize(unique int id: @derivedtype ref,
+ int size: int ref,
+ int alignment: int ref);
+
+arraysizes(
+ unique int id: @derivedtype ref,
+ int num_elements: int ref,
+ int bytesize: int ref,
+ int alignment: int ref
+);
+
+tupleelements(
+ unique int id: @derivedtype ref,
+ int num_elements: int ref
+);
+
+typedefbase(
+ unique int id: @usertype ref,
+ int type_id: @type ref
+);
+
+/**
+ * An instance of the C++11 `decltype` operator or C23 `typeof`/`typeof_unqual`
+ * operator taking an expression as its argument. For example:
+ * ```
+ * int a;
+ * decltype(1+a) b;
+ * typeof(1+a) c;
+ * ```
+ * Here `expr` is `1+a`.
+ *
+ * Sometimes an additional pair of parentheses around the expression
+ * changes the semantics of the decltype, e.g.
+ * ```
+ * struct A { double x; };
+ * const A* a = new A();
+ * decltype( a->x ); // type is double
+ * decltype((a->x)); // type is const double&
+ * ```
+ * (Please consult the C++11 standard for more details).
+ * `parentheses_would_change_meaning` is `true` iff that is the case.
+ */
+
+/*
+case @decltype.kind of
+| 0 = @decltype
+| 1 = @typeof // The frontend does not differentiate between typeof and typeof_unqual
+;
+*/
+
+#keyset[id, expr]
+decltypes(
+ int id: @decltype,
+ int expr: @expr ref,
+ int kind: int ref,
+ int base_type: @type ref,
+ boolean parentheses_would_change_meaning: boolean ref
+);
+
+case @type_operator.kind of
+ 0 = @typeof // The frontend does not differentiate between typeof and typeof_unqual
+| 1 = @underlying_type
+| 2 = @bases
+| 3 = @direct_bases
+| 4 = @add_lvalue_reference
+| 5 = @add_pointer
+| 6 = @add_rvalue_reference
+| 7 = @decay
+| 8 = @make_signed
+| 9 = @make_unsigned
+| 10 = @remove_all_extents
+| 11 = @remove_const
+| 12 = @remove_cv
+| 13 = @remove_cvref
+| 14 = @remove_extent
+| 15 = @remove_pointer
+| 16 = @remove_reference_t
+| 17 = @remove_restrict
+| 18 = @remove_volatile
+| 19 = @remove_reference
+;
+
+type_operators(
+ unique int id: @type_operator,
+ int arg_type: @type ref,
+ int kind: int ref,
+ int base_type: @type ref
+)
+
+case @usertype.kind of
+ 0 = @unknown_usertype
+| 1 = @struct
+| 2 = @class
+| 3 = @union
+| 4 = @enum
+// ... 5 = @typedef deprecated // classic C: typedef typedef type name
+// ... 6 = @template deprecated
+| 7 = @template_parameter
+| 8 = @template_template_parameter
+| 9 = @proxy_class // a proxy class associated with a template parameter
+// ... 10 objc_class deprecated
+// ... 11 objc_protocol deprecated
+// ... 12 objc_category deprecated
+| 13 = @scoped_enum
+// ... 14 = @using_alias deprecated // a using name = type style typedef
+| 15 = @template_struct
+| 16 = @template_class
+| 17 = @template_union
+| 18 = @alias
+;
+
+usertypes(
+ unique int id: @usertype,
+ string name: string ref,
+ int kind: int ref
+);
+
+usertypesize(
+ unique int id: @usertype ref,
+ int size: int ref,
+ int alignment: int ref
+);
+
+usertype_final(unique int id: @usertype ref);
+
+usertype_uuid(
+ unique int id: @usertype ref,
+ string uuid: string ref
+);
+
+/*
+case @usertype.alias_kind of
+| 0 = @typedef
+| 1 = @alias
+*/
+
+usertype_alias_kind(
+ int id: @usertype ref,
+ int alias_kind: int ref
+)
+
+nontype_template_parameters(
+ int id: @expr ref
+);
+
+type_template_type_constraint(
+ int id: @usertype ref,
+ int constraint: @expr ref
+);
+
+mangled_name(
+ unique int id: @declaration ref,
+ int mangled_name : @mangledname,
+ boolean is_complete: boolean ref
+);
+
+is_pod_class(unique int id: @usertype ref);
+is_standard_layout_class(unique int id: @usertype ref);
+
+is_complete(unique int id: @usertype ref);
+
+is_class_template(unique int id: @usertype ref);
+class_instantiation(
+ int to: @usertype ref,
+ int from: @usertype ref
+);
+class_template_argument(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+class_template_argument_value(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+@user_or_decltype = @usertype | @decltype;
+
+is_proxy_class_for(
+ unique int id: @usertype ref,
+ int templ_param_id: @user_or_decltype ref
+);
+
+type_mentions(
+ unique int id: @type_mention,
+ int type_id: @type ref,
+ int location: @location_default ref,
+ // a_symbol_reference_kind from the frontend.
+ int kind: int ref
+);
+
+is_function_template(unique int id: @function ref);
+function_instantiation(
+ unique int to: @function ref,
+ int from: @function ref
+);
+function_template_argument(
+ int function_id: @function ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+function_template_argument_value(
+ int function_id: @function ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+is_variable_template(unique int id: @variable ref);
+variable_instantiation(
+ unique int to: @variable ref,
+ int from: @variable ref
+);
+variable_template_argument(
+ int variable_id: @variable ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+variable_template_argument_value(
+ int variable_id: @variable ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+template_template_instantiation(
+ int to: @usertype ref,
+ int from: @usertype ref
+);
+template_template_argument(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+template_template_argument_value(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+@concept = @concept_template | @concept_id;
+
+concept_templates(
+ unique int concept_id: @concept_template,
+ string name: string ref,
+ int location: @location_default ref
+);
+concept_instantiation(
+ unique int to: @concept_id ref,
+ int from: @concept_template ref
+);
+is_type_constraint(int concept_id: @concept_id ref);
+concept_template_argument(
+ int concept_id: @concept ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+concept_template_argument_value(
+ int concept_id: @concept ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+routinetypes(
+ unique int id: @routinetype,
+ int return_type: @type ref
+);
+
+routinetypeargs(
+ int routine: @routinetype ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+
+ptrtomembers(
+ unique int id: @ptrtomember,
+ int type_id: @type ref,
+ int class_id: @type ref
+);
+
+/*
+ specifiers for types, functions, and variables
+
+ "public",
+ "protected",
+ "private",
+
+ "const",
+ "volatile",
+ "static",
+
+ "pure",
+ "virtual",
+ "sealed", // Microsoft
+ "__interface", // Microsoft
+ "inline",
+ "explicit",
+
+ "near", // near far extension
+ "far", // near far extension
+ "__ptr32", // Microsoft
+ "__ptr64", // Microsoft
+ "__sptr", // Microsoft
+ "__uptr", // Microsoft
+ "dllimport", // Microsoft
+ "dllexport", // Microsoft
+ "thread", // Microsoft
+ "naked", // Microsoft
+ "microsoft_inline", // Microsoft
+ "forceinline", // Microsoft
+ "selectany", // Microsoft
+ "nothrow", // Microsoft
+ "novtable", // Microsoft
+ "noreturn", // Microsoft
+ "noinline", // Microsoft
+ "noalias", // Microsoft
+ "restrict", // Microsoft
+*/
+
+specifiers(
+ unique int id: @specifier,
+ unique string str: string ref
+);
+
+typespecifiers(
+ int type_id: @type ref,
+ int spec_id: @specifier ref
+);
+
+funspecifiers(
+ int func_id: @function ref,
+ int spec_id: @specifier ref
+);
+
+varspecifiers(
+ int var_id: @accessible ref,
+ int spec_id: @specifier ref
+);
+
+explicit_specifier_exprs(
+ unique int func_id: @function ref,
+ int constant: @expr ref
+)
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ string name: string ref,
+ string name_space: string ref,
+ int location: @location_default ref
+);
+
+case @attribute.kind of
+ 0 = @gnuattribute
+| 1 = @stdattribute
+| 2 = @declspec
+| 3 = @msattribute
+| 4 = @alignas
+// ... 5 @objc_propertyattribute deprecated
+;
+
+attribute_args(
+ unique int id: @attribute_arg,
+ int kind: int ref,
+ int attribute: @attribute ref,
+ int index: int ref,
+ int location: @location_default ref
+);
+
+case @attribute_arg.kind of
+ 0 = @attribute_arg_empty
+| 1 = @attribute_arg_token
+| 2 = @attribute_arg_constant
+| 3 = @attribute_arg_type
+| 4 = @attribute_arg_constant_expr
+| 5 = @attribute_arg_expr
+;
+
+attribute_arg_value(
+ unique int arg: @attribute_arg ref,
+ string value: string ref
+);
+attribute_arg_type(
+ unique int arg: @attribute_arg ref,
+ int type_id: @type ref
+);
+attribute_arg_constant(
+ unique int arg: @attribute_arg ref,
+ int constant: @expr ref
+)
+attribute_arg_expr(
+ unique int arg: @attribute_arg ref,
+ int expr: @expr ref
+)
+attribute_arg_name(
+ unique int arg: @attribute_arg ref,
+ string name: string ref
+);
+
+typeattributes(
+ int type_id: @type ref,
+ int spec_id: @attribute ref
+);
+
+funcattributes(
+ int func_id: @function ref,
+ int spec_id: @attribute ref
+);
+
+varattributes(
+ int var_id: @accessible ref,
+ int spec_id: @attribute ref
+);
+
+namespaceattributes(
+ int namespace_id: @namespace ref,
+ int spec_id: @attribute ref
+);
+
+stmtattributes(
+ int stmt_id: @stmt ref,
+ int spec_id: @attribute ref
+);
+
+@type = @builtintype
+ | @derivedtype
+ | @usertype
+ | @routinetype
+ | @ptrtomember
+ | @decltype
+ | @type_operator;
+
+unspecifiedtype(
+ unique int type_id: @type ref,
+ int unspecified_type_id: @type ref
+);
+
+member(
+ int parent: @type ref,
+ int index: int ref,
+ int child: @member ref
+);
+
+@enclosingfunction_child = @usertype | @variable | @namespace
+
+enclosingfunction(
+ unique int child: @enclosingfunction_child ref,
+ int parent: @function ref
+);
+
+derivations(
+ unique int derivation: @derivation,
+ int sub: @type ref,
+ int index: int ref,
+ int super: @type ref,
+ int location: @location_default ref
+);
+
+derspecifiers(
+ int der_id: @derivation ref,
+ int spec_id: @specifier ref
+);
+
+/**
+ * Contains the byte offset of the base class subobject within the derived
+ * class. Only holds for non-virtual base classes, but see table
+ * `virtual_base_offsets` for offsets of virtual base class subobjects.
+ */
+direct_base_offsets(
+ unique int der_id: @derivation ref,
+ int offset: int ref
+);
+
+/**
+ * Contains the byte offset of the virtual base class subobject for class
+ * `super` within a most-derived object of class `sub`. `super` can be either a
+ * direct or indirect base class.
+ */
+#keyset[sub, super]
+virtual_base_offsets(
+ int sub: @usertype ref,
+ int super: @usertype ref,
+ int offset: int ref
+);
+
+frienddecls(
+ unique int id: @frienddecl,
+ int type_id: @type ref,
+ int decl_id: @declaration ref,
+ int location: @location_default ref
+);
+
+@declaredtype = @usertype ;
+
+@declaration = @function
+ | @declaredtype
+ | @variable
+ | @enumconstant
+ | @frienddecl
+ | @concept_template;
+
+@member = @membervariable
+ | @function
+ | @declaredtype
+ | @enumconstant;
+
+@locatable = @diagnostic
+ | @declaration
+ | @ppd_include
+ | @ppd_define
+ | @macroinvocation
+ /*| @funcall*/
+ | @xmllocatable
+ | @attribute
+ | @attribute_arg;
+
+@namedscope = @namespace | @usertype;
+
+@element = @locatable
+ | @file
+ | @folder
+ | @specifier
+ | @type
+ | @expr
+ | @namespace
+ | @initialiser
+ | @stmt
+ | @derivation
+ | @comment
+ | @preprocdirect
+ | @fun_decl
+ | @var_decl
+ | @type_decl
+ | @namespace_decl
+ | @using
+ | @namequalifier
+ | @specialnamequalifyingelement
+ | @static_assert
+ | @type_mention
+ | @lambdacapture;
+
+@exprparent = @element;
+
+comments(
+ unique int id: @comment,
+ string contents: string ref,
+ int location: @location_default ref
+);
+
+commentbinding(
+ int id: @comment ref,
+ int element: @element ref
+);
+
+exprconv(
+ int converted: @expr ref,
+ unique int conversion: @expr ref
+);
+
+compgenerated(unique int id: @element ref);
+
+/**
+ * `destructor_call` destructs the `i`'th entity that should be
+ * destructed following `element`. Note that entities should be
+ * destructed in reverse construction order, so for a given `element`
+ * these should be called from highest to lowest `i`.
+ */
+#keyset[element, destructor_call]
+#keyset[element, i]
+synthetic_destructor_call(
+ int element: @element ref,
+ int i: int ref,
+ int destructor_call: @routineexpr ref
+);
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref
+);
+
+namespace_inline(
+ unique int id: @namespace ref
+);
+
+namespacembrs(
+ int parentid: @namespace ref,
+ unique int memberid: @namespacembr ref
+);
+
+@namespacembr = @declaration | @namespace;
+
+exprparents(
+ int expr_id: @expr ref,
+ int child_index: int ref,
+ int parent_id: @exprparent ref
+);
+
+expr_isload(unique int expr_id: @expr ref);
+
+@cast = @c_style_cast
+ | @const_cast
+ | @dynamic_cast
+ | @reinterpret_cast
+ | @static_cast
+ ;
+
+/*
+case @conversion.kind of
+ 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast
+| 1 = @bool_conversion // conversion to 'bool'
+| 2 = @base_class_conversion // a derived-to-base conversion
+| 3 = @derived_class_conversion // a base-to-derived conversion
+| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member
+| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member
+| 6 = @glvalue_adjust // an adjustment of the type of a glvalue
+| 7 = @prvalue_adjust // an adjustment of the type of a prvalue
+;
+*/
+/**
+ * Describes the semantics represented by a cast expression. This is largely
+ * independent of the source syntax of the cast, so it is separate from the
+ * regular expression kind.
+ */
+conversionkinds(
+ unique int expr_id: @cast ref,
+ int kind: int ref
+);
+
+@conversion = @cast
+ | @array_to_pointer
+ | @parexpr
+ | @reference_to
+ | @ref_indirect
+ | @temp_init
+ | @c11_generic
+ ;
+
+/*
+case @funbindexpr.kind of
+ 0 = @normal_call // a normal call
+| 1 = @virtual_call // a virtual call
+| 2 = @adl_call // a call whose target is only found by ADL
+;
+*/
+iscall(
+ unique int caller: @funbindexpr ref,
+ int kind: int ref
+);
+
+numtemplatearguments(
+ unique int expr_id: @expr ref,
+ int num: int ref
+);
+
+specialnamequalifyingelements(
+ unique int id: @specialnamequalifyingelement,
+ unique string name: string ref
+);
+
+@namequalifiableelement = @expr | @namequalifier;
+@namequalifyingelement = @namespace
+ | @specialnamequalifyingelement
+ | @usertype
+ | @decltype;
+
+namequalifiers(
+ unique int id: @namequalifier,
+ unique int qualifiableelement: @namequalifiableelement ref,
+ int qualifyingelement: @namequalifyingelement ref,
+ int location: @location_default ref
+);
+
+varbind(
+ int expr: @varbindexpr ref,
+ int var: @accessible ref
+);
+
+funbind(
+ int expr: @funbindexpr ref,
+ int fun: @function ref
+);
+
+@any_new_expr = @new_expr
+ | @new_array_expr;
+
+@new_or_delete_expr = @any_new_expr
+ | @delete_expr
+ | @delete_array_expr;
+
+@prefix_crement_expr = @preincrexpr | @predecrexpr;
+
+@postfix_crement_expr = @postincrexpr | @postdecrexpr;
+
+@increment_expr = @preincrexpr | @postincrexpr;
+
+@decrement_expr = @predecrexpr | @postdecrexpr;
+
+@crement_expr = @increment_expr | @decrement_expr;
+
+@un_arith_op_expr = @arithnegexpr
+ | @unaryplusexpr
+ | @conjugation
+ | @realpartexpr
+ | @imagpartexpr
+ | @crement_expr
+ ;
+
+@un_bitwise_op_expr = @complementexpr;
+
+@un_log_op_expr = @notexpr;
+
+@un_op_expr = @address_of
+ | @indirect
+ | @un_arith_op_expr
+ | @un_bitwise_op_expr
+ | @builtinaddressof
+ | @vec_fill
+ | @un_log_op_expr
+ | @co_await
+ | @co_yield
+ ;
+
+@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr;
+
+@cmp_op_expr = @eq_op_expr | @rel_op_expr;
+
+@eq_op_expr = @eqexpr | @neexpr;
+
+@rel_op_expr = @gtexpr
+ | @ltexpr
+ | @geexpr
+ | @leexpr
+ | @spaceshipexpr
+ ;
+
+@bin_bitwise_op_expr = @lshiftexpr
+ | @rshiftexpr
+ | @andexpr
+ | @orexpr
+ | @xorexpr
+ ;
+
+@p_arith_op_expr = @paddexpr
+ | @psubexpr
+ | @pdiffexpr
+ ;
+
+@bin_arith_op_expr = @addexpr
+ | @subexpr
+ | @mulexpr
+ | @divexpr
+ | @remexpr
+ | @jmulexpr
+ | @jdivexpr
+ | @fjaddexpr
+ | @jfaddexpr
+ | @fjsubexpr
+ | @jfsubexpr
+ | @minexpr
+ | @maxexpr
+ | @p_arith_op_expr
+ ;
+
+@bin_op_expr = @bin_arith_op_expr
+ | @bin_bitwise_op_expr
+ | @cmp_op_expr
+ | @bin_log_op_expr
+ ;
+
+@op_expr = @un_op_expr
+ | @bin_op_expr
+ | @assign_expr
+ | @conditionalexpr
+ ;
+
+@assign_arith_expr = @assignaddexpr
+ | @assignsubexpr
+ | @assignmulexpr
+ | @assigndivexpr
+ | @assignremexpr
+ ;
+
+@assign_bitwise_expr = @assignandexpr
+ | @assignorexpr
+ | @assignxorexpr
+ | @assignlshiftexpr
+ | @assignrshiftexpr
+ ;
+
+@assign_pointer_expr = @assignpaddexpr
+ | @assignpsubexpr
+ ;
+
+@assign_op_expr = @assign_arith_expr
+ | @assign_bitwise_expr
+ | @assign_pointer_expr
+ ;
+
+@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
+
+/*
+ Binary encoding of the allocator form.
+
+ case @allocator.form of
+ 0 = plain
+ | 1 = alignment
+ ;
+*/
+
+/**
+ * The allocator function associated with a `new` or `new[]` expression.
+ * The `form` column specified whether the allocation call contains an alignment
+ * argument.
+ */
+expr_allocator(
+ unique int expr: @any_new_expr ref,
+ int func: @function ref,
+ int form: int ref
+);
+
+/*
+ Binary encoding of the deallocator form.
+
+ case @deallocator.form of
+ 0 = plain
+ | 1 = size
+ | 2 = alignment
+ | 4 = destroying_delete
+ ;
+*/
+
+/**
+ * The deallocator function associated with a `delete`, `delete[]`, `new`, or
+ * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the
+ * one used to free memory if the initialization throws an exception.
+ * The `form` column specifies whether the deallocation call contains a size
+ * argument, and alignment argument, or both.
+ */
+expr_deallocator(
+ unique int expr: @new_or_delete_expr ref,
+ int func: @function ref,
+ int form: int ref
+);
+
+/**
+ * Holds if the `@conditionalexpr` is of the two operand form
+ * `guard ? : false`.
+ */
+expr_cond_two_operand(
+ unique int cond: @conditionalexpr ref
+);
+
+/**
+ * The guard of `@conditionalexpr` `guard ? true : false`
+ */
+expr_cond_guard(
+ unique int cond: @conditionalexpr ref,
+ int guard: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` holds. For the two operand form
+ * `guard ?: false` consider using `expr_cond_guard` instead.
+ */
+expr_cond_true(
+ unique int cond: @conditionalexpr ref,
+ int true: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` does not hold.
+ */
+expr_cond_false(
+ unique int cond: @conditionalexpr ref,
+ int false: @expr ref
+);
+
+/** A string representation of the value. */
+values(
+ unique int id: @value,
+ string str: string ref
+);
+
+/** The actual text in the source code for the value, if any. */
+valuetext(
+ unique int id: @value ref,
+ string text: string ref
+);
+
+valuebind(
+ int val: @value ref,
+ unique int expr: @expr ref
+);
+
+fieldoffsets(
+ unique int id: @variable ref,
+ int byteoffset: int ref,
+ int bitoffset: int ref
+);
+
+bitfield(
+ unique int id: @variable ref,
+ int bits: int ref,
+ int declared_bits: int ref
+);
+
+/* TODO
+memberprefix(
+ int member: @expr ref,
+ int prefix: @expr ref
+);
+*/
+
+/*
+ kind(1) = mbrcallexpr
+ kind(2) = mbrptrcallexpr
+ kind(3) = mbrptrmbrcallexpr
+ kind(4) = ptrmbrptrmbrcallexpr
+ kind(5) = mbrreadexpr // x.y
+ kind(6) = mbrptrreadexpr // p->y
+ kind(7) = mbrptrmbrreadexpr // x.*pm
+ kind(8) = mbrptrmbrptrreadexpr // x->*pm
+ kind(9) = staticmbrreadexpr // static x.y
+ kind(10) = staticmbrptrreadexpr // static p->y
+*/
+/* TODO
+memberaccess(
+ int member: @expr ref,
+ int kind: int ref
+);
+*/
+
+initialisers(
+ unique int init: @initialiser,
+ int var: @accessible ref,
+ unique int expr: @expr ref,
+ int location: @location_default ref
+);
+
+braced_initialisers(
+ int init: @initialiser ref
+);
+
+/**
+ * An ancestor for the expression, for cases in which we cannot
+ * otherwise find the expression's parent.
+ */
+expr_ancestor(
+ int exp: @expr ref,
+ int ancestor: @element ref
+);
+
+exprs(
+ unique int id: @expr,
+ int kind: int ref,
+ int location: @location_default ref
+);
+
+expr_reuse(
+ int reuse: @expr ref,
+ int original: @expr ref,
+ int value_category: int ref
+)
+
+/*
+ case @value.category of
+ 1 = prval
+ | 2 = xval
+ | 3 = lval
+ ;
+*/
+expr_types(
+ int id: @expr ref,
+ int typeid: @type ref,
+ int value_category: int ref
+);
+
+case @expr.kind of
+ 1 = @errorexpr
+| 2 = @address_of // & AddressOfExpr
+| 3 = @reference_to // ReferenceToExpr (implicit?)
+| 4 = @indirect // * PointerDereferenceExpr
+| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?)
+// ...
+| 8 = @array_to_pointer // (???)
+| 9 = @vacuous_destructor_call // VacuousDestructorCall
+// ...
+| 11 = @assume // Microsoft
+| 12 = @parexpr
+| 13 = @arithnegexpr
+| 14 = @unaryplusexpr
+| 15 = @complementexpr
+| 16 = @notexpr
+| 17 = @conjugation // GNU ~ operator
+| 18 = @realpartexpr // GNU __real
+| 19 = @imagpartexpr // GNU __imag
+| 20 = @postincrexpr
+| 21 = @postdecrexpr
+| 22 = @preincrexpr
+| 23 = @predecrexpr
+| 24 = @conditionalexpr
+| 25 = @addexpr
+| 26 = @subexpr
+| 27 = @mulexpr
+| 28 = @divexpr
+| 29 = @remexpr
+| 30 = @jmulexpr // C99 mul imaginary
+| 31 = @jdivexpr // C99 div imaginary
+| 32 = @fjaddexpr // C99 add real + imaginary
+| 33 = @jfaddexpr // C99 add imaginary + real
+| 34 = @fjsubexpr // C99 sub real - imaginary
+| 35 = @jfsubexpr // C99 sub imaginary - real
+| 36 = @paddexpr // pointer add (pointer + int or int + pointer)
+| 37 = @psubexpr // pointer sub (pointer - integer)
+| 38 = @pdiffexpr // difference between two pointers
+| 39 = @lshiftexpr
+| 40 = @rshiftexpr
+| 41 = @andexpr
+| 42 = @orexpr
+| 43 = @xorexpr
+| 44 = @eqexpr
+| 45 = @neexpr
+| 46 = @gtexpr
+| 47 = @ltexpr
+| 48 = @geexpr
+| 49 = @leexpr
+| 50 = @minexpr // GNU minimum
+| 51 = @maxexpr // GNU maximum
+| 52 = @assignexpr
+| 53 = @assignaddexpr
+| 54 = @assignsubexpr
+| 55 = @assignmulexpr
+| 56 = @assigndivexpr
+| 57 = @assignremexpr
+| 58 = @assignlshiftexpr
+| 59 = @assignrshiftexpr
+| 60 = @assignandexpr
+| 61 = @assignorexpr
+| 62 = @assignxorexpr
+| 63 = @assignpaddexpr // assign pointer add
+| 64 = @assignpsubexpr // assign pointer sub
+| 65 = @andlogicalexpr
+| 66 = @orlogicalexpr
+| 67 = @commaexpr
+| 68 = @subscriptexpr // access to member of an array, e.g., a[5]
+// ... 69 @objc_subscriptexpr deprecated
+// ... 70 @cmdaccess deprecated
+// ...
+| 73 = @virtfunptrexpr
+| 74 = @callexpr
+// ... 75 @msgexpr_normal deprecated
+// ... 76 @msgexpr_super deprecated
+// ... 77 @atselectorexpr deprecated
+// ... 78 @atprotocolexpr deprecated
+| 79 = @vastartexpr
+| 80 = @vaargexpr
+| 81 = @vaendexpr
+| 82 = @vacopyexpr
+// ... 83 @atencodeexpr deprecated
+| 84 = @varaccess
+| 85 = @thisaccess
+// ... 86 @objc_box_expr deprecated
+| 87 = @new_expr
+| 88 = @delete_expr
+| 89 = @throw_expr
+| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2)
+| 91 = @braced_init_list
+| 92 = @type_id
+| 93 = @runtime_sizeof
+| 94 = @runtime_alignof
+| 95 = @sizeof_pack
+| 96 = @expr_stmt // GNU extension
+| 97 = @routineexpr
+| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....)
+| 99 = @offsetofexpr // offsetof ::= type and field
+| 100 = @hasassignexpr // __has_assign ::= type
+| 101 = @hascopyexpr // __has_copy ::= type
+| 102 = @hasnothrowassign // __has_nothrow_assign ::= type
+| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type
+| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type
+| 105 = @hastrivialassign // __has_trivial_assign ::= type
+| 106 = @hastrivialconstr // __has_trivial_constructor ::= type
+| 107 = @hastrivialcopy // __has_trivial_copy ::= type
+| 108 = @hasuserdestr // __has_user_destructor ::= type
+| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type
+| 110 = @isabstractexpr // __is_abstract ::= type
+| 111 = @isbaseofexpr // __is_base_of ::= type type
+| 112 = @isclassexpr // __is_class ::= type
+| 113 = @isconvtoexpr // __is_convertible_to ::= type type
+| 114 = @isemptyexpr // __is_empty ::= type
+| 115 = @isenumexpr // __is_enum ::= type
+| 116 = @ispodexpr // __is_pod ::= type
+| 117 = @ispolyexpr // __is_polymorphic ::= type
+| 118 = @isunionexpr // __is_union ::= type
+| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type
+| 120 = @intaddrexpr // frontend internal builtin, used to implement offsetof
+// ...
+| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type
+| 123 = @literal
+| 124 = @uuidof
+| 127 = @aggregateliteral
+| 128 = @delete_array_expr
+| 129 = @new_array_expr
+// ... 130 @objc_array_literal deprecated
+// ... 131 @objc_dictionary_literal deprecated
+| 132 = @foldexpr
+// ...
+| 200 = @ctordirectinit
+| 201 = @ctorvirtualinit
+| 202 = @ctorfieldinit
+| 203 = @ctordelegatinginit
+| 204 = @dtordirectdestruct
+| 205 = @dtorvirtualdestruct
+| 206 = @dtorfielddestruct
+// ...
+| 210 = @static_cast
+| 211 = @reinterpret_cast
+| 212 = @const_cast
+| 213 = @dynamic_cast
+| 214 = @c_style_cast
+| 215 = @lambdaexpr
+| 216 = @param_ref
+| 217 = @noopexpr
+// ...
+| 294 = @istriviallyconstructibleexpr
+| 295 = @isdestructibleexpr
+| 296 = @isnothrowdestructibleexpr
+| 297 = @istriviallydestructibleexpr
+| 298 = @istriviallyassignableexpr
+| 299 = @isnothrowassignableexpr
+| 300 = @istrivialexpr
+| 301 = @isstandardlayoutexpr
+| 302 = @istriviallycopyableexpr
+| 303 = @isliteraltypeexpr
+| 304 = @hastrivialmoveconstructorexpr
+| 305 = @hastrivialmoveassignexpr
+| 306 = @hasnothrowmoveassignexpr
+| 307 = @isconstructibleexpr
+| 308 = @isnothrowconstructibleexpr
+| 309 = @hasfinalizerexpr
+| 310 = @isdelegateexpr
+| 311 = @isinterfaceclassexpr
+| 312 = @isrefarrayexpr
+| 313 = @isrefclassexpr
+| 314 = @issealedexpr
+| 315 = @issimplevalueclassexpr
+| 316 = @isvalueclassexpr
+| 317 = @isfinalexpr
+| 319 = @noexceptexpr
+| 320 = @builtinshufflevector
+| 321 = @builtinchooseexpr
+| 322 = @builtinaddressof
+| 323 = @vec_fill
+| 324 = @builtinconvertvector
+| 325 = @builtincomplex
+| 326 = @spaceshipexpr
+| 327 = @co_await
+| 328 = @co_yield
+| 329 = @temp_init
+| 330 = @isassignable
+| 331 = @isaggregate
+| 332 = @hasuniqueobjectrepresentations
+| 333 = @builtinbitcast
+| 334 = @builtinshuffle
+| 335 = @blockassignexpr
+| 336 = @issame
+| 337 = @isfunction
+| 338 = @islayoutcompatible
+| 339 = @ispointerinterconvertiblebaseof
+| 340 = @isarray
+| 341 = @arrayrank
+| 342 = @arrayextent
+| 343 = @isarithmetic
+| 344 = @iscompletetype
+| 345 = @iscompound
+| 346 = @isconst
+| 347 = @isfloatingpoint
+| 348 = @isfundamental
+| 349 = @isintegral
+| 350 = @islvaluereference
+| 351 = @ismemberfunctionpointer
+| 352 = @ismemberobjectpointer
+| 353 = @ismemberpointer
+| 354 = @isobject
+| 355 = @ispointer
+| 356 = @isreference
+| 357 = @isrvaluereference
+| 358 = @isscalar
+| 359 = @issigned
+| 360 = @isunsigned
+| 361 = @isvoid
+| 362 = @isvolatile
+| 363 = @reuseexpr
+| 364 = @istriviallycopyassignable
+| 365 = @isassignablenopreconditioncheck
+| 366 = @referencebindstotemporary
+| 367 = @issameas
+| 368 = @builtinhasattribute
+| 369 = @ispointerinterconvertiblewithclass
+| 370 = @builtinispointerinterconvertiblewithclass
+| 371 = @iscorrespondingmember
+| 372 = @builtiniscorrespondingmember
+| 373 = @isboundedarray
+| 374 = @isunboundedarray
+| 375 = @isreferenceable
+| 378 = @isnothrowconvertible
+| 379 = @referenceconstructsfromtemporary
+| 380 = @referenceconvertsfromtemporary
+| 381 = @isconvertible
+| 382 = @isvalidwinrttype
+| 383 = @iswinclass
+| 384 = @iswininterface
+| 385 = @istriviallyequalitycomparable
+| 386 = @isscopedenum
+| 387 = @istriviallyrelocatable
+| 388 = @datasizeof
+| 389 = @c11_generic
+| 390 = @requires_expr
+| 391 = @nested_requirement
+| 392 = @compound_requirement
+| 393 = @concept_id
+| 394 = @isinvocable
+| 395 = @isnothrowinvocable
+| 396 = @isbitwisecloneable
+;
+
+@var_args_expr = @vastartexpr
+ | @vaendexpr
+ | @vaargexpr
+ | @vacopyexpr
+ ;
+
+@builtin_op = @var_args_expr
+ | @noopexpr
+ | @offsetofexpr
+ | @intaddrexpr
+ | @hasassignexpr
+ | @hascopyexpr
+ | @hasnothrowassign
+ | @hasnothrowconstr
+ | @hasnothrowcopy
+ | @hastrivialassign
+ | @hastrivialconstr
+ | @hastrivialcopy
+ | @hastrivialdestructor
+ | @hasuserdestr
+ | @hasvirtualdestr
+ | @isabstractexpr
+ | @isbaseofexpr
+ | @isclassexpr
+ | @isconvtoexpr
+ | @isemptyexpr
+ | @isenumexpr
+ | @ispodexpr
+ | @ispolyexpr
+ | @isunionexpr
+ | @typescompexpr
+ | @builtinshufflevector
+ | @builtinconvertvector
+ | @builtinaddressof
+ | @istriviallyconstructibleexpr
+ | @isdestructibleexpr
+ | @isnothrowdestructibleexpr
+ | @istriviallydestructibleexpr
+ | @istriviallyassignableexpr
+ | @isnothrowassignableexpr
+ | @istrivialexpr
+ | @isstandardlayoutexpr
+ | @istriviallycopyableexpr
+ | @isliteraltypeexpr
+ | @hastrivialmoveconstructorexpr
+ | @hastrivialmoveassignexpr
+ | @hasnothrowmoveassignexpr
+ | @isconstructibleexpr
+ | @isnothrowconstructibleexpr
+ | @hasfinalizerexpr
+ | @isdelegateexpr
+ | @isinterfaceclassexpr
+ | @isrefarrayexpr
+ | @isrefclassexpr
+ | @issealedexpr
+ | @issimplevalueclassexpr
+ | @isvalueclassexpr
+ | @isfinalexpr
+ | @builtinchooseexpr
+ | @builtincomplex
+ | @isassignable
+ | @isaggregate
+ | @hasuniqueobjectrepresentations
+ | @builtinbitcast
+ | @builtinshuffle
+ | @issame
+ | @isfunction
+ | @islayoutcompatible
+ | @ispointerinterconvertiblebaseof
+ | @isarray
+ | @arrayrank
+ | @arrayextent
+ | @isarithmetic
+ | @iscompletetype
+ | @iscompound
+ | @isconst
+ | @isfloatingpoint
+ | @isfundamental
+ | @isintegral
+ | @islvaluereference
+ | @ismemberfunctionpointer
+ | @ismemberobjectpointer
+ | @ismemberpointer
+ | @isobject
+ | @ispointer
+ | @isreference
+ | @isrvaluereference
+ | @isscalar
+ | @issigned
+ | @isunsigned
+ | @isvoid
+ | @isvolatile
+ | @istriviallycopyassignable
+ | @isassignablenopreconditioncheck
+ | @referencebindstotemporary
+ | @issameas
+ | @builtinhasattribute
+ | @ispointerinterconvertiblewithclass
+ | @builtinispointerinterconvertiblewithclass
+ | @iscorrespondingmember
+ | @builtiniscorrespondingmember
+ | @isboundedarray
+ | @isunboundedarray
+ | @isreferenceable
+ | @isnothrowconvertible
+ | @referenceconstructsfromtemporary
+ | @referenceconvertsfromtemporary
+ | @isconvertible
+ | @isvalidwinrttype
+ | @iswinclass
+ | @iswininterface
+ | @istriviallyequalitycomparable
+ | @isscopedenum
+ | @istriviallyrelocatable
+ | @isinvocable
+ | @isnothrowinvocable
+ | @isbitwisecloneable
+ ;
+
+compound_requirement_is_noexcept(
+ int expr: @compound_requirement ref
+);
+
+new_allocated_type(
+ unique int expr: @new_expr ref,
+ int type_id: @type ref
+);
+
+new_array_allocated_type(
+ unique int expr: @new_array_expr ref,
+ int type_id: @type ref
+);
+
+param_ref_to_this(
+ int expr: @param_ref ref
+)
+
+/**
+ * The field being initialized by an initializer expression within an aggregate
+ * initializer for a class/struct/union. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_field_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int field: @membervariable ref,
+ int position: int ref,
+ boolean is_designated: boolean ref
+);
+
+/**
+ * The index of the element being initialized by an initializer expression
+ * within an aggregate initializer for an array. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_array_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int element_index: int ref,
+ int position: int ref,
+ boolean is_designated: boolean ref
+);
+
+@ctorinit = @ctordirectinit
+ | @ctorvirtualinit
+ | @ctorfieldinit
+ | @ctordelegatinginit;
+@dtordestruct = @dtordirectdestruct
+ | @dtorvirtualdestruct
+ | @dtorfielddestruct;
+
+
+condition_decl_bind(
+ unique int expr: @condition_decl ref,
+ unique int decl: @declaration ref
+);
+
+typeid_bind(
+ unique int expr: @type_id ref,
+ int type_id: @type ref
+);
+
+uuidof_bind(
+ unique int expr: @uuidof ref,
+ int type_id: @type ref
+);
+
+@sizeof_or_alignof = @runtime_sizeof | @runtime_alignof | @datasizeof | @sizeof_pack;
+
+sizeof_bind(
+ unique int expr: @sizeof_or_alignof ref,
+ int type_id: @type ref
+);
+
+code_block(
+ unique int block: @literal ref,
+ unique int routine: @function ref
+);
+
+lambdas(
+ unique int expr: @lambdaexpr ref,
+ string default_capture: string ref,
+ boolean has_explicit_return_type: boolean ref,
+ boolean has_explicit_parameter_list: boolean ref
+);
+
+lambda_capture(
+ unique int id: @lambdacapture,
+ int lambda: @lambdaexpr ref,
+ int index: int ref,
+ int field: @membervariable ref,
+ boolean captured_by_reference: boolean ref,
+ boolean is_implicit: boolean ref,
+ int location: @location_default ref
+);
+
+@funbindexpr = @routineexpr
+ | @new_expr
+ | @delete_expr
+ | @delete_array_expr
+ | @ctordirectinit
+ | @ctorvirtualinit
+ | @ctordelegatinginit
+ | @dtordirectdestruct
+ | @dtorvirtualdestruct;
+
+@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct;
+@addressable = @function | @variable ;
+@accessible = @addressable | @enumconstant ;
+
+@access = @varaccess | @routineexpr ;
+
+fold(
+ int expr: @foldexpr ref,
+ string operator: string ref,
+ boolean is_left_fold: boolean ref
+);
+
+stmts(
+ unique int id: @stmt,
+ int kind: int ref,
+ int location: @location_default ref
+);
+
+case @stmt.kind of
+ 1 = @stmt_expr
+| 2 = @stmt_if
+| 3 = @stmt_while
+| 4 = @stmt_goto
+| 5 = @stmt_label
+| 6 = @stmt_return
+| 7 = @stmt_block
+| 8 = @stmt_end_test_while // do { ... } while ( ... )
+| 9 = @stmt_for
+| 10 = @stmt_switch_case
+| 11 = @stmt_switch
+| 13 = @stmt_asm // "asm" statement or the body of an asm function
+| 15 = @stmt_try_block
+| 16 = @stmt_microsoft_try // Microsoft
+| 17 = @stmt_decl
+| 18 = @stmt_set_vla_size // C99
+| 19 = @stmt_vla_decl // C99
+| 25 = @stmt_assigned_goto // GNU
+| 26 = @stmt_empty
+| 27 = @stmt_continue
+| 28 = @stmt_break
+| 29 = @stmt_range_based_for // C++11
+// ... 30 @stmt_at_autoreleasepool_block deprecated
+// ... 31 @stmt_objc_for_in deprecated
+// ... 32 @stmt_at_synchronized deprecated
+| 33 = @stmt_handler
+// ... 34 @stmt_finally_end deprecated
+| 35 = @stmt_constexpr_if
+| 37 = @stmt_co_return
+| 38 = @stmt_consteval_if
+| 39 = @stmt_not_consteval_if
+| 40 = @stmt_leave
+;
+
+type_vla(
+ int type_id: @type ref,
+ int decl: @stmt_vla_decl ref
+);
+
+variable_vla(
+ int var: @variable ref,
+ int decl: @stmt_vla_decl ref
+);
+
+type_is_vla(unique int type_id: @derivedtype ref)
+
+if_initialization(
+ unique int if_stmt: @stmt_if ref,
+ int init_id: @stmt ref
+);
+
+if_then(
+ unique int if_stmt: @stmt_if ref,
+ int then_id: @stmt ref
+);
+
+if_else(
+ unique int if_stmt: @stmt_if ref,
+ int else_id: @stmt ref
+);
+
+constexpr_if_initialization(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int init_id: @stmt ref
+);
+
+constexpr_if_then(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int then_id: @stmt ref
+);
+
+constexpr_if_else(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int else_id: @stmt ref
+);
+
+@stmt_consteval_or_not_consteval_if = @stmt_consteval_if | @stmt_not_consteval_if;
+
+consteval_if_then(
+ unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref,
+ int then_id: @stmt ref
+);
+
+consteval_if_else(
+ unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref,
+ int else_id: @stmt ref
+);
+
+while_body(
+ unique int while_stmt: @stmt_while ref,
+ int body_id: @stmt ref
+);
+
+do_body(
+ unique int do_stmt: @stmt_end_test_while ref,
+ int body_id: @stmt ref
+);
+
+switch_initialization(
+ unique int switch_stmt: @stmt_switch ref,
+ int init_id: @stmt ref
+);
+
+#keyset[switch_stmt, index]
+switch_case(
+ int switch_stmt: @stmt_switch ref,
+ int index: int ref,
+ int case_id: @stmt_switch_case ref
+);
+
+switch_body(
+ unique int switch_stmt: @stmt_switch ref,
+ int body_id: @stmt ref
+);
+
+@stmt_for_or_range_based_for = @stmt_for
+ | @stmt_range_based_for;
+
+for_initialization(
+ unique int for_stmt: @stmt_for_or_range_based_for ref,
+ int init_id: @stmt ref
+);
+
+for_condition(
+ unique int for_stmt: @stmt_for ref,
+ int condition_id: @expr ref
+);
+
+for_update(
+ unique int for_stmt: @stmt_for ref,
+ int update_id: @expr ref
+);
+
+for_body(
+ unique int for_stmt: @stmt_for ref,
+ int body_id: @stmt ref
+);
+
+@stmtparent = @stmt | @expr_stmt ;
+stmtparents(
+ unique int id: @stmt ref,
+ int index: int ref,
+ int parent: @stmtparent ref
+);
+
+ishandler(unique int block: @stmt_block ref);
+
+@cfgnode = @stmt | @expr | @function | @initialiser ;
+
+stmt_decl_bind(
+ int stmt: @stmt_decl ref,
+ int num: int ref,
+ int decl: @declaration ref
+);
+
+stmt_decl_entry_bind(
+ int stmt: @stmt_decl ref,
+ int num: int ref,
+ int decl_entry: @element ref
+);
+
+@parameterized_element = @function | @stmt_block | @requires_expr;
+
+blockscope(
+ unique int block: @stmt_block ref,
+ int enclosing: @parameterized_element ref
+);
+
+@jump = @stmt_goto | @stmt_break | @stmt_continue | @stmt_leave;
+
+@jumporlabel = @jump | @stmt_label | @literal;
+
+jumpinfo(
+ unique int id: @jumporlabel ref,
+ string str: string ref,
+ int target: @stmt ref
+);
+
+preprocdirects(
+ unique int id: @preprocdirect,
+ int kind: int ref,
+ int location: @location_default ref
+);
+case @preprocdirect.kind of
+ 0 = @ppd_if
+| 1 = @ppd_ifdef
+| 2 = @ppd_ifndef
+| 3 = @ppd_elif
+| 4 = @ppd_else
+| 5 = @ppd_endif
+| 6 = @ppd_plain_include
+| 7 = @ppd_define
+| 8 = @ppd_undef
+| 9 = @ppd_line
+| 10 = @ppd_error
+| 11 = @ppd_pragma
+| 12 = @ppd_objc_import
+| 13 = @ppd_include_next
+| 14 = @ppd_ms_import
+| 15 = @ppd_elifdef
+| 16 = @ppd_elifndef
+| 17 = @ppd_embed
+| 18 = @ppd_warning
+;
+
+@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next | @ppd_ms_import;
+
+@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif | @ppd_elifdef | @ppd_elifndef;
+
+preprocpair(
+ int begin : @ppd_branch ref,
+ int elseelifend : @preprocdirect ref
+);
+
+preproctrue(int branch : @ppd_branch ref);
+preprocfalse(int branch : @ppd_branch ref);
+
+preproctext(
+ unique int id: @preprocdirect ref,
+ string head: string ref,
+ string body: string ref
+);
+
+includes(
+ unique int id: @ppd_include ref,
+ int included: @file ref
+);
+
+embeds(
+ unique int id: @ppd_embed ref,
+ int included: @file ref
+);
+
+link_targets(
+ int id: @link_target,
+ int binary: @file ref
+);
+
+link_parent(
+ int element : @element ref,
+ int link_target : @link_target ref
+);
+
+/*- Database metadata -*/
+
+/**
+ * The CLI will automatically emit applicable tuples for this table,
+ * such as `databaseMetadata("isOverlay", "true")` when building an
+ * overlay database.
+ */
+databaseMetadata(
+ string metadataKey: string ref,
+ string value: string ref
+);
+
+/*- Overlay support -*/
+
+/**
+ * The CLI will automatically emit tuples for each new/modified/deleted file
+ * when building an overlay database.
+ */
+overlayChangedFiles(
+ string path: string ref
+);
+
+/*- XML Files -*/
+
+xmlEncoding(
+ unique int id: @file ref,
+ string encoding: string ref
+);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref
+);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref
+);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref
+);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref
+);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref
+);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref
+);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref
+);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref
+);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
diff --git a/cpp/ql/lib/upgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/semmlecode.cpp.dbscheme b/cpp/ql/lib/upgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/semmlecode.cpp.dbscheme
new file mode 100644
index 00000000000..770002bb023
--- /dev/null
+++ b/cpp/ql/lib/upgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/semmlecode.cpp.dbscheme
@@ -0,0 +1,2545 @@
+
+/*- Compilations -*/
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ /**
+ * An invocation of the compiler. Note that more than one file may
+ * be compiled per invocation. For example, this command compiles
+ * three source files:
+ *
+ * gcc -c f1.c f2.c f3.c
+ */
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | *path to extractor*
+ * 1 | `--mimic`
+ * 2 | `/usr/bin/gcc`
+ * 3 | `-c`
+ * 4 | f1.c
+ * 5 | f2.c
+ * 6 | f3.c
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The expanded arguments that were passed to the extractor for a
+ * compiler invocation. This is similar to `compilation_args`, but
+ * for a `@someFile` argument, it includes the arguments from that
+ * file, rather than just taking the argument literally.
+ */
+#keyset[id, num]
+compilation_expanded_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * Optionally, record the build mode for each compilation.
+ */
+compilation_build_mode(
+ unique int id : @compilation ref,
+ int mode : int ref
+);
+
+/*
+case @compilation_build_mode.mode of
+ 0 = @build_mode_none
+| 1 = @build_mode_manual
+| 2 = @build_mode_auto
+;
+*/
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * gcc -c f1.c f2.c f3.c
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.c
+ * 1 | f2.c
+ * 2 | f3.c
+ *
+ * Note that even if those files `#include` headers, those headers
+ * do not appear as rows.
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+/*- External data -*/
+
+/**
+ * External data, loaded from CSV files during snapshot creation. See
+ * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data)
+ * for more information.
+ */
+externalData(
+ int id : @externalDataElement,
+ string path : string ref,
+ int column: int ref,
+ string value : string ref
+);
+
+/*- Source location prefix -*/
+
+/**
+ * The source location of the snapshot.
+ */
+sourceLocationPrefix(string prefix : string ref);
+
+/*- Files and folders -*/
+
+/**
+ * The location of an element.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref
+);
+
+files(
+ unique int id: @file,
+ string name: string ref
+);
+
+folders(
+ unique int id: @folder,
+ string name: string ref
+);
+
+@container = @file | @folder
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref
+);
+
+/*- Lines of code -*/
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref
+);
+
+/*- Diagnostic messages -*/
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location_default ref
+);
+
+/*- C++ dbscheme -*/
+
+extractor_version(
+ string codeql_version: string ref,
+ string frontend_version: string ref
+)
+
+/**
+ * Gives the TRAP filename that `trap` is associated with.
+ * For debugging only.
+ */
+trap_filename(
+ int trap: @trap,
+ string filename: string ref
+);
+
+/**
+ * Gives the tag name for `tag`.
+ * For debugging only.
+ */
+tag_name(
+ int tag: @tag,
+ string name: string ref
+);
+
+@trap_or_tag = @tag | @trap;
+
+/**
+ * Gives the name for the source file.
+ */
+source_file_name(
+ int sf: @source_file,
+ string name: string ref
+);
+
+/**
+ * In `build-mode: none` overlay mode, indicates that `source_file`
+ * (`/path/to/foo.c`) uses the TRAP file `trap_file`; i.e. it is the
+ * TRAP file corresponding to `foo.c`, something it transitively
+ * includes, or a template instantiation it transitively uses.
+ */
+source_file_uses_trap(
+ int source_file: @source_file ref,
+ int trap_file: @trap ref
+);
+
+/**
+ * In `build-mode: none` overlay mode, indicates that the TRAP file
+ * `trap_file` uses tag `tag`.
+ */
+trap_uses_tag(
+ int trap_file: @trap ref,
+ int tag: @tag ref
+);
+
+/**
+ * Holds if there is a definition of `element` in TRAP file or tag `t`.
+ */
+in_trap_or_tag(
+ int element: @element ref,
+ int t: @trap_or_tag ref
+);
+
+pch_uses(
+ int pch: @pch ref,
+ int compilation: @compilation ref,
+ int id: @file ref
+)
+
+#keyset[pch, compilation]
+pch_creations(
+ int pch: @pch,
+ int compilation: @compilation ref,
+ int from: @file ref
+)
+
+/** An element for which line-count information is available. */
+@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable;
+
+fileannotations(
+ int id: @file ref,
+ int kind: int ref,
+ string name: string ref,
+ string value: string ref
+);
+
+inmacroexpansion(
+ int id: @element ref,
+ int inv: @macroinvocation ref
+);
+
+affectedbymacroexpansion(
+ int id: @element ref,
+ int inv: @macroinvocation ref
+);
+
+case @macroinvocation.kind of
+ 1 = @macro_expansion
+| 2 = @other_macro_reference
+;
+
+macroinvocations(
+ unique int id: @macroinvocation,
+ int macro_id: @ppd_define ref,
+ int location: @location_default ref,
+ int kind: int ref
+);
+
+macroparent(
+ unique int id: @macroinvocation ref,
+ int parent_id: @macroinvocation ref
+);
+
+// a macroinvocation may be part of another location
+// the way to find a constant expression that uses a macro
+// is thus to find a constant expression that has a location
+// to which a macro invocation is bound
+macrolocationbind(
+ int id: @macroinvocation ref,
+ int location: @location_default ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_unexpanded(
+ int invocation: @macroinvocation ref,
+ int argument_index: int ref,
+ string text: string ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_expanded(
+ int invocation: @macroinvocation ref,
+ int argument_index: int ref,
+ string text: string ref
+);
+
+case @function.kind of
+ 0 = @unknown_function
+| 1 = @normal_function
+| 2 = @constructor
+| 3 = @destructor
+| 4 = @conversion_function
+| 5 = @operator
+// ... 6 = @builtin_function deprecated // GCC built-in functions, e.g. __builtin___memcpy_chk
+| 7 = @user_defined_literal
+| 8 = @deduction_guide
+;
+
+functions(
+ unique int id: @function,
+ string name: string ref,
+ int kind: int ref
+);
+
+builtin_functions(
+ int id: @function ref
+)
+
+function_entry_point(
+ int id: @function ref,
+ unique int entry_point: @stmt ref
+);
+
+function_return_type(
+ int id: @function ref,
+ int return_type: @type ref
+);
+
+/**
+ * If `function` is a coroutine, then this gives the `std::experimental::resumable_traits`
+ * instance associated with it, and the variables representing the `handle` and `promise`
+ * for it.
+ */
+coroutine(
+ unique int function: @function ref,
+ int traits: @type ref
+);
+
+/*
+case @coroutine_placeholder_variable.kind of
+ 1 = @handle
+| 2 = @promise
+| 3 = @init_await_resume
+;
+*/
+
+coroutine_placeholder_variable(
+ unique int placeholder_variable: @variable ref,
+ int kind: int ref,
+ int function: @function ref
+)
+
+/** The `new` function used for allocating the coroutine state, if any. */
+coroutine_new(
+ unique int function: @function ref,
+ int new: @function ref
+);
+
+/** The `delete` function used for deallocating the coroutine state, if any. */
+coroutine_delete(
+ unique int function: @function ref,
+ int delete: @function ref
+);
+
+purefunctions(unique int id: @function ref);
+
+function_deleted(unique int id: @function ref);
+
+function_defaulted(unique int id: @function ref);
+
+function_prototyped(unique int id: @function ref)
+
+deduction_guide_for_class(
+ int id: @function ref,
+ int class_template: @usertype ref
+)
+
+member_function_this_type(
+ unique int id: @function ref,
+ int this_type: @type ref
+);
+
+#keyset[id, type_id]
+fun_decls(
+ int id: @fun_decl,
+ int function: @function ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+fun_def(unique int id: @fun_decl ref);
+fun_specialized(unique int id: @fun_decl ref);
+fun_implicit(unique int id: @fun_decl ref);
+fun_decl_specifiers(
+ int id: @fun_decl ref,
+ string name: string ref
+)
+#keyset[fun_decl, index]
+fun_decl_throws(
+ int fun_decl: @fun_decl ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+/* an empty throw specification is different from none */
+fun_decl_empty_throws(unique int fun_decl: @fun_decl ref);
+fun_decl_noexcept(
+ int fun_decl: @fun_decl ref,
+ int constant: @expr ref
+);
+fun_decl_empty_noexcept(int fun_decl: @fun_decl ref);
+fun_decl_typedef_type(
+ unique int fun_decl: @fun_decl ref,
+ int typedeftype_id: @usertype ref
+);
+
+/*
+case @fun_requires.kind of
+ 1 = @template_attached
+| 2 = @function_attached
+;
+*/
+
+fun_requires(
+ int id: @fun_decl ref,
+ int kind: int ref,
+ int constraint: @expr ref
+);
+
+param_decl_bind(
+ unique int id: @var_decl ref,
+ int index: int ref,
+ int fun_decl: @fun_decl ref
+);
+
+#keyset[id, type_id]
+var_decls(
+ int id: @var_decl,
+ int variable: @variable ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+var_def(unique int id: @var_decl ref);
+var_specialized(int id: @var_decl ref);
+var_decl_specifiers(
+ int id: @var_decl ref,
+ string name: string ref
+)
+is_structured_binding(unique int id: @variable ref);
+var_requires(
+ int id: @var_decl ref,
+ int constraint: @expr ref
+);
+
+type_decls(
+ unique int id: @type_decl,
+ int type_id: @type ref,
+ int location: @location_default ref
+);
+type_def(unique int id: @type_decl ref);
+type_decl_top(
+ unique int type_decl: @type_decl ref
+);
+type_requires(
+ int id: @type_decl ref,
+ int constraint: @expr ref
+);
+
+namespace_decls(
+ unique int id: @namespace_decl,
+ int namespace_id: @namespace ref,
+ int location: @location_default ref,
+ int bodylocation: @location_default ref
+);
+
+case @using.kind of
+ 1 = @using_declaration
+| 2 = @using_directive
+| 3 = @using_enum_declaration
+;
+
+usings(
+ unique int id: @using,
+ int element_id: @element ref,
+ int location: @location_default ref,
+ int kind: int ref
+);
+
+/** The element which contains the `using` declaration. */
+using_container(
+ int parent: @element ref,
+ int child: @using ref
+);
+
+static_asserts(
+ unique int id: @static_assert,
+ int condition : @expr ref,
+ string message : string ref,
+ int location: @location_default ref,
+ int enclosing : @element ref
+);
+
+// each function has an ordered list of parameters
+#keyset[id, type_id]
+#keyset[function, index, type_id]
+params(
+ int id: @parameter,
+ int function: @parameterized_element ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+
+overrides(
+ int new: @function ref,
+ int old: @function ref
+);
+
+#keyset[id, type_id]
+membervariables(
+ int id: @membervariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+#keyset[id, type_id]
+globalvariables(
+ int id: @globalvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+#keyset[id, type_id]
+localvariables(
+ int id: @localvariable,
+ int type_id: @type ref,
+ string name: string ref
+);
+
+autoderivation(
+ unique int var: @variable ref,
+ int derivation_type: @type ref
+);
+
+orphaned_variables(
+ int var: @localvariable ref,
+ int function: @function ref
+)
+
+enumconstants(
+ unique int id: @enumconstant,
+ int parent: @usertype ref,
+ int index: int ref,
+ int type_id: @type ref,
+ string name: string ref,
+ int location: @location_default ref
+);
+
+@variable = @localscopevariable | @globalvariable | @membervariable;
+
+@localscopevariable = @localvariable | @parameter;
+
+/**
+ * Built-in types are the fundamental types, e.g., integral, floating, and void.
+ */
+case @builtintype.kind of
+ 1 = @errortype
+| 2 = @unknowntype
+| 3 = @void
+| 4 = @boolean
+| 5 = @char
+| 6 = @unsigned_char
+| 7 = @signed_char
+| 8 = @short
+| 9 = @unsigned_short
+| 10 = @signed_short
+| 11 = @int
+| 12 = @unsigned_int
+| 13 = @signed_int
+| 14 = @long
+| 15 = @unsigned_long
+| 16 = @signed_long
+| 17 = @long_long
+| 18 = @unsigned_long_long
+| 19 = @signed_long_long
+// ... 20 Microsoft-specific __int8
+// ... 21 Microsoft-specific __int16
+// ... 22 Microsoft-specific __int32
+// ... 23 Microsoft-specific __int64
+| 24 = @float
+| 25 = @double
+| 26 = @long_double
+| 27 = @complex_float // C99-specific _Complex float
+| 28 = @complex_double // C99-specific _Complex double
+| 29 = @complex_long_double // C99-specific _Complex long double
+| 30 = @imaginary_float // C99-specific _Imaginary float
+| 31 = @imaginary_double // C99-specific _Imaginary double
+| 32 = @imaginary_long_double // C99-specific _Imaginary long double
+| 33 = @wchar_t // Microsoft-specific
+| 34 = @decltype_nullptr // C++11
+| 35 = @int128 // __int128
+| 36 = @unsigned_int128 // unsigned __int128
+| 37 = @signed_int128 // signed __int128
+| 38 = @float128 // __float128
+| 39 = @complex_float128 // _Complex __float128
+// ... 40 _Decimal32
+// ... 41 _Decimal64
+// ... 42 _Decimal128
+| 43 = @char16_t
+| 44 = @char32_t
+| 45 = @std_float32 // _Float32
+| 46 = @float32x // _Float32x
+| 47 = @std_float64 // _Float64
+| 48 = @float64x // _Float64x
+| 49 = @std_float128 // _Float128
+// ... 50 _Float128x
+| 51 = @char8_t
+| 52 = @float16 // _Float16
+| 53 = @complex_float16 // _Complex _Float16
+| 54 = @fp16 // __fp16
+| 55 = @std_bfloat16 // __bf16
+| 56 = @std_float16 // std::float16_t
+| 57 = @complex_std_float32 // _Complex _Float32
+| 58 = @complex_float32x // _Complex _Float32x
+| 59 = @complex_std_float64 // _Complex _Float64
+| 60 = @complex_float64x // _Complex _Float64x
+| 61 = @complex_std_float128 // _Complex _Float128
+| 62 = @mfp8 // __mfp8
+| 63 = @scalable_vector_count // __SVCount_t
+| 64 = @complex_fp16 // _Complex __fp16
+| 65 = @complex_std_bfloat16 // _Complex __bf16
+| 66 = @complex_std_float16 // _Complex std::float16_t
+;
+
+builtintypes(
+ unique int id: @builtintype,
+ string name: string ref,
+ int kind: int ref,
+ int size: int ref,
+ int sign: int ref,
+ int alignment: int ref
+);
+
+/**
+ * Derived types are types that are directly derived from existing types and
+ * point to, refer to, transform type data to return a new type.
+ */
+case @derivedtype.kind of
+ 1 = @pointer
+| 2 = @reference
+| 3 = @type_with_specifiers
+| 4 = @array
+| 5 = @gnu_vector
+| 6 = @routineptr
+| 7 = @routinereference
+| 8 = @rvalue_reference // C++11
+// ... 9 type_conforming_to_protocols deprecated
+| 10 = @block
+| 11 = @scalable_vector // Arm SVE
+;
+
+derivedtypes(
+ unique int id: @derivedtype,
+ string name: string ref,
+ int kind: int ref,
+ int type_id: @type ref
+);
+
+pointerishsize(unique int id: @derivedtype ref,
+ int size: int ref,
+ int alignment: int ref);
+
+arraysizes(
+ unique int id: @derivedtype ref,
+ int num_elements: int ref,
+ int bytesize: int ref,
+ int alignment: int ref
+);
+
+tupleelements(
+ unique int id: @derivedtype ref,
+ int num_elements: int ref
+);
+
+typedefbase(
+ unique int id: @usertype ref,
+ int type_id: @type ref
+);
+
+/**
+ * An instance of the C++11 `decltype` operator or C23 `typeof`/`typeof_unqual`
+ * operator taking an expression as its argument. For example:
+ * ```
+ * int a;
+ * decltype(1+a) b;
+ * typeof(1+a) c;
+ * ```
+ * Here `expr` is `1+a`.
+ *
+ * Sometimes an additional pair of parentheses around the expression
+ * changes the semantics of the decltype, e.g.
+ * ```
+ * struct A { double x; };
+ * const A* a = new A();
+ * decltype( a->x ); // type is double
+ * decltype((a->x)); // type is const double&
+ * ```
+ * (Please consult the C++11 standard for more details).
+ * `parentheses_would_change_meaning` is `true` iff that is the case.
+ */
+
+/*
+case @decltype.kind of
+| 0 = @decltype
+| 1 = @typeof // The frontend does not differentiate between typeof and typeof_unqual
+;
+*/
+
+#keyset[id, expr]
+decltypes(
+ int id: @decltype,
+ int expr: @expr ref,
+ int kind: int ref,
+ int base_type: @type ref,
+ boolean parentheses_would_change_meaning: boolean ref
+);
+
+case @type_operator.kind of
+ 0 = @typeof // The frontend does not differentiate between typeof and typeof_unqual
+| 1 = @underlying_type
+| 2 = @bases
+| 3 = @direct_bases
+| 4 = @add_lvalue_reference
+| 5 = @add_pointer
+| 6 = @add_rvalue_reference
+| 7 = @decay
+| 8 = @make_signed
+| 9 = @make_unsigned
+| 10 = @remove_all_extents
+| 11 = @remove_const
+| 12 = @remove_cv
+| 13 = @remove_cvref
+| 14 = @remove_extent
+| 15 = @remove_pointer
+| 16 = @remove_reference_t
+| 17 = @remove_restrict
+| 18 = @remove_volatile
+| 19 = @remove_reference
+;
+
+type_operators(
+ unique int id: @type_operator,
+ int arg_type: @type ref,
+ int kind: int ref,
+ int base_type: @type ref
+)
+
+case @usertype.kind of
+ 0 = @unknown_usertype
+| 1 = @struct
+| 2 = @class
+| 3 = @union
+| 4 = @enum
+// ... 5 = @typedef deprecated // classic C: typedef typedef type name
+// ... 6 = @template deprecated
+| 7 = @template_parameter
+| 8 = @template_template_parameter
+| 9 = @proxy_class // a proxy class associated with a template parameter
+// ... 10 objc_class deprecated
+// ... 11 objc_protocol deprecated
+// ... 12 objc_category deprecated
+| 13 = @scoped_enum
+// ... 14 = @using_alias deprecated // a using name = type style typedef
+| 15 = @template_struct
+| 16 = @template_class
+| 17 = @template_union
+| 18 = @alias
+;
+
+usertypes(
+ unique int id: @usertype,
+ string name: string ref,
+ int kind: int ref
+);
+
+usertypesize(
+ unique int id: @usertype ref,
+ int size: int ref,
+ int alignment: int ref
+);
+
+usertype_final(unique int id: @usertype ref);
+
+usertype_uuid(
+ unique int id: @usertype ref,
+ string uuid: string ref
+);
+
+/*
+case @usertype.alias_kind of
+| 0 = @typedef
+| 1 = @alias
+*/
+
+usertype_alias_kind(
+ int id: @usertype ref,
+ int alias_kind: int ref
+)
+
+nontype_template_parameters(
+ int id: @expr ref
+);
+
+type_template_type_constraint(
+ int id: @usertype ref,
+ int constraint: @expr ref
+);
+
+mangled_name(
+ unique int id: @declaration ref,
+ int mangled_name : @mangledname,
+ boolean is_complete: boolean ref
+);
+
+is_pod_class(unique int id: @usertype ref);
+is_standard_layout_class(unique int id: @usertype ref);
+
+is_complete(unique int id: @usertype ref);
+
+is_class_template(unique int id: @usertype ref);
+class_instantiation(
+ int to: @usertype ref,
+ int from: @usertype ref
+);
+class_template_argument(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+class_template_argument_value(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+@user_or_decltype = @usertype | @decltype;
+
+is_proxy_class_for(
+ unique int id: @usertype ref,
+ int templ_param_id: @user_or_decltype ref
+);
+
+type_mentions(
+ unique int id: @type_mention,
+ int type_id: @type ref,
+ int location: @location_default ref,
+ // a_symbol_reference_kind from the frontend.
+ int kind: int ref
+);
+
+is_function_template(unique int id: @function ref);
+function_instantiation(
+ unique int to: @function ref,
+ int from: @function ref
+);
+function_template_argument(
+ int function_id: @function ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+function_template_argument_value(
+ int function_id: @function ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+is_variable_template(unique int id: @variable ref);
+variable_instantiation(
+ unique int to: @variable ref,
+ int from: @variable ref
+);
+variable_template_argument(
+ int variable_id: @variable ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+variable_template_argument_value(
+ int variable_id: @variable ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+template_template_instantiation(
+ int to: @usertype ref,
+ int from: @usertype ref
+);
+template_template_argument(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+template_template_argument_value(
+ int type_id: @usertype ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+@concept = @concept_template | @concept_id;
+
+concept_templates(
+ unique int concept_id: @concept_template,
+ string name: string ref,
+ int location: @location_default ref
+);
+concept_instantiation(
+ unique int to: @concept_id ref,
+ int from: @concept_template ref
+);
+is_type_constraint(int concept_id: @concept_id ref);
+concept_template_argument(
+ int concept_id: @concept ref,
+ int index: int ref,
+ int arg_type: @type ref
+);
+concept_template_argument_value(
+ int concept_id: @concept ref,
+ int index: int ref,
+ int arg_value: @expr ref
+);
+
+routinetypes(
+ unique int id: @routinetype,
+ int return_type: @type ref
+);
+
+routinetypeargs(
+ int routine: @routinetype ref,
+ int index: int ref,
+ int type_id: @type ref
+);
+
+ptrtomembers(
+ unique int id: @ptrtomember,
+ int type_id: @type ref,
+ int class_id: @type ref
+);
+
+/*
+ specifiers for types, functions, and variables
+
+ "public",
+ "protected",
+ "private",
+
+ "const",
+ "volatile",
+ "static",
+
+ "pure",
+ "virtual",
+ "sealed", // Microsoft
+ "__interface", // Microsoft
+ "inline",
+ "explicit",
+
+ "near", // near far extension
+ "far", // near far extension
+ "__ptr32", // Microsoft
+ "__ptr64", // Microsoft
+ "__sptr", // Microsoft
+ "__uptr", // Microsoft
+ "dllimport", // Microsoft
+ "dllexport", // Microsoft
+ "thread", // Microsoft
+ "naked", // Microsoft
+ "microsoft_inline", // Microsoft
+ "forceinline", // Microsoft
+ "selectany", // Microsoft
+ "nothrow", // Microsoft
+ "novtable", // Microsoft
+ "noreturn", // Microsoft
+ "noinline", // Microsoft
+ "noalias", // Microsoft
+ "restrict", // Microsoft
+*/
+
+specifiers(
+ unique int id: @specifier,
+ unique string str: string ref
+);
+
+typespecifiers(
+ int type_id: @type ref,
+ int spec_id: @specifier ref
+);
+
+funspecifiers(
+ int func_id: @function ref,
+ int spec_id: @specifier ref
+);
+
+varspecifiers(
+ int var_id: @accessible ref,
+ int spec_id: @specifier ref
+);
+
+explicit_specifier_exprs(
+ unique int func_id: @function ref,
+ int constant: @expr ref
+)
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ string name: string ref,
+ string name_space: string ref,
+ int location: @location_default ref
+);
+
+case @attribute.kind of
+ 0 = @gnuattribute
+| 1 = @stdattribute
+| 2 = @declspec
+| 3 = @msattribute
+| 4 = @alignas
+// ... 5 @objc_propertyattribute deprecated
+;
+
+attribute_args(
+ unique int id: @attribute_arg,
+ int kind: int ref,
+ int attribute: @attribute ref,
+ int index: int ref,
+ int location: @location_default ref
+);
+
+case @attribute_arg.kind of
+ 0 = @attribute_arg_empty
+| 1 = @attribute_arg_token
+| 2 = @attribute_arg_constant
+| 3 = @attribute_arg_type
+| 4 = @attribute_arg_constant_expr
+| 5 = @attribute_arg_expr
+;
+
+attribute_arg_value(
+ unique int arg: @attribute_arg ref,
+ string value: string ref
+);
+attribute_arg_type(
+ unique int arg: @attribute_arg ref,
+ int type_id: @type ref
+);
+attribute_arg_constant(
+ unique int arg: @attribute_arg ref,
+ int constant: @expr ref
+)
+attribute_arg_expr(
+ unique int arg: @attribute_arg ref,
+ int expr: @expr ref
+)
+attribute_arg_name(
+ unique int arg: @attribute_arg ref,
+ string name: string ref
+);
+
+typeattributes(
+ int type_id: @type ref,
+ int spec_id: @attribute ref
+);
+
+funcattributes(
+ int func_id: @function ref,
+ int spec_id: @attribute ref
+);
+
+varattributes(
+ int var_id: @accessible ref,
+ int spec_id: @attribute ref
+);
+
+namespaceattributes(
+ int namespace_id: @namespace ref,
+ int spec_id: @attribute ref
+);
+
+stmtattributes(
+ int stmt_id: @stmt ref,
+ int spec_id: @attribute ref
+);
+
+@type = @builtintype
+ | @derivedtype
+ | @usertype
+ | @routinetype
+ | @ptrtomember
+ | @decltype
+ | @type_operator;
+
+unspecifiedtype(
+ unique int type_id: @type ref,
+ int unspecified_type_id: @type ref
+);
+
+member(
+ int parent: @type ref,
+ int index: int ref,
+ int child: @member ref
+);
+
+@enclosingfunction_child = @usertype | @variable | @namespace
+
+enclosingfunction(
+ unique int child: @enclosingfunction_child ref,
+ int parent: @function ref
+);
+
+derivations(
+ unique int derivation: @derivation,
+ int sub: @type ref,
+ int index: int ref,
+ int super: @type ref,
+ int location: @location_default ref
+);
+
+derspecifiers(
+ int der_id: @derivation ref,
+ int spec_id: @specifier ref
+);
+
+/**
+ * Contains the byte offset of the base class subobject within the derived
+ * class. Only holds for non-virtual base classes, but see table
+ * `virtual_base_offsets` for offsets of virtual base class subobjects.
+ */
+direct_base_offsets(
+ unique int der_id: @derivation ref,
+ int offset: int ref
+);
+
+/**
+ * Contains the byte offset of the virtual base class subobject for class
+ * `super` within a most-derived object of class `sub`. `super` can be either a
+ * direct or indirect base class.
+ */
+#keyset[sub, super]
+virtual_base_offsets(
+ int sub: @usertype ref,
+ int super: @usertype ref,
+ int offset: int ref
+);
+
+frienddecls(
+ unique int id: @frienddecl,
+ int type_id: @type ref,
+ int decl_id: @declaration ref,
+ int location: @location_default ref
+);
+
+@declaredtype = @usertype ;
+
+@declaration = @function
+ | @declaredtype
+ | @variable
+ | @enumconstant
+ | @frienddecl
+ | @concept_template;
+
+@member = @membervariable
+ | @function
+ | @declaredtype
+ | @enumconstant;
+
+@locatable = @diagnostic
+ | @declaration
+ | @ppd_include
+ | @ppd_define
+ | @macroinvocation
+ /*| @funcall*/
+ | @xmllocatable
+ | @attribute
+ | @attribute_arg;
+
+@namedscope = @namespace | @usertype;
+
+@element = @locatable
+ | @file
+ | @folder
+ | @specifier
+ | @type
+ | @expr
+ | @namespace
+ | @initialiser
+ | @stmt
+ | @derivation
+ | @comment
+ | @preprocdirect
+ | @fun_decl
+ | @var_decl
+ | @type_decl
+ | @namespace_decl
+ | @using
+ | @namequalifier
+ | @specialnamequalifyingelement
+ | @static_assert
+ | @type_mention
+ | @lambdacapture;
+
+@exprparent = @element;
+
+comments(
+ unique int id: @comment,
+ string contents: string ref,
+ int location: @location_default ref
+);
+
+commentbinding(
+ int id: @comment ref,
+ int element: @element ref
+);
+
+exprconv(
+ int converted: @expr ref,
+ unique int conversion: @expr ref
+);
+
+compgenerated(unique int id: @element ref);
+
+/**
+ * `destructor_call` destructs the `i`'th entity that should be
+ * destructed following `element`. Note that entities should be
+ * destructed in reverse construction order, so for a given `element`
+ * these should be called from highest to lowest `i`.
+ */
+#keyset[element, destructor_call]
+#keyset[element, i]
+synthetic_destructor_call(
+ int element: @element ref,
+ int i: int ref,
+ int destructor_call: @routineexpr ref
+);
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref
+);
+
+namespace_inline(
+ unique int id: @namespace ref
+);
+
+namespacembrs(
+ int parentid: @namespace ref,
+ unique int memberid: @namespacembr ref
+);
+
+@namespacembr = @declaration | @namespace;
+
+exprparents(
+ int expr_id: @expr ref,
+ int child_index: int ref,
+ int parent_id: @exprparent ref
+);
+
+expr_isload(unique int expr_id: @expr ref);
+
+@cast = @c_style_cast
+ | @const_cast
+ | @dynamic_cast
+ | @reinterpret_cast
+ | @static_cast
+ ;
+
+/*
+case @conversion.kind of
+ 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast
+| 1 = @bool_conversion // conversion to 'bool'
+| 2 = @base_class_conversion // a derived-to-base conversion
+| 3 = @derived_class_conversion // a base-to-derived conversion
+| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member
+| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member
+| 6 = @glvalue_adjust // an adjustment of the type of a glvalue
+| 7 = @prvalue_adjust // an adjustment of the type of a prvalue
+;
+*/
+/**
+ * Describes the semantics represented by a cast expression. This is largely
+ * independent of the source syntax of the cast, so it is separate from the
+ * regular expression kind.
+ */
+conversionkinds(
+ unique int expr_id: @cast ref,
+ int kind: int ref
+);
+
+@conversion = @cast
+ | @array_to_pointer
+ | @parexpr
+ | @reference_to
+ | @ref_indirect
+ | @temp_init
+ | @c11_generic
+ ;
+
+/*
+case @funbindexpr.kind of
+ 0 = @normal_call // a normal call
+| 1 = @virtual_call // a virtual call
+| 2 = @adl_call // a call whose target is only found by ADL
+;
+*/
+iscall(
+ unique int caller: @funbindexpr ref,
+ int kind: int ref
+);
+
+numtemplatearguments(
+ unique int expr_id: @expr ref,
+ int num: int ref
+);
+
+specialnamequalifyingelements(
+ unique int id: @specialnamequalifyingelement,
+ unique string name: string ref
+);
+
+@namequalifiableelement = @expr | @namequalifier;
+@namequalifyingelement = @namespace
+ | @specialnamequalifyingelement
+ | @usertype
+ | @decltype;
+
+namequalifiers(
+ unique int id: @namequalifier,
+ unique int qualifiableelement: @namequalifiableelement ref,
+ int qualifyingelement: @namequalifyingelement ref,
+ int location: @location_default ref
+);
+
+varbind(
+ int expr: @varbindexpr ref,
+ int var: @accessible ref
+);
+
+funbind(
+ int expr: @funbindexpr ref,
+ int fun: @function ref
+);
+
+@any_new_expr = @new_expr
+ | @new_array_expr;
+
+@new_or_delete_expr = @any_new_expr
+ | @delete_expr
+ | @delete_array_expr;
+
+@prefix_crement_expr = @preincrexpr | @predecrexpr;
+
+@postfix_crement_expr = @postincrexpr | @postdecrexpr;
+
+@increment_expr = @preincrexpr | @postincrexpr;
+
+@decrement_expr = @predecrexpr | @postdecrexpr;
+
+@crement_expr = @increment_expr | @decrement_expr;
+
+@un_arith_op_expr = @arithnegexpr
+ | @unaryplusexpr
+ | @conjugation
+ | @realpartexpr
+ | @imagpartexpr
+ | @crement_expr
+ ;
+
+@un_bitwise_op_expr = @complementexpr;
+
+@un_log_op_expr = @notexpr;
+
+@un_op_expr = @address_of
+ | @indirect
+ | @un_arith_op_expr
+ | @un_bitwise_op_expr
+ | @builtinaddressof
+ | @vec_fill
+ | @un_log_op_expr
+ | @co_await
+ | @co_yield
+ ;
+
+@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr;
+
+@cmp_op_expr = @eq_op_expr | @rel_op_expr;
+
+@eq_op_expr = @eqexpr | @neexpr;
+
+@rel_op_expr = @gtexpr
+ | @ltexpr
+ | @geexpr
+ | @leexpr
+ | @spaceshipexpr
+ ;
+
+@bin_bitwise_op_expr = @lshiftexpr
+ | @rshiftexpr
+ | @andexpr
+ | @orexpr
+ | @xorexpr
+ ;
+
+@p_arith_op_expr = @paddexpr
+ | @psubexpr
+ | @pdiffexpr
+ ;
+
+@bin_arith_op_expr = @addexpr
+ | @subexpr
+ | @mulexpr
+ | @divexpr
+ | @remexpr
+ | @jmulexpr
+ | @jdivexpr
+ | @fjaddexpr
+ | @jfaddexpr
+ | @fjsubexpr
+ | @jfsubexpr
+ | @minexpr
+ | @maxexpr
+ | @p_arith_op_expr
+ ;
+
+@bin_op_expr = @bin_arith_op_expr
+ | @bin_bitwise_op_expr
+ | @cmp_op_expr
+ | @bin_log_op_expr
+ ;
+
+@op_expr = @un_op_expr
+ | @bin_op_expr
+ | @assign_expr
+ | @conditionalexpr
+ ;
+
+@assign_arith_expr = @assignaddexpr
+ | @assignsubexpr
+ | @assignmulexpr
+ | @assigndivexpr
+ | @assignremexpr
+ ;
+
+@assign_bitwise_expr = @assignandexpr
+ | @assignorexpr
+ | @assignxorexpr
+ | @assignlshiftexpr
+ | @assignrshiftexpr
+ ;
+
+@assign_pointer_expr = @assignpaddexpr
+ | @assignpsubexpr
+ ;
+
+@assign_op_expr = @assign_arith_expr
+ | @assign_bitwise_expr
+ | @assign_pointer_expr
+ ;
+
+@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
+
+/*
+ Binary encoding of the allocator form.
+
+ case @allocator.form of
+ 0 = plain
+ | 1 = alignment
+ ;
+*/
+
+/**
+ * The allocator function associated with a `new` or `new[]` expression.
+ * The `form` column specified whether the allocation call contains an alignment
+ * argument.
+ */
+expr_allocator(
+ unique int expr: @any_new_expr ref,
+ int func: @function ref,
+ int form: int ref
+);
+
+/*
+ Binary encoding of the deallocator form.
+
+ case @deallocator.form of
+ 0 = plain
+ | 1 = size
+ | 2 = alignment
+ | 4 = destroying_delete
+ ;
+*/
+
+/**
+ * The deallocator function associated with a `delete`, `delete[]`, `new`, or
+ * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the
+ * one used to free memory if the initialization throws an exception.
+ * The `form` column specifies whether the deallocation call contains a size
+ * argument, and alignment argument, or both.
+ */
+expr_deallocator(
+ unique int expr: @new_or_delete_expr ref,
+ int func: @function ref,
+ int form: int ref
+);
+
+/**
+ * Holds if the `@conditionalexpr` is of the two operand form
+ * `guard ? : false`.
+ */
+expr_cond_two_operand(
+ unique int cond: @conditionalexpr ref
+);
+
+/**
+ * The guard of `@conditionalexpr` `guard ? true : false`
+ */
+expr_cond_guard(
+ unique int cond: @conditionalexpr ref,
+ int guard: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` holds. For the two operand form
+ * `guard ?: false` consider using `expr_cond_guard` instead.
+ */
+expr_cond_true(
+ unique int cond: @conditionalexpr ref,
+ int true: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` does not hold.
+ */
+expr_cond_false(
+ unique int cond: @conditionalexpr ref,
+ int false: @expr ref
+);
+
+/** A string representation of the value. */
+values(
+ unique int id: @value,
+ string str: string ref
+);
+
+/** The actual text in the source code for the value, if any. */
+valuetext(
+ unique int id: @value ref,
+ string text: string ref
+);
+
+valuebind(
+ int val: @value ref,
+ unique int expr: @expr ref
+);
+
+fieldoffsets(
+ unique int id: @variable ref,
+ int byteoffset: int ref,
+ int bitoffset: int ref
+);
+
+bitfield(
+ unique int id: @variable ref,
+ int bits: int ref,
+ int declared_bits: int ref
+);
+
+/* TODO
+memberprefix(
+ int member: @expr ref,
+ int prefix: @expr ref
+);
+*/
+
+/*
+ kind(1) = mbrcallexpr
+ kind(2) = mbrptrcallexpr
+ kind(3) = mbrptrmbrcallexpr
+ kind(4) = ptrmbrptrmbrcallexpr
+ kind(5) = mbrreadexpr // x.y
+ kind(6) = mbrptrreadexpr // p->y
+ kind(7) = mbrptrmbrreadexpr // x.*pm
+ kind(8) = mbrptrmbrptrreadexpr // x->*pm
+ kind(9) = staticmbrreadexpr // static x.y
+ kind(10) = staticmbrptrreadexpr // static p->y
+*/
+/* TODO
+memberaccess(
+ int member: @expr ref,
+ int kind: int ref
+);
+*/
+
+initialisers(
+ unique int init: @initialiser,
+ int var: @accessible ref,
+ unique int expr: @expr ref,
+ int location: @location_default ref
+);
+
+braced_initialisers(
+ int init: @initialiser ref
+);
+
+/**
+ * An ancestor for the expression, for cases in which we cannot
+ * otherwise find the expression's parent.
+ */
+expr_ancestor(
+ int exp: @expr ref,
+ int ancestor: @element ref
+);
+
+exprs(
+ unique int id: @expr,
+ int kind: int ref,
+ int location: @location_default ref
+);
+
+expr_reuse(
+ int reuse: @expr ref,
+ int original: @expr ref,
+ int value_category: int ref
+)
+
+/*
+ case @value.category of
+ 1 = prval
+ | 2 = xval
+ | 3 = lval
+ ;
+*/
+expr_types(
+ int id: @expr ref,
+ int typeid: @type ref,
+ int value_category: int ref
+);
+
+case @expr.kind of
+ 1 = @errorexpr
+| 2 = @address_of // & AddressOfExpr
+| 3 = @reference_to // ReferenceToExpr (implicit?)
+| 4 = @indirect // * PointerDereferenceExpr
+| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?)
+// ...
+| 8 = @array_to_pointer // (???)
+| 9 = @vacuous_destructor_call // VacuousDestructorCall
+// ...
+| 11 = @assume // Microsoft
+| 12 = @parexpr
+| 13 = @arithnegexpr
+| 14 = @unaryplusexpr
+| 15 = @complementexpr
+| 16 = @notexpr
+| 17 = @conjugation // GNU ~ operator
+| 18 = @realpartexpr // GNU __real
+| 19 = @imagpartexpr // GNU __imag
+| 20 = @postincrexpr
+| 21 = @postdecrexpr
+| 22 = @preincrexpr
+| 23 = @predecrexpr
+| 24 = @conditionalexpr
+| 25 = @addexpr
+| 26 = @subexpr
+| 27 = @mulexpr
+| 28 = @divexpr
+| 29 = @remexpr
+| 30 = @jmulexpr // C99 mul imaginary
+| 31 = @jdivexpr // C99 div imaginary
+| 32 = @fjaddexpr // C99 add real + imaginary
+| 33 = @jfaddexpr // C99 add imaginary + real
+| 34 = @fjsubexpr // C99 sub real - imaginary
+| 35 = @jfsubexpr // C99 sub imaginary - real
+| 36 = @paddexpr // pointer add (pointer + int or int + pointer)
+| 37 = @psubexpr // pointer sub (pointer - integer)
+| 38 = @pdiffexpr // difference between two pointers
+| 39 = @lshiftexpr
+| 40 = @rshiftexpr
+| 41 = @andexpr
+| 42 = @orexpr
+| 43 = @xorexpr
+| 44 = @eqexpr
+| 45 = @neexpr
+| 46 = @gtexpr
+| 47 = @ltexpr
+| 48 = @geexpr
+| 49 = @leexpr
+| 50 = @minexpr // GNU minimum
+| 51 = @maxexpr // GNU maximum
+| 52 = @assignexpr
+| 53 = @assignaddexpr
+| 54 = @assignsubexpr
+| 55 = @assignmulexpr
+| 56 = @assigndivexpr
+| 57 = @assignremexpr
+| 58 = @assignlshiftexpr
+| 59 = @assignrshiftexpr
+| 60 = @assignandexpr
+| 61 = @assignorexpr
+| 62 = @assignxorexpr
+| 63 = @assignpaddexpr // assign pointer add
+| 64 = @assignpsubexpr // assign pointer sub
+| 65 = @andlogicalexpr
+| 66 = @orlogicalexpr
+| 67 = @commaexpr
+| 68 = @subscriptexpr // access to member of an array, e.g., a[5]
+// ... 69 @objc_subscriptexpr deprecated
+// ... 70 @cmdaccess deprecated
+// ...
+| 73 = @virtfunptrexpr
+| 74 = @callexpr
+// ... 75 @msgexpr_normal deprecated
+// ... 76 @msgexpr_super deprecated
+// ... 77 @atselectorexpr deprecated
+// ... 78 @atprotocolexpr deprecated
+| 79 = @vastartexpr
+| 80 = @vaargexpr
+| 81 = @vaendexpr
+| 82 = @vacopyexpr
+// ... 83 @atencodeexpr deprecated
+| 84 = @varaccess
+| 85 = @thisaccess
+// ... 86 @objc_box_expr deprecated
+| 87 = @new_expr
+| 88 = @delete_expr
+| 89 = @throw_expr
+| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2)
+| 91 = @braced_init_list
+| 92 = @type_id
+| 93 = @runtime_sizeof
+| 94 = @runtime_alignof
+| 95 = @sizeof_pack
+| 96 = @expr_stmt // GNU extension
+| 97 = @routineexpr
+| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....)
+| 99 = @offsetofexpr // offsetof ::= type and field
+| 100 = @hasassignexpr // __has_assign ::= type
+| 101 = @hascopyexpr // __has_copy ::= type
+| 102 = @hasnothrowassign // __has_nothrow_assign ::= type
+| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type
+| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type
+| 105 = @hastrivialassign // __has_trivial_assign ::= type
+| 106 = @hastrivialconstr // __has_trivial_constructor ::= type
+| 107 = @hastrivialcopy // __has_trivial_copy ::= type
+| 108 = @hasuserdestr // __has_user_destructor ::= type
+| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type
+| 110 = @isabstractexpr // __is_abstract ::= type
+| 111 = @isbaseofexpr // __is_base_of ::= type type
+| 112 = @isclassexpr // __is_class ::= type
+| 113 = @isconvtoexpr // __is_convertible_to ::= type type
+| 114 = @isemptyexpr // __is_empty ::= type
+| 115 = @isenumexpr // __is_enum ::= type
+| 116 = @ispodexpr // __is_pod ::= type
+| 117 = @ispolyexpr // __is_polymorphic ::= type
+| 118 = @isunionexpr // __is_union ::= type
+| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type
+| 120 = @intaddrexpr // frontend internal builtin, used to implement offsetof
+// ...
+| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type
+| 123 = @literal
+| 124 = @uuidof
+| 127 = @aggregateliteral
+| 128 = @delete_array_expr
+| 129 = @new_array_expr
+// ... 130 @objc_array_literal deprecated
+// ... 131 @objc_dictionary_literal deprecated
+| 132 = @foldexpr
+// ...
+| 200 = @ctordirectinit
+| 201 = @ctorvirtualinit
+| 202 = @ctorfieldinit
+| 203 = @ctordelegatinginit
+| 204 = @dtordirectdestruct
+| 205 = @dtorvirtualdestruct
+| 206 = @dtorfielddestruct
+// ...
+| 210 = @static_cast
+| 211 = @reinterpret_cast
+| 212 = @const_cast
+| 213 = @dynamic_cast
+| 214 = @c_style_cast
+| 215 = @lambdaexpr
+| 216 = @param_ref
+| 217 = @noopexpr
+// ...
+| 294 = @istriviallyconstructibleexpr
+| 295 = @isdestructibleexpr
+| 296 = @isnothrowdestructibleexpr
+| 297 = @istriviallydestructibleexpr
+| 298 = @istriviallyassignableexpr
+| 299 = @isnothrowassignableexpr
+| 300 = @istrivialexpr
+| 301 = @isstandardlayoutexpr
+| 302 = @istriviallycopyableexpr
+| 303 = @isliteraltypeexpr
+| 304 = @hastrivialmoveconstructorexpr
+| 305 = @hastrivialmoveassignexpr
+| 306 = @hasnothrowmoveassignexpr
+| 307 = @isconstructibleexpr
+| 308 = @isnothrowconstructibleexpr
+| 309 = @hasfinalizerexpr
+| 310 = @isdelegateexpr
+| 311 = @isinterfaceclassexpr
+| 312 = @isrefarrayexpr
+| 313 = @isrefclassexpr
+| 314 = @issealedexpr
+| 315 = @issimplevalueclassexpr
+| 316 = @isvalueclassexpr
+| 317 = @isfinalexpr
+| 319 = @noexceptexpr
+| 320 = @builtinshufflevector
+| 321 = @builtinchooseexpr
+| 322 = @builtinaddressof
+| 323 = @vec_fill
+| 324 = @builtinconvertvector
+| 325 = @builtincomplex
+| 326 = @spaceshipexpr
+| 327 = @co_await
+| 328 = @co_yield
+| 329 = @temp_init
+| 330 = @isassignable
+| 331 = @isaggregate
+| 332 = @hasuniqueobjectrepresentations
+| 333 = @builtinbitcast
+| 334 = @builtinshuffle
+| 335 = @blockassignexpr
+| 336 = @issame
+| 337 = @isfunction
+| 338 = @islayoutcompatible
+| 339 = @ispointerinterconvertiblebaseof
+| 340 = @isarray
+| 341 = @arrayrank
+| 342 = @arrayextent
+| 343 = @isarithmetic
+| 344 = @iscompletetype
+| 345 = @iscompound
+| 346 = @isconst
+| 347 = @isfloatingpoint
+| 348 = @isfundamental
+| 349 = @isintegral
+| 350 = @islvaluereference
+| 351 = @ismemberfunctionpointer
+| 352 = @ismemberobjectpointer
+| 353 = @ismemberpointer
+| 354 = @isobject
+| 355 = @ispointer
+| 356 = @isreference
+| 357 = @isrvaluereference
+| 358 = @isscalar
+| 359 = @issigned
+| 360 = @isunsigned
+| 361 = @isvoid
+| 362 = @isvolatile
+| 363 = @reuseexpr
+| 364 = @istriviallycopyassignable
+| 365 = @isassignablenopreconditioncheck
+| 366 = @referencebindstotemporary
+| 367 = @issameas
+| 368 = @builtinhasattribute
+| 369 = @ispointerinterconvertiblewithclass
+| 370 = @builtinispointerinterconvertiblewithclass
+| 371 = @iscorrespondingmember
+| 372 = @builtiniscorrespondingmember
+| 373 = @isboundedarray
+| 374 = @isunboundedarray
+| 375 = @isreferenceable
+| 378 = @isnothrowconvertible
+| 379 = @referenceconstructsfromtemporary
+| 380 = @referenceconvertsfromtemporary
+| 381 = @isconvertible
+| 382 = @isvalidwinrttype
+| 383 = @iswinclass
+| 384 = @iswininterface
+| 385 = @istriviallyequalitycomparable
+| 386 = @isscopedenum
+| 387 = @istriviallyrelocatable
+| 388 = @datasizeof
+| 389 = @c11_generic
+| 390 = @requires_expr
+| 391 = @nested_requirement
+| 392 = @compound_requirement
+| 393 = @concept_id
+| 394 = @isinvocable
+| 395 = @isnothrowinvocable
+| 396 = @isbitwisecloneable
+;
+
+@var_args_expr = @vastartexpr
+ | @vaendexpr
+ | @vaargexpr
+ | @vacopyexpr
+ ;
+
+@builtin_op = @var_args_expr
+ | @noopexpr
+ | @offsetofexpr
+ | @intaddrexpr
+ | @hasassignexpr
+ | @hascopyexpr
+ | @hasnothrowassign
+ | @hasnothrowconstr
+ | @hasnothrowcopy
+ | @hastrivialassign
+ | @hastrivialconstr
+ | @hastrivialcopy
+ | @hastrivialdestructor
+ | @hasuserdestr
+ | @hasvirtualdestr
+ | @isabstractexpr
+ | @isbaseofexpr
+ | @isclassexpr
+ | @isconvtoexpr
+ | @isemptyexpr
+ | @isenumexpr
+ | @ispodexpr
+ | @ispolyexpr
+ | @isunionexpr
+ | @typescompexpr
+ | @builtinshufflevector
+ | @builtinconvertvector
+ | @builtinaddressof
+ | @istriviallyconstructibleexpr
+ | @isdestructibleexpr
+ | @isnothrowdestructibleexpr
+ | @istriviallydestructibleexpr
+ | @istriviallyassignableexpr
+ | @isnothrowassignableexpr
+ | @istrivialexpr
+ | @isstandardlayoutexpr
+ | @istriviallycopyableexpr
+ | @isliteraltypeexpr
+ | @hastrivialmoveconstructorexpr
+ | @hastrivialmoveassignexpr
+ | @hasnothrowmoveassignexpr
+ | @isconstructibleexpr
+ | @isnothrowconstructibleexpr
+ | @hasfinalizerexpr
+ | @isdelegateexpr
+ | @isinterfaceclassexpr
+ | @isrefarrayexpr
+ | @isrefclassexpr
+ | @issealedexpr
+ | @issimplevalueclassexpr
+ | @isvalueclassexpr
+ | @isfinalexpr
+ | @builtinchooseexpr
+ | @builtincomplex
+ | @isassignable
+ | @isaggregate
+ | @hasuniqueobjectrepresentations
+ | @builtinbitcast
+ | @builtinshuffle
+ | @issame
+ | @isfunction
+ | @islayoutcompatible
+ | @ispointerinterconvertiblebaseof
+ | @isarray
+ | @arrayrank
+ | @arrayextent
+ | @isarithmetic
+ | @iscompletetype
+ | @iscompound
+ | @isconst
+ | @isfloatingpoint
+ | @isfundamental
+ | @isintegral
+ | @islvaluereference
+ | @ismemberfunctionpointer
+ | @ismemberobjectpointer
+ | @ismemberpointer
+ | @isobject
+ | @ispointer
+ | @isreference
+ | @isrvaluereference
+ | @isscalar
+ | @issigned
+ | @isunsigned
+ | @isvoid
+ | @isvolatile
+ | @istriviallycopyassignable
+ | @isassignablenopreconditioncheck
+ | @referencebindstotemporary
+ | @issameas
+ | @builtinhasattribute
+ | @ispointerinterconvertiblewithclass
+ | @builtinispointerinterconvertiblewithclass
+ | @iscorrespondingmember
+ | @builtiniscorrespondingmember
+ | @isboundedarray
+ | @isunboundedarray
+ | @isreferenceable
+ | @isnothrowconvertible
+ | @referenceconstructsfromtemporary
+ | @referenceconvertsfromtemporary
+ | @isconvertible
+ | @isvalidwinrttype
+ | @iswinclass
+ | @iswininterface
+ | @istriviallyequalitycomparable
+ | @isscopedenum
+ | @istriviallyrelocatable
+ | @isinvocable
+ | @isnothrowinvocable
+ | @isbitwisecloneable
+ ;
+
+compound_requirement_is_noexcept(
+ int expr: @compound_requirement ref
+);
+
+new_allocated_type(
+ unique int expr: @new_expr ref,
+ int type_id: @type ref
+);
+
+new_array_allocated_type(
+ unique int expr: @new_array_expr ref,
+ int type_id: @type ref
+);
+
+param_ref_to_this(
+ int expr: @param_ref ref
+)
+
+/**
+ * The field being initialized by an initializer expression within an aggregate
+ * initializer for a class/struct/union. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_field_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int field: @membervariable ref,
+ int position: int ref,
+ boolean is_designated: boolean ref
+);
+
+/**
+ * The index of the element being initialized by an initializer expression
+ * within an aggregate initializer for an array. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_array_init(
+ int aggregate: @aggregateliteral ref,
+ int initializer: @expr ref,
+ int element_index: int ref,
+ int position: int ref,
+ boolean is_designated: boolean ref
+);
+
+@ctorinit = @ctordirectinit
+ | @ctorvirtualinit
+ | @ctorfieldinit
+ | @ctordelegatinginit;
+@dtordestruct = @dtordirectdestruct
+ | @dtorvirtualdestruct
+ | @dtorfielddestruct;
+
+
+condition_decl_bind(
+ unique int expr: @condition_decl ref,
+ unique int decl: @declaration ref
+);
+
+typeid_bind(
+ unique int expr: @type_id ref,
+ int type_id: @type ref
+);
+
+uuidof_bind(
+ unique int expr: @uuidof ref,
+ int type_id: @type ref
+);
+
+@sizeof_or_alignof = @runtime_sizeof | @runtime_alignof | @datasizeof | @sizeof_pack;
+
+sizeof_bind(
+ unique int expr: @sizeof_or_alignof ref,
+ int type_id: @type ref
+);
+
+code_block(
+ unique int block: @literal ref,
+ unique int routine: @function ref
+);
+
+lambdas(
+ unique int expr: @lambdaexpr ref,
+ string default_capture: string ref,
+ boolean has_explicit_return_type: boolean ref,
+ boolean has_explicit_parameter_list: boolean ref
+);
+
+lambda_capture(
+ unique int id: @lambdacapture,
+ int lambda: @lambdaexpr ref,
+ int index: int ref,
+ int field: @membervariable ref,
+ boolean captured_by_reference: boolean ref,
+ boolean is_implicit: boolean ref,
+ int location: @location_default ref
+);
+
+@funbindexpr = @routineexpr
+ | @new_expr
+ | @delete_expr
+ | @delete_array_expr
+ | @ctordirectinit
+ | @ctorvirtualinit
+ | @ctordelegatinginit
+ | @dtordirectdestruct
+ | @dtorvirtualdestruct;
+
+@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct;
+@addressable = @function | @variable ;
+@accessible = @addressable | @enumconstant ;
+
+@access = @varaccess | @routineexpr ;
+
+fold(
+ int expr: @foldexpr ref,
+ string operator: string ref,
+ boolean is_left_fold: boolean ref
+);
+
+stmts(
+ unique int id: @stmt,
+ int kind: int ref,
+ int location: @location_default ref
+);
+
+case @stmt.kind of
+ 1 = @stmt_expr
+| 2 = @stmt_if
+| 3 = @stmt_while
+| 4 = @stmt_goto
+| 5 = @stmt_label
+| 6 = @stmt_return
+| 7 = @stmt_block
+| 8 = @stmt_end_test_while // do { ... } while ( ... )
+| 9 = @stmt_for
+| 10 = @stmt_switch_case
+| 11 = @stmt_switch
+| 13 = @stmt_asm // "asm" statement or the body of an asm function
+| 15 = @stmt_try_block
+| 16 = @stmt_microsoft_try // Microsoft
+| 17 = @stmt_decl
+| 18 = @stmt_set_vla_size // C99
+| 19 = @stmt_vla_decl // C99
+| 25 = @stmt_assigned_goto // GNU
+| 26 = @stmt_empty
+| 27 = @stmt_continue
+| 28 = @stmt_break
+| 29 = @stmt_range_based_for // C++11
+// ... 30 @stmt_at_autoreleasepool_block deprecated
+// ... 31 @stmt_objc_for_in deprecated
+// ... 32 @stmt_at_synchronized deprecated
+| 33 = @stmt_handler
+// ... 34 @stmt_finally_end deprecated
+| 35 = @stmt_constexpr_if
+| 37 = @stmt_co_return
+| 38 = @stmt_consteval_if
+| 39 = @stmt_not_consteval_if
+| 40 = @stmt_leave
+;
+
+type_vla(
+ int type_id: @type ref,
+ int decl: @stmt_vla_decl ref
+);
+
+variable_vla(
+ int var: @variable ref,
+ int decl: @stmt_vla_decl ref
+);
+
+type_is_vla(unique int type_id: @derivedtype ref)
+
+if_initialization(
+ unique int if_stmt: @stmt_if ref,
+ int init_id: @stmt ref
+);
+
+if_then(
+ unique int if_stmt: @stmt_if ref,
+ int then_id: @stmt ref
+);
+
+if_else(
+ unique int if_stmt: @stmt_if ref,
+ int else_id: @stmt ref
+);
+
+constexpr_if_initialization(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int init_id: @stmt ref
+);
+
+constexpr_if_then(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int then_id: @stmt ref
+);
+
+constexpr_if_else(
+ unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+ int else_id: @stmt ref
+);
+
+@stmt_consteval_or_not_consteval_if = @stmt_consteval_if | @stmt_not_consteval_if;
+
+consteval_if_then(
+ unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref,
+ int then_id: @stmt ref
+);
+
+consteval_if_else(
+ unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref,
+ int else_id: @stmt ref
+);
+
+while_body(
+ unique int while_stmt: @stmt_while ref,
+ int body_id: @stmt ref
+);
+
+do_body(
+ unique int do_stmt: @stmt_end_test_while ref,
+ int body_id: @stmt ref
+);
+
+switch_initialization(
+ unique int switch_stmt: @stmt_switch ref,
+ int init_id: @stmt ref
+);
+
+#keyset[switch_stmt, index]
+switch_case(
+ int switch_stmt: @stmt_switch ref,
+ int index: int ref,
+ int case_id: @stmt_switch_case ref
+);
+
+switch_body(
+ unique int switch_stmt: @stmt_switch ref,
+ int body_id: @stmt ref
+);
+
+@stmt_for_or_range_based_for = @stmt_for
+ | @stmt_range_based_for;
+
+for_initialization(
+ unique int for_stmt: @stmt_for_or_range_based_for ref,
+ int init_id: @stmt ref
+);
+
+for_condition(
+ unique int for_stmt: @stmt_for ref,
+ int condition_id: @expr ref
+);
+
+for_update(
+ unique int for_stmt: @stmt_for ref,
+ int update_id: @expr ref
+);
+
+for_body(
+ unique int for_stmt: @stmt_for ref,
+ int body_id: @stmt ref
+);
+
+@stmtparent = @stmt | @expr_stmt ;
+stmtparents(
+ unique int id: @stmt ref,
+ int index: int ref,
+ int parent: @stmtparent ref
+);
+
+ishandler(unique int block: @stmt_block ref);
+
+@cfgnode = @stmt | @expr | @function | @initialiser ;
+
+stmt_decl_bind(
+ int stmt: @stmt_decl ref,
+ int num: int ref,
+ int decl: @declaration ref
+);
+
+stmt_decl_entry_bind(
+ int stmt: @stmt_decl ref,
+ int num: int ref,
+ int decl_entry: @element ref
+);
+
+@parameterized_element = @function | @stmt_block | @requires_expr;
+
+blockscope(
+ unique int block: @stmt_block ref,
+ int enclosing: @parameterized_element ref
+);
+
+@jump = @stmt_goto | @stmt_break | @stmt_continue | @stmt_leave;
+
+@jumporlabel = @jump | @stmt_label | @literal;
+
+jumpinfo(
+ unique int id: @jumporlabel ref,
+ string str: string ref,
+ int target: @stmt ref
+);
+
+preprocdirects(
+ unique int id: @preprocdirect,
+ int kind: int ref,
+ int location: @location_default ref
+);
+case @preprocdirect.kind of
+ 0 = @ppd_if
+| 1 = @ppd_ifdef
+| 2 = @ppd_ifndef
+| 3 = @ppd_elif
+| 4 = @ppd_else
+| 5 = @ppd_endif
+| 6 = @ppd_plain_include
+| 7 = @ppd_define
+| 8 = @ppd_undef
+| 9 = @ppd_line
+| 10 = @ppd_error
+| 11 = @ppd_pragma
+| 12 = @ppd_objc_import
+| 13 = @ppd_include_next
+| 14 = @ppd_ms_import
+| 15 = @ppd_elifdef
+| 16 = @ppd_elifndef
+| 17 = @ppd_embed
+| 18 = @ppd_warning
+;
+
+@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next | @ppd_ms_import;
+
+@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif | @ppd_elifdef | @ppd_elifndef;
+
+preprocpair(
+ int begin : @ppd_branch ref,
+ int elseelifend : @preprocdirect ref
+);
+
+preproctrue(int branch : @ppd_branch ref);
+preprocfalse(int branch : @ppd_branch ref);
+
+preproctext(
+ unique int id: @preprocdirect ref,
+ string head: string ref,
+ string body: string ref
+);
+
+includes(
+ unique int id: @ppd_include ref,
+ int included: @file ref
+);
+
+embeds(
+ unique int id: @ppd_embed ref,
+ int included: @file ref
+);
+
+link_targets(
+ int id: @link_target,
+ int binary: @file ref
+);
+
+link_parent(
+ int element : @element ref,
+ int link_target : @link_target ref
+);
+
+/*- Database metadata -*/
+
+/**
+ * The CLI will automatically emit applicable tuples for this table,
+ * such as `databaseMetadata("isOverlay", "true")` when building an
+ * overlay database.
+ */
+databaseMetadata(
+ string metadataKey: string ref,
+ string value: string ref
+);
+
+/*- Overlay support -*/
+
+/**
+ * The CLI will automatically emit tuples for each new/modified/deleted file
+ * when building an overlay database.
+ */
+overlayChangedFiles(
+ string path: string ref
+);
+
+/*- XML Files -*/
+
+xmlEncoding(
+ unique int id: @file ref,
+ string encoding: string ref
+);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref
+);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref
+);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref
+);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref
+);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref
+);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref
+);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref
+);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref
+);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
diff --git a/cpp/ql/lib/upgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/source_files.ql b/cpp/ql/lib/upgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/source_files.ql
new file mode 100644
index 00000000000..19c08d64ece
--- /dev/null
+++ b/cpp/ql/lib/upgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/source_files.ql
@@ -0,0 +1,22 @@
+newtype TSourceFile = MkSourceFile(string name) { source_file_uses_trap(name, _) }
+
+module FreshSourceFile = QlBuiltins::NewEntity;
+
+class SourceFile extends FreshSourceFile::EntityId {
+ string toString() { none() }
+}
+
+class Trap extends @trap {
+ string toString() { none() }
+}
+
+query predicate mk_source_file_name(SourceFile source_file, string name) {
+ source_file = FreshSourceFile::map(MkSourceFile(name))
+}
+
+query predicate mk_source_file_uses_trap(SourceFile source_file, Trap trap) {
+ exists(string name |
+ source_file_uses_trap(name, trap) and
+ mk_source_file_name(source_file, name)
+ )
+}
diff --git a/cpp/ql/lib/upgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/upgrade.properties b/cpp/ql/lib/upgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/upgrade.properties
new file mode 100644
index 00000000000..26400eeded8
--- /dev/null
+++ b/cpp/ql/lib/upgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/upgrade.properties
@@ -0,0 +1,6 @@
+description: Add source_file_name
+compatibility: backwards
+source_file_uses_trap.rel: run source_files.ql mk_source_file_uses_trap
+source_file_name.rel: run source_files.ql mk_source_file_name
+in_trap.rel: delete
+in_trap_or_tag.rel: run in_trap_or_tag.ql
diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md
index 61792c6a700..80b9ad0e475 100644
--- a/cpp/ql/src/CHANGELOG.md
+++ b/cpp/ql/src/CHANGELOG.md
@@ -1,3 +1,48 @@
+## 1.6.1
+
+### Minor Analysis Improvements
+
+* Added `AllocationFunction` models for `aligned_alloc`, `std::aligned_alloc`, and `bsl::aligned_alloc`.
+* The "Comparison of narrow type with wide type in loop condition" (`cpp/comparison-with-wider-type`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
+* The "Multiplication result converted to larger type" (`cpp/integer-multiplication-cast-to-long`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
+* The "Suspicious add with sizeof" (`cpp/suspicious-add-sizeof`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
+* The "Wrong type of arguments to formatting function" (`cpp/wrong-type-format-argument`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
+* The "Implicit function declaration" (`cpp/implicit-function-declaration`) query has been upgraded to `high` precision. However, for `build mode: none` databases, it no longer produces any results. The results in this mode were found to be very noisy and fundamentally imprecise.
+
+## 1.6.0
+
+### Query Metadata Changes
+
+* The `@security-severity` metadata of `cpp/cgi-xss` has been increased from 6.1 (medium) to 7.8 (high).
+
+### Minor Analysis Improvements
+
+* The "Extraction warnings" (`cpp/diagnostics/extraction-warnings`) diagnostics query no longer yields `ExtractionRecoverableWarning`s for `build-mode: none` databases. The results were found to significantly increase the sizes of the produced SARIF files, making them unprocessable in some cases.
+* Fixed an issue with the "Suspicious add with sizeof" (`cpp/suspicious-add-sizeof`) query causing false positive results in `build-mode: none` databases.
+* Fixed an issue with the "Uncontrolled format string" (`cpp/tainted-format-string`) query involving certain kinds of formatting function implementations.
+* Fixed an issue with the "Wrong type of arguments to formatting function" (`cpp/wrong-type-format-argument`) query causing false positive results in `build-mode: none` databases.
+* Fixed an issue with the "Multiplication result converted to larger type" (`cpp/integer-multiplication-cast-to-long`) query causing false positive results in `build-mode: none` databases.
+
+## 1.5.15
+
+No user-facing changes.
+
+## 1.5.14
+
+No user-facing changes.
+
+## 1.5.13
+
+No user-facing changes.
+
+## 1.5.12
+
+No user-facing changes.
+
+## 1.5.11
+
+No user-facing changes.
+
## 1.5.10
No user-facing changes.
@@ -321,7 +366,7 @@ No user-facing changes.
### Minor Analysis Improvements
* The "non-constant format string" query (`cpp/non-constant-format`) has been updated to produce fewer false positives.
-* Added dataflow models for the `gettext` function variants.
+* Added dataflow models for the `gettext` function variants.
## 0.9.4
diff --git a/cpp/ql/src/Diagnostics/ExtractionProblems.qll b/cpp/ql/src/Diagnostics/ExtractionProblems.qll
index b6dd835261d..1199ca1c7f4 100644
--- a/cpp/ql/src/Diagnostics/ExtractionProblems.qll
+++ b/cpp/ql/src/Diagnostics/ExtractionProblems.qll
@@ -50,7 +50,7 @@ private newtype TExtractionProblem =
/**
* Superclass for the extraction problem hierarchy.
*/
-class ExtractionProblem extends TExtractionProblem {
+abstract class ExtractionProblem extends TExtractionProblem {
/** Gets the string representation of the problem. */
string toString() { none() }
@@ -65,6 +65,9 @@ class ExtractionProblem extends TExtractionProblem {
/** Gets the SARIF severity of this problem. */
int getSeverity() { none() }
+
+ /** Gets the `Compilation` the problem is associated with. */
+ abstract Compilation getCompilation();
}
/**
@@ -96,6 +99,8 @@ class ExtractionUnrecoverableError extends ExtractionProblem, TCompilationFailed
// [errors](https://docs.oasis-open.org/sarif/sarif/v2.1.0/csprd01/sarif-v2.1.0-csprd01.html#_Toc10541338).
result = 2
}
+
+ override Compilation getCompilation() { result = c }
}
/**
@@ -122,6 +127,8 @@ class ExtractionRecoverableWarning extends ExtractionProblem, TReportableWarning
// [warnings](https://docs.oasis-open.org/sarif/sarif/v2.1.0/csprd01/sarif-v2.1.0-csprd01.html#_Toc10541338).
result = 1
}
+
+ override Compilation getCompilation() { result = err.getCompilation() }
}
/**
@@ -148,4 +155,6 @@ class ExtractionUnknownProblem extends ExtractionProblem, TUnknownProblem {
// [warnings](https://docs.oasis-open.org/sarif/sarif/v2.1.0/csprd01/sarif-v2.1.0-csprd01.html#_Toc10541338).
result = 1
}
+
+ override Compilation getCompilation() { result = err.getCompilation() }
}
diff --git a/cpp/ql/src/Diagnostics/ExtractionWarnings.ql b/cpp/ql/src/Diagnostics/ExtractionWarnings.ql
index f32768734ca..c0e9eb7d24b 100644
--- a/cpp/ql/src/Diagnostics/ExtractionWarnings.ql
+++ b/cpp/ql/src/Diagnostics/ExtractionWarnings.ql
@@ -10,7 +10,9 @@ import ExtractionProblems
from ExtractionProblem warning
where
- warning instanceof ExtractionRecoverableWarning and exists(warning.getFile().getRelativePath())
+ warning instanceof ExtractionRecoverableWarning and
+ exists(warning.getFile().getRelativePath()) and
+ not warning.getCompilation().buildModeNone()
or
warning instanceof ExtractionUnknownProblem
select warning,
diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql b/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql
index a54ac9020c8..b05bd637dc2 100644
--- a/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql
+++ b/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql
@@ -5,7 +5,7 @@
* @kind problem
* @problem.severity warning
* @security-severity 8.1
- * @precision medium
+ * @precision high
* @id cpp/integer-multiplication-cast-to-long
* @tags reliability
* security
@@ -218,7 +218,9 @@ where
// only report if we cannot prove that the result of the
// multiplication will be less (resp. greater) than the
// maximum (resp. minimum) number we can compute.
- overflows(me, t1)
+ overflows(me, t1) and
+ // exclude cases where the expression type may not have been extracted accurately
+ not me.getParent().(Call).getTarget().hasAmbiguousReturnType()
select me,
"Multiplication result may overflow '" + me.getType().toString() + "' before it is converted to '"
+ me.getFullyConverted().getType().toString() + "'."
diff --git a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
index 33fe3a0b7a1..5842b9474f7 100644
--- a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
+++ b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
@@ -5,7 +5,7 @@
* @kind problem
* @problem.severity error
* @security-severity 7.5
- * @precision medium
+ * @precision high
* @id cpp/wrong-type-format-argument
* @tags reliability
* correctness
@@ -168,9 +168,11 @@ where
formatOtherArgType(ffc, n, expected, arg, actual) and
not actual.getUnspecifiedType().(IntegralType).getSize() = sizeof_IntType()
) and
+ // Exclude some cases where we're less confident the result is correct / clear / valuable
not arg.isAffectedByMacro() and
not arg.isFromUninstantiatedTemplate(_) and
not actual.stripType() instanceof ErroneousType and
+ not arg.getType().stripType().(RoutineType).getReturnType() instanceof ErroneousType and
not arg.(Call).mayBeFromImplicitlyDeclaredFunction() and
// Make sure that the format function definition is consistent
count(ffc.getTarget().getFormatParameterIndex()) = 1
diff --git a/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll b/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll
index 2b68730fa58..99981873d26 100644
--- a/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll
+++ b/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll
@@ -308,3 +308,37 @@ private module PossibleYearArithmeticOperationCheckConfig implements DataFlow::C
module PossibleYearArithmeticOperationCheckFlow =
TaintTracking::Global;
+
+/**
+ * A time conversion function where either
+ * 1) an incorrect leap year date would result in an error that can be checked from the return value or
+ * 2) an incorrect leap year date is auto corrected (no checks required)
+ */
+class TimeConversionFunction extends Function {
+ boolean autoLeapYearCorrecting;
+
+ TimeConversionFunction() {
+ autoLeapYearCorrecting = false and
+ (
+ this.getName() =
+ [
+ "FileTimeToSystemTime", "SystemTimeToFileTime", "SystemTimeToTzSpecificLocalTime",
+ "SystemTimeToTzSpecificLocalTimeEx", "TzSpecificLocalTimeToSystemTime",
+ "TzSpecificLocalTimeToSystemTimeEx", "RtlLocalTimeToSystemTime",
+ "RtlTimeToSecondsSince1970", "_mkgmtime", "SetSystemTime", "VarUdateFromDate", "from_tm"
+ ]
+ or
+ // Matches all forms of GetDateFormat, e.g. GetDateFormatA/W/Ex
+ this.getName().matches("GetDateFormat%")
+ )
+ or
+ autoLeapYearCorrecting = true and
+ this.getName() =
+ ["mktime", "_mktime32", "_mktime64", "SystemTimeToVariantTime", "VariantTimeToSystemTime"]
+ }
+
+ /**
+ * Holds if the function is expected to auto convert a bad leap year date.
+ */
+ predicate isAutoLeapYearCorrecting() { autoLeapYearCorrecting = true }
+}
diff --git a/cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification.ql b/cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification.ql
index 03570b3611c..0a52a2b0ff4 100644
--- a/cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification.ql
+++ b/cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification.ql
@@ -1,7 +1,7 @@
/**
* @name Year field changed using an arithmetic operation without checking for leap year
* @description A field that represents a year is being modified by an arithmetic operation, but no proper check for leap years can be detected afterwards.
- * @kind problem
+ * @kind path-problem
* @problem.severity warning
* @id cpp/leap-year/unchecked-after-arithmetic-year-modification
* @precision medium
@@ -11,49 +11,844 @@
import cpp
import LeapYear
+import semmle.code.cpp.controlflow.IRGuards
-from Variable var, LeapYearFieldAccess yfa
-where
- exists(VariableAccess va |
- yfa.getQualifier() = va and
- var.getAnAccess() = va and
- // The year is modified with an arithmetic operation. Avoid values that are likely false positives
- yfa.isModifiedByArithmeticOperationNotForNormalization() and
- // Avoid false positives
- not (
- // If there is a local check for leap year after the modification
- exists(LeapYearFieldAccess yfacheck |
- yfacheck.getQualifier() = var.getAnAccess() and
- yfacheck.isUsedInCorrectLeapYearCheck() and
- yfacheck.getBasicBlock() = yfa.getBasicBlock().getASuccessor*()
- )
+/**
+ * Functions whose operations should never be considered a
+ * source or sink of a dangerous leap year operation.
+ * The general concept is to add conversion functions
+ * that convert one time type to another. Often
+ * other ignorable operation heuristics will filter these,
+ * but some cases, the simplest approach is to simply filter
+ * the function entirely.
+ * Note that flow through these functions should still be allowed
+ * we just cannot start or end flow from an operation to a
+ * year assignment in one of these functions.
+ */
+class IgnorableFunction extends Function {
+ IgnorableFunction() {
+ // arithmetic in known time conversion functions may look like dangerous operations
+ // we assume all known time conversion functions are safe.
+ this instanceof TimeConversionFunction
+ or
+ // Helper utility in postgres with string time conversions
+ this.getName() = "DecodeISO8601Interval"
+ or
+ // helper utility for date conversions in qtbase
+ this.getName() = "adjacentDay"
+ or
+ // Windows API function that does timezone conversions
+ this.getName().matches("%SystemTimeToTzSpecificLocalTime%")
+ or
+ // Windows APIs that do time conversions
+ this.getName().matches("%localtime%\\_s%")
+ or
+ // Windows APIs that do time conversions
+ this.getName().matches("%SpecificLocalTimeToSystemTime%")
+ or
+ // postgres function for diffing timestamps, date for leap year
+ // is not applicable.
+ this.getName().toLowerCase().matches("%timestamp%age%")
+ or
+ // Reading byte streams often involves operations of some base, but that's
+ // not a real source of leap year issues.
+ this.getName().toLowerCase().matches("%read%bytes%")
+ or
+ // A postgres function for local time conversions
+ // conversion operations (from one time structure to another) are generally ignorable
+ this.getName() = "localsub"
+ or
+ // Indication of a calendar not applicable to
+ // gregorian leap year, e.g., Hijri, Persian, Hebrew
+ this.getName().toLowerCase().matches("%hijri%")
+ or
+ this.getFile().getBaseName().toLowerCase().matches("%hijri%")
+ or
+ this.getName().toLowerCase().matches("%persian%")
+ or
+ this.getFile().getBaseName().toLowerCase().matches("%persian%")
+ or
+ this.getName().toLowerCase().matches("%hebrew%")
+ or
+ this.getFile().getBaseName().toLowerCase().matches("%hebrew%")
+ or
+ // misc. from string/char converters heuristic
+ this.getName()
+ .toLowerCase()
+ .matches(["%char%to%", "%string%to%", "%from%char%", "%from%string%"])
+ or
+ // boost's gregorian.cpp has year manipulations that are checked in complex ways.
+ // ignore the entire file as a source or sink.
+ this.getFile().getAbsolutePath().toLowerCase().matches("%boost%gregorian.cpp%")
+ }
+}
+
+/**
+ * The set of expressions which are ignorable; either because they seem to not be part of a year mutation,
+ * or because they seem to be a conversion pattern of mapping date scalars.
+ */
+abstract class IgnorableOperation extends Expr { }
+
+class IgnorableExprRem extends IgnorableOperation instanceof RemExpr { }
+
+/**
+ * An operation with 10, 100, 1000, 10000 as an operand is often a sign of conversion
+ * or atoi.
+ */
+class IgnorableExpr10MultipleComponent extends IgnorableOperation {
+ IgnorableExpr10MultipleComponent() {
+ this.(Operation).getAnOperand().getValue().toInt() in [10, 100, 1000, 10000]
+ or
+ exists(AssignOperation a | a.getRValue() = this |
+ a.getRValue().getValue().toInt() in [10, 100, 1000, 10000]
+ )
+ }
+}
+
+/**
+ * An operation involving a sub expression with char literal `48`, ignore as a likely string conversion. For example: `X - '0'`
+ */
+class IgnorableExpr48Mapping extends IgnorableOperation {
+ IgnorableExpr48Mapping() {
+ this.(SubExpr).getRightOperand().getValue().toInt() = 48
+ or
+ exists(AssignSubExpr e | e.getRValue() = this | e.getRValue().getValue().toInt() = 48)
+ }
+}
+
+/**
+ * A binary or arithmetic operation whereby one of the components is textual or a string.
+ */
+class IgnorableCharLiteralArithmetic extends IgnorableOperation {
+ IgnorableCharLiteralArithmetic() {
+ this.(BinaryArithmeticOperation).getAnOperand() instanceof TextLiteral
+ or
+ this instanceof TextLiteral and
+ any(AssignArithmeticOperation arith).getRValue() = this
+ }
+}
+
+/**
+ * Constants often used in date conversions (from one date data type to another)
+ * Numerous examples exist, like 1900 or 2000 that convert years from one
+ * representation to another.
+ * Also '0' is sometimes observed as an atoi style conversion.
+ */
+bindingset[c]
+predicate isLikelyConversionConstant(int c) {
+ exists(int i | i = c.abs() |
+ i =
+ [
+ 146097, // days in 400-year Gregorian cycle
+ 36524, // days in 100-year Gregorian subcycle
+ 1461, // days in 4-year cycle (incl. 1 leap)
+ 32044, // Fliegel-van Flandern JDN epoch shift
+ 1721425, // JDN of 0001-01-01 (Gregorian)
+ 1721119, // alt epoch offset
+ 2400000, // MJD -> JDN conversion
+ 2400001, // alt MJD -> JDN conversion
+ 2141, // fixed-point month/day extraction
+ 65536, // observed in some conversions
+ 7834, // observed in some conversions
+ 256, // observed in some conversions
+ 292275056, // qdatetime.h Qt Core year range first year constant
+ 292278994, // qdatetime.h Qt Core year range last year constant
+ 1601, // Windows FILETIME epoch start year
+ 1970, // Unix epoch start year
+ 70, // Unix epoch start year short form
+ 1899, // Observed in uses with 1900 to address off by one scenarios
+ 1900, // Used when converting a 2 digit year
+ 2000, // Used when converting a 2 digit year
+ 1400, // Hijri base year, used when converting a 2 digit year
+ 1980, // FAT filesystem epoch start year
+ 227013, // constant observed for Hirji year conversion, and Hirji years are not applicable for gregorian leap year
+ 10631, // constant observed for Hirji year conversion, and Hirji years are not applicable for gregorian leap year,
+ 80, // 1980/01/01 is the start of the epoch on DOS
+ 0
+ ]
+ )
+}
+
+/**
+ * An `isLikelyConversionConstant` constant indicates conversion that is ignorable, e.g.,
+ * julian to gregorian conversion or conversions from linux time structs
+ * that start at 1900, etc.
+ */
+class IgnorableConstantArithmetic extends IgnorableOperation {
+ IgnorableConstantArithmetic() {
+ exists(int i | isLikelyConversionConstant(i) |
+ this.(Operation).getAnOperand().getValue().toInt() = i
or
- // If there is a data flow from the variable that was modified to a function that seems to check for leap year
- exists(VariableAccess source, ChecksForLeapYearFunctionCall fc |
- source = var.getAnAccess() and
- LeapYearCheckFlow::flow(DataFlow::exprNode(source), DataFlow::exprNode(fc.getAnArgument()))
- )
- or
- // If there is a data flow from the field that was modified to a function that seems to check for leap year
- exists(VariableAccess vacheck, YearFieldAccess yfacheck, ChecksForLeapYearFunctionCall fc |
- vacheck = var.getAnAccess() and
- yfacheck.getQualifier() = vacheck and
- LeapYearCheckFlow::flow(DataFlow::exprNode(yfacheck), DataFlow::exprNode(fc.getAnArgument()))
- )
- or
- // If there is a successor or predecessor that sets the month = 1
- exists(MonthFieldAccess mfa, AssignExpr ae |
- mfa.getQualifier() = var.getAnAccess() and
- mfa.isModified() and
- (
- mfa.getBasicBlock() = yfa.getBasicBlock().getASuccessor*() or
- yfa.getBasicBlock() = mfa.getBasicBlock().getASuccessor+()
- ) and
- ae = mfa.getEnclosingElement() and
- ae.getAnOperand().getValue().toInt() = 1
+ exists(AssignArithmeticOperation a | this = a.getRValue() |
+ a.getRValue().getValue().toInt() = i
)
)
+ }
+}
+
+// If a unary minus assume it is some sort of conversion
+class IgnorableUnaryMinus extends IgnorableOperation {
+ IgnorableUnaryMinus() {
+ this instanceof UnaryMinusExpr
+ or
+ this.(Operation).getAnOperand() instanceof UnaryMinusExpr
+ }
+}
+
+/**
+ * An argument to a function is ignorable if the function that is called is an ignored function
+ */
+class OperationAsArgToIgnorableFunction extends IgnorableOperation {
+ OperationAsArgToIgnorableFunction() {
+ exists(Call c |
+ c.getAnArgument().getAChild*() = this and
+ c.getTarget() instanceof IgnorableFunction
+ )
+ }
+}
+
+/**
+ * A binary operation on two literals means the result is constant/known
+ * and the operation is basically ignorable (it's not a real operation but
+ * probably one visual simplicity what it means).
+ */
+class ConstantBinaryArithmeticOperation extends IgnorableOperation, BinaryArithmeticOperation {
+ ConstantBinaryArithmeticOperation() {
+ this.getLeftOperand() instanceof Literal and
+ this.getRightOperand() instanceof Literal
+ }
+}
+
+class IgnorableBinaryBitwiseOperation extends IgnorableOperation instanceof BinaryBitwiseOperation {
+}
+
+class IgnorableUnaryBitwiseOperation extends IgnorableOperation instanceof UnaryBitwiseOperation { }
+
+class IgnorableAssignmentBitwiseOperation extends IgnorableOperation instanceof AssignBitwiseOperation
+{ }
+
+/**
+ * An arithmetic operation where one of the operands is a pointer or char type, ignore it
+ */
+class IgnorablePointerOrCharArithmetic extends IgnorableOperation {
+ IgnorablePointerOrCharArithmetic() {
+ this instanceof BinaryArithmeticOperation and
+ exists(Expr op | op = this.(BinaryArithmeticOperation).getAnOperand() |
+ op.getUnspecifiedType() instanceof PointerType
+ or
+ op.getUnspecifiedType() instanceof CharType
+ or
+ // Operations on calls to functions that accept char or char*
+ op.(Call).getAnArgument().getUnspecifiedType().stripType() instanceof CharType
+ or
+ // Operations on calls to functions named like "strlen", "wcslen", etc
+ // NOTE: workaround for cases where the wchar_t type is not a char, but an unsigned short
+ // unclear if there is a best way to filter cases like these out based on type info.
+ op.(Call).getTarget().getName().matches("%len%")
+ )
+ or
+ exists(AssignArithmeticOperation a | a.getRValue() = this |
+ exists(Expr op | op = a.getAnOperand() |
+ op.getUnspecifiedType() instanceof PointerType
+ or
+ op.getUnspecifiedType() instanceof CharType
+ or
+ // Operations on calls to functions that accept char or char*
+ op.(Call).getAnArgument().getUnspecifiedType().stripType() instanceof CharType
+ )
+ or
+ // Operations on calls to functions named like "strlen", "wcslen", etc
+ // for example `strlen(foo) + bar`
+ this.(BinaryArithmeticOperation).getAnOperand().(Call).getTarget().getName().matches("%len%")
+ )
+ }
+}
+
+/**
+ * Holds for an expression that is an add or similar operation that could flow to a Year field.
+ */
+predicate isOperationSourceCandidate(Expr e) {
+ not e instanceof IgnorableOperation and
+ exists(Function f |
+ f = e.getEnclosingFunction() and
+ not f instanceof IgnorableFunction
+ ) and
+ (
+ e instanceof SubExpr
+ or
+ e instanceof AddExpr
+ or
+ e instanceof CrementOperation
+ or
+ e instanceof AssignSubExpr
+ or
+ e instanceof AssignAddExpr
)
-select yfa,
- "Field $@ on variable $@ has been modified, but no appropriate check for LeapYear was found.",
- yfa.getTarget(), yfa.getTarget().toString(), var, var.toString()
+}
+
+/**
+ * A data flow that tracks an ignorable operation (such as a bitwise operation) to an operation source, so we may disqualify it.
+ */
+module IgnorableOperationToOperationSourceCandidateConfig implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node n) { n.asExpr() instanceof IgnorableOperation }
+
+ predicate isSink(DataFlow::Node n) { isOperationSourceCandidate(n.asExpr()) }
+
+ // looking for sources and sinks in the same function
+ DataFlow::FlowFeature getAFeature() {
+ result instanceof DataFlow::FeatureEqualSourceSinkCallContext
+ }
+}
+
+module IgnorableOperationToOperationSourceCandidateFlow =
+ TaintTracking::Global;
+
+/**
+ * The set of all expressions which is a candidate expression and also does not flow from to to some ignorable expression (eg. bitwise op)
+ * ```
+ * a = something <<< 2;
+ * myDate.year = a + 1; // invalid
+ * ...
+ * a = someDate.year + 1;
+ * myDate.year = a; // valid
+ * ```
+ */
+class OperationSource extends Expr {
+ OperationSource() {
+ isOperationSourceCandidate(this) and
+ // If the candidate came from an ignorable operation, ignore the candidate
+ // NOTE: we cannot easily flow the candidate to an ignorable operation as that can
+ // be tricky in practice, e.g., a mod operation on a year would be part of a leap year check
+ // but a mod operation ending in a year is more indicative of something to ignore (a conversion)
+ not exists(IgnorableOperationToOperationSourceCandidateFlow::PathNode sink |
+ sink.getNode().asExpr() = this and
+ sink.isSink()
+ )
+ }
+}
+
+class YearFieldAssignmentNode extends DataFlow::Node {
+ YearFieldAccess access;
+
+ YearFieldAssignmentNode() {
+ exists(Function f |
+ f = this.getEnclosingCallable().getUnderlyingCallable() and not f instanceof IgnorableFunction
+ ) and
+ (
+ this.asDefinition().(Assignment).getLValue() = access
+ or
+ this.asDefinition().(CrementOperation).getOperand() = access
+ or
+ exists(Call c | c.getAnArgument() = access and this.asDefiningArgument() = access)
+ or
+ exists(Call c, AddressOfExpr aoe |
+ c.getAnArgument() = aoe and
+ aoe.getOperand() = access and
+ this.asDefiningArgument() = aoe
+ )
+ )
+ }
+
+ YearFieldAccess getYearFieldAccess() { result = access }
+}
+
+/**
+ * A DataFlow configuration for identifying flows from an identified source
+ * to the Year field of a date object.
+ */
+module OperationToYearAssignmentConfig implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node n) { n.asExpr() instanceof OperationSource }
+
+ predicate isSink(DataFlow::Node n) {
+ n instanceof YearFieldAssignmentNode and
+ not isYearModifiedWithCheck(n) and
+ not isControlledByMonthEqualityCheckNonFebruary(n.asExpr())
+ }
+
+ predicate isBarrier(DataFlow::Node n) {
+ exists(ArrayExpr arr | arr.getArrayOffset() = n.asExpr())
+ or
+ n.getType().getUnspecifiedType() instanceof PointerType
+ or
+ n.getType().getUnspecifiedType() instanceof CharType
+ or
+ // If a type resembles "string" ignore flow (likely string conversion, currently ignored)
+ n.getType().getUnspecifiedType().stripType().getName().toLowerCase().matches("%string%")
+ or
+ n.asExpr() instanceof IgnorableOperation
+ or
+ // Flowing into variables that indicate likely non-gregorian years are barriers
+ // e.g., names similar to hijri, persian, lunar, chinese, hebrew, etc.
+ exists(Variable v |
+ v.getName()
+ .toLowerCase()
+ .matches(["%hijri%", "%persian%", "%lunar%", "%chinese%", "%hebrew%"]) and
+ v.getAnAccess() = [n.asIndirectExpr(), n.asExpr()]
+ )
+ or
+ isLeapYearCheckSink(n)
+ or
+ // this is a bit of a hack to address cases where a year is normalized and checked, but the
+ // normalized year is never itself assigned to the final year struct
+ // isLeapYear(getCivilYear(year))
+ // struct.year = year
+ // This is assuming a user would have done this all on one line though.
+ // setting a variable for the conversion and passing that separately would be more difficult to track
+ // considering this approach good enough for current observed false positives
+ exists(Expr arg |
+ isLeapYearCheckCall(_, arg) and arg.getAChild*() = [n.asExpr(), n.asIndirectExpr()]
+ )
+ or
+ // If as the flow progresses, the value holding a dangerous operation result
+ // is apparently being passed by address to some function, it is more than likely
+ // intended to be modified, and therefore, the definition is killed.
+ exists(Call c | c.getAnArgument().(AddressOfExpr).getAnOperand() = n.asIndirectExpr())
+ }
+
+ /** Block flow out of an operation source to get the "closest" operation to the sink */
+ predicate isBarrierIn(DataFlow::Node n) { isSource(n) }
+
+ predicate isBarrierOut(DataFlow::Node n) { isSink(n) }
+}
+
+module OperationToYearAssignmentFlow = TaintTracking::Global;
+
+predicate isLeapYearCheckSink(DataFlow::Node sink) {
+ exists(LeapYearGuardCondition lgc |
+ lgc.checkedYearAccess() = [sink.asExpr(), sink.asIndirectExpr()]
+ )
+ or
+ isLeapYearCheckCall(_, [sink.asExpr(), sink.asIndirectExpr()])
+}
+
+predicate yearAssignmentToCheckCommonSteps(DataFlow::Node node1, DataFlow::Node node2) {
+ // flow from a YearFieldAccess to the qualifier
+ node2.asExpr() = node1.asExpr().(YearFieldAccess).getQualifier*()
+ or
+ // getting the 'access' can be tricky at definitions (assignments especially)
+ // as dataflow uses asDefinition not asExpr.
+ // the YearFieldAssignmentNode holds the access in these cases
+ node1.(YearFieldAssignmentNode).getYearFieldAccess().getQualifier() = node2.asExpr()
+ or
+ // flow from a year access qualifier to a year field
+ exists(YearFieldAccess yfa | node2.asExpr() = yfa and node1.asExpr() = yfa.getQualifier())
+ or
+ node1.(YearFieldAssignmentNode).getYearFieldAccess().getQualifier() = node2.asExpr()
+ or
+ // Pass through any intermediate struct
+ exists(Assignment a |
+ a.getRValue() = node1.asExpr() and
+ node2.asExpr() = a.getLValue().(YearFieldAccess).getQualifier*()
+ )
+ or
+ // in cases of t.year = x and the value of x is checked, but the year t.year isn't directly checked
+ // flow from a year assignment node to an RHS if it is an assignment
+ // e.g.,
+ // t.year = x;
+ // isLeapYear(x);
+ // --> at this point there is no flow of t.year to a check, but only its raw value
+ // To detect the flow of 'x' to the isLeapYear check,
+ // flow from t.year to 'x' (at assignment, t.year = x, flow to the RHS to track use-use flow of x)
+ exists(YearFieldAssignmentNode yfan |
+ node1 = yfan and
+ node2.asExpr() = yfan.asDefinition().(Assignment).getRValue()
+ )
+}
+
+/**
+ * A flow configuration from a Year field access to some Leap year check or guard
+ */
+module YearAssignmentToLeapYearCheckConfig implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node source) { source instanceof YearFieldAssignmentNode }
+
+ predicate isSink(DataFlow::Node sink) { isLeapYearCheckSink(sink) }
+
+ predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
+ yearAssignmentToCheckCommonSteps(node1, node2)
+ }
+
+ /**
+ * Enforcing the check must occur in the same call context as the source,
+ * i.e., do not return from the source function and check in a caller.
+ */
+ DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
+}
+
+module YearAssignmentToLeapYearCheckFlow =
+ TaintTracking::Global;
+
+/** Does there exist a flow from the given YearFieldAccess to a Leap Year check or guard? */
+predicate isYearModifiedWithCheck(YearFieldAssignmentNode n) {
+ exists(YearAssignmentToLeapYearCheckFlow::PathNode src |
+ src.isSource() and
+ src.getNode() = n
+ )
+ or
+ // If the time flows to a time conversion whose value/result is checked,
+ // assume the leap year is being handled.
+ exists(YearAssignmentToCheckedTimeConversionFlow::PathNode timeQualSrc |
+ timeQualSrc.isSource() and
+ timeQualSrc.getNode() = n
+ )
+}
+
+/**
+ * An expression which checks the value of a Month field `a->month == 1`.
+ */
+class MonthEqualityCheck extends EqualityOperation {
+ MonthEqualityCheck() { this.getAnOperand() instanceof MonthFieldAccess }
+
+ Expr getExprCompared() {
+ exists(Expr e |
+ e = this.getAnOperand() and
+ not e instanceof MonthFieldAccess and
+ result = e
+ )
+ }
+}
+
+final class FinalMonthEqualityCheck = MonthEqualityCheck;
+
+class MonthEqualityCheckGuard extends GuardCondition, FinalMonthEqualityCheck { }
+
+/**
+ * Verifies if the expression is guarded by a check on the Month property of a date struct, that is NOT February.
+ */
+bindingset[e]
+pragma[inline_late]
+predicate isControlledByMonthEqualityCheckNonFebruary(Expr e) {
+ exists(MonthEqualityCheckGuard monthGuard, Expr compared |
+ monthGuard.controls(e.getBasicBlock(), true) and
+ compared = monthGuard.getExprCompared() and
+ not compared.getValue().toInt() = 2
+ )
+}
+
+/**
+ * Flow from a year field access to a time conversion function
+ * that auto converts feb29 in non-leap year, or through a conversion function that doesn't
+ * auto convert to a sanity check guard of the result for error conditions.
+ */
+module YearAssignmentToCheckedTimeConversionConfig implements DataFlow::StateConfigSig {
+ // Flow state tracks if flow goes through a known time conversion function
+ // see `TimeConversionFunction`.
+ // A valid check with a time conversion function is either the case:
+ // 1) the year flows into a time conversion function, and the time conversion function's result is checked or
+ // 2) the year flows into a time conversion function that auto corrects for leap year, so no check is necessary.
+ class FlowState = boolean;
+
+ predicate isSource(DataFlow::Node source, FlowState state) {
+ source instanceof YearFieldAssignmentNode and
+ state = false
+ }
+
+ predicate isSink(DataFlow::Node sink, FlowState state) {
+ // Case 1: Flow through a time conversion function that requires a check,
+ // and we have arrived at a guard, implying the result was checked for possible error, including leap year error.
+ // state = true indicates the flow went through a time conversion function
+ state = true and
+ (
+ exists(IfStmt ifs | ifs.getCondition().getAChild*() = [sink.asExpr(), sink.asIndirectExpr()])
+ or
+ exists(ConditionalExpr ce |
+ ce.getCondition().getAChild*() = [sink.asExpr(), sink.asIndirectExpr()]
+ )
+ or
+ exists(Loop l | l.getCondition().getAChild*() = [sink.asExpr(), sink.asIndirectExpr()])
+ )
+ or
+ // Case 2: Flow through a time conversion function that auto corrects for leap year, so no check is necessary.
+ // state true or false, as flowing through a time conversion function is not necessary in this instance.
+ state in [true, false] and
+ exists(Call c, TimeConversionFunction f |
+ f.isAutoLeapYearCorrecting() and
+ c.getTarget() = f and
+ c.getAnArgument().getAChild*() = [sink.asExpr(), sink.asIndirectExpr()]
+ )
+ }
+
+ predicate isAdditionalFlowStep(
+ DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
+ ) {
+ state1 in [true, false] and
+ state2 = true and
+ exists(Call c |
+ c.getTarget() instanceof TimeConversionFunction and
+ c.getAnArgument().getAChild*() = [node1.asExpr(), node1.asIndirectExpr()] and
+ node2.asExpr() = c
+ )
+ }
+
+ predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
+ yearAssignmentToCheckCommonSteps(node1, node2)
+ }
+
+ DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
+}
+
+module YearAssignmentToCheckedTimeConversionFlow =
+ DataFlow::GlobalWithState;
+
+/**
+ * Finds flow from a parameter of a function to a leap year check.
+ * This is necessary to handle for scenarios like this:
+ *
+ * year = DANGEROUS_OP // source
+ * isLeap = isLeapYear(year);
+ * // logic based on isLeap
+ * struct.year = year; // sink
+ *
+ * In this case, we may flow a dangerous op to a year assignment, failing
+ * to barrier the flow through a leap year check, as the leap year check
+ * is nested, and dataflow does not progress down into the check and out.
+ * Instead, the point of this flow is to detect isLeapYear's argument
+ * is checked for leap year, making the isLeapYear call a barrier for
+ * the dangerous flow if we flow through the parameter identified to
+ * be checked.
+ */
+module ParameterToLeapYearCheckConfig implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node source) { exists(source.asParameter()) }
+
+ predicate isSink(DataFlow::Node sink) {
+ exists(LeapYearGuardCondition lgc |
+ lgc.checkedYearAccess() = [sink.asExpr(), sink.asIndirectExpr()]
+ )
+ }
+
+ predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
+ // flow from a YearFieldAccess to the qualifier
+ node2.asExpr() = node1.asExpr().(YearFieldAccess).getQualifier*()
+ or
+ // flow from a year access qualifier to a year field
+ exists(YearFieldAccess yfa | node2.asExpr() = yfa and node1.asExpr() = yfa.getQualifier())
+ }
+
+ /**
+ * Enforcing the check must occur in the same call context as the source,
+ * i.e., do not return from the source function and check in a caller.
+ */
+ DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
+}
+
+// NOTE: I do not believe taint flow is necessary here as we should
+// be flowing directyly from some parameter to a leap year check.
+module ParameterToLeapYearCheckFlow = DataFlow::Global;
+
+predicate isLeapYearCheckCall(Call c, Expr arg) {
+ exists(ParameterToLeapYearCheckFlow::PathNode src, Function f, int i |
+ src.isSource() and
+ f.getParameter(i) = src.getNode().asParameter() and
+ c.getTarget() = f and
+ c.getArgument(i) = arg
+ )
+}
+
+class LeapYearGuardCondition extends GuardCondition {
+ Expr yearSinkDiv4;
+ Expr yearSinkDiv100;
+ Expr yearSinkDiv400;
+
+ LeapYearGuardCondition() {
+ exists(
+ LogicalAndExpr andExpr, LogicalOrExpr orExpr, GuardCondition div4Check,
+ GuardCondition div100Check, GuardCondition div400Check, GuardValue gv
+ |
+ // canonical case:
+ // form: `(year % 4 == 0) && (year % 100 != 0 || year % 400 == 0)`
+ // `!((year % 4 == 0) && (year % 100 != 0 || year % 400 == 0))`
+ // `!(year % 4) && (year % 100 || !(year % 400))`
+ // Also accepting `((year & 3) == 0) && (year % 100 != 0 || year % 400 == 0)`
+ // and `(year % 4 == 0) && (year % 100 > 0 || year % 400 == 0)`
+ this = andExpr and
+ andExpr.hasOperands(div4Check, orExpr) and
+ orExpr.hasOperands(div100Check, div400Check) and
+ (
+ // year % 4 == 0
+ exists(RemExpr e |
+ div4Check.comparesEq(e, 0, true, gv) and
+ e.getRightOperand().getValue().toInt() = 4 and
+ yearSinkDiv4 = e.getLeftOperand()
+ )
+ or
+ // year & 3 == 0
+ exists(BitwiseAndExpr e |
+ div4Check.comparesEq(e, 0, true, gv) and
+ e.getRightOperand().getValue().toInt() = 3 and
+ yearSinkDiv4 = e.getLeftOperand()
+ )
+ ) and
+ exists(RemExpr e |
+ // year % 100 != 0 or year % 100 > 0
+ (
+ div100Check.comparesEq(e, 0, false, gv) or
+ div100Check.comparesLt(e, 1, false, gv)
+ ) and
+ e.getRightOperand().getValue().toInt() = 100 and
+ yearSinkDiv100 = e.getLeftOperand()
+ ) and
+ // year % 400 == 0
+ exists(RemExpr e |
+ div400Check.comparesEq(e, 0, true, gv) and
+ e.getRightOperand().getValue().toInt() = 400 and
+ yearSinkDiv400 = e.getLeftOperand()
+ )
+ or
+ // Inverted logic case:
+ // `year % 4 != 0 || (year % 100 == 0 && year % 400 != 0)`
+ // or `year & 3 != 0 || (year % 100 == 0 && year % 400 != 0)`
+ // also accepting `year % 4 > 0 || (year % 100 == 0 && year % 400 > 0)`
+ this = orExpr and
+ orExpr.hasOperands(div4Check, andExpr) and
+ andExpr.hasOperands(div100Check, div400Check) and
+ (
+ // year % 4 != 0 or year % 4 > 0
+ exists(RemExpr e |
+ (
+ div4Check.comparesEq(e, 0, false, gv)
+ or
+ div4Check.comparesLt(e, 1, false, gv)
+ ) and
+ e.getRightOperand().getValue().toInt() = 4 and
+ yearSinkDiv4 = e.getLeftOperand()
+ )
+ or
+ // year & 3 != 0
+ exists(BitwiseAndExpr e |
+ div4Check.comparesEq(e, 0, false, gv) and
+ e.getRightOperand().getValue().toInt() = 3 and
+ yearSinkDiv4 = e.getLeftOperand()
+ )
+ ) and
+ // year % 100 == 0
+ exists(RemExpr e |
+ div100Check.comparesEq(e, 0, true, gv) and
+ e.getRightOperand().getValue().toInt() = 100 and
+ yearSinkDiv100 = e.getLeftOperand()
+ ) and
+ // year % 400 != 0 or year % 400 > 0
+ exists(RemExpr e |
+ (
+ div400Check.comparesEq(e, 0, false, gv)
+ or
+ div400Check.comparesLt(e, 1, false, gv)
+ ) and
+ e.getRightOperand().getValue().toInt() = 400 and
+ yearSinkDiv400 = e.getLeftOperand()
+ )
+ )
+ }
+
+ Expr getYearSinkDiv4() { result = yearSinkDiv4 }
+
+ Expr getYearSinkDiv100() { result = yearSinkDiv100 }
+
+ Expr getYearSinkDiv400() { result = yearSinkDiv400 }
+
+ /**
+ * Gets the variable access that is used in all 3 components of the leap year check
+ * e.g., see getYearSinkDiv4/100/400..
+ * If a field access is used, the qualifier and the field access are both returned
+ * in checked condition.
+ * NOTE: if the year is not checked using the same access in all 3 components, no result is returned.
+ * The typical case observed is a consistent variable access is used. If not, this may indicate a bug.
+ * We could check more accurately with a dataflow analysis, but this is likely sufficient for now.
+ */
+ VariableAccess checkedYearAccess() {
+ exists(Variable var |
+ (
+ this.getYearSinkDiv4().getAChild*() = var.getAnAccess() and
+ this.getYearSinkDiv100().getAChild*() = var.getAnAccess() and
+ this.getYearSinkDiv400().getAChild*() = var.getAnAccess() and
+ result = var.getAnAccess() and
+ (
+ result = this.getYearSinkDiv4().getAChild*() or
+ result = this.getYearSinkDiv100().getAChild*() or
+ result = this.getYearSinkDiv400().getAChild*()
+ )
+ )
+ )
+ }
+}
+
+/**
+ * A difficult case to detect is if a year modification is tied to a month or day modification
+ * and the month or day is safe for leap year.
+ * e.g.,
+ * year++;
+ * month = 1;
+ * // alternative: day = 15;
+ * ... values eventually used in the same time struct
+ * If this is even more challenging if the struct the values end up in are not
+ * local (set inter-procedurally).
+ * This configuration looks for constants 1-31 flowing to a month or day assignment.
+ * It is assumed a user of this flow will check if the month/day source and month/day sink
+ * are in the same basic blocks as a year modification source and a year modification sink.
+ * It is also assumed a user will check if the constant source is a value that is ignorable
+ * e.g., if it is 2 and the sink is a month assignment, then it isn't ignorable or
+ * if the value is < 27 and is a day assignment, it is likely ignorable
+ *
+ * Obviously this does not handle all conditions (e.g., the month set in another block).
+ * It is meant to capture the most common cases of false positives.
+ */
+module CandidateConstantToDayOrMonthAssignmentConfig implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node source) {
+ source.asExpr().getValue().toInt() in [1 .. 31] and
+ (
+ exists(Assignment a | a.getRValue() = source.asExpr())
+ or
+ exists(Call c | c.getAnArgument() = source.asExpr())
+ )
+ }
+
+ predicate isSink(DataFlow::Node sink) {
+ exists(Assignment a |
+ (a.getLValue() instanceof MonthFieldAccess or a.getLValue() instanceof DayFieldAccess) and
+ a.getRValue() = sink.asExpr()
+ )
+ }
+}
+
+// NOTE: only data flow here (no taint tracking) as we want the exact
+// constant flowing to the month assignment
+module CandidateConstantToDayOrMonthAssignmentFlow =
+ DataFlow::Global;
+
+/**
+ * Holds if value the assignment `a` resolves to (`dayOrMonthValSrcExpr`) doesn't represent February,
+ * and/or if it represents a day, is a 'safe' day (meaning the 27th or prior).
+ */
+bindingset[dayOrMonthValSrcExpr]
+predicate isSafeValueForAssignmentOfMonthOrDayValue(Assignment a, Expr dayOrMonthValSrcExpr) {
+ a.getLValue() instanceof MonthFieldAccess and
+ dayOrMonthValSrcExpr.getValue().toInt() != 2
+ or
+ a.getLValue() instanceof DayFieldAccess and
+ dayOrMonthValSrcExpr.getValue().toInt() <= 27
+}
+
+import OperationToYearAssignmentFlow::PathGraph
+
+from OperationToYearAssignmentFlow::PathNode src, OperationToYearAssignmentFlow::PathNode sink
+where
+ OperationToYearAssignmentFlow::flowPath(src, sink) and
+ // Check if a month is set in the same block as the year operation source
+ // and the month value would indicate its set to any other month than february.
+ // Finds if the source year node is in the same block as a source month block
+ // and if the same for the sinks.
+ not exists(DataFlow::Node dayOrMonthValSrc, DataFlow::Node dayOrMonthValSink, Assignment a |
+ CandidateConstantToDayOrMonthAssignmentFlow::flow(dayOrMonthValSrc, dayOrMonthValSink) and
+ a.getRValue() = dayOrMonthValSink.asExpr() and
+ dayOrMonthValSink.getBasicBlock() = sink.getNode().getBasicBlock() and
+ exists(IRBlock dayOrMonthValBB |
+ dayOrMonthValBB = dayOrMonthValSrc.getBasicBlock() and
+ // The source of the day is set in the same block as the source for the year
+ // or the source for the day is set in the same block as the sink for the year
+ dayOrMonthValBB in [
+ src.getNode().getBasicBlock(),
+ sink.getNode().getBasicBlock()
+ ]
+ ) and
+ isSafeValueForAssignmentOfMonthOrDayValue(a, dayOrMonthValSrc.asExpr())
+ )
+select sink, src, sink,
+ "Year field has been modified, but no appropriate check for LeapYear was found."
diff --git a/cpp/ql/src/Likely Bugs/Leap Year/UncheckedReturnValueForTimeFunctions.ql b/cpp/ql/src/Likely Bugs/Leap Year/UncheckedReturnValueForTimeFunctions.ql
index af02a2814a2..8e2d6e9d10f 100644
--- a/cpp/ql/src/Likely Bugs/Leap Year/UncheckedReturnValueForTimeFunctions.ql
+++ b/cpp/ql/src/Likely Bugs/Leap Year/UncheckedReturnValueForTimeFunctions.ql
@@ -44,23 +44,9 @@ class SafeTimeGatheringFunction extends Function {
}
}
-/**
- * This list of APIs should check for the return value to detect problems during the conversion.
- */
-class TimeConversionFunction extends Function {
- TimeConversionFunction() {
- this.getQualifiedName() =
- [
- "FileTimeToSystemTime", "SystemTimeToFileTime", "SystemTimeToTzSpecificLocalTime",
- "SystemTimeToTzSpecificLocalTimeEx", "TzSpecificLocalTimeToSystemTime",
- "TzSpecificLocalTimeToSystemTimeEx", "RtlLocalTimeToSystemTime",
- "RtlTimeToSecondsSince1970", "_mkgmtime"
- ]
- }
-}
-
from FunctionCall fcall, TimeConversionFunction trf, Variable var
where
+ not trf.isAutoLeapYearCorrecting() and
fcall = trf.getACallToThisFunction() and
fcall instanceof ExprInVoidContext and
var.getUnderlyingType() instanceof UnpackedTimeType and
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql b/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql
index b4e517b3bab..c85b33a9727 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql
@@ -15,6 +15,7 @@
import cpp
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
import semmle.code.cpp.ir.dataflow.DataFlow
+private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
/** Gets a loop that contains `e`. */
Loop getAnEnclosingLoopOfExpr(Expr e) { result = getAnEnclosingLoopOfStmt(e.getEnclosingStmt()) }
@@ -45,9 +46,9 @@ private Expr getExpr(DataFlow::Node node) {
or
result = node.asOperand().getUse().getAst()
or
- result = node.(DataFlow::RawIndirectInstruction).getInstruction().getAst()
+ result = node.(RawIndirectInstruction).getInstruction().getAst()
or
- result = node.(DataFlow::RawIndirectOperand).getOperand().getUse().getAst()
+ result = node.(RawIndirectOperand).getOperand().getUse().getAst()
}
/**
@@ -208,7 +209,7 @@ class LoopWithAlloca extends Stmt {
this.conditionRequiresInequality(va, _, _) and
DataFlow::localFlow(result, DataFlow::exprNode(va)) and
// Phi nodes will be preceded by nodes that represent actual definitions
- not result instanceof DataFlow::SsaSynthNode and
+ not result instanceof SsaSynthNode and
// A source is outside the loop if it's not inside the loop
not exists(Expr e | e = getExpr(result) | this = getAnEnclosingLoopOfExpr(e))
)
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql b/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql
index b8788910332..efd136bcd2d 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql
@@ -16,17 +16,15 @@
import cpp
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.dataflow.MustFlow
-import PathGraph
+import ReturnStackAllocatedMemory::PathGraph
/** Holds if `f` has a name that we interpret as evidence of intentionally returning the value of the stack pointer. */
predicate intentionallyReturnsStackPointer(Function f) {
f.getName().toLowerCase().matches(["%stack%", "%sp%"])
}
-class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
- ReturnStackAllocatedMemoryConfig() { this = "ReturnStackAllocatedMemoryConfig" }
-
- override predicate isSource(Instruction source) {
+module ReturnStackAllocatedMemoryConfig implements MustFlow::ConfigSig {
+ predicate isSource(Instruction source) {
exists(Function func |
// Rule out FPs caused by extraction errors.
not func.hasErrors() and
@@ -50,7 +48,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
)
}
- override predicate isSink(Operand sink) {
+ predicate isSink(Operand sink) {
// Holds if `sink` is a node that represents the `StoreInstruction` that is subsequently used in
// a `ReturnValueInstruction`.
// We use the `StoreInstruction` instead of the instruction that defines the
@@ -72,7 +70,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
// int* px = id(&x);
// }
// ```
- override predicate allowInterproceduralFlow() { none() }
+ predicate allowInterproceduralFlow() { none() }
/**
* This configuration intentionally conflates addresses of fields and their object, and pointer offsets
@@ -87,20 +85,22 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
* }
* ```
*/
- override predicate isAdditionalFlowStep(Operand node1, Instruction node2) {
+ predicate isAdditionalFlowStep(Operand node1, Instruction node2) {
node2.(FieldAddressInstruction).getObjectAddressOperand() = node1
or
node2.(PointerOffsetInstruction).getLeftOperand() = node1
}
- override predicate isBarrier(Instruction n) { n.getResultType() instanceof ErroneousType }
+ predicate isBarrier(Instruction n) { n.getResultType() instanceof ErroneousType }
}
+module ReturnStackAllocatedMemory = MustFlow::Global;
+
from
- MustFlowPathNode source, MustFlowPathNode sink, Instruction instr,
- ReturnStackAllocatedMemoryConfig conf
+ ReturnStackAllocatedMemory::PathNode source, ReturnStackAllocatedMemory::PathNode sink,
+ Instruction instr
where
- conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
+ ReturnStackAllocatedMemory::flowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
source.getInstruction() = instr
select sink.getInstruction(), source, sink, "May return stack-allocated memory from $@.",
instr.getAst(), instr.getAst().toString()
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql b/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql
index 763a142f1b9..1697ad31810 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql
@@ -15,7 +15,7 @@
import cpp
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.dataflow.MustFlow
-import PathGraph
+import UninitializedLocal::PathGraph
/**
* Auxiliary predicate: Types that don't require initialization
@@ -70,25 +70,26 @@ predicate isSinkImpl(Instruction sink, VariableAccess va) {
)
}
-class MustFlow extends MustFlowConfiguration {
- MustFlow() { this = "MustFlow" }
-
- override predicate isSource(Instruction source) {
+module UninitializedLocalConfig implements MustFlow::ConfigSig {
+ predicate isSource(Instruction source) {
source instanceof UninitializedInstruction and
exists(Type t | t = source.getResultType() | not allocatedType(t))
}
- override predicate isSink(Operand sink) { isSinkImpl(sink.getDef(), _) }
+ predicate isSink(Operand sink) { isSinkImpl(sink.getDef(), _) }
- override predicate allowInterproceduralFlow() { none() }
+ predicate allowInterproceduralFlow() { none() }
- override predicate isBarrier(Instruction instr) { instr instanceof ChiInstruction }
+ predicate isBarrier(Instruction instr) { instr instanceof ChiInstruction }
}
+module UninitializedLocal = MustFlow::Global;
+
from
- VariableAccess va, LocalVariable v, MustFlow conf, MustFlowPathNode source, MustFlowPathNode sink
+ VariableAccess va, LocalVariable v, UninitializedLocal::PathNode source,
+ UninitializedLocal::PathNode sink
where
- conf.hasFlowPath(source, sink) and
+ UninitializedLocal::flowPath(source, sink) and
isSinkImpl(sink.getInstruction(), va) and
v = va.getTarget()
select va, source, sink, "The variable $@ may not be initialized at this access.", v, v.getName()
diff --git a/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql b/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql
index bb62cfc1755..63b56d470e2 100644
--- a/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql
+++ b/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql
@@ -17,16 +17,16 @@
import cpp
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.dataflow.MustFlow
-import PathGraph
+import UnsafeUseOfThis::PathGraph
-class UnsafeUseOfThisConfig extends MustFlowConfiguration {
- UnsafeUseOfThisConfig() { this = "UnsafeUseOfThisConfig" }
+module UnsafeUseOfThisConfig implements MustFlow::ConfigSig {
+ predicate isSource(Instruction source) { isSource(source, _, _) }
- override predicate isSource(Instruction source) { isSource(source, _, _) }
-
- override predicate isSink(Operand sink) { isSink(sink, _) }
+ predicate isSink(Operand sink) { isSink(sink, _) }
}
+module UnsafeUseOfThis = MustFlow::Global;
+
/** Holds if `sink` is a `this` pointer used by the call instruction `call`. */
predicate isSink(Operand sink, CallInstruction call) {
exists(PureVirtualFunction func |
@@ -66,19 +66,17 @@ predicate isSource(InitializeParameterInstruction source, string msg, Class c) {
* - `msg` is a string describing whether `source` is from a constructor or destructor.
*/
predicate flows(
- MustFlowPathNode source, string msg, Class sourceClass, MustFlowPathNode sink,
+ UnsafeUseOfThis::PathNode source, string msg, Class sourceClass, UnsafeUseOfThis::PathNode sink,
CallInstruction call
) {
- exists(UnsafeUseOfThisConfig conf |
- conf.hasFlowPath(source, sink) and
- isSource(source.getInstruction(), msg, sourceClass) and
- isSink(sink.getInstruction().getAUse(), call)
- )
+ UnsafeUseOfThis::flowPath(source, sink) and
+ isSource(source.getInstruction(), msg, sourceClass) and
+ isSink(sink.getInstruction().getAUse(), call)
}
from
- MustFlowPathNode source, MustFlowPathNode sink, CallInstruction call, string msg,
- Class sourceClass
+ UnsafeUseOfThis::PathNode source, UnsafeUseOfThis::PathNode sink, CallInstruction call,
+ string msg, Class sourceClass
where
flows(source, msg, sourceClass, sink, call) and
// Only raise an alert if there is no override of the pure virtual function in any base class.
diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.qhelp b/cpp/ql/src/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.qhelp
index 6ff60d38341..90a98e1bf57 100644
--- a/cpp/ql/src/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.qhelp
+++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.qhelp
@@ -14,6 +14,9 @@ function may behave unpredictably.
This may indicate a misspelled function name, or that the required header containing
the function declaration has not been included.
+Note: This query is not compatible with build mode: none databases, and produces
+no results on those databases.
+
Provide an explicit declaration of the function before invoking it.
@@ -26,4 +29,4 @@ the function declaration has not been included.
SEI CERT C Coding Standard: DCL31-C. Declare identifiers before using them
-
\ No newline at end of file
+
diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql
index 6a55557cf70..00b29efbd0f 100644
--- a/cpp/ql/src/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql
+++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql
@@ -5,7 +5,7 @@
* may lead to unpredictable behavior.
* @kind problem
* @problem.severity warning
- * @precision medium
+ * @precision high
* @id cpp/implicit-function-declaration
* @tags correctness
* maintainability
@@ -17,6 +17,11 @@ import TooFewArguments
import TooManyArguments
import semmle.code.cpp.commons.Exclusions
+/*
+ * This query is not compatible with build mode: none databases, and produces
+ * no results on those databases.
+ */
+
predicate locInfo(Locatable e, File file, int line, int col) {
e.getFile() = file and
e.getLocation().getStartLine() = line and
@@ -39,6 +44,7 @@ predicate isCompiledAsC(File f) {
from FunctionDeclarationEntry fdeIm, FunctionCall fc
where
isCompiledAsC(fdeIm.getFile()) and
+ not any(Compilation c).buildModeNone() and
not isFromMacroDefinition(fc) and
fdeIm.isImplicit() and
sameLocation(fdeIm, fc) and
diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.qll b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.qll
index 2dced5d8d84..dbb457db505 100644
--- a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.qll
+++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.qll
@@ -79,9 +79,7 @@ private predicate hasZeroParamDecl(Function f) {
// True if this file (or header) was compiled as a C file
private predicate isCompiledAsC(File f) {
- f.compiledAsC()
- or
- exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
+ exists(File src | src.compiledAsC() | src.getAnIncludedFile*() = f)
}
predicate mistypedFunctionArguments(FunctionCall fc, Function f, Parameter p) {
diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll
index 218a54b36c5..fd323513a49 100644
--- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll
+++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll
@@ -28,9 +28,7 @@ private predicate hasZeroParamDecl(Function f) {
/* Holds if this file (or header) was compiled as a C file. */
private predicate isCompiledAsC(File f) {
- f.compiledAsC()
- or
- exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
+ exists(File src | src.compiledAsC() | src.getAnIncludedFile*() = f)
}
/** Holds if `fc` is a call to `f` with too few arguments. */
diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.qll b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.qll
index 7fba78b5550..ab2a98ae3a5 100644
--- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.qll
+++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.qll
@@ -19,9 +19,7 @@ private predicate hasZeroParamDecl(Function f) {
// True if this file (or header) was compiled as a C file
private predicate isCompiledAsC(File f) {
- f.compiledAsC()
- or
- exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
+ exists(File src | src.compiledAsC() | src.getAnIncludedFile*() = f)
}
predicate tooManyArguments(FunctionCall fc, Function f) {
diff --git a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql
index 994aba733d2..0e4a8f9741c 100644
--- a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql
+++ b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql
@@ -4,7 +4,7 @@
* allows for a cross-site scripting vulnerability.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.1
+ * @security-severity 7.8
* @precision high
* @id cpp/cgi-xss
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql
index 37e3fa0c49f..bf6f014672f 100644
--- a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql
+++ b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql
@@ -23,13 +23,31 @@ import Flow::PathGraph
predicate isSource(FlowSource source, string sourceType) { sourceType = source.getSourceType() }
+/**
+ * Holds if `f` is a printf-like function or a (possibly nested) wrapper
+ * that forwards a format-string parameter to one.
+ *
+ * Functions that *implement* printf-like behavior (e.g. a custom
+ * `vsnprintf` variant) internally parse the caller-supplied format string
+ * and build small, bounded, local format strings such as `"%d"` or `"%ld"`
+ * for inner `sprintf` calls. Taint that reaches those inner calls via the
+ * parsed format specifier is not exploitable, so sinks inside such
+ * functions should be excluded.
+ */
+private predicate isPrintfImplementation(Function f) {
+ f instanceof PrintfLikeFunction
+ or
+ exists(PrintfLikeFunction printf | printf.wrapperFunction(f, _, _))
+}
+
module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { isSource(node, _) }
predicate isSink(DataFlow::Node node) {
exists(PrintfLikeFunction printf |
printf.outermostWrapperFunctionCall([node.asExpr(), node.asIndirectExpr()], _)
- )
+ ) and
+ not isPrintfImplementation([node.asExpr(), node.asIndirectExpr()].getEnclosingFunction())
}
private predicate isArithmeticNonCharType(ArithmeticType type) {
diff --git a/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql b/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
index 3f330807304..7d9ef88adea 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
@@ -6,7 +6,7 @@
* @kind problem
* @problem.severity warning
* @security-severity 7.8
- * @precision medium
+ * @precision high
* @tags reliability
* security
* external/cwe/cwe-190
diff --git a/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql b/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql
index d9c9df4fd91..d5a5cd8f665 100644
--- a/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql
+++ b/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql
@@ -6,7 +6,7 @@
* @kind problem
* @problem.severity warning
* @security-severity 8.8
- * @precision medium
+ * @precision high
* @id cpp/suspicious-add-sizeof
* @tags security
* external/cwe/cwe-468
@@ -18,7 +18,8 @@ import IncorrectPointerScalingCommon
private predicate isCharSzPtrExpr(Expr e) {
exists(PointerType pt | pt = e.getFullyConverted().getUnspecifiedType() |
pt.getBaseType() instanceof CharType or
- pt.getBaseType() instanceof VoidType
+ pt.getBaseType() instanceof VoidType or
+ pt.getBaseType() instanceof ErroneousType // this could be char / void type in a successful compilation
)
}
diff --git a/cpp/ql/src/Telemetry/DatabaseQuality.qll b/cpp/ql/src/Telemetry/DatabaseQuality.qll
new file mode 100644
index 00000000000..04351052986
--- /dev/null
+++ b/cpp/ql/src/Telemetry/DatabaseQuality.qll
@@ -0,0 +1,48 @@
+import cpp
+import codeql.util.ReportStats
+
+/** A file that is included in the quality statistics. */
+private class RelevantFile extends File {
+ RelevantFile() { this.fromSource() and exists(this.getRelativePath()) }
+}
+
+module CallTargetStats implements StatsSig {
+ private class RelevantCall extends Call {
+ RelevantCall() { this.getFile() instanceof RelevantFile }
+ }
+
+ // We assume that calls with an implicit target are calls that could not be
+ // resolved. This is accurate in the vast majority of cases, but is inaccurate
+ // for calls that deliberately rely on implicitly declared functions.
+ private predicate hasImplicitTarget(RelevantCall call) {
+ call.getTarget().getADeclarationEntry().isImplicit()
+ }
+
+ int getNumberOfOk() { result = count(RelevantCall call | not hasImplicitTarget(call)) }
+
+ int getNumberOfNotOk() { result = count(RelevantCall call | hasImplicitTarget(call)) }
+
+ string getOkText() { result = "calls with call target" }
+
+ string getNotOkText() { result = "calls with missing call target" }
+}
+
+private class SourceExpr extends Expr {
+ SourceExpr() { this.getFile() instanceof RelevantFile }
+}
+
+private predicate hasGoodType(Expr e) { not e.getType() instanceof ErroneousType }
+
+module ExprTypeStats implements StatsSig {
+ int getNumberOfOk() { result = count(SourceExpr e | hasGoodType(e)) }
+
+ int getNumberOfNotOk() { result = count(SourceExpr e | not hasGoodType(e)) }
+
+ string getOkText() { result = "expressions with known type" }
+
+ string getNotOkText() { result = "expressions with unknown type" }
+}
+
+module CallTargetStatsReport = ReportStats;
+
+module ExprTypeStatsReport = ReportStats;
diff --git a/cpp/ql/src/Telemetry/ExtractorInformation.ql b/cpp/ql/src/Telemetry/ExtractorInformation.ql
new file mode 100644
index 00000000000..a82b3b86ace
--- /dev/null
+++ b/cpp/ql/src/Telemetry/ExtractorInformation.ql
@@ -0,0 +1,28 @@
+/**
+ * @name C/C++ extraction information
+ * @description Information about the extraction for a C/C++ database
+ * @kind metric
+ * @tags summary telemetry
+ * @id cpp/telemetry/extraction-information
+ */
+
+import cpp
+import DatabaseQuality
+
+from string key, float value
+where
+ (
+ CallTargetStatsReport::numberOfOk(key, value) or
+ CallTargetStatsReport::numberOfNotOk(key, value) or
+ CallTargetStatsReport::percentageOfOk(key, value) or
+ ExprTypeStatsReport::numberOfOk(key, value) or
+ ExprTypeStatsReport::numberOfNotOk(key, value) or
+ ExprTypeStatsReport::percentageOfOk(key, value)
+ ) and
+ /* Infinity */
+ value != 1.0 / 0.0 and
+ /* -Infinity */
+ value != -1.0 / 0.0 and
+ /* NaN */
+ value != 0.0 / 0.0
+select key, value
diff --git a/cpp/ql/src/change-notes/released/1.5.11.md b/cpp/ql/src/change-notes/released/1.5.11.md
new file mode 100644
index 00000000000..5f42fc9133d
--- /dev/null
+++ b/cpp/ql/src/change-notes/released/1.5.11.md
@@ -0,0 +1,3 @@
+## 1.5.11
+
+No user-facing changes.
diff --git a/cpp/ql/src/change-notes/released/1.5.12.md b/cpp/ql/src/change-notes/released/1.5.12.md
new file mode 100644
index 00000000000..6c2f3cd309b
--- /dev/null
+++ b/cpp/ql/src/change-notes/released/1.5.12.md
@@ -0,0 +1,3 @@
+## 1.5.12
+
+No user-facing changes.
diff --git a/cpp/ql/src/change-notes/released/1.5.13.md b/cpp/ql/src/change-notes/released/1.5.13.md
new file mode 100644
index 00000000000..293a8ca4ee1
--- /dev/null
+++ b/cpp/ql/src/change-notes/released/1.5.13.md
@@ -0,0 +1,3 @@
+## 1.5.13
+
+No user-facing changes.
diff --git a/cpp/ql/src/change-notes/released/1.5.14.md b/cpp/ql/src/change-notes/released/1.5.14.md
new file mode 100644
index 00000000000..a165735f53d
--- /dev/null
+++ b/cpp/ql/src/change-notes/released/1.5.14.md
@@ -0,0 +1,3 @@
+## 1.5.14
+
+No user-facing changes.
diff --git a/cpp/ql/src/change-notes/released/1.5.15.md b/cpp/ql/src/change-notes/released/1.5.15.md
new file mode 100644
index 00000000000..dd184231746
--- /dev/null
+++ b/cpp/ql/src/change-notes/released/1.5.15.md
@@ -0,0 +1,3 @@
+## 1.5.15
+
+No user-facing changes.
diff --git a/cpp/ql/src/change-notes/released/1.6.0.md b/cpp/ql/src/change-notes/released/1.6.0.md
new file mode 100644
index 00000000000..3bbb9480660
--- /dev/null
+++ b/cpp/ql/src/change-notes/released/1.6.0.md
@@ -0,0 +1,13 @@
+## 1.6.0
+
+### Query Metadata Changes
+
+* The `@security-severity` metadata of `cpp/cgi-xss` has been increased from 6.1 (medium) to 7.8 (high).
+
+### Minor Analysis Improvements
+
+* The "Extraction warnings" (`cpp/diagnostics/extraction-warnings`) diagnostics query no longer yields `ExtractionRecoverableWarning`s for `build-mode: none` databases. The results were found to significantly increase the sizes of the produced SARIF files, making them unprocessable in some cases.
+* Fixed an issue with the "Suspicious add with sizeof" (`cpp/suspicious-add-sizeof`) query causing false positive results in `build-mode: none` databases.
+* Fixed an issue with the "Uncontrolled format string" (`cpp/tainted-format-string`) query involving certain kinds of formatting function implementations.
+* Fixed an issue with the "Wrong type of arguments to formatting function" (`cpp/wrong-type-format-argument`) query causing false positive results in `build-mode: none` databases.
+* Fixed an issue with the "Multiplication result converted to larger type" (`cpp/integer-multiplication-cast-to-long`) query causing false positive results in `build-mode: none` databases.
diff --git a/cpp/ql/src/change-notes/released/1.6.1.md b/cpp/ql/src/change-notes/released/1.6.1.md
new file mode 100644
index 00000000000..83781b87c58
--- /dev/null
+++ b/cpp/ql/src/change-notes/released/1.6.1.md
@@ -0,0 +1,10 @@
+## 1.6.1
+
+### Minor Analysis Improvements
+
+* Added `AllocationFunction` models for `aligned_alloc`, `std::aligned_alloc`, and `bsl::aligned_alloc`.
+* The "Comparison of narrow type with wide type in loop condition" (`cpp/comparison-with-wider-type`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
+* The "Multiplication result converted to larger type" (`cpp/integer-multiplication-cast-to-long`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
+* The "Suspicious add with sizeof" (`cpp/suspicious-add-sizeof`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
+* The "Wrong type of arguments to formatting function" (`cpp/wrong-type-format-argument`) query has been upgraded to `high` precision. This query will now run in the default code scanning suite.
+* The "Implicit function declaration" (`cpp/implicit-function-declaration`) query has been upgraded to `high` precision. However, for `build mode: none` databases, it no longer produces any results. The results in this mode were found to be very noisy and fundamentally imprecise.
diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml
index fda54b31bff..ef7a789e0cf 100644
--- a/cpp/ql/src/codeql-pack.release.yml
+++ b/cpp/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 1.5.10
+lastReleaseVersion: 1.6.1
diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml
index b374fb51f75..714167434c8 100644
--- a/cpp/ql/src/qlpack.yml
+++ b/cpp/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-queries
-version: 1.5.11-dev
+version: 1.6.2-dev
groups:
- cpp
- queries
diff --git a/cpp/ql/src/utils/modelgenerator/internal/CaptureModels.qll b/cpp/ql/src/utils/modelgenerator/internal/CaptureModels.qll
index f2c621d04cb..90160df3c21 100644
--- a/cpp/ql/src/utils/modelgenerator/internal/CaptureModels.qll
+++ b/cpp/ql/src/utils/modelgenerator/internal/CaptureModels.qll
@@ -8,6 +8,7 @@ private import semmle.code.cpp.dataflow.ExternalFlow as ExternalFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as DataFlowPrivate
+private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes as DataFlowNodes
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific
private import semmle.code.cpp.dataflow.new.TaintTracking as Tt
@@ -403,7 +404,7 @@ private module SinkModelGeneratorInput implements SinkModelGeneratorInputSig {
}
predicate apiSource(DataFlow::Node source) {
- DataFlowPrivate::nodeHasOperand(source, any(DataFlow::FieldAddress fa), 1)
+ DataFlowPrivate::nodeHasOperand(source, any(DataFlowNodes::FieldAddress fa), 1)
or
source instanceof DataFlow::ParameterNode
}
@@ -416,7 +417,7 @@ private module SinkModelGeneratorInput implements SinkModelGeneratorInputSig {
result = "Argument[" + DataFlow::repeatStars(indirectionIndex) + argumentIndex + "]"
)
or
- DataFlowPrivate::nodeHasOperand(source, any(DataFlow::FieldAddress fa), 1) and
+ DataFlowPrivate::nodeHasOperand(source, any(DataFlowNodes::FieldAddress fa), 1) and
result = qualifierString()
}
diff --git a/cpp/ql/test/library-tests/ctorinits/ctors.expected b/cpp/ql/test/library-tests/ctorinits/ctors.expected
index 8a14ee6001a..e8eba338560 100644
--- a/cpp/ql/test/library-tests/ctorinits/ctors.expected
+++ b/cpp/ql/test/library-tests/ctorinits/ctors.expected
@@ -1,17 +1,17 @@
-| ctorinits.cpp:5:3:5:10 | NoisyInt | 0 | ConstructorFieldInit | ctorinits.cpp:5:29:5:42 | constructor init of field m_value | 1 | 0 |
-| ctorinits.cpp:13:3:13:11 | NoisyPair | 0 | ConstructorFieldInit | ctorinits.cpp:14:7:14:16 | constructor init of field m_fst | 1 | 0 |
-| ctorinits.cpp:13:3:13:11 | NoisyPair | 1 | ConstructorFieldInit | ctorinits.cpp:15:7:15:16 | constructor init of field m_snd | 1 | 0 |
+| ctorinits.cpp:5:3:5:10 | NoisyInt | 0 | ConstructorDirectFieldInit | ctorinits.cpp:5:29:5:42 | constructor init of field m_value | 1 | 0 |
+| ctorinits.cpp:13:3:13:11 | NoisyPair | 0 | ConstructorDirectFieldInit | ctorinits.cpp:14:7:14:16 | constructor init of field m_fst | 1 | 0 |
+| ctorinits.cpp:13:3:13:11 | NoisyPair | 1 | ConstructorDirectFieldInit | ctorinits.cpp:15:7:15:16 | constructor init of field m_snd | 1 | 0 |
| ctorinits.cpp:16:3:16:11 | NoisyPair | 0 | ConstructorDelegationInit | ctorinits.cpp:16:17:16:31 | call to NoisyPair | 2 | 2 |
| ctorinits.cpp:21:8:21:8 | NoisyTriple | 0 | ConstructorDirectInit | ctorinits.cpp:21:8:21:8 | call to NoisyPair | 0 | 0 |
-| ctorinits.cpp:21:8:21:8 | NoisyTriple | 1 | ConstructorFieldInit | ctorinits.cpp:21:8:21:8 | constructor init of field m_third | 1 | 0 |
-| ctorinits.cpp:28:2:28:9 | ArrayInt | 0 | ConstructorFieldInit | ctorinits.cpp:28:13:28:13 | constructor init of field m_array | 1 | 0 |
-| ctorinits.cpp:42:2:42:16 | ArrayMemberInit | 0 | ConstructorFieldInit | ctorinits.cpp:42:22:42:32 | constructor init of field xs | 1 | 4 |
+| ctorinits.cpp:21:8:21:8 | NoisyTriple | 1 | ConstructorDirectFieldInit | ctorinits.cpp:21:8:21:8 | constructor init of field m_third | 1 | 0 |
+| ctorinits.cpp:28:2:28:9 | ArrayInt | 0 | ConstructorDirectFieldInit | ctorinits.cpp:28:13:28:13 | constructor init of field m_array | 1 | 0 |
+| ctorinits.cpp:42:2:42:16 | ArrayMemberInit | 0 | ConstructorDirectFieldInit | ctorinits.cpp:42:22:42:32 | constructor init of field xs | 1 | 4 |
| ctorinits.cpp:65:3:65:15 | MultipleBases | 0 | ConstructorDirectInit | ctorinits.cpp:69:5:69:8 | call to A | 1 | 1 |
| ctorinits.cpp:65:3:65:15 | MultipleBases | 1 | ConstructorDirectInit | ctorinits.cpp:67:5:67:8 | call to B | 1 | 1 |
| ctorinits.cpp:65:3:65:15 | MultipleBases | 2 | ConstructorDirectInit | ctorinits.cpp:70:5:70:8 | call to C | 1 | 1 |
-| ctorinits.cpp:65:3:65:15 | MultipleBases | 3 | ConstructorFieldInit | ctorinits.cpp:68:5:68:8 | constructor init of field x | 1 | 1 |
-| ctorinits.cpp:65:3:65:15 | MultipleBases | 4 | ConstructorFieldInit | ctorinits.cpp:71:5:71:8 | constructor init of field y | 1 | 1 |
-| ctorinits.cpp:65:3:65:15 | MultipleBases | 5 | ConstructorFieldInit | ctorinits.cpp:66:5:66:8 | constructor init of field z | 1 | 1 |
+| ctorinits.cpp:65:3:65:15 | MultipleBases | 3 | ConstructorDirectFieldInit | ctorinits.cpp:68:5:68:8 | constructor init of field x | 1 | 1 |
+| ctorinits.cpp:65:3:65:15 | MultipleBases | 4 | ConstructorDirectFieldInit | ctorinits.cpp:71:5:71:8 | constructor init of field y | 1 | 1 |
+| ctorinits.cpp:65:3:65:15 | MultipleBases | 5 | ConstructorDirectFieldInit | ctorinits.cpp:66:5:66:8 | constructor init of field z | 1 | 1 |
| ctorinits.cpp:81:8:81:8 | VD | 0 | ConstructorVirtualInit | ctorinits.cpp:81:8:81:8 | call to VB | 0 | 0 |
| ctorinits.cpp:85:3:85:22 | VirtualAndNonVirtual | 0 | ConstructorVirtualInit | ctorinits.cpp:85:26:85:26 | call to VB | 0 | 0 |
| ctorinits.cpp:85:3:85:22 | VirtualAndNonVirtual | 1 | ConstructorDirectInit | ctorinits.cpp:85:26:85:26 | call to VD | 0 | 0 |
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected
index ff41f299f9c..4e145427a36 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected
@@ -10,11 +10,13 @@ uniqueEnclosingCallable
| test.cpp:1158:18:1158:42 | ... , ... | Node should have one enclosing callable but has 0. |
| test.cpp:1158:23:1158:31 | recursion | Node should have one enclosing callable but has 0. |
| test.cpp:1158:35:1158:40 | call to source | Node should have one enclosing callable but has 0. |
+| test.cpp:1318:13:1318:18 | call to source | Node should have one enclosing callable but has 0. |
uniqueCallEnclosingCallable
| test.cpp:864:47:864:54 | call to source | Call should have one enclosing callable but has 0. |
| test.cpp:872:46:872:51 | call to source | Call should have one enclosing callable but has 0. |
| test.cpp:1158:18:1158:21 | call to sink | Call should have one enclosing callable but has 0. |
| test.cpp:1158:35:1158:40 | call to source | Call should have one enclosing callable but has 0. |
+| test.cpp:1318:13:1318:18 | call to source | Call should have one enclosing callable but has 0. |
uniqueType
uniqueNodeLocation
missingLocation
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test-source-sink.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test-source-sink.expected
index 03a106208a5..5ee2ca86cbc 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test-source-sink.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test-source-sink.expected
@@ -170,6 +170,7 @@ astFlow
| test.cpp:1308:7:1308:12 | call to source | test.cpp:1309:14:1309:16 | ... ++ |
| test.cpp:1312:7:1312:12 | call to source | test.cpp:1313:8:1313:24 | ... ? ... : ... |
| test.cpp:1312:7:1312:12 | call to source | test.cpp:1314:8:1314:8 | x |
+| test.cpp:1329:11:1329:16 | call to source | test.cpp:1330:10:1330:10 | i |
| true_upon_entry.cpp:17:11:17:16 | call to source | true_upon_entry.cpp:21:8:21:8 | x |
| true_upon_entry.cpp:27:9:27:14 | call to source | true_upon_entry.cpp:29:8:29:8 | x |
| true_upon_entry.cpp:33:11:33:16 | call to source | true_upon_entry.cpp:39:8:39:8 | x |
@@ -390,6 +391,8 @@ irFlow
| test.cpp:1308:7:1308:12 | call to source | test.cpp:1309:8:1309:16 | ... ++ |
| test.cpp:1312:7:1312:12 | call to source | test.cpp:1313:8:1313:24 | ... ? ... : ... |
| test.cpp:1312:7:1312:12 | call to source | test.cpp:1314:8:1314:8 | x |
+| test.cpp:1318:13:1318:18 | call to source | test.cpp:1327:10:1327:10 | i |
+| test.cpp:1329:11:1329:16 | call to source | test.cpp:1330:10:1330:10 | i |
| true_upon_entry.cpp:9:11:9:16 | call to source | true_upon_entry.cpp:13:8:13:8 | x |
| true_upon_entry.cpp:17:11:17:16 | call to source | true_upon_entry.cpp:21:8:21:8 | x |
| true_upon_entry.cpp:27:9:27:14 | call to source | true_upon_entry.cpp:29:8:29:8 | x |
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp
index e1c3ef98fb7..892d49b0085 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp
@@ -1312,4 +1312,20 @@ void crement_test2(bool b, int y) {
x = source();
sink(b ? (long)x++ : 0); // $ ir ast
sink(x); // $ ir ast
-}
\ No newline at end of file
+}
+
+struct nsdmi {
+ int i = source();
+
+ nsdmi() {}
+
+ nsdmi(int i) : i(i) {}
+};
+
+void nsdmi_test() {
+ nsdmi x;
+ sink(x.i); // $ ir MISSING: ast
+
+ nsdmi y(source());
+ sink(y.i); // $ ir ast
+}
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/type-bugs.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/type-bugs.expected
index 87ebdc9e83a..2ba0cf2928b 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/type-bugs.expected
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/type-bugs.expected
@@ -1,41 +1,5 @@
astTypeBugs
irTypeBugs
-| ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | [summary param] *0 in iterator |
-| ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | [summary param] this in iterator |
-| ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | [summary] read: Argument[*0].Element in iterator |
-| ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | [summary] read: Argument[*0].Element[****] in iterator |
-| ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | [summary] read: Argument[*0].Element[***] in iterator |
-| ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | [summary] read: Argument[*0].Element[**] in iterator |
-| ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | [summary] read: Argument[*0].Element[*] in iterator |
-| ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | [summary] to write: Argument[this] in iterator |
-| ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | [summary] to write: Argument[this].Element in iterator |
-| ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | [summary] to write: Argument[this].Element[****] in iterator |
-| ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | [summary] to write: Argument[this].Element[***] in iterator |
-| ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | [summary] to write: Argument[this].Element[**] in iterator |
-| ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | ../../../include/iterator.h:21:3:21:10 | [summary] to write: Argument[this].Element[*] in iterator |
-| ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | [summary param] *0 in iterator |
-| ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | [summary param] this in iterator |
-| ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | [summary] read: Argument[*0].Element in iterator |
-| ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | [summary] read: Argument[*0].Element[****] in iterator |
-| ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | [summary] read: Argument[*0].Element[***] in iterator |
-| ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | [summary] read: Argument[*0].Element[**] in iterator |
-| ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | [summary] read: Argument[*0].Element[*] in iterator |
-| ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | [summary] to write: Argument[this] in iterator |
-| ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | [summary] to write: Argument[this].Element in iterator |
-| ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | [summary] to write: Argument[this].Element[****] in iterator |
-| ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | [summary] to write: Argument[this].Element[***] in iterator |
-| ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | [summary] to write: Argument[this].Element[**] in iterator |
-| ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | ../../../include/iterator.h:22:3:22:10 | [summary] to write: Argument[this].Element[*] in iterator |
-| ../../../include/iterator.h:30:18:30:26 | ../../../include/iterator.h:30:18:30:26 | ../../../include/iterator.h:30:18:30:26 | [summary param] this in operator* |
-| ../../../include/iterator.h:30:18:30:26 | ../../../include/iterator.h:30:18:30:26 | ../../../include/iterator.h:30:18:30:26 | [summary] read: Argument[this].Element in operator* |
-| ../../../include/iterator.h:30:18:30:26 | ../../../include/iterator.h:30:18:30:26 | ../../../include/iterator.h:30:18:30:26 | [summary] read: Argument[this].Element[*] in operator* |
-| ../../../include/iterator.h:30:18:30:26 | ../../../include/iterator.h:30:18:30:26 | ../../../include/iterator.h:30:18:30:26 | [summary] to write: ReturnValue[**] in operator* |
-| ../../../include/iterator.h:30:18:30:26 | ../../../include/iterator.h:30:18:30:26 | ../../../include/iterator.h:30:18:30:26 | [summary] to write: ReturnValue[*] in operator* |
-| ../../../include/iterator.h:31:16:31:25 | ../../../include/iterator.h:31:16:31:25 | ../../../include/iterator.h:31:16:31:25 | [summary param] this in operator-> |
-| ../../../include/iterator.h:31:16:31:25 | ../../../include/iterator.h:31:16:31:25 | ../../../include/iterator.h:31:16:31:25 | [summary] read: Argument[this].Element in operator-> |
-| ../../../include/iterator.h:31:16:31:25 | ../../../include/iterator.h:31:16:31:25 | ../../../include/iterator.h:31:16:31:25 | [summary] read: Argument[this].Element[*] in operator-> |
-| ../../../include/iterator.h:31:16:31:25 | ../../../include/iterator.h:31:16:31:25 | ../../../include/iterator.h:31:16:31:25 | [summary] to write: ReturnValue[**] in operator-> |
-| ../../../include/iterator.h:31:16:31:25 | ../../../include/iterator.h:31:16:31:25 | ../../../include/iterator.h:31:16:31:25 | [summary] to write: ReturnValue[*] in operator-> |
incorrectBaseType
| clang.cpp:22:8:22:20 | *& ... | Expected 'Node.getType()' to be int, but it was int * |
| clang.cpp:23:17:23:29 | *& ... | Expected 'Node.getType()' to be int, but it was int * |
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/type-bugs.ql b/cpp/ql/test/library-tests/dataflow/dataflow-tests/type-bugs.ql
index 3e5f9165ef8..3fcf39ef1c5 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/type-bugs.ql
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/type-bugs.ql
@@ -17,9 +17,13 @@ import AstTest
module IrTest {
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
+ private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
query predicate irTypeBugs(Location location, Node node) {
exists(int n |
+ // Flow summary nodes don't have a type since we don't necessarily have
+ // the source code in the database.
+ not node instanceof FlowSummaryNode and
n = count(node.getType()) and
location = node.getLocation() and
n != 1
diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected
index 1e46060c97e..4142b09473a 100644
--- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected
+++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected
@@ -4,121 +4,124 @@ models
| 3 | Source: ; ; false; GetCommandLineA; ; ; ReturnValue[*]; local; manual |
| 4 | Source: ; ; false; GetEnvironmentStringsA; ; ; ReturnValue[*]; local; manual |
| 5 | Source: ; ; false; GetEnvironmentVariableA; ; ; Argument[*1]; local; manual |
-| 6 | Source: ; ; false; MapViewOfFile2; ; ; ReturnValue[*]; local; manual |
-| 7 | Source: ; ; false; MapViewOfFile3; ; ; ReturnValue[*]; local; manual |
-| 8 | Source: ; ; false; MapViewOfFile3FromApp; ; ; ReturnValue[*]; local; manual |
-| 9 | Source: ; ; false; MapViewOfFile; ; ; ReturnValue[*]; local; manual |
-| 10 | Source: ; ; false; MapViewOfFileEx; ; ; ReturnValue[*]; local; manual |
-| 11 | Source: ; ; false; MapViewOfFileFromApp; ; ; ReturnValue[*]; local; manual |
-| 12 | Source: ; ; false; MapViewOfFileNuma2; ; ; ReturnValue[*]; local; manual |
-| 13 | Source: ; ; false; NtReadFile; ; ; Argument[*5]; local; manual |
-| 14 | Source: ; ; false; ReadFile; ; ; Argument[*1]; local; manual |
-| 15 | Source: ; ; false; ReadFileEx; ; ; Argument[*1]; local; manual |
-| 16 | Source: ; ; false; WinHttpQueryHeaders; ; ; Argument[*3]; remote; manual |
-| 17 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[**8]; remote; manual |
-| 18 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*5]; remote; manual |
-| 19 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*6]; remote; manual |
-| 20 | Source: ; ; false; WinHttpReadData; ; ; Argument[*1]; remote; manual |
-| 21 | Source: ; ; false; WinHttpReadDataEx; ; ; Argument[*1]; remote; manual |
-| 22 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual |
-| 23 | Source: Azure::Core::Http; RawResponse; true; ExtractBodyStream; ; ; ReturnValue[*]; remote; manual |
-| 24 | Source: Azure::Core::Http; RawResponse; true; GetBody; ; ; ReturnValue[*]; remote; manual |
-| 25 | Source: Azure::Core::Http; RawResponse; true; GetHeaders; ; ; ReturnValue[*]; remote; manual |
-| 26 | Source: Azure::Core::Http; Request; true; GetBodyStream; ; ; ReturnValue[*]; remote; manual |
-| 27 | Source: Azure::Core::Http; Request; true; GetHeader; ; ; ReturnValue; remote; manual |
-| 28 | Source: Azure::Core::Http; Request; true; GetHeaders; ; ; ReturnValue; remote; manual |
-| 29 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual |
-| 30 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual |
-| 31 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual |
-| 32 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual |
-| 33 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual |
-| 34 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual |
-| 35 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
-| 36 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
-| 37 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual |
-| 38 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual |
-| 39 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
-| 40 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual |
-| 41 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
-| 42 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
-| 43 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual |
-| 44 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual |
-| 45 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual |
-| 46 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual |
-| 47 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated |
-| 48 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual |
-| 49 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual |
-| 50 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual |
-| 51 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual |
-| 52 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual |
-| 53 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual |
-| 54 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual |
+| 6 | Source: ; ; false; HttpReceiveClientCertificate; ; ; Argument[*3]; remote; manual |
+| 7 | Source: ; ; false; HttpReceiveHttpRequest; ; ; Argument[*3]; remote; manual |
+| 8 | Source: ; ; false; HttpReceiveRequestEntityBody; ; ; Argument[*3]; remote; manual |
+| 9 | Source: ; ; false; MapViewOfFile2; ; ; ReturnValue[*]; local; manual |
+| 10 | Source: ; ; false; MapViewOfFile3; ; ; ReturnValue[*]; local; manual |
+| 11 | Source: ; ; false; MapViewOfFile3FromApp; ; ; ReturnValue[*]; local; manual |
+| 12 | Source: ; ; false; MapViewOfFile; ; ; ReturnValue[*]; local; manual |
+| 13 | Source: ; ; false; MapViewOfFileEx; ; ; ReturnValue[*]; local; manual |
+| 14 | Source: ; ; false; MapViewOfFileFromApp; ; ; ReturnValue[*]; local; manual |
+| 15 | Source: ; ; false; MapViewOfFileNuma2; ; ; ReturnValue[*]; local; manual |
+| 16 | Source: ; ; false; NtReadFile; ; ; Argument[*5]; local; manual |
+| 17 | Source: ; ; false; ReadFile; ; ; Argument[*1]; local; manual |
+| 18 | Source: ; ; false; ReadFileEx; ; ; Argument[*1]; local; manual |
+| 19 | Source: ; ; false; WinHttpQueryHeaders; ; ; Argument[*3]; remote; manual |
+| 20 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[**8]; remote; manual |
+| 21 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*5]; remote; manual |
+| 22 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*6]; remote; manual |
+| 23 | Source: ; ; false; WinHttpReadData; ; ; Argument[*1]; remote; manual |
+| 24 | Source: ; ; false; WinHttpReadDataEx; ; ; Argument[*1]; remote; manual |
+| 25 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual |
+| 26 | Source: Azure::Core::Http; RawResponse; true; ExtractBodyStream; ; ; ReturnValue[*]; remote; manual |
+| 27 | Source: Azure::Core::Http; RawResponse; true; GetBody; ; ; ReturnValue[*]; remote; manual |
+| 28 | Source: Azure::Core::Http; RawResponse; true; GetHeaders; ; ; ReturnValue[*]; remote; manual |
+| 29 | Source: Azure::Core::Http; Request; true; GetBodyStream; ; ; ReturnValue[*]; remote; manual |
+| 30 | Source: Azure::Core::Http; Request; true; GetHeader; ; ; ReturnValue; remote; manual |
+| 31 | Source: Azure::Core::Http; Request; true; GetHeaders; ; ; ReturnValue; remote; manual |
+| 32 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual |
+| 33 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual |
+| 34 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual |
+| 35 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual |
+| 36 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual |
+| 37 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual |
+| 38 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
+| 39 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
+| 40 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual |
+| 41 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual |
+| 42 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
+| 43 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual |
+| 44 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
+| 45 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
+| 46 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual |
+| 47 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual |
+| 48 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual |
+| 49 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual |
+| 50 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated |
+| 51 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual |
+| 52 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual |
+| 53 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual |
+| 54 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual |
+| 55 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual |
+| 56 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual |
+| 57 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual |
edges
-| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:54 |
-| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:29 |
-| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:29 Sink:MaD:2 |
+| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:57 |
+| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:32 |
+| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:32 Sink:MaD:2 |
| asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction |
| asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:100:64:100:71 | *send_str | provenance | TaintFunction |
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | |
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | |
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:2 |
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | provenance | |
-| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:54 |
-| azure.cpp:62:10:62:14 | [summary param] this in Value | azure.cpp:62:10:62:14 | [summary] to write: ReturnValue[*] in Value | provenance | MaD:53 |
-| azure.cpp:113:16:113:19 | [summary param] this in Read | azure.cpp:113:16:113:19 | [summary param] *0 in Read [Return] | provenance | MaD:50 |
-| azure.cpp:114:16:114:26 | [summary param] this in ReadToCount | azure.cpp:114:16:114:26 | [summary param] *0 in ReadToCount [Return] | provenance | MaD:51 |
-| azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | azure.cpp:115:30:115:38 | [summary] to write: ReturnValue.Element in ReadToEnd | provenance | MaD:52 |
+| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:57 |
+| azure.cpp:62:10:62:14 | [summary param] this in Value | azure.cpp:62:10:62:14 | [summary] to write: ReturnValue[*] in Value | provenance | MaD:56 |
+| azure.cpp:113:16:113:19 | [summary param] this in Read | azure.cpp:113:16:113:19 | [summary param] *0 in Read [Return] | provenance | MaD:53 |
+| azure.cpp:114:16:114:26 | [summary param] this in ReadToCount | azure.cpp:114:16:114:26 | [summary param] *0 in ReadToCount [Return] | provenance | MaD:54 |
+| azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | azure.cpp:115:30:115:38 | [summary] to write: ReturnValue.Element in ReadToEnd | provenance | MaD:55 |
| azure.cpp:115:30:115:38 | [summary] to write: ReturnValue.Element in ReadToEnd | azure.cpp:115:30:115:38 | [summary] to write: ReturnValue in ReadToEnd [element] | provenance | |
-| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:26 |
+| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:29 |
| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:257:5:257:8 | *resp | provenance | |
| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:262:5:262:8 | *resp | provenance | |
| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:266:38:266:41 | *resp | provenance | |
| azure.cpp:257:5:257:8 | *resp | azure.cpp:113:16:113:19 | [summary param] this in Read | provenance | |
-| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:50 |
+| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:53 |
| azure.cpp:257:16:257:21 | Read output argument | azure.cpp:258:10:258:16 | * ... | provenance | |
| azure.cpp:262:5:262:8 | *resp | azure.cpp:114:16:114:26 | [summary param] this in ReadToCount | provenance | |
-| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:51 |
+| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:54 |
| azure.cpp:262:23:262:28 | ReadToCount output argument | azure.cpp:263:10:263:16 | * ... | provenance | |
| azure.cpp:266:38:266:41 | *resp | azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | provenance | |
-| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:52 |
+| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:55 |
| azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | |
| azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:267:10:267:12 | vec [element] | provenance | |
| azure.cpp:267:10:267:12 | vec [element] | azure.cpp:267:10:267:12 | vec | provenance | |
-| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:273:62:273:64 | call to GetHeaders | provenance | Src:MaD:25 |
+| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:273:62:273:64 | call to GetHeaders | provenance | Src:MaD:28 |
| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction |
| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction |
| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction |
| azure.cpp:274:14:274:29 | call to operator[] | azure.cpp:274:10:274:29 | call to operator[] | provenance | |
| azure.cpp:274:14:274:29 | call to operator[] | azure.cpp:274:14:274:29 | call to operator[] | provenance | |
-| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:277:45:277:47 | call to GetBody | provenance | Src:MaD:24 |
+| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:277:45:277:47 | call to GetBody | provenance | Src:MaD:27 |
| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:278:10:278:13 | body | provenance | |
| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:278:10:278:13 | body | provenance | |
| azure.cpp:278:10:278:13 | body | azure.cpp:278:10:278:13 | body | provenance | |
-| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:23 |
+| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:26 |
| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:282:21:282:23 | *call to get | provenance | |
| azure.cpp:282:21:282:23 | *call to get | azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | provenance | |
-| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:52 |
+| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:55 |
| azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:10:282:38 | call to ReadToEnd | provenance | |
| azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | |
| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:62:10:62:14 | [summary param] this in Value | provenance | |
-| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:53 |
+| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:56 |
| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:24:289:56 | call to GetHeader | provenance | |
-| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:27 |
+| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:30 |
| azure.cpp:289:63:289:65 | call to Value | azure.cpp:289:63:289:65 | call to Value | provenance | |
| azure.cpp:289:63:289:65 | call to Value | azure.cpp:290:10:290:20 | headerValue | provenance | |
| azure.cpp:289:63:289:65 | call to Value | azure.cpp:290:10:290:20 | headerValue | provenance | |
| azure.cpp:290:10:290:20 | headerValue | azure.cpp:290:10:290:20 | headerValue | provenance | |
-| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:293:58:293:67 | call to GetHeaders | provenance | Src:MaD:28 |
+| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:293:58:293:67 | call to GetHeaders | provenance | Src:MaD:31 |
| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:294:38:294:53 | call to operator[] | provenance | TaintFunction |
| azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | |
| azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | |
| azure.cpp:295:10:295:20 | contentType | azure.cpp:295:10:295:20 | contentType | provenance | |
-| test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | provenance | MaD:48 |
-| test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | provenance | MaD:47 |
-| test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | provenance | MaD:49 |
+| test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | provenance | MaD:51 |
+| test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | provenance | MaD:50 |
+| test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | provenance | MaD:52 |
| test.cpp:7:47:7:52 | value2 | test.cpp:7:64:7:69 | value2 | provenance | |
| test.cpp:7:64:7:69 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | provenance | |
-| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:22 |
+| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:25 |
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:14:10:14:10 | x | provenance | Sink:MaD:1 |
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:17:24:17:24 | x | provenance | |
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:21:27:21:27 | x | provenance | |
@@ -127,15 +130,15 @@ edges
| test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | |
| test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:1 |
| test.cpp:17:24:17:24 | x | test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | provenance | |
-| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:48 |
+| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:51 |
| test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | |
| test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:1 |
| test.cpp:21:27:21:27 | x | test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | provenance | |
-| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:47 |
+| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:50 |
| test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | |
| test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:1 |
| test.cpp:25:35:25:35 | x | test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | provenance | |
-| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:49 |
+| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:52 |
| test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | |
| test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:1 |
| test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | provenance | |
@@ -143,16 +146,16 @@ edges
| test.cpp:46:30:46:32 | *arg [x] | test.cpp:47:12:47:19 | *arg [x] | provenance | |
| test.cpp:47:12:47:19 | *arg [x] | test.cpp:48:13:48:13 | *s [x] | provenance | |
| test.cpp:48:13:48:13 | *s [x] | test.cpp:48:16:48:16 | x | provenance | Sink:MaD:1 |
-| test.cpp:52:5:52:18 | [summary param] *3 in pthread_create [x] | test.cpp:52:5:52:18 | [summary] to write: Argument[2].Parameter[*0] in pthread_create [x] | provenance | MaD:46 |
+| test.cpp:52:5:52:18 | [summary param] *3 in pthread_create [x] | test.cpp:52:5:52:18 | [summary] to write: Argument[2].Parameter[*0] in pthread_create [x] | provenance | MaD:49 |
| test.cpp:52:5:52:18 | [summary] to write: Argument[2].Parameter[*0] in pthread_create [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | |
| test.cpp:56:2:56:2 | *s [post update] [x] | test.cpp:59:55:59:64 | *& ... [x] | provenance | |
| test.cpp:56:2:56:18 | ... = ... | test.cpp:56:2:56:2 | *s [post update] [x] | provenance | |
-| test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:22 |
+| test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:25 |
| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:52:5:52:18 | [summary param] *3 in pthread_create [x] | provenance | |
-| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:44 |
-| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:44 |
-| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:44 |
-| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:44 |
+| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:47 |
+| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:47 |
+| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:47 |
+| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:47 |
| test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | test.cpp:68:22:68:22 | y | provenance | |
| test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | test.cpp:74:22:74:22 | y | provenance | |
| test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | test.cpp:82:22:82:22 | y | provenance | |
@@ -161,7 +164,7 @@ edges
| test.cpp:74:22:74:22 | y | test.cpp:75:11:75:11 | y | provenance | Sink:MaD:1 |
| test.cpp:82:22:82:22 | y | test.cpp:83:11:83:11 | y | provenance | Sink:MaD:1 |
| test.cpp:88:22:88:22 | y | test.cpp:89:11:89:11 | y | provenance | Sink:MaD:1 |
-| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:22 |
+| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:25 |
| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:97:26:97:26 | x | provenance | |
| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:101:26:101:26 | x | provenance | |
| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:103:63:103:63 | x | provenance | |
@@ -170,28 +173,28 @@ edges
| test.cpp:101:26:101:26 | x | test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | provenance | |
| test.cpp:103:63:103:63 | x | test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | provenance | |
| test.cpp:104:62:104:62 | x | test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | provenance | |
-| test.cpp:111:3:111:25 | [summary param] *0 in callWithNonTypeTemplate | test.cpp:111:3:111:25 | [summary] to write: ReturnValue in callWithNonTypeTemplate | provenance | MaD:45 |
-| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:22 |
+| test.cpp:111:3:111:25 | [summary param] *0 in callWithNonTypeTemplate | test.cpp:111:3:111:25 | [summary] to write: ReturnValue in callWithNonTypeTemplate | provenance | MaD:48 |
+| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:25 |
| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:118:44:118:44 | *x | provenance | |
| test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | |
| test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:119:10:119:11 | y2 | provenance | Sink:MaD:1 |
| test.cpp:118:44:118:44 | *x | test.cpp:111:3:111:25 | [summary param] *0 in callWithNonTypeTemplate | provenance | |
-| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:45 |
-| windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | windows.cpp:17:8:17:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | provenance | MaD:30 |
+| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:48 |
+| windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | windows.cpp:17:8:17:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | provenance | MaD:33 |
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:3 |
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:24:8:24:11 | * ... | provenance | |
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:27:36:27:38 | *cmd | provenance | |
| windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | |
| windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:30:8:30:15 | * ... | provenance | |
| windows.cpp:27:36:27:38 | *cmd | windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | provenance | |
-| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:30 |
+| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:33 |
| windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | provenance | Src:MaD:4 |
| windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:36:10:36:13 | * ... | provenance | |
| windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | windows.cpp:41:10:41:13 | * ... | provenance | Src:MaD:5 |
| windows.cpp:90:6:90:15 | [summary param] *3 in ReadFileEx [*hEvent] | windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[*hEvent] in ReadFileEx | provenance | |
| windows.cpp:90:6:90:15 | [summary param] *3 in ReadFileEx [hEvent] | windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[hEvent] in ReadFileEx | provenance | |
-| windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[*hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[*hEvent] in ReadFileEx | provenance | MaD:34 |
-| windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[hEvent] in ReadFileEx | provenance | MaD:34 |
+| windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[*hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[*hEvent] in ReadFileEx | provenance | MaD:37 |
+| windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[hEvent] in ReadFileEx | provenance | MaD:37 |
| windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2] in ReadFileEx [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | |
| windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2] in ReadFileEx [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | |
| windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[*hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2] in ReadFileEx [*hEvent] | provenance | |
@@ -207,43 +210,43 @@ edges
| windows.cpp:159:12:159:55 | hEvent | windows.cpp:160:8:160:8 | c | provenance | |
| windows.cpp:159:35:159:46 | *lpOverlapped [hEvent] | windows.cpp:159:12:159:55 | hEvent | provenance | |
| windows.cpp:159:35:159:46 | *lpOverlapped [hEvent] | windows.cpp:159:12:159:55 | hEvent | provenance | |
-| windows.cpp:168:35:168:40 | ReadFile output argument | windows.cpp:170:10:170:16 | * ... | provenance | Src:MaD:14 |
-| windows.cpp:177:23:177:28 | ReadFileEx output argument | windows.cpp:179:10:179:16 | * ... | provenance | Src:MaD:15 |
-| windows.cpp:189:21:189:26 | ReadFile output argument | windows.cpp:190:5:190:56 | *... = ... | provenance | Src:MaD:14 |
+| windows.cpp:168:35:168:40 | ReadFile output argument | windows.cpp:170:10:170:16 | * ... | provenance | Src:MaD:17 |
+| windows.cpp:177:23:177:28 | ReadFileEx output argument | windows.cpp:179:10:179:16 | * ... | provenance | Src:MaD:18 |
+| windows.cpp:189:21:189:26 | ReadFile output argument | windows.cpp:190:5:190:56 | *... = ... | provenance | Src:MaD:17 |
| windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | windows.cpp:192:53:192:63 | *& ... [*hEvent] | provenance | |
| windows.cpp:190:5:190:56 | *... = ... | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | provenance | |
| windows.cpp:192:53:192:63 | *& ... [*hEvent] | windows.cpp:90:6:90:15 | [summary param] *3 in ReadFileEx [*hEvent] | provenance | |
-| windows.cpp:198:21:198:26 | ReadFile output argument | windows.cpp:199:5:199:57 | ... = ... | provenance | Src:MaD:14 |
+| windows.cpp:198:21:198:26 | ReadFile output argument | windows.cpp:199:5:199:57 | ... = ... | provenance | Src:MaD:17 |
| windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | windows.cpp:201:53:201:63 | *& ... [hEvent] | provenance | |
| windows.cpp:199:5:199:57 | ... = ... | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | provenance | |
| windows.cpp:201:53:201:63 | *& ... [hEvent] | windows.cpp:90:6:90:15 | [summary param] *3 in ReadFileEx [hEvent] | provenance | |
-| windows.cpp:209:84:209:89 | NtReadFile output argument | windows.cpp:211:10:211:16 | * ... | provenance | Src:MaD:13 |
-| windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:286:23:286:35 | *call to MapViewOfFile | provenance | Src:MaD:9 |
+| windows.cpp:209:84:209:89 | NtReadFile output argument | windows.cpp:211:10:211:16 | * ... | provenance | Src:MaD:16 |
+| windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:286:23:286:35 | *call to MapViewOfFile | provenance | Src:MaD:12 |
| windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:287:20:287:52 | *pMapView | provenance | |
| windows.cpp:287:20:287:52 | *pMapView | windows.cpp:289:10:289:16 | * ... | provenance | |
-| windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | provenance | Src:MaD:6 |
+| windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | provenance | Src:MaD:9 |
| windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | windows.cpp:294:20:294:52 | *pMapView | provenance | |
| windows.cpp:294:20:294:52 | *pMapView | windows.cpp:296:10:296:16 | * ... | provenance | |
-| windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | provenance | Src:MaD:7 |
+| windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | provenance | Src:MaD:10 |
| windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | windows.cpp:303:20:303:52 | *pMapView | provenance | |
| windows.cpp:303:20:303:52 | *pMapView | windows.cpp:305:10:305:16 | * ... | provenance | |
-| windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | provenance | Src:MaD:8 |
+| windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | provenance | Src:MaD:11 |
| windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | windows.cpp:312:20:312:52 | *pMapView | provenance | |
| windows.cpp:312:20:312:52 | *pMapView | windows.cpp:314:10:314:16 | * ... | provenance | |
-| windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | provenance | Src:MaD:10 |
+| windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | provenance | Src:MaD:13 |
| windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | windows.cpp:319:20:319:52 | *pMapView | provenance | |
| windows.cpp:319:20:319:52 | *pMapView | windows.cpp:321:10:321:16 | * ... | provenance | |
-| windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | provenance | Src:MaD:11 |
+| windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | provenance | Src:MaD:14 |
| windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | windows.cpp:326:20:326:52 | *pMapView | provenance | |
| windows.cpp:326:20:326:52 | *pMapView | windows.cpp:328:10:328:16 | * ... | provenance | |
-| windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | provenance | Src:MaD:12 |
+| windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | provenance | Src:MaD:15 |
| windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | windows.cpp:333:20:333:52 | *pMapView | provenance | |
| windows.cpp:333:20:333:52 | *pMapView | windows.cpp:335:10:335:16 | * ... | provenance | |
-| windows.cpp:349:8:349:19 | [summary param] *3 in CreateThread [x] | windows.cpp:349:8:349:19 | [summary] to write: Argument[2].Parameter[*0] in CreateThread [x] | provenance | MaD:33 |
+| windows.cpp:349:8:349:19 | [summary param] *3 in CreateThread [x] | windows.cpp:349:8:349:19 | [summary] to write: Argument[2].Parameter[*0] in CreateThread [x] | provenance | MaD:36 |
| windows.cpp:349:8:349:19 | [summary] to write: Argument[2].Parameter[*0] in CreateThread [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | |
-| windows.cpp:357:8:357:25 | [summary param] *4 in CreateRemoteThread [x] | windows.cpp:357:8:357:25 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThread [x] | provenance | MaD:31 |
+| windows.cpp:357:8:357:25 | [summary param] *4 in CreateRemoteThread [x] | windows.cpp:357:8:357:25 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThread [x] | provenance | MaD:34 |
| windows.cpp:357:8:357:25 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThread [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | |
-| windows.cpp:387:8:387:27 | [summary param] *4 in CreateRemoteThreadEx [x] | windows.cpp:387:8:387:27 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThreadEx [x] | provenance | MaD:32 |
+| windows.cpp:387:8:387:27 | [summary param] *4 in CreateRemoteThreadEx [x] | windows.cpp:387:8:387:27 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThreadEx [x] | provenance | MaD:35 |
| windows.cpp:387:8:387:27 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThreadEx [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | |
| windows.cpp:403:26:403:36 | *lpParameter [x] | windows.cpp:405:10:405:25 | *lpParameter [x] | provenance | |
| windows.cpp:405:10:405:25 | *lpParameter [x] | windows.cpp:406:8:406:8 | *s [x] | provenance | |
@@ -262,17 +265,17 @@ edges
| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:349:8:349:19 | [summary param] *3 in CreateThread [x] | provenance | |
| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:357:8:357:25 | [summary param] *4 in CreateRemoteThread [x] | provenance | |
| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:387:8:387:27 | [summary param] *4 in CreateRemoteThreadEx [x] | provenance | |
-| windows.cpp:473:17:473:37 | [summary param] *1 in RtlCopyVolatileMemory | windows.cpp:473:17:473:37 | [summary param] *0 in RtlCopyVolatileMemory [Return] | provenance | MaD:39 |
-| windows.cpp:479:17:479:35 | [summary param] *1 in RtlCopyDeviceMemory | windows.cpp:479:17:479:35 | [summary param] *0 in RtlCopyDeviceMemory [Return] | provenance | MaD:35 |
-| windows.cpp:485:6:485:18 | [summary param] *1 in RtlCopyMemory | windows.cpp:485:6:485:18 | [summary param] *0 in RtlCopyMemory [Return] | provenance | MaD:36 |
-| windows.cpp:493:6:493:29 | [summary param] *1 in RtlCopyMemoryNonTemporal | windows.cpp:493:6:493:29 | [summary param] *0 in RtlCopyMemoryNonTemporal [Return] | provenance | MaD:37 |
+| windows.cpp:473:17:473:37 | [summary param] *1 in RtlCopyVolatileMemory | windows.cpp:473:17:473:37 | [summary param] *0 in RtlCopyVolatileMemory [Return] | provenance | MaD:42 |
+| windows.cpp:479:17:479:35 | [summary param] *1 in RtlCopyDeviceMemory | windows.cpp:479:17:479:35 | [summary param] *0 in RtlCopyDeviceMemory [Return] | provenance | MaD:38 |
+| windows.cpp:485:6:485:18 | [summary param] *1 in RtlCopyMemory | windows.cpp:485:6:485:18 | [summary param] *0 in RtlCopyMemory [Return] | provenance | MaD:39 |
+| windows.cpp:493:6:493:29 | [summary param] *1 in RtlCopyMemoryNonTemporal | windows.cpp:493:6:493:29 | [summary param] *0 in RtlCopyMemoryNonTemporal [Return] | provenance | MaD:40 |
| windows.cpp:510:6:510:25 | [summary param] *1 in RtlCopyUnicodeString [*Buffer] | windows.cpp:510:6:510:25 | [summary] read: Argument[*1].Field[*Buffer] in RtlCopyUnicodeString | provenance | |
-| windows.cpp:510:6:510:25 | [summary] read: Argument[*1].Field[*Buffer] in RtlCopyUnicodeString | windows.cpp:510:6:510:25 | [summary] to write: Argument[*0].Field[*Buffer] in RtlCopyUnicodeString | provenance | MaD:38 |
+| windows.cpp:510:6:510:25 | [summary] read: Argument[*1].Field[*Buffer] in RtlCopyUnicodeString | windows.cpp:510:6:510:25 | [summary] to write: Argument[*0].Field[*Buffer] in RtlCopyUnicodeString | provenance | MaD:41 |
| windows.cpp:510:6:510:25 | [summary] to write: Argument[*0] in RtlCopyUnicodeString [*Buffer] | windows.cpp:510:6:510:25 | [summary param] *0 in RtlCopyUnicodeString [Return] [*Buffer] | provenance | |
| windows.cpp:510:6:510:25 | [summary] to write: Argument[*0].Field[*Buffer] in RtlCopyUnicodeString | windows.cpp:510:6:510:25 | [summary] to write: Argument[*0] in RtlCopyUnicodeString [*Buffer] | provenance | |
-| windows.cpp:515:6:515:18 | [summary param] *1 in RtlMoveMemory | windows.cpp:515:6:515:18 | [summary param] *0 in RtlMoveMemory [Return] | provenance | MaD:41 |
-| windows.cpp:521:17:521:37 | [summary param] *1 in RtlMoveVolatileMemory | windows.cpp:521:17:521:37 | [summary param] *0 in RtlMoveVolatileMemory [Return] | provenance | MaD:42 |
-| windows.cpp:527:6:527:25 | [summary param] *1 in RtlInitUnicodeString | windows.cpp:527:6:527:25 | [summary] to write: Argument[*0].Field[*Buffer] in RtlInitUnicodeString | provenance | MaD:40 |
+| windows.cpp:515:6:515:18 | [summary param] *1 in RtlMoveMemory | windows.cpp:515:6:515:18 | [summary param] *0 in RtlMoveMemory [Return] | provenance | MaD:44 |
+| windows.cpp:521:17:521:37 | [summary param] *1 in RtlMoveVolatileMemory | windows.cpp:521:17:521:37 | [summary param] *0 in RtlMoveVolatileMemory [Return] | provenance | MaD:45 |
+| windows.cpp:527:6:527:25 | [summary param] *1 in RtlInitUnicodeString | windows.cpp:527:6:527:25 | [summary] to write: Argument[*0].Field[*Buffer] in RtlInitUnicodeString | provenance | MaD:43 |
| windows.cpp:527:6:527:25 | [summary] to write: Argument[*0] in RtlInitUnicodeString [*Buffer] | windows.cpp:527:6:527:25 | [summary param] *0 in RtlInitUnicodeString [Return] [*Buffer] | provenance | |
| windows.cpp:527:6:527:25 | [summary] to write: Argument[*0].Field[*Buffer] in RtlInitUnicodeString | windows.cpp:527:6:527:25 | [summary] to write: Argument[*0] in RtlInitUnicodeString [*Buffer] | provenance | |
| windows.cpp:533:11:533:16 | call to source | windows.cpp:533:11:533:16 | call to source | provenance | |
@@ -284,51 +287,68 @@ edges
| windows.cpp:533:11:533:16 | call to source | windows.cpp:573:40:573:41 | *& ... | provenance | |
| windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | windows.cpp:538:10:538:23 | access to array | provenance | |
| windows.cpp:537:40:537:41 | *& ... | windows.cpp:473:17:473:37 | [summary param] *1 in RtlCopyVolatileMemory | provenance | |
-| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:39 |
+| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:42 |
| windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | windows.cpp:543:10:543:23 | access to array | provenance | |
| windows.cpp:542:38:542:39 | *& ... | windows.cpp:479:17:479:35 | [summary param] *1 in RtlCopyDeviceMemory | provenance | |
-| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:35 |
+| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:38 |
| windows.cpp:547:19:547:29 | RtlCopyMemory output argument | windows.cpp:548:10:548:23 | access to array | provenance | |
| windows.cpp:547:32:547:33 | *& ... | windows.cpp:485:6:485:18 | [summary param] *1 in RtlCopyMemory | provenance | |
-| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:36 |
+| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:39 |
| windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | windows.cpp:553:10:553:23 | access to array | provenance | |
| windows.cpp:552:43:552:44 | *& ... | windows.cpp:493:6:493:29 | [summary param] *1 in RtlCopyMemoryNonTemporal | provenance | |
-| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:37 |
+| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:40 |
| windows.cpp:559:5:559:24 | ... = ... | windows.cpp:561:39:561:44 | *buffer | provenance | |
| windows.cpp:559:17:559:24 | call to source | windows.cpp:559:5:559:24 | ... = ... | provenance | |
| windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:562:10:562:19 | *src_string [*Buffer] | provenance | |
| windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:563:40:563:50 | *& ... [*Buffer] | provenance | |
| windows.cpp:561:39:561:44 | *buffer | windows.cpp:527:6:527:25 | [summary param] *1 in RtlInitUnicodeString | provenance | |
-| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:40 |
+| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:43 |
| windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:10:562:29 | access to array | provenance | |
| windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:21:562:26 | *Buffer | provenance | |
| windows.cpp:562:21:562:26 | *Buffer | windows.cpp:562:10:562:29 | access to array | provenance | |
| windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | provenance | |
| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:510:6:510:25 | [summary param] *1 in RtlCopyUnicodeString [*Buffer] | provenance | |
-| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:38 |
+| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:41 |
| windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:10:564:30 | access to array | provenance | |
| windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:22:564:27 | *Buffer | provenance | |
| windows.cpp:564:22:564:27 | *Buffer | windows.cpp:564:10:564:30 | access to array | provenance | |
| windows.cpp:568:19:568:29 | RtlMoveMemory output argument | windows.cpp:569:10:569:23 | access to array | provenance | |
| windows.cpp:568:32:568:33 | *& ... | windows.cpp:515:6:515:18 | [summary param] *1 in RtlMoveMemory | provenance | |
-| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:41 |
+| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:44 |
| windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | windows.cpp:574:10:574:23 | access to array | provenance | |
| windows.cpp:573:40:573:41 | *& ... | windows.cpp:521:17:521:37 | [summary param] *1 in RtlMoveVolatileMemory | provenance | |
-| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:42 |
-| windows.cpp:645:45:645:50 | WinHttpReadData output argument | windows.cpp:647:10:647:16 | * ... | provenance | Src:MaD:20 |
-| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | windows.cpp:654:10:654:16 | * ... | provenance | Src:MaD:21 |
-| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | windows.cpp:661:10:661:16 | * ... | provenance | Src:MaD:16 |
-| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | windows.cpp:673:10:673:29 | * ... | provenance | Src:MaD:18 |
-| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | windows.cpp:671:10:671:16 | * ... | provenance | Src:MaD:19 |
-| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:17 |
-| windows.cpp:714:6:714:20 | [summary param] *0 in WinHttpCrackUrl | windows.cpp:714:6:714:20 | [summary param] *3 in WinHttpCrackUrl [Return] | provenance | MaD:43 |
+| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:45 |
+| windows.cpp:645:45:645:50 | WinHttpReadData output argument | windows.cpp:647:10:647:16 | * ... | provenance | Src:MaD:23 |
+| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | windows.cpp:654:10:654:16 | * ... | provenance | Src:MaD:24 |
+| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | windows.cpp:661:10:661:16 | * ... | provenance | Src:MaD:19 |
+| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | windows.cpp:673:10:673:29 | * ... | provenance | Src:MaD:21 |
+| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | windows.cpp:671:10:671:16 | * ... | provenance | Src:MaD:22 |
+| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:20 |
+| windows.cpp:714:6:714:20 | [summary param] *0 in WinHttpCrackUrl | windows.cpp:714:6:714:20 | [summary param] *3 in WinHttpCrackUrl [Return] | provenance | MaD:46 |
| windows.cpp:728:5:728:28 | ... = ... | windows.cpp:729:35:729:35 | *x | provenance | |
| windows.cpp:728:12:728:28 | call to source | windows.cpp:728:5:728:28 | ... = ... | provenance | |
| windows.cpp:729:35:729:35 | *x | windows.cpp:714:6:714:20 | [summary param] *0 in WinHttpCrackUrl | provenance | |
-| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:43 |
+| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:46 |
| windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:731:10:731:36 | * ... | provenance | |
| windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:733:10:733:35 | * ... | provenance | |
| windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:735:10:735:37 | * ... | provenance | |
+| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:901:15:901:53 | *& ... | provenance | Src:MaD:7 |
+| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:905:10:905:31 | * ... | provenance | Src:MaD:7 |
+| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:907:10:907:42 | * ... | provenance | Src:MaD:7 |
+| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:909:10:909:57 | * ... | provenance | Src:MaD:7 |
+| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:911:10:911:60 | * ... | provenance | Src:MaD:7 |
+| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:912:54:912:63 | FileHandle | provenance | Src:MaD:7 |
+| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:914:10:914:70 | * ... | provenance | Src:MaD:7 |
+| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:916:10:916:72 | * ... | provenance | Src:MaD:7 |
+| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:918:10:918:64 | * ... | provenance | Src:MaD:7 |
+| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:920:10:920:51 | * ... | provenance | Src:MaD:7 |
+| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:922:10:922:52 | * ... | provenance | Src:MaD:7 |
+| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:924:10:924:63 | * ... | provenance | Src:MaD:7 |
+| windows.cpp:901:15:901:53 | *& ... | windows.cpp:903:10:903:11 | * ... | provenance | |
+| windows.cpp:929:70:929:75 | HttpReceiveRequestEntityBody output argument | windows.cpp:931:10:931:16 | * ... | provenance | Src:MaD:8 |
+| windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | windows.cpp:937:15:937:48 | *& ... | provenance | Src:MaD:6 |
+| windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | windows.cpp:941:10:941:31 | * ... | provenance | Src:MaD:6 |
+| windows.cpp:937:15:937:48 | *& ... | windows.cpp:939:10:939:11 | * ... | provenance | |
nodes
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | semmle.label | [summary param] *0 in buffer |
| asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | semmle.label | [summary] to write: ReturnValue in buffer |
@@ -636,6 +656,26 @@ nodes
| windows.cpp:731:10:731:36 | * ... | semmle.label | * ... |
| windows.cpp:733:10:733:35 | * ... | semmle.label | * ... |
| windows.cpp:735:10:735:37 | * ... | semmle.label | * ... |
+| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | semmle.label | HttpReceiveHttpRequest output argument |
+| windows.cpp:901:15:901:53 | *& ... | semmle.label | *& ... |
+| windows.cpp:903:10:903:11 | * ... | semmle.label | * ... |
+| windows.cpp:905:10:905:31 | * ... | semmle.label | * ... |
+| windows.cpp:907:10:907:42 | * ... | semmle.label | * ... |
+| windows.cpp:909:10:909:57 | * ... | semmle.label | * ... |
+| windows.cpp:911:10:911:60 | * ... | semmle.label | * ... |
+| windows.cpp:912:54:912:63 | FileHandle | semmle.label | FileHandle |
+| windows.cpp:914:10:914:70 | * ... | semmle.label | * ... |
+| windows.cpp:916:10:916:72 | * ... | semmle.label | * ... |
+| windows.cpp:918:10:918:64 | * ... | semmle.label | * ... |
+| windows.cpp:920:10:920:51 | * ... | semmle.label | * ... |
+| windows.cpp:922:10:922:52 | * ... | semmle.label | * ... |
+| windows.cpp:924:10:924:63 | * ... | semmle.label | * ... |
+| windows.cpp:929:70:929:75 | HttpReceiveRequestEntityBody output argument | semmle.label | HttpReceiveRequestEntityBody output argument |
+| windows.cpp:931:10:931:16 | * ... | semmle.label | * ... |
+| windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | semmle.label | HttpReceiveClientCertificate output argument |
+| windows.cpp:937:15:937:48 | *& ... | semmle.label | *& ... |
+| windows.cpp:939:10:939:11 | * ... | semmle.label | * ... |
+| windows.cpp:941:10:941:31 | * ... | semmle.label | * ... |
subpaths
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | asio_streams.cpp:100:44:100:62 | call to buffer |
| azure.cpp:257:5:257:8 | *resp | azure.cpp:113:16:113:19 | [summary param] this in Read | azure.cpp:113:16:113:19 | [summary param] *0 in Read [Return] | azure.cpp:257:16:257:21 | Read output argument |
diff --git a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected
index c683d8539a0..b46aa87af6f 100644
--- a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected
+++ b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected
@@ -32,3 +32,6 @@
| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | remote |
| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | remote |
| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | remote |
+| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | remote |
+| windows.cpp:929:70:929:75 | HttpReceiveRequestEntityBody output argument | remote |
+| windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | remote |
diff --git a/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.ql b/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.ql
index a162349b7cd..63e6520c56f 100644
--- a/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.ql
+++ b/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.ql
@@ -1,2 +1,2 @@
import cpp
-import semmle.code.cpp.dataflow.ExternalFlow::CsvValidation
+import semmle.code.cpp.dataflow.ExternalFlow::ModelValidation
diff --git a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp
index 2900af9034c..f098f7344e4 100644
--- a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp
+++ b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp
@@ -734,4 +734,210 @@ void test_winhttp_crack_url() {
sink(urlComponents.lpszExtraInfo);
sink(*urlComponents.lpszExtraInfo); // $ ir
}
+}
+
+using HTTP_REQUEST_ID = ULONGLONG;
+using HTTP_CONNECTION_ID = ULONGLONG;
+using HTTP_URL_CONTEXT = ULONGLONG;
+using HTTP_RAW_CONNECTION_ID = ULONGLONG;
+
+typedef struct _HTTP_VERSION {
+ USHORT MajorVersion;
+ USHORT MinorVersion;
+} HTTP_VERSION, *PHTTP_VERSION;
+
+typedef enum _HTTP_VERB {
+ HttpVerbUnparsed = 0
+} HTTP_VERB, *PHTTP_VERB;
+
+typedef struct _HTTP_COOKED_URL {
+ USHORT FullUrlLength;
+ USHORT HostLength;
+ USHORT AbsPathLength;
+ USHORT QueryStringLength;
+ PCWSTR pFullUrl;
+ PCWSTR pHost;
+ PCWSTR pAbsPath;
+ PCWSTR pQueryString;
+} HTTP_COOKED_URL, *PHTTP_COOKED_URL;
+
+typedef struct _HTTP_TRANSPORT_ADDRESS {
+ struct sockaddr* pRemoteAddress;
+ struct sockaddr* pLocalAddress;
+} HTTP_TRANSPORT_ADDRESS, *PHTTP_TRANSPORT_ADDRESS;
+
+typedef struct _HTTP_KNOWN_HEADER {
+ USHORT RawValueLength;
+ PCSTR pRawValue;
+} HTTP_KNOWN_HEADER, *PHTTP_KNOWN_HEADER;
+
+typedef struct _HTTP_UNKNOWN_HEADER {
+ USHORT NameLength;
+ USHORT RawValueLength;
+ PCSTR pName;
+ PCSTR pRawValue;
+} HTTP_UNKNOWN_HEADER, *PHTTP_UNKNOWN_HEADER;
+
+typedef struct _HTTP_REQUEST_HEADERS {
+ USHORT UnknownHeaderCount;
+ PHTTP_UNKNOWN_HEADER pUnknownHeaders;
+ USHORT TrailerCount;
+ PHTTP_UNKNOWN_HEADER pTrailers;
+ HTTP_KNOWN_HEADER KnownHeaders[41];
+} HTTP_REQUEST_HEADERS, *PHTTP_REQUEST_HEADERS;
+
+typedef struct _HTTP_BYTE_RANGE {
+ ULONGLONG StartingOffset;
+ ULONGLONG Length;
+} HTTP_BYTE_RANGE, *PHTTP_BYTE_RANGE;
+
+typedef struct _HTTP_DATA_CHUNK {
+ int DataChunkType;
+ union {
+ struct {
+ PVOID pBuffer;
+ ULONG BufferLength;
+ } FromMemory;
+ struct {
+ HTTP_BYTE_RANGE ByteRange;
+ HANDLE FileHandle;
+ } FromFileHandle;
+ struct {
+ USHORT FragmentNameLength;
+ PCWSTR pFragmentName;
+ } FromFragmentCache;
+ struct {
+ HTTP_BYTE_RANGE ByteRange;
+ PCWSTR pFragmentName;
+ } FromFragmentCacheEx;
+ struct {
+ USHORT TrailerCount;
+ PHTTP_UNKNOWN_HEADER pTrailers;
+ } Trailers;
+ };
+} HTTP_DATA_CHUNK, *PHTTP_DATA_CHUNK;
+
+typedef struct _HTTP_SSL_CLIENT_CERT_INFO {
+ ULONG CertFlags;
+ ULONG CertEncodedSize;
+ char* pCertEncoded;
+ HANDLE Token;
+ BOOL CertDeniedByMapper;
+} HTTP_SSL_CLIENT_CERT_INFO, *PHTTP_SSL_CLIENT_CERT_INFO;
+
+typedef struct _HTTP_SSL_INFO {
+ USHORT ServerCertKeySize;
+ USHORT ConnectionKeySize;
+ ULONG ServerCertIssuerSize;
+ ULONG ServerCertSubjectSize;
+ PCSTR pServerCertIssuer;
+ PCSTR pServerCertSubject;
+ PHTTP_SSL_CLIENT_CERT_INFO pClientCertInfo;
+ ULONG SslClientCertNegotiated;
+} HTTP_SSL_INFO, *PHTTP_SSL_INFO;
+
+typedef struct _HTTP_REQUEST_V1 {
+ ULONG Flags;
+ HTTP_CONNECTION_ID ConnectionId;
+ HTTP_REQUEST_ID RequestId;
+ HTTP_URL_CONTEXT UrlContext;
+ HTTP_VERSION Version;
+ HTTP_VERB Verb;
+ USHORT UnknownVerbLength;
+ USHORT RawUrlLength;
+ PCSTR pUnknownVerb;
+ PCSTR pRawUrl;
+ HTTP_COOKED_URL CookedUrl;
+ HTTP_TRANSPORT_ADDRESS Address;
+ HTTP_REQUEST_HEADERS Headers;
+ ULONGLONG BytesReceived;
+ USHORT EntityChunkCount;
+ PHTTP_DATA_CHUNK pEntityChunks;
+ HTTP_RAW_CONNECTION_ID RawConnectionId;
+ PHTTP_SSL_INFO pSslInfo;
+} HTTP_REQUEST_V1, *PHTTP_REQUEST_V1;
+
+using HTTP_REQUEST = HTTP_REQUEST_V1;
+using PHTTP_REQUEST = PHTTP_REQUEST_V1;
+
+ULONG HttpReceiveHttpRequest(
+ HANDLE RequestQueueHandle,
+ HTTP_REQUEST_ID RequestId,
+ ULONG Flags,
+ PHTTP_REQUEST RequestBuffer,
+ ULONG RequestBufferLength,
+ PULONG BytesReturned,
+ LPOVERLAPPED Overlapped
+);
+
+ULONG HttpReceiveRequestEntityBody(
+ HANDLE RequestQueueHandle,
+ HTTP_REQUEST_ID RequestId,
+ ULONG Flags,
+ PVOID EntityBuffer,
+ ULONG EntityBufferLength,
+ PULONG BytesReturned,
+ LPOVERLAPPED Overlapped
+);
+
+ULONG HttpReceiveClientCertificate(
+ HANDLE RequestQueueHandle,
+ HTTP_CONNECTION_ID ConnectionId,
+ ULONG Flags,
+ PHTTP_SSL_CLIENT_CERT_INFO SslClientCertInfo,
+ ULONG SslClientCertInfoSize,
+ PULONG BytesReceived,
+ LPOVERLAPPED Overlapped
+);
+
+void sink(PCWSTR);
+void sink(HANDLE);
+
+void test_http_server_api(HANDLE hRequestQueue) {
+ {
+ HTTP_REQUEST requestBuffer;
+ ULONG bytesReturned;
+ ULONG result = HttpReceiveHttpRequest(hRequestQueue, 0, 0, &requestBuffer, sizeof(requestBuffer), &bytesReturned, nullptr);
+ char* p = reinterpret_cast(&requestBuffer);
+ sink(p);
+ sink(*p); // $ ir
+ sink(requestBuffer.pRawUrl);
+ sink(*requestBuffer.pRawUrl); // $ ir
+ sink(requestBuffer.CookedUrl.pFullUrl);
+ sink(*requestBuffer.CookedUrl.pFullUrl); // $ ir
+ sink(requestBuffer.Headers.KnownHeaders[0].pRawValue);
+ sink(*requestBuffer.Headers.KnownHeaders[0].pRawValue); // $ ir
+ sink(requestBuffer.Headers.pUnknownHeaders[0].pRawValue);
+ sink(*requestBuffer.Headers.pUnknownHeaders[0].pRawValue); // $ ir
+ sink(requestBuffer.pEntityChunks->FromFileHandle.FileHandle); // $ ir
+ sink(requestBuffer.pEntityChunks->FromFragmentCache.pFragmentName);
+ sink(*requestBuffer.pEntityChunks->FromFragmentCache.pFragmentName); // $ ir
+ sink(requestBuffer.pEntityChunks->FromFragmentCacheEx.pFragmentName);
+ sink(*requestBuffer.pEntityChunks->FromFragmentCacheEx.pFragmentName); // $ ir
+ sink(requestBuffer.pEntityChunks->FromMemory.pBuffer);
+ sink(*(char*)requestBuffer.pEntityChunks->FromMemory.pBuffer); // $ ir
+ sink(requestBuffer.pSslInfo->pServerCertIssuer);
+ sink(*requestBuffer.pSslInfo->pServerCertIssuer); // $ ir
+ sink(requestBuffer.pSslInfo->pServerCertSubject);
+ sink(*requestBuffer.pSslInfo->pServerCertSubject); // $ ir
+ sink(requestBuffer.pSslInfo->pClientCertInfo->pCertEncoded);
+ sink(*requestBuffer.pSslInfo->pClientCertInfo->pCertEncoded); // $ ir
+ }
+ {
+ char buffer[1024];
+ ULONG bytesReturned;
+ ULONG result = HttpReceiveRequestEntityBody(hRequestQueue, 0, 0, buffer, sizeof(buffer), &bytesReturned, nullptr);
+ sink(buffer);
+ sink(*buffer); // $ ir
+ }
+ {
+ HTTP_SSL_CLIENT_CERT_INFO certInfo;
+ ULONG bytesReceived;
+ ULONG result = HttpReceiveClientCertificate(hRequestQueue, 0, 0, &certInfo, sizeof(certInfo), &bytesReceived, nullptr);
+ char* p = reinterpret_cast(&certInfo);
+ sink(p);
+ sink(*p); // $ ir
+ sink(certInfo.pCertEncoded);
+ sink(*certInfo.pCertEncoded); // $ ir
+ }
}
\ No newline at end of file
diff --git a/cpp/ql/test/library-tests/dataflow/fields/A.cpp b/cpp/ql/test/library-tests/dataflow/fields/A.cpp
index a3a151576e5..d65fa7c543d 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/A.cpp
+++ b/cpp/ql/test/library-tests/dataflow/fields/A.cpp
@@ -46,7 +46,7 @@ public:
{
C *c = new C();
B *b = B::make(c);
- sink(b->c); // $ast,ir
+ sink(b->c); // $ ast,ir
}
void f2()
diff --git a/cpp/ql/test/library-tests/dataflow/fields/C.cpp b/cpp/ql/test/library-tests/dataflow/fields/C.cpp
index 96bbb25a3b6..0c092928272 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/C.cpp
+++ b/cpp/ql/test/library-tests/dataflow/fields/C.cpp
@@ -26,9 +26,9 @@ public:
void func()
{
- sink(s1); // $ast,ir
- sink(s2); // $ MISSING: ast,ir
- sink(s3); // $ast,ir
+ sink(s1); // $ ast,ir
+ sink(s2); // $ ir MISSING: ast
+ sink(s3); // $ ast,ir
sink(s4); // $ MISSING: ast,ir
}
};
diff --git a/cpp/ql/test/library-tests/dataflow/fields/D.cpp b/cpp/ql/test/library-tests/dataflow/fields/D.cpp
index ee51e6e5428..b2c882a6982 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/D.cpp
+++ b/cpp/ql/test/library-tests/dataflow/fields/D.cpp
@@ -19,7 +19,7 @@ public:
};
static void sinkWrap(Box2* b2) {
- sink(b2->getBox1()->getElem()); // $ast,ir=28:15 ast,ir=35:15 ast,ir=42:15 ast,ir=49:15
+ sink(b2->getBox1()->getElem()); // $ ast,ir=28:15 ast,ir=35:15 ast,ir=42:15 ast,ir=49:15
}
Box2* boxfield;
diff --git a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp
index d8c6a194151..680b1489228 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp
+++ b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp
@@ -48,25 +48,25 @@ struct S {
void test_setDirectly() {
S s;
s.setDirectly(user_input());
- sink(s.getDirectly()); // $ast ir
+ sink(s.getDirectly()); // $ ast ir
}
void test_setIndirectly() {
S s;
s.setIndirectly(user_input());
- sink(s.getIndirectly()); // $ast ir
+ sink(s.getIndirectly()); // $ ast ir
}
void test_setThroughNonMember() {
S s;
s.setThroughNonMember(user_input());
- sink(s.getThroughNonMember()); // $ast ir
+ sink(s.getThroughNonMember()); // $ ast ir
}
void test_nonMemberSetA() {
S s;
nonMemberSetA(&s, user_input());
- sink(nonMemberGetA(&s)); // $ast,ir
+ sink(nonMemberGetA(&s)); // $ ast,ir
}
////////////////////
@@ -112,7 +112,7 @@ void test_outer_with_ptr(Outer *pouter) {
sink(outer.a); // $ ast,ir
sink(pouter->inner_nested.a); // $ ast,ir
- sink(pouter->inner_ptr->a); // $ast,ir
+ sink(pouter->inner_ptr->a); // $ ast,ir
sink(pouter->a); // $ ast,ir
}
diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected
index cc8cd2826bf..2e38382150f 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected
+++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected
@@ -187,23 +187,34 @@ edges
| B.cpp:46:7:46:10 | *this [post update] [*box1, elem2] | B.cpp:44:5:44:8 | *this [Return] [*box1, elem2] | provenance | |
| B.cpp:46:7:46:21 | *... = ... [elem1] | B.cpp:46:7:46:10 | *this [post update] [*box1, elem1] | provenance | |
| B.cpp:46:7:46:21 | *... = ... [elem2] | B.cpp:46:7:46:10 | *this [post update] [*box1, elem2] | provenance | |
+| C.cpp:10:15:10:16 | *s2 [post update] [s2] | C.cpp:10:15:10:16 | *this [Return] [s2] | provenance | |
+| C.cpp:10:15:10:16 | *this [Return] [s2] | C.cpp:22:3:22:3 | s2 output argument [s2] | provenance | |
+| C.cpp:10:20:10:29 | new | C.cpp:10:15:10:16 | *s2 [post update] [s2] | provenance | |
+| C.cpp:10:20:10:29 | new | C.cpp:10:20:10:29 | new | provenance | |
| C.cpp:18:12:18:18 | *new [s1] | C.cpp:19:5:19:5 | *c [s1] | provenance | |
+| C.cpp:18:12:18:18 | *new [s2] | C.cpp:19:5:19:5 | *c [s2] | provenance | |
| C.cpp:18:12:18:18 | *new [s3] | C.cpp:19:5:19:5 | *c [s3] | provenance | |
| C.cpp:18:12:18:18 | call to C [s1] | C.cpp:18:12:18:18 | *new [s1] | provenance | |
+| C.cpp:18:12:18:18 | call to C [s2] | C.cpp:18:12:18:18 | *new [s2] | provenance | |
| C.cpp:18:12:18:18 | call to C [s3] | C.cpp:18:12:18:18 | *new [s3] | provenance | |
| C.cpp:19:5:19:5 | *c [s1] | C.cpp:27:8:27:11 | *this [s1] | provenance | |
+| C.cpp:19:5:19:5 | *c [s2] | C.cpp:27:8:27:11 | *this [s2] | provenance | |
| C.cpp:19:5:19:5 | *c [s3] | C.cpp:27:8:27:11 | *this [s3] | provenance | |
| C.cpp:22:3:22:3 | *C [post update] [s1] | C.cpp:22:3:22:3 | *this [Return] [s1] | provenance | |
| C.cpp:22:3:22:3 | *this [Return] [s1] | C.cpp:18:12:18:18 | call to C [s1] | provenance | |
+| C.cpp:22:3:22:3 | *this [Return] [s2] | C.cpp:18:12:18:18 | call to C [s2] | provenance | |
| C.cpp:22:3:22:3 | *this [Return] [s3] | C.cpp:18:12:18:18 | call to C [s3] | provenance | |
+| C.cpp:22:3:22:3 | s2 output argument [s2] | C.cpp:22:3:22:3 | *this [Return] [s2] | provenance | |
| C.cpp:22:12:22:21 | new | C.cpp:22:3:22:3 | *C [post update] [s1] | provenance | |
| C.cpp:22:12:22:21 | new | C.cpp:22:12:22:21 | new | provenance | |
| C.cpp:24:5:24:8 | *this [post update] [s3] | C.cpp:22:3:22:3 | *this [Return] [s3] | provenance | |
| C.cpp:24:5:24:25 | ... = ... | C.cpp:24:5:24:8 | *this [post update] [s3] | provenance | |
| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | ... = ... | provenance | |
| C.cpp:27:8:27:11 | *this [s1] | C.cpp:29:10:29:11 | *this [s1] | provenance | |
+| C.cpp:27:8:27:11 | *this [s2] | C.cpp:30:10:30:11 | *this [s2] | provenance | |
| C.cpp:27:8:27:11 | *this [s3] | C.cpp:31:10:31:11 | *this [s3] | provenance | |
| C.cpp:29:10:29:11 | *this [s1] | C.cpp:29:10:29:11 | s1 | provenance | |
+| C.cpp:30:10:30:11 | *this [s2] | C.cpp:30:10:30:11 | s2 | provenance | |
| C.cpp:31:10:31:11 | *this [s3] | C.cpp:31:10:31:11 | s3 | provenance | |
| D.cpp:10:11:10:17 | *this [elem] | D.cpp:10:30:10:33 | *this [elem] | provenance | |
| D.cpp:10:30:10:33 | *this [elem] | D.cpp:10:30:10:33 | elem | provenance | |
@@ -1116,24 +1127,36 @@ nodes
| B.cpp:46:7:46:10 | *this [post update] [*box1, elem2] | semmle.label | *this [post update] [*box1, elem2] |
| B.cpp:46:7:46:21 | *... = ... [elem1] | semmle.label | *... = ... [elem1] |
| B.cpp:46:7:46:21 | *... = ... [elem2] | semmle.label | *... = ... [elem2] |
+| C.cpp:10:15:10:16 | *s2 [post update] [s2] | semmle.label | *s2 [post update] [s2] |
+| C.cpp:10:15:10:16 | *this [Return] [s2] | semmle.label | *this [Return] [s2] |
+| C.cpp:10:20:10:29 | new | semmle.label | new |
+| C.cpp:10:20:10:29 | new | semmle.label | new |
| C.cpp:18:12:18:18 | *new [s1] | semmle.label | *new [s1] |
+| C.cpp:18:12:18:18 | *new [s2] | semmle.label | *new [s2] |
| C.cpp:18:12:18:18 | *new [s3] | semmle.label | *new [s3] |
| C.cpp:18:12:18:18 | call to C [s1] | semmle.label | call to C [s1] |
+| C.cpp:18:12:18:18 | call to C [s2] | semmle.label | call to C [s2] |
| C.cpp:18:12:18:18 | call to C [s3] | semmle.label | call to C [s3] |
| C.cpp:19:5:19:5 | *c [s1] | semmle.label | *c [s1] |
+| C.cpp:19:5:19:5 | *c [s2] | semmle.label | *c [s2] |
| C.cpp:19:5:19:5 | *c [s3] | semmle.label | *c [s3] |
| C.cpp:22:3:22:3 | *C [post update] [s1] | semmle.label | *C [post update] [s1] |
| C.cpp:22:3:22:3 | *this [Return] [s1] | semmle.label | *this [Return] [s1] |
+| C.cpp:22:3:22:3 | *this [Return] [s2] | semmle.label | *this [Return] [s2] |
| C.cpp:22:3:22:3 | *this [Return] [s3] | semmle.label | *this [Return] [s3] |
+| C.cpp:22:3:22:3 | s2 output argument [s2] | semmle.label | s2 output argument [s2] |
| C.cpp:22:12:22:21 | new | semmle.label | new |
| C.cpp:22:12:22:21 | new | semmle.label | new |
| C.cpp:24:5:24:8 | *this [post update] [s3] | semmle.label | *this [post update] [s3] |
| C.cpp:24:5:24:25 | ... = ... | semmle.label | ... = ... |
| C.cpp:24:16:24:25 | new | semmle.label | new |
| C.cpp:27:8:27:11 | *this [s1] | semmle.label | *this [s1] |
+| C.cpp:27:8:27:11 | *this [s2] | semmle.label | *this [s2] |
| C.cpp:27:8:27:11 | *this [s3] | semmle.label | *this [s3] |
| C.cpp:29:10:29:11 | *this [s1] | semmle.label | *this [s1] |
| C.cpp:29:10:29:11 | s1 | semmle.label | s1 |
+| C.cpp:30:10:30:11 | *this [s2] | semmle.label | *this [s2] |
+| C.cpp:30:10:30:11 | s2 | semmle.label | s2 |
| C.cpp:31:10:31:11 | *this [s3] | semmle.label | *this [s3] |
| C.cpp:31:10:31:11 | s3 | semmle.label | s3 |
| D.cpp:10:11:10:17 | *getElem | semmle.label | *getElem |
@@ -1958,6 +1981,7 @@ subpaths
| B.cpp:9:10:9:24 | elem1 | B.cpp:6:15:6:24 | new | B.cpp:9:10:9:24 | elem1 | elem1 flows from $@ | B.cpp:6:15:6:24 | new | new |
| B.cpp:19:10:19:24 | elem2 | B.cpp:15:15:15:27 | new | B.cpp:19:10:19:24 | elem2 | elem2 flows from $@ | B.cpp:15:15:15:27 | new | new |
| C.cpp:29:10:29:11 | s1 | C.cpp:22:12:22:21 | new | C.cpp:29:10:29:11 | s1 | s1 flows from $@ | C.cpp:22:12:22:21 | new | new |
+| C.cpp:30:10:30:11 | s2 | C.cpp:10:20:10:29 | new | C.cpp:30:10:30:11 | s2 | s2 flows from $@ | C.cpp:10:20:10:29 | new | new |
| C.cpp:31:10:31:11 | s3 | C.cpp:24:16:24:25 | new | C.cpp:31:10:31:11 | s3 | s3 flows from $@ | C.cpp:24:16:24:25 | new | new |
| D.cpp:22:10:22:33 | call to getElem | D.cpp:28:15:28:24 | new | D.cpp:22:10:22:33 | call to getElem | call to getElem flows from $@ | D.cpp:28:15:28:24 | new | new |
| D.cpp:22:10:22:33 | call to getElem | D.cpp:35:15:35:24 | new | D.cpp:22:10:22:33 | call to getElem | call to getElem flows from $@ | D.cpp:35:15:35:24 | new | new |
diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp
index d220b416e1a..fb598bd9d71 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp
+++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp
@@ -64,7 +64,7 @@ void single_field_test()
A a;
a.i = user_input();
A a2 = a;
- sink(a2.i); //$ ast,ir
+ sink(a2.i); // $ ast,ir
}
struct C {
@@ -81,7 +81,7 @@ struct C2
void m() {
f2.f1 = user_input();
- sink(getf2f1()); //$ ast,ir
+ sink(getf2f1()); // $ ast,ir
}
};
@@ -91,7 +91,7 @@ void single_field_test_typedef(A_typedef a)
{
a.i = user_input();
A_typedef a2 = a;
- sink(a2.i); //$ ast,ir
+ sink(a2.i); // $ ast,ir
}
namespace TestAdditionalCallTargets {
@@ -168,4 +168,4 @@ void test_union_with_two_instantiations_of_different_sizes() {
sink(u_int.y); // $ MISSING: ir
}
-} // namespace Simple
\ No newline at end of file
+} // namespace Simple
diff --git a/cpp/ql/test/library-tests/dataflow/fields/struct_init.c b/cpp/ql/test/library-tests/dataflow/fields/struct_init.c
index d2abfeefc08..2b6716a4bc3 100644
--- a/cpp/ql/test/library-tests/dataflow/fields/struct_init.c
+++ b/cpp/ql/test/library-tests/dataflow/fields/struct_init.c
@@ -12,14 +12,14 @@ struct Outer {
};
void absink(struct AB *ab) {
- sink(ab->a); //$ ast,ir=20:20 ast,ir=27:7 ast,ir=40:20
+ sink(ab->a); // $ ast,ir=20:20 ast,ir=27:7 ast,ir=40:20
sink(ab->b); // no flow
}
int struct_init(void) {
struct AB ab = { user_input(), 0 };
- sink(ab.a); //$ ast,ir
+ sink(ab.a); // $ ast,ir
sink(ab.b); // no flow
absink(&ab);
@@ -28,9 +28,9 @@ int struct_init(void) {
&ab,
};
- sink(outer.nestedAB.a); //$ ast,ir
+ sink(outer.nestedAB.a); // $ ast,ir
sink(outer.nestedAB.b); // no flow
- sink(outer.pointerAB->a); //$ ast,ir
+ sink(outer.pointerAB->a); // $ ast,ir
sink(outer.pointerAB->b); // no flow
absink(&outer.nestedAB);
diff --git a/cpp/ql/test/library-tests/dataflow/ir-barrier-guards/test.ql b/cpp/ql/test/library-tests/dataflow/ir-barrier-guards/test.ql
index 8948c65e33c..ce7b7999102 100644
--- a/cpp/ql/test/library-tests/dataflow/ir-barrier-guards/test.ql
+++ b/cpp/ql/test/library-tests/dataflow/ir-barrier-guards/test.ql
@@ -15,7 +15,10 @@ predicate instructionGuardChecks(IRGuardCondition gc, Instruction checked, boole
module BarrierGuard = DataFlow::InstructionBarrierGuard;
predicate indirectBarrierGuard(DataFlow::Node node, string s) {
- node = BarrierGuard::getAnIndirectBarrierNode(_) and
+ // This any(...) could technically be removed, but it helps us verify that we don't
+ // accidentially change the API of this predicate (for instance, by having
+ // the column be a unit parameter).
+ node = BarrierGuard::getAnIndirectBarrierNode(any(int indirectionIndex)) and
if node.isGLValue()
then s = "glval<" + node.getType().toString().replaceAll(" ", "") + ">"
else s = node.getType().toString().replaceAll(" ", "")
diff --git a/cpp/ql/test/library-tests/dataflow/models-as-data/FlowSummaryNode.ql b/cpp/ql/test/library-tests/dataflow/models-as-data/FlowSummaryNode.ql
deleted file mode 100644
index 399e2e129b3..00000000000
--- a/cpp/ql/test/library-tests/dataflow/models-as-data/FlowSummaryNode.ql
+++ /dev/null
@@ -1,19 +0,0 @@
-import testModels
-private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
-private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
-
-string describe(DataFlow::Node n) {
- n instanceof ParameterNode and result = "ParameterNode"
- or
- n instanceof PostUpdateNode and result = "PostUpdateNode"
- or
- n instanceof ArgumentNode and result = "ArgumentNode"
- or
- n instanceof ReturnNode and result = "ReturnNode"
- or
- n instanceof OutNode and result = "OutNode"
-}
-
-from FlowSummaryNode n
-select n, concat(describe(n), ", "), concat(n.getSummarizedCallable().toString(), ", "),
- concat(n.getEnclosingCallable().toString(), ", ")
diff --git a/cpp/ql/test/library-tests/dataflow/models-as-data/SummaryCall.expected b/cpp/ql/test/library-tests/dataflow/models-as-data/SummaryCall.expected
deleted file mode 100644
index 54bd0ca489a..00000000000
--- a/cpp/ql/test/library-tests/dataflow/models-as-data/SummaryCall.expected
+++ /dev/null
@@ -1,267 +0,0 @@
-summaryCalls
-| file://:0:0:0:0 | [summary] call to [summary param] 0 in madCallArg0ReturnToReturn in madCallArg0ReturnToReturn |
-| file://:0:0:0:0 | [summary] call to [summary param] 0 in madCallArg0ReturnToReturnFirst in madCallArg0ReturnToReturnFirst |
-| file://:0:0:0:0 | [summary] call to [summary param] 0 in madCallArg0WithValue in madCallArg0WithValue |
-summarizedCallables
-| tests.cpp:144:5:144:19 | madArg0ToReturn |
-| tests.cpp:145:6:145:28 | madArg0ToReturnIndirect |
-| tests.cpp:147:5:147:28 | madArg0ToReturnValueFlow |
-| tests.cpp:148:5:148:27 | madArg0IndirectToReturn |
-| tests.cpp:149:5:149:33 | madArg0DoubleIndirectToReturn |
-| tests.cpp:150:5:150:30 | madArg0NotIndirectToReturn |
-| tests.cpp:151:6:151:26 | madArg0ToArg1Indirect |
-| tests.cpp:152:6:152:34 | madArg0IndirectToArg1Indirect |
-| tests.cpp:153:5:153:18 | madArgsComplex |
-| tests.cpp:154:5:154:14 | madArgsAny |
-| tests.cpp:155:5:155:28 | madAndImplementedComplex |
-| tests.cpp:160:5:160:24 | madArg0FieldToReturn |
-| tests.cpp:161:5:161:32 | madArg0IndirectFieldToReturn |
-| tests.cpp:162:5:162:32 | madArg0FieldIndirectToReturn |
-| tests.cpp:163:13:163:32 | madArg0ToReturnField |
-| tests.cpp:164:14:164:41 | madArg0ToReturnIndirectField |
-| tests.cpp:165:13:165:40 | madArg0ToReturnFieldIndirect |
-| tests.cpp:284:7:284:19 | madArg0ToSelf |
-| tests.cpp:285:6:285:20 | madSelfToReturn |
-| tests.cpp:287:7:287:20 | madArg0ToField |
-| tests.cpp:288:6:288:21 | madFieldToReturn |
-| tests.cpp:313:7:313:30 | namespaceMadSelfToReturn |
-| tests.cpp:434:5:434:29 | madCallArg0ReturnToReturn |
-| tests.cpp:435:9:435:38 | madCallArg0ReturnToReturnFirst |
-| tests.cpp:436:6:436:25 | madCallArg0WithValue |
-| tests.cpp:437:5:437:36 | madCallReturnValueIgnoreFunction |
-| tests.cpp:459:5:459:31 | parameter_ref_to_return_ref |
-| tests.cpp:471:5:471:17 | receive_array |
-sourceCallables
-| tests.cpp:3:5:3:10 | source |
-| tests.cpp:4:6:4:14 | sourcePtr |
-| tests.cpp:5:6:5:19 | sourceIndirect |
-| tests.cpp:6:6:6:9 | sink |
-| tests.cpp:6:15:6:17 | val |
-| tests.cpp:7:6:7:9 | sink |
-| tests.cpp:7:16:7:18 | ptr |
-| tests.cpp:11:5:11:18 | localMadSource |
-| tests.cpp:12:5:12:19 | remoteMadSource |
-| tests.cpp:13:5:13:14 | notASource |
-| tests.cpp:14:5:14:22 | localMadSourceVoid |
-| tests.cpp:15:5:15:25 | localMadSourceHasBody |
-| tests.cpp:16:6:16:28 | remoteMadSourceIndirect |
-| tests.cpp:17:7:17:35 | remoteMadSourceDoubleIndirect |
-| tests.cpp:18:6:18:32 | remoteMadSourceIndirectArg0 |
-| tests.cpp:18:39:18:39 | x |
-| tests.cpp:18:47:18:47 | y |
-| tests.cpp:19:6:19:32 | remoteMadSourceIndirectArg1 |
-| tests.cpp:19:39:19:39 | x |
-| tests.cpp:19:47:19:47 | y |
-| tests.cpp:20:5:20:22 | remoteMadSourceVar |
-| tests.cpp:21:6:21:31 | remoteMadSourceVarIndirect |
-| tests.cpp:24:6:24:28 | namespaceLocalMadSource |
-| tests.cpp:25:6:25:31 | namespaceLocalMadSourceVar |
-| tests.cpp:28:7:28:30 | namespace2LocalMadSource |
-| tests.cpp:31:6:31:19 | localMadSource |
-| tests.cpp:33:5:33:27 | namespaceLocalMadSource |
-| tests.cpp:35:6:35:17 | test_sources |
-| tests.cpp:50:6:50:6 | v |
-| tests.cpp:51:7:51:16 | v_indirect |
-| tests.cpp:52:6:52:13 | v_direct |
-| tests.cpp:63:6:63:6 | a |
-| tests.cpp:63:9:63:9 | b |
-| tests.cpp:63:12:63:12 | c |
-| tests.cpp:63:15:63:15 | d |
-| tests.cpp:75:6:75:6 | e |
-| tests.cpp:85:6:85:26 | remoteMadSourceParam0 |
-| tests.cpp:85:32:85:32 | x |
-| tests.cpp:92:6:92:16 | madSinkArg0 |
-| tests.cpp:92:22:92:22 | x |
-| tests.cpp:93:6:93:13 | notASink |
-| tests.cpp:93:19:93:19 | x |
-| tests.cpp:94:6:94:16 | madSinkArg1 |
-| tests.cpp:94:22:94:22 | x |
-| tests.cpp:94:29:94:29 | y |
-| tests.cpp:95:6:95:17 | madSinkArg01 |
-| tests.cpp:95:23:95:23 | x |
-| tests.cpp:95:30:95:30 | y |
-| tests.cpp:95:37:95:37 | z |
-| tests.cpp:96:6:96:17 | madSinkArg02 |
-| tests.cpp:96:23:96:23 | x |
-| tests.cpp:96:30:96:30 | y |
-| tests.cpp:96:37:96:37 | z |
-| tests.cpp:97:6:97:24 | madSinkIndirectArg0 |
-| tests.cpp:97:31:97:31 | x |
-| tests.cpp:98:6:98:30 | madSinkDoubleIndirectArg0 |
-| tests.cpp:98:38:98:38 | x |
-| tests.cpp:99:5:99:14 | madSinkVar |
-| tests.cpp:100:6:100:23 | madSinkVarIndirect |
-| tests.cpp:102:6:102:15 | test_sinks |
-| tests.cpp:116:6:116:6 | a |
-| tests.cpp:117:7:117:11 | a_ptr |
-| tests.cpp:132:6:132:18 | madSinkParam0 |
-| tests.cpp:132:24:132:24 | x |
-| tests.cpp:138:8:138:8 | operator= |
-| tests.cpp:138:8:138:8 | operator= |
-| tests.cpp:138:8:138:18 | MyContainer |
-| tests.cpp:139:6:139:10 | value |
-| tests.cpp:140:6:140:11 | value2 |
-| tests.cpp:141:7:141:9 | ptr |
-| tests.cpp:144:5:144:19 | madArg0ToReturn |
-| tests.cpp:144:25:144:25 | x |
-| tests.cpp:145:6:145:28 | madArg0ToReturnIndirect |
-| tests.cpp:145:34:145:34 | x |
-| tests.cpp:146:5:146:15 | notASummary |
-| tests.cpp:146:21:146:21 | x |
-| tests.cpp:147:5:147:28 | madArg0ToReturnValueFlow |
-| tests.cpp:147:34:147:34 | x |
-| tests.cpp:148:5:148:27 | madArg0IndirectToReturn |
-| tests.cpp:148:34:148:34 | x |
-| tests.cpp:149:5:149:33 | madArg0DoubleIndirectToReturn |
-| tests.cpp:149:41:149:41 | x |
-| tests.cpp:150:5:150:30 | madArg0NotIndirectToReturn |
-| tests.cpp:150:37:150:37 | x |
-| tests.cpp:151:6:151:26 | madArg0ToArg1Indirect |
-| tests.cpp:151:32:151:32 | x |
-| tests.cpp:151:40:151:40 | y |
-| tests.cpp:152:6:152:34 | madArg0IndirectToArg1Indirect |
-| tests.cpp:152:47:152:47 | x |
-| tests.cpp:152:55:152:55 | y |
-| tests.cpp:153:5:153:18 | madArgsComplex |
-| tests.cpp:153:25:153:25 | a |
-| tests.cpp:153:33:153:33 | b |
-| tests.cpp:153:40:153:40 | c |
-| tests.cpp:153:47:153:47 | d |
-| tests.cpp:154:5:154:14 | madArgsAny |
-| tests.cpp:154:20:154:20 | a |
-| tests.cpp:154:28:154:28 | b |
-| tests.cpp:155:5:155:28 | madAndImplementedComplex |
-| tests.cpp:155:34:155:34 | a |
-| tests.cpp:155:41:155:41 | b |
-| tests.cpp:155:48:155:48 | c |
-| tests.cpp:160:5:160:24 | madArg0FieldToReturn |
-| tests.cpp:160:38:160:39 | mc |
-| tests.cpp:161:5:161:32 | madArg0IndirectFieldToReturn |
-| tests.cpp:161:47:161:48 | mc |
-| tests.cpp:162:5:162:32 | madArg0FieldIndirectToReturn |
-| tests.cpp:162:46:162:47 | mc |
-| tests.cpp:163:13:163:32 | madArg0ToReturnField |
-| tests.cpp:163:38:163:38 | x |
-| tests.cpp:164:14:164:41 | madArg0ToReturnIndirectField |
-| tests.cpp:164:47:164:47 | x |
-| tests.cpp:165:13:165:40 | madArg0ToReturnFieldIndirect |
-| tests.cpp:165:46:165:46 | x |
-| tests.cpp:167:13:167:30 | madFieldToFieldVar |
-| tests.cpp:168:13:168:38 | madFieldToIndirectFieldVar |
-| tests.cpp:169:14:169:39 | madIndirectFieldToFieldVar |
-| tests.cpp:171:6:171:19 | test_summaries |
-| tests.cpp:174:6:174:6 | a |
-| tests.cpp:174:9:174:9 | b |
-| tests.cpp:174:12:174:12 | c |
-| tests.cpp:174:15:174:15 | d |
-| tests.cpp:174:18:174:18 | e |
-| tests.cpp:175:7:175:11 | a_ptr |
-| tests.cpp:218:14:218:16 | mc1 |
-| tests.cpp:218:19:218:21 | mc2 |
-| tests.cpp:237:15:237:18 | rtn1 |
-| tests.cpp:240:14:240:17 | rtn2 |
-| tests.cpp:241:7:241:14 | rtn2_ptr |
-| tests.cpp:267:7:267:7 | operator= |
-| tests.cpp:267:7:267:7 | operator= |
-| tests.cpp:267:7:267:13 | MyClass |
-| tests.cpp:270:6:270:26 | memberRemoteMadSource |
-| tests.cpp:271:7:271:39 | memberRemoteMadSourceIndirectArg0 |
-| tests.cpp:271:46:271:46 | x |
-| tests.cpp:272:6:272:29 | memberRemoteMadSourceVar |
-| tests.cpp:273:7:273:21 | qualifierSource |
-| tests.cpp:274:7:274:26 | qualifierFieldSource |
-| tests.cpp:277:7:277:23 | memberMadSinkArg0 |
-| tests.cpp:277:29:277:29 | x |
-| tests.cpp:278:6:278:21 | memberMadSinkVar |
-| tests.cpp:279:7:279:19 | qualifierSink |
-| tests.cpp:280:7:280:23 | qualifierArg0Sink |
-| tests.cpp:280:29:280:29 | x |
-| tests.cpp:281:7:281:24 | qualifierFieldSink |
-| tests.cpp:284:7:284:19 | madArg0ToSelf |
-| tests.cpp:284:25:284:25 | x |
-| tests.cpp:285:6:285:20 | madSelfToReturn |
-| tests.cpp:286:6:286:16 | notASummary |
-| tests.cpp:287:7:287:20 | madArg0ToField |
-| tests.cpp:287:26:287:26 | x |
-| tests.cpp:288:6:288:21 | madFieldToReturn |
-| tests.cpp:290:6:290:8 | val |
-| tests.cpp:293:7:293:7 | MyDerivedClass |
-| tests.cpp:293:7:293:7 | operator= |
-| tests.cpp:293:7:293:7 | operator= |
-| tests.cpp:293:7:293:20 | MyDerivedClass |
-| tests.cpp:295:6:295:28 | subtypeRemoteMadSource1 |
-| tests.cpp:296:6:296:21 | subtypeNonSource |
-| tests.cpp:297:6:297:28 | subtypeRemoteMadSource2 |
-| tests.cpp:300:9:300:15 | source2 |
-| tests.cpp:301:6:301:9 | sink |
-| tests.cpp:301:19:301:20 | mc |
-| tests.cpp:304:8:304:8 | operator= |
-| tests.cpp:304:8:304:8 | operator= |
-| tests.cpp:304:8:304:14 | MyClass |
-| tests.cpp:307:8:307:33 | namespaceMemberMadSinkArg0 |
-| tests.cpp:307:39:307:39 | x |
-| tests.cpp:308:15:308:46 | namespaceStaticMemberMadSinkArg0 |
-| tests.cpp:308:52:308:52 | x |
-| tests.cpp:309:7:309:31 | namespaceMemberMadSinkVar |
-| tests.cpp:310:14:310:44 | namespaceStaticMemberMadSinkVar |
-| tests.cpp:313:7:313:30 | namespaceMadSelfToReturn |
-| tests.cpp:317:22:317:28 | source3 |
-| tests.cpp:319:6:319:23 | test_class_members |
-| tests.cpp:320:10:320:11 | mc |
-| tests.cpp:320:14:320:16 | mc2 |
-| tests.cpp:320:19:320:21 | mc3 |
-| tests.cpp:320:24:320:26 | mc4 |
-| tests.cpp:320:29:320:31 | mc5 |
-| tests.cpp:320:34:320:36 | mc6 |
-| tests.cpp:320:39:320:41 | mc7 |
-| tests.cpp:320:44:320:46 | mc8 |
-| tests.cpp:320:49:320:51 | mc9 |
-| tests.cpp:320:54:320:57 | mc10 |
-| tests.cpp:320:60:320:63 | mc11 |
-| tests.cpp:321:11:321:13 | ptr |
-| tests.cpp:321:17:321:23 | mc4_ptr |
-| tests.cpp:322:17:322:19 | mdc |
-| tests.cpp:323:23:323:25 | mnc |
-| tests.cpp:323:28:323:31 | mnc2 |
-| tests.cpp:324:24:324:31 | mnc2_ptr |
-| tests.cpp:330:6:330:6 | a |
-| tests.cpp:429:8:429:8 | operator= |
-| tests.cpp:429:8:429:8 | operator= |
-| tests.cpp:429:8:429:14 | intPair |
-| tests.cpp:430:6:430:10 | first |
-| tests.cpp:431:6:431:11 | second |
-| tests.cpp:434:5:434:29 | madCallArg0ReturnToReturn |
-| tests.cpp:434:37:434:43 | fun_ptr |
-| tests.cpp:435:9:435:38 | madCallArg0ReturnToReturnFirst |
-| tests.cpp:435:46:435:52 | fun_ptr |
-| tests.cpp:436:6:436:25 | madCallArg0WithValue |
-| tests.cpp:436:34:436:40 | fun_ptr |
-| tests.cpp:436:53:436:57 | value |
-| tests.cpp:437:5:437:36 | madCallReturnValueIgnoreFunction |
-| tests.cpp:437:45:437:51 | fun_ptr |
-| tests.cpp:437:64:437:68 | value |
-| tests.cpp:439:5:439:14 | getTainted |
-| tests.cpp:440:6:440:13 | useValue |
-| tests.cpp:440:19:440:19 | x |
-| tests.cpp:441:6:441:17 | dontUseValue |
-| tests.cpp:441:23:441:23 | x |
-| tests.cpp:443:6:443:27 | test_function_pointers |
-| tests.cpp:456:19:456:19 | X |
-| tests.cpp:457:8:457:35 | StructWithTypedefInParameter |
-| tests.cpp:457:8:457:35 | StructWithTypedefInParameter |
-| tests.cpp:458:12:458:15 | Type |
-| tests.cpp:459:5:459:31 | parameter_ref_to_return_ref |
-| tests.cpp:459:5:459:31 | parameter_ref_to_return_ref |
-| tests.cpp:459:45:459:45 | x |
-| tests.cpp:459:45:459:45 | x |
-| tests.cpp:462:6:462:37 | test_parameter_ref_to_return_ref |
-| tests.cpp:463:6:463:6 | x |
-| tests.cpp:464:36:464:36 | s |
-| tests.cpp:465:6:465:6 | y |
-| tests.cpp:469:7:469:9 | INT |
-| tests.cpp:471:5:471:17 | receive_array |
-| tests.cpp:471:23:471:23 | a |
-| tests.cpp:473:6:473:23 | test_receive_array |
-| tests.cpp:474:6:474:6 | x |
-| tests.cpp:475:6:475:10 | array |
-| tests.cpp:476:6:476:6 | y |
diff --git a/cpp/ql/test/library-tests/dataflow/models-as-data/SummaryCall.ql b/cpp/ql/test/library-tests/dataflow/models-as-data/SummaryCall.ql
deleted file mode 100644
index 1b569040028..00000000000
--- a/cpp/ql/test/library-tests/dataflow/models-as-data/SummaryCall.ql
+++ /dev/null
@@ -1,9 +0,0 @@
-import testModels
-private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
-private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
-
-query predicate summaryCalls(SummaryCall c) { any() }
-
-query predicate summarizedCallables(SummarizedCallable c) { any() }
-
-query predicate sourceCallables(SourceCallable c) { c.getLocation().getFile().toString() != "" }
diff --git a/cpp/ql/test/library-tests/dataflow/models-as-data/consistency.expected b/cpp/ql/test/library-tests/dataflow/models-as-data/consistency.expected
deleted file mode 100644
index c89f4455bc5..00000000000
--- a/cpp/ql/test/library-tests/dataflow/models-as-data/consistency.expected
+++ /dev/null
@@ -1,29 +0,0 @@
-uniqueEnclosingCallable
-uniqueCallEnclosingCallable
-uniqueType
-uniqueNodeLocation
-missingLocation
-uniqueNodeToString
-parameterCallable
-localFlowIsLocal
-readStepIsLocal
-storeStepIsLocal
-compatibleTypesReflexive
-unreachableNodeCCtx
-localCallNodes
-postIsNotPre
-postHasUniquePre
-uniquePostUpdate
-postIsInSameCallable
-reverseRead
-argHasPostUpdate
-postWithInFlow
-viableImplInCallContextTooLarge
-uniqueParameterNodeAtPosition
-uniqueParameterNodePosition
-uniqueContentApprox
-identityLocalStep
-missingArgumentCall
-multipleArgumentCall
-lambdaCallEnclosingCallableMismatch
-speculativeStepAlreadyHasModel
diff --git a/cpp/ql/test/library-tests/dataflow/models-as-data/consistency.ql b/cpp/ql/test/library-tests/dataflow/models-as-data/consistency.ql
deleted file mode 100644
index 1af8d69a356..00000000000
--- a/cpp/ql/test/library-tests/dataflow/models-as-data/consistency.ql
+++ /dev/null
@@ -1,2 +0,0 @@
-import testModels
-import semmle.code.cpp.ir.dataflow.internal.DataFlowImplConsistency::Consistency
diff --git a/cpp/ql/test/library-tests/dataflow/models-as-data/interpretElement.ql b/cpp/ql/test/library-tests/dataflow/models-as-data/interpretElement.ql
deleted file mode 100644
index ccf0c3f886d..00000000000
--- a/cpp/ql/test/library-tests/dataflow/models-as-data/interpretElement.ql
+++ /dev/null
@@ -1,18 +0,0 @@
-import utils.test.InlineExpectationsTest
-import testModels
-
-module InterpretElementTest implements TestSig {
- string getARelevantTag() { result = "interpretElement" }
-
- predicate hasActualResult(Location location, string element, string tag, string value) {
- exists(Element e |
- e = interpretElement(_, _, _, _, _, _) and
- location = e.getLocation() and
- element = e.toString() and
- tag = "interpretElement" and
- value = ""
- )
- }
-}
-
-import MakeTest
diff --git a/cpp/ql/test/library-tests/dataflow/models-as-data/taint.ql b/cpp/ql/test/library-tests/dataflow/models-as-data/taint.ql
deleted file mode 100644
index 8c362d78e3e..00000000000
--- a/cpp/ql/test/library-tests/dataflow/models-as-data/taint.ql
+++ /dev/null
@@ -1,32 +0,0 @@
-import utils.test.dataflow.FlowTestCommon
-import testModels
-
-module IRTest {
- private import semmle.code.cpp.ir.IR
- private import semmle.code.cpp.ir.dataflow.TaintTracking
-
- /** Common data flow configuration to be used by tests. */
- module TestAllocationConfig implements DataFlow::ConfigSig {
- predicate isSource(DataFlow::Node source) {
- source instanceof FlowSource
- or
- source.asExpr().(FunctionCall).getTarget().getName() =
- ["source", "source2", "source3", "sourcePtr"]
- or
- source.asIndirectExpr(1).(FunctionCall).getTarget().getName() = "sourceIndirect"
- }
-
- predicate isSink(DataFlow::Node sink) {
- sinkNode(sink, "test-sink")
- or
- exists(FunctionCall call |
- call.getTarget().getName() = "sink" and
- sink.asExpr() = call.getAnArgument()
- )
- }
- }
-
- module IRFlow = TaintTracking::Global;
-}
-
-import MakeTest>
diff --git a/cpp/ql/test/library-tests/dataflow/models-as-data/FlowSummaryNode.expected b/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.expected
similarity index 50%
rename from cpp/ql/test/library-tests/dataflow/models-as-data/FlowSummaryNode.expected
rename to cpp/ql/test/library-tests/dataflow/models-as-data/testModels.expected
index 756e9a7e22a..0faf016ee41 100644
--- a/cpp/ql/test/library-tests/dataflow/models-as-data/FlowSummaryNode.expected
+++ b/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.expected
@@ -1,3 +1,301 @@
+uniqueEnclosingCallable
+uniqueCallEnclosingCallable
+uniqueType
+uniqueNodeLocation
+missingLocation
+uniqueNodeToString
+parameterCallable
+localFlowIsLocal
+readStepIsLocal
+storeStepIsLocal
+compatibleTypesReflexive
+unreachableNodeCCtx
+localCallNodes
+postIsNotPre
+postHasUniquePre
+uniquePostUpdate
+postIsInSameCallable
+reverseRead
+argHasPostUpdate
+postWithInFlow
+viableImplInCallContextTooLarge
+uniqueParameterNodeAtPosition
+uniqueParameterNodePosition
+uniqueContentApprox
+identityLocalStep
+missingArgumentCall
+multipleArgumentCall
+lambdaCallEnclosingCallableMismatch
+speculativeStepAlreadyHasModel
+testFailures
+summaryCalls
+| file://:0:0:0:0 | [summary] call to [summary param] 0 in madCallArg0ReturnToReturn in madCallArg0ReturnToReturn |
+| file://:0:0:0:0 | [summary] call to [summary param] 0 in madCallArg0ReturnToReturnFirst in madCallArg0ReturnToReturnFirst |
+| file://:0:0:0:0 | [summary] call to [summary param] 0 in madCallArg0WithValue in madCallArg0WithValue |
+summarizedCallables
+| tests.cpp:144:5:144:19 | madArg0ToReturn |
+| tests.cpp:145:6:145:28 | madArg0ToReturnIndirect |
+| tests.cpp:147:5:147:28 | madArg0ToReturnValueFlow |
+| tests.cpp:148:5:148:27 | madArg0IndirectToReturn |
+| tests.cpp:149:5:149:33 | madArg0DoubleIndirectToReturn |
+| tests.cpp:150:5:150:30 | madArg0NotIndirectToReturn |
+| tests.cpp:151:6:151:26 | madArg0ToArg1Indirect |
+| tests.cpp:152:6:152:34 | madArg0IndirectToArg1Indirect |
+| tests.cpp:153:5:153:18 | madArgsComplex |
+| tests.cpp:154:5:154:14 | madArgsAny |
+| tests.cpp:155:5:155:28 | madAndImplementedComplex |
+| tests.cpp:160:5:160:24 | madArg0FieldToReturn |
+| tests.cpp:161:5:161:32 | madArg0IndirectFieldToReturn |
+| tests.cpp:162:5:162:32 | madArg0FieldIndirectToReturn |
+| tests.cpp:163:13:163:32 | madArg0ToReturnField |
+| tests.cpp:164:14:164:41 | madArg0ToReturnIndirectField |
+| tests.cpp:165:13:165:40 | madArg0ToReturnFieldIndirect |
+| tests.cpp:284:7:284:19 | madArg0ToSelf |
+| tests.cpp:285:6:285:20 | madSelfToReturn |
+| tests.cpp:287:7:287:20 | madArg0ToField |
+| tests.cpp:288:6:288:21 | madFieldToReturn |
+| tests.cpp:313:7:313:30 | namespaceMadSelfToReturn |
+| tests.cpp:434:5:434:29 | madCallArg0ReturnToReturn |
+| tests.cpp:435:9:435:38 | madCallArg0ReturnToReturnFirst |
+| tests.cpp:436:6:436:25 | madCallArg0WithValue |
+| tests.cpp:437:5:437:36 | madCallReturnValueIgnoreFunction |
+| tests.cpp:459:5:459:31 | parameter_ref_to_return_ref |
+| tests.cpp:471:5:471:17 | receive_array |
+sourceCallables
+| tests.cpp:3:5:3:10 | source |
+| tests.cpp:4:6:4:14 | sourcePtr |
+| tests.cpp:5:6:5:19 | sourceIndirect |
+| tests.cpp:6:6:6:9 | sink |
+| tests.cpp:6:15:6:17 | val |
+| tests.cpp:7:6:7:9 | sink |
+| tests.cpp:7:16:7:18 | ptr |
+| tests.cpp:11:5:11:18 | localMadSource |
+| tests.cpp:12:5:12:19 | remoteMadSource |
+| tests.cpp:13:5:13:14 | notASource |
+| tests.cpp:14:5:14:22 | localMadSourceVoid |
+| tests.cpp:15:5:15:25 | localMadSourceHasBody |
+| tests.cpp:16:6:16:28 | remoteMadSourceIndirect |
+| tests.cpp:17:7:17:35 | remoteMadSourceDoubleIndirect |
+| tests.cpp:18:6:18:32 | remoteMadSourceIndirectArg0 |
+| tests.cpp:18:39:18:39 | x |
+| tests.cpp:18:47:18:47 | y |
+| tests.cpp:19:6:19:32 | remoteMadSourceIndirectArg1 |
+| tests.cpp:19:39:19:39 | x |
+| tests.cpp:19:47:19:47 | y |
+| tests.cpp:20:5:20:22 | remoteMadSourceVar |
+| tests.cpp:21:6:21:31 | remoteMadSourceVarIndirect |
+| tests.cpp:24:6:24:28 | namespaceLocalMadSource |
+| tests.cpp:25:6:25:31 | namespaceLocalMadSourceVar |
+| tests.cpp:28:7:28:30 | namespace2LocalMadSource |
+| tests.cpp:31:6:31:19 | localMadSource |
+| tests.cpp:33:5:33:27 | namespaceLocalMadSource |
+| tests.cpp:35:6:35:17 | test_sources |
+| tests.cpp:50:6:50:6 | v |
+| tests.cpp:51:7:51:16 | v_indirect |
+| tests.cpp:52:6:52:13 | v_direct |
+| tests.cpp:63:6:63:6 | a |
+| tests.cpp:63:9:63:9 | b |
+| tests.cpp:63:12:63:12 | c |
+| tests.cpp:63:15:63:15 | d |
+| tests.cpp:75:6:75:6 | e |
+| tests.cpp:85:6:85:26 | remoteMadSourceParam0 |
+| tests.cpp:85:32:85:32 | x |
+| tests.cpp:92:6:92:16 | madSinkArg0 |
+| tests.cpp:92:22:92:22 | x |
+| tests.cpp:93:6:93:13 | notASink |
+| tests.cpp:93:19:93:19 | x |
+| tests.cpp:94:6:94:16 | madSinkArg1 |
+| tests.cpp:94:22:94:22 | x |
+| tests.cpp:94:29:94:29 | y |
+| tests.cpp:95:6:95:17 | madSinkArg01 |
+| tests.cpp:95:23:95:23 | x |
+| tests.cpp:95:30:95:30 | y |
+| tests.cpp:95:37:95:37 | z |
+| tests.cpp:96:6:96:17 | madSinkArg02 |
+| tests.cpp:96:23:96:23 | x |
+| tests.cpp:96:30:96:30 | y |
+| tests.cpp:96:37:96:37 | z |
+| tests.cpp:97:6:97:24 | madSinkIndirectArg0 |
+| tests.cpp:97:31:97:31 | x |
+| tests.cpp:98:6:98:30 | madSinkDoubleIndirectArg0 |
+| tests.cpp:98:38:98:38 | x |
+| tests.cpp:99:5:99:14 | madSinkVar |
+| tests.cpp:100:6:100:23 | madSinkVarIndirect |
+| tests.cpp:102:6:102:15 | test_sinks |
+| tests.cpp:116:6:116:6 | a |
+| tests.cpp:117:7:117:11 | a_ptr |
+| tests.cpp:132:6:132:18 | madSinkParam0 |
+| tests.cpp:132:24:132:24 | x |
+| tests.cpp:138:8:138:8 | operator= |
+| tests.cpp:138:8:138:8 | operator= |
+| tests.cpp:138:8:138:18 | MyContainer |
+| tests.cpp:139:6:139:10 | value |
+| tests.cpp:140:6:140:11 | value2 |
+| tests.cpp:141:7:141:9 | ptr |
+| tests.cpp:144:5:144:19 | madArg0ToReturn |
+| tests.cpp:144:25:144:25 | x |
+| tests.cpp:145:6:145:28 | madArg0ToReturnIndirect |
+| tests.cpp:145:34:145:34 | x |
+| tests.cpp:146:5:146:15 | notASummary |
+| tests.cpp:146:21:146:21 | x |
+| tests.cpp:147:5:147:28 | madArg0ToReturnValueFlow |
+| tests.cpp:147:34:147:34 | x |
+| tests.cpp:148:5:148:27 | madArg0IndirectToReturn |
+| tests.cpp:148:34:148:34 | x |
+| tests.cpp:149:5:149:33 | madArg0DoubleIndirectToReturn |
+| tests.cpp:149:41:149:41 | x |
+| tests.cpp:150:5:150:30 | madArg0NotIndirectToReturn |
+| tests.cpp:150:37:150:37 | x |
+| tests.cpp:151:6:151:26 | madArg0ToArg1Indirect |
+| tests.cpp:151:32:151:32 | x |
+| tests.cpp:151:40:151:40 | y |
+| tests.cpp:152:6:152:34 | madArg0IndirectToArg1Indirect |
+| tests.cpp:152:47:152:47 | x |
+| tests.cpp:152:55:152:55 | y |
+| tests.cpp:153:5:153:18 | madArgsComplex |
+| tests.cpp:153:25:153:25 | a |
+| tests.cpp:153:33:153:33 | b |
+| tests.cpp:153:40:153:40 | c |
+| tests.cpp:153:47:153:47 | d |
+| tests.cpp:154:5:154:14 | madArgsAny |
+| tests.cpp:154:20:154:20 | a |
+| tests.cpp:154:28:154:28 | b |
+| tests.cpp:155:5:155:28 | madAndImplementedComplex |
+| tests.cpp:155:34:155:34 | a |
+| tests.cpp:155:41:155:41 | b |
+| tests.cpp:155:48:155:48 | c |
+| tests.cpp:160:5:160:24 | madArg0FieldToReturn |
+| tests.cpp:160:38:160:39 | mc |
+| tests.cpp:161:5:161:32 | madArg0IndirectFieldToReturn |
+| tests.cpp:161:47:161:48 | mc |
+| tests.cpp:162:5:162:32 | madArg0FieldIndirectToReturn |
+| tests.cpp:162:46:162:47 | mc |
+| tests.cpp:163:13:163:32 | madArg0ToReturnField |
+| tests.cpp:163:38:163:38 | x |
+| tests.cpp:164:14:164:41 | madArg0ToReturnIndirectField |
+| tests.cpp:164:47:164:47 | x |
+| tests.cpp:165:13:165:40 | madArg0ToReturnFieldIndirect |
+| tests.cpp:165:46:165:46 | x |
+| tests.cpp:167:13:167:30 | madFieldToFieldVar |
+| tests.cpp:168:13:168:38 | madFieldToIndirectFieldVar |
+| tests.cpp:169:14:169:39 | madIndirectFieldToFieldVar |
+| tests.cpp:171:6:171:19 | test_summaries |
+| tests.cpp:174:6:174:6 | a |
+| tests.cpp:174:9:174:9 | b |
+| tests.cpp:174:12:174:12 | c |
+| tests.cpp:174:15:174:15 | d |
+| tests.cpp:174:18:174:18 | e |
+| tests.cpp:175:7:175:11 | a_ptr |
+| tests.cpp:218:14:218:16 | mc1 |
+| tests.cpp:218:19:218:21 | mc2 |
+| tests.cpp:237:15:237:18 | rtn1 |
+| tests.cpp:240:14:240:17 | rtn2 |
+| tests.cpp:241:7:241:14 | rtn2_ptr |
+| tests.cpp:267:7:267:7 | operator= |
+| tests.cpp:267:7:267:7 | operator= |
+| tests.cpp:267:7:267:13 | MyClass |
+| tests.cpp:270:6:270:26 | memberRemoteMadSource |
+| tests.cpp:271:7:271:39 | memberRemoteMadSourceIndirectArg0 |
+| tests.cpp:271:46:271:46 | x |
+| tests.cpp:272:6:272:29 | memberRemoteMadSourceVar |
+| tests.cpp:273:7:273:21 | qualifierSource |
+| tests.cpp:274:7:274:26 | qualifierFieldSource |
+| tests.cpp:277:7:277:23 | memberMadSinkArg0 |
+| tests.cpp:277:29:277:29 | x |
+| tests.cpp:278:6:278:21 | memberMadSinkVar |
+| tests.cpp:279:7:279:19 | qualifierSink |
+| tests.cpp:280:7:280:23 | qualifierArg0Sink |
+| tests.cpp:280:29:280:29 | x |
+| tests.cpp:281:7:281:24 | qualifierFieldSink |
+| tests.cpp:284:7:284:19 | madArg0ToSelf |
+| tests.cpp:284:25:284:25 | x |
+| tests.cpp:285:6:285:20 | madSelfToReturn |
+| tests.cpp:286:6:286:16 | notASummary |
+| tests.cpp:287:7:287:20 | madArg0ToField |
+| tests.cpp:287:26:287:26 | x |
+| tests.cpp:288:6:288:21 | madFieldToReturn |
+| tests.cpp:290:6:290:8 | val |
+| tests.cpp:293:7:293:7 | MyDerivedClass |
+| tests.cpp:293:7:293:7 | operator= |
+| tests.cpp:293:7:293:7 | operator= |
+| tests.cpp:293:7:293:20 | MyDerivedClass |
+| tests.cpp:295:6:295:28 | subtypeRemoteMadSource1 |
+| tests.cpp:296:6:296:21 | subtypeNonSource |
+| tests.cpp:297:6:297:28 | subtypeRemoteMadSource2 |
+| tests.cpp:300:9:300:15 | source2 |
+| tests.cpp:301:6:301:9 | sink |
+| tests.cpp:301:19:301:20 | mc |
+| tests.cpp:304:8:304:8 | operator= |
+| tests.cpp:304:8:304:8 | operator= |
+| tests.cpp:304:8:304:14 | MyClass |
+| tests.cpp:307:8:307:33 | namespaceMemberMadSinkArg0 |
+| tests.cpp:307:39:307:39 | x |
+| tests.cpp:308:15:308:46 | namespaceStaticMemberMadSinkArg0 |
+| tests.cpp:308:52:308:52 | x |
+| tests.cpp:309:7:309:31 | namespaceMemberMadSinkVar |
+| tests.cpp:310:14:310:44 | namespaceStaticMemberMadSinkVar |
+| tests.cpp:313:7:313:30 | namespaceMadSelfToReturn |
+| tests.cpp:317:22:317:28 | source3 |
+| tests.cpp:319:6:319:23 | test_class_members |
+| tests.cpp:320:10:320:11 | mc |
+| tests.cpp:320:14:320:16 | mc2 |
+| tests.cpp:320:19:320:21 | mc3 |
+| tests.cpp:320:24:320:26 | mc4 |
+| tests.cpp:320:29:320:31 | mc5 |
+| tests.cpp:320:34:320:36 | mc6 |
+| tests.cpp:320:39:320:41 | mc7 |
+| tests.cpp:320:44:320:46 | mc8 |
+| tests.cpp:320:49:320:51 | mc9 |
+| tests.cpp:320:54:320:57 | mc10 |
+| tests.cpp:320:60:320:63 | mc11 |
+| tests.cpp:321:11:321:13 | ptr |
+| tests.cpp:321:17:321:23 | mc4_ptr |
+| tests.cpp:322:17:322:19 | mdc |
+| tests.cpp:323:23:323:25 | mnc |
+| tests.cpp:323:28:323:31 | mnc2 |
+| tests.cpp:324:24:324:31 | mnc2_ptr |
+| tests.cpp:330:6:330:6 | a |
+| tests.cpp:429:8:429:8 | operator= |
+| tests.cpp:429:8:429:8 | operator= |
+| tests.cpp:429:8:429:14 | intPair |
+| tests.cpp:430:6:430:10 | first |
+| tests.cpp:431:6:431:11 | second |
+| tests.cpp:434:5:434:29 | madCallArg0ReturnToReturn |
+| tests.cpp:434:37:434:43 | fun_ptr |
+| tests.cpp:435:9:435:38 | madCallArg0ReturnToReturnFirst |
+| tests.cpp:435:46:435:52 | fun_ptr |
+| tests.cpp:436:6:436:25 | madCallArg0WithValue |
+| tests.cpp:436:34:436:40 | fun_ptr |
+| tests.cpp:436:53:436:57 | value |
+| tests.cpp:437:5:437:36 | madCallReturnValueIgnoreFunction |
+| tests.cpp:437:45:437:51 | fun_ptr |
+| tests.cpp:437:64:437:68 | value |
+| tests.cpp:439:5:439:14 | getTainted |
+| tests.cpp:440:6:440:13 | useValue |
+| tests.cpp:440:19:440:19 | x |
+| tests.cpp:441:6:441:17 | dontUseValue |
+| tests.cpp:441:23:441:23 | x |
+| tests.cpp:443:6:443:27 | test_function_pointers |
+| tests.cpp:456:19:456:19 | X |
+| tests.cpp:457:8:457:35 | StructWithTypedefInParameter |
+| tests.cpp:457:8:457:35 | StructWithTypedefInParameter |
+| tests.cpp:458:12:458:15 | Type |
+| tests.cpp:459:5:459:31 | parameter_ref_to_return_ref |
+| tests.cpp:459:5:459:31 | parameter_ref_to_return_ref |
+| tests.cpp:459:45:459:45 | x |
+| tests.cpp:459:45:459:45 | x |
+| tests.cpp:462:6:462:37 | test_parameter_ref_to_return_ref |
+| tests.cpp:463:6:463:6 | x |
+| tests.cpp:464:36:464:36 | s |
+| tests.cpp:465:6:465:6 | y |
+| tests.cpp:469:7:469:9 | INT |
+| tests.cpp:471:5:471:17 | receive_array |
+| tests.cpp:471:23:471:23 | a |
+| tests.cpp:473:6:473:23 | test_receive_array |
+| tests.cpp:474:6:474:6 | x |
+| tests.cpp:475:6:475:10 | array |
+| tests.cpp:476:6:476:6 | y |
+flowSummaryNode
| tests.cpp:144:5:144:19 | [summary param] 0 in madArg0ToReturn | ParameterNode | madArg0ToReturn | madArg0ToReturn |
| tests.cpp:144:5:144:19 | [summary] to write: ReturnValue in madArg0ToReturn | ReturnNode | madArg0ToReturn | madArg0ToReturn |
| tests.cpp:145:6:145:28 | [summary param] 0 in madArg0ToReturnIndirect | ParameterNode | madArg0ToReturnIndirect | madArg0ToReturnIndirect |
diff --git a/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.ext.yml b/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.ext.yml
new file mode 100644
index 00000000000..95261223473
--- /dev/null
+++ b/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.ext.yml
@@ -0,0 +1,84 @@
+extensions:
+ - addsTo:
+ pack: codeql/cpp-all
+ extensible: sourceModel
+ data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
+ - ["", "", False, "localMadSource", "", "", "ReturnValue", "local", "manual"]
+ - ["", "", False, "remoteMadSource", "", "", "ReturnValue", "remote", "manual"]
+ - ["", "", False, "localMadSourceVoid", "", "", "ReturnValue", "local", "manual"]
+ - ["", "", False, "localMadSourceHasBody", "", "", "ReturnValue", "local", "manual"]
+ - ["", "", False, "remoteMadSourceIndirect", "", "", "ReturnValue[*]", "remote", "manual"]
+ - ["", "", False, "remoteMadSourceDoubleIndirect", "", "", "ReturnValue[**]", "remote", "manual"]
+ - ["", "", False, "remoteMadSourceIndirectArg0", "", "", "Argument[*0]", "remote", "manual"]
+ - ["", "", False, "remoteMadSourceIndirectArg1", "", "", "Argument[*1]", "remote", "manual"]
+ - ["", "", False, "remoteMadSourceVar", "", "", "", "remote", "manual"]
+ - ["", "", False, "remoteMadSourceVarIndirect", "", "", "*", "remote", "manual"] # we can't express this source/sink correctly at present, "*" is not a valid access path
+ - ["", "", False, "remoteMadSourceParam0", "", "", "Parameter[0]", "remote", "manual"]
+ - ["MyNamespace", "", False, "namespaceLocalMadSource", "", "", "ReturnValue", "local", "manual"]
+ - ["MyNamespace", "", False, "namespaceLocalMadSourceVar", "", "", "", "local", "manual"]
+ - ["MyNamespace::MyNamespace2", "", False, "namespace2LocalMadSource", "", "", "ReturnValue", "local", "manual"]
+ - ["", "MyClass", True, "memberRemoteMadSource", "", "", "ReturnValue", "remote", "manual"]
+ - ["", "MyClass", True, "memberRemoteMadSourceIndirectArg0", "", "", "Argument[*0]", "remote", "manual"]
+ - ["", "MyClass", True, "memberRemoteMadSourceVar", "", "", "", "remote", "manual"]
+ - ["", "MyClass", True, "subtypeRemoteMadSource1", "", "", "ReturnValue", "remote", "manual"]
+ - ["", "MyClass", False, "subtypeNonSource", "", "", "ReturnValue", "remote", "manual"] # the tests define this in MyDerivedClass, so it should *not* be recongized as a source
+ - ["", "MyClass", True, "qualifierSource", "", "", "Argument[-1]", "remote", "manual"]
+ - ["", "MyClass", True, "qualifierFieldSource", "", "", "Argument[-1].val", "remote", "manual"]
+ - ["", "MyDerivedClass", False, "subtypeRemoteMadSource2", "", "", "ReturnValue", "remote", "manual"]
+ - addsTo:
+ pack: codeql/cpp-all
+ extensible: sinkModel
+ data: # namespace, type, subtypes, name, signature, ext, input, kind, provenance
+ - ["", "", False, "madSinkArg0", "", "", "Argument[0]", "test-sink", "manual"]
+ - ["", "", False, "madSinkArg1", "", "", "Argument[1]", "test-sink", "manual"]
+ - ["", "", False, "madSinkArg01", "", "", "Argument[0..1]", "test-sink", "manual"]
+ - ["", "", False, "madSinkArg02", "", "", "Argument[0,2]", "test-sink", "manual"]
+ - ["", "", False, "madSinkIndirectArg0", "", "", "Argument[*0]", "test-sink", "manual"]
+ - ["", "", False, "madSinkDoubleIndirectArg0", "", "", "Argument[**0]", "test-sink", "manual"]
+ - ["", "", False, "madSinkVar", "", "", "", "test-sink", "manual"]
+ - ["", "", False, "madSinkVarIndirect", "", "", "*", "test-sink", "manual"] # we can't express this source/sink correctly at present, "*" is not a valid access path
+ - ["", "", False, "madSinkParam0", "", "", "Parameter[0]", "test-sink", "manual"]
+ - ["", "MyClass", True, "memberMadSinkArg0", "", "", "Argument[0]", "test-sink", "manual"]
+ - ["", "MyClass", True, "memberMadSinkVar", "", "", "", "test-sink", "manual"]
+ - ["", "MyClass", True, "qualifierSink", "", "", "Argument[-1]", "test-sink", "manual"]
+ - ["", "MyClass", True, "qualifierArg0Sink", "", "", "Argument[-1..0]", "test-sink", "manual"]
+ - ["", "MyClass", True, "qualifierFieldSink", "", "", "Argument[-1].val", "test-sink", "manual"]
+ - ["MyNamespace", "MyClass", True, "namespaceMemberMadSinkArg0", "", "", "Argument[0]", "test-sink", "manual"]
+ - ["MyNamespace", "MyClass", True, "namespaceStaticMemberMadSinkArg0", "", "", "Argument[0]", "test-sink", "manual"]
+ - ["MyNamespace", "MyClass", True, "namespaceMemberMadSinkVar", "", "", "", "test-sink", "manual"]
+ - ["MyNamespace", "MyClass", True, "namespaceStaticMemberMadSinkVar", "", "", "", "test-sink", "manual"]
+ - addsTo:
+ pack: codeql/cpp-all
+ extensible: summaryModel
+ data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
+ - ["", "", False, "madArg0ToReturn", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
+ - ["", "", False, "madArg0ToReturnIndirect", "", "", "Argument[0]", "ReturnValue[*]", "taint", "manual"]
+ - ["", "", False, "madArg0ToReturnValueFlow", "", "", "Argument[0]", "ReturnValue", "value", "manual"]
+ - ["", "", False, "madArg0IndirectToReturn", "", "", "Argument[*0]", "ReturnValue", "taint", "manual"]
+ - ["", "", False, "madArg0DoubleIndirectToReturn", "", "", "Argument[**0]", "ReturnValue", "taint", "manual"]
+ - ["", "", False, "madArg0NotIndirectToReturn", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
+ - ["", "", False, "madArg0ToArg1Indirect", "", "", "Argument[0]", "Argument[*1]", "taint", "manual"]
+ - ["", "", False, "madArg0IndirectToArg1Indirect", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"]
+ - ["", "", False, "madArgsComplex", "", "", "Argument[*0..1,2]", "ReturnValue", "taint", "manual"]
+ - ["", "", False, "madAndImplementedComplex", "", "", "Argument[2]", "ReturnValue", "taint", "manual"]
+ - ["", "", False, "madArgsAny", "", "", "Argument", "ReturnValue", "taint", "manual"] # we can't express this source/sink correctly at present, "Argument" is not a valid input
+ - ["", "", False, "madArg0FieldToReturn", "", "", "Argument[0].Field[value]", "ReturnValue", "taint", "manual"]
+ - ["", "", False, "madArg0IndirectFieldToReturn", "", "", "Argument[*0].Field[value]", "ReturnValue", "taint", "manual"]
+ - ["", "", False, "madArg0FieldIndirectToReturn", "", "", "Argument[0].Field[*ptr]", "ReturnValue", "taint", "manual"]
+ - ["", "", False, "madArg0ToReturnField", "", "", "Argument[0]", "ReturnValue.Field[value]", "taint", "manual"]
+ - ["", "", False, "madArg0ToReturnIndirectField", "", "", "Argument[0]", "ReturnValue[*].Field[value]", "taint", "manual"]
+ - ["", "", False, "madArg0ToReturnFieldIndirect", "", "", "Argument[0]", "ReturnValue.Field[*ptr]", "taint", "manual"]
+ - ["", "", False, "madFieldToFieldVar", "", "", "Field[value]", "Field[value2]", "taint", "manual"] # we can't express this source/sink correctly at present, "Field[value]" is not a valid input and "Field[value2]" is not a valid output
+ - ["", "", False, "madFieldToIndirectFieldVar", "", "", "Field[value]", "Field[*ptr]", "taint", "manual"] # we can't express this source/sink correctly at present, "Field[value]" is not a valid input and "Field[*ptr]" is not a valid output
+ - ["", "", False, "madIndirectFieldToFieldVar", "", "", "Field[value]", "Field[value2]", "taint", "manual"] # we can't express this source/sink correctly at present, "Field[value]" is not a valid input and "Field[value2]" is not a valid output
+ - ["", "MyClass", True, "madArg0ToSelf", "", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
+ - ["", "MyClass", True, "madSelfToReturn", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
+ - ["", "MyClass", True, "madArg0ToField", "", "", "Argument[0]", "Argument[-1].Field[val]", "taint", "manual"]
+ - ["", "MyClass", True, "madFieldToReturn", "", "", "Argument[-1].Field[val]", "ReturnValue", "taint", "manual"]
+ - ["MyNamespace", "MyClass", True, "namespaceMadSelfToReturn", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
+ - ["", "", False, "madCallArg0ReturnToReturn", "", "", "Argument[0].ReturnValue", "ReturnValue", "value", "manual"]
+ - ["", "", False, "madCallArg0ReturnToReturnFirst", "", "", "Argument[0].ReturnValue", "ReturnValue.Field[first]", "value", "manual"]
+ - ["", "", False, "madCallArg0WithValue", "", "", "Argument[1]", "Argument[0].Parameter[0]", "value", "manual"]
+ - ["", "", False, "madCallReturnValueIgnoreFunction", "", "", "Argument[1]", "ReturnValue", "value", "manual"]
+ - ["", "StructWithTypedefInParameter", True, "parameter_ref_to_return_ref", "(const T &)", "", "Argument[*0]", "ReturnValue[*]", "value", "manual"]
+ - ["", "", False, "receive_array", "(int[20])", "", "Argument[*0]", "ReturnValue", "taint", "manual"]
diff --git a/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.ql b/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.ql
new file mode 100644
index 00000000000..4b89b7da409
--- /dev/null
+++ b/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.ql
@@ -0,0 +1,74 @@
+import semmle.code.cpp.ir.dataflow.internal.DataFlowImplConsistency::Consistency
+import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
+import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
+import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
+import semmle.code.cpp.security.FlowSources
+import utils.test.dataflow.FlowTestCommon
+
+module InterpretElementTest implements TestSig {
+ string getARelevantTag() { result = "interpretElement" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ exists(Element e |
+ e = interpretElement(_, _, _, _, _, _) and
+ location = e.getLocation() and
+ element = e.toString() and
+ tag = "interpretElement" and
+ value = ""
+ )
+ }
+}
+
+query predicate summaryCalls(SummaryCall c) { any() }
+
+query predicate summarizedCallables(SummarizedCallable c) { any() }
+
+query predicate sourceCallables(SourceCallable c) { c.getLocation().getFile().toString() != "" }
+
+module IRTest {
+ private import semmle.code.cpp.ir.IR
+ private import semmle.code.cpp.ir.dataflow.TaintTracking
+
+ /** Common data flow configuration to be used by tests. */
+ module TestAllocationConfig implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node source) {
+ source instanceof FlowSource
+ or
+ source.asExpr().(FunctionCall).getTarget().getName() =
+ ["source", "source2", "source3", "sourcePtr"]
+ or
+ source.asIndirectExpr(1).(FunctionCall).getTarget().getName() = "sourceIndirect"
+ }
+
+ predicate isSink(DataFlow::Node sink) {
+ sinkNode(sink, "test-sink")
+ or
+ exists(FunctionCall call |
+ call.getTarget().getName() = "sink" and
+ sink.asExpr() = call.getAnArgument()
+ )
+ }
+ }
+
+ module IRFlow = TaintTracking::Global;
+}
+
+import MakeTest, InterpretElementTest>>
+
+string describe(DataFlow::Node n) {
+ n instanceof ParameterNode and result = "ParameterNode"
+ or
+ n instanceof PostUpdateNode and result = "PostUpdateNode"
+ or
+ n instanceof ArgumentNode and result = "ArgumentNode"
+ or
+ n instanceof ReturnNode and result = "ReturnNode"
+ or
+ n instanceof OutNode and result = "OutNode"
+}
+
+query predicate flowSummaryNode(FlowSummaryNode n, string str1, string str2, string str3) {
+ str1 = concat(describe(n), ", ") and
+ str2 = concat(n.getSummarizedCallable().toString(), ", ") and
+ str3 = concat(n.getEnclosingCallable().toString(), ", ")
+}
diff --git a/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.qll b/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.qll
deleted file mode 100644
index e8d1393fc4a..00000000000
--- a/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.qll
+++ /dev/null
@@ -1,105 +0,0 @@
-import semmle.code.cpp.security.FlowSources
-
-/**
- * Models-as-data source models for this test.
- */
-private class TestSources extends SourceModelCsv {
- override predicate row(string row) {
- row =
- [
- ";;false;localMadSource;;;ReturnValue;local",
- ";;false;remoteMadSource;;;ReturnValue;remote",
- ";;false;localMadSourceVoid;;;ReturnValue;local",
- ";;false;localMadSourceHasBody;;;ReturnValue;local",
- ";;false;remoteMadSourceIndirect;;;ReturnValue[*];remote",
- ";;false;remoteMadSourceDoubleIndirect;;;ReturnValue[**];remote",
- ";;false;remoteMadSourceIndirectArg0;;;Argument[*0];remote",
- ";;false;remoteMadSourceIndirectArg1;;;Argument[*1];remote",
- ";;false;remoteMadSourceVar;;;;remote",
- ";;false;remoteMadSourceVarIndirect;;;*;remote", // not correctly expressed
- ";;false;remoteMadSourceParam0;;;Parameter[0];remote",
- "MyNamespace;;false;namespaceLocalMadSource;;;ReturnValue;local",
- "MyNamespace;;false;namespaceLocalMadSourceVar;;;;local",
- "MyNamespace::MyNamespace2;;false;namespace2LocalMadSource;;;ReturnValue;local",
- ";MyClass;true;memberRemoteMadSource;;;ReturnValue;remote",
- ";MyClass;true;memberRemoteMadSourceIndirectArg0;;;Argument[*0];remote",
- ";MyClass;true;memberRemoteMadSourceVar;;;;remote",
- ";MyClass;true;subtypeRemoteMadSource1;;;ReturnValue;remote",
- ";MyClass;false;subtypeNonSource;;;ReturnValue;remote", // the tests define this in MyDerivedClass, so it should *not* be recongized as a source
- ";MyClass;true;qualifierSource;;;Argument[-1];remote",
- ";MyClass;true;qualifierFieldSource;;;Argument[-1].val;remote",
- ";MyDerivedClass;false;subtypeRemoteMadSource2;;;ReturnValue;remote",
- ]
- }
-}
-
-/**
- * Models-as-data sink models for this test.
- */
-private class TestSinks extends SinkModelCsv {
- override predicate row(string row) {
- row =
- [
- ";;false;madSinkArg0;;;Argument[0];test-sink",
- ";;false;madSinkArg1;;;Argument[1];test-sink",
- ";;false;madSinkArg01;;;Argument[0..1];test-sink",
- ";;false;madSinkArg02;;;Argument[0,2];test-sink",
- ";;false;madSinkIndirectArg0;;;Argument[*0];test-sink",
- ";;false;madSinkDoubleIndirectArg0;;;Argument[**0];test-sink",
- ";;false;madSinkVar;;;;test-sink",
- ";;false;madSinkVarIndirect;;;*;test-sink", // not correctly expressed
- ";;false;madSinkParam0;;;Parameter[0];test-sink",
- ";MyClass;true;memberMadSinkArg0;;;Argument[0];test-sink",
- ";MyClass;true;memberMadSinkVar;;;;test-sink",
- ";MyClass;true;qualifierSink;;;Argument[-1];test-sink",
- ";MyClass;true;qualifierArg0Sink;;;Argument[-1..0];test-sink",
- ";MyClass;true;qualifierFieldSink;;;Argument[-1].val;test-sink",
- "MyNamespace;MyClass;true;namespaceMemberMadSinkArg0;;;Argument[0];test-sink",
- "MyNamespace;MyClass;true;namespaceStaticMemberMadSinkArg0;;;Argument[0];test-sink",
- "MyNamespace;MyClass;true;namespaceMemberMadSinkVar;;;;test-sink",
- "MyNamespace;MyClass;true;namespaceStaticMemberMadSinkVar;;;;test-sink",
- ]
- }
-}
-
-/**
- * Models-as-data summary models for this test.
- */
-private class TestSummaries extends SummaryModelCsv {
- override predicate row(string row) {
- row =
- [
- ";;false;madArg0ToReturn;;;Argument[0];ReturnValue;taint",
- ";;false;madArg0ToReturnIndirect;;;Argument[0];ReturnValue[*];taint",
- ";;false;madArg0ToReturnValueFlow;;;Argument[0];ReturnValue;value",
- ";;false;madArg0IndirectToReturn;;;Argument[*0];ReturnValue;taint",
- ";;false;madArg0DoubleIndirectToReturn;;;Argument[**0];ReturnValue;taint",
- ";;false;madArg0NotIndirectToReturn;;;Argument[0];ReturnValue;taint",
- ";;false;madArg0ToArg1Indirect;;;Argument[0];Argument[*1];taint",
- ";;false;madArg0IndirectToArg1Indirect;;;Argument[*0];Argument[*1];taint",
- ";;false;madArgsComplex;;;Argument[*0..1,2];ReturnValue;taint",
- ";;false;madAndImplementedComplex;;;Argument[2];ReturnValue;taint",
- ";;false;madArgsAny;;;Argument;ReturnValue;taint", // (syntax not supported)
- ";;false;madArg0FieldToReturn;;;Argument[0].Field[value];ReturnValue;taint",
- ";;false;madArg0IndirectFieldToReturn;;;Argument[*0].Field[value];ReturnValue;taint",
- ";;false;madArg0FieldIndirectToReturn;;;Argument[0].Field[*ptr];ReturnValue;taint",
- ";;false;madArg0ToReturnField;;;Argument[0];ReturnValue.Field[value];taint",
- ";;false;madArg0ToReturnIndirectField;;;Argument[0];ReturnValue[*].Field[value];taint",
- ";;false;madArg0ToReturnFieldIndirect;;;Argument[0];ReturnValue.Field[*ptr];taint",
- ";;false;madFieldToFieldVar;;;Field[value];Field[value2];taint",
- ";;false;madFieldToIndirectFieldVar;;;Field[value];Field[*ptr];taint",
- ";;false;madIndirectFieldToFieldVar;;;;Field[value];Field[value2];taint", // not correctly expressed
- ";MyClass;true;madArg0ToSelf;;;Argument[0];Argument[-1];taint",
- ";MyClass;true;madSelfToReturn;;;Argument[-1];ReturnValue;taint",
- ";MyClass;true;madArg0ToField;;;Argument[0];Argument[-1].Field[val];taint",
- ";MyClass;true;madFieldToReturn;;;Argument[-1].Field[val];ReturnValue;taint",
- "MyNamespace;MyClass;true;namespaceMadSelfToReturn;;;Argument[-1];ReturnValue;taint",
- ";;false;madCallArg0ReturnToReturn;;;Argument[0].ReturnValue;ReturnValue;value",
- ";;false;madCallArg0ReturnToReturnFirst;;;Argument[0].ReturnValue;ReturnValue.Field[first];value",
- ";;false;madCallArg0WithValue;;;Argument[1];Argument[0].Parameter[0];value",
- ";;false;madCallReturnValueIgnoreFunction;;;Argument[1];ReturnValue;value",
- ";StructWithTypedefInParameter;true;parameter_ref_to_return_ref;(const T &);;Argument[*0];ReturnValue[*];value",
- ";;false;receive_array;(int[20]);;Argument[*0];ReturnValue;taint"
- ]
- }
-}
diff --git a/cpp/ql/test/library-tests/dataflow/models-as-data/tests.cpp b/cpp/ql/test/library-tests/dataflow/models-as-data/tests.cpp
index 92397bc91c3..cb2bf965083 100644
--- a/cpp/ql/test/library-tests/dataflow/models-as-data/tests.cpp
+++ b/cpp/ql/test/library-tests/dataflow/models-as-data/tests.cpp
@@ -75,7 +75,7 @@ void test_sources() {
int e = localMadSource();
sink(e); // $ ir
- sink(MyNamespace::namespaceLocalMadSource()); // $: ir
+ sink(MyNamespace::namespaceLocalMadSource()); // $ ir
sink(MyNamespace::namespaceLocalMadSourceVar); // $ ir
sink(MyNamespace::MyNamespace2::namespace2LocalMadSource()); // $ ir
sink(MyNamespace::localMadSource()); // $ (the MyNamespace version of this function is not a source)
@@ -475,4 +475,4 @@ void test_receive_array() {
int array[10] = {x};
int y = receive_array(array);
sink(y); // $ ir
-}
\ No newline at end of file
+}
diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp
index 70d5b8c7b00..fa32e192239 100644
--- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp
+++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp
@@ -450,7 +450,7 @@ void test_qualifiers()
b.member = source();
sink(b); // $ ir MISSING: ast
sink(b.member); // $ ast,ir
- sink(b.getMember()); // $ MISSING: ir ast
+ sink(b.getMember()); // $ MISSING: ir ast
c = new MyClass2(0);
@@ -865,4 +865,4 @@ void test_iconv(size_t size) {
size_t size_out;
iconv(0, &s, &size, &p, &size_out);
sink(*p); // $ ast,ir
-}
\ No newline at end of file
+}
diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
index 45666a3b50b..c3e46114edf 100644
--- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
+++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
@@ -277,7 +277,7 @@ bad_asts.cpp:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const Point &
# 19| :
-# 19| getInitializer(0): [ConstructorFieldInit] constructor init of field x
+# 19| getInitializer(0): [ConstructorDirectFieldInit] constructor init of field x
# 19| Type = [IntType] int
# 19| ValueCategory = prvalue
# 19| getExpr(): [ReferenceFieldAccess] x
@@ -289,7 +289,7 @@ bad_asts.cpp:
# 19| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 19| Type = [SpecifiedType] const Point
# 19| ValueCategory = lvalue
-# 19| getInitializer(1): [ConstructorFieldInit] constructor init of field y
+# 19| getInitializer(1): [ConstructorDirectFieldInit] constructor init of field y
# 19| Type = [IntType] int
# 19| ValueCategory = prvalue
# 19| getExpr(): [ReferenceFieldAccess] y
@@ -8986,20 +8986,20 @@ ir.cpp:
# 658| [Constructor] void C::C()
# 658| :
# 658| :
-# 659| getInitializer(0): [ConstructorFieldInit] constructor init of field m_a
+# 659| getInitializer(0): [ConstructorDirectFieldInit] constructor init of field m_a
# 659| Type = [IntType] int
# 659| ValueCategory = prvalue
# 659| getExpr(): [Literal] 1
# 659| Type = [IntType] int
# 659| Value = [Literal] 1
# 659| ValueCategory = prvalue
-# 663| getInitializer(1): [ConstructorFieldInit] constructor init of field m_b
+# 663| getInitializer(1): [ConstructorDirectFieldInit] constructor init of field m_b
# 663| Type = [Struct] String
# 663| ValueCategory = prvalue
# 663| getExpr(): [ConstructorCall] call to String
# 663| Type = [VoidType] void
# 663| ValueCategory = prvalue
-# 660| getInitializer(2): [ConstructorFieldInit] constructor init of field m_c
+# 660| getInitializer(2): [ConstructorDirectFieldInit] constructor init of field m_c
# 660| Type = [PlainCharType] char
# 660| ValueCategory = prvalue
# 660| getExpr(): [Literal] 3
@@ -9011,14 +9011,14 @@ ir.cpp:
# 660| Type = [PlainCharType] char
# 660| Value = [CStyleCast] 3
# 660| ValueCategory = prvalue
-# 661| getInitializer(3): [ConstructorFieldInit] constructor init of field m_e
+# 661| getInitializer(3): [ConstructorDirectFieldInit] constructor init of field m_e
# 661| Type = [VoidPointerType] void *
# 661| ValueCategory = prvalue
# 661| getExpr(): [Literal] 0
# 661| Type = [VoidPointerType] void *
# 661| Value = [Literal] 0
# 661| ValueCategory = prvalue
-# 662| getInitializer(4): [ConstructorFieldInit] constructor init of field m_f
+# 662| getInitializer(4): [ConstructorDirectFieldInit] constructor init of field m_f
# 662| Type = [Struct] String
# 662| ValueCategory = prvalue
# 662| getExpr(): [ConstructorCall] call to String
@@ -9474,7 +9474,7 @@ ir.cpp:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const Base &
# 745| :
-# 745| getInitializer(0): [ConstructorFieldInit] constructor init of field base_s
+# 745| getInitializer(0): [ConstructorDirectFieldInit] constructor init of field base_s
# 745| Type = [Struct] String
# 745| ValueCategory = prvalue
# 745| getExpr(): [ConstructorCall] call to String
@@ -9485,7 +9485,7 @@ ir.cpp:
# 748| [Constructor] void Base::Base()
# 748| :
# 748| :
-# 748| getInitializer(0): [ConstructorFieldInit] constructor init of field base_s
+# 748| getInitializer(0): [ConstructorDirectFieldInit] constructor init of field base_s
# 748| Type = [Struct] String
# 748| ValueCategory = prvalue
# 748| getExpr(): [ConstructorCall] call to String
@@ -9593,7 +9593,7 @@ ir.cpp:
# 757| getInitializer(0): [ConstructorDirectInit] call to Base
# 757| Type = [VoidType] void
# 757| ValueCategory = prvalue
-# 757| getInitializer(1): [ConstructorFieldInit] constructor init of field middle_s
+# 757| getInitializer(1): [ConstructorDirectFieldInit] constructor init of field middle_s
# 757| Type = [Struct] String
# 757| ValueCategory = prvalue
# 757| getExpr(): [ConstructorCall] call to String
@@ -9704,7 +9704,7 @@ ir.cpp:
# 766| getInitializer(0): [ConstructorDirectInit] call to Middle
# 766| Type = [VoidType] void
# 766| ValueCategory = prvalue
-# 766| getInitializer(1): [ConstructorFieldInit] constructor init of field derived_s
+# 766| getInitializer(1): [ConstructorDirectFieldInit] constructor init of field derived_s
# 766| Type = [Struct] String
# 766| ValueCategory = prvalue
# 766| getExpr(): [ConstructorCall] call to String
@@ -9743,7 +9743,7 @@ ir.cpp:
# 775| getInitializer(0): [ConstructorVirtualInit] call to Base
# 775| Type = [VoidType] void
# 775| ValueCategory = prvalue
-# 775| getInitializer(1): [ConstructorFieldInit] constructor init of field middlevb1_s
+# 775| getInitializer(1): [ConstructorDirectFieldInit] constructor init of field middlevb1_s
# 775| Type = [Struct] String
# 775| ValueCategory = prvalue
# 775| getExpr(): [ConstructorCall] call to String
@@ -9782,7 +9782,7 @@ ir.cpp:
# 784| getInitializer(0): [ConstructorVirtualInit] call to Base
# 784| Type = [VoidType] void
# 784| ValueCategory = prvalue
-# 784| getInitializer(1): [ConstructorFieldInit] constructor init of field middlevb2_s
+# 784| getInitializer(1): [ConstructorDirectFieldInit] constructor init of field middlevb2_s
# 784| Type = [Struct] String
# 784| ValueCategory = prvalue
# 784| getExpr(): [ConstructorCall] call to String
@@ -9827,7 +9827,7 @@ ir.cpp:
# 793| getInitializer(2): [ConstructorDirectInit] call to MiddleVB2
# 793| Type = [VoidType] void
# 793| ValueCategory = prvalue
-# 793| getInitializer(3): [ConstructorFieldInit] constructor init of field derivedvb_s
+# 793| getInitializer(3): [ConstructorDirectFieldInit] constructor init of field derivedvb_s
# 793| Type = [Struct] String
# 793| ValueCategory = prvalue
# 793| getExpr(): [ConstructorCall] call to String
@@ -15190,7 +15190,7 @@ ir.cpp:
# 1508| getInitializer(0): [ConstructorInit] constructor init
# 1508| Type = [Struct] Inheritance_Test_B
# 1508| ValueCategory = prvalue
-# 1508| getInitializer(1): [ConstructorFieldInit] constructor init of field x
+# 1508| getInitializer(1): [ConstructorDirectFieldInit] constructor init of field x
# 1508| Type = [IntType] int
# 1508| ValueCategory = prvalue
# 1508| getExpr(): [Literal] 42
@@ -15414,7 +15414,7 @@ ir.cpp:
# 1533| [Constructor] void StructuredBindingDataMemberMemberStruct::StructuredBindingDataMemberMemberStruct()
# 1533| :
# 1533| :
-# 1533| getInitializer(0): [ConstructorFieldInit] constructor init of field x
+# 1533| getInitializer(0): [ConstructorDefaultFieldInit] constructor init of field x
# 1533| Type = [IntType] int
# 1533| ValueCategory = prvalue
# 1533| getEntryPoint(): [BlockStmt] { ... }
@@ -15434,25 +15434,25 @@ ir.cpp:
# 1537| [Constructor] void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct()
# 1537| :
# 1537| :
-# 1537| getInitializer(0): [ConstructorFieldInit] constructor init of field i
+# 1537| getInitializer(0): [ConstructorDefaultFieldInit] constructor init of field i
# 1537| Type = [IntType] int
# 1537| ValueCategory = prvalue
-# 1537| getInitializer(1): [ConstructorFieldInit] constructor init of field d
+# 1537| getInitializer(1): [ConstructorDefaultFieldInit] constructor init of field d
# 1537| Type = [DoubleType] double
# 1537| ValueCategory = prvalue
-# 1537| getInitializer(2): [ConstructorFieldInit] constructor init of field r
+# 1537| getInitializer(2): [ConstructorDefaultFieldInit] constructor init of field r
# 1537| Type = [LValueReferenceType] int &
# 1537| ValueCategory = prvalue
-# 1537| getInitializer(3): [ConstructorFieldInit] constructor init of field p
+# 1537| getInitializer(3): [ConstructorDefaultFieldInit] constructor init of field p
# 1537| Type = [IntPointerType] int *
# 1537| ValueCategory = prvalue
-# 1537| getInitializer(4): [ConstructorFieldInit] constructor init of field xs
+# 1537| getInitializer(4): [ConstructorDefaultFieldInit] constructor init of field xs
# 1537| Type = [CTypedefType,NestedTypedefType] ArrayType
# 1537| ValueCategory = prvalue
-# 1537| getInitializer(5): [ConstructorFieldInit] constructor init of field r_alt
+# 1537| getInitializer(5): [ConstructorDefaultFieldInit] constructor init of field r_alt
# 1537| Type = [CTypedefType,NestedTypedefType] RefType
# 1537| ValueCategory = prvalue
-# 1537| getInitializer(6): [ConstructorFieldInit] constructor init of field m
+# 1537| getInitializer(6): [ConstructorDirectFieldInit] constructor init of field m
# 1537| Type = [Struct] StructuredBindingDataMemberMemberStruct
# 1537| ValueCategory = prvalue
# 1537| getExpr(): [ConstructorCall] call to StructuredBindingDataMemberMemberStruct
@@ -15465,7 +15465,7 @@ ir.cpp:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1537| :
-# 1537| getInitializer(0): [ConstructorFieldInit] constructor init of field i
+# 1537| getInitializer(0): [ConstructorDirectFieldInit] constructor init of field i
# 1537| Type = [IntType] int
# 1537| ValueCategory = prvalue
# 1537| getExpr(): [ReferenceFieldAccess] i
@@ -15477,7 +15477,7 @@ ir.cpp:
# 1537| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1537| Type = [SpecifiedType] const StructuredBindingDataMemberStruct
# 1537| ValueCategory = lvalue
-# 1537| getInitializer(1): [ConstructorFieldInit] constructor init of field d
+# 1537| getInitializer(1): [ConstructorDirectFieldInit] constructor init of field d
# 1537| Type = [DoubleType] double
# 1537| ValueCategory = prvalue
# 1537| getExpr(): [ReferenceFieldAccess] d
@@ -15489,7 +15489,7 @@ ir.cpp:
# 1537| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1537| Type = [SpecifiedType] const StructuredBindingDataMemberStruct
# 1537| ValueCategory = lvalue
-# 1537| getInitializer(2): [ConstructorFieldInit] constructor init of field b
+# 1537| getInitializer(2): [ConstructorDirectFieldInit] constructor init of field b
# 1537| Type = [IntType] unsigned int
# 1537| ValueCategory = prvalue
# 1537| getExpr(): [ReferenceFieldAccess] b
@@ -15501,7 +15501,7 @@ ir.cpp:
# 1537| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1537| Type = [SpecifiedType] const StructuredBindingDataMemberStruct
# 1537| ValueCategory = lvalue
-# 1537| getInitializer(3): [ConstructorFieldInit] constructor init of field r
+# 1537| getInitializer(3): [ConstructorDirectFieldInit] constructor init of field r
# 1537| Type = [LValueReferenceType] int &
# 1537| ValueCategory = prvalue
# 1537| getExpr(): [ReferenceFieldAccess] r
@@ -15513,7 +15513,7 @@ ir.cpp:
# 1537| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1537| Type = [SpecifiedType] const StructuredBindingDataMemberStruct
# 1537| ValueCategory = lvalue
-# 1537| getInitializer(4): [ConstructorFieldInit] constructor init of field p
+# 1537| getInitializer(4): [ConstructorDirectFieldInit] constructor init of field p
# 1537| Type = [IntPointerType] int *
# 1537| ValueCategory = prvalue
# 1537| getExpr(): [ReferenceFieldAccess] p
@@ -15525,7 +15525,7 @@ ir.cpp:
# 1537| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1537| Type = [SpecifiedType] const StructuredBindingDataMemberStruct
# 1537| ValueCategory = lvalue
-# 1537| getInitializer(5): [ConstructorFieldInit] constructor init of field xs
+# 1537| getInitializer(5): [ConstructorDirectFieldInit] constructor init of field xs
# 1537| Type = [CTypedefType,NestedTypedefType] ArrayType
# 1537| ValueCategory = prvalue
# 1537| getExpr(): [ReferenceFieldAccess] xs
@@ -15537,7 +15537,7 @@ ir.cpp:
# 1537| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1537| Type = [SpecifiedType] const StructuredBindingDataMemberStruct
# 1537| ValueCategory = lvalue
-# 1537| getInitializer(6): [ConstructorFieldInit] constructor init of field r_alt
+# 1537| getInitializer(6): [ConstructorDirectFieldInit] constructor init of field r_alt
# 1537| Type = [CTypedefType,NestedTypedefType] RefType
# 1537| ValueCategory = prvalue
# 1537| getExpr(): [ReferenceFieldAccess] r_alt
@@ -15549,7 +15549,7 @@ ir.cpp:
# 1537| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1537| Type = [SpecifiedType] const StructuredBindingDataMemberStruct
# 1537| ValueCategory = lvalue
-# 1537| getInitializer(7): [ConstructorFieldInit] constructor init of field m
+# 1537| getInitializer(7): [ConstructorDirectFieldInit] constructor init of field m
# 1537| Type = [Struct] StructuredBindingDataMemberMemberStruct
# 1537| ValueCategory = prvalue
# 1537| getExpr(): [ReferenceFieldAccess] m
@@ -15918,13 +15918,13 @@ ir.cpp:
# 1590| [Constructor] void StructuredBindingTupleRefGet::StructuredBindingTupleRefGet()
# 1590| :
# 1590| :
-# 1590| getInitializer(0): [ConstructorFieldInit] constructor init of field i
+# 1590| getInitializer(0): [ConstructorDefaultFieldInit] constructor init of field i
# 1590| Type = [IntType] int
# 1590| ValueCategory = prvalue
-# 1590| getInitializer(1): [ConstructorFieldInit] constructor init of field d
+# 1590| getInitializer(1): [ConstructorDefaultFieldInit] constructor init of field d
# 1590| Type = [DoubleType] double
# 1590| ValueCategory = prvalue
-# 1590| getInitializer(2): [ConstructorFieldInit] constructor init of field r
+# 1590| getInitializer(2): [ConstructorDefaultFieldInit] constructor init of field r
# 1590| Type = [LValueReferenceType] int &
# 1590| ValueCategory = prvalue
# 1590| getEntryPoint(): [BlockStmt] { ... }
@@ -15934,7 +15934,7 @@ ir.cpp:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const StructuredBindingTupleRefGet &
# 1590| :
-# 1590| getInitializer(0): [ConstructorFieldInit] constructor init of field i
+# 1590| getInitializer(0): [ConstructorDirectFieldInit] constructor init of field i
# 1590| Type = [IntType] int
# 1590| ValueCategory = prvalue
# 1590| getExpr(): [ReferenceFieldAccess] i
@@ -15946,7 +15946,7 @@ ir.cpp:
# 1590| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1590| Type = [SpecifiedType] const StructuredBindingTupleRefGet
# 1590| ValueCategory = lvalue
-# 1590| getInitializer(1): [ConstructorFieldInit] constructor init of field d
+# 1590| getInitializer(1): [ConstructorDirectFieldInit] constructor init of field d
# 1590| Type = [DoubleType] double
# 1590| ValueCategory = prvalue
# 1590| getExpr(): [ReferenceFieldAccess] d
@@ -15958,7 +15958,7 @@ ir.cpp:
# 1590| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1590| Type = [SpecifiedType] const StructuredBindingTupleRefGet
# 1590| ValueCategory = lvalue
-# 1590| getInitializer(2): [ConstructorFieldInit] constructor init of field r
+# 1590| getInitializer(2): [ConstructorDirectFieldInit] constructor init of field r
# 1590| Type = [LValueReferenceType] int &
# 1590| ValueCategory = prvalue
# 1590| getExpr(): [ReferenceFieldAccess] r
@@ -16327,10 +16327,10 @@ ir.cpp:
# 1657| [Constructor] void StructuredBindingTupleNoRefGet::StructuredBindingTupleNoRefGet()
# 1657| :
# 1657| :
-# 1657| getInitializer(0): [ConstructorFieldInit] constructor init of field i
+# 1657| getInitializer(0): [ConstructorDefaultFieldInit] constructor init of field i
# 1657| Type = [IntType] int
# 1657| ValueCategory = prvalue
-# 1657| getInitializer(1): [ConstructorFieldInit] constructor init of field r
+# 1657| getInitializer(1): [ConstructorDefaultFieldInit] constructor init of field r
# 1657| Type = [LValueReferenceType] int &
# 1657| ValueCategory = prvalue
# 1657| getEntryPoint(): [BlockStmt] { ... }
@@ -19817,7 +19817,7 @@ ir.cpp:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const ClassWithDestructor &
# 2188| :
-# 2188| getInitializer(0): [ConstructorFieldInit] constructor init of field x
+# 2188| getInitializer(0): [ConstructorDirectFieldInit] constructor init of field x
# 2188| Type = [CharPointerType] char *
# 2188| ValueCategory = prvalue
# 2188| getExpr(): [ReferenceFieldAccess] x
@@ -25642,6 +25642,168 @@ ir.cpp:
# 2884| Type = [VoidType] void
# 2884| ValueCategory = prvalue
# 2886| getStmt(6): [ReturnStmt] return ...
+# 2889| [CopyAssignmentOperator] StructInit& StructInit::operator=(StructInit const&)
+# 2889| :
+#-----| getParameter(0): [Parameter] (unnamed parameter 0)
+#-----| Type = [LValueReferenceType] const StructInit &
+# 2889| [MoveAssignmentOperator] StructInit& StructInit::operator=(StructInit&&)
+# 2889| :
+#-----| getParameter(0): [Parameter] (unnamed parameter 0)
+#-----| Type = [RValueReferenceType] StructInit &&
+# 2889| [CopyConstructor] void StructInit::StructInit(StructInit const&)
+# 2889| :
+#-----| getParameter(0): [Parameter] (unnamed parameter 0)
+#-----| Type = [LValueReferenceType] const StructInit &
+# 2889| [MoveConstructor] void StructInit::StructInit(StructInit&&)
+# 2889| :
+#-----| getParameter(0): [Parameter] (unnamed parameter 0)
+#-----| Type = [RValueReferenceType] StructInit &&
+# 2897| [Constructor] void StructInit::StructInit(int)
+# 2897| :
+# 2897| getParameter(0): [Parameter] j
+# 2897| Type = [IntType] int
+# 2897| :
+# 2897| getInitializer(0): [ConstructorDefaultFieldInit] constructor init of field i
+# 2897| Type = [IntType] int
+# 2897| ValueCategory = prvalue
+# 2897| getInitializer(1): [ConstructorDirectFieldInit] constructor init of field j
+# 2897| Type = [IntType] int
+# 2897| ValueCategory = prvalue
+# 2897| getExpr(): [VariableAccess] j
+# 2897| Type = [IntType] int
+# 2897| ValueCategory = prvalue(load)
+# 2897| getInitializer(2): [ConstructorDefaultFieldInit] constructor init of field k
+# 2897| Type = [IntType] int
+# 2897| ValueCategory = prvalue
+# 2897| getInitializer(3): [ConstructorDefaultFieldInit] constructor init of field l
+# 2897| Type = [IntType] int
+# 2897| ValueCategory = prvalue
+# 2897| getInitializer(4): [ConstructorDefaultFieldInit] constructor init of field m
+# 2897| Type = [IntType] int
+# 2897| ValueCategory = prvalue
+# 2897| getInitializer(5): [ConstructorDirectFieldInit] constructor init of field n
+# 2897| Type = [IntType] int
+# 2897| ValueCategory = prvalue
+# 2897| getExpr(): [FunctionCall] call to get_val
+# 2897| Type = [IntType] int
+# 2897| ValueCategory = prvalue
+# 2897| getQualifier(): [ThisExpr] this
+# 2897| Type = [PointerType] StructInit *
+# 2897| ValueCategory = prvalue(load)
+# 2897| getEntryPoint(): [BlockStmt] { ... }
+# 2897| getStmt(0): [ReturnStmt] return ...
+# 2899| [Constructor] void StructInit::StructInit()
+# 2899| :
+# 2899| :
+# 2899| getInitializer(0): [ConstructorDirectFieldInit] constructor init of field i
+# 2899| Type = [IntType] int
+# 2899| ValueCategory = prvalue
+# 2899| getExpr(): [Literal] 41
+# 2899| Type = [IntType] int
+# 2899| Value = [Literal] 41
+# 2899| ValueCategory = prvalue
+# 2899| getInitializer(1): [ConstructorDefaultFieldInit] constructor init of field j
+# 2899| Type = [IntType] int
+# 2899| ValueCategory = prvalue
+# 2899| getInitializer(2): [ConstructorDirectFieldInit] constructor init of field k
+# 2899| Type = [IntType] int
+# 2899| ValueCategory = prvalue
+# 2899| getExpr(): [Literal] 41
+# 2899| Type = [IntType] int
+# 2899| Value = [Literal] 41
+# 2899| ValueCategory = prvalue
+# 2899| getInitializer(3): [ConstructorDefaultFieldInit] constructor init of field l
+# 2899| Type = [IntType] int
+# 2899| ValueCategory = prvalue
+# 2899| getInitializer(4): [ConstructorDefaultFieldInit] constructor init of field m
+# 2899| Type = [IntType] int
+# 2899| ValueCategory = prvalue
+# 2899| getInitializer(5): [ConstructorDefaultFieldInit] constructor init of field n
+# 2899| Type = [IntType] int
+# 2899| ValueCategory = prvalue
+# 2899| getEntryPoint(): [BlockStmt] { ... }
+# 2899| getStmt(0): [ReturnStmt] return ...
+# 2901| [MemberFunction] int StructInit::get_val()
+# 2901| :
+# 2901| getEntryPoint(): [BlockStmt] { ... }
+# 2901| getStmt(0): [ReturnStmt] return ...
+# 2901| getExpr(): [ImplicitThisFieldAccess,PointerFieldAccess] k
+# 2901| Type = [IntType] int
+# 2901| ValueCategory = prvalue(load)
+# 2901| getQualifier(): [ThisExpr] this
+# 2901| Type = [PointerType] StructInit *
+# 2901| ValueCategory = prvalue(load)
+# 2905| [Constructor] void StructInitFromTemplate::StructInitFromTemplate()
+# 2905| :
+# 2905| :
+# 2905| getInitializer(0): [ConstructorDefaultFieldInit] constructor init of field t
+# 2905| Type = [IntType] int
+# 2905| ValueCategory = prvalue
+# 2905| getEntryPoint(): [BlockStmt] { ... }
+# 2905| getStmt(0): [ReturnStmt] return ...
+# 2909| [GlobalVariable] StructInitFromTemplate StructInitFromTemplateVar
+#-----| getInitializer(): [Initializer] initializer for StructInitFromTemplateVar
+#-----| getExpr(): [ConstructorCall] call to StructInitFromTemplate
+#-----| Type = [VoidType] void
+#-----| ValueCategory = prvalue
+#-----| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
+#-----| Type = [ClassTemplateInstantiation,Struct] StructInitFromTemplate
+#-----| ValueCategory = prvalue(load)
+# 2912| [GlobalVariable,VariableTemplateInstantiation] double VariableTemplate
+# 2912| getInitializer(): [Initializer] initializer for VariableTemplate
+# 2912| getExpr(): [Literal] 42
+# 2912| Type = [IntType] int
+# 2912| Value = [Literal] 42
+# 2912| ValueCategory = prvalue
+# 2912| getExpr().getFullyConverted(): [CStyleCast] (double)...
+# 2912| Conversion = [IntegralToFloatingPointConversion] integral to floating point conversion
+# 2912| Type = [DoubleType] double
+# 2912| Value = [CStyleCast] 42.0
+# 2912| ValueCategory = prvalue
+# 2915| [TemplateFunction,TopLevelFunction] T VariableTemplateFunc(T)
+# 2915| :
+# 2915| getParameter(0): [Parameter] x
+# 2915| Type = [TypeTemplateParameter] T
+# 2915| getEntryPoint(): [BlockStmt] { ... }
+# 2916| getStmt(0): [ReturnStmt] return ...
+# 2916| getExpr(): [AddExpr] ... + ...
+# 2916| Type = [UnknownType] unknown
+# 2916| ValueCategory = prvalue
+# 2916| getLeftOperand(): [VariableAccess] VariableTemplate
+# 2916| Type = [UnknownType] unknown
+# 2916| ValueCategory = lvalue
+# 2916| getRightOperand(): [VariableAccess] x
+# 2916| Type = [TypeTemplateParameter] T
+# 2916| ValueCategory = lvalue
+# 2915| [FunctionTemplateInstantiation,TopLevelFunction] double VariableTemplateFunc(double)
+# 2915| :
+# 2915| getParameter(0): [Parameter] x
+# 2915| Type = [DoubleType] double
+# 2915| getEntryPoint(): [BlockStmt] { ... }
+# 2916| getStmt(0): [ReturnStmt] return ...
+# 2916| getExpr(): [AddExpr] ... + ...
+# 2916| Type = [DoubleType] double
+# 2916| ValueCategory = prvalue
+# 2916| getLeftOperand(): [VariableAccess] VariableTemplate
+# 2916| Type = [DoubleType] double
+# 2916| Value = [VariableAccess] 42.0
+# 2916| ValueCategory = prvalue(load)
+# 2916| getRightOperand(): [VariableAccess] x
+# 2916| Type = [DoubleType] double
+# 2916| ValueCategory = prvalue(load)
+# 2919| [GlobalVariable] int VariableTemplateFuncUse
+# 2919| getInitializer(): [Initializer] initializer for VariableTemplateFuncUse
+# 2919| getExpr(): [FunctionCall] call to VariableTemplateFunc
+# 2919| Type = [DoubleType] double
+# 2919| ValueCategory = prvalue
+# 2919| getArgument(0): [Literal] 2.299999999999999822
+# 2919| Type = [DoubleType] double
+# 2919| Value = [Literal] 2.299999999999999822
+# 2919| ValueCategory = prvalue
+# 2919| getExpr().getFullyConverted(): [CStyleCast] (int)...
+# 2919| Conversion = [FloatingPointToIntegralConversion] floating point to integral conversion
+# 2919| Type = [IntType] int
+# 2919| ValueCategory = prvalue
ir23.cpp:
# 1| [TopLevelFunction] bool consteval_1()
# 1| :
@@ -50386,7 +50548,7 @@ perf-regression.cpp:
# 6| [Constructor] void Big::Big()
# 6| :
# 6| :
-# 6| getInitializer(0): [ConstructorFieldInit] constructor init of field buffer
+# 6| getInitializer(0): [ConstructorDirectFieldInit] constructor init of field buffer
# 6| Type = [ArrayType] char[1073741824]
# 6| ValueCategory = prvalue
# 6| getExpr(): [ArrayAggregateLiteral] {...}
diff --git a/cpp/ql/test/library-tests/ir/ir/PrintConfig.qll b/cpp/ql/test/library-tests/ir/ir/PrintConfig.qll
index aa23cf423ad..6e98d23bcf4 100644
--- a/cpp/ql/test/library-tests/ir/ir/PrintConfig.qll
+++ b/cpp/ql/test/library-tests/ir/ir/PrintConfig.qll
@@ -20,5 +20,7 @@ predicate shouldDumpDeclaration(Declaration decl) {
decl.(GlobalOrNamespaceVariable).hasInitializer()
or
decl.(StaticLocalVariable).hasInitializer()
+ or
+ decl.(Field).hasInitializer()
)
}
diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected
index 369cc9495a2..66810913e5d 100644
--- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected
+++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected
@@ -12361,35 +12361,111 @@ ir.cpp:
# 1533| void StructuredBindingDataMemberMemberStruct::StructuredBindingDataMemberMemberStruct()
# 1533| Block 0
-# 1533| v1533_1(void) = EnterFunction :
-# 1533| m1533_2(unknown) = AliasedDefinition :
-# 1533| m1533_3(unknown) = InitializeNonLocal :
-# 1533| m1533_4(unknown) = Chi : total:m1533_2, partial:m1533_3
-# 1533| r1533_5(glval) = VariableAddress[#this] :
-# 1533| m1533_6(glval) = InitializeParameter[#this] : &:r1533_5
-# 1533| r1533_7(glval) = Load[#this] : &:r1533_5, m1533_6
-# 1533| m1533_8(StructuredBindingDataMemberMemberStruct) = InitializeIndirection[#this] : &:r1533_7
-# 1533| v1533_9(void) = NoOp :
-# 1533| v1533_10(void) = ReturnIndirection[#this] : &:r1533_7, m1533_8
-# 1533| v1533_11(void) = ReturnVoid :
-# 1533| v1533_12(void) = AliasedUse : m1533_3
-# 1533| v1533_13(void) = ExitFunction :
+# 1533| v1533_1(void) = EnterFunction :
+# 1533| m1533_2(unknown) = AliasedDefinition :
+# 1533| m1533_3(unknown) = InitializeNonLocal :
+# 1533| m1533_4(unknown) = Chi : total:m1533_2, partial:m1533_3
+# 1533| r1533_5(glval) = VariableAddress[#this] :
+# 1533| m1533_6(glval) = InitializeParameter[#this] : &:r1533_5
+# 1533| r1533_7(glval) = Load[#this] : &:r1533_5, m1533_6
+# 1533| m1533_8(StructuredBindingDataMemberMemberStruct) = InitializeIndirection[#this] : &:r1533_7
+# 1533| m1533_9(unknown) = Chi : total:m1533_4, partial:m1533_8
+# 1533| r1533_10(glval) = FunctionAddress[x] :
+# 1533| v1533_11(void) = Call[x] : func:r1533_10, this:r1533_7
+# 1533| m1533_12(unknown) = ^CallSideEffect : ~m1533_9
+# 1533| m1533_13(unknown) = Chi : total:m1533_9, partial:m1533_12
+# 1533| v1533_14(void) = ^IndirectReadSideEffect[-1] : &:r1533_7, ~m1533_13
+# 1533| m1533_15(StructuredBindingDataMemberMemberStruct) = ^IndirectMayWriteSideEffect[-1] : &:r1533_7
+# 1533| m1533_16(unknown) = Chi : total:m1533_13, partial:m1533_15
+# 1533| v1533_17(void) = NoOp :
+# 1533| v1533_18(void) = ReturnIndirection[#this] : &:r1533_7, ~m1533_16
+# 1533| v1533_19(void) = ReturnVoid :
+# 1533| v1533_20(void) = AliasedUse : ~m1533_16
+# 1533| v1533_21(void) = ExitFunction :
+
+# 1534| int StructuredBindingDataMemberMemberStruct::x
+# 1534| Block 0
+# 1534| v1534_1(void) = EnterFunction :
+# 1534| m1534_2(unknown) = AliasedDefinition :
+# 1534| m1534_3(unknown) = InitializeNonLocal :
+# 1534| m1534_4(unknown) = Chi : total:m1534_2, partial:m1534_3
+# 1534| r1534_5(glval) = VariableAddress[#this] :
+# 1534| m1534_6(glval) = InitializeParameter[#this] : &:r1534_5
+# 1534| r1534_7(glval) = Load[#this] : &:r1534_5, m1534_6
+# 1534| m1534_8(StructuredBindingDataMemberMemberStruct) = InitializeIndirection[#this] : &:r1534_7
+# 1534| r1534_9(glval) = FieldAddress[x] : r1534_7
+# 1534| r1534_10(int) = Constant[5] :
+# 1534| m1534_11(int) = Store[?] : &:r1534_9, r1534_10
+# 1534| m1534_12(unknown) = Chi : total:m1534_8, partial:m1534_11
+# 1534| v1534_13(void) = ReturnVoid :
+# 1534| v1534_14(void) = AliasedUse : m1534_3
+# 1534| v1534_15(void) = ExitFunction :
# 1537| void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct()
# 1537| Block 0
-# 1537| v1537_1(void) = EnterFunction :
-# 1537| m1537_2(unknown) = AliasedDefinition :
-# 1537| m1537_3(unknown) = InitializeNonLocal :
-# 1537| m1537_4(unknown) = Chi : total:m1537_2, partial:m1537_3
-# 1537| r1537_5(glval) = VariableAddress[#this] :
-# 1537| m1537_6(glval) = InitializeParameter[#this] : &:r1537_5
-# 1537| r1537_7(glval) = Load[#this] : &:r1537_5, m1537_6
-# 1537| m1537_8(StructuredBindingDataMemberStruct) = InitializeIndirection[#this] : &:r1537_7
-# 1537| v1537_9(void) = NoOp :
-# 1537| v1537_10(void) = ReturnIndirection[#this] : &:r1537_7, m1537_8
-# 1537| v1537_11(void) = ReturnVoid :
-# 1537| v1537_12(void) = AliasedUse : m1537_3
-# 1537| v1537_13(void) = ExitFunction :
+# 1537| v1537_1(void) = EnterFunction :
+# 1537| m1537_2(unknown) = AliasedDefinition :
+# 1537| m1537_3(unknown) = InitializeNonLocal :
+# 1537| m1537_4(unknown) = Chi : total:m1537_2, partial:m1537_3
+# 1537| r1537_5(glval) = VariableAddress[#this] :
+# 1537| m1537_6(glval) = InitializeParameter[#this] : &:r1537_5
+# 1537| r1537_7(glval) = Load[#this] : &:r1537_5, m1537_6
+# 1537| m1537_8(StructuredBindingDataMemberStruct) = InitializeIndirection[#this] : &:r1537_7
+# 1537| m1537_9(unknown) = Chi : total:m1537_4, partial:m1537_8
+# 1537| r1537_10(glval) = FunctionAddress[i] :
+# 1537| v1537_11(void) = Call[i] : func:r1537_10, this:r1537_7
+# 1537| m1537_12(unknown) = ^CallSideEffect : ~m1537_9
+# 1537| m1537_13(unknown) = Chi : total:m1537_9, partial:m1537_12
+# 1537| v1537_14(void) = ^IndirectReadSideEffect[-1] : &:r1537_7, ~m1537_13
+# 1537| m1537_15(StructuredBindingDataMemberStruct) = ^IndirectMayWriteSideEffect[-1] : &:r1537_7
+# 1537| m1537_16(unknown) = Chi : total:m1537_13, partial:m1537_15
+# 1537| r1537_17(glval) = FunctionAddress[d] :
+# 1537| v1537_18(void) = Call[d] : func:r1537_17, this:r1537_7
+# 1537| m1537_19(unknown) = ^CallSideEffect : ~m1537_16
+# 1537| m1537_20(unknown) = Chi : total:m1537_16, partial:m1537_19
+# 1537| v1537_21(void) = ^IndirectReadSideEffect[-1] : &:r1537_7, ~m1537_20
+# 1537| m1537_22(StructuredBindingDataMemberStruct) = ^IndirectMayWriteSideEffect[-1] : &:r1537_7
+# 1537| m1537_23(unknown) = Chi : total:m1537_20, partial:m1537_22
+# 1537| r1537_24(glval) = FunctionAddress[r] :
+# 1537| v1537_25(void) = Call[r] : func:r1537_24, this:r1537_7
+# 1537| m1537_26(unknown) = ^CallSideEffect : ~m1537_23
+# 1537| m1537_27(unknown) = Chi : total:m1537_23, partial:m1537_26
+# 1537| v1537_28(void) = ^IndirectReadSideEffect[-1] : &:r1537_7, ~m1537_27
+# 1537| m1537_29(StructuredBindingDataMemberStruct) = ^IndirectMayWriteSideEffect[-1] : &:r1537_7
+# 1537| m1537_30(unknown) = Chi : total:m1537_27, partial:m1537_29
+# 1537| r1537_31(glval) = FunctionAddress[p] :
+# 1537| v1537_32(void) = Call[p] : func:r1537_31, this:r1537_7
+# 1537| m1537_33(unknown) = ^CallSideEffect : ~m1537_30
+# 1537| m1537_34(unknown) = Chi : total:m1537_30, partial:m1537_33
+# 1537| v1537_35(void) = ^IndirectReadSideEffect[-1] : &:r1537_7, ~m1537_34
+# 1537| m1537_36(StructuredBindingDataMemberStruct) = ^IndirectMayWriteSideEffect[-1] : &:r1537_7
+# 1537| m1537_37(unknown) = Chi : total:m1537_34, partial:m1537_36
+# 1537| r1537_38(glval) = FunctionAddress[xs] :
+# 1537| v1537_39(void) = Call[xs] : func:r1537_38, this:r1537_7
+# 1537| m1537_40(unknown) = ^CallSideEffect : ~m1537_37
+# 1537| m1537_41(unknown) = Chi : total:m1537_37, partial:m1537_40
+# 1537| v1537_42(void) = ^IndirectReadSideEffect[-1] : &:r1537_7, ~m1537_41
+# 1537| m1537_43(StructuredBindingDataMemberStruct) = ^IndirectMayWriteSideEffect[-1] : &:r1537_7
+# 1537| m1537_44(unknown) = Chi : total:m1537_41, partial:m1537_43
+# 1537| r1537_45(glval) = FunctionAddress[r_alt] :
+# 1537| v1537_46(void) = Call[r_alt] : func:r1537_45, this:r1537_7
+# 1537| m1537_47(unknown) = ^CallSideEffect : ~m1537_44
+# 1537| m1537_48(unknown) = Chi : total:m1537_44, partial:m1537_47
+# 1537| v1537_49(void) = ^IndirectReadSideEffect[-1] : &:r1537_7, ~m1537_48
+# 1537| m1537_50(StructuredBindingDataMemberStruct) = ^IndirectMayWriteSideEffect[-1] : &:r1537_7
+# 1537| m1537_51(unknown) = Chi : total:m1537_48, partial:m1537_50
+# 1537| r1537_52(glval) = FieldAddress[m] : r1537_7
+# 1537| r1537_53(glval) = FunctionAddress[StructuredBindingDataMemberMemberStruct] :
+# 1537| v1537_54(void) = Call[StructuredBindingDataMemberMemberStruct] : func:r1537_53, this:r1537_52
+# 1537| m1537_55(unknown) = ^CallSideEffect : ~m1537_51
+# 1537| m1537_56(unknown) = Chi : total:m1537_51, partial:m1537_55
+# 1537| m1537_57(StructuredBindingDataMemberMemberStruct) = ^IndirectMayWriteSideEffect[-1] : &:r1537_52
+# 1537| m1537_58(unknown) = Chi : total:m1537_56, partial:m1537_57
+# 1537| v1537_59(void) = NoOp :
+# 1537| v1537_60(void) = ReturnIndirection[#this] : &:r1537_7, ~m1537_58
+# 1537| v1537_61(void) = ReturnVoid :
+# 1537| v1537_62(void) = AliasedUse : ~m1537_58
+# 1537| v1537_63(void) = ExitFunction :
# 1537| void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct(StructuredBindingDataMemberStruct const&)
# 1537| Block 0
@@ -12476,6 +12552,130 @@ ir.cpp:
# 1537| v1537_76(void) = AliasedUse : m1537_3
# 1537| v1537_77(void) = ExitFunction :
+# 1540| int StructuredBindingDataMemberStruct::i
+# 1540| Block 0
+# 1540| v1540_1(void) = EnterFunction :
+# 1540| m1540_2(unknown) = AliasedDefinition :
+# 1540| m1540_3(unknown) = InitializeNonLocal :
+# 1540| m1540_4(unknown) = Chi : total:m1540_2, partial:m1540_3
+# 1540| r1540_5(glval) = VariableAddress[#this] :
+# 1540| m1540_6(glval) = InitializeParameter[#this] : &:r1540_5
+# 1540| r1540_7(glval) = Load[#this] : &:r1540_5, m1540_6
+# 1540| m1540_8(StructuredBindingDataMemberStruct) = InitializeIndirection[#this] : &:r1540_7
+# 1540| r1540_9(glval) = FieldAddress[i] : r1540_7
+# 1540| r1540_10(int) = Constant[1] :
+# 1540| m1540_11(int) = Store[?] : &:r1540_9, r1540_10
+# 1540| m1540_12(unknown) = Chi : total:m1540_8, partial:m1540_11
+# 1540| v1540_13(void) = ReturnVoid :
+# 1540| v1540_14(void) = AliasedUse : m1540_3
+# 1540| v1540_15(void) = ExitFunction :
+
+# 1541| double StructuredBindingDataMemberStruct::d
+# 1541| Block 0
+# 1541| v1541_1(void) = EnterFunction :
+# 1541| m1541_2(unknown) = AliasedDefinition :
+# 1541| m1541_3(unknown) = InitializeNonLocal :
+# 1541| m1541_4(unknown) = Chi : total:m1541_2, partial:m1541_3
+# 1541| r1541_5(glval) = VariableAddress[#this] :
+# 1541| m1541_6(glval) = InitializeParameter[#this] : &:r1541_5
+# 1541| r1541_7(glval) = Load[#this] : &:r1541_5, m1541_6
+# 1541| m1541_8(StructuredBindingDataMemberStruct) = InitializeIndirection[#this] : &:r1541_7
+# 1541| r1541_9(glval) = FieldAddress[d] : r1541_7
+# 1541| r1541_10(double) = Constant[2.0] :
+# 1541| m1541_11(double) = Store[?] : &:r1541_9, r1541_10
+# 1541| m1541_12(unknown) = Chi : total:m1541_8, partial:m1541_11
+# 1541| v1541_13(void) = ReturnVoid :
+# 1541| v1541_14(void) = AliasedUse : m1541_3
+# 1541| v1541_15(void) = ExitFunction :
+
+# 1543| int& StructuredBindingDataMemberStruct::r
+# 1543| Block 0
+# 1543| v1543_1(void) = EnterFunction :
+# 1543| m1543_2(unknown) = AliasedDefinition :
+# 1543| m1543_3(unknown) = InitializeNonLocal :
+# 1543| m1543_4(unknown) = Chi : total:m1543_2, partial:m1543_3
+# 1543| r1543_5(glval) = VariableAddress[#this] :
+# 1543| m1543_6(glval) = InitializeParameter[#this] : &:r1543_5
+# 1543| r1543_7(glval) = Load[#this] : &:r1543_5, m1543_6
+# 1543| m1543_8(StructuredBindingDataMemberStruct) = InitializeIndirection[#this] : &:r1543_7
+# 1543| m1543_9(unknown) = Chi : total:m1543_4, partial:m1543_8
+# 1543| r1543_10(glval) = FieldAddress[r] : r1543_7
+# 1543| r1543_11(StructuredBindingDataMemberStruct *) = CopyValue : r1543_7
+# 1543| r1543_12(glval) = FieldAddress[i] : r1543_11
+#-----| r0_1(int &) = CopyValue : r1543_12
+#-----| m0_2(int &) = Store[?] : &:r1543_10, r0_1
+#-----| m0_3(unknown) = Chi : total:m1543_9, partial:m0_2
+# 1543| v1543_13(void) = ReturnVoid :
+# 1543| v1543_14(void) = AliasedUse : ~m0_3
+# 1543| v1543_15(void) = ExitFunction :
+
+# 1544| int* StructuredBindingDataMemberStruct::p
+# 1544| Block 0
+# 1544| v1544_1(void) = EnterFunction :
+# 1544| m1544_2(unknown) = AliasedDefinition :
+# 1544| m1544_3(unknown) = InitializeNonLocal :
+# 1544| m1544_4(unknown) = Chi : total:m1544_2, partial:m1544_3
+# 1544| r1544_5(glval) = VariableAddress[#this] :
+# 1544| m1544_6(glval) = InitializeParameter[#this] : &:r1544_5
+# 1544| r1544_7(glval) = Load[#this] : &:r1544_5, m1544_6
+# 1544| m1544_8(StructuredBindingDataMemberStruct) = InitializeIndirection[#this] : &:r1544_7
+# 1544| m1544_9(unknown) = Chi : total:m1544_4, partial:m1544_8
+# 1544| r1544_10(glval) = FieldAddress[p] : r1544_7
+# 1544| r1544_11(StructuredBindingDataMemberStruct *) = CopyValue : r1544_7
+# 1544| r1544_12(glval) = FieldAddress[i] : r1544_11
+# 1544| r1544_13(int *) = CopyValue : r1544_12
+# 1544| m1544_14(int *) = Store[?] : &:r1544_10, r1544_13
+# 1544| m1544_15(unknown) = Chi : total:m1544_9, partial:m1544_14
+# 1544| v1544_16(void) = ReturnVoid :
+# 1544| v1544_17(void) = AliasedUse : ~m1544_15
+# 1544| v1544_18(void) = ExitFunction :
+
+# 1545| StructuredBindingDataMemberStruct::ArrayType StructuredBindingDataMemberStruct::xs
+# 1545| Block 0
+# 1545| v1545_1(void) = EnterFunction :
+# 1545| m1545_2(unknown) = AliasedDefinition :
+# 1545| m1545_3(unknown) = InitializeNonLocal :
+# 1545| m1545_4(unknown) = Chi : total:m1545_2, partial:m1545_3
+# 1545| r1545_5(glval) = VariableAddress[#this] :
+# 1545| m1545_6(glval) = InitializeParameter[#this] : &:r1545_5
+# 1545| r1545_7(glval) = Load[#this] : &:r1545_5, m1545_6
+# 1545| m1545_8(StructuredBindingDataMemberStruct) = InitializeIndirection[#this] : &:r1545_7
+# 1545| r1545_9(glval) = FieldAddress[xs] : r1545_7
+# 1545| r1545_10(int) = Constant[0] :
+# 1545| r1545_11(glval) = PointerAdd[4] : r1545_9, r1545_10
+# 1545| r1545_12(int) = Constant[1] :
+# 1545| m1545_13(int) = Store[?] : &:r1545_11, r1545_12
+# 1545| m1545_14(unknown) = Chi : total:m1545_8, partial:m1545_13
+# 1545| r1545_15(int) = Constant[1] :
+# 1545| r1545_16(glval) = PointerAdd[4] : r1545_9, r1545_15
+# 1545| r1545_17(int) = Constant[2] :
+# 1545| m1545_18(int) = Store[?] : &:r1545_16, r1545_17
+# 1545| m1545_19(unknown) = Chi : total:m1545_14, partial:m1545_18
+# 1545| v1545_20(void) = ReturnVoid :
+# 1545| v1545_21(void) = AliasedUse : m1545_3
+# 1545| v1545_22(void) = ExitFunction :
+
+# 1546| StructuredBindingDataMemberStruct::RefType StructuredBindingDataMemberStruct::r_alt
+# 1546| Block 0
+# 1546| v1546_1(void) = EnterFunction :
+# 1546| m1546_2(unknown) = AliasedDefinition :
+# 1546| m1546_3(unknown) = InitializeNonLocal :
+# 1546| m1546_4(unknown) = Chi : total:m1546_2, partial:m1546_3
+# 1546| r1546_5(glval) = VariableAddress[#this] :
+# 1546| m1546_6(glval) = InitializeParameter[#this] : &:r1546_5
+# 1546| r1546_7(glval) = Load[#this] : &:r1546_5, m1546_6
+# 1546| m1546_8(StructuredBindingDataMemberStruct) = InitializeIndirection[#this] : &:r1546_7
+# 1546| m1546_9(unknown) = Chi : total:m1546_4, partial:m1546_8
+# 1546| r1546_10(glval) = FieldAddress[r_alt] : r1546_7
+# 1546| r1546_11(StructuredBindingDataMemberStruct *) = CopyValue : r1546_7
+# 1546| r1546_12(glval) = FieldAddress[i] : r1546_11
+#-----| r0_1(int &) = CopyValue : r1546_12
+#-----| m0_2(int &) = Store[?] : &:r1546_10, r0_1
+#-----| m0_3(unknown) = Chi : total:m1546_9, partial:m0_2
+# 1546| v1546_13(void) = ReturnVoid :
+# 1546| v1546_14(void) = AliasedUse : ~m0_3
+# 1546| v1546_15(void) = ExitFunction :
+
# 1550| void data_member_structured_binding()
# 1550| Block 0
# 1550| v1550_1(void) = EnterFunction :
@@ -12484,15 +12684,16 @@ ir.cpp:
# 1550| m1550_4(unknown) = Chi : total:m1550_2, partial:m1550_3
# 1551| r1551_1(glval) = VariableAddress[s] :
# 1551| m1551_2(StructuredBindingDataMemberStruct) = Uninitialized[s] : &:r1551_1
-# 1551| r1551_3(glval) = FunctionAddress[StructuredBindingDataMemberStruct] :
-# 1551| v1551_4(void) = Call[StructuredBindingDataMemberStruct] : func:r1551_3, this:r1551_1
-# 1551| m1551_5(unknown) = ^CallSideEffect : ~m1550_4
-# 1551| m1551_6(unknown) = Chi : total:m1550_4, partial:m1551_5
-# 1551| m1551_7(StructuredBindingDataMemberStruct) = ^IndirectMayWriteSideEffect[-1] : &:r1551_1
-# 1551| m1551_8(StructuredBindingDataMemberStruct) = Chi : total:m1551_2, partial:m1551_7
+# 1551| m1551_3(unknown) = Chi : total:m1550_4, partial:m1551_2
+# 1551| r1551_4(glval) = FunctionAddress[StructuredBindingDataMemberStruct] :
+# 1551| v1551_5(void) = Call[StructuredBindingDataMemberStruct] : func:r1551_4, this:r1551_1
+# 1551| m1551_6(unknown) = ^CallSideEffect : ~m1551_3
+# 1551| m1551_7(unknown) = Chi : total:m1551_3, partial:m1551_6
+# 1551| m1551_8(StructuredBindingDataMemberStruct) = ^IndirectMayWriteSideEffect[-1] : &:r1551_1
+# 1551| m1551_9(unknown) = Chi : total:m1551_7, partial:m1551_8
# 1554| r1554_1(glval) = VariableAddress[(unnamed local variable)] :
# 1554| r1554_2(glval) = VariableAddress[s] :
-# 1554| r1554_3(StructuredBindingDataMemberStruct) = Load[s] : &:r1554_2, m1551_8
+# 1554| r1554_3(StructuredBindingDataMemberStruct) = Load[s] : &:r1554_2, ~m1551_9
# 1554| m1554_4(StructuredBindingDataMemberStruct) = Store[(unnamed local variable)] : &:r1554_1, r1554_3
# 1554| r1554_5(glval) = VariableAddress[i] :
# 1554| r1554_6(glval) = VariableAddress[(unnamed local variable)] :
@@ -12549,7 +12750,7 @@ ir.cpp:
# 1558| r1558_2(glval) = VariableAddress[r] :
# 1558| r1558_3(int &) = Load[r] : &:r1558_2, m1554_22
# 1558| m1558_4(int) = Store[?] : &:r1558_3, r1558_1
-# 1558| m1558_5(unknown) = Chi : total:m1551_6, partial:m1558_4
+# 1558| m1558_5(unknown) = Chi : total:m1551_9, partial:m1558_4
# 1559| r1559_1(int) = Constant[6] :
# 1559| r1559_2(glval) = VariableAddress[p] :
# 1559| r1559_3(int *&) = Load[p] : &:r1559_2, m1554_26
@@ -12574,7 +12775,7 @@ ir.cpp:
# 1562| m1562_5(int) = Store[w] : &:r1562_1, r1562_4
# 1566| r1566_1(glval) = VariableAddress[unnamed_local_variable] :
# 1566| r1566_2(glval) = VariableAddress[s] :
-# 1566| r1566_3(StructuredBindingDataMemberStruct) = Load[s] : &:r1566_2, m1551_8
+# 1566| r1566_3(StructuredBindingDataMemberStruct) = Load[s] : &:r1566_2, ~m1559_7
# 1566| m1566_4(StructuredBindingDataMemberStruct) = Store[unnamed_local_variable] : &:r1566_1, r1566_3
# 1567| r1567_1(glval) = VariableAddress[i] :
# 1567| r1567_2(glval) = VariableAddress[unnamed_local_variable] :
@@ -12652,19 +12853,41 @@ ir.cpp:
# 1590| void StructuredBindingTupleRefGet::StructuredBindingTupleRefGet()
# 1590| Block 0
-# 1590| v1590_1(void) = EnterFunction :
-# 1590| m1590_2(unknown) = AliasedDefinition :
-# 1590| m1590_3(unknown) = InitializeNonLocal :
-# 1590| m1590_4(unknown) = Chi : total:m1590_2, partial:m1590_3
-# 1590| r1590_5(glval) = VariableAddress[#this] :
-# 1590| m1590_6(glval) = InitializeParameter[#this] : &:r1590_5
-# 1590| r1590_7(glval) = Load[#this] : &:r1590_5, m1590_6
-# 1590| m1590_8(StructuredBindingTupleRefGet) = InitializeIndirection[#this] : &:r1590_7
-# 1590| v1590_9(void) = NoOp :
-# 1590| v1590_10(void) = ReturnIndirection[#this] : &:r1590_7, m1590_8
-# 1590| v1590_11(void) = ReturnVoid :
-# 1590| v1590_12(void) = AliasedUse : m1590_3
-# 1590| v1590_13(void) = ExitFunction :
+# 1590| v1590_1(void) = EnterFunction :
+# 1590| m1590_2(unknown) = AliasedDefinition :
+# 1590| m1590_3(unknown) = InitializeNonLocal :
+# 1590| m1590_4(unknown) = Chi : total:m1590_2, partial:m1590_3
+# 1590| r1590_5(glval) = VariableAddress[#this] :
+# 1590| m1590_6(glval) = InitializeParameter[#this] : &:r1590_5
+# 1590| r1590_7(glval) = Load[#this] : &:r1590_5, m1590_6
+# 1590| m1590_8(StructuredBindingTupleRefGet) = InitializeIndirection[#this] : &:r1590_7
+# 1590| m1590_9(unknown) = Chi : total:m1590_4, partial:m1590_8
+# 1590| r1590_10(glval) = FunctionAddress[i] :
+# 1590| v1590_11(void) = Call[i] : func:r1590_10, this:r1590_7
+# 1590| m1590_12(unknown) = ^CallSideEffect : ~m1590_9
+# 1590| m1590_13(unknown) = Chi : total:m1590_9, partial:m1590_12
+# 1590| v1590_14(void) = ^IndirectReadSideEffect[-1] : &:r1590_7, ~m1590_13
+# 1590| m1590_15(StructuredBindingTupleRefGet) = ^IndirectMayWriteSideEffect[-1] : &:r1590_7
+# 1590| m1590_16(unknown) = Chi : total:m1590_13, partial:m1590_15
+# 1590| r1590_17(glval) = FunctionAddress[d] :
+# 1590| v1590_18(void) = Call[d] : func:r1590_17, this:r1590_7
+# 1590| m1590_19(unknown) = ^CallSideEffect : ~m1590_16
+# 1590| m1590_20(unknown) = Chi : total:m1590_16, partial:m1590_19
+# 1590| v1590_21(void) = ^IndirectReadSideEffect[-1] : &:r1590_7, ~m1590_20
+# 1590| m1590_22(StructuredBindingTupleRefGet) = ^IndirectMayWriteSideEffect[-1] : &:r1590_7
+# 1590| m1590_23(unknown) = Chi : total:m1590_20, partial:m1590_22
+# 1590| r1590_24(glval) = FunctionAddress[r] :
+# 1590| v1590_25(void) = Call[r] : func:r1590_24, this:r1590_7
+# 1590| m1590_26(unknown) = ^CallSideEffect : ~m1590_23
+# 1590| m1590_27(unknown) = Chi : total:m1590_23, partial:m1590_26
+# 1590| v1590_28(void) = ^IndirectReadSideEffect[-1] : &:r1590_7, ~m1590_27
+# 1590| m1590_29(StructuredBindingTupleRefGet) = ^IndirectMayWriteSideEffect[-1] : &:r1590_7
+# 1590| m1590_30(unknown) = Chi : total:m1590_27, partial:m1590_29
+# 1590| v1590_31(void) = NoOp :
+# 1590| v1590_32(void) = ReturnIndirection[#this] : &:r1590_7, ~m1590_30
+# 1590| v1590_33(void) = ReturnVoid :
+# 1590| v1590_34(void) = AliasedUse : ~m1590_30
+# 1590| v1590_35(void) = ExitFunction :
# 1590| void StructuredBindingTupleRefGet::StructuredBindingTupleRefGet(StructuredBindingTupleRefGet const&)
# 1590| Block 0
@@ -12711,6 +12934,63 @@ ir.cpp:
# 1590| v1590_36(void) = AliasedUse : m1590_3
# 1590| v1590_37(void) = ExitFunction :
+# 1591| int StructuredBindingTupleRefGet::i
+# 1591| Block 0
+# 1591| v1591_1(void) = EnterFunction :
+# 1591| m1591_2(unknown) = AliasedDefinition :
+# 1591| m1591_3(unknown) = InitializeNonLocal :
+# 1591| m1591_4(unknown) = Chi : total:m1591_2, partial:m1591_3
+# 1591| r1591_5(glval) = VariableAddress[#this] :
+# 1591| m1591_6(glval) = InitializeParameter[#this] : &:r1591_5
+# 1591| r1591_7(glval) = Load[#this] : &:r1591_5, m1591_6
+# 1591| m1591_8(StructuredBindingTupleRefGet) = InitializeIndirection[#this] : &:r1591_7
+# 1591| r1591_9(glval) = FieldAddress[i] : r1591_7
+# 1591| r1591_10(int) = Constant[1] :
+# 1591| m1591_11(int) = Store[?] : &:r1591_9, r1591_10
+# 1591| m1591_12(unknown) = Chi : total:m1591_8, partial:m1591_11
+# 1591| v1591_13(void) = ReturnVoid :
+# 1591| v1591_14(void) = AliasedUse : m1591_3
+# 1591| v1591_15(void) = ExitFunction :
+
+# 1592| double StructuredBindingTupleRefGet::d
+# 1592| Block 0
+# 1592| v1592_1(void) = EnterFunction :
+# 1592| m1592_2(unknown) = AliasedDefinition :
+# 1592| m1592_3(unknown) = InitializeNonLocal :
+# 1592| m1592_4(unknown) = Chi : total:m1592_2, partial:m1592_3
+# 1592| r1592_5(glval) = VariableAddress[#this] :
+# 1592| m1592_6(glval) = InitializeParameter[#this] : &:r1592_5
+# 1592| r1592_7(glval) = Load[#this] : &:r1592_5, m1592_6
+# 1592| m1592_8(StructuredBindingTupleRefGet) = InitializeIndirection[#this] : &:r1592_7
+# 1592| r1592_9(glval) = FieldAddress[d] : r1592_7
+# 1592| r1592_10(double) = Constant[2.200000000000000178] :
+# 1592| m1592_11(double) = Store[?] : &:r1592_9, r1592_10
+# 1592| m1592_12(unknown) = Chi : total:m1592_8, partial:m1592_11
+# 1592| v1592_13(void) = ReturnVoid :
+# 1592| v1592_14(void) = AliasedUse : m1592_3
+# 1592| v1592_15(void) = ExitFunction :
+
+# 1593| int& StructuredBindingTupleRefGet::r
+# 1593| Block 0
+# 1593| v1593_1(void) = EnterFunction :
+# 1593| m1593_2(unknown) = AliasedDefinition :
+# 1593| m1593_3(unknown) = InitializeNonLocal :
+# 1593| m1593_4(unknown) = Chi : total:m1593_2, partial:m1593_3
+# 1593| r1593_5(glval) = VariableAddress[#this] :
+# 1593| m1593_6(glval) = InitializeParameter[#this] : &:r1593_5
+# 1593| r1593_7(glval) = Load[#this] : &:r1593_5, m1593_6
+# 1593| m1593_8(StructuredBindingTupleRefGet) = InitializeIndirection[#this] : &:r1593_7
+# 1593| m1593_9(unknown) = Chi : total:m1593_4, partial:m1593_8
+# 1593| r1593_10(glval) = FieldAddress[r] : r1593_7
+# 1593| r1593_11(StructuredBindingTupleRefGet *) = CopyValue : r1593_7
+# 1593| r1593_12(glval) = FieldAddress[i] : r1593_11
+#-----| r0_1(int &) = CopyValue : r1593_12
+#-----| m0_2(int &) = Store[?] : &:r1593_10, r0_1
+#-----| m0_3(unknown) = Chi : total:m1593_9, partial:m0_2
+# 1593| v1593_13(void) = ReturnVoid :
+# 1593| v1593_14(void) = AliasedUse : ~m0_3
+# 1593| v1593_15(void) = ExitFunction :
+
# 1618| std::tuple_element::type& StructuredBindingTupleRefGet::get()
# 1618| Block 0
# 1618| v1618_1(void) = EnterFunction :
@@ -12787,22 +13067,23 @@ ir.cpp:
# 1630| m1630_4(unknown) = Chi : total:m1630_2, partial:m1630_3
# 1631| r1631_1(glval) = VariableAddress[t] :
# 1631| m1631_2(StructuredBindingTupleRefGet) = Uninitialized[t] : &:r1631_1
-# 1631| r1631_3(glval) = FunctionAddress[StructuredBindingTupleRefGet] :
-# 1631| v1631_4(void) = Call[StructuredBindingTupleRefGet] : func:r1631_3, this:r1631_1
-# 1631| m1631_5(unknown) = ^CallSideEffect : ~m1630_4
-# 1631| m1631_6(unknown) = Chi : total:m1630_4, partial:m1631_5
-# 1631| m1631_7(StructuredBindingTupleRefGet) = ^IndirectMayWriteSideEffect[-1] : &:r1631_1
-# 1631| m1631_8(StructuredBindingTupleRefGet) = Chi : total:m1631_2, partial:m1631_7
+# 1631| m1631_3(unknown) = Chi : total:m1630_4, partial:m1631_2
+# 1631| r1631_4(glval) = FunctionAddress[StructuredBindingTupleRefGet] :
+# 1631| v1631_5(void) = Call[StructuredBindingTupleRefGet] : func:r1631_4, this:r1631_1
+# 1631| m1631_6(unknown) = ^CallSideEffect : ~m1631_3
+# 1631| m1631_7(unknown) = Chi : total:m1631_3, partial:m1631_6
+# 1631| m1631_8(StructuredBindingTupleRefGet) = ^IndirectMayWriteSideEffect[-1] : &:r1631_1
+# 1631| m1631_9(unknown) = Chi : total:m1631_7, partial:m1631_8
# 1634| r1634_1(glval) = VariableAddress[(unnamed local variable)] :
# 1634| r1634_2(glval) = VariableAddress[t] :
-# 1634| r1634_3(StructuredBindingTupleRefGet) = Load[t] : &:r1634_2, m1631_8
+# 1634| r1634_3(StructuredBindingTupleRefGet) = Load[t] : &:r1634_2, ~m1631_9
# 1634| m1634_4(StructuredBindingTupleRefGet) = Store[(unnamed local variable)] : &:r1634_1, r1634_3
# 1634| r1634_5(glval) = VariableAddress[i] :
# 1634| r1634_6(glval) = VariableAddress[(unnamed local variable)] :
# 1634| r1634_7(glval) = FunctionAddress[get] :
# 1634| r1634_8(int &) = Call[get] : func:r1634_7, this:r1634_6
-# 1634| m1634_9(unknown) = ^CallSideEffect : ~m1631_6
-# 1634| m1634_10(unknown) = Chi : total:m1631_6, partial:m1634_9
+# 1634| m1634_9(unknown) = ^CallSideEffect : ~m1631_9
+# 1634| m1634_10(unknown) = Chi : total:m1631_9, partial:m1634_9
# 1634| v1634_11(void) = ^IndirectReadSideEffect[-1] : &:r1634_6, m1634_4
# 1634| m1634_12(StructuredBindingTupleRefGet) = ^IndirectMayWriteSideEffect[-1] : &:r1634_6
# 1634| m1634_13(StructuredBindingTupleRefGet) = Chi : total:m1634_4, partial:m1634_12
@@ -12869,7 +13150,7 @@ ir.cpp:
# 1640| m1640_5(int) = Store[w] : &:r1640_1, r1640_4
# 1644| r1644_1(glval) = VariableAddress[unnamed_local_variable] :
# 1644| r1644_2(glval) = VariableAddress[t] :
-# 1644| r1644_3(StructuredBindingTupleRefGet) = Load[t] : &:r1644_2, m1631_8
+# 1644| r1644_3(StructuredBindingTupleRefGet) = Load[t] : &:r1644_2, ~m1638_6
# 1644| m1644_4(StructuredBindingTupleRefGet) = Store[unnamed_local_variable] : &:r1644_1, r1644_3
# 1645| r1645_1(glval) = VariableAddress[i] :
# 1645| r1645_2(glval) = VariableAddress[unnamed_local_variable] :
@@ -12948,19 +13229,73 @@ ir.cpp:
# 1657| void StructuredBindingTupleNoRefGet::StructuredBindingTupleNoRefGet()
# 1657| Block 0
-# 1657| v1657_1(void) = EnterFunction :
-# 1657| m1657_2(unknown) = AliasedDefinition :
-# 1657| m1657_3(unknown) = InitializeNonLocal :
-# 1657| m1657_4(unknown) = Chi : total:m1657_2, partial:m1657_3
-# 1657| r1657_5(glval) = VariableAddress[#this] :
-# 1657| m1657_6(glval) = InitializeParameter[#this] : &:r1657_5
-# 1657| r1657_7(glval) = Load[#this] : &:r1657_5, m1657_6
-# 1657| m1657_8(StructuredBindingTupleNoRefGet) = InitializeIndirection[#this] : &:r1657_7
-# 1657| v1657_9(void) = NoOp :
-# 1657| v1657_10(void) = ReturnIndirection[#this] : &:r1657_7, m1657_8
-# 1657| v1657_11(void) = ReturnVoid :
-# 1657| v1657_12(void) = AliasedUse : m1657_3
-# 1657| v1657_13(void) = ExitFunction :
+# 1657| v1657_1(void) = EnterFunction :
+# 1657| m1657_2(unknown) = AliasedDefinition :
+# 1657| m1657_3(unknown) = InitializeNonLocal :
+# 1657| m1657_4(unknown) = Chi : total:m1657_2, partial:m1657_3
+# 1657| r1657_5(glval) = VariableAddress[#this] :
+# 1657| m1657_6(glval) = InitializeParameter[#this] : &:r1657_5
+# 1657| r1657_7(glval) = Load[#this] : &:r1657_5, m1657_6
+# 1657| m1657_8(StructuredBindingTupleNoRefGet) = InitializeIndirection[#this] : &:r1657_7
+# 1657| m1657_9(unknown) = Chi : total:m1657_4, partial:m1657_8
+# 1657| r1657_10(glval) = FunctionAddress[i] :
+# 1657| v1657_11(void) = Call[i] : func:r1657_10, this:r1657_7
+# 1657| m1657_12(unknown) = ^CallSideEffect : ~m1657_9
+# 1657| m1657_13(unknown) = Chi : total:m1657_9, partial:m1657_12
+# 1657| v1657_14(void) = ^IndirectReadSideEffect[-1] : &:r1657_7, ~m1657_13
+# 1657| m1657_15(StructuredBindingTupleNoRefGet) = ^IndirectMayWriteSideEffect[-1] : &:r1657_7
+# 1657| m1657_16(unknown) = Chi : total:m1657_13, partial:m1657_15
+# 1657| r1657_17(glval) = FunctionAddress[r] :
+# 1657| v1657_18(void) = Call[r] : func:r1657_17, this:r1657_7
+# 1657| m1657_19(unknown) = ^CallSideEffect : ~m1657_16
+# 1657| m1657_20(unknown) = Chi : total:m1657_16, partial:m1657_19
+# 1657| v1657_21(void) = ^IndirectReadSideEffect[-1] : &:r1657_7, ~m1657_20
+# 1657| m1657_22(StructuredBindingTupleNoRefGet) = ^IndirectMayWriteSideEffect[-1] : &:r1657_7
+# 1657| m1657_23(unknown) = Chi : total:m1657_20, partial:m1657_22
+# 1657| v1657_24(void) = NoOp :
+# 1657| v1657_25(void) = ReturnIndirection[#this] : &:r1657_7, ~m1657_23
+# 1657| v1657_26(void) = ReturnVoid :
+# 1657| v1657_27(void) = AliasedUse : ~m1657_23
+# 1657| v1657_28(void) = ExitFunction :
+
+# 1658| int StructuredBindingTupleNoRefGet::i
+# 1658| Block 0
+# 1658| v1658_1(void) = EnterFunction :
+# 1658| m1658_2(unknown) = AliasedDefinition :
+# 1658| m1658_3(unknown) = InitializeNonLocal :
+# 1658| m1658_4(unknown) = Chi : total:m1658_2, partial:m1658_3
+# 1658| r1658_5(glval) = VariableAddress[#this] :
+# 1658| m1658_6(glval) = InitializeParameter[#this] : &:r1658_5
+# 1658| r1658_7(glval) = Load[#this] : &:r1658_5, m1658_6
+# 1658| m1658_8(StructuredBindingTupleNoRefGet) = InitializeIndirection[#this] : &:r1658_7
+# 1658| r1658_9(glval) = FieldAddress[i] : r1658_7
+# 1658| r1658_10(int) = Constant[1] :
+# 1658| m1658_11(int) = Store[?] : &:r1658_9, r1658_10
+# 1658| m1658_12(unknown) = Chi : total:m1658_8, partial:m1658_11
+# 1658| v1658_13(void) = ReturnVoid :
+# 1658| v1658_14(void) = AliasedUse : m1658_3
+# 1658| v1658_15(void) = ExitFunction :
+
+# 1659| int& StructuredBindingTupleNoRefGet::r
+# 1659| Block 0
+# 1659| v1659_1(void) = EnterFunction :
+# 1659| m1659_2(unknown) = AliasedDefinition :
+# 1659| m1659_3(unknown) = InitializeNonLocal :
+# 1659| m1659_4(unknown) = Chi : total:m1659_2, partial:m1659_3
+# 1659| r1659_5(glval) = VariableAddress[#this] :
+# 1659| m1659_6(glval) = InitializeParameter[#this] : &:r1659_5
+# 1659| r1659_7(glval) = Load[#this] : &:r1659_5, m1659_6
+# 1659| m1659_8(StructuredBindingTupleNoRefGet) = InitializeIndirection[#this] : &:r1659_7
+# 1659| m1659_9(unknown) = Chi : total:m1659_4, partial:m1659_8
+# 1659| r1659_10(glval) = FieldAddress[r] : r1659_7
+# 1659| r1659_11(StructuredBindingTupleNoRefGet *) = CopyValue : r1659_7
+# 1659| r1659_12(glval) = FieldAddress[i] : r1659_11
+#-----| r0_1(int &) = CopyValue : r1659_12
+#-----| m0_2(int &) = Store[?] : &:r1659_10, r0_1
+#-----| m0_3(unknown) = Chi : total:m1659_9, partial:m0_2
+# 1659| v1659_13(void) = ReturnVoid :
+# 1659| v1659_14(void) = AliasedUse : ~m0_3
+# 1659| v1659_15(void) = ExitFunction :
# 1684| std::tuple_element::type StructuredBindingTupleNoRefGet::get()
# 1684| Block 0
@@ -13038,12 +13373,13 @@ ir.cpp:
# 1696| m1696_4(unknown) = Chi : total:m1696_2, partial:m1696_3
# 1697| r1697_1(glval) = VariableAddress[t] :
# 1697| m1697_2(StructuredBindingTupleNoRefGet) = Uninitialized[t] : &:r1697_1
-# 1697| r1697_3(glval) = FunctionAddress[StructuredBindingTupleNoRefGet] :
-# 1697| v1697_4(void) = Call[StructuredBindingTupleNoRefGet] : func:r1697_3, this:r1697_1
-# 1697| m1697_5(unknown) = ^CallSideEffect : ~m1696_4
-# 1697| m1697_6(unknown) = Chi : total:m1696_4, partial:m1697_5
-# 1697| m1697_7(StructuredBindingTupleNoRefGet) = ^IndirectMayWriteSideEffect[-1] : &:r1697_1
-# 1697| m1697_8(StructuredBindingTupleNoRefGet) = Chi : total:m1697_2, partial:m1697_7
+# 1697| m1697_3(unknown) = Chi : total:m1696_4, partial:m1697_2
+# 1697| r1697_4(glval) = FunctionAddress[StructuredBindingTupleNoRefGet] :
+# 1697| v1697_5(void) = Call[StructuredBindingTupleNoRefGet] : func:r1697_4, this:r1697_1
+# 1697| m1697_6(unknown) = ^CallSideEffect : ~m1697_3
+# 1697| m1697_7(unknown) = Chi : total:m1697_3, partial:m1697_6
+# 1697| m1697_8(StructuredBindingTupleNoRefGet) = ^IndirectMayWriteSideEffect[-1] : &:r1697_1
+# 1697| m1697_9(unknown) = Chi : total:m1697_7, partial:m1697_8
# 1700| r1700_1(glval) = VariableAddress[(unnamed local variable)] :
# 1700| r1700_2(glval) = VariableAddress[t] :
# 1700| r1700_3(StructuredBindingTupleNoRefGet &) = CopyValue : r1700_2
@@ -13055,11 +13391,11 @@ ir.cpp:
# 1700| r1700_9(glval) = CopyValue : r1700_8
# 1700| r1700_10(glval) = FunctionAddress[get] :
# 1700| r1700_11(int) = Call[get] : func:r1700_10, this:r1700_9
-# 1700| m1700_12(unknown) = ^CallSideEffect : ~m1697_6
-# 1700| m1700_13(unknown) = Chi : total:m1697_6, partial:m1700_12
-# 1700| v1700_14(void) = ^IndirectReadSideEffect[-1] : &:r1700_9, m1697_8
+# 1700| m1700_12(unknown) = ^CallSideEffect : ~m1697_9
+# 1700| m1700_13(unknown) = Chi : total:m1697_9, partial:m1700_12
+# 1700| v1700_14(void) = ^IndirectReadSideEffect[-1] : &:r1700_9, ~m1700_13
# 1700| m1700_15(StructuredBindingTupleNoRefGet) = ^IndirectMayWriteSideEffect[-1] : &:r1700_9
-# 1700| m1700_16(StructuredBindingTupleNoRefGet) = Chi : total:m1697_8, partial:m1700_15
+# 1700| m1700_16(unknown) = Chi : total:m1700_13, partial:m1700_15
# 1700| m1700_17(int) = Store[#temp1700:16] : &:r1700_6, r1700_11
# 1700| r1700_18(int &) = CopyValue : r1700_6
# 1700| m1700_19(int &&) = Store[i] : &:r1700_5, r1700_18
@@ -13069,11 +13405,11 @@ ir.cpp:
# 1700| r1700_23(glval) = CopyValue : r1700_22
# 1700| r1700_24(glval) = FunctionAddress[get] :
# 1700| r1700_25(int &) = Call[get] : func:r1700_24, this:r1700_23
-# 1700| m1700_26(unknown) = ^CallSideEffect : ~m1700_13
-# 1700| m1700_27(unknown) = Chi : total:m1700_13, partial:m1700_26
-# 1700| v1700_28(void) = ^IndirectReadSideEffect[-1] : &:r1700_23, m1700_16
+# 1700| m1700_26(unknown) = ^CallSideEffect : ~m1700_16
+# 1700| m1700_27(unknown) = Chi : total:m1700_16, partial:m1700_26
+# 1700| v1700_28(void) = ^IndirectReadSideEffect[-1] : &:r1700_23, ~m1700_27
# 1700| m1700_29(StructuredBindingTupleNoRefGet) = ^IndirectMayWriteSideEffect[-1] : &:r1700_23
-# 1700| m1700_30(StructuredBindingTupleNoRefGet) = Chi : total:m1700_16, partial:m1700_29
+# 1700| m1700_30(unknown) = Chi : total:m1700_27, partial:m1700_29
# 1700| r1700_31(glval) = CopyValue : r1700_25
# 1700| r1700_32(int &) = CopyValue : r1700_31
# 1700| m1700_33(int &) = Store[r] : &:r1700_20, r1700_32
@@ -13083,11 +13419,11 @@ ir.cpp:
# 1700| r1700_37(glval) = CopyValue : r1700_36
# 1700| r1700_38(glval) = FunctionAddress[get] :
# 1700| r1700_39(int &&) = Call[get] : func:r1700_38, this:r1700_37
-# 1700| m1700_40(unknown) = ^CallSideEffect : ~m1700_27
-# 1700| m1700_41(unknown) = Chi : total:m1700_27, partial:m1700_40
-# 1700| v1700_42(void) = ^IndirectReadSideEffect[-1] : &:r1700_37, m1700_30
+# 1700| m1700_40(unknown) = ^CallSideEffect : ~m1700_30
+# 1700| m1700_41(unknown) = Chi : total:m1700_30, partial:m1700_40
+# 1700| v1700_42(void) = ^IndirectReadSideEffect[-1] : &:r1700_37, ~m1700_41
# 1700| m1700_43(StructuredBindingTupleNoRefGet) = ^IndirectMayWriteSideEffect[-1] : &:r1700_37
-# 1700| m1700_44(StructuredBindingTupleNoRefGet) = Chi : total:m1700_30, partial:m1700_43
+# 1700| m1700_44(unknown) = Chi : total:m1700_41, partial:m1700_43
# 1700| r1700_45(glval) = CopyValue : r1700_39
# 1700| r1700_46(int &) = CopyValue : r1700_45
# 1700| m1700_47(int &&) = Store[rv] : &:r1700_34, r1700_46
@@ -13112,7 +13448,7 @@ ir.cpp:
# 1704| r1704_3(int &) = Load[r] : &:r1704_2, m1700_33
# 1704| r1704_4(glval) = CopyValue : r1704_3
# 1704| m1704_5(int) = Store[?] : &:r1704_4, r1704_1
-# 1704| m1704_6(unknown) = Chi : total:m1700_41, partial:m1704_5
+# 1704| m1704_6(unknown) = Chi : total:m1700_44, partial:m1704_5
# 1705| r1705_1(glval) = VariableAddress[rr] :
# 1705| r1705_2(glval) = VariableAddress[r] :
# 1705| r1705_3(int &) = Load[r] : &:r1705_2, m1700_33
@@ -13137,9 +13473,9 @@ ir.cpp:
# 1711| r1711_7(int) = Call[get] : func:r1711_6, this:r1711_5
# 1711| m1711_8(unknown) = ^CallSideEffect : ~m1704_6
# 1711| m1711_9(unknown) = Chi : total:m1704_6, partial:m1711_8
-# 1711| v1711_10(void) = ^IndirectReadSideEffect[-1] : &:r1711_5, m1700_44
+# 1711| v1711_10(void) = ^IndirectReadSideEffect[-1] : &:r1711_5, ~m1711_9
# 1711| m1711_11(StructuredBindingTupleNoRefGet) = ^IndirectMayWriteSideEffect[-1] : &:r1711_5
-# 1711| m1711_12(StructuredBindingTupleNoRefGet) = Chi : total:m1700_44, partial:m1711_11
+# 1711| m1711_12(unknown) = Chi : total:m1711_9, partial:m1711_11
# 1711| m1711_13(int) = Store[#temp1711:20] : &:r1711_2, r1711_7
# 1711| r1711_14(int &) = CopyValue : r1711_2
# 1711| m1711_15(int &&) = Store[i] : &:r1711_1, r1711_14
@@ -13149,11 +13485,11 @@ ir.cpp:
# 1712| r1712_4(glval) = CopyValue : r1712_3
# 1712| r1712_5(glval) = FunctionAddress[get] :
# 1712| r1712_6(int &) = Call[get] : func:r1712_5, this:r1712_4
-# 1712| m1712_7(unknown) = ^CallSideEffect : ~m1711_9
-# 1712| m1712_8(unknown) = Chi : total:m1711_9, partial:m1712_7
-# 1712| v1712_9(void) = ^IndirectReadSideEffect[-1] : &:r1712_4, m1711_12
+# 1712| m1712_7(unknown) = ^CallSideEffect : ~m1711_12
+# 1712| m1712_8(unknown) = Chi : total:m1711_12, partial:m1712_7
+# 1712| v1712_9(void) = ^IndirectReadSideEffect[-1] : &:r1712_4, ~m1712_8
# 1712| m1712_10(StructuredBindingTupleNoRefGet) = ^IndirectMayWriteSideEffect[-1] : &:r1712_4
-# 1712| m1712_11(StructuredBindingTupleNoRefGet) = Chi : total:m1711_12, partial:m1712_10
+# 1712| m1712_11(unknown) = Chi : total:m1712_8, partial:m1712_10
# 1712| r1712_12(glval) = CopyValue : r1712_6
# 1712| r1712_13(int &) = CopyValue : r1712_12
# 1712| m1712_14(int &) = Store[r] : &:r1712_1, r1712_13
@@ -13163,11 +13499,11 @@ ir.cpp:
# 1713| r1713_4(glval) = CopyValue : r1713_3
# 1713| r1713_5(glval) = FunctionAddress[get] :
# 1713| r1713_6(int &&) = Call[get] : func:r1713_5, this:r1713_4
-# 1713| m1713_7(unknown) = ^CallSideEffect : ~m1712_8
-# 1713| m1713_8(unknown) = Chi : total:m1712_8, partial:m1713_7
-# 1713| v1713_9(void) = ^IndirectReadSideEffect[-1] : &:r1713_4, m1712_11
+# 1713| m1713_7(unknown) = ^CallSideEffect : ~m1712_11
+# 1713| m1713_8(unknown) = Chi : total:m1712_11, partial:m1713_7
+# 1713| v1713_9(void) = ^IndirectReadSideEffect[-1] : &:r1713_4, ~m1713_8
# 1713| m1713_10(StructuredBindingTupleNoRefGet) = ^IndirectMayWriteSideEffect[-1] : &:r1713_4
-# 1713| m1713_11(StructuredBindingTupleNoRefGet) = Chi : total:m1712_11, partial:m1713_10
+# 1713| m1713_11(unknown) = Chi : total:m1713_8, partial:m1713_10
# 1713| r1713_12(glval) = CopyValue : r1713_6
# 1713| r1713_13(int &) = CopyValue : r1713_12
# 1713| m1713_14(int &&) = Store[rv] : &:r1713_1, r1713_13
@@ -13192,7 +13528,7 @@ ir.cpp:
# 1717| r1717_3(int &) = Load[r] : &:r1717_2, m1712_14
# 1717| r1717_4(glval) = CopyValue : r1717_3
# 1717| m1717_5(int) = Store[?] : &:r1717_4, r1717_1
-# 1717| m1717_6(unknown) = Chi : total:m1713_8, partial:m1717_5
+# 1717| m1717_6(unknown) = Chi : total:m1713_11, partial:m1717_5
# 1718| r1718_1(glval) = VariableAddress[rr] :
# 1718| r1718_2(glval) = VariableAddress[r] :
# 1718| r1718_3(int &) = Load[r] : &:r1718_2, m1712_14
@@ -21066,6 +21402,376 @@ ir.cpp:
# 2867| v2867_14(void) = ReturnVoid :
#-----| Goto -> Block 1
+# 2890| int StructInit::i
+# 2890| Block 0
+# 2890| v2890_1(void) = EnterFunction :
+# 2890| m2890_2(unknown) = AliasedDefinition :
+# 2890| m2890_3(unknown) = InitializeNonLocal :
+# 2890| m2890_4(unknown) = Chi : total:m2890_2, partial:m2890_3
+# 2890| r2890_5(glval) = VariableAddress[#this] :
+# 2890| m2890_6(glval) = InitializeParameter[#this] : &:r2890_5
+# 2890| r2890_7(glval) = Load[#this] : &:r2890_5, m2890_6
+# 2890| m2890_8(StructInit) = InitializeIndirection[#this] : &:r2890_7
+# 2890| r2890_9(glval) = FieldAddress[i] : r2890_7
+# 2890| r2890_10(int) = Constant[42] :
+# 2890| m2890_11(int) = Store[?] : &:r2890_9, r2890_10
+# 2890| m2890_12(unknown) = Chi : total:m2890_8, partial:m2890_11
+# 2890| v2890_13(void) = ReturnVoid :
+# 2890| v2890_14(void) = AliasedUse : m2890_3
+# 2890| v2890_15(void) = ExitFunction :
+
+# 2891| int StructInit::j
+# 2891| Block 0
+# 2891| v2891_1(void) = EnterFunction :
+# 2891| m2891_2(unknown) = AliasedDefinition :
+# 2891| m2891_3(unknown) = InitializeNonLocal :
+# 2891| m2891_4(unknown) = Chi : total:m2891_2, partial:m2891_3
+# 2891| r2891_5(glval) = VariableAddress[#this] :
+# 2891| m2891_6(glval) = InitializeParameter[#this] : &:r2891_5
+# 2891| r2891_7(glval) = Load[#this] : &:r2891_5, m2891_6
+# 2891| m2891_8(StructInit) = InitializeIndirection[#this] : &:r2891_7
+# 2891| r2891_9(glval) = FieldAddress[j] : r2891_7
+# 2891| r2891_10(int) = Constant[42] :
+# 2891| m2891_11(int) = Store[?] : &:r2891_9, r2891_10
+# 2891| m2891_12(unknown) = Chi : total:m2891_8, partial:m2891_11
+# 2891| v2891_13(void) = ReturnVoid :
+# 2891| v2891_14(void) = AliasedUse : m2891_3
+# 2891| v2891_15(void) = ExitFunction :
+
+# 2892| int StructInit::k
+# 2892| Block 0
+# 2892| v2892_1(void) = EnterFunction :
+# 2892| m2892_2(unknown) = AliasedDefinition :
+# 2892| m2892_3(unknown) = InitializeNonLocal :
+# 2892| m2892_4(unknown) = Chi : total:m2892_2, partial:m2892_3
+# 2892| r2892_5(glval) = VariableAddress[#this] :
+# 2892| m2892_6(glval) = InitializeParameter[#this] : &:r2892_5
+# 2892| r2892_7(glval) = Load[#this] : &:r2892_5, m2892_6
+# 2892| m2892_8(StructInit) = InitializeIndirection[#this] : &:r2892_7
+# 2892| r2892_9(glval) = FieldAddress[k] : r2892_7
+# 2892| r2892_10(int) = Constant[42] :
+# 2892| m2892_11(int) = Store[?] : &:r2892_9, r2892_10
+# 2892| m2892_12(unknown) = Chi : total:m2892_8, partial:m2892_11
+# 2892| v2892_13(void) = ReturnVoid :
+# 2892| v2892_14(void) = AliasedUse : m2892_3
+# 2892| v2892_15(void) = ExitFunction :
+
+# 2893| int StructInit::l
+# 2893| Block 0
+# 2893| v2893_1(void) = EnterFunction :
+# 2893| m2893_2(unknown) = AliasedDefinition :
+# 2893| m2893_3(unknown) = InitializeNonLocal :
+# 2893| m2893_4(unknown) = Chi : total:m2893_2, partial:m2893_3
+# 2893| r2893_5(glval) = VariableAddress[#this] :
+# 2893| m2893_6(glval) = InitializeParameter[#this] : &:r2893_5
+# 2893| r2893_7(glval) = Load[#this] : &:r2893_5, m2893_6
+# 2893| m2893_8(StructInit) = InitializeIndirection[#this] : &:r2893_7
+# 2893| r2893_9(glval) = FieldAddress[l] : r2893_7
+# 2893| r2893_10(StructInit *) = CopyValue : r2893_7
+# 2893| r2893_11(glval) = FieldAddress[k] : r2893_10
+# 2893| r2893_12(int) = Load[?] : &:r2893_11, ~m2893_8
+# 2893| m2893_13(int) = Store[?] : &:r2893_9, r2893_12
+# 2893| m2893_14(unknown) = Chi : total:m2893_8, partial:m2893_13
+# 2893| v2893_15(void) = ReturnVoid :
+# 2893| v2893_16(void) = AliasedUse : m2893_3
+# 2893| v2893_17(void) = ExitFunction :
+
+# 2894| int StructInit::m
+# 2894| Block 0
+# 2894| v2894_1(void) = EnterFunction :
+# 2894| m2894_2(unknown) = AliasedDefinition :
+# 2894| m2894_3(unknown) = InitializeNonLocal :
+# 2894| m2894_4(unknown) = Chi : total:m2894_2, partial:m2894_3
+# 2894| r2894_5(glval) = VariableAddress[#this] :
+# 2894| m2894_6(glval) = InitializeParameter[#this] : &:r2894_5
+# 2894| r2894_7(glval) = Load[#this] : &:r2894_5, m2894_6
+# 2894| m2894_8(StructInit) = InitializeIndirection[#this] : &:r2894_7
+# 2894| r2894_9(glval) = FieldAddress[m] : r2894_7
+# 2894| r2894_10(StructInit *) = CopyValue : r2894_7
+# 2894| r2894_11(glval) = FunctionAddress[get_val] :
+# 2894| r2894_12(int) = Call[get_val] : func:r2894_11, this:r2894_10
+# 2894| m2894_13(unknown) = ^CallSideEffect : ~m2894_4
+# 2894| m2894_14(unknown) = Chi : total:m2894_4, partial:m2894_13
+# 2894| v2894_15(void) = ^IndirectReadSideEffect[-1] : &:r2894_10, ~m2894_8
+# 2894| m2894_16(StructInit) = ^IndirectMayWriteSideEffect[-1] : &:r2894_10
+# 2894| m2894_17(unknown) = Chi : total:m2894_8, partial:m2894_16
+# 2894| m2894_18(int) = Store[?] : &:r2894_9, r2894_12
+# 2894| m2894_19(unknown) = Chi : total:m2894_17, partial:m2894_18
+# 2894| v2894_20(void) = ReturnVoid :
+# 2894| v2894_21(void) = AliasedUse : ~m2894_14
+# 2894| v2894_22(void) = ExitFunction :
+
+# 2895| int StructInit::n
+# 2895| Block 0
+# 2895| v2895_1(void) = EnterFunction :
+# 2895| m2895_2(unknown) = AliasedDefinition :
+# 2895| m2895_3(unknown) = InitializeNonLocal :
+# 2895| m2895_4(unknown) = Chi : total:m2895_2, partial:m2895_3
+# 2895| r2895_5(glval) = VariableAddress[#this] :
+# 2895| m2895_6(glval) = InitializeParameter[#this] : &:r2895_5
+# 2895| r2895_7(glval) = Load[#this] : &:r2895_5, m2895_6
+# 2895| m2895_8(StructInit) = InitializeIndirection[#this] : &:r2895_7
+# 2895| r2895_9(glval) = FieldAddress[n] : r2895_7
+# 2895| r2895_10(int) = Constant[42] :
+# 2895| m2895_11(int) = Store[?] : &:r2895_9, r2895_10
+# 2895| m2895_12(unknown) = Chi : total:m2895_8, partial:m2895_11
+# 2895| v2895_13(void) = ReturnVoid :
+# 2895| v2895_14(void) = AliasedUse : m2895_3
+# 2895| v2895_15(void) = ExitFunction :
+
+# 2897| void StructInit::StructInit(int)
+# 2897| Block 0
+# 2897| v2897_1(void) = EnterFunction :
+# 2897| m2897_2(unknown) = AliasedDefinition :
+# 2897| m2897_3(unknown) = InitializeNonLocal :
+# 2897| m2897_4(unknown) = Chi : total:m2897_2, partial:m2897_3
+# 2897| r2897_5(glval) = VariableAddress[#this] :
+# 2897| m2897_6(glval) = InitializeParameter[#this] : &:r2897_5
+# 2897| r2897_7(glval) = Load[#this] : &:r2897_5, m2897_6
+# 2897| m2897_8(StructInit) = InitializeIndirection[#this] : &:r2897_7
+# 2897| m2897_9(unknown) = Chi : total:m2897_4, partial:m2897_8
+# 2897| r2897_10(glval) = VariableAddress[j] :
+# 2897| m2897_11(int) = InitializeParameter[j] : &:r2897_10
+# 2897| r2897_12(glval) = FunctionAddress[i] :
+# 2897| v2897_13(void) = Call[i] : func:r2897_12, this:r2897_7
+# 2897| m2897_14(unknown) = ^CallSideEffect : ~m2897_9
+# 2897| m2897_15(unknown) = Chi : total:m2897_9, partial:m2897_14
+# 2897| v2897_16(void) = ^IndirectReadSideEffect[-1] : &:r2897_7, ~m2897_15
+# 2897| m2897_17(StructInit) = ^IndirectMayWriteSideEffect[-1] : &:r2897_7
+# 2897| m2897_18(unknown) = Chi : total:m2897_15, partial:m2897_17
+# 2897| r2897_19(glval) = FieldAddress[j] : r2897_7
+# 2897| r2897_20(glval) = VariableAddress[j] :
+# 2897| r2897_21(int) = Load[j] : &:r2897_20, m2897_11
+# 2897| m2897_22(int) = Store[?] : &:r2897_19, r2897_21
+# 2897| m2897_23(unknown) = Chi : total:m2897_18, partial:m2897_22
+# 2897| r2897_24(glval) = FunctionAddress[k] :
+# 2897| v2897_25(void) = Call[k] : func:r2897_24, this:r2897_7
+# 2897| m2897_26(unknown) = ^CallSideEffect : ~m2897_23
+# 2897| m2897_27(unknown) = Chi : total:m2897_23, partial:m2897_26
+# 2897| v2897_28(void) = ^IndirectReadSideEffect[-1] : &:r2897_7, ~m2897_27
+# 2897| m2897_29(StructInit) = ^IndirectMayWriteSideEffect[-1] : &:r2897_7
+# 2897| m2897_30(unknown) = Chi : total:m2897_27, partial:m2897_29
+# 2897| r2897_31(glval) = FunctionAddress[l] :
+# 2897| v2897_32(void) = Call[l] : func:r2897_31, this:r2897_7
+# 2897| m2897_33(unknown) = ^CallSideEffect : ~m2897_30
+# 2897| m2897_34(unknown) = Chi : total:m2897_30, partial:m2897_33
+# 2897| v2897_35(void) = ^IndirectReadSideEffect[-1] : &:r2897_7, ~m2897_34
+# 2897| m2897_36(StructInit) = ^IndirectMayWriteSideEffect[-1] : &:r2897_7
+# 2897| m2897_37(unknown) = Chi : total:m2897_34, partial:m2897_36
+# 2897| r2897_38(glval) = FunctionAddress[m] :
+# 2897| v2897_39(void) = Call[m] : func:r2897_38, this:r2897_7
+# 2897| m2897_40(unknown) = ^CallSideEffect : ~m2897_37
+# 2897| m2897_41(unknown) = Chi : total:m2897_37, partial:m2897_40
+# 2897| v2897_42(void) = ^IndirectReadSideEffect[-1] : &:r2897_7, ~m2897_41
+# 2897| m2897_43(StructInit) = ^IndirectMayWriteSideEffect[-1] : &:r2897_7
+# 2897| m2897_44(unknown) = Chi : total:m2897_41, partial:m2897_43
+# 2897| r2897_45(glval) = FieldAddress[n] : r2897_7
+# 2897| r2897_46(glval) = VariableAddress[#this] :
+# 2897| r2897_47(StructInit *) = Load[#this] : &:r2897_46, m2897_6
+# 2897| r2897_48(glval) = FunctionAddress[get_val] :
+# 2897| r2897_49(int) = Call[get_val] : func:r2897_48, this:r2897_47
+# 2897| m2897_50(unknown) = ^CallSideEffect : ~m2897_44
+# 2897| m2897_51(unknown) = Chi : total:m2897_44, partial:m2897_50
+# 2897| v2897_52(void) = ^IndirectReadSideEffect[-1] : &:r2897_47, ~m2897_51
+# 2897| m2897_53(StructInit) = ^IndirectMayWriteSideEffect[-1] : &:r2897_47
+# 2897| m2897_54(unknown) = Chi : total:m2897_51, partial:m2897_53
+# 2897| m2897_55(int) = Store[?] : &:r2897_45, r2897_49
+# 2897| m2897_56(unknown) = Chi : total:m2897_54, partial:m2897_55
+# 2897| v2897_57(void) = NoOp :
+# 2897| v2897_58(void) = ReturnIndirection[#this] : &:r2897_7, ~m2897_56
+# 2897| v2897_59(void) = ReturnVoid :
+# 2897| v2897_60(void) = AliasedUse : ~m2897_56
+# 2897| v2897_61(void) = ExitFunction :
+
+# 2899| void StructInit::StructInit()
+# 2899| Block 0
+# 2899| v2899_1(void) = EnterFunction :
+# 2899| m2899_2(unknown) = AliasedDefinition :
+# 2899| m2899_3(unknown) = InitializeNonLocal :
+# 2899| m2899_4(unknown) = Chi : total:m2899_2, partial:m2899_3
+# 2899| r2899_5(glval) = VariableAddress[#this] :
+# 2899| m2899_6(glval) = InitializeParameter[#this] : &:r2899_5
+# 2899| r2899_7(glval) = Load[#this] : &:r2899_5, m2899_6
+# 2899| m2899_8(StructInit) = InitializeIndirection[#this] : &:r2899_7
+# 2899| m2899_9(unknown) = Chi : total:m2899_4, partial:m2899_8
+# 2899| r2899_10(glval) = FieldAddress[i] : r2899_7
+# 2899| r2899_11(int) = Constant[41] :
+# 2899| m2899_12(int) = Store[?] : &:r2899_10, r2899_11
+# 2899| m2899_13(unknown) = Chi : total:m2899_9, partial:m2899_12
+# 2899| r2899_14(glval) = FunctionAddress[j] :
+# 2899| v2899_15(void) = Call[j] : func:r2899_14, this:r2899_7
+# 2899| m2899_16(unknown) = ^CallSideEffect : ~m2899_13
+# 2899| m2899_17(unknown) = Chi : total:m2899_13, partial:m2899_16
+# 2899| v2899_18(void) = ^IndirectReadSideEffect[-1] : &:r2899_7, ~m2899_17
+# 2899| m2899_19(StructInit) = ^IndirectMayWriteSideEffect[-1] : &:r2899_7
+# 2899| m2899_20(unknown) = Chi : total:m2899_17, partial:m2899_19
+# 2899| r2899_21(glval) = FieldAddress[k] : r2899_7
+# 2899| r2899_22(int) = Constant[41] :
+# 2899| m2899_23(int) = Store[?] : &:r2899_21, r2899_22
+# 2899| m2899_24(unknown) = Chi : total:m2899_20, partial:m2899_23
+# 2899| r2899_25(glval) = FunctionAddress[l] :
+# 2899| v2899_26(void) = Call[l] : func:r2899_25, this:r2899_7
+# 2899| m2899_27(unknown) = ^CallSideEffect : ~m2899_24
+# 2899| m2899_28(unknown) = Chi : total:m2899_24, partial:m2899_27
+# 2899| v2899_29(void) = ^IndirectReadSideEffect[-1] : &:r2899_7, ~m2899_28
+# 2899| m2899_30(StructInit) = ^IndirectMayWriteSideEffect[-1] : &:r2899_7
+# 2899| m2899_31(unknown) = Chi : total:m2899_28, partial:m2899_30
+# 2899| r2899_32(glval) = FunctionAddress[m] :
+# 2899| v2899_33(void) = Call[m] : func:r2899_32, this:r2899_7
+# 2899| m2899_34(unknown) = ^CallSideEffect : ~m2899_31
+# 2899| m2899_35(unknown) = Chi : total:m2899_31, partial:m2899_34
+# 2899| v2899_36(void) = ^IndirectReadSideEffect[-1] : &:r2899_7, ~m2899_35
+# 2899| m2899_37(StructInit) = ^IndirectMayWriteSideEffect[-1] : &:r2899_7
+# 2899| m2899_38(unknown) = Chi : total:m2899_35, partial:m2899_37
+# 2899| r2899_39(glval) = FunctionAddress[n] :
+# 2899| v2899_40(void) = Call[n] : func:r2899_39, this:r2899_7
+# 2899| m2899_41(unknown) = ^CallSideEffect : ~m2899_38
+# 2899| m2899_42(unknown) = Chi : total:m2899_38, partial:m2899_41
+# 2899| v2899_43(void) = ^IndirectReadSideEffect[-1] : &:r2899_7, ~m2899_42
+# 2899| m2899_44(StructInit) = ^IndirectMayWriteSideEffect[-1] : &:r2899_7
+# 2899| m2899_45(unknown) = Chi : total:m2899_42, partial:m2899_44
+# 2899| v2899_46(void) = NoOp :
+# 2899| v2899_47(void) = ReturnIndirection[#this] : &:r2899_7, ~m2899_45
+# 2899| v2899_48(void) = ReturnVoid :
+# 2899| v2899_49(void) = AliasedUse : ~m2899_45
+# 2899| v2899_50(void) = ExitFunction :
+
+# 2901| int StructInit::get_val()
+# 2901| Block 0
+# 2901| v2901_1(void) = EnterFunction :
+# 2901| m2901_2(unknown) = AliasedDefinition :
+# 2901| m2901_3(unknown) = InitializeNonLocal :
+# 2901| m2901_4(unknown) = Chi : total:m2901_2, partial:m2901_3
+# 2901| r2901_5(glval