Compare commits

..

1 Commits

Author SHA1 Message Date
Chris Smowton
cd79bc51dd Kotlin: drop same-file requirement for overridden parameter labels 2022-11-02 19:29:33 +00:00
1804 changed files with 90193 additions and 142069 deletions

View File

@@ -0,0 +1,24 @@
---
name: LGTM.com - false positive
about: Tell us about an alert that shouldn't be reported
title: LGTM.com - false positive
labels: false-positive
assignees: ''
---
**Description of the false positive**
<!-- Please explain briefly why you think it shouldn't be included. -->
**URL to the alert on the project page on LGTM.com**
<!--
1. Open the project on LGTM.com.
For example, https://lgtm.com/projects/g/pallets/click/.
2. Switch to the `Alerts` tab. For example, https://lgtm.com/projects/g/pallets/click/alerts/.
3. Scroll to the alert that you would like to report.
4. Click on the right most icon `View this alert within the complete file`.
5. A new browser tab opens. Copy and paste the page URL here.
For example, https://lgtm.com/projects/g/pallets/click/snapshot/719fb7d8322b0767cdd1e5903ba3eb3233ba8dd5/files/click/_winconsole.py#xa08d213ab3289f87:1.
-->

View File

@@ -1,36 +0,0 @@
---
name: CodeQL False positive
about: Report CodeQL alerts that you think should not have been detected (not applicable, not exploitable, etc.)
title: False positive
labels: false-positive
assignees: ''
---
**Description of the false positive**
<!-- Please explain briefly why you think it shouldn't be included. -->
**Code samples or links to source code**
<!--
For open source code: file links with line numbers on GitHub, for example:
https://github.com/github/codeql/blob/dc440aaee6695deb0d9676b87e06ea984e1b4ae5/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/exec-sh2.js#L10
For closed source code: (redacted) code samples that illustrate the problem, for example:
```
function execSh(command, options) {
return cp.spawn(getShell(), ["-c", command], options) // <- command line injection
};
```
-->
**URL to the alert on GitHub code scanning (optional)**
<!--
1. Open the project on GitHub.com.
2. Switch to the `Security` tab.
3. Browse to the alert that you would like to report.
4. Copy and paste the page URL here.
-->

View File

@@ -1,61 +0,0 @@
name: Cache query compilation
description: Caches CodeQL compilation caches - should be run both on PRs and pushes to main.
inputs:
key:
description: 'The cache key to use - should be unique to the workflow'
required: true
outputs:
cache-dir:
description: "The directory where the cache was stored"
value: ${{ steps.fill-compilation-dir.outputs.compdir }}
runs:
using: composite
steps:
# Cache the query compilation caches.
# calculate the merge-base with main, in a way that works both on PRs and pushes to main.
- name: Calculate merge-base
shell: bash
if: ${{ github.event_name == 'pull_request' }}
env:
BASE_BRANCH: ${{ github.base_ref }}
run: |
MERGE_BASE=$(git cat-file commit $GITHUB_SHA | grep '^parent ' | head -1 | cut -f 2 -d " ")
echo "merge_base=$MERGE_BASE" >> $GITHUB_ENV
- name: Read CodeQL query compilation - PR
if: ${{ github.event_name == 'pull_request' }}
uses: erik-krogh/actions-cache@a88d0603fe5fb5606db9f002dfcadeb32b5f84c6
with:
path: '**/.cache'
read-only: true
key: codeql-compile-${{ inputs.key }}-pr-${{ github.sha }} # deliberately not using the `compile-compile-main` keys here.
restore-keys: |
codeql-compile-${{ inputs.key }}-${{ github.base_ref }}-${{ env.merge_base }}
codeql-compile-${{ inputs.key }}-${{ github.base_ref }}-
codeql-compile-${{ inputs.key }}-main-
- name: Fill CodeQL query compilation cache - main
if: ${{ github.event_name != 'pull_request' }}
uses: erik-krogh/actions-cache@a88d0603fe5fb5606db9f002dfcadeb32b5f84c6
with:
path: '**/.cache'
key: codeql-compile-${{ inputs.key }}-${{ github.ref_name }}-${{ github.sha }} # just fill on main
restore-keys: | # restore from another random commit, to speed up compilation.
codeql-compile-${{ inputs.key }}-${{ github.ref_name }}-
codeql-compile-${{ inputs.key }}-main-
- name: Fill compilation cache directory
id: fill-compilation-dir
shell: bash
run: |
# Move all the existing cache into another folder, so we only preserve the cache for the current queries.
mkdir -p ${COMBINED_CACHE_DIR}
rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty.
# copy the contents of the .cache folders into the combined cache folder.
cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files
# clean up the .cache folders
rm -rf **/.cache/*
echo "compdir=${COMBINED_CACHE_DIR}" >> $GITHUB_OUTPUT
env:
COMBINED_CACHE_DIR: ${{ github.workspace }}/compilation-dir

View File

@@ -1,22 +1,14 @@
name: Fetch CodeQL
description: Fetches the latest version of CodeQL
inputs:
channel:
description: 'The CodeQL channel to use'
required: false
default: 'nightly'
runs:
using: composite
steps:
- name: Fetch CodeQL
shell: bash
env:
GITHUB_TOKEN: ${{ github.token }}
CHANNEL: ${{ inputs.channel }}
run: |
gh extension install github/gh-codeql
gh codeql set-channel "$CHANNEL"
gh codeql set-channel nightly
gh codeql version
gh codeql version --format=json | jq -r .unpackedLocation >> "${GITHUB_PATH}"
env:
GITHUB_TOKEN: ${{ github.token }}

3
.github/labeler.yml vendored
View File

@@ -51,6 +51,3 @@ documentation:
- "java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
- "java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll"
- "java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll"
"ATM":
- javascript/ql/experimental/adaptivethreatmodeling/**/*

View File

@@ -0,0 +1,56 @@
name: ATM Check Queries Run
env:
DB_PATH: test_db
ATM_MODEL_PACK: javascript/ql/experimental/adaptivethreatmodeling/src
QUERY_SUITE: codeql-suites/javascript-atm-code-scanning.qls
on:
pull_request:
paths:
- ".github/workflows/atm-check-queries-run.yml"
- "javascript/ql/experimental/adaptivethreatmodeling/**"
workflow_dispatch:
jobs:
run-atm-queries:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install CodeQL CLI
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh extensions install github/gh-codeql
gh codeql download
- name: Install ATM model pack
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -exu
# Install ATM model pack
gh codeql pack install ${ATM_MODEL_PACK}
# Retrieve model checksum
model_checksum=$(gh codeql resolve extensions ${ATM_MODEL_PACK}/${QUERY_SUITE} | jq -r '.models[0].checksum')
# Trust the model so that we can use it in the ATM boosted queries
mkdir -p "$HOME/.config/codeql"
echo "--insecurely-execute-ml-model-checksums ${model_checksum}" >> "$HOME/.config/codeql/config"
- name: Create test DB
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh codeql database create ${RUNNER_TEMP}/${DB_PATH} --source-root config/atm/ --language javascript
- name: Run ATM query suite
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh codeql database run-queries -vv -- ${RUNNER_TEMP}/${DB_PATH} ${ATM_MODEL_PACK}/${QUERY_SUITE}

View File

@@ -1,93 +0,0 @@
name: "ATM - Check query suite"
env:
QUERY_PACK: javascript/ql/experimental/adaptivethreatmodeling/src
QUERY_SUITE: codeql-suites/javascript-atm-code-scanning.qls
on:
pull_request:
paths:
- ".github/workflows/atm-check-query-suite.yml"
- "javascript/ql/experimental/adaptivethreatmodeling/**"
workflow_dispatch:
jobs:
atm-check-query-suite:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup CodeQL
uses: ./.github/actions/fetch-codeql
with:
channel: release
- name: Install ATM model
run: |
set -exu
# Install dependencies of ATM query pack, i.e. the ATM model
codeql pack install "${QUERY_PACK}"
# Retrieve model checksum
model_checksum=$(codeql resolve extensions "${QUERY_PACK}/${QUERY_SUITE}" | jq -r '.models[0].checksum')
# Trust the model so that we can use it in the ATM boosted queries
mkdir -p "$HOME/.config/codeql"
echo "--insecurely-execute-ml-model-checksums ${model_checksum}" >> "$HOME/.config/codeql/config"
- name: Create test DB
run: |
DB_PATH="${RUNNER_TEMP}/db"
echo "DB_PATH=${DB_PATH}" >> "${GITHUB_ENV}"
codeql database create "${DB_PATH}" --source-root config/atm --language javascript
- name: Run ATM query suite
run: |
SARIF_PATH="${RUNNER_TEMP}/sarif.json"
echo "SARIF_PATH=${SARIF_PATH}" >> "${GITHUB_ENV}"
codeql database analyze \
--format sarif-latest \
--output "${SARIF_PATH}" \
--sarif-group-rules-by-pack \
-vv \
-- \
"${DB_PATH}" \
"${QUERY_PACK}/${QUERY_SUITE}"
- name: Upload SARIF
uses: actions/upload-artifact@v3
with:
name: javascript-ml-powered-queries.sarif
path: "${{ env.SARIF_PATH }}"
retention-days: 5
- name: Check results
run: |
# We should run at least the ML-powered queries in `expected_rules`.
expected_rules="js/ml-powered/nosql-injection js/ml-powered/path-injection js/ml-powered/sql-injection js/ml-powered/xss"
for rule in ${expected_rules}; do
found_rule=$(jq --arg rule "${rule}" '[.runs[0].tool.extensions[].rules | select(. != null) |
flatten | .[].id] | any(. == $rule)' "${SARIF_PATH}")
if [[ "${found_rule}" != "true" ]]; then
echo "Expected SARIF output to contain rule '${rule}', but found no such rule."
exit 1
else
echo "Found rule '${rule}'."
fi
done
# We should have at least one alert from an ML-powered query.
num_alerts=$(jq '[.runs[0].results[] |
select(.properties.score != null and (.rule.id | startswith("js/ml-powered/")))] | length' \
"${SARIF_PATH}")
if [[ "${num_alerts}" -eq 0 ]]; then
echo "Expected to find at least one alert from an ML-powered query but found ${num_alerts}."
exit 1
else
echo "Found ${num_alerts} alerts from ML-powered queries.";
fi

View File

@@ -1,39 +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:
jobs:
compile-queries:
runs-on: ubuntu-latest-xl
steps:
- uses: actions/checkout@v3
- 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: all-queries
- name: check formatting
run: find */ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 codeql query format --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 -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
- 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 -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
env:
COMBINED_CACHE_DIR: ${{ github.workspace }}/compilation-dir

View File

@@ -1,86 +0,0 @@
name: "C#: Run QL Tests"
on:
push:
paths:
- "csharp/**"
- "shared/**"
- .github/actions/fetch-codeql/action.yml
- codeql-workspace.yml
branches:
- main
- "rc/*"
pull_request:
paths:
- "csharp/**"
- "shared/**"
- .github/workflows/csharp-qltest.yml
- .github/actions/fetch-codeql/action.yml
- codeql-workspace.yml
branches:
- main
- "rc/*"
defaults:
run:
working-directory: csharp
jobs:
qlupgrade:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/fetch-codeql
- name: Check DB upgrade scripts
run: |
echo >empty.trap
codeql dataset import -S ql/lib/upgrades/initial/semmlecode.csharp.dbscheme testdb empty.trap
codeql dataset upgrade testdb --additional-packs ql/lib
diff -q testdb/semmlecode.csharp.dbscheme ql/lib/semmlecode.csharp.dbscheme
- name: Check DB downgrade scripts
run: |
echo >empty.trap
rm -rf testdb; codeql dataset import -S ql/lib/semmlecode.csharp.dbscheme testdb empty.trap
codeql resolve upgrades --format=lines --allow-downgrades --additional-packs downgrades \
--dbscheme=ql/lib/semmlecode.csharp.dbscheme --target-dbscheme=downgrades/initial/semmlecode.csharp.dbscheme |
xargs codeql execute upgrades testdb
diff -q testdb/semmlecode.csharp.dbscheme downgrades/initial/semmlecode.csharp.dbscheme
qltest:
runs-on: ubuntu-latest-xl
strategy:
fail-fast: false
matrix:
slice: ["1/2", "2/2"]
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/fetch-codeql
- uses: ./csharp/actions/create-extractor-pack
- name: Cache compilation cache
id: query-cache
uses: ./.github/actions/cache-query-compilation
with:
key: csharp-qltest-${{ matrix.slice }}
- name: Run QL tests
run: |
CODEQL_PATH=$(gh codeql version --format=json | jq -r .unpackedLocation)
# The legacy ASP extractor is not in this repo, so take the one from the nightly build
mv "$CODEQL_PATH/csharp/tools/extractor-asp.jar" "${{ github.workspace }}/csharp/extractor-pack/tools"
# Safe guard against using the bundled extractor
rm -rf "$CODEQL_PATH/csharp"
codeql test run --threads=0 --ram 52000 --slice ${{ matrix.slice }} --search-path "${{ github.workspace }}/csharp/extractor-pack" --check-databases --check-undefined-labels --check-repeated-labels --check-redefined-labels --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
env:
GITHUB_TOKEN: ${{ github.token }}
unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup dotnet
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.202
- name: Extractor unit tests
run: |
dotnet test -p:RuntimeFrameworkVersion=6.0.4 "${{ github.workspace }}/csharp/extractor/Semmle.Util.Tests"
dotnet test -p:RuntimeFrameworkVersion=6.0.4 "${{ github.workspace }}/csharp/extractor/Semmle.Extraction.Tests"
dotnet test -p:RuntimeFrameworkVersion=6.0.4 "${{ github.workspace }}/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests"
dotnet test -p:RuntimeFrameworkVersion=6.0.4 "${{ github.workspace }}/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests"

View File

@@ -23,6 +23,19 @@ defaults:
working-directory: javascript/ql/experimental/adaptivethreatmodeling
jobs:
qlformat:
name: Check QL formatting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/fetch-codeql
- name: Check QL formatting
run: |
find . "(" -name "*.ql" -or -name "*.qll" ")" -print0 | \
xargs -0 codeql query format --check-only
qlcompile:
name: Check QL compilation
runs-on: ubuntu-latest

View File

@@ -24,13 +24,13 @@ jobs:
- uses: actions/checkout@v3
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
with:
languages: javascript # does not matter
- name: Get CodeQL version
id: get-codeql-version
run: |
echo "version=$("${CODEQL}" --version | head -n 1 | rev | cut -d " " -f 1 | rev)" >> $GITHUB_OUTPUT
echo "::set-output name=version::$("${CODEQL}" --version | head -n 1 | rev | cut -d " " -f 1 | rev)"
shell: bash
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
@@ -133,7 +133,7 @@ jobs:
env:
CONF: ./ql-for-ql-config.yml
- name: Initialize CodeQL
uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
with:
languages: ql
db-location: ${{ runner.temp }}/db
@@ -145,7 +145,7 @@ jobs:
PACK: ${{ runner.temp }}/pack
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
uses: github/codeql-action/analyze@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
with:
category: "ql-for-ql"
- name: Copy sarif file to CWD

View File

@@ -25,7 +25,7 @@ jobs:
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
with:
languages: javascript # does not matter
- uses: actions/cache@v3

View File

@@ -22,7 +22,7 @@ jobs:
- uses: actions/checkout@v3
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
with:
languages: javascript # does not matter
- uses: actions/cache@v3
@@ -47,3 +47,8 @@ jobs:
find ql/ql/src "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 "${CODEQL}" query format --check-only
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
- name: Check QL compilation
run: |
"${CODEQL}" query compile --check-only --threads=4 --warnings=error --search-path "${{ github.workspace }}/ql/extractor-pack" "ql/ql/src" "ql/ql/examples"
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}

View File

@@ -86,24 +86,19 @@ jobs:
ruby/target/release/ruby-extractor.exe
retention-days: 1
compile-queries:
runs-on: ubuntu-latest-xl
runs-on: ubuntu-latest
env:
CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
steps:
- uses: actions/checkout@v3
- 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: |
rm -rf target/packs
codeql pack create ../shared/ssa --output target/packs
codeql pack create ../misc/suite-helpers --output target/packs
codeql pack create ../shared/regex --output target/packs
codeql pack create ql/lib --output target/packs
codeql pack create -j0 ql/src --output target/packs --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
codeql pack create ql/src --output target/packs
PACK_FOLDER=$(readlink -f target/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}/{}" \;)

View File

@@ -4,7 +4,7 @@ on:
push:
paths:
- "ruby/**"
- .github/workflows/ruby-build.yml
- .github/workflows/ruby-qltest.yml
- .github/actions/fetch-codeql/action.yml
- codeql-workspace.yml
branches:
@@ -28,6 +28,23 @@ defaults:
working-directory: ruby
jobs:
qlformat:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/fetch-codeql
- name: Check QL formatting
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
qlcompile:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/fetch-codeql
- name: Check QL compilation
run: |
codeql query compile --check-only --threads=0 --ram 5000 --warnings=error "ql/src" "ql/examples"
env:
GITHUB_TOKEN: ${{ github.token }}
qlupgrade:
runs-on: ubuntu-latest
steps:
@@ -48,20 +65,17 @@ jobs:
xargs codeql execute upgrades testdb
diff -q testdb/ruby.dbscheme downgrades/initial/ruby.dbscheme
qltest:
runs-on: ubuntu-latest-xl
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
slice: ["1/2", "2/2"]
steps:
- uses: actions/checkout@v3
- 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 52000 --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-undefined-labels --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
codeql test run --threads=0 --ram 5000 --slice ${{ matrix.slice }} --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test
env:
GITHUB_TOKEN: ${{ github.token }}

27
.github/workflows/swift-autobuilder.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: "Swift: Build and test Xcode autobuilder"
on:
pull_request:
paths:
- "swift/xcode-autobuilder/**"
- "misc/bazel/**"
- "*.bazel*"
- .github/workflows/swift-autobuilder.yml
branches:
- main
jobs:
autobuilder:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: bazelbuild/setup-bazelisk@v2
- uses: actions/setup-python@v4
with:
python-version-file: 'swift/.python-version'
- name: Build the Xcode autobuilder
run: |
bazel build //swift/xcode-autobuilder
- name: Test the Xcode autobuilder
run: |
bazel test //swift/xcode-autobuilder/tests

44
.github/workflows/swift-codegen.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
name: "Swift: Check code generation"
on:
pull_request:
paths:
- "swift/**"
- "misc/bazel/**"
- "*.bazel*"
- .github/workflows/swift-codegen.yml
- .github/actions/fetch-codeql/action.yml
branches:
- main
defaults:
run:
working-directory: swift
jobs:
codegen:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/fetch-codeql
- uses: bazelbuild/setup-bazelisk@v2
- uses: actions/setup-python@v4
with:
python-version-file: 'swift/.python-version'
- uses: pre-commit/action@v3.0.0
name: Check that python code is properly formatted
with:
extra_args: autopep8 --all-files
- name: Run unit tests
run: |
bazel test //swift/codegen/test --test_output=errors
- uses: pre-commit/action@v3.0.0
name: Check that QL generated code was checked in
with:
extra_args: swift-codegen --all-files
- name: Generate C++ files
run: |
bazel run //swift/codegen:codegen -- --generate=trap,cpp --cpp-output=$PWD/swift-generated-cpp-files
- uses: actions/upload-artifact@v3
with:
name: swift-generated-cpp-files
path: swift-generated-cpp-files/**

View File

@@ -0,0 +1,47 @@
name: "Swift: Run Integration Tests"
on:
pull_request:
paths:
- "swift/**"
- "misc/bazel/**"
- "*.bazel*"
- .github/workflows/swift-integration-tests.yml
- .github/actions/fetch-codeql/action.yml
- codeql-workspace.yml
branches:
- main
defaults:
run:
working-directory: swift
jobs:
integration-tests:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-20.04
# - macos-latest TODO
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/fetch-codeql
- uses: bazelbuild/setup-bazelisk@v2
- uses: actions/setup-python@v4
with:
python-version-file: 'swift/.python-version'
- name: Build Swift extractor
run: |
bazel run //swift:create-extractor-pack
- name: Get Swift version
id: get_swift_version
run: |
VERSION=$(bazel run //swift/extractor -- --version | sed -ne 's/.*version \(\S*\).*/\1/p')
echo "::set-output name=version::$VERSION"
- uses: swift-actions/setup-swift@v1
with:
swift-version: "${{steps.get_swift_version.outputs.version}}"
- name: Run integration tests
run: |
python integration-tests/runner.py

57
.github/workflows/swift-qltest.yml vendored Normal file
View File

@@ -0,0 +1,57 @@
name: "Swift: Run QL Tests"
on:
pull_request:
paths:
- "swift/**"
- "misc/bazel/**"
- "*.bazel*"
- .github/workflows/swift-qltest.yml
- .github/actions/fetch-codeql/action.yml
- codeql-workspace.yml
branches:
- main
defaults:
run:
working-directory: swift
jobs:
qlformat:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/fetch-codeql
- name: Check QL formatting
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
qltest-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: bazelbuild/setup-bazelisk@v2
- uses: actions/setup-python@v4
with:
python-version-file: 'swift/.python-version'
- name: Test qltest.sh
run: |
bazel test //swift/tools/test/qltest
qltest:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-20.04, macos-latest ]
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/fetch-codeql
- uses: bazelbuild/setup-bazelisk@v2
- uses: actions/setup-python@v4
with:
python-version-file: 'swift/.python-version'
- name: Build Swift extractor
run: |
bazel run //swift:create-extractor-pack
- name: Run QL tests
run: |
codeql test run --threads=0 --ram 5000 --search-path "${{ github.workspace }}/swift/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition ql/test
env:
GITHUB_TOKEN: ${{ github.token }}

View File

@@ -1,121 +0,0 @@
name: "Swift"
on:
pull_request:
paths:
- "swift/**"
- "misc/bazel/**"
- "*.bazel*"
- .github/workflows/swift.yml
- .github/actions/fetch-codeql/action.yml
- codeql-workspace.yml
- .pre-commit-config.yaml
- "!**/*.md"
- "!**/*.qhelp"
branches:
- main
jobs:
changes:
runs-on: ubuntu-latest
outputs:
codegen: ${{ steps.filter.outputs.codegen }}
ql: ${{ steps.filter.outputs.ql }}
steps:
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50
id: filter
with:
filters: |
codegen:
- '.github/workflows/swift.yml'
- "misc/bazel/**"
- "*.bazel*"
- 'swift/actions/setup-env/**'
- '.pre-commit-config.yaml'
- 'swift/codegen/**'
- 'swift/schema.py'
- 'swift/**/*.dbscheme'
- 'swift/ql/lib/codeql/swift/elements.qll'
- 'swift/ql/lib/codeql/swift/elements/**'
- 'swift/ql/lib/codeql/swift/generated/**'
- 'swift/ql/test/extractor-tests/generated/**'
- 'swift/ql/.generated.list'
ql:
- 'github/workflows/swift.yml'
- 'swift/**/*.ql'
- 'swift/**/*.qll'
# not using a matrix as you cannot depend on a specific job in a matrix, and we want to start linux checks
# without waiting for the macOS build
build-and-test-macos:
runs-on: macos-12-xl
steps:
- uses: actions/checkout@v3
- uses: ./swift/actions/create-extractor-pack
- uses: ./swift/actions/run-quick-tests
- uses: ./swift/actions/print-unextracted
build-and-test-linux:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: ./swift/actions/create-extractor-pack
- uses: ./swift/actions/run-quick-tests
- uses: ./swift/actions/print-unextracted
qltests-linux:
needs: build-and-test-linux
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./swift/actions/run-ql-tests
qltests-macos:
needs: build-and-test-macos
runs-on: macos-12-xl
strategy:
fail-fast: false
matrix:
slice: ["1/2", "2/2"]
steps:
- uses: actions/checkout@v3
- uses: ./swift/actions/run-ql-tests
with:
flags: --slice ${{ matrix.slice }}
integration-tests-linux:
needs: build-and-test-linux
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./swift/actions/run-integration-tests
integration-tests-macos:
needs: build-and-test-macos
runs-on: macos-12-xl
steps:
- uses: actions/checkout@v3
- uses: ./swift/actions/run-integration-tests
codegen:
runs-on: ubuntu-latest
needs: changes
if: ${{ needs.changes.outputs.codegen == 'true' }}
steps:
- uses: actions/checkout@v3
- uses: ./swift/actions/setup-env
- uses: pre-commit/action@v3.0.0
name: Check that python code is properly formatted
with:
extra_args: autopep8 --all-files
- uses: ./.github/actions/fetch-codeql
- uses: pre-commit/action@v3.0.0
name: Check that QL generated code was checked in
with:
extra_args: swift-codegen --all-files
- name: Generate C++ files
run: |
bazel run //swift/codegen:codegen -- --generate=trap,cpp --cpp-output=$PWD/generated-cpp-files
- uses: actions/upload-artifact@v3
with:
name: swift-generated-cpp-files
path: generated-cpp-files/**
database-upgrade-scripts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/fetch-codeql
- uses: ./swift/actions/database-upgrade-scripts

2
.gitignore vendored
View File

@@ -27,6 +27,8 @@
# It's useful (though not required) to be able to unpack codeql in the ql checkout itself
/codeql/
csharp/extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
# Avoid committing cached package components
.codeql

View File

@@ -19,7 +19,7 @@ repos:
rev: v1.6.0
hooks:
- id: autopep8
files: ^swift/.*\.py
files: ^swift/codegen/.*\.py
- repo: local
hooks:
@@ -31,7 +31,7 @@ repos:
- id: sync-files
name: Fix files required to be identical
files: \.(qll?|qhelp|swift)$|^config/identical-files\.json$
files: \.(qll?|qhelp|swift)$
language: system
entry: python3 config/sync-files.py --latest
pass_filenames: false
@@ -44,7 +44,7 @@ repos:
- id: swift-codegen
name: Run Swift checked in code generation
files: ^swift/(schema.py$|codegen/|.*/generated/|ql/lib/(swift\.dbscheme$|codeql/swift/elements)|ql/\.generated.list)
files: ^swift/(codegen/|.*/generated/|ql/lib/(swift\.dbscheme$|codeql/swift/elements))
language: system
entry: bazel run //swift/codegen -- --quiet
pass_filenames: false

View File

@@ -1,5 +1,3 @@
{
"omnisharp.autoStart": false,
"cmake.sourceDirectory": "${workspaceFolder}/swift",
"cmake.buildDirectory": "${workspaceFolder}/bazel-cmake-build"
"omnisharp.autoStart": false
}

View File

@@ -5,7 +5,7 @@
/javascript/ @github/codeql-javascript
/python/ @github/codeql-python
/ruby/ @github/codeql-ruby
/swift/ @github/codeql-swift
/swift/ @github/codeql-c
/java/kotlin-extractor/ @github/codeql-kotlin
/java/kotlin-explorer/ @github/codeql-kotlin
@@ -40,9 +40,8 @@ WORKSPACE.bazel @github/codeql-ci-reviewers
# Workflows
/.github/workflows/ @github/codeql-ci-reviewers
/.github/workflows/atm-* @github/codeql-ml-powered-queries-reviewers
/.github/workflows/go-* @github/codeql-go
/.github/workflows/js-ml-tests.yml @github/codeql-ml-powered-queries-reviewers
/.github/workflows/ql-for-ql-* @github/codeql-ql-for-ql-reviewers
/.github/workflows/ruby-* @github/codeql-ruby
/.github/workflows/swift.yml @github/codeql-swift
/.github/workflows/swift-* @github/codeql-c

View File

@@ -17,7 +17,6 @@ provide:
# - "javascript/ql/experimental/adaptivethreatmodeling/model/qlpack.yml"
- "javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml"
- "javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml"
- "javascript/ql/experimental/adaptivethreatmodeling/test/qlpack.yml"
- "csharp/ql/campaigns/Solorigate/lib/qlpack.yml"
- "csharp/ql/campaigns/Solorigate/src/qlpack.yml"
- "csharp/ql/campaigns/Solorigate/test/qlpack.yml"
@@ -25,7 +24,7 @@ provide:
- "misc/suite-helpers/qlpack.yml"
- "ruby/extractor-pack/codeql-extractor.yml"
- "swift/extractor-pack/codeql-extractor.yml"
- "ql/extractor-pack/codeql-extractor.yml"
- "ql/extractor-pack/codeql-extractor.ym"
versionPolicies:
default:

View File

@@ -94,8 +94,8 @@
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
],
"Model as Data Generation Java/C# - CaptureModels": [
"java/ql/src/utils/modelgenerator/internal/CaptureModels.qll",
"csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll"
"java/ql/src/utils/model-generator/internal/CaptureModels.qll",
"csharp/ql/src/utils/model-generator/internal/CaptureModels.qll"
],
"Sign Java/C#": [
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll",
@@ -486,6 +486,40 @@
"python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll",
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll"
],
"ReDoS Util Python/JS/Ruby/Java": [
"javascript/ql/lib/semmle/javascript/security/regexp/NfaUtils.qll",
"python/ql/lib/semmle/python/security/regexp/NfaUtils.qll",
"ruby/ql/lib/codeql/ruby/security/regexp/NfaUtils.qll",
"java/ql/lib/semmle/code/java/security/regexp/NfaUtils.qll"
],
"ReDoS Exponential Python/JS/Ruby/Java": [
"javascript/ql/lib/semmle/javascript/security/regexp/ExponentialBackTracking.qll",
"python/ql/lib/semmle/python/security/regexp/ExponentialBackTracking.qll",
"ruby/ql/lib/codeql/ruby/security/regexp/ExponentialBackTracking.qll",
"java/ql/lib/semmle/code/java/security/regexp/ExponentialBackTracking.qll"
],
"ReDoS Polynomial Python/JS/Ruby/Java": [
"javascript/ql/lib/semmle/javascript/security/regexp/SuperlinearBackTracking.qll",
"python/ql/lib/semmle/python/security/regexp/SuperlinearBackTracking.qll",
"ruby/ql/lib/codeql/ruby/security/regexp/SuperlinearBackTracking.qll",
"java/ql/lib/semmle/code/java/security/regexp/SuperlinearBackTracking.qll"
],
"RegexpMatching Python/JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/regexp/RegexpMatching.qll",
"python/ql/lib/semmle/python/security/regexp/RegexpMatching.qll",
"ruby/ql/lib/codeql/ruby/security/regexp/RegexpMatching.qll"
],
"BadTagFilterQuery Python/JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll",
"python/ql/lib/semmle/python/security/BadTagFilterQuery.qll",
"ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll"
],
"OverlyLargeRange Python/JS/Ruby/Java": [
"javascript/ql/lib/semmle/javascript/security/OverlyLargeRangeQuery.qll",
"python/ql/lib/semmle/python/security/OverlyLargeRangeQuery.qll",
"ruby/ql/lib/codeql/ruby/security/OverlyLargeRangeQuery.qll",
"java/ql/lib/semmle/code/java/security/OverlyLargeRangeQuery.qll"
],
"CFG": [
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",
"ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll",
@@ -566,12 +600,8 @@
"swift/ql/test/extractor-tests/patterns/patterns.swift",
"swift/ql/test/library-tests/ast/patterns.swift"
],
"Swift control flow test file": [
"swift/ql/test/library-tests/controlflow/graph/cfg.swift",
"swift/ql/test/library-tests/ast/cfg.swift"
],
"IncompleteMultiCharacterSanitization JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/IncompleteMultiCharacterSanitizationQuery.qll",
"ruby/ql/lib/codeql/ruby/security/IncompleteMultiCharacterSanitizationQuery.qll"
]
}
}

View File

@@ -257,11 +257,11 @@ namespace Semmle.Autobuild.Cpp.Tests
Actions.GetCurrentDirectory = cwd;
Actions.IsWindows = isWindows;
var options = new CppAutobuildOptions(Actions);
var options = new AutobuildOptions(Actions, Language.Cpp);
return new CppAutobuilder(Actions, options);
}
void TestAutobuilderScript(CppAutobuilder autobuilder, int expectedOutput, int commandsRun)
void TestAutobuilderScript(Autobuilder autobuilder, int expectedOutput, int commandsRun)
{
Assert.Equal(expectedOutput, autobuilder.GetBuildScript().Run(Actions, StartCallback, EndCallback));
@@ -299,7 +299,7 @@ namespace Semmle.Autobuild.Cpp.Tests
{
Actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test.sln -DisableParallelProcessing"] = 1;
Actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test.sln -DisableParallelProcessing"] = 0;
Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && msbuild C:\Project\test.sln /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"""] = 0;
Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0;
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "";
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1;
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0;

View File

@@ -11,12 +11,11 @@
<ItemGroup>
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -2,26 +2,9 @@
namespace Semmle.Autobuild.Cpp
{
/// <summary>
/// Encapsulates C++ build options.
/// </summary>
public class CppAutobuildOptions : AutobuildOptionsShared
public class CppAutobuilder : Autobuilder
{
public override Language Language => Language.Cpp;
/// <summary>
/// Reads options from environment variables.
/// Throws ArgumentOutOfRangeException for invalid arguments.
/// </summary>
public CppAutobuildOptions(IBuildActions actions) : base(actions)
{
}
}
public class CppAutobuilder : Autobuilder<CppAutobuildOptions>
{
public CppAutobuilder(IBuildActions actions, CppAutobuildOptions options) : base(actions, options) { }
public CppAutobuilder(IBuildActions actions, AutobuildOptions options) : base(actions, options) { }
public override BuildScript GetBuildScript()
{

View File

@@ -11,14 +11,14 @@ namespace Semmle.Autobuild.Cpp
try
{
var actions = SystemBuildActions.Instance;
var options = new CppAutobuildOptions(actions);
var options = new AutobuildOptions(actions, Language.Cpp);
try
{
Console.WriteLine("CodeQL C++ autobuilder");
var builder = new CppAutobuilder(actions, options);
return builder.AttemptBuild();
}
catch (InvalidEnvironmentException ex)
catch(InvalidEnvironmentException ex)
{
Console.WriteLine("The environment is invalid: {0}", ex.Message);
}

View File

@@ -17,7 +17,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="17.3.2" />
<PackageReference Include="Microsoft.Build" Version="16.11.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -3,4 +3,4 @@ groups:
- cpp
- examples
dependencies:
codeql/cpp-all: ${workspace}
codeql/cpp-all: "*"

View File

@@ -1,13 +1,3 @@
## 0.4.4
No user-facing changes.
## 0.4.3
### Minor Analysis Improvements
* Fixed bugs in the `FormatLiteral` class that were causing `getMaxConvertedLength` and related predicates to return no results when the format literal was `%e`, `%f` or `%g` and an explicit precision was specified.
## 0.4.2
No user-facing changes.

View File

@@ -1,5 +1,4 @@
## 0.4.3
### Minor Analysis Improvements
---
category: minorAnalysis
---
* Fixed bugs in the `FormatLiteral` class that were causing `getMaxConvertedLength` and related predicates to return no results when the format literal was `%e`, `%f` or `%g` and an explicit precision was specified.

View File

@@ -1,6 +0,0 @@
---
category: deprecated
---
* Deprecated `semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl`. Use `semmle.code.cpp.valuenumbering.GlobalValueNumbering`, which exposes the same API.

View File

@@ -1,4 +0,0 @@
---
category: breaking
---
The predicates in the `MustFlow::Configuration` class used by the `MustFlow` library (`semmle.code.cpp.ir.dataflow.MustFlow`) have changed to be defined directly in terms of the C++ IR instead of IR dataflow nodes.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Deleted the deprecated `getName` and `getShortName` predicates from the `Folder` class.

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.4.4
lastReleaseVersion: 0.4.2

View File

@@ -147,12 +147,6 @@ abstract class Configuration extends string {
*/
FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -164,7 +158,7 @@ abstract class Configuration extends string {
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
@@ -2635,7 +2629,6 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
/**
* Gets the number of `AccessPath`s that correspond to `apa`.
*/
pragma[assume_small_delta]
private int countAps(AccessPathApprox apa, Configuration config) {
evalUnfold(apa, false, config) and
result = 1 and
@@ -2654,7 +2647,6 @@ private int countAps(AccessPathApprox apa, Configuration config) {
* that it is expanded to a precise head-tail representation.
*/
language[monotonicAggregates]
pragma[assume_small_delta]
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
apa instanceof AccessPathApproxNil and result = 1
or
@@ -2689,7 +2681,6 @@ private newtype TAccessPath =
}
private newtype TPathNode =
pragma[assume_small_delta]
TPathNodeMid(
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) {
@@ -2718,18 +2709,6 @@ private newtype TPathNode =
state = sink.getState() and
config = sink.getConfiguration()
)
} or
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
exists(PathNodeImpl source |
sourceGroup = source.getSourceGroup() and
config = source.getConfiguration()
)
} or
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
exists(PathNodeSink sink |
sinkGroup = sink.getSinkGroup() and
config = sink.getConfiguration()
)
}
/**
@@ -2799,7 +2778,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
pragma[assume_small_delta]
override AccessPathApproxCons getApprox() {
result = TConsNil(head, tail.(AccessPathNil).getType())
or
@@ -2808,7 +2786,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
result = TCons1(head, this.length())
}
pragma[assume_small_delta]
override int length() { result = 1 + tail.length() }
private string toStringImpl(boolean needsSuffix) {
@@ -2897,16 +2874,54 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
}
}
abstract private class PathNodeImpl extends TPathNode {
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
abstract FlowState getState();
FlowState getState() { none() }
/** Gets the associated configuration. */
abstract Configuration getConfiguration();
Configuration getConfiguration() { none() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
abstract predicate isSource();
predicate isSource() { none() }
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
@@ -2938,22 +2953,6 @@ abstract private class PathNodeImpl extends TPathNode {
)
}
string getSourceGroup() {
this.isSource() and
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
}
predicate isFlowSource() {
this.isSource() and not exists(this.getSourceGroup())
or
this instanceof PathNodeSourceGroup
}
predicate isFlowSink() {
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
this instanceof PathNodeSinkGroup
}
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -2968,23 +2967,13 @@ abstract private class PathNodeImpl extends TPathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
/** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2993,71 +2982,18 @@ abstract private class PathNodeImpl extends TPathNode {
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or
n instanceof PathNodeSinkGroup or
directReach(n.getANonHiddenSuccessor())
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
/** Holds if this node is a grouping of source nodes. */
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
/** Holds if this node is a grouping of sink nodes. */
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
/**
* Provides the query predicates needed to include a graph in a path-problem query.
@@ -3068,7 +3004,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
key = "semmle.label" and val = n.toString()
reach(n) and key = "semmle.label" and val = n.toString()
}
/**
@@ -3077,7 +3013,11 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out)
Subpaths::subpaths(arg, par, ret, out) and
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
}
}
@@ -3178,66 +3118,9 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
}
override predicate isSource() { sourceNode(node, state, config) }
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
}
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
string sourceGroup;
Configuration config;
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result.getSourceGroup() = sourceGroup and
result.getConfiguration() = config
}
override predicate isSource() { none() }
override string toString() { result = sourceGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
}
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
string sinkGroup;
Configuration config;
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { none() }
override string toString() { result = sinkGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
override predicate isSource() { sourceNode(node, state, config) }
}
private predicate pathNode(
@@ -3259,7 +3142,6 @@ private predicate pathNode(
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
@@ -3517,7 +3399,7 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths02(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout
) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3525,14 +3407,14 @@ private module Subpaths {
}
pragma[nomagic]
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/
pragma[nomagic]
private predicate subpaths03(
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3562,7 +3444,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3578,7 +3460,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNodeImpl n) {
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNodeImpl mid |
retReach(mid) and
@@ -3594,22 +3476,12 @@ private module Subpaths {
* Will only have results if `configuration` has non-empty sources and
* sinks.
*/
private predicate hasFlowPath(
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
) {
flowsource.isFlowSource() and
flowsource.getConfiguration() = configuration and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.isFlowSink()
}
private predicate flowsTo(
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
flowsource.getNodeEx().asNode() = source and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink
}
@@ -3632,14 +3504,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNodeImpl pn)
tuples = count(PathNode pn)
or
fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn)
tuples = count(PathNode pn | reach(pn))
}
/**

View File

@@ -147,12 +147,6 @@ abstract class Configuration extends string {
*/
FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -164,7 +158,7 @@ abstract class Configuration extends string {
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
@@ -2635,7 +2629,6 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
/**
* Gets the number of `AccessPath`s that correspond to `apa`.
*/
pragma[assume_small_delta]
private int countAps(AccessPathApprox apa, Configuration config) {
evalUnfold(apa, false, config) and
result = 1 and
@@ -2654,7 +2647,6 @@ private int countAps(AccessPathApprox apa, Configuration config) {
* that it is expanded to a precise head-tail representation.
*/
language[monotonicAggregates]
pragma[assume_small_delta]
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
apa instanceof AccessPathApproxNil and result = 1
or
@@ -2689,7 +2681,6 @@ private newtype TAccessPath =
}
private newtype TPathNode =
pragma[assume_small_delta]
TPathNodeMid(
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) {
@@ -2718,18 +2709,6 @@ private newtype TPathNode =
state = sink.getState() and
config = sink.getConfiguration()
)
} or
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
exists(PathNodeImpl source |
sourceGroup = source.getSourceGroup() and
config = source.getConfiguration()
)
} or
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
exists(PathNodeSink sink |
sinkGroup = sink.getSinkGroup() and
config = sink.getConfiguration()
)
}
/**
@@ -2799,7 +2778,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
pragma[assume_small_delta]
override AccessPathApproxCons getApprox() {
result = TConsNil(head, tail.(AccessPathNil).getType())
or
@@ -2808,7 +2786,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
result = TCons1(head, this.length())
}
pragma[assume_small_delta]
override int length() { result = 1 + tail.length() }
private string toStringImpl(boolean needsSuffix) {
@@ -2897,16 +2874,54 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
}
}
abstract private class PathNodeImpl extends TPathNode {
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
abstract FlowState getState();
FlowState getState() { none() }
/** Gets the associated configuration. */
abstract Configuration getConfiguration();
Configuration getConfiguration() { none() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
abstract predicate isSource();
predicate isSource() { none() }
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
@@ -2938,22 +2953,6 @@ abstract private class PathNodeImpl extends TPathNode {
)
}
string getSourceGroup() {
this.isSource() and
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
}
predicate isFlowSource() {
this.isSource() and not exists(this.getSourceGroup())
or
this instanceof PathNodeSourceGroup
}
predicate isFlowSink() {
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
this instanceof PathNodeSinkGroup
}
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -2968,23 +2967,13 @@ abstract private class PathNodeImpl extends TPathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
/** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2993,71 +2982,18 @@ abstract private class PathNodeImpl extends TPathNode {
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or
n instanceof PathNodeSinkGroup or
directReach(n.getANonHiddenSuccessor())
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
/** Holds if this node is a grouping of source nodes. */
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
/** Holds if this node is a grouping of sink nodes. */
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
/**
* Provides the query predicates needed to include a graph in a path-problem query.
@@ -3068,7 +3004,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
key = "semmle.label" and val = n.toString()
reach(n) and key = "semmle.label" and val = n.toString()
}
/**
@@ -3077,7 +3013,11 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out)
Subpaths::subpaths(arg, par, ret, out) and
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
}
}
@@ -3178,66 +3118,9 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
}
override predicate isSource() { sourceNode(node, state, config) }
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
}
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
string sourceGroup;
Configuration config;
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result.getSourceGroup() = sourceGroup and
result.getConfiguration() = config
}
override predicate isSource() { none() }
override string toString() { result = sourceGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
}
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
string sinkGroup;
Configuration config;
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { none() }
override string toString() { result = sinkGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
override predicate isSource() { sourceNode(node, state, config) }
}
private predicate pathNode(
@@ -3259,7 +3142,6 @@ private predicate pathNode(
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
@@ -3517,7 +3399,7 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths02(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout
) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3525,14 +3407,14 @@ private module Subpaths {
}
pragma[nomagic]
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/
pragma[nomagic]
private predicate subpaths03(
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3562,7 +3444,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3578,7 +3460,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNodeImpl n) {
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNodeImpl mid |
retReach(mid) and
@@ -3594,22 +3476,12 @@ private module Subpaths {
* Will only have results if `configuration` has non-empty sources and
* sinks.
*/
private predicate hasFlowPath(
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
) {
flowsource.isFlowSource() and
flowsource.getConfiguration() = configuration and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.isFlowSink()
}
private predicate flowsTo(
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
flowsource.getNodeEx().asNode() = source and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink
}
@@ -3632,14 +3504,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNodeImpl pn)
tuples = count(PathNode pn)
or
fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn)
tuples = count(PathNode pn | reach(pn))
}
/**

View File

@@ -147,12 +147,6 @@ abstract class Configuration extends string {
*/
FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -164,7 +158,7 @@ abstract class Configuration extends string {
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
@@ -2635,7 +2629,6 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
/**
* Gets the number of `AccessPath`s that correspond to `apa`.
*/
pragma[assume_small_delta]
private int countAps(AccessPathApprox apa, Configuration config) {
evalUnfold(apa, false, config) and
result = 1 and
@@ -2654,7 +2647,6 @@ private int countAps(AccessPathApprox apa, Configuration config) {
* that it is expanded to a precise head-tail representation.
*/
language[monotonicAggregates]
pragma[assume_small_delta]
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
apa instanceof AccessPathApproxNil and result = 1
or
@@ -2689,7 +2681,6 @@ private newtype TAccessPath =
}
private newtype TPathNode =
pragma[assume_small_delta]
TPathNodeMid(
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) {
@@ -2718,18 +2709,6 @@ private newtype TPathNode =
state = sink.getState() and
config = sink.getConfiguration()
)
} or
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
exists(PathNodeImpl source |
sourceGroup = source.getSourceGroup() and
config = source.getConfiguration()
)
} or
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
exists(PathNodeSink sink |
sinkGroup = sink.getSinkGroup() and
config = sink.getConfiguration()
)
}
/**
@@ -2799,7 +2778,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
pragma[assume_small_delta]
override AccessPathApproxCons getApprox() {
result = TConsNil(head, tail.(AccessPathNil).getType())
or
@@ -2808,7 +2786,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
result = TCons1(head, this.length())
}
pragma[assume_small_delta]
override int length() { result = 1 + tail.length() }
private string toStringImpl(boolean needsSuffix) {
@@ -2897,16 +2874,54 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
}
}
abstract private class PathNodeImpl extends TPathNode {
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
abstract FlowState getState();
FlowState getState() { none() }
/** Gets the associated configuration. */
abstract Configuration getConfiguration();
Configuration getConfiguration() { none() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
abstract predicate isSource();
predicate isSource() { none() }
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
@@ -2938,22 +2953,6 @@ abstract private class PathNodeImpl extends TPathNode {
)
}
string getSourceGroup() {
this.isSource() and
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
}
predicate isFlowSource() {
this.isSource() and not exists(this.getSourceGroup())
or
this instanceof PathNodeSourceGroup
}
predicate isFlowSink() {
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
this instanceof PathNodeSinkGroup
}
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -2968,23 +2967,13 @@ abstract private class PathNodeImpl extends TPathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
/** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2993,71 +2982,18 @@ abstract private class PathNodeImpl extends TPathNode {
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or
n instanceof PathNodeSinkGroup or
directReach(n.getANonHiddenSuccessor())
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
/** Holds if this node is a grouping of source nodes. */
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
/** Holds if this node is a grouping of sink nodes. */
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
/**
* Provides the query predicates needed to include a graph in a path-problem query.
@@ -3068,7 +3004,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
key = "semmle.label" and val = n.toString()
reach(n) and key = "semmle.label" and val = n.toString()
}
/**
@@ -3077,7 +3013,11 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out)
Subpaths::subpaths(arg, par, ret, out) and
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
}
}
@@ -3178,66 +3118,9 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
}
override predicate isSource() { sourceNode(node, state, config) }
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
}
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
string sourceGroup;
Configuration config;
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result.getSourceGroup() = sourceGroup and
result.getConfiguration() = config
}
override predicate isSource() { none() }
override string toString() { result = sourceGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
}
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
string sinkGroup;
Configuration config;
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { none() }
override string toString() { result = sinkGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
override predicate isSource() { sourceNode(node, state, config) }
}
private predicate pathNode(
@@ -3259,7 +3142,6 @@ private predicate pathNode(
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
@@ -3517,7 +3399,7 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths02(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout
) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3525,14 +3407,14 @@ private module Subpaths {
}
pragma[nomagic]
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/
pragma[nomagic]
private predicate subpaths03(
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3562,7 +3444,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3578,7 +3460,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNodeImpl n) {
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNodeImpl mid |
retReach(mid) and
@@ -3594,22 +3476,12 @@ private module Subpaths {
* Will only have results if `configuration` has non-empty sources and
* sinks.
*/
private predicate hasFlowPath(
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
) {
flowsource.isFlowSource() and
flowsource.getConfiguration() = configuration and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.isFlowSink()
}
private predicate flowsTo(
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
flowsource.getNodeEx().asNode() = source and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink
}
@@ -3632,14 +3504,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNodeImpl pn)
tuples = count(PathNode pn)
or
fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn)
tuples = count(PathNode pn | reach(pn))
}
/**

View File

@@ -147,12 +147,6 @@ abstract class Configuration extends string {
*/
FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -164,7 +158,7 @@ abstract class Configuration extends string {
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
@@ -2635,7 +2629,6 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
/**
* Gets the number of `AccessPath`s that correspond to `apa`.
*/
pragma[assume_small_delta]
private int countAps(AccessPathApprox apa, Configuration config) {
evalUnfold(apa, false, config) and
result = 1 and
@@ -2654,7 +2647,6 @@ private int countAps(AccessPathApprox apa, Configuration config) {
* that it is expanded to a precise head-tail representation.
*/
language[monotonicAggregates]
pragma[assume_small_delta]
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
apa instanceof AccessPathApproxNil and result = 1
or
@@ -2689,7 +2681,6 @@ private newtype TAccessPath =
}
private newtype TPathNode =
pragma[assume_small_delta]
TPathNodeMid(
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) {
@@ -2718,18 +2709,6 @@ private newtype TPathNode =
state = sink.getState() and
config = sink.getConfiguration()
)
} or
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
exists(PathNodeImpl source |
sourceGroup = source.getSourceGroup() and
config = source.getConfiguration()
)
} or
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
exists(PathNodeSink sink |
sinkGroup = sink.getSinkGroup() and
config = sink.getConfiguration()
)
}
/**
@@ -2799,7 +2778,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
pragma[assume_small_delta]
override AccessPathApproxCons getApprox() {
result = TConsNil(head, tail.(AccessPathNil).getType())
or
@@ -2808,7 +2786,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
result = TCons1(head, this.length())
}
pragma[assume_small_delta]
override int length() { result = 1 + tail.length() }
private string toStringImpl(boolean needsSuffix) {
@@ -2897,16 +2874,54 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
}
}
abstract private class PathNodeImpl extends TPathNode {
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
abstract FlowState getState();
FlowState getState() { none() }
/** Gets the associated configuration. */
abstract Configuration getConfiguration();
Configuration getConfiguration() { none() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
abstract predicate isSource();
predicate isSource() { none() }
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
@@ -2938,22 +2953,6 @@ abstract private class PathNodeImpl extends TPathNode {
)
}
string getSourceGroup() {
this.isSource() and
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
}
predicate isFlowSource() {
this.isSource() and not exists(this.getSourceGroup())
or
this instanceof PathNodeSourceGroup
}
predicate isFlowSink() {
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
this instanceof PathNodeSinkGroup
}
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -2968,23 +2967,13 @@ abstract private class PathNodeImpl extends TPathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
/** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2993,71 +2982,18 @@ abstract private class PathNodeImpl extends TPathNode {
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or
n instanceof PathNodeSinkGroup or
directReach(n.getANonHiddenSuccessor())
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
/** Holds if this node is a grouping of source nodes. */
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
/** Holds if this node is a grouping of sink nodes. */
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
/**
* Provides the query predicates needed to include a graph in a path-problem query.
@@ -3068,7 +3004,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
key = "semmle.label" and val = n.toString()
reach(n) and key = "semmle.label" and val = n.toString()
}
/**
@@ -3077,7 +3013,11 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out)
Subpaths::subpaths(arg, par, ret, out) and
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
}
}
@@ -3178,66 +3118,9 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
}
override predicate isSource() { sourceNode(node, state, config) }
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
}
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
string sourceGroup;
Configuration config;
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result.getSourceGroup() = sourceGroup and
result.getConfiguration() = config
}
override predicate isSource() { none() }
override string toString() { result = sourceGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
}
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
string sinkGroup;
Configuration config;
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { none() }
override string toString() { result = sinkGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
override predicate isSource() { sourceNode(node, state, config) }
}
private predicate pathNode(
@@ -3259,7 +3142,6 @@ private predicate pathNode(
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
@@ -3517,7 +3399,7 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths02(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout
) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3525,14 +3407,14 @@ private module Subpaths {
}
pragma[nomagic]
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/
pragma[nomagic]
private predicate subpaths03(
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3562,7 +3444,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3578,7 +3460,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNodeImpl n) {
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNodeImpl mid |
retReach(mid) and
@@ -3594,22 +3476,12 @@ private module Subpaths {
* Will only have results if `configuration` has non-empty sources and
* sinks.
*/
private predicate hasFlowPath(
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
) {
flowsource.isFlowSource() and
flowsource.getConfiguration() = configuration and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.isFlowSink()
}
private predicate flowsTo(
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
flowsource.getNodeEx().asNode() = source and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink
}
@@ -3632,14 +3504,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNodeImpl pn)
tuples = count(PathNode pn)
or
fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn)
tuples = count(PathNode pn | reach(pn))
}
/**

View File

@@ -136,18 +136,6 @@ module Consistency {
msg = "Local flow step does not preserve enclosing callable."
}
query predicate readStepIsLocal(Node n1, Node n2, string msg) {
readStep(n1, _, n2) and
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
msg = "Read step does not preserve enclosing callable."
}
query predicate storeStepIsLocal(Node n1, Node n2, string msg) {
storeStep(n1, _, n2) and
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
msg = "Store step does not preserve enclosing callable."
}
private DataFlowType typeRepr() { result = getNodeType(_) }
query predicate compatibleTypesReflexive(DataFlowType t, string msg) {

View File

@@ -1,9 +1,9 @@
name: codeql/cpp-all
version: 0.4.5-dev
version: 0.4.3-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
library: true
upgrades: upgrades
dependencies:
codeql/ssa: ${workspace}
codeql/ssa: 0.0.1

View File

@@ -189,6 +189,18 @@ class Folder extends Container, @folder {
* Gets the URL of this folder.
*/
deprecated override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
/**
* DEPRECATED: use `getAbsolutePath` instead.
* Gets the name of this folder.
*/
deprecated string getName() { folders(underlyingElement(this), result) }
/**
* DEPRECATED: use `getBaseName` instead.
* Gets the last part of the folder name.
*/
deprecated string getShortName() { result = this.getBaseName() }
}
/**

View File

@@ -147,12 +147,6 @@ abstract class Configuration extends string {
*/
FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -164,7 +158,7 @@ abstract class Configuration extends string {
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
@@ -2635,7 +2629,6 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
/**
* Gets the number of `AccessPath`s that correspond to `apa`.
*/
pragma[assume_small_delta]
private int countAps(AccessPathApprox apa, Configuration config) {
evalUnfold(apa, false, config) and
result = 1 and
@@ -2654,7 +2647,6 @@ private int countAps(AccessPathApprox apa, Configuration config) {
* that it is expanded to a precise head-tail representation.
*/
language[monotonicAggregates]
pragma[assume_small_delta]
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
apa instanceof AccessPathApproxNil and result = 1
or
@@ -2689,7 +2681,6 @@ private newtype TAccessPath =
}
private newtype TPathNode =
pragma[assume_small_delta]
TPathNodeMid(
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) {
@@ -2718,18 +2709,6 @@ private newtype TPathNode =
state = sink.getState() and
config = sink.getConfiguration()
)
} or
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
exists(PathNodeImpl source |
sourceGroup = source.getSourceGroup() and
config = source.getConfiguration()
)
} or
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
exists(PathNodeSink sink |
sinkGroup = sink.getSinkGroup() and
config = sink.getConfiguration()
)
}
/**
@@ -2799,7 +2778,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
pragma[assume_small_delta]
override AccessPathApproxCons getApprox() {
result = TConsNil(head, tail.(AccessPathNil).getType())
or
@@ -2808,7 +2786,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
result = TCons1(head, this.length())
}
pragma[assume_small_delta]
override int length() { result = 1 + tail.length() }
private string toStringImpl(boolean needsSuffix) {
@@ -2897,16 +2874,54 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
}
}
abstract private class PathNodeImpl extends TPathNode {
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
abstract FlowState getState();
FlowState getState() { none() }
/** Gets the associated configuration. */
abstract Configuration getConfiguration();
Configuration getConfiguration() { none() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
abstract predicate isSource();
predicate isSource() { none() }
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
@@ -2938,22 +2953,6 @@ abstract private class PathNodeImpl extends TPathNode {
)
}
string getSourceGroup() {
this.isSource() and
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
}
predicate isFlowSource() {
this.isSource() and not exists(this.getSourceGroup())
or
this instanceof PathNodeSourceGroup
}
predicate isFlowSink() {
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
this instanceof PathNodeSinkGroup
}
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -2968,23 +2967,13 @@ abstract private class PathNodeImpl extends TPathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
/** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2993,71 +2982,18 @@ abstract private class PathNodeImpl extends TPathNode {
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or
n instanceof PathNodeSinkGroup or
directReach(n.getANonHiddenSuccessor())
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
/** Holds if this node is a grouping of source nodes. */
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
/** Holds if this node is a grouping of sink nodes. */
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
/**
* Provides the query predicates needed to include a graph in a path-problem query.
@@ -3068,7 +3004,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
key = "semmle.label" and val = n.toString()
reach(n) and key = "semmle.label" and val = n.toString()
}
/**
@@ -3077,7 +3013,11 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out)
Subpaths::subpaths(arg, par, ret, out) and
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
}
}
@@ -3178,66 +3118,9 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
}
override predicate isSource() { sourceNode(node, state, config) }
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
}
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
string sourceGroup;
Configuration config;
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result.getSourceGroup() = sourceGroup and
result.getConfiguration() = config
}
override predicate isSource() { none() }
override string toString() { result = sourceGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
}
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
string sinkGroup;
Configuration config;
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { none() }
override string toString() { result = sinkGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
override predicate isSource() { sourceNode(node, state, config) }
}
private predicate pathNode(
@@ -3259,7 +3142,6 @@ private predicate pathNode(
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
@@ -3517,7 +3399,7 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths02(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout
) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3525,14 +3407,14 @@ private module Subpaths {
}
pragma[nomagic]
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/
pragma[nomagic]
private predicate subpaths03(
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3562,7 +3444,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3578,7 +3460,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNodeImpl n) {
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNodeImpl mid |
retReach(mid) and
@@ -3594,22 +3476,12 @@ private module Subpaths {
* Will only have results if `configuration` has non-empty sources and
* sinks.
*/
private predicate hasFlowPath(
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
) {
flowsource.isFlowSource() and
flowsource.getConfiguration() = configuration and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.isFlowSink()
}
private predicate flowsTo(
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
flowsource.getNodeEx().asNode() = source and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink
}
@@ -3632,14 +3504,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNodeImpl pn)
tuples = count(PathNode pn)
or
fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn)
tuples = count(PathNode pn | reach(pn))
}
/**

View File

@@ -147,12 +147,6 @@ abstract class Configuration extends string {
*/
FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -164,7 +158,7 @@ abstract class Configuration extends string {
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
@@ -2635,7 +2629,6 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
/**
* Gets the number of `AccessPath`s that correspond to `apa`.
*/
pragma[assume_small_delta]
private int countAps(AccessPathApprox apa, Configuration config) {
evalUnfold(apa, false, config) and
result = 1 and
@@ -2654,7 +2647,6 @@ private int countAps(AccessPathApprox apa, Configuration config) {
* that it is expanded to a precise head-tail representation.
*/
language[monotonicAggregates]
pragma[assume_small_delta]
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
apa instanceof AccessPathApproxNil and result = 1
or
@@ -2689,7 +2681,6 @@ private newtype TAccessPath =
}
private newtype TPathNode =
pragma[assume_small_delta]
TPathNodeMid(
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) {
@@ -2718,18 +2709,6 @@ private newtype TPathNode =
state = sink.getState() and
config = sink.getConfiguration()
)
} or
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
exists(PathNodeImpl source |
sourceGroup = source.getSourceGroup() and
config = source.getConfiguration()
)
} or
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
exists(PathNodeSink sink |
sinkGroup = sink.getSinkGroup() and
config = sink.getConfiguration()
)
}
/**
@@ -2799,7 +2778,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
pragma[assume_small_delta]
override AccessPathApproxCons getApprox() {
result = TConsNil(head, tail.(AccessPathNil).getType())
or
@@ -2808,7 +2786,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
result = TCons1(head, this.length())
}
pragma[assume_small_delta]
override int length() { result = 1 + tail.length() }
private string toStringImpl(boolean needsSuffix) {
@@ -2897,16 +2874,54 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
}
}
abstract private class PathNodeImpl extends TPathNode {
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
abstract FlowState getState();
FlowState getState() { none() }
/** Gets the associated configuration. */
abstract Configuration getConfiguration();
Configuration getConfiguration() { none() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
abstract predicate isSource();
predicate isSource() { none() }
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
@@ -2938,22 +2953,6 @@ abstract private class PathNodeImpl extends TPathNode {
)
}
string getSourceGroup() {
this.isSource() and
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
}
predicate isFlowSource() {
this.isSource() and not exists(this.getSourceGroup())
or
this instanceof PathNodeSourceGroup
}
predicate isFlowSink() {
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
this instanceof PathNodeSinkGroup
}
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -2968,23 +2967,13 @@ abstract private class PathNodeImpl extends TPathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
/** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2993,71 +2982,18 @@ abstract private class PathNodeImpl extends TPathNode {
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or
n instanceof PathNodeSinkGroup or
directReach(n.getANonHiddenSuccessor())
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
/** Holds if this node is a grouping of source nodes. */
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
/** Holds if this node is a grouping of sink nodes. */
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
/**
* Provides the query predicates needed to include a graph in a path-problem query.
@@ -3068,7 +3004,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
key = "semmle.label" and val = n.toString()
reach(n) and key = "semmle.label" and val = n.toString()
}
/**
@@ -3077,7 +3013,11 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out)
Subpaths::subpaths(arg, par, ret, out) and
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
}
}
@@ -3178,66 +3118,9 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
}
override predicate isSource() { sourceNode(node, state, config) }
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
}
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
string sourceGroup;
Configuration config;
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result.getSourceGroup() = sourceGroup and
result.getConfiguration() = config
}
override predicate isSource() { none() }
override string toString() { result = sourceGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
}
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
string sinkGroup;
Configuration config;
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { none() }
override string toString() { result = sinkGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
override predicate isSource() { sourceNode(node, state, config) }
}
private predicate pathNode(
@@ -3259,7 +3142,6 @@ private predicate pathNode(
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
@@ -3517,7 +3399,7 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths02(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout
) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3525,14 +3407,14 @@ private module Subpaths {
}
pragma[nomagic]
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/
pragma[nomagic]
private predicate subpaths03(
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3562,7 +3444,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3578,7 +3460,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNodeImpl n) {
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNodeImpl mid |
retReach(mid) and
@@ -3594,22 +3476,12 @@ private module Subpaths {
* Will only have results if `configuration` has non-empty sources and
* sinks.
*/
private predicate hasFlowPath(
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
) {
flowsource.isFlowSource() and
flowsource.getConfiguration() = configuration and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.isFlowSink()
}
private predicate flowsTo(
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
flowsource.getNodeEx().asNode() = source and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink
}
@@ -3632,14 +3504,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNodeImpl pn)
tuples = count(PathNode pn)
or
fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn)
tuples = count(PathNode pn | reach(pn))
}
/**

View File

@@ -147,12 +147,6 @@ abstract class Configuration extends string {
*/
FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -164,7 +158,7 @@ abstract class Configuration extends string {
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
@@ -2635,7 +2629,6 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
/**
* Gets the number of `AccessPath`s that correspond to `apa`.
*/
pragma[assume_small_delta]
private int countAps(AccessPathApprox apa, Configuration config) {
evalUnfold(apa, false, config) and
result = 1 and
@@ -2654,7 +2647,6 @@ private int countAps(AccessPathApprox apa, Configuration config) {
* that it is expanded to a precise head-tail representation.
*/
language[monotonicAggregates]
pragma[assume_small_delta]
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
apa instanceof AccessPathApproxNil and result = 1
or
@@ -2689,7 +2681,6 @@ private newtype TAccessPath =
}
private newtype TPathNode =
pragma[assume_small_delta]
TPathNodeMid(
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) {
@@ -2718,18 +2709,6 @@ private newtype TPathNode =
state = sink.getState() and
config = sink.getConfiguration()
)
} or
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
exists(PathNodeImpl source |
sourceGroup = source.getSourceGroup() and
config = source.getConfiguration()
)
} or
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
exists(PathNodeSink sink |
sinkGroup = sink.getSinkGroup() and
config = sink.getConfiguration()
)
}
/**
@@ -2799,7 +2778,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
pragma[assume_small_delta]
override AccessPathApproxCons getApprox() {
result = TConsNil(head, tail.(AccessPathNil).getType())
or
@@ -2808,7 +2786,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
result = TCons1(head, this.length())
}
pragma[assume_small_delta]
override int length() { result = 1 + tail.length() }
private string toStringImpl(boolean needsSuffix) {
@@ -2897,16 +2874,54 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
}
}
abstract private class PathNodeImpl extends TPathNode {
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
abstract FlowState getState();
FlowState getState() { none() }
/** Gets the associated configuration. */
abstract Configuration getConfiguration();
Configuration getConfiguration() { none() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
abstract predicate isSource();
predicate isSource() { none() }
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
@@ -2938,22 +2953,6 @@ abstract private class PathNodeImpl extends TPathNode {
)
}
string getSourceGroup() {
this.isSource() and
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
}
predicate isFlowSource() {
this.isSource() and not exists(this.getSourceGroup())
or
this instanceof PathNodeSourceGroup
}
predicate isFlowSink() {
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
this instanceof PathNodeSinkGroup
}
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -2968,23 +2967,13 @@ abstract private class PathNodeImpl extends TPathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
/** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2993,71 +2982,18 @@ abstract private class PathNodeImpl extends TPathNode {
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or
n instanceof PathNodeSinkGroup or
directReach(n.getANonHiddenSuccessor())
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
/** Holds if this node is a grouping of source nodes. */
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
/** Holds if this node is a grouping of sink nodes. */
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
/**
* Provides the query predicates needed to include a graph in a path-problem query.
@@ -3068,7 +3004,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
key = "semmle.label" and val = n.toString()
reach(n) and key = "semmle.label" and val = n.toString()
}
/**
@@ -3077,7 +3013,11 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out)
Subpaths::subpaths(arg, par, ret, out) and
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
}
}
@@ -3178,66 +3118,9 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
}
override predicate isSource() { sourceNode(node, state, config) }
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
}
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
string sourceGroup;
Configuration config;
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result.getSourceGroup() = sourceGroup and
result.getConfiguration() = config
}
override predicate isSource() { none() }
override string toString() { result = sourceGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
}
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
string sinkGroup;
Configuration config;
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { none() }
override string toString() { result = sinkGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
override predicate isSource() { sourceNode(node, state, config) }
}
private predicate pathNode(
@@ -3259,7 +3142,6 @@ private predicate pathNode(
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
@@ -3517,7 +3399,7 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths02(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout
) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3525,14 +3407,14 @@ private module Subpaths {
}
pragma[nomagic]
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/
pragma[nomagic]
private predicate subpaths03(
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3562,7 +3444,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3578,7 +3460,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNodeImpl n) {
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNodeImpl mid |
retReach(mid) and
@@ -3594,22 +3476,12 @@ private module Subpaths {
* Will only have results if `configuration` has non-empty sources and
* sinks.
*/
private predicate hasFlowPath(
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
) {
flowsource.isFlowSource() and
flowsource.getConfiguration() = configuration and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.isFlowSink()
}
private predicate flowsTo(
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
flowsource.getNodeEx().asNode() = source and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink
}
@@ -3632,14 +3504,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNodeImpl pn)
tuples = count(PathNode pn)
or
fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn)
tuples = count(PathNode pn | reach(pn))
}
/**

View File

@@ -147,12 +147,6 @@ abstract class Configuration extends string {
*/
FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -164,7 +158,7 @@ abstract class Configuration extends string {
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
@@ -2635,7 +2629,6 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
/**
* Gets the number of `AccessPath`s that correspond to `apa`.
*/
pragma[assume_small_delta]
private int countAps(AccessPathApprox apa, Configuration config) {
evalUnfold(apa, false, config) and
result = 1 and
@@ -2654,7 +2647,6 @@ private int countAps(AccessPathApprox apa, Configuration config) {
* that it is expanded to a precise head-tail representation.
*/
language[monotonicAggregates]
pragma[assume_small_delta]
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
apa instanceof AccessPathApproxNil and result = 1
or
@@ -2689,7 +2681,6 @@ private newtype TAccessPath =
}
private newtype TPathNode =
pragma[assume_small_delta]
TPathNodeMid(
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) {
@@ -2718,18 +2709,6 @@ private newtype TPathNode =
state = sink.getState() and
config = sink.getConfiguration()
)
} or
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
exists(PathNodeImpl source |
sourceGroup = source.getSourceGroup() and
config = source.getConfiguration()
)
} or
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
exists(PathNodeSink sink |
sinkGroup = sink.getSinkGroup() and
config = sink.getConfiguration()
)
}
/**
@@ -2799,7 +2778,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
pragma[assume_small_delta]
override AccessPathApproxCons getApprox() {
result = TConsNil(head, tail.(AccessPathNil).getType())
or
@@ -2808,7 +2786,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
result = TCons1(head, this.length())
}
pragma[assume_small_delta]
override int length() { result = 1 + tail.length() }
private string toStringImpl(boolean needsSuffix) {
@@ -2897,16 +2874,54 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
}
}
abstract private class PathNodeImpl extends TPathNode {
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
abstract FlowState getState();
FlowState getState() { none() }
/** Gets the associated configuration. */
abstract Configuration getConfiguration();
Configuration getConfiguration() { none() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
abstract predicate isSource();
predicate isSource() { none() }
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
@@ -2938,22 +2953,6 @@ abstract private class PathNodeImpl extends TPathNode {
)
}
string getSourceGroup() {
this.isSource() and
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
}
predicate isFlowSource() {
this.isSource() and not exists(this.getSourceGroup())
or
this instanceof PathNodeSourceGroup
}
predicate isFlowSink() {
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
this instanceof PathNodeSinkGroup
}
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -2968,23 +2967,13 @@ abstract private class PathNodeImpl extends TPathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
/** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2993,71 +2982,18 @@ abstract private class PathNodeImpl extends TPathNode {
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or
n instanceof PathNodeSinkGroup or
directReach(n.getANonHiddenSuccessor())
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
/** Holds if this node is a grouping of source nodes. */
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
/** Holds if this node is a grouping of sink nodes. */
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
/**
* Provides the query predicates needed to include a graph in a path-problem query.
@@ -3068,7 +3004,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
key = "semmle.label" and val = n.toString()
reach(n) and key = "semmle.label" and val = n.toString()
}
/**
@@ -3077,7 +3013,11 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out)
Subpaths::subpaths(arg, par, ret, out) and
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
}
}
@@ -3178,66 +3118,9 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
}
override predicate isSource() { sourceNode(node, state, config) }
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
}
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
string sourceGroup;
Configuration config;
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result.getSourceGroup() = sourceGroup and
result.getConfiguration() = config
}
override predicate isSource() { none() }
override string toString() { result = sourceGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
}
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
string sinkGroup;
Configuration config;
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { none() }
override string toString() { result = sinkGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
override predicate isSource() { sourceNode(node, state, config) }
}
private predicate pathNode(
@@ -3259,7 +3142,6 @@ private predicate pathNode(
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
@@ -3517,7 +3399,7 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths02(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout
) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3525,14 +3407,14 @@ private module Subpaths {
}
pragma[nomagic]
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/
pragma[nomagic]
private predicate subpaths03(
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3562,7 +3444,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3578,7 +3460,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNodeImpl n) {
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNodeImpl mid |
retReach(mid) and
@@ -3594,22 +3476,12 @@ private module Subpaths {
* Will only have results if `configuration` has non-empty sources and
* sinks.
*/
private predicate hasFlowPath(
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
) {
flowsource.isFlowSource() and
flowsource.getConfiguration() = configuration and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.isFlowSink()
}
private predicate flowsTo(
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
flowsource.getNodeEx().asNode() = source and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink
}
@@ -3632,14 +3504,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNodeImpl pn)
tuples = count(PathNode pn)
or
fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn)
tuples = count(PathNode pn | reach(pn))
}
/**

View File

@@ -136,18 +136,6 @@ module Consistency {
msg = "Local flow step does not preserve enclosing callable."
}
query predicate readStepIsLocal(Node n1, Node n2, string msg) {
readStep(n1, _, n2) and
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
msg = "Read step does not preserve enclosing callable."
}
query predicate storeStepIsLocal(Node n1, Node n2, string msg) {
storeStep(n1, _, n2) and
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
msg = "Store step does not preserve enclosing callable."
}
private DataFlowType typeRepr() { result = getNodeType(_) }
query predicate compatibleTypesReflexive(DataFlowType t, string msg) {

View File

@@ -147,12 +147,6 @@ abstract class Configuration extends string {
*/
FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -164,7 +158,7 @@ abstract class Configuration extends string {
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
@@ -2635,7 +2629,6 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
/**
* Gets the number of `AccessPath`s that correspond to `apa`.
*/
pragma[assume_small_delta]
private int countAps(AccessPathApprox apa, Configuration config) {
evalUnfold(apa, false, config) and
result = 1 and
@@ -2654,7 +2647,6 @@ private int countAps(AccessPathApprox apa, Configuration config) {
* that it is expanded to a precise head-tail representation.
*/
language[monotonicAggregates]
pragma[assume_small_delta]
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
apa instanceof AccessPathApproxNil and result = 1
or
@@ -2689,7 +2681,6 @@ private newtype TAccessPath =
}
private newtype TPathNode =
pragma[assume_small_delta]
TPathNodeMid(
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) {
@@ -2718,18 +2709,6 @@ private newtype TPathNode =
state = sink.getState() and
config = sink.getConfiguration()
)
} or
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
exists(PathNodeImpl source |
sourceGroup = source.getSourceGroup() and
config = source.getConfiguration()
)
} or
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
exists(PathNodeSink sink |
sinkGroup = sink.getSinkGroup() and
config = sink.getConfiguration()
)
}
/**
@@ -2799,7 +2778,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
pragma[assume_small_delta]
override AccessPathApproxCons getApprox() {
result = TConsNil(head, tail.(AccessPathNil).getType())
or
@@ -2808,7 +2786,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
result = TCons1(head, this.length())
}
pragma[assume_small_delta]
override int length() { result = 1 + tail.length() }
private string toStringImpl(boolean needsSuffix) {
@@ -2897,16 +2874,54 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
}
}
abstract private class PathNodeImpl extends TPathNode {
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
abstract FlowState getState();
FlowState getState() { none() }
/** Gets the associated configuration. */
abstract Configuration getConfiguration();
Configuration getConfiguration() { none() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
abstract predicate isSource();
predicate isSource() { none() }
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
@@ -2938,22 +2953,6 @@ abstract private class PathNodeImpl extends TPathNode {
)
}
string getSourceGroup() {
this.isSource() and
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
}
predicate isFlowSource() {
this.isSource() and not exists(this.getSourceGroup())
or
this instanceof PathNodeSourceGroup
}
predicate isFlowSink() {
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
this instanceof PathNodeSinkGroup
}
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -2968,23 +2967,13 @@ abstract private class PathNodeImpl extends TPathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
/** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2993,71 +2982,18 @@ abstract private class PathNodeImpl extends TPathNode {
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or
n instanceof PathNodeSinkGroup or
directReach(n.getANonHiddenSuccessor())
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
/** Holds if this node is a grouping of source nodes. */
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
/** Holds if this node is a grouping of sink nodes. */
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
/**
* Provides the query predicates needed to include a graph in a path-problem query.
@@ -3068,7 +3004,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
key = "semmle.label" and val = n.toString()
reach(n) and key = "semmle.label" and val = n.toString()
}
/**
@@ -3077,7 +3013,11 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out)
Subpaths::subpaths(arg, par, ret, out) and
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
}
}
@@ -3178,66 +3118,9 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
}
override predicate isSource() { sourceNode(node, state, config) }
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
}
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
string sourceGroup;
Configuration config;
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result.getSourceGroup() = sourceGroup and
result.getConfiguration() = config
}
override predicate isSource() { none() }
override string toString() { result = sourceGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
}
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
string sinkGroup;
Configuration config;
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { none() }
override string toString() { result = sinkGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
override predicate isSource() { sourceNode(node, state, config) }
}
private predicate pathNode(
@@ -3259,7 +3142,6 @@ private predicate pathNode(
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
@@ -3517,7 +3399,7 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths02(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout
) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3525,14 +3407,14 @@ private module Subpaths {
}
pragma[nomagic]
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/
pragma[nomagic]
private predicate subpaths03(
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3562,7 +3444,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3578,7 +3460,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNodeImpl n) {
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNodeImpl mid |
retReach(mid) and
@@ -3594,22 +3476,12 @@ private module Subpaths {
* Will only have results if `configuration` has non-empty sources and
* sinks.
*/
private predicate hasFlowPath(
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
) {
flowsource.isFlowSource() and
flowsource.getConfiguration() = configuration and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.isFlowSink()
}
private predicate flowsTo(
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
flowsource.getNodeEx().asNode() = source and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink
}
@@ -3632,14 +3504,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNodeImpl pn)
tuples = count(PathNode pn)
or
fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn)
tuples = count(PathNode pn | reach(pn))
}
/**

View File

@@ -5,6 +5,7 @@
*/
private import cpp
import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.IR
/**
@@ -24,18 +25,18 @@ abstract class MustFlowConfiguration extends string {
/**
* Holds if `source` is a relevant data flow source.
*/
abstract predicate isSource(Instruction source);
abstract predicate isSource(DataFlow::Node source);
/**
* Holds if `sink` is a relevant data flow sink.
*/
abstract predicate isSink(Operand sink);
abstract predicate isSink(DataFlow::Node sink);
/**
* 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() }
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
/** Holds if this configuration allows flow from arguments to parameters. */
predicate allowInterproceduralFlow() { any() }
@@ -47,17 +48,17 @@ abstract class MustFlowConfiguration extends string {
* included in the module `PathGraph`.
*/
final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) {
this.isSource(source.getInstruction()) and
this.isSource(source.getNode()) and
source.getASuccessor+() = sink
}
}
/** Holds if `node` flows from a source. */
pragma[nomagic]
private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) {
private predicate flowsFromSource(DataFlow::Node node, MustFlowConfiguration config) {
config.isSource(node)
or
exists(Instruction mid |
exists(DataFlow::Node mid |
step(mid, node, config) and
flowsFromSource(mid, pragma[only_bind_into](config))
)
@@ -65,12 +66,12 @@ private predicate flowsFromSource(Instruction node, MustFlowConfiguration config
/** Holds if `node` flows to a sink. */
pragma[nomagic]
private predicate flowsToSink(Instruction node, MustFlowConfiguration config) {
private predicate flowsToSink(DataFlow::Node node, MustFlowConfiguration config) {
flowsFromSource(node, pragma[only_bind_into](config)) and
(
config.isSink(node.getAUse())
config.isSink(node)
or
exists(Instruction mid |
exists(DataFlow::Node mid |
step(node, mid, config) and
flowsToSink(mid, pragma[only_bind_into](config))
)
@@ -197,13 +198,12 @@ private module Cached {
}
cached
predicate step(Instruction nodeFrom, Instruction nodeTo) {
exists(Operand mid |
instructionToOperandStep(nodeFrom, mid) and
operandToInstructionStep(mid, nodeTo)
)
predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
instructionToOperandStep(nodeFrom.asInstruction(), nodeTo.asOperand())
or
flowThroughCallable(nodeFrom, nodeTo)
flowThroughCallable(nodeFrom.asInstruction(), nodeTo.asInstruction())
or
operandToInstructionStep(nodeFrom.asOperand(), nodeTo.asInstruction())
}
}
@@ -213,12 +213,12 @@ private module Cached {
* way around.
*/
pragma[inline]
private IRFunction getEnclosingCallable(Instruction n) {
pragma[only_bind_into](result) = pragma[only_bind_out](n).getEnclosingIRFunction()
private Declaration getEnclosingCallable(DataFlow::Node n) {
pragma[only_bind_into](result) = pragma[only_bind_out](n).getEnclosingCallable()
}
/** Holds if `nodeFrom` flows to `nodeTo`. */
private predicate step(Instruction nodeFrom, Instruction nodeTo, MustFlowConfiguration config) {
private predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, MustFlowConfiguration config) {
exists(config) and
Cached::step(pragma[only_bind_into](nodeFrom), pragma[only_bind_into](nodeTo)) and
(
@@ -227,37 +227,37 @@ private predicate step(Instruction nodeFrom, Instruction nodeTo, MustFlowConfigu
getEnclosingCallable(nodeFrom) = getEnclosingCallable(nodeTo)
)
or
config.isAdditionalFlowStep(nodeFrom.getAUse(), nodeTo)
config.isAdditionalFlowStep(nodeFrom, nodeTo)
}
private newtype TLocalPathNode =
MkLocalPathNode(Instruction n, MustFlowConfiguration config) {
MkLocalPathNode(DataFlow::Node n, MustFlowConfiguration config) {
flowsToSink(n, config) and
(
config.isSource(n)
or
exists(MustFlowPathNode mid | step(mid.getInstruction(), n, config))
exists(MustFlowPathNode mid | step(mid.getNode(), n, config))
)
}
/** A `Node` that is in a path from a source to a sink. */
class MustFlowPathNode extends TLocalPathNode {
Instruction n;
DataFlow::Node n;
MustFlowPathNode() { this = MkLocalPathNode(n, _) }
/** Gets the underlying node. */
Instruction getInstruction() { result = n }
DataFlow::Node getNode() { result = n }
/** Gets a textual representation of this node. */
string toString() { result = n.getAst().toString() }
string toString() { result = n.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())
step(this.getNode(), result.getNode(), this.getConfiguration())
}
/** Gets the associated configuration. */
@@ -265,7 +265,7 @@ class MustFlowPathNode extends TLocalPathNode {
}
private class MustFlowPathSink extends MustFlowPathNode {
MustFlowPathSink() { this.getConfiguration().isSink(this.getInstruction().getAUse()) }
MustFlowPathSink() { this.getConfiguration().isSink(this.getNode()) }
}
/**

View File

@@ -147,12 +147,6 @@ abstract class Configuration extends string {
*/
FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -164,7 +158,7 @@ abstract class Configuration extends string {
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
@@ -2635,7 +2629,6 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
/**
* Gets the number of `AccessPath`s that correspond to `apa`.
*/
pragma[assume_small_delta]
private int countAps(AccessPathApprox apa, Configuration config) {
evalUnfold(apa, false, config) and
result = 1 and
@@ -2654,7 +2647,6 @@ private int countAps(AccessPathApprox apa, Configuration config) {
* that it is expanded to a precise head-tail representation.
*/
language[monotonicAggregates]
pragma[assume_small_delta]
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
apa instanceof AccessPathApproxNil and result = 1
or
@@ -2689,7 +2681,6 @@ private newtype TAccessPath =
}
private newtype TPathNode =
pragma[assume_small_delta]
TPathNodeMid(
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) {
@@ -2718,18 +2709,6 @@ private newtype TPathNode =
state = sink.getState() and
config = sink.getConfiguration()
)
} or
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
exists(PathNodeImpl source |
sourceGroup = source.getSourceGroup() and
config = source.getConfiguration()
)
} or
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
exists(PathNodeSink sink |
sinkGroup = sink.getSinkGroup() and
config = sink.getConfiguration()
)
}
/**
@@ -2799,7 +2778,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
pragma[assume_small_delta]
override AccessPathApproxCons getApprox() {
result = TConsNil(head, tail.(AccessPathNil).getType())
or
@@ -2808,7 +2786,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
result = TCons1(head, this.length())
}
pragma[assume_small_delta]
override int length() { result = 1 + tail.length() }
private string toStringImpl(boolean needsSuffix) {
@@ -2897,16 +2874,54 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
}
}
abstract private class PathNodeImpl extends TPathNode {
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
abstract FlowState getState();
FlowState getState() { none() }
/** Gets the associated configuration. */
abstract Configuration getConfiguration();
Configuration getConfiguration() { none() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
abstract predicate isSource();
predicate isSource() { none() }
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
@@ -2938,22 +2953,6 @@ abstract private class PathNodeImpl extends TPathNode {
)
}
string getSourceGroup() {
this.isSource() and
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
}
predicate isFlowSource() {
this.isSource() and not exists(this.getSourceGroup())
or
this instanceof PathNodeSourceGroup
}
predicate isFlowSink() {
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
this instanceof PathNodeSinkGroup
}
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -2968,23 +2967,13 @@ abstract private class PathNodeImpl extends TPathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
/** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2993,71 +2982,18 @@ abstract private class PathNodeImpl extends TPathNode {
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or
n instanceof PathNodeSinkGroup or
directReach(n.getANonHiddenSuccessor())
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
/** Holds if this node is a grouping of source nodes. */
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
/** Holds if this node is a grouping of sink nodes. */
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
/**
* Provides the query predicates needed to include a graph in a path-problem query.
@@ -3068,7 +3004,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
key = "semmle.label" and val = n.toString()
reach(n) and key = "semmle.label" and val = n.toString()
}
/**
@@ -3077,7 +3013,11 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out)
Subpaths::subpaths(arg, par, ret, out) and
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
}
}
@@ -3178,66 +3118,9 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
}
override predicate isSource() { sourceNode(node, state, config) }
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
}
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
string sourceGroup;
Configuration config;
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result.getSourceGroup() = sourceGroup and
result.getConfiguration() = config
}
override predicate isSource() { none() }
override string toString() { result = sourceGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
}
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
string sinkGroup;
Configuration config;
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { none() }
override string toString() { result = sinkGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
override predicate isSource() { sourceNode(node, state, config) }
}
private predicate pathNode(
@@ -3259,7 +3142,6 @@ private predicate pathNode(
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
@@ -3517,7 +3399,7 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths02(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout
) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3525,14 +3407,14 @@ private module Subpaths {
}
pragma[nomagic]
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/
pragma[nomagic]
private predicate subpaths03(
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3562,7 +3444,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3578,7 +3460,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNodeImpl n) {
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNodeImpl mid |
retReach(mid) and
@@ -3594,22 +3476,12 @@ private module Subpaths {
* Will only have results if `configuration` has non-empty sources and
* sinks.
*/
private predicate hasFlowPath(
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
) {
flowsource.isFlowSource() and
flowsource.getConfiguration() = configuration and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.isFlowSink()
}
private predicate flowsTo(
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
flowsource.getNodeEx().asNode() = source and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink
}
@@ -3632,14 +3504,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNodeImpl pn)
tuples = count(PathNode pn)
or
fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn)
tuples = count(PathNode pn | reach(pn))
}
/**

View File

@@ -147,12 +147,6 @@ abstract class Configuration extends string {
*/
FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -164,7 +158,7 @@ abstract class Configuration extends string {
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
@@ -2635,7 +2629,6 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
/**
* Gets the number of `AccessPath`s that correspond to `apa`.
*/
pragma[assume_small_delta]
private int countAps(AccessPathApprox apa, Configuration config) {
evalUnfold(apa, false, config) and
result = 1 and
@@ -2654,7 +2647,6 @@ private int countAps(AccessPathApprox apa, Configuration config) {
* that it is expanded to a precise head-tail representation.
*/
language[monotonicAggregates]
pragma[assume_small_delta]
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
apa instanceof AccessPathApproxNil and result = 1
or
@@ -2689,7 +2681,6 @@ private newtype TAccessPath =
}
private newtype TPathNode =
pragma[assume_small_delta]
TPathNodeMid(
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) {
@@ -2718,18 +2709,6 @@ private newtype TPathNode =
state = sink.getState() and
config = sink.getConfiguration()
)
} or
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
exists(PathNodeImpl source |
sourceGroup = source.getSourceGroup() and
config = source.getConfiguration()
)
} or
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
exists(PathNodeSink sink |
sinkGroup = sink.getSinkGroup() and
config = sink.getConfiguration()
)
}
/**
@@ -2799,7 +2778,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
pragma[assume_small_delta]
override AccessPathApproxCons getApprox() {
result = TConsNil(head, tail.(AccessPathNil).getType())
or
@@ -2808,7 +2786,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
result = TCons1(head, this.length())
}
pragma[assume_small_delta]
override int length() { result = 1 + tail.length() }
private string toStringImpl(boolean needsSuffix) {
@@ -2897,16 +2874,54 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
}
}
abstract private class PathNodeImpl extends TPathNode {
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
abstract FlowState getState();
FlowState getState() { none() }
/** Gets the associated configuration. */
abstract Configuration getConfiguration();
Configuration getConfiguration() { none() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
abstract predicate isSource();
predicate isSource() { none() }
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
@@ -2938,22 +2953,6 @@ abstract private class PathNodeImpl extends TPathNode {
)
}
string getSourceGroup() {
this.isSource() and
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
}
predicate isFlowSource() {
this.isSource() and not exists(this.getSourceGroup())
or
this instanceof PathNodeSourceGroup
}
predicate isFlowSink() {
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
this instanceof PathNodeSinkGroup
}
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -2968,23 +2967,13 @@ abstract private class PathNodeImpl extends TPathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
/** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2993,71 +2982,18 @@ abstract private class PathNodeImpl extends TPathNode {
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or
n instanceof PathNodeSinkGroup or
directReach(n.getANonHiddenSuccessor())
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
/** Holds if this node is a grouping of source nodes. */
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
/** Holds if this node is a grouping of sink nodes. */
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
/**
* Provides the query predicates needed to include a graph in a path-problem query.
@@ -3068,7 +3004,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
key = "semmle.label" and val = n.toString()
reach(n) and key = "semmle.label" and val = n.toString()
}
/**
@@ -3077,7 +3013,11 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out)
Subpaths::subpaths(arg, par, ret, out) and
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
}
}
@@ -3178,66 +3118,9 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
}
override predicate isSource() { sourceNode(node, state, config) }
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
}
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
string sourceGroup;
Configuration config;
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result.getSourceGroup() = sourceGroup and
result.getConfiguration() = config
}
override predicate isSource() { none() }
override string toString() { result = sourceGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
}
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
string sinkGroup;
Configuration config;
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { none() }
override string toString() { result = sinkGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
override predicate isSource() { sourceNode(node, state, config) }
}
private predicate pathNode(
@@ -3259,7 +3142,6 @@ private predicate pathNode(
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
@@ -3517,7 +3399,7 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths02(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout
) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3525,14 +3407,14 @@ private module Subpaths {
}
pragma[nomagic]
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/
pragma[nomagic]
private predicate subpaths03(
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3562,7 +3444,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3578,7 +3460,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNodeImpl n) {
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNodeImpl mid |
retReach(mid) and
@@ -3594,22 +3476,12 @@ private module Subpaths {
* Will only have results if `configuration` has non-empty sources and
* sinks.
*/
private predicate hasFlowPath(
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
) {
flowsource.isFlowSource() and
flowsource.getConfiguration() = configuration and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.isFlowSink()
}
private predicate flowsTo(
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
flowsource.getNodeEx().asNode() = source and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink
}
@@ -3632,14 +3504,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNodeImpl pn)
tuples = count(PathNode pn)
or
fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn)
tuples = count(PathNode pn | reach(pn))
}
/**

View File

@@ -147,12 +147,6 @@ abstract class Configuration extends string {
*/
FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -164,7 +158,7 @@ abstract class Configuration extends string {
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
@@ -2635,7 +2629,6 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
/**
* Gets the number of `AccessPath`s that correspond to `apa`.
*/
pragma[assume_small_delta]
private int countAps(AccessPathApprox apa, Configuration config) {
evalUnfold(apa, false, config) and
result = 1 and
@@ -2654,7 +2647,6 @@ private int countAps(AccessPathApprox apa, Configuration config) {
* that it is expanded to a precise head-tail representation.
*/
language[monotonicAggregates]
pragma[assume_small_delta]
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
apa instanceof AccessPathApproxNil and result = 1
or
@@ -2689,7 +2681,6 @@ private newtype TAccessPath =
}
private newtype TPathNode =
pragma[assume_small_delta]
TPathNodeMid(
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) {
@@ -2718,18 +2709,6 @@ private newtype TPathNode =
state = sink.getState() and
config = sink.getConfiguration()
)
} or
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
exists(PathNodeImpl source |
sourceGroup = source.getSourceGroup() and
config = source.getConfiguration()
)
} or
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
exists(PathNodeSink sink |
sinkGroup = sink.getSinkGroup() and
config = sink.getConfiguration()
)
}
/**
@@ -2799,7 +2778,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
pragma[assume_small_delta]
override AccessPathApproxCons getApprox() {
result = TConsNil(head, tail.(AccessPathNil).getType())
or
@@ -2808,7 +2786,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
result = TCons1(head, this.length())
}
pragma[assume_small_delta]
override int length() { result = 1 + tail.length() }
private string toStringImpl(boolean needsSuffix) {
@@ -2897,16 +2874,54 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
}
}
abstract private class PathNodeImpl extends TPathNode {
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
abstract FlowState getState();
FlowState getState() { none() }
/** Gets the associated configuration. */
abstract Configuration getConfiguration();
Configuration getConfiguration() { none() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
abstract predicate isSource();
predicate isSource() { none() }
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
@@ -2938,22 +2953,6 @@ abstract private class PathNodeImpl extends TPathNode {
)
}
string getSourceGroup() {
this.isSource() and
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
}
predicate isFlowSource() {
this.isSource() and not exists(this.getSourceGroup())
or
this instanceof PathNodeSourceGroup
}
predicate isFlowSink() {
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
this instanceof PathNodeSinkGroup
}
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -2968,23 +2967,13 @@ abstract private class PathNodeImpl extends TPathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
/** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2993,71 +2982,18 @@ abstract private class PathNodeImpl extends TPathNode {
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or
n instanceof PathNodeSinkGroup or
directReach(n.getANonHiddenSuccessor())
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
/** Holds if this node is a grouping of source nodes. */
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
/** Holds if this node is a grouping of sink nodes. */
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
/**
* Provides the query predicates needed to include a graph in a path-problem query.
@@ -3068,7 +3004,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
key = "semmle.label" and val = n.toString()
reach(n) and key = "semmle.label" and val = n.toString()
}
/**
@@ -3077,7 +3013,11 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out)
Subpaths::subpaths(arg, par, ret, out) and
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
}
}
@@ -3178,66 +3118,9 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
}
override predicate isSource() { sourceNode(node, state, config) }
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
}
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
string sourceGroup;
Configuration config;
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result.getSourceGroup() = sourceGroup and
result.getConfiguration() = config
}
override predicate isSource() { none() }
override string toString() { result = sourceGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
}
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
string sinkGroup;
Configuration config;
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { none() }
override string toString() { result = sinkGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
override predicate isSource() { sourceNode(node, state, config) }
}
private predicate pathNode(
@@ -3259,7 +3142,6 @@ private predicate pathNode(
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
@@ -3517,7 +3399,7 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths02(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout
) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3525,14 +3407,14 @@ private module Subpaths {
}
pragma[nomagic]
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/
pragma[nomagic]
private predicate subpaths03(
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3562,7 +3444,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3578,7 +3460,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNodeImpl n) {
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNodeImpl mid |
retReach(mid) and
@@ -3594,22 +3476,12 @@ private module Subpaths {
* Will only have results if `configuration` has non-empty sources and
* sinks.
*/
private predicate hasFlowPath(
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
) {
flowsource.isFlowSource() and
flowsource.getConfiguration() = configuration and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.isFlowSink()
}
private predicate flowsTo(
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
flowsource.getNodeEx().asNode() = source and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink
}
@@ -3632,14 +3504,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNodeImpl pn)
tuples = count(PathNode pn)
or
fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn)
tuples = count(PathNode pn | reach(pn))
}
/**

View File

@@ -147,12 +147,6 @@ abstract class Configuration extends string {
*/
FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -164,7 +158,7 @@ abstract class Configuration extends string {
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
@@ -2635,7 +2629,6 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
/**
* Gets the number of `AccessPath`s that correspond to `apa`.
*/
pragma[assume_small_delta]
private int countAps(AccessPathApprox apa, Configuration config) {
evalUnfold(apa, false, config) and
result = 1 and
@@ -2654,7 +2647,6 @@ private int countAps(AccessPathApprox apa, Configuration config) {
* that it is expanded to a precise head-tail representation.
*/
language[monotonicAggregates]
pragma[assume_small_delta]
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
apa instanceof AccessPathApproxNil and result = 1
or
@@ -2689,7 +2681,6 @@ private newtype TAccessPath =
}
private newtype TPathNode =
pragma[assume_small_delta]
TPathNodeMid(
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) {
@@ -2718,18 +2709,6 @@ private newtype TPathNode =
state = sink.getState() and
config = sink.getConfiguration()
)
} or
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
exists(PathNodeImpl source |
sourceGroup = source.getSourceGroup() and
config = source.getConfiguration()
)
} or
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
exists(PathNodeSink sink |
sinkGroup = sink.getSinkGroup() and
config = sink.getConfiguration()
)
}
/**
@@ -2799,7 +2778,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
pragma[assume_small_delta]
override AccessPathApproxCons getApprox() {
result = TConsNil(head, tail.(AccessPathNil).getType())
or
@@ -2808,7 +2786,6 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
result = TCons1(head, this.length())
}
pragma[assume_small_delta]
override int length() { result = 1 + tail.length() }
private string toStringImpl(boolean needsSuffix) {
@@ -2897,16 +2874,54 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
}
}
abstract private class PathNodeImpl extends TPathNode {
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
abstract FlowState getState();
FlowState getState() { none() }
/** Gets the associated configuration. */
abstract Configuration getConfiguration();
Configuration getConfiguration() { none() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
abstract predicate isSource();
predicate isSource() { none() }
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
@@ -2938,22 +2953,6 @@ abstract private class PathNodeImpl extends TPathNode {
)
}
string getSourceGroup() {
this.isSource() and
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
}
predicate isFlowSource() {
this.isSource() and not exists(this.getSourceGroup())
or
this instanceof PathNodeSourceGroup
}
predicate isFlowSink() {
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
this instanceof PathNodeSinkGroup
}
private string ppAp() {
this instanceof PathNodeSink and result = ""
or
@@ -2968,23 +2967,13 @@ abstract private class PathNodeImpl extends TPathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
/** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2993,71 +2982,18 @@ abstract private class PathNodeImpl extends TPathNode {
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or
n instanceof PathNodeSinkGroup or
directReach(n.getANonHiddenSuccessor())
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
/** Holds if this node is a grouping of source nodes. */
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
/** Holds if this node is a grouping of sink nodes. */
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
/**
* Provides the query predicates needed to include a graph in a path-problem query.
@@ -3068,7 +3004,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
key = "semmle.label" and val = n.toString()
reach(n) and key = "semmle.label" and val = n.toString()
}
/**
@@ -3077,7 +3013,11 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out)
Subpaths::subpaths(arg, par, ret, out) and
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
}
}
@@ -3178,66 +3118,9 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
}
override predicate isSource() { sourceNode(node, state, config) }
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
}
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
string sourceGroup;
Configuration config;
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() {
result.getSourceGroup() = sourceGroup and
result.getConfiguration() = config
}
override predicate isSource() { none() }
override string toString() { result = sourceGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
}
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
string sinkGroup;
Configuration config;
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
override NodeEx getNodeEx() { none() }
override FlowState getState() { none() }
override Configuration getConfiguration() { result = config }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { none() }
override string toString() { result = sinkGroup }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
}
override predicate isSource() { sourceNode(node, state, config) }
}
private predicate pathNode(
@@ -3259,7 +3142,6 @@ private predicate pathNode(
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
@@ -3517,7 +3399,7 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths02(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout
) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3525,14 +3407,14 @@ private module Subpaths {
}
pragma[nomagic]
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/
pragma[nomagic]
private predicate subpaths03(
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3562,7 +3444,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3578,7 +3460,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNodeImpl n) {
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNodeImpl mid |
retReach(mid) and
@@ -3594,22 +3476,12 @@ private module Subpaths {
* Will only have results if `configuration` has non-empty sources and
* sinks.
*/
private predicate hasFlowPath(
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
) {
flowsource.isFlowSource() and
flowsource.getConfiguration() = configuration and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.isFlowSink()
}
private predicate flowsTo(
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
) {
flowsource.isSource() and
flowsource.getConfiguration() = configuration and
flowsource.getNodeEx().asNode() = source and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink
}
@@ -3632,14 +3504,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNodeImpl pn)
tuples = count(PathNode pn)
or
fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn)
tuples = count(PathNode pn | reach(pn))
}
/**

View File

@@ -136,18 +136,6 @@ module Consistency {
msg = "Local flow step does not preserve enclosing callable."
}
query predicate readStepIsLocal(Node n1, Node n2, string msg) {
readStep(n1, _, n2) and
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
msg = "Read step does not preserve enclosing callable."
}
query predicate storeStepIsLocal(Node n1, Node n2, string msg) {
storeStep(n1, _, n2) and
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
msg = "Store step does not preserve enclosing callable."
}
private DataFlowType typeRepr() { result = getNodeType(_) }
query predicate compatibleTypesReflexive(DataFlowType t, string msg) {

View File

@@ -98,16 +98,16 @@ class ParameterPosition = Position;
/** An argument position represented by an integer. */
class ArgumentPosition = Position;
abstract class Position extends TPosition {
class Position extends TPosition {
abstract string toString();
}
class DirectPosition extends Position, TDirectPosition {
class DirectPosition extends TDirectPosition {
int index;
DirectPosition() { this = TDirectPosition(index) }
override string toString() {
string toString() {
index = -1 and
result = "this"
or
@@ -118,12 +118,12 @@ class DirectPosition extends Position, TDirectPosition {
int getIndex() { result = index }
}
class IndirectionPosition extends Position, TIndirectionPosition {
class IndirectionPosition extends TIndirectionPosition {
int index;
IndirectionPosition() { this = TIndirectionPosition(index) }
override string toString() {
string toString() {
index = -1 and
result = "this"
or

View File

@@ -16,23 +16,21 @@ private class StdBasicString extends ClassTemplateInstantiation {
}
/**
* The `std::basic_string::iterator` declaration.
* Additional model for `std::string` constructors that reference the character
* type of the container, or an iterator. For example construction from
* iterators:
* ```
* std::string b(a.begin(), a.end());
* ```
*/
private class StdBasicStringIterator extends Iterator, Type {
StdBasicStringIterator() {
this.getEnclosingElement() instanceof StdBasicString and this.hasName("iterator")
}
}
private class StdStringConstructor extends Constructor, TaintFunction {
StdStringConstructor() { this.getDeclaringType() instanceof StdBasicString }
/**
* A `std::string` function for which taint should be propagated.
*/
abstract private class StdStringTaintFunction extends TaintFunction {
/**
* Gets the index of a parameter to this function that is a string (or
* character).
*/
final int getAStringParameterIndex() {
int getAStringParameterIndex() {
exists(Type paramType | paramType = this.getParameter(result).getUnspecifiedType() |
// e.g. `std::basic_string::CharT *`
paramType instanceof PointerType
@@ -43,28 +41,15 @@ abstract private class StdStringTaintFunction extends TaintFunction {
this.getDeclaringType().getTemplateArgument(2).(Type).getUnspecifiedType()
or
// i.e. `std::basic_string::CharT`
paramType = this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType()
this.getParameter(result).getUnspecifiedType() =
this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType()
)
}
/**
* Gets the index of a parameter to this function that is an iterator.
*/
final int getAnIteratorParameterIndex() {
this.getParameter(result).getType() instanceof Iterator
}
}
/**
* Additional model for `std::string` constructors that reference the character
* type of the container, or an iterator. For example construction from
* iterators:
* ```
* std::string b(a.begin(), a.end());
* ```
*/
private class StdStringConstructor extends Constructor, StdStringTaintFunction {
StdStringConstructor() { this.getDeclaringType() instanceof StdBasicString }
int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// taint flow from any parameter of the value type to the returned object
@@ -83,7 +68,7 @@ private class StdStringConstructor extends Constructor, StdStringTaintFunction {
/**
* The `std::string` function `c_str`.
*/
private class StdStringCStr extends StdStringTaintFunction {
private class StdStringCStr extends TaintFunction {
StdStringCStr() { this.getClassAndName("c_str") instanceof StdBasicString }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
@@ -96,7 +81,7 @@ private class StdStringCStr extends StdStringTaintFunction {
/**
* The `std::string` function `data`.
*/
private class StdStringData extends StdStringTaintFunction {
private class StdStringData extends TaintFunction {
StdStringData() { this.getClassAndName("data") instanceof StdBasicString }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
@@ -114,7 +99,7 @@ private class StdStringData extends StdStringTaintFunction {
/**
* The `std::string` function `push_back`.
*/
private class StdStringPush extends StdStringTaintFunction {
private class StdStringPush extends TaintFunction {
StdStringPush() { this.getClassAndName("push_back") instanceof StdBasicString }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
@@ -127,7 +112,7 @@ private class StdStringPush extends StdStringTaintFunction {
/**
* The `std::string` functions `front` and `back`.
*/
private class StdStringFrontBack extends StdStringTaintFunction {
private class StdStringFrontBack extends TaintFunction {
StdStringFrontBack() { this.getClassAndName(["front", "back"]) instanceof StdBasicString }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
@@ -140,7 +125,7 @@ private class StdStringFrontBack extends StdStringTaintFunction {
/**
* The (non-member) `std::string` function `operator+`.
*/
private class StdStringPlus extends StdStringTaintFunction {
private class StdStringPlus extends TaintFunction {
StdStringPlus() {
this.hasQualifiedName(["std", "bsl"], "operator+") and
this.getUnspecifiedType() instanceof StdBasicString
@@ -157,15 +142,31 @@ private class StdStringPlus extends StdStringTaintFunction {
}
/**
* The `std::string` functions `operator+=`, `append` and `replace`.
* All of these functions combine the existing string with a new
* string (or character) from one of the arguments.
* The `std::string` functions `operator+=`, `append`, `insert` and
* `replace`. All of these functions combine the existing string
* with a new string (or character) from one of the arguments.
*/
private class StdStringAppend extends StdStringTaintFunction {
private class StdStringAppend extends TaintFunction {
StdStringAppend() {
this.getClassAndName(["operator+=", "append", "replace"]) instanceof StdBasicString
this.getClassAndName(["operator+=", "append", "insert", "replace"]) instanceof StdBasicString
}
/**
* Gets the index of a parameter to this function that is a string (or
* character).
*/
int getAStringParameterIndex() {
this.getParameter(result).getType() instanceof PointerType or // e.g. `std::basic_string::CharT *`
this.getParameter(result).getType() instanceof ReferenceType or // e.g. `std::basic_string &`
this.getParameter(result).getUnspecifiedType() =
this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT`
}
/**
* Gets the index of a parameter to this function that is an iterator.
*/
int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from string and parameter to string (qualifier) and return value
(
@@ -185,44 +186,28 @@ private class StdStringAppend extends StdStringTaintFunction {
}
}
/**
* The `std::string` function `insert`.
*/
private class StdStringInsert extends StdStringTaintFunction {
StdStringInsert() { this.getClassAndName("insert") instanceof StdBasicString }
/**
* Holds if the return type is an iterator.
*/
predicate hasIteratorReturnValue() { this.getType() instanceof Iterator }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from string and parameter to string (qualifier) and return value
(
input.isQualifierObject() or
input.isParameterDeref(this.getAStringParameterIndex()) or
input.isParameter(this.getAnIteratorParameterIndex())
) and
(
output.isQualifierObject()
or
if this.hasIteratorReturnValue() then output.isReturnValue() else output.isReturnValueDeref()
)
or
// reverse flow from returned reference to the qualifier (for writes to
// the result)
not this.hasIteratorReturnValue() and
input.isReturnValueDeref() and
output.isQualifierObject()
}
}
/**
* The standard function `std::string.assign`.
*/
private class StdStringAssign extends StdStringTaintFunction {
private class StdStringAssign extends TaintFunction {
StdStringAssign() { this.getClassAndName("assign") instanceof StdBasicString }
/**
* Gets the index of a parameter to this function that is a string (or
* character).
*/
int getAStringParameterIndex() {
this.getParameter(result).getType() instanceof PointerType or // e.g. `std::basic_string::CharT *`
this.getParameter(result).getType() instanceof ReferenceType or // e.g. `std::basic_string &`
this.getParameter(result).getUnspecifiedType() =
this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT`
}
/**
* Gets the index of a parameter to this function that is an iterator.
*/
int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// flow from parameter to string itself (qualifier) and return value
(
@@ -244,7 +229,7 @@ private class StdStringAssign extends StdStringTaintFunction {
/**
* The standard function `std::string.copy`.
*/
private class StdStringCopy extends StdStringTaintFunction {
private class StdStringCopy extends TaintFunction {
StdStringCopy() { this.getClassAndName("copy") instanceof StdBasicString }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
@@ -257,7 +242,7 @@ private class StdStringCopy extends StdStringTaintFunction {
/**
* The standard function `std::string.substr`.
*/
private class StdStringSubstr extends StdStringTaintFunction {
private class StdStringSubstr extends TaintFunction {
StdStringSubstr() { this.getClassAndName("substr") instanceof StdBasicString }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
@@ -270,7 +255,7 @@ private class StdStringSubstr extends StdStringTaintFunction {
/**
* The `std::string` functions `at` and `operator[]`.
*/
private class StdStringAt extends StdStringTaintFunction {
private class StdStringAt extends TaintFunction {
StdStringAt() { this.getClassAndName(["at", "operator[]"]) instanceof StdBasicString }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {

View File

@@ -50,18 +50,19 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
(
this.getName() = ["strncat", "wcsncat", "_mbsncat", "_mbsncat_l"] and
input.isParameter(2)
or
this.getName() = ["_mbsncat_l", "_mbsnbcat_l"] and
input.isParameter(3)
or
input.isParameterDeref(0)
or
input.isParameterDeref(1)
) and
(output.isParameterDeref(0) or output.isReturnValueDeref())
this.getName() = ["strncat", "wcsncat", "_mbsncat", "_mbsncat_l"] and
input.isParameter(2) and
output.isParameterDeref(0)
or
this.getName() = ["_mbsncat_l", "_mbsnbcat_l"] and
input.isParameter(3) and
output.isParameterDeref(0)
or
input.isParameterDeref(0) and
output.isParameterDeref(0)
or
input.isParameterDeref(1) and
output.isParameterDeref(0)
}
override predicate hasArrayInput(int param) {

View File

@@ -1,4 +1,4 @@
/**
/*
* Support for tracking tainted data through the program. This is an alias for
* `semmle.code.cpp.ir.dataflow.DefaultTaintTracking` provided for backwards
* compatibility.

View File

@@ -1,8 +1,4 @@
/**
* DEPRECATED: This library has been replaced with a newer version which
* provides better performance and precision. Use
* `semmle.code.cpp.valuenumbering.GlobalValueNumbering` instead.
*
* Provides an implementation of Global Value Numbering.
* See https://en.wikipedia.org/wiki/Global_value_numbering
*
@@ -225,7 +221,7 @@ private newtype GvnBase =
* expression with this `GVN` and using its `toString` and `getLocation`
* methods.
*/
deprecated class GVN extends GvnBase {
class GVN extends GvnBase {
GVN() { this instanceof GvnBase }
/** Gets an expression that has this GVN. */
@@ -507,7 +503,7 @@ private predicate mk_Deref(GVN p, ControlFlowNode dominator, PointerDereferenceE
/** Gets the global value number of expression `e`. */
cached
deprecated GVN globalValueNumber(Expr e) {
GVN globalValueNumber(Expr e) {
exists(int val, Type t |
mk_IntConst(val, t, e) and
result = GVN_IntConst(val, t)

View File

@@ -1,13 +1,3 @@
## 0.4.4
No user-facing changes.
## 0.4.3
### Minor Analysis Improvements
* Fixed a bug in `cpp/jsf/av-rule-76` that caused the query to miss results when an implicitly-defined copy constructor or copy assignment operator was generated.
## 0.4.2
### New Queries

View File

@@ -13,18 +13,11 @@
import cpp
from FormatLiteral fl, FormattingFunctionCall ffc, int expected, int given, string ffcName
from FormatLiteral fl, FormattingFunctionCall ffc, int expected, int given
where
ffc = fl.getUse() and
expected = fl.getNumArgNeeded() and
given = ffc.getNumFormatArgument() and
expected < given and
fl.specsAreKnown() and
(
if ffc.isInMacroExpansion()
then ffcName = ffc.getTarget().getName() + " (in a macro expansion)"
else ffcName = ffc.getTarget().getName()
)
select ffc,
"Format for " + ffcName + " expects " + expected.toString() + " arguments but given " +
given.toString()
fl.specsAreKnown()
select ffc, "Format expects " + expected.toString() + " arguments but given " + given.toString()

View File

@@ -16,18 +16,11 @@
import cpp
from FormatLiteral fl, FormattingFunctionCall ffc, int expected, int given, string ffcName
from FormatLiteral fl, FormattingFunctionCall ffc, int expected, int given
where
ffc = fl.getUse() and
expected = fl.getNumArgNeeded() and
given = ffc.getNumFormatArgument() and
expected > given and
fl.specsAreKnown() and
(
if ffc.isInMacroExpansion()
then ffcName = ffc.getTarget().getName() + " (in a macro expansion)"
else ffcName = ffc.getTarget().getName()
)
select ffc,
"Format for " + ffcName + " expects " + expected.toString() + " arguments but given " +
given.toString()
fl.specsAreKnown()
select ffc, "Format expects " + expected.toString() + " arguments but given " + given.toString()

View File

@@ -26,11 +26,11 @@ predicate intentionallyReturnsStackPointer(Function f) {
class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
ReturnStackAllocatedMemoryConfig() { this = "ReturnStackAllocatedMemoryConfig" }
override predicate isSource(Instruction source) {
override predicate isSource(DataFlow::Node source) {
// Holds if `source` is a node that represents the use of a stack variable
exists(VariableAddressInstruction var, Function func |
var = source and
func = source.getEnclosingFunction() and
var = source.asInstruction() and
func = var.getEnclosingFunction() and
var.getAstVariable() instanceof StackVariable and
// Pointer-to-member types aren't properly handled in the dbscheme.
not var.getResultType() instanceof PointerToMemberType and
@@ -40,7 +40,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
)
}
override predicate isSink(Operand sink) {
override predicate isSink(DataFlow::Node 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
@@ -48,7 +48,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
exists(StoreInstruction store |
store.getDestinationAddress().(VariableAddressInstruction).getIRVariable() instanceof
IRReturnVariable and
sink = store.getSourceValueOperand()
sink.asOperand() = store.getSourceValueOperand()
)
}
@@ -77,10 +77,10 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
* }
* ```
*/
override predicate isAdditionalFlowStep(Operand node1, Instruction node2) {
node2.(FieldAddressInstruction).getObjectAddressOperand() = node1
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
node2.asInstruction().(FieldAddressInstruction).getObjectAddressOperand() = node1.asOperand()
or
node2.(PointerOffsetInstruction).getLeftOperand() = node1
node2.asInstruction().(PointerOffsetInstruction).getLeftOperand() = node1.asOperand()
}
}
@@ -89,6 +89,6 @@ from
ReturnStackAllocatedMemoryConfig conf
where
conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
source.getInstruction() = var
select sink.getInstruction(), source, sink, "May return stack-allocated memory from $@.",
var.getAst(), var.getAst().toString()
source.getNode().asInstruction() = var
select sink.getNode(), source, sink, "May return stack-allocated memory from $@.", var.getAst(),
var.getAst().toString()

View File

@@ -22,40 +22,37 @@ import PathGraph
class UnsafeUseOfThisConfig extends MustFlowConfiguration {
UnsafeUseOfThisConfig() { this = "UnsafeUseOfThisConfig" }
override predicate isSource(Instruction source) { isSource(source, _, _) }
override predicate isSource(DataFlow::Node source) { isSource(source, _, _) }
override predicate isSink(Operand sink) { isSink(sink, _) }
override predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
}
/** Holds if `sink` is a `this` pointer used by the call instruction `call`. */
predicate isSink(Operand sink, CallInstruction call) {
/** Holds if `instr` is a `this` pointer used by the call instruction `call`. */
predicate isSink(DataFlow::Node sink, CallInstruction call) {
exists(PureVirtualFunction func |
call.getStaticCallTarget() = func and
call.getThisArgumentOperand() = sink and
call.getThisArgument() = sink.asInstruction() and
// Weed out implicit calls to destructors of a base class
not func instanceof Destructor
)
}
/**
* Holds if `source` initializes the `this` pointer in class `c`.
*
* The string `msg` describes whether the enclosing function is a
* constructor or destructor.
*/
predicate isSource(InitializeParameterInstruction source, string msg, Class c) {
(
exists(Constructor func |
not func instanceof CopyConstructor and
not func instanceof MoveConstructor and
func = source.getEnclosingFunction() and
msg = "construction"
)
or
source.getEnclosingFunction() instanceof Destructor and msg = "destruction"
) and
source.getIRVariable() instanceof IRThisVariable and
source.getEnclosingFunction().getDeclaringType() = c
/** Holds if `init` initializes the `this` pointer in class `c`. */
predicate isSource(DataFlow::Node source, string msg, Class c) {
exists(InitializeParameterInstruction init | init = source.asInstruction() |
(
exists(Constructor func |
not func instanceof CopyConstructor and
not func instanceof MoveConstructor and
func = init.getEnclosingFunction() and
msg = "construction"
)
or
init.getEnclosingFunction() instanceof Destructor and msg = "destruction"
) and
init.getIRVariable() instanceof IRThisVariable and
init.getEnclosingFunction().getDeclaringType() = c
)
}
/**
@@ -71,8 +68,8 @@ predicate flows(
) {
exists(UnsafeUseOfThisConfig conf |
conf.hasFlowPath(source, sink) and
isSource(source.getInstruction(), msg, sourceClass) and
isSink(sink.getInstruction().getAUse(), call)
isSource(source.getNode(), msg, sourceClass) and
isSink(sink.getNode(), call)
)
}

View File

@@ -1,5 +0,0 @@
## 0.4.3
### Minor Analysis Improvements
* Fixed a bug in `cpp/jsf/av-rule-76` that caused the query to miss results when an implicitly-defined copy constructor or copy assignment operator was generated.

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.4.4
lastReleaseVersion: 0.4.2

View File

@@ -1,4 +1,4 @@
/**
/*
* Common functions for implementing naming conventions
*
* Naming rules are the following:

View File

@@ -38,9 +38,9 @@ predicate hasNontrivialDestructor(Class c) {
from Class c
where
(hasPointerMember(c) or hasNontrivialDestructor(c)) and
(
c.hasImplicitCopyAssignmentOperator() or
c.hasImplicitCopyConstructor()
not (
c.getAMemberFunction() instanceof CopyConstructor and
c.getAMemberFunction() instanceof CopyAssignmentOperator
) and
not c instanceof Struct
select c,

View File

@@ -1,11 +1,11 @@
name: codeql/cpp-queries
version: 0.4.5-dev
version: 0.4.3-dev
groups:
- cpp
- queries
dependencies:
codeql/cpp-all: ${workspace}
codeql/suite-helpers: ${workspace}
codeql/cpp-all: "*"
codeql/suite-helpers: "*"
suites: codeql-suites
extractor: cpp
defaultSuiteFile: codeql-suites/cpp-code-scanning.qls

View File

@@ -2,21 +2,43 @@ edges
| test.cpp:4:15:4:20 | call to malloc | test.cpp:5:15:5:15 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store |
| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | Store |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | Store |
@@ -94,6 +116,7 @@ edges
| test.cpp:8:16:8:16 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:8:16:8:16 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:8:16:8:20 | ... + ... | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:8:16:8:20 | ... + ... | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:9:16:9:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:9:16:9:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:9:16:9:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
@@ -116,30 +139,62 @@ edges
| test.cpp:11:16:11:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:11:16:11:16 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:12:16:12:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:12:16:12:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:12:16:12:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:12:16:12:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:16:15:16:20 | call to malloc | test.cpp:17:15:17:15 | Load |
| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... |
| test.cpp:17:15:17:22 | ... + ... | test.cpp:20:14:20:21 | Load: * ... |
| test.cpp:17:15:17:22 | ... + ... | test.cpp:20:14:20:21 | Load: * ... |
| test.cpp:20:16:20:20 | ... + ... | test.cpp:20:14:20:21 | Load: * ... |
| test.cpp:20:16:20:20 | ... + ... | test.cpp:20:14:20:21 | Load: * ... |
| test.cpp:28:15:28:20 | call to malloc | test.cpp:29:15:29:15 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store |
| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | Store |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | Store |
@@ -217,6 +272,7 @@ edges
| test.cpp:32:16:32:16 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:32:16:32:16 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:32:16:32:20 | ... + ... | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:32:16:32:20 | ... + ... | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:33:16:33:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:33:16:33:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:33:16:33:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
@@ -239,25 +295,49 @@ edges
| test.cpp:35:16:35:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:35:16:35:16 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:36:16:36:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:36:16:36:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:36:16:36:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:36:16:36:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:40:15:40:20 | call to malloc | test.cpp:41:15:41:15 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store |
| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:41:15:41:28 | Store |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:41:15:41:28 | Store |
@@ -335,6 +415,7 @@ edges
| test.cpp:44:16:44:16 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:44:16:44:16 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:44:16:44:20 | ... + ... | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:44:16:44:20 | ... + ... | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:45:16:45:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:45:16:45:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:45:16:45:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
@@ -357,6 +438,8 @@ edges
| test.cpp:47:16:47:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:47:16:47:16 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:48:16:48:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:48:16:48:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:48:16:48:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:48:16:48:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:51:7:51:14 | VariableAddress indirection | test.cpp:62:39:62:39 | Load |
| test.cpp:51:7:51:14 | VariableAddress indirection | test.cpp:66:39:66:39 | Load |
@@ -366,13 +449,18 @@ edges
| test.cpp:52:19:52:24 | call to malloc | test.cpp:53:12:53:16 | Load |
| test.cpp:53:5:53:23 | Store | test.cpp:51:33:51:35 | Load indirection |
| test.cpp:53:12:53:16 | Load | test.cpp:53:5:53:23 | Store |
| test.cpp:53:12:53:16 | Load | test.cpp:53:5:53:23 | Store |
| test.cpp:53:12:53:16 | Load | test.cpp:53:12:53:23 | ... + ... |
| test.cpp:53:12:53:16 | Load | test.cpp:53:12:53:23 | ... + ... |
| test.cpp:53:12:53:23 | ... + ... | test.cpp:51:33:51:35 | Load indirection |
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:62:32:62:34 | Load |
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:66:32:66:34 | Load |
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:70:31:70:33 | Load |
| test.cpp:62:32:62:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:62:32:62:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:66:32:66:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:66:32:66:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:70:31:70:33 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:70:31:70:33 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:80:9:80:16 | VariableAddress indirection [begin] | test.cpp:91:20:91:22 | arr indirection [begin] |
| test.cpp:80:9:80:16 | VariableAddress indirection [begin] | test.cpp:95:20:95:22 | arr indirection [begin] |
@@ -391,6 +479,8 @@ edges
| test.cpp:83:15:83:17 | arr indirection [begin] | test.cpp:83:19:83:23 | begin |
| test.cpp:83:15:83:30 | ... + ... | test.cpp:83:5:83:30 | Store |
| test.cpp:83:19:83:23 | Load | test.cpp:83:5:83:30 | Store |
| test.cpp:83:19:83:23 | Load | test.cpp:83:5:83:30 | Store |
| test.cpp:83:19:83:23 | Load | test.cpp:83:15:83:30 | ... + ... |
| test.cpp:83:19:83:23 | Load | test.cpp:83:15:83:30 | ... + ... |
| test.cpp:83:19:83:23 | begin | test.cpp:83:19:83:23 | Load |
| test.cpp:91:20:91:22 | arr indirection [begin] | test.cpp:91:24:91:28 | begin |
@@ -398,18 +488,21 @@ edges
| test.cpp:91:24:91:28 | begin | test.cpp:91:47:91:47 | Load |
| test.cpp:91:36:91:38 | arr indirection [end] | test.cpp:91:40:91:42 | end |
| test.cpp:91:40:91:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:91:40:91:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:91:40:91:42 | end | test.cpp:91:40:91:42 | Load |
| test.cpp:95:20:95:22 | arr indirection [begin] | test.cpp:95:24:95:28 | begin |
| test.cpp:95:20:95:22 | arr indirection [begin] | test.cpp:95:47:95:47 | Load |
| test.cpp:95:24:95:28 | begin | test.cpp:95:47:95:47 | Load |
| test.cpp:95:36:95:38 | arr indirection [end] | test.cpp:95:40:95:42 | end |
| test.cpp:95:40:95:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:95:40:95:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:95:40:95:42 | end | test.cpp:95:40:95:42 | Load |
| test.cpp:99:20:99:22 | arr indirection [begin] | test.cpp:99:24:99:28 | begin |
| test.cpp:99:20:99:22 | arr indirection [begin] | test.cpp:99:46:99:46 | Load |
| test.cpp:99:24:99:28 | begin | test.cpp:99:46:99:46 | Load |
| test.cpp:99:35:99:37 | arr indirection [end] | test.cpp:99:39:99:41 | end |
| test.cpp:99:39:99:41 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:99:39:99:41 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:99:39:99:41 | end | test.cpp:99:39:99:41 | Load |
| test.cpp:104:27:104:29 | arr [begin] | test.cpp:105:20:105:22 | arr indirection [begin] |
| test.cpp:104:27:104:29 | arr [begin] | test.cpp:109:20:109:22 | arr indirection [begin] |
@@ -422,18 +515,21 @@ edges
| test.cpp:105:24:105:28 | begin | test.cpp:105:47:105:47 | Load |
| test.cpp:105:36:105:38 | arr indirection [end] | test.cpp:105:40:105:42 | end |
| test.cpp:105:40:105:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:105:40:105:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:105:40:105:42 | end | test.cpp:105:40:105:42 | Load |
| test.cpp:109:20:109:22 | arr indirection [begin] | test.cpp:109:24:109:28 | begin |
| test.cpp:109:20:109:22 | arr indirection [begin] | test.cpp:109:47:109:47 | Load |
| test.cpp:109:24:109:28 | begin | test.cpp:109:47:109:47 | Load |
| test.cpp:109:36:109:38 | arr indirection [end] | test.cpp:109:40:109:42 | end |
| test.cpp:109:40:109:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:109:40:109:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:109:40:109:42 | end | test.cpp:109:40:109:42 | Load |
| test.cpp:113:20:113:22 | arr indirection [begin] | test.cpp:113:24:113:28 | begin |
| test.cpp:113:20:113:22 | arr indirection [begin] | test.cpp:113:46:113:46 | Load |
| test.cpp:113:24:113:28 | begin | test.cpp:113:46:113:46 | Load |
| test.cpp:113:35:113:37 | arr indirection [end] | test.cpp:113:39:113:41 | end |
| test.cpp:113:39:113:41 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:113:39:113:41 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:113:39:113:41 | end | test.cpp:113:39:113:41 | Load |
| test.cpp:119:18:119:25 | call to mk_array [begin] | test.cpp:104:27:104:29 | arr [begin] |
| test.cpp:119:18:119:25 | call to mk_array [end] | test.cpp:104:27:104:29 | arr [end] |
@@ -462,6 +558,8 @@ edges
| test.cpp:144:16:144:18 | Load indirection [begin] | test.cpp:144:21:144:25 | begin |
| test.cpp:144:16:144:32 | ... + ... | test.cpp:144:5:144:32 | Store |
| test.cpp:144:21:144:25 | Load | test.cpp:144:5:144:32 | Store |
| test.cpp:144:21:144:25 | Load | test.cpp:144:5:144:32 | Store |
| test.cpp:144:21:144:25 | Load | test.cpp:144:16:144:32 | ... + ... |
| test.cpp:144:21:144:25 | Load | test.cpp:144:16:144:32 | ... + ... |
| test.cpp:144:21:144:25 | begin | test.cpp:144:21:144:25 | Load |
| test.cpp:150:20:150:29 | Call indirection [begin] | test.cpp:152:20:152:22 | Load indirection [begin] |
@@ -476,6 +574,7 @@ edges
| test.cpp:156:25:156:29 | begin | test.cpp:156:49:156:49 | Load |
| test.cpp:156:37:156:39 | Load indirection [end] | test.cpp:156:42:156:44 | end |
| test.cpp:156:42:156:44 | Load | test.cpp:157:9:157:14 | Store: ... = ... |
| test.cpp:156:42:156:44 | Load | test.cpp:157:9:157:14 | Store: ... = ... |
| test.cpp:156:42:156:44 | end | test.cpp:156:42:156:44 | Load |
| test.cpp:160:20:160:22 | Load indirection [begin] | test.cpp:160:25:160:29 | begin |
| test.cpp:160:20:160:22 | Load indirection [begin] | test.cpp:160:48:160:48 | Load |
@@ -491,18 +590,21 @@ edges
| test.cpp:166:25:166:29 | begin | test.cpp:166:49:166:49 | Load |
| test.cpp:166:37:166:39 | Load indirection [end] | test.cpp:166:42:166:44 | end |
| test.cpp:166:42:166:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:166:42:166:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:166:42:166:44 | end | test.cpp:166:42:166:44 | Load |
| test.cpp:170:20:170:22 | Load indirection [begin] | test.cpp:170:25:170:29 | begin |
| test.cpp:170:20:170:22 | Load indirection [begin] | test.cpp:170:49:170:49 | Load |
| test.cpp:170:25:170:29 | begin | test.cpp:170:49:170:49 | Load |
| test.cpp:170:37:170:39 | Load indirection [end] | test.cpp:170:42:170:44 | end |
| test.cpp:170:42:170:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:170:42:170:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:170:42:170:44 | end | test.cpp:170:42:170:44 | Load |
| test.cpp:174:20:174:22 | Load indirection [begin] | test.cpp:174:25:174:29 | begin |
| test.cpp:174:20:174:22 | Load indirection [begin] | test.cpp:174:48:174:48 | Load |
| test.cpp:174:25:174:29 | begin | test.cpp:174:48:174:48 | Load |
| test.cpp:174:36:174:38 | Load indirection [end] | test.cpp:174:41:174:43 | end |
| test.cpp:174:41:174:43 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:174:41:174:43 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:174:41:174:43 | end | test.cpp:174:41:174:43 | Load |
| test.cpp:180:19:180:28 | call to mk_array_p indirection [begin] | test.cpp:165:29:165:31 | arr indirection [begin] |
| test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | test.cpp:165:29:165:31 | arr indirection [end] |
@@ -512,9 +614,19 @@ edges
| test.cpp:194:23:194:28 | call to malloc | test.cpp:201:5:201:5 | Load |
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... |
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... |
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... |
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... |
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store |
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store |
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store |
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store |
| test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load |
| test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load |
| test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load |
| test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load |
| test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array |
| test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array |
| test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array |
| test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array |
| test.cpp:195:17:195:23 | ... + ... | test.cpp:195:17:195:23 | Store |
| test.cpp:195:17:195:23 | ... + ... | test.cpp:195:17:195:23 | Store |
@@ -525,15 +637,29 @@ edges
| test.cpp:195:17:195:23 | Store | test.cpp:201:5:201:19 | Store: ... = ... |
| test.cpp:195:17:195:23 | Store | test.cpp:201:5:201:19 | Store: ... = ... |
| test.cpp:197:20:197:22 | Load | test.cpp:201:5:201:19 | Store: ... = ... |
| test.cpp:197:20:197:22 | Load | test.cpp:201:5:201:19 | Store: ... = ... |
| test.cpp:201:5:201:12 | access to array | test.cpp:201:5:201:19 | Store: ... = ... |
| test.cpp:201:5:201:12 | access to array | test.cpp:201:5:201:19 | Store: ... = ... |
| test.cpp:205:23:205:28 | call to malloc | test.cpp:206:17:206:17 | Load |
| test.cpp:205:23:205:28 | call to malloc | test.cpp:208:15:208:15 | Load |
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... |
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... |
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... |
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... |
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store |
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store |
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store |
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store |
| test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load |
| test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load |
| test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load |
| test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load |
| test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... |
| test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... |
| test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... |
| test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... |
| test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load |
| test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load |
| test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load |
| test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load |
| test.cpp:206:17:206:23 | ... + ... | test.cpp:206:17:206:23 | Store |
@@ -545,6 +671,8 @@ edges
| test.cpp:206:17:206:23 | Store | test.cpp:213:5:213:13 | Store: ... = ... |
| test.cpp:206:17:206:23 | Store | test.cpp:213:5:213:13 | Store: ... = ... |
| test.cpp:209:12:209:14 | Load | test.cpp:213:5:213:13 | Store: ... = ... |
| test.cpp:209:12:209:14 | Load | test.cpp:213:5:213:13 | Store: ... = ... |
| test.cpp:213:5:213:6 | * ... | test.cpp:213:5:213:13 | Store: ... = ... |
| test.cpp:213:5:213:6 | * ... | test.cpp:213:5:213:13 | Store: ... = ... |
| test.cpp:213:6:213:6 | Load | test.cpp:213:5:213:6 | * ... |
| test.cpp:213:6:213:6 | Load | test.cpp:213:5:213:13 | Store: ... = ... |

View File

@@ -6,8 +6,6 @@ uniqueNodeToString
missingToString
parameterCallable
localFlowIsLocal
readStepIsLocal
storeStepIsLocal
compatibleTypesReflexive
unreachableNodeCCtx
localCallNodes
@@ -89,7 +87,4 @@ postWithInFlow
| test.cpp:465:3:465:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:465:4:465:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:470:22:470:22 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:499:3:499:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:499:4:499:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:505:35:505:35 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
viableImplInCallContextTooLarge

View File

@@ -21,8 +21,6 @@ uniqueNodeToString
missingToString
parameterCallable
localFlowIsLocal
readStepIsLocal
storeStepIsLocal
compatibleTypesReflexive
unreachableNodeCCtx
localCallNodes
@@ -584,13 +582,6 @@ postWithInFlow
| test.cpp:489:7:489:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:491:5:491:5 | x [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:494:5:494:5 | x [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:499:3:499:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:499:4:499:4 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:499:4:499:4 | p [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:504:7:504:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:505:34:505:35 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:505:34:505:35 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:505:35:505:35 | x [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:9:7:9:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:10:12:10:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:10:27:10:27 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |

View File

@@ -87,7 +87,7 @@ Top *identity(Top *top) {
void callIdentityFunctions(Top *top, Bottom *bottom) {
identity(bottom)->isSink(source()); // $ MISSING: ast,ir
identity(top)->isSink(source()); // no flow
identity(top)->isSink(source()); // now flow
}
using SinkFunctionType = void (*)(int);

View File

@@ -329,21 +329,21 @@ namespace NestedTests {
namespace FlowThroughGlobals {
int globalVar;
void taintGlobal() {
int taintGlobal() {
globalVar = source();
}
void f() {
int f() {
sink(globalVar); // $ ir=333:17 ir=347:17 // tainted or clean? Not sure.
taintGlobal();
sink(globalVar); // $ ir=333:17 ir=347:17 MISSING: ast
}
void calledAfterTaint() {
int calledAfterTaint() {
sink(globalVar); // $ ir=333:17 ir=347:17 MISSING: ast
}
void taintAndCall() {
int taintAndCall() {
globalVar = source();
calledAfterTaint();
sink(globalVar); // $ ast ir=333:17 ir=347:17
@@ -494,14 +494,3 @@ void regression_with_phi_flow(int clean1) {
x = source();
}
}
int intOutparamSourceMissingReturn(int *p) {
*p = source();
// return deliberately omitted to test IR dataflow behavior
}
void viaOutparamMissingReturn() {
int x = 0;
intOutparamSourceMissingReturn(&x);
sink(x); // $ ast,ir
}

View File

@@ -77,9 +77,27 @@ module IRTest {
)
}
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
exists(GlobalOrNamespaceVariable var | var.getName().matches("flowTestGlobal%") |
writesVariable(n1.asInstruction(), var) and
var = n2.asVariable()
or
readsVariable(n2.asInstruction(), var) and
var = n1.asVariable()
)
}
override predicate isBarrier(DataFlow::Node barrier) {
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier") or
barrier = DataFlow::InstructionBarrierGuard<testBarrierGuard/3>::getABarrierNode()
}
}
private predicate readsVariable(LoadInstruction load, Variable var) {
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
}
private predicate writesVariable(StoreInstruction store, Variable var) {
store.getDestinationAddress().(VariableAddressInstruction).getAstVariable() = var
}
}

View File

@@ -5,7 +5,7 @@ int source();
void sink(...);
bool random();
void test1() {
int test1() {
int x = source();
for (int i = 0; i < 10; i++) {
x = 0;
@@ -13,7 +13,7 @@ void test1() {
sink(x); // $ SPURIOUS: ir
}
void test2(int iterations) {
int test2(int iterations) {
int x = source();
for (int i = 0; i < iterations; i++) {
x = 0;
@@ -21,7 +21,7 @@ void test2(int iterations) {
sink(x); // $ ast,ir
}
void test3() {
int test3() {
int x = 0;
for (int i = 0; i < 10; i++) {
x = source();
@@ -29,7 +29,7 @@ void test3() {
sink(x); // $ ast,ir
}
void test4() {
int test4() {
int x = source();
for (int i = 0; i < 10; i++) {
if (random())
@@ -39,7 +39,7 @@ void test4() {
sink(x); // $ ast,ir
}
void test5() {
int test5() {
int x = source();
for (int i = 0; i < 10; i++) {
if (random())
@@ -49,7 +49,7 @@ void test5() {
sink(x); // $ ast,ir
}
void test6() {
int test6() {
int y;
int x = source();
for (int i = 0; i < 10 && (y = 1); i++) {
@@ -57,7 +57,7 @@ void test6() {
sink(x); // $ ast,ir
}
void test7() {
int test7() {
int y;
int x = source();
for (int i = 0; i < 10 && (y = 1); i++) {
@@ -66,7 +66,7 @@ void test7() {
sink(x); // $ SPURIOUS: ir
}
void test8() {
int test8() {
int x = source();
// It appears to the analysis that the condition can exit after `i < 10`
// without having assigned to `x`. That is an effect of how the
@@ -78,7 +78,7 @@ void test8() {
sink(x); // $ SPURIOUS: ast,ir
}
void test9() {
int test9() {
int y;
int x = source();
for (int i = 0; (y = 1) && i < 10; i++) {
@@ -86,21 +86,21 @@ void test9() {
sink(x); // $ ast,ir
}
void test10() {
int test10() {
int x = source();
for (int i = 0; (x = 1) && i < 10; i++) {
}
sink(x); // no flow
}
void test10(int b, int d) {
int test10(int b, int d) {
int i = 0;
int x = source();
if (b)
goto L;
for (; i < 10; i += d) {
x = 0;
L: ;
L:
}
sink(x); // $ ir MISSING: ast
}

View File

@@ -12,8 +12,6 @@ uniqueNodeToString
missingToString
parameterCallable
localFlowIsLocal
readStepIsLocal
storeStepIsLocal
compatibleTypesReflexive
unreachableNodeCCtx
localCallNodes

View File

@@ -15,8 +15,6 @@ uniqueNodeToString
missingToString
parameterCallable
localFlowIsLocal
readStepIsLocal
storeStepIsLocal
compatibleTypesReflexive
unreachableNodeCCtx
localCallNodes

View File

@@ -9,7 +9,7 @@ struct sockaddr {
char* sa_data;
};
int accept(int, sockaddr*, int*);
int accept(int, const sockaddr*, int*);
void sink(sockaddr);
@@ -20,5 +20,5 @@ void test_accept() {
int a = accept(s, &addr, &size);
sink(a); // $ ast=17:11 ir SPURIOUS: ast=18:12
sink(addr); // $ ast=17:11 ir SPURIOUS: ast=18:12
sink(addr); // $ ast,ir
}

View File

@@ -142,14 +142,9 @@
| bsd.cpp:19:14:19:29 | sizeof(sockaddr) | bsd.cpp:20:29:20:32 | size | |
| bsd.cpp:20:11:20:16 | call to accept | bsd.cpp:22:8:22:8 | a | |
| bsd.cpp:20:18:20:18 | s | bsd.cpp:20:11:20:16 | call to accept | TAINT |
| bsd.cpp:20:18:20:18 | s | bsd.cpp:20:21:20:25 | ref arg & ... | TAINT |
| bsd.cpp:20:21:20:25 | & ... | bsd.cpp:20:11:20:16 | call to accept | TAINT |
| bsd.cpp:20:21:20:25 | & ... | bsd.cpp:20:21:20:25 | ref arg & ... | TAINT |
| bsd.cpp:20:21:20:25 | ref arg & ... | bsd.cpp:20:22:20:25 | addr [inner post update] | |
| bsd.cpp:20:21:20:25 | ref arg & ... | bsd.cpp:23:8:23:11 | addr | |
| bsd.cpp:20:22:20:25 | addr | bsd.cpp:20:11:20:16 | call to accept | TAINT |
| bsd.cpp:20:22:20:25 | addr | bsd.cpp:20:21:20:25 | & ... | |
| bsd.cpp:20:22:20:25 | addr | bsd.cpp:20:21:20:25 | ref arg & ... | TAINT |
| bsd.cpp:20:28:20:32 | ref arg & ... | bsd.cpp:20:29:20:32 | size [inner post update] | |
| bsd.cpp:20:29:20:32 | size | bsd.cpp:20:28:20:32 | & ... | |
| constructor_delegation.cpp:8:2:8:8 | this | constructor_delegation.cpp:8:20:8:24 | constructor init of field x [pre-this] | |
@@ -5969,7 +5964,6 @@
| taint.cpp:172:10:172:15 | buffer | taint.cpp:172:3:172:8 | call to strcat | |
| taint.cpp:172:10:172:15 | buffer | taint.cpp:172:10:172:15 | ref arg buffer | TAINT |
| taint.cpp:172:10:172:15 | ref arg buffer | taint.cpp:173:8:173:13 | buffer | |
| taint.cpp:172:18:172:24 | tainted | taint.cpp:172:3:172:8 | call to strcat | TAINT |
| taint.cpp:172:18:172:24 | tainted | taint.cpp:172:10:172:15 | ref arg buffer | TAINT |
| taint.cpp:180:19:180:19 | p | taint.cpp:180:19:180:19 | p | |
| taint.cpp:180:19:180:19 | p | taint.cpp:181:9:181:9 | p | |
@@ -6379,14 +6373,12 @@
| taint.cpp:561:9:561:13 | dest1 | taint.cpp:561:9:561:13 | ref arg dest1 | TAINT |
| taint.cpp:561:9:561:13 | ref arg dest1 | taint.cpp:560:24:560:28 | dest1 | |
| taint.cpp:561:9:561:13 | ref arg dest1 | taint.cpp:562:7:562:11 | dest1 | |
| taint.cpp:561:16:561:21 | source | taint.cpp:561:2:561:7 | call to strcat | TAINT |
| taint.cpp:561:16:561:21 | source | taint.cpp:561:9:561:13 | ref arg dest1 | TAINT |
| taint.cpp:562:7:562:11 | ref arg dest1 | taint.cpp:560:24:560:28 | dest1 | |
| taint.cpp:564:9:564:13 | dest2 | taint.cpp:564:2:564:7 | call to strcat | |
| taint.cpp:564:9:564:13 | dest2 | taint.cpp:564:9:564:13 | ref arg dest2 | TAINT |
| taint.cpp:564:9:564:13 | ref arg dest2 | taint.cpp:560:37:560:41 | dest2 | |
| taint.cpp:564:9:564:13 | ref arg dest2 | taint.cpp:565:7:565:11 | dest2 | |
| taint.cpp:564:16:564:20 | clean | taint.cpp:564:2:564:7 | call to strcat | TAINT |
| taint.cpp:564:16:564:20 | clean | taint.cpp:564:9:564:13 | ref arg dest2 | TAINT |
| taint.cpp:565:7:565:11 | ref arg dest2 | taint.cpp:560:37:560:41 | dest2 | |
| taint.cpp:572:37:572:41 | dest1 | taint.cpp:572:37:572:41 | dest1 | |
@@ -6413,12 +6405,9 @@
| taint.cpp:574:36:574:40 | ref arg dest1 | taint.cpp:572:37:572:41 | dest1 | |
| taint.cpp:574:36:574:40 | ref arg dest1 | taint.cpp:575:7:575:11 | dest1 | |
| taint.cpp:574:36:574:40 | ref arg dest1 | taint.cpp:576:8:576:12 | dest1 | |
| taint.cpp:574:43:574:45 | ptr | taint.cpp:574:25:574:34 | call to _mbsncat_l | TAINT |
| taint.cpp:574:43:574:45 | ptr | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT |
| taint.cpp:574:48:574:48 | n | taint.cpp:574:25:574:34 | call to _mbsncat_l | TAINT |
| taint.cpp:574:48:574:48 | n | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT |
| taint.cpp:574:51:574:56 | ref arg source | taint.cpp:573:49:573:54 | source | |
| taint.cpp:574:51:574:56 | source | taint.cpp:574:25:574:34 | call to _mbsncat_l | TAINT |
| taint.cpp:574:51:574:56 | source | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT |
| taint.cpp:575:7:575:11 | ref arg dest1 | taint.cpp:572:37:572:41 | dest1 | |
| taint.cpp:575:7:575:11 | ref arg dest1 | taint.cpp:576:8:576:12 | dest1 | |
@@ -6432,11 +6421,8 @@
| taint.cpp:580:36:580:40 | ref arg dest3 | taint.cpp:572:85:572:89 | dest3 | |
| taint.cpp:580:36:580:40 | ref arg dest3 | taint.cpp:581:7:581:11 | dest3 | |
| taint.cpp:580:36:580:40 | ref arg dest3 | taint.cpp:582:8:582:12 | dest3 | |
| taint.cpp:580:43:580:45 | ptr | taint.cpp:580:25:580:34 | call to _mbsncat_l | TAINT |
| taint.cpp:580:43:580:45 | ptr | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT |
| taint.cpp:580:48:580:48 | n | taint.cpp:580:25:580:34 | call to _mbsncat_l | TAINT |
| taint.cpp:580:48:580:48 | n | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT |
| taint.cpp:580:51:580:55 | clean | taint.cpp:580:25:580:34 | call to _mbsncat_l | TAINT |
| taint.cpp:580:51:580:55 | clean | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT |
| taint.cpp:580:51:580:55 | ref arg clean | taint.cpp:573:32:573:36 | clean | |
| taint.cpp:581:7:581:11 | ref arg dest3 | taint.cpp:572:85:572:89 | dest3 | |

View File

@@ -574,8 +574,8 @@ void test__mbsncat_l(unsigned char* dest1, unsigned const char* ptr, unsigned ch
unsigned char* dest2 = _mbsncat_l(dest1, ptr, n, source);
sink(dest1); // $ SPURIOUS: ast,ir
sink(*dest1); // $ ast,ir
sink(dest2); // $ SPURIOUS: ast,ir
sink(*dest2); // $ ast,ir
sink(dest2); // $ SPURIOUS: ir
sink(*dest2); // $ ir
unsigned char* dest4 = _mbsncat_l(dest3, ptr, n, clean);
sink(dest3);

View File

@@ -95,7 +95,16 @@ module IRTest {
override predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call |
call.getTarget().getName() = "sink" and
sink.asExpr() = call.getAnArgument()
sink.asConvertedExpr() = call.getAnArgument()
or
call.getTarget().getName() = "sink" and
sink.asExpr() = call.getAnArgument() and
sink.asConvertedExpr() instanceof ReferenceDereferenceExpr
)
or
exists(ReadSideEffectInstruction read |
read.getSideEffectOperand() = sink.asOperand() and
read.getPrimaryInstruction().(CallInstruction).getStaticCallTarget().hasName("sink")
)
}

View File

@@ -52,8 +52,6 @@ uniqueNodeToString
missingToString
parameterCallable
localFlowIsLocal
readStepIsLocal
storeStepIsLocal
compatibleTypesReflexive
unreachableNodeCCtx
localCallNodes

View File

@@ -1463,8 +1463,6 @@ uniqueNodeToString
missingToString
parameterCallable
localFlowIsLocal
readStepIsLocal
storeStepIsLocal
compatibleTypesReflexive
unreachableNodeCCtx
localCallNodes

View File

@@ -1,4 +1,3 @@
WARNING: Type GVN has been deprecated and may be removed in future (ast_gvn.ql:4,6-9)
| test.cpp:5:3:5:3 | x | 5:c3-c3 6:c3-c3 |
| test.cpp:5:7:5:8 | p0 | 5:c7-c8 6:c7-c8 |
| test.cpp:5:7:5:13 | ... + ... | 5:c7-c13 6:c7-c13 7:c7-c7 |

View File

@@ -1,3 +0,0 @@
WARNING: Predicate globalValueNumber has been deprecated and may be removed in future (ast_uniqueness.ql:7,13-30)
WARNING: Predicate globalValueNumber has been deprecated and may be removed in future (ast_uniqueness.ql:8,30-47)
WARNING: Type GVN has been deprecated and may be removed in future (ast_uniqueness.ql:8,18-21)

View File

@@ -1,4 +1,3 @@
WARNING: Predicate globalValueNumber has been deprecated and may be removed in future (diff_ir_expr.ql:8,29-51)
| test.cpp:5:3:5:13 | ... = ... | test.cpp:5:3:5:13 | ... = ... | AST only |
| test.cpp:6:3:6:13 | ... = ... | test.cpp:6:3:6:13 | ... = ... | AST only |
| test.cpp:7:3:7:7 | ... = ... | test.cpp:7:3:7:7 | ... = ... | AST only |

View File

@@ -1,7 +1,7 @@
name: codeql/cpp-tests
groups: [cpp, test]
dependencies:
codeql/cpp-all: ${workspace}
codeql/cpp-queries: ${workspace}
codeql/cpp-all: "*"
codeql/cpp-queries: "*"
extractor: cpp
tests: .

View File

@@ -1,61 +1,103 @@
edges
| test.cpp:7:3:7:3 | B | test.cpp:8:12:8:15 | this |
| test.cpp:7:3:7:3 | this | test.cpp:8:12:8:15 | Load |
| test.cpp:8:12:8:15 | Load | test.cpp:8:12:8:15 | this |
| test.cpp:8:12:8:15 | this | test.cpp:34:16:34:16 | x |
| test.cpp:11:8:11:8 | b | test.cpp:12:5:12:5 | b |
| test.cpp:12:5:12:5 | (reference dereference) | test.cpp:12:5:12:5 | (A)... |
| test.cpp:12:5:12:5 | b | test.cpp:12:5:12:5 | (reference dereference) |
| test.cpp:15:3:15:4 | ~B | test.cpp:16:5:16:5 | this |
| test.cpp:16:5:16:5 | this | file://:0:0:0:0 | (A *)... |
| test.cpp:21:3:21:3 | C | test.cpp:21:13:21:13 | call to B |
| test.cpp:21:3:21:3 | C | test.cpp:22:12:22:15 | this |
| test.cpp:21:3:21:3 | C | test.cpp:25:7:25:10 | this |
| test.cpp:21:13:21:13 | call to B | test.cpp:7:3:7:3 | B |
| test.cpp:11:8:11:8 | b | test.cpp:12:5:12:5 | Load |
| test.cpp:12:5:12:5 | (reference dereference) | test.cpp:12:5:12:5 | Unary |
| test.cpp:12:5:12:5 | Load | test.cpp:12:5:12:5 | b |
| test.cpp:12:5:12:5 | Unary | test.cpp:12:5:12:5 | (A)... |
| test.cpp:12:5:12:5 | Unary | test.cpp:12:5:12:5 | (reference dereference) |
| test.cpp:12:5:12:5 | b | test.cpp:12:5:12:5 | Unary |
| test.cpp:15:3:15:4 | this | test.cpp:16:5:16:5 | Load |
| test.cpp:16:5:16:5 | Load | test.cpp:16:5:16:5 | this |
| test.cpp:16:5:16:5 | Unary | file://:0:0:0:0 | (A *)... |
| test.cpp:16:5:16:5 | this | test.cpp:16:5:16:5 | Unary |
| test.cpp:21:3:21:3 | Unary | test.cpp:21:13:21:13 | ConvertToNonVirtualBase |
| test.cpp:21:3:21:3 | this | test.cpp:21:3:21:3 | Unary |
| test.cpp:21:3:21:3 | this | test.cpp:22:12:22:15 | Load |
| test.cpp:21:3:21:3 | this | test.cpp:25:7:25:10 | Load |
| test.cpp:21:13:21:13 | ConvertToNonVirtualBase | test.cpp:7:3:7:3 | this |
| test.cpp:22:12:22:15 | (B *)... | test.cpp:34:16:34:16 | x |
| test.cpp:22:12:22:15 | this | test.cpp:22:12:22:15 | (B *)... |
| test.cpp:25:7:25:10 | (B *)... | test.cpp:25:7:25:10 | (A *)... |
| test.cpp:25:7:25:10 | this | test.cpp:25:7:25:10 | (B *)... |
| test.cpp:31:3:31:3 | D | test.cpp:31:12:31:15 | this |
| test.cpp:31:11:31:15 | (B)... | test.cpp:31:11:31:15 | (reference to) |
| test.cpp:22:12:22:15 | Load | test.cpp:22:12:22:15 | this |
| test.cpp:22:12:22:15 | Unary | test.cpp:22:12:22:15 | (B *)... |
| test.cpp:22:12:22:15 | this | test.cpp:22:12:22:15 | Unary |
| test.cpp:25:7:25:10 | (B *)... | test.cpp:25:7:25:10 | Unary |
| test.cpp:25:7:25:10 | Load | test.cpp:25:7:25:10 | this |
| test.cpp:25:7:25:10 | Unary | test.cpp:25:7:25:10 | (A *)... |
| test.cpp:25:7:25:10 | Unary | test.cpp:25:7:25:10 | (B *)... |
| test.cpp:25:7:25:10 | this | test.cpp:25:7:25:10 | Unary |
| test.cpp:31:3:31:3 | this | test.cpp:31:12:31:15 | Load |
| test.cpp:31:11:31:15 | (B)... | test.cpp:31:11:31:15 | Unary |
| test.cpp:31:11:31:15 | (reference to) | test.cpp:11:8:11:8 | b |
| test.cpp:31:11:31:15 | * ... | test.cpp:31:11:31:15 | (B)... |
| test.cpp:31:12:31:15 | this | test.cpp:31:11:31:15 | * ... |
| test.cpp:34:16:34:16 | x | test.cpp:35:3:35:3 | x |
| test.cpp:35:3:35:3 | x | test.cpp:35:3:35:3 | (A *)... |
| test.cpp:47:3:47:3 | F | test.cpp:48:10:48:13 | this |
| test.cpp:48:10:48:13 | (E *)... | test.cpp:48:6:48:13 | (A *)... |
| test.cpp:48:10:48:13 | this | test.cpp:48:10:48:13 | (E *)... |
| test.cpp:31:11:31:15 | * ... | test.cpp:31:11:31:15 | Unary |
| test.cpp:31:11:31:15 | Unary | test.cpp:31:11:31:15 | (B)... |
| test.cpp:31:11:31:15 | Unary | test.cpp:31:11:31:15 | (reference to) |
| test.cpp:31:12:31:15 | Load | test.cpp:31:12:31:15 | this |
| test.cpp:31:12:31:15 | Unary | test.cpp:31:11:31:15 | * ... |
| test.cpp:31:12:31:15 | this | test.cpp:31:12:31:15 | Unary |
| test.cpp:34:16:34:16 | x | test.cpp:35:3:35:3 | Load |
| test.cpp:35:3:35:3 | Load | test.cpp:35:3:35:3 | x |
| test.cpp:35:3:35:3 | Unary | test.cpp:35:3:35:3 | (A *)... |
| test.cpp:35:3:35:3 | x | test.cpp:35:3:35:3 | Unary |
| test.cpp:47:3:47:3 | this | test.cpp:48:10:48:13 | Load |
| test.cpp:48:10:48:13 | (E *)... | test.cpp:48:10:48:13 | Unary |
| test.cpp:48:10:48:13 | Load | test.cpp:48:10:48:13 | this |
| test.cpp:48:10:48:13 | Unary | test.cpp:48:6:48:13 | (A *)... |
| test.cpp:48:10:48:13 | Unary | test.cpp:48:10:48:13 | (E *)... |
| test.cpp:48:10:48:13 | this | test.cpp:48:10:48:13 | Unary |
nodes
| file://:0:0:0:0 | (A *)... | semmle.label | (A *)... |
| test.cpp:7:3:7:3 | B | semmle.label | B |
| test.cpp:7:3:7:3 | this | semmle.label | this |
| test.cpp:8:12:8:15 | Load | semmle.label | Load |
| test.cpp:8:12:8:15 | this | semmle.label | this |
| test.cpp:11:8:11:8 | b | semmle.label | b |
| test.cpp:12:5:12:5 | (A)... | semmle.label | (A)... |
| test.cpp:12:5:12:5 | (reference dereference) | semmle.label | (reference dereference) |
| test.cpp:12:5:12:5 | Load | semmle.label | Load |
| test.cpp:12:5:12:5 | Unary | semmle.label | Unary |
| test.cpp:12:5:12:5 | Unary | semmle.label | Unary |
| test.cpp:12:5:12:5 | b | semmle.label | b |
| test.cpp:15:3:15:4 | ~B | semmle.label | ~B |
| test.cpp:15:3:15:4 | this | semmle.label | this |
| test.cpp:16:5:16:5 | Load | semmle.label | Load |
| test.cpp:16:5:16:5 | Unary | semmle.label | Unary |
| test.cpp:16:5:16:5 | this | semmle.label | this |
| test.cpp:21:3:21:3 | C | semmle.label | C |
| test.cpp:21:13:21:13 | call to B | semmle.label | call to B |
| test.cpp:21:3:21:3 | Unary | semmle.label | Unary |
| test.cpp:21:3:21:3 | this | semmle.label | this |
| test.cpp:21:13:21:13 | ConvertToNonVirtualBase | semmle.label | ConvertToNonVirtualBase |
| test.cpp:22:12:22:15 | (B *)... | semmle.label | (B *)... |
| test.cpp:22:12:22:15 | Load | semmle.label | Load |
| test.cpp:22:12:22:15 | Unary | semmle.label | Unary |
| test.cpp:22:12:22:15 | this | semmle.label | this |
| test.cpp:25:7:25:10 | (A *)... | semmle.label | (A *)... |
| test.cpp:25:7:25:10 | (B *)... | semmle.label | (B *)... |
| test.cpp:25:7:25:10 | Load | semmle.label | Load |
| test.cpp:25:7:25:10 | Unary | semmle.label | Unary |
| test.cpp:25:7:25:10 | Unary | semmle.label | Unary |
| test.cpp:25:7:25:10 | this | semmle.label | this |
| test.cpp:31:3:31:3 | D | semmle.label | D |
| test.cpp:31:3:31:3 | this | semmle.label | this |
| test.cpp:31:11:31:15 | (B)... | semmle.label | (B)... |
| test.cpp:31:11:31:15 | (reference to) | semmle.label | (reference to) |
| test.cpp:31:11:31:15 | * ... | semmle.label | * ... |
| test.cpp:31:11:31:15 | Unary | semmle.label | Unary |
| test.cpp:31:11:31:15 | Unary | semmle.label | Unary |
| test.cpp:31:12:31:15 | Load | semmle.label | Load |
| test.cpp:31:12:31:15 | Unary | semmle.label | Unary |
| test.cpp:31:12:31:15 | this | semmle.label | this |
| test.cpp:34:16:34:16 | x | semmle.label | x |
| test.cpp:35:3:35:3 | (A *)... | semmle.label | (A *)... |
| test.cpp:35:3:35:3 | Load | semmle.label | Load |
| test.cpp:35:3:35:3 | Unary | semmle.label | Unary |
| test.cpp:35:3:35:3 | x | semmle.label | x |
| test.cpp:47:3:47:3 | F | semmle.label | F |
| test.cpp:47:3:47:3 | this | semmle.label | this |
| test.cpp:48:6:48:13 | (A *)... | semmle.label | (A *)... |
| test.cpp:48:10:48:13 | (E *)... | semmle.label | (E *)... |
| test.cpp:48:10:48:13 | Load | semmle.label | Load |
| test.cpp:48:10:48:13 | Unary | semmle.label | Unary |
| test.cpp:48:10:48:13 | Unary | semmle.label | Unary |
| test.cpp:48:10:48:13 | this | semmle.label | this |
#select
| test.cpp:12:7:12:7 | call to f | test.cpp:31:3:31:3 | D | test.cpp:12:5:12:5 | (A)... | Call to pure virtual function during construction. |
| test.cpp:16:5:16:5 | call to f | test.cpp:15:3:15:4 | ~B | file://:0:0:0:0 | (A *)... | Call to pure virtual function during destruction. |
| test.cpp:25:13:25:13 | call to f | test.cpp:21:3:21:3 | C | test.cpp:25:7:25:10 | (A *)... | Call to pure virtual function during construction. |
| test.cpp:35:6:35:6 | call to f | test.cpp:7:3:7:3 | B | test.cpp:35:3:35:3 | (A *)... | Call to pure virtual function during construction. |
| test.cpp:35:6:35:6 | call to f | test.cpp:21:3:21:3 | C | test.cpp:35:3:35:3 | (A *)... | Call to pure virtual function during construction. |
| test.cpp:12:7:12:7 | call to f | test.cpp:31:3:31:3 | this | test.cpp:12:5:12:5 | (A)... | Call to pure virtual function during construction. |
| test.cpp:16:5:16:5 | call to f | test.cpp:15:3:15:4 | this | file://:0:0:0:0 | (A *)... | Call to pure virtual function during destruction. |
| test.cpp:25:13:25:13 | call to f | test.cpp:21:3:21:3 | this | test.cpp:25:7:25:10 | (A *)... | Call to pure virtual function during construction. |
| test.cpp:35:6:35:6 | call to f | test.cpp:7:3:7:3 | this | test.cpp:35:3:35:3 | (A *)... | Call to pure virtual function during construction. |
| test.cpp:35:6:35:6 | call to f | test.cpp:21:3:21:3 | this | test.cpp:35:3:35:3 | (A *)... | Call to pure virtual function during construction. |

View File

@@ -1,14 +1,14 @@
| a.c:18:3:18:25 | call to myMultiplyDefinedPrintf | Format for myMultiplyDefinedPrintf expects 1 arguments but given 2 |
| b.c:15:3:15:25 | call to myMultiplyDefinedPrintf | Format for myMultiplyDefinedPrintf expects 1 arguments but given 2 |
| c.c:7:3:7:25 | call to myMultiplyDefinedPrintf | Format for myMultiplyDefinedPrintf expects 1 arguments but given 2 |
| custom_printf.cpp:31:5:31:12 | call to myPrintf | Format for myPrintf expects 2 arguments but given 3 |
| macros.cpp:12:2:12:31 | call to printf | Format for printf (in a macro expansion) expects 2 arguments but given 3 |
| macros.cpp:16:2:16:30 | call to printf | Format for printf (in a macro expansion) expects 2 arguments but given 3 |
| test.c:7:2:7:7 | call to printf | Format for printf expects 0 arguments but given 1 |
| test.c:21:2:21:7 | call to printf | Format for printf expects 2 arguments but given 3 |
| test.c:27:3:27:8 | call to printf | Format for printf expects 2 arguments but given 3 |
| test.c:31:3:31:8 | call to printf | Format for printf expects 1 arguments but given 3 |
| test.c:32:3:32:8 | call to printf | Format for printf expects 1 arguments but given 2 |
| test.c:39:3:39:8 | call to printf | Format for printf expects 2 arguments but given 5 |
| test.c:40:3:40:8 | call to printf | Format for printf expects 2 arguments but given 4 |
| test.c:41:3:41:8 | call to printf | Format for printf expects 2 arguments but given 3 |
| a.c:18:3:18:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 |
| b.c:15:3:15:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 |
| c.c:7:3:7:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 |
| custom_printf.cpp:31:5:31:12 | call to myPrintf | Format expects 2 arguments but given 3 |
| macros.cpp:12:2:12:31 | call to printf | Format expects 2 arguments but given 3 |
| macros.cpp:16:2:16:30 | call to printf | Format expects 2 arguments but given 3 |
| test.c:7:2:7:7 | call to printf | Format expects 0 arguments but given 1 |
| test.c:21:2:21:7 | call to printf | Format expects 2 arguments but given 3 |
| test.c:27:3:27:8 | call to printf | Format expects 2 arguments but given 3 |
| test.c:31:3:31:8 | call to printf | Format expects 1 arguments but given 3 |
| test.c:32:3:32:8 | call to printf | Format expects 1 arguments but given 2 |
| test.c:39:3:39:8 | call to printf | Format expects 2 arguments but given 5 |
| test.c:40:3:40:8 | call to printf | Format expects 2 arguments but given 4 |
| test.c:41:3:41:8 | call to printf | Format expects 2 arguments but given 3 |

View File

@@ -1,12 +1,11 @@
| a.c:16:3:16:25 | call to myMultiplyDefinedPrintf | Format for myMultiplyDefinedPrintf expects 1 arguments but given 0 |
| b.c:13:3:13:25 | call to myMultiplyDefinedPrintf | Format for myMultiplyDefinedPrintf expects 1 arguments but given 0 |
| c.c:5:3:5:25 | call to myMultiplyDefinedPrintf | Format for myMultiplyDefinedPrintf expects 1 arguments but given 0 |
| custom_printf.cpp:29:5:29:12 | call to myPrintf | Format for myPrintf expects 2 arguments but given 1 |
| macros.cpp:14:2:14:37 | call to printf | Format for printf (in a macro expansion) expects 4 arguments but given 3 |
| macros.cpp:21:2:21:36 | call to printf | Format for printf (in a macro expansion) expects 4 arguments but given 3 |
| macros.cpp:32:2:32:25 | call to printf | Format for printf (in a macro expansion) expects 1 arguments but given 0 |
| test.c:9:2:9:7 | call to printf | Format for printf expects 1 arguments but given 0 |
| test.c:12:2:12:7 | call to printf | Format for printf expects 2 arguments but given 1 |
| test.c:15:2:15:7 | call to printf | Format for printf expects 3 arguments but given 2 |
| test.c:19:2:19:7 | call to printf | Format for printf expects 2 arguments but given 1 |
| test.c:29:3:29:8 | call to printf | Format for printf expects 2 arguments but given 1 |
| a.c:16:3:16:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 |
| b.c:13:3:13:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 |
| c.c:5:3:5:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 |
| custom_printf.cpp:29:5:29:12 | call to myPrintf | Format expects 2 arguments but given 1 |
| macros.cpp:14:2:14:37 | call to printf | Format expects 4 arguments but given 3 |
| macros.cpp:21:2:21:36 | call to printf | Format expects 4 arguments but given 3 |
| test.c:9:2:9:7 | call to printf | Format expects 1 arguments but given 0 |
| test.c:12:2:12:7 | call to printf | Format expects 2 arguments but given 1 |
| test.c:15:2:15:7 | call to printf | Format expects 3 arguments but given 2 |
| test.c:19:2:19:7 | call to printf | Format expects 2 arguments but given 1 |
| test.c:29:3:29:8 | call to printf | Format expects 2 arguments but given 1 |

View File

@@ -13,21 +13,10 @@ void testMacros(int a, int b, int c)
GOODPRINTF("%i %i %i\n", a, b, c); // GOOD
GOODPRINTF("%i %i %i %i\n", a, b, c); // BAD: too few format arguments
BADPRINTF("%i %i\n", a, b, 0); // DUBIOUS: too many format arguments
BADPRINTF("%i %i\n", a, b, 0); // BAD: too many format arguments
// ^ here there are too many format arguments, but the design of the Macro forces the user
// to do this, and the extra argument is harmlessly ignored in practice. Reporting these
// results can be extremely noisy (e.g. in openldap).
BADPRINTF("%i %i %i\n", a, b, c); // GOOD
BADPRINTF("%i %i %i %i\n", a, b, c); // BAD: too few format arguments
}
#define DOTHING(x) \
printf("doing thing: " #x); x
void testMacros2()
{
int x;
DOTHING(x++); // GOOD
DOTHING(printf("%i", x)); // BAD: the printf inside the macro has too few format arguments
}

View File

@@ -1,117 +1,231 @@
edges
| test.cpp:17:10:17:11 | mc | test.cpp:17:9:17:11 | & ... |
| test.cpp:23:17:23:19 | & ... | test.cpp:23:17:23:19 | & ... |
| test.cpp:23:17:23:19 | & ... | test.cpp:25:9:25:11 | ptr |
| test.cpp:23:18:23:19 | mc | test.cpp:23:17:23:19 | & ... |
| test.cpp:39:17:39:18 | (reference to) | test.cpp:39:17:39:18 | (reference to) |
| test.cpp:39:17:39:18 | (reference to) | test.cpp:41:10:41:12 | ref |
| test.cpp:39:17:39:18 | mc | test.cpp:39:17:39:18 | (reference to) |
| test.cpp:41:10:41:12 | (reference dereference) | test.cpp:41:9:41:12 | & ... |
| test.cpp:41:10:41:12 | ref | test.cpp:41:10:41:12 | (reference dereference) |
| test.cpp:47:9:47:10 | mc | test.cpp:47:9:47:10 | (reference to) |
| test.cpp:54:11:54:12 | mc | test.cpp:54:14:54:14 | a |
| test.cpp:54:14:54:14 | a | test.cpp:54:9:54:15 | & ... |
| test.cpp:89:3:89:11 | ... = ... | test.cpp:92:9:92:11 | ptr |
| test.cpp:89:9:89:11 | & ... | test.cpp:89:3:89:11 | ... = ... |
| test.cpp:89:10:89:11 | mc | test.cpp:89:9:89:11 | & ... |
| test.cpp:112:9:112:11 | arr | test.cpp:112:9:112:11 | array to pointer conversion |
| test.cpp:119:11:119:13 | arr | test.cpp:119:11:119:13 | array to pointer conversion |
| test.cpp:119:11:119:13 | array to pointer conversion | test.cpp:119:11:119:17 | access to array |
| test.cpp:119:11:119:17 | access to array | test.cpp:119:9:119:18 | & ... |
| test.cpp:134:2:134:14 | ... = ... | test.cpp:135:2:135:4 | ptr |
| test.cpp:134:8:134:10 | arr | test.cpp:134:8:134:10 | array to pointer conversion |
| test.cpp:134:8:134:10 | array to pointer conversion | test.cpp:134:8:134:14 | ... + ... |
| test.cpp:134:8:134:14 | ... + ... | test.cpp:134:2:134:14 | ... = ... |
| test.cpp:135:2:135:4 | ptr | test.cpp:135:2:135:6 | ... ++ |
| test.cpp:135:2:135:6 | ... ++ | test.cpp:135:2:135:6 | ... ++ |
| test.cpp:135:2:135:6 | ... ++ | test.cpp:137:9:137:11 | ptr |
| test.cpp:170:26:170:41 | (void *)... | test.cpp:170:26:170:41 | (void *)... |
| test.cpp:170:26:170:41 | (void *)... | test.cpp:171:10:171:23 | pointerToLocal |
| test.cpp:170:34:170:41 | & ... | test.cpp:170:26:170:41 | (void *)... |
| test.cpp:170:35:170:41 | myLocal | test.cpp:170:34:170:41 | & ... |
| test.cpp:176:25:176:34 | array to pointer conversion | test.cpp:176:25:176:34 | array to pointer conversion |
| test.cpp:176:25:176:34 | array to pointer conversion | test.cpp:177:10:177:23 | pointerToLocal |
| test.cpp:176:25:176:34 | localArray | test.cpp:176:25:176:34 | array to pointer conversion |
| test.cpp:177:10:177:23 | pointerToLocal | test.cpp:177:10:177:23 | (void *)... |
| test.cpp:182:21:182:27 | (reference to) | test.cpp:182:21:182:27 | (reference to) |
| test.cpp:182:21:182:27 | (reference to) | test.cpp:183:10:183:19 | refToLocal |
| test.cpp:182:21:182:27 | myLocal | test.cpp:182:21:182:27 | (reference to) |
| test.cpp:183:10:183:19 | (reference dereference) | test.cpp:183:10:183:19 | (reference to) |
| test.cpp:183:10:183:19 | refToLocal | test.cpp:183:10:183:19 | (reference dereference) |
| test.cpp:189:16:189:16 | (reference to) | test.cpp:189:16:189:16 | (reference to) |
| test.cpp:189:16:189:16 | (reference to) | test.cpp:190:10:190:13 | pRef |
| test.cpp:189:16:189:16 | p | test.cpp:189:16:189:16 | (reference to) |
| test.cpp:190:10:190:13 | (reference dereference) | test.cpp:190:10:190:13 | (reference to) |
| test.cpp:190:10:190:13 | pRef | test.cpp:190:10:190:13 | (reference dereference) |
| test.cpp:17:9:17:11 | & ... | test.cpp:17:9:17:11 | StoreValue |
| test.cpp:17:10:17:11 | Unary | test.cpp:17:9:17:11 | & ... |
| test.cpp:17:10:17:11 | mc | test.cpp:17:10:17:11 | Unary |
| test.cpp:23:17:23:19 | & ... | test.cpp:23:17:23:19 | StoreValue |
| test.cpp:23:17:23:19 | Store | test.cpp:25:9:25:11 | Load |
| test.cpp:23:17:23:19 | StoreValue | test.cpp:23:17:23:19 | Store |
| test.cpp:23:18:23:19 | Unary | test.cpp:23:17:23:19 | & ... |
| test.cpp:23:18:23:19 | mc | test.cpp:23:18:23:19 | Unary |
| test.cpp:25:9:25:11 | Load | test.cpp:25:9:25:11 | ptr |
| test.cpp:25:9:25:11 | ptr | test.cpp:25:9:25:11 | StoreValue |
| test.cpp:39:17:39:18 | (reference to) | test.cpp:39:17:39:18 | StoreValue |
| test.cpp:39:17:39:18 | Store | test.cpp:41:10:41:12 | Load |
| test.cpp:39:17:39:18 | StoreValue | test.cpp:39:17:39:18 | Store |
| test.cpp:39:17:39:18 | Unary | test.cpp:39:17:39:18 | (reference to) |
| test.cpp:39:17:39:18 | mc | test.cpp:39:17:39:18 | Unary |
| test.cpp:41:9:41:12 | & ... | test.cpp:41:9:41:12 | StoreValue |
| test.cpp:41:10:41:12 | (reference dereference) | test.cpp:41:10:41:12 | Unary |
| test.cpp:41:10:41:12 | Load | test.cpp:41:10:41:12 | ref |
| test.cpp:41:10:41:12 | Unary | test.cpp:41:9:41:12 | & ... |
| test.cpp:41:10:41:12 | Unary | test.cpp:41:10:41:12 | (reference dereference) |
| test.cpp:41:10:41:12 | ref | test.cpp:41:10:41:12 | Unary |
| test.cpp:47:9:47:10 | (reference to) | test.cpp:47:9:47:10 | StoreValue |
| test.cpp:47:9:47:10 | Unary | test.cpp:47:9:47:10 | (reference to) |
| test.cpp:47:9:47:10 | mc | test.cpp:47:9:47:10 | Unary |
| test.cpp:54:9:54:15 | & ... | test.cpp:54:9:54:15 | StoreValue |
| test.cpp:54:11:54:12 | Unary | test.cpp:54:14:54:14 | a |
| test.cpp:54:11:54:12 | mc | test.cpp:54:11:54:12 | Unary |
| test.cpp:54:14:54:14 | Unary | test.cpp:54:9:54:15 | & ... |
| test.cpp:54:14:54:14 | a | test.cpp:54:14:54:14 | Unary |
| test.cpp:89:3:89:11 | Store | test.cpp:92:9:92:11 | Load |
| test.cpp:89:9:89:11 | & ... | test.cpp:89:9:89:11 | StoreValue |
| test.cpp:89:9:89:11 | StoreValue | test.cpp:89:3:89:11 | Store |
| test.cpp:89:10:89:11 | Unary | test.cpp:89:9:89:11 | & ... |
| test.cpp:89:10:89:11 | mc | test.cpp:89:10:89:11 | Unary |
| test.cpp:92:9:92:11 | Load | test.cpp:92:9:92:11 | ptr |
| test.cpp:92:9:92:11 | ptr | test.cpp:92:9:92:11 | StoreValue |
| test.cpp:112:9:112:11 | Unary | test.cpp:112:9:112:11 | array to pointer conversion |
| test.cpp:112:9:112:11 | arr | test.cpp:112:9:112:11 | Unary |
| test.cpp:112:9:112:11 | array to pointer conversion | test.cpp:112:9:112:11 | StoreValue |
| test.cpp:119:9:119:18 | & ... | test.cpp:119:9:119:18 | StoreValue |
| test.cpp:119:11:119:13 | Left | test.cpp:119:11:119:17 | access to array |
| test.cpp:119:11:119:13 | Unary | test.cpp:119:11:119:13 | array to pointer conversion |
| test.cpp:119:11:119:13 | arr | test.cpp:119:11:119:13 | Unary |
| test.cpp:119:11:119:13 | array to pointer conversion | test.cpp:119:11:119:13 | Left |
| test.cpp:119:11:119:17 | Unary | test.cpp:119:9:119:18 | & ... |
| test.cpp:119:11:119:17 | access to array | test.cpp:119:11:119:17 | Unary |
| test.cpp:134:2:134:14 | Store | test.cpp:135:2:135:4 | Load |
| test.cpp:134:8:134:10 | Left | test.cpp:134:8:134:14 | ... + ... |
| test.cpp:134:8:134:10 | Unary | test.cpp:134:8:134:10 | array to pointer conversion |
| test.cpp:134:8:134:10 | arr | test.cpp:134:8:134:10 | Unary |
| test.cpp:134:8:134:10 | array to pointer conversion | test.cpp:134:8:134:10 | Left |
| test.cpp:134:8:134:14 | ... + ... | test.cpp:134:8:134:14 | StoreValue |
| test.cpp:134:8:134:14 | StoreValue | test.cpp:134:2:134:14 | Store |
| test.cpp:135:2:135:4 | Left | test.cpp:135:2:135:6 | PointerAdd |
| test.cpp:135:2:135:4 | Load | test.cpp:135:2:135:4 | ptr |
| test.cpp:135:2:135:4 | ptr | test.cpp:135:2:135:4 | Left |
| test.cpp:135:2:135:6 | PointerAdd | test.cpp:135:2:135:6 | StoreValue |
| test.cpp:135:2:135:6 | Store | test.cpp:137:9:137:11 | Load |
| test.cpp:135:2:135:6 | StoreValue | test.cpp:135:2:135:6 | Store |
| test.cpp:137:9:137:11 | Load | test.cpp:137:9:137:11 | ptr |
| test.cpp:137:9:137:11 | ptr | test.cpp:137:9:137:11 | StoreValue |
| test.cpp:170:26:170:41 | (void *)... | test.cpp:170:26:170:41 | StoreValue |
| test.cpp:170:26:170:41 | Store | test.cpp:171:10:171:23 | Load |
| test.cpp:170:26:170:41 | StoreValue | test.cpp:170:26:170:41 | Store |
| test.cpp:170:34:170:41 | & ... | test.cpp:170:34:170:41 | Unary |
| test.cpp:170:34:170:41 | Unary | test.cpp:170:26:170:41 | (void *)... |
| test.cpp:170:35:170:41 | Unary | test.cpp:170:34:170:41 | & ... |
| test.cpp:170:35:170:41 | myLocal | test.cpp:170:35:170:41 | Unary |
| test.cpp:171:10:171:23 | Load | test.cpp:171:10:171:23 | pointerToLocal |
| test.cpp:171:10:171:23 | pointerToLocal | test.cpp:171:10:171:23 | StoreValue |
| test.cpp:176:25:176:34 | Store | test.cpp:177:10:177:23 | Load |
| test.cpp:176:25:176:34 | StoreValue | test.cpp:176:25:176:34 | Store |
| test.cpp:176:25:176:34 | Unary | test.cpp:176:25:176:34 | array to pointer conversion |
| test.cpp:176:25:176:34 | array to pointer conversion | test.cpp:176:25:176:34 | StoreValue |
| test.cpp:176:25:176:34 | localArray | test.cpp:176:25:176:34 | Unary |
| test.cpp:177:10:177:23 | (void *)... | test.cpp:177:10:177:23 | StoreValue |
| test.cpp:177:10:177:23 | Load | test.cpp:177:10:177:23 | pointerToLocal |
| test.cpp:177:10:177:23 | Unary | test.cpp:177:10:177:23 | (void *)... |
| test.cpp:177:10:177:23 | pointerToLocal | test.cpp:177:10:177:23 | Unary |
| test.cpp:182:21:182:27 | (reference to) | test.cpp:182:21:182:27 | StoreValue |
| test.cpp:182:21:182:27 | Store | test.cpp:183:10:183:19 | Load |
| test.cpp:182:21:182:27 | StoreValue | test.cpp:182:21:182:27 | Store |
| test.cpp:182:21:182:27 | Unary | test.cpp:182:21:182:27 | (reference to) |
| test.cpp:182:21:182:27 | myLocal | test.cpp:182:21:182:27 | Unary |
| test.cpp:183:10:183:19 | (reference dereference) | test.cpp:183:10:183:19 | Unary |
| test.cpp:183:10:183:19 | (reference to) | test.cpp:183:10:183:19 | StoreValue |
| test.cpp:183:10:183:19 | Load | test.cpp:183:10:183:19 | refToLocal |
| test.cpp:183:10:183:19 | Unary | test.cpp:183:10:183:19 | (reference dereference) |
| test.cpp:183:10:183:19 | Unary | test.cpp:183:10:183:19 | (reference to) |
| test.cpp:183:10:183:19 | refToLocal | test.cpp:183:10:183:19 | Unary |
| test.cpp:189:16:189:16 | (reference to) | test.cpp:189:16:189:16 | StoreValue |
| test.cpp:189:16:189:16 | Store | test.cpp:190:10:190:13 | Load |
| test.cpp:189:16:189:16 | StoreValue | test.cpp:189:16:189:16 | Store |
| test.cpp:189:16:189:16 | Unary | test.cpp:189:16:189:16 | (reference to) |
| test.cpp:189:16:189:16 | p | test.cpp:189:16:189:16 | Unary |
| test.cpp:190:10:190:13 | (reference dereference) | test.cpp:190:10:190:13 | Unary |
| test.cpp:190:10:190:13 | (reference to) | test.cpp:190:10:190:13 | StoreValue |
| test.cpp:190:10:190:13 | Load | test.cpp:190:10:190:13 | pRef |
| test.cpp:190:10:190:13 | Unary | test.cpp:190:10:190:13 | (reference dereference) |
| test.cpp:190:10:190:13 | Unary | test.cpp:190:10:190:13 | (reference to) |
| test.cpp:190:10:190:13 | pRef | test.cpp:190:10:190:13 | Unary |
nodes
| test.cpp:17:9:17:11 | & ... | semmle.label | & ... |
| test.cpp:17:9:17:11 | StoreValue | semmle.label | StoreValue |
| test.cpp:17:10:17:11 | Unary | semmle.label | Unary |
| test.cpp:17:10:17:11 | mc | semmle.label | mc |
| test.cpp:23:17:23:19 | & ... | semmle.label | & ... |
| test.cpp:23:17:23:19 | & ... | semmle.label | & ... |
| test.cpp:23:17:23:19 | Store | semmle.label | Store |
| test.cpp:23:17:23:19 | StoreValue | semmle.label | StoreValue |
| test.cpp:23:18:23:19 | Unary | semmle.label | Unary |
| test.cpp:23:18:23:19 | mc | semmle.label | mc |
| test.cpp:25:9:25:11 | Load | semmle.label | Load |
| test.cpp:25:9:25:11 | StoreValue | semmle.label | StoreValue |
| test.cpp:25:9:25:11 | ptr | semmle.label | ptr |
| test.cpp:39:17:39:18 | (reference to) | semmle.label | (reference to) |
| test.cpp:39:17:39:18 | (reference to) | semmle.label | (reference to) |
| test.cpp:39:17:39:18 | Store | semmle.label | Store |
| test.cpp:39:17:39:18 | StoreValue | semmle.label | StoreValue |
| test.cpp:39:17:39:18 | Unary | semmle.label | Unary |
| test.cpp:39:17:39:18 | mc | semmle.label | mc |
| test.cpp:41:9:41:12 | & ... | semmle.label | & ... |
| test.cpp:41:9:41:12 | StoreValue | semmle.label | StoreValue |
| test.cpp:41:10:41:12 | (reference dereference) | semmle.label | (reference dereference) |
| test.cpp:41:10:41:12 | Load | semmle.label | Load |
| test.cpp:41:10:41:12 | Unary | semmle.label | Unary |
| test.cpp:41:10:41:12 | Unary | semmle.label | Unary |
| test.cpp:41:10:41:12 | ref | semmle.label | ref |
| test.cpp:47:9:47:10 | (reference to) | semmle.label | (reference to) |
| test.cpp:47:9:47:10 | StoreValue | semmle.label | StoreValue |
| test.cpp:47:9:47:10 | Unary | semmle.label | Unary |
| test.cpp:47:9:47:10 | mc | semmle.label | mc |
| test.cpp:54:9:54:15 | & ... | semmle.label | & ... |
| test.cpp:54:9:54:15 | StoreValue | semmle.label | StoreValue |
| test.cpp:54:11:54:12 | Unary | semmle.label | Unary |
| test.cpp:54:11:54:12 | mc | semmle.label | mc |
| test.cpp:54:14:54:14 | Unary | semmle.label | Unary |
| test.cpp:54:14:54:14 | a | semmle.label | a |
| test.cpp:89:3:89:11 | ... = ... | semmle.label | ... = ... |
| test.cpp:89:3:89:11 | Store | semmle.label | Store |
| test.cpp:89:9:89:11 | & ... | semmle.label | & ... |
| test.cpp:89:9:89:11 | StoreValue | semmle.label | StoreValue |
| test.cpp:89:10:89:11 | Unary | semmle.label | Unary |
| test.cpp:89:10:89:11 | mc | semmle.label | mc |
| test.cpp:92:9:92:11 | Load | semmle.label | Load |
| test.cpp:92:9:92:11 | StoreValue | semmle.label | StoreValue |
| test.cpp:92:9:92:11 | ptr | semmle.label | ptr |
| test.cpp:112:9:112:11 | StoreValue | semmle.label | StoreValue |
| test.cpp:112:9:112:11 | Unary | semmle.label | Unary |
| test.cpp:112:9:112:11 | arr | semmle.label | arr |
| test.cpp:112:9:112:11 | array to pointer conversion | semmle.label | array to pointer conversion |
| test.cpp:119:9:119:18 | & ... | semmle.label | & ... |
| test.cpp:119:9:119:18 | StoreValue | semmle.label | StoreValue |
| test.cpp:119:11:119:13 | Left | semmle.label | Left |
| test.cpp:119:11:119:13 | Unary | semmle.label | Unary |
| test.cpp:119:11:119:13 | arr | semmle.label | arr |
| test.cpp:119:11:119:13 | array to pointer conversion | semmle.label | array to pointer conversion |
| test.cpp:119:11:119:17 | Unary | semmle.label | Unary |
| test.cpp:119:11:119:17 | access to array | semmle.label | access to array |
| test.cpp:134:2:134:14 | ... = ... | semmle.label | ... = ... |
| test.cpp:134:2:134:14 | Store | semmle.label | Store |
| test.cpp:134:8:134:10 | Left | semmle.label | Left |
| test.cpp:134:8:134:10 | Unary | semmle.label | Unary |
| test.cpp:134:8:134:10 | arr | semmle.label | arr |
| test.cpp:134:8:134:10 | array to pointer conversion | semmle.label | array to pointer conversion |
| test.cpp:134:8:134:14 | ... + ... | semmle.label | ... + ... |
| test.cpp:134:8:134:14 | StoreValue | semmle.label | StoreValue |
| test.cpp:135:2:135:4 | Left | semmle.label | Left |
| test.cpp:135:2:135:4 | Load | semmle.label | Load |
| test.cpp:135:2:135:4 | ptr | semmle.label | ptr |
| test.cpp:135:2:135:6 | ... ++ | semmle.label | ... ++ |
| test.cpp:135:2:135:6 | ... ++ | semmle.label | ... ++ |
| test.cpp:135:2:135:6 | PointerAdd | semmle.label | PointerAdd |
| test.cpp:135:2:135:6 | Store | semmle.label | Store |
| test.cpp:135:2:135:6 | StoreValue | semmle.label | StoreValue |
| test.cpp:137:9:137:11 | Load | semmle.label | Load |
| test.cpp:137:9:137:11 | StoreValue | semmle.label | StoreValue |
| test.cpp:137:9:137:11 | ptr | semmle.label | ptr |
| test.cpp:170:26:170:41 | (void *)... | semmle.label | (void *)... |
| test.cpp:170:26:170:41 | (void *)... | semmle.label | (void *)... |
| test.cpp:170:26:170:41 | Store | semmle.label | Store |
| test.cpp:170:26:170:41 | StoreValue | semmle.label | StoreValue |
| test.cpp:170:34:170:41 | & ... | semmle.label | & ... |
| test.cpp:170:34:170:41 | Unary | semmle.label | Unary |
| test.cpp:170:35:170:41 | Unary | semmle.label | Unary |
| test.cpp:170:35:170:41 | myLocal | semmle.label | myLocal |
| test.cpp:171:10:171:23 | Load | semmle.label | Load |
| test.cpp:171:10:171:23 | StoreValue | semmle.label | StoreValue |
| test.cpp:171:10:171:23 | pointerToLocal | semmle.label | pointerToLocal |
| test.cpp:176:25:176:34 | array to pointer conversion | semmle.label | array to pointer conversion |
| test.cpp:176:25:176:34 | Store | semmle.label | Store |
| test.cpp:176:25:176:34 | StoreValue | semmle.label | StoreValue |
| test.cpp:176:25:176:34 | Unary | semmle.label | Unary |
| test.cpp:176:25:176:34 | array to pointer conversion | semmle.label | array to pointer conversion |
| test.cpp:176:25:176:34 | localArray | semmle.label | localArray |
| test.cpp:177:10:177:23 | (void *)... | semmle.label | (void *)... |
| test.cpp:177:10:177:23 | Load | semmle.label | Load |
| test.cpp:177:10:177:23 | StoreValue | semmle.label | StoreValue |
| test.cpp:177:10:177:23 | Unary | semmle.label | Unary |
| test.cpp:177:10:177:23 | pointerToLocal | semmle.label | pointerToLocal |
| test.cpp:182:21:182:27 | (reference to) | semmle.label | (reference to) |
| test.cpp:182:21:182:27 | (reference to) | semmle.label | (reference to) |
| test.cpp:182:21:182:27 | Store | semmle.label | Store |
| test.cpp:182:21:182:27 | StoreValue | semmle.label | StoreValue |
| test.cpp:182:21:182:27 | Unary | semmle.label | Unary |
| test.cpp:182:21:182:27 | myLocal | semmle.label | myLocal |
| test.cpp:183:10:183:19 | (reference dereference) | semmle.label | (reference dereference) |
| test.cpp:183:10:183:19 | (reference to) | semmle.label | (reference to) |
| test.cpp:183:10:183:19 | Load | semmle.label | Load |
| test.cpp:183:10:183:19 | StoreValue | semmle.label | StoreValue |
| test.cpp:183:10:183:19 | Unary | semmle.label | Unary |
| test.cpp:183:10:183:19 | Unary | semmle.label | Unary |
| test.cpp:183:10:183:19 | refToLocal | semmle.label | refToLocal |
| test.cpp:189:16:189:16 | (reference to) | semmle.label | (reference to) |
| test.cpp:189:16:189:16 | (reference to) | semmle.label | (reference to) |
| test.cpp:189:16:189:16 | Store | semmle.label | Store |
| test.cpp:189:16:189:16 | StoreValue | semmle.label | StoreValue |
| test.cpp:189:16:189:16 | Unary | semmle.label | Unary |
| test.cpp:189:16:189:16 | p | semmle.label | p |
| test.cpp:190:10:190:13 | (reference dereference) | semmle.label | (reference dereference) |
| test.cpp:190:10:190:13 | (reference to) | semmle.label | (reference to) |
| test.cpp:190:10:190:13 | Load | semmle.label | Load |
| test.cpp:190:10:190:13 | StoreValue | semmle.label | StoreValue |
| test.cpp:190:10:190:13 | Unary | semmle.label | Unary |
| test.cpp:190:10:190:13 | Unary | semmle.label | Unary |
| test.cpp:190:10:190:13 | pRef | semmle.label | pRef |
#select
| test.cpp:17:9:17:11 | CopyValue: & ... | test.cpp:17:10:17:11 | mc | test.cpp:17:9:17:11 | & ... | May return stack-allocated memory from $@. | test.cpp:17:10:17:11 | mc | mc |
| test.cpp:25:9:25:11 | Load: ptr | test.cpp:23:18:23:19 | mc | test.cpp:25:9:25:11 | ptr | May return stack-allocated memory from $@. | test.cpp:23:18:23:19 | mc | mc |
| test.cpp:41:9:41:12 | CopyValue: & ... | test.cpp:39:17:39:18 | mc | test.cpp:41:9:41:12 | & ... | May return stack-allocated memory from $@. | test.cpp:39:17:39:18 | mc | mc |
| test.cpp:47:9:47:10 | CopyValue: (reference to) | test.cpp:47:9:47:10 | mc | test.cpp:47:9:47:10 | (reference to) | May return stack-allocated memory from $@. | test.cpp:47:9:47:10 | mc | mc |
| test.cpp:54:9:54:15 | CopyValue: & ... | test.cpp:54:11:54:12 | mc | test.cpp:54:9:54:15 | & ... | May return stack-allocated memory from $@. | test.cpp:54:11:54:12 | mc | mc |
| test.cpp:92:9:92:11 | Load: ptr | test.cpp:89:10:89:11 | mc | test.cpp:92:9:92:11 | ptr | May return stack-allocated memory from $@. | test.cpp:89:10:89:11 | mc | mc |
| test.cpp:112:9:112:11 | Convert: array to pointer conversion | test.cpp:112:9:112:11 | arr | test.cpp:112:9:112:11 | array to pointer conversion | May return stack-allocated memory from $@. | test.cpp:112:9:112:11 | arr | arr |
| test.cpp:119:9:119:18 | CopyValue: & ... | test.cpp:119:11:119:13 | arr | test.cpp:119:9:119:18 | & ... | May return stack-allocated memory from $@. | test.cpp:119:11:119:13 | arr | arr |
| test.cpp:137:9:137:11 | Load: ptr | test.cpp:134:8:134:10 | arr | test.cpp:137:9:137:11 | ptr | May return stack-allocated memory from $@. | test.cpp:134:8:134:10 | arr | arr |
| test.cpp:171:10:171:23 | Load: pointerToLocal | test.cpp:170:35:170:41 | myLocal | test.cpp:171:10:171:23 | pointerToLocal | May return stack-allocated memory from $@. | test.cpp:170:35:170:41 | myLocal | myLocal |
| test.cpp:177:10:177:23 | Convert: (void *)... | test.cpp:176:25:176:34 | localArray | test.cpp:177:10:177:23 | (void *)... | May return stack-allocated memory from $@. | test.cpp:176:25:176:34 | localArray | localArray |
| test.cpp:183:10:183:19 | CopyValue: (reference to) | test.cpp:182:21:182:27 | myLocal | test.cpp:183:10:183:19 | (reference to) | May return stack-allocated memory from $@. | test.cpp:182:21:182:27 | myLocal | myLocal |
| test.cpp:190:10:190:13 | CopyValue: (reference to) | test.cpp:189:16:189:16 | p | test.cpp:190:10:190:13 | (reference to) | May return stack-allocated memory from $@. | test.cpp:189:16:189:16 | p | p |
| test.cpp:17:9:17:11 | StoreValue | test.cpp:17:10:17:11 | mc | test.cpp:17:9:17:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:17:10:17:11 | mc | mc |
| test.cpp:25:9:25:11 | StoreValue | test.cpp:23:18:23:19 | mc | test.cpp:25:9:25:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:23:18:23:19 | mc | mc |
| test.cpp:41:9:41:12 | StoreValue | test.cpp:39:17:39:18 | mc | test.cpp:41:9:41:12 | StoreValue | May return stack-allocated memory from $@. | test.cpp:39:17:39:18 | mc | mc |
| test.cpp:47:9:47:10 | StoreValue | test.cpp:47:9:47:10 | mc | test.cpp:47:9:47:10 | StoreValue | May return stack-allocated memory from $@. | test.cpp:47:9:47:10 | mc | mc |
| test.cpp:54:9:54:15 | StoreValue | test.cpp:54:11:54:12 | mc | test.cpp:54:9:54:15 | StoreValue | May return stack-allocated memory from $@. | test.cpp:54:11:54:12 | mc | mc |
| test.cpp:92:9:92:11 | StoreValue | test.cpp:89:10:89:11 | mc | test.cpp:92:9:92:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:89:10:89:11 | mc | mc |
| test.cpp:112:9:112:11 | StoreValue | test.cpp:112:9:112:11 | arr | test.cpp:112:9:112:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:112:9:112:11 | arr | arr |
| test.cpp:119:9:119:18 | StoreValue | test.cpp:119:11:119:13 | arr | test.cpp:119:9:119:18 | StoreValue | May return stack-allocated memory from $@. | test.cpp:119:11:119:13 | arr | arr |
| test.cpp:137:9:137:11 | StoreValue | test.cpp:134:8:134:10 | arr | test.cpp:137:9:137:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:134:8:134:10 | arr | arr |
| test.cpp:171:10:171:23 | StoreValue | test.cpp:170:35:170:41 | myLocal | test.cpp:171:10:171:23 | StoreValue | May return stack-allocated memory from $@. | test.cpp:170:35:170:41 | myLocal | myLocal |
| test.cpp:177:10:177:23 | StoreValue | test.cpp:176:25:176:34 | localArray | test.cpp:177:10:177:23 | StoreValue | May return stack-allocated memory from $@. | test.cpp:176:25:176:34 | localArray | localArray |
| test.cpp:183:10:183:19 | StoreValue | test.cpp:182:21:182:27 | myLocal | test.cpp:183:10:183:19 | StoreValue | May return stack-allocated memory from $@. | test.cpp:182:21:182:27 | myLocal | myLocal |
| test.cpp:190:10:190:13 | StoreValue | test.cpp:189:16:189:16 | p | test.cpp:190:10:190:13 | StoreValue | May return stack-allocated memory from $@. | test.cpp:189:16:189:16 | p | p |

View File

@@ -12,8 +12,11 @@ nodes
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | semmle.label | ... + ... |
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | semmle.label | fgets output argument |
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... | semmle.label | (const char *)... |
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... | semmle.label | (const char *)... |
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | semmle.label | data |
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | semmle.label | data |
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | semmle.label | data |
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | semmle.label | data indirection |
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | semmle.label | data indirection |
#select
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | This argument to a file access function is derived from $@ and then passed to fopen(filename). | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | user input (fgets) |

View File

@@ -12,8 +12,11 @@ nodes
| test.c:9:23:9:26 | argv | semmle.label | argv |
| test.c:9:23:9:26 | argv | semmle.label | argv |
| test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... |
| test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... |
| test.c:17:11:17:18 | fileName | semmle.label | fileName |
| test.c:17:11:17:18 | fileName | semmle.label | fileName |
| test.c:17:11:17:18 | fileName | semmle.label | fileName |
| test.c:17:11:17:18 | fileName indirection | semmle.label | fileName indirection |
| test.c:17:11:17:18 | fileName indirection | semmle.label | fileName indirection |
#select
| test.c:17:11:17:18 | fileName | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:9:23:9:26 | argv | user input (argv) |

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