Compare commits

..

1 Commits

Author SHA1 Message Date
Esben Sparre Andreasen
ee314a4dad remove javascript 2021-09-29 11:19:08 +02:00
9251 changed files with 25464 additions and 811015 deletions

View File

@@ -1,11 +1,8 @@
{ "provide": [ "ruby/.codeqlmanifest.json",
"*/ql/src/qlpack.yml",
{ "provide": [ "*/ql/src/qlpack.yml",
"*/ql/lib/qlpack.yml",
"*/ql/test/qlpack.yml",
"cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml",
"*/ql/examples/qlpack.yml",
"*/upgrades/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml",
"misc/legacy-support/*/qlpack.yml",
"misc/suite-helpers/qlpack.yml" ] }

View File

@@ -1,14 +1,9 @@
{
"extensions": [
"rust-lang.rust",
"bungcip.better-toml",
"github.vscode-codeql",
"slevesque.vscode-zipexplorer"
],
"settings": {
"files.watcherExclude": {
"**/target/**": true
},
"codeQL.runningQueries.memory": 2048
}
}

View File

@@ -1,14 +0,0 @@
name: Fetch CodeQL
description: Fetches the latest version of CodeQL
runs:
using: composite
steps:
- name: Fetch CodeQL
shell: bash
run: |
LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | grep -v beta | sort --version-sort | tail -1)
gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-linux64.zip "$LATEST"
unzip -q -d "${RUNNER_TEMP}" codeql-linux64.zip
echo "${RUNNER_TEMP}/codeql" >> "${GITHUB_PATH}"
env:
GITHUB_TOKEN: ${{ github.token }}

View File

@@ -1,18 +0,0 @@
version: 2
updates:
- package-ecosystem: "cargo"
directory: "ruby/node-types"
schedule:
interval: "daily"
- package-ecosystem: "cargo"
directory: "ruby/generator"
schedule:
interval: "daily"
- package-ecosystem: "cargo"
directory: "ruby/extractor"
schedule:
interval: "daily"
- package-ecosystem: "cargo"
directory: "ruby/autobuilder"
schedule:
interval: "daily"

4
.github/labeler.yml vendored
View File

@@ -18,10 +18,6 @@ Python:
- python/**/*
- change-notes/**/*python*
Ruby:
- ruby/**/*
- change-notes/**/*ruby*
documentation:
- "**/*.qhelp"
- "**/*.md"

View File

@@ -6,8 +6,6 @@ on:
- '.github/workflows/csv-coverage-pr-comment.yml'
- '*/ql/src/**/*.ql'
- '*/ql/src/**/*.qll'
- '*/ql/lib/**/*.ql'
- '*/ql/lib/**/*.qll'
- 'misc/scripts/library-coverage/*.py'
# input data files
- '*/documentation/library-coverage/cwe-sink.csv'

View File

@@ -1,31 +0,0 @@
name: Post pull-request comment
on:
workflow_run:
workflows: ["Query help preview"]
types:
- completed
permissions:
pull-requests: write
jobs:
post_comment:
runs-on: ubuntu-latest
steps:
- name: Download artifact
run: gh run download "${WORKFLOW_RUN_ID}" --repo "${GITHUB_REPOSITORY}" --name "comment"
env:
GITHUB_TOKEN: ${{ github.token }}
WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
- run: |
PR="$(grep -o '^[0-9]\+$' pr.txt)"
PR_HEAD_SHA="$(gh api "/repos/${GITHUB_REPOSITORY}/pulls/${PR}" --jq .head.sha)"
# Check that the pull-request head SHA matches the head SHA of the workflow run
if [ "${WORKFLOW_RUN_HEAD_SHA}" != "${PR_HEAD_SHA}" ]; then
echo "PR head SHA ${PR_HEAD_SHA} does not match workflow_run event SHA ${WORKFLOW_RUN_HEAD_SHA}. Stopping." 1>&2
exit 1
fi
gh pr comment "${PR}" --repo "${GITHUB_REPOSITORY}" -F comment.txt
env:
GITHUB_TOKEN: ${{ github.token }}
WORKFLOW_RUN_HEAD_SHA: ${{ github.event.workflow_run.head_commit.id }}

View File

@@ -1,63 +0,0 @@
name: Query help preview
permissions:
contents: read
on:
pull_request:
branches:
- main
- "rc/*"
paths:
- "ruby/**/*.qhelp"
jobs:
qhelp:
runs-on: ubuntu-latest
steps:
- run: echo "${{ github.event.number }}" > pr.txt
- uses: actions/upload-artifact@v2
with:
name: comment
path: pr.txt
retention-days: 1
- uses: actions/checkout@v2
with:
fetch-depth: 2
persist-credentials: false
- uses: ./.github/actions/fetch-codeql
- name: Determine changed files
id: changes
run: |
(git diff -z --name-only --diff-filter=ACMRT HEAD~1 HEAD | grep -z '.qhelp$' | grep -z -v '.inc.qhelp';
git diff -z --name-only --diff-filter=ACMRT HEAD~1 HEAD | grep -z '.inc.qhelp$' | xargs --null -rn1 basename | xargs --null -rn1 git grep -z -l) |
grep -z '.qhelp$' | grep -z -v '^-' | sort -z -u > "${RUNNER_TEMP}/paths.txt"
- name: QHelp preview
run: |
EXIT_CODE=0
echo "QHelp previews:" > comment.txt
while read -r -d $'\0' path; do
if [ ! -f "${path}" ]; then
exit 1
fi
echo "<details> <summary>${path}</summary>"
echo
codeql generate query-help --format=markdown -- "./${path}" 2> errors.txt || EXIT_CODE="$?"
if [ -s errors.txt ]; then
echo "# errors/warnings:"
echo '```'
cat errors.txt
cat errors.txt 1>&2
echo '```'
fi
echo "</details>"
done < "${RUNNER_TEMP}/paths.txt" >> comment.txt
exit "${EXIT_CODE}"
- if: always()
uses: actions/upload-artifact@v2
with:
name: comment
path: comment.txt
retention-days: 1

View File

@@ -1,224 +0,0 @@
name: "Ruby: Build"
on:
push:
paths:
- "ruby/**"
- .github/workflows/ruby-build.yml
branches:
- main
- "rc/*"
pull_request:
paths:
- "ruby/**"
- .github/workflows/ruby-build.yml
branches:
- main
- "rc/*"
workflow_dispatch:
inputs:
tag:
description: "Version tag to create"
required: false
env:
CARGO_TERM_COLOR: always
defaults:
run:
working-directory: ruby
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Install GNU tar
if: runner.os == 'macOS'
run: |
brew install gnu-tar
echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH
- uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
ruby/target
key: ${{ runner.os }}-rust-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Check formatting
run: cargo fmt --all -- --check
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
- name: Release build
run: cargo build --release
- name: Generate dbscheme
if: ${{ matrix.os == 'ubuntu-latest' }}
run: target/release/ruby-generator --dbscheme ql/lib/ruby.dbscheme --library ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
- uses: actions/upload-artifact@v2
if: ${{ matrix.os == 'ubuntu-latest' }}
with:
name: ruby.dbscheme
path: ruby/ql/lib/ruby.dbscheme
- uses: actions/upload-artifact@v2
if: ${{ matrix.os == 'ubuntu-latest' }}
with:
name: TreeSitter.qll
path: ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
- uses: actions/upload-artifact@v2
with:
name: extractor-${{ matrix.os }}
path: |
ruby/target/release/ruby-autobuilder
ruby/target/release/ruby-autobuilder.exe
ruby/target/release/ruby-extractor
ruby/target/release/ruby-extractor.exe
retention-days: 1
compile-queries:
runs-on: ubuntu-latest
env:
CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
steps:
- uses: actions/checkout@v2
- name: Fetch CodeQL
run: |
LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | grep -v beta | sort --version-sort | tail -1)
gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-linux64.zip "$LATEST"
unzip -q codeql-linux64.zip
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Build Query Pack
run: |
codeql/codeql pack create ql/lib --output target/packs
codeql/codeql pack install ql/src
codeql/codeql pack create ql/src --output target/packs
PACK_FOLDER=$(readlink -f target/packs/codeql/ruby-queries/*)
codeql/codeql generate query-help --format=sarifv2.1.0 --output="${PACK_FOLDER}/rules.sarif" ql/src
(cd ql/src; find queries \( -name '*.qhelp' -o -name '*.rb' -o -name '*.erb' \) -exec bash -c 'mkdir -p "'"${PACK_FOLDER}"'/$(dirname "{}")"' \; -exec cp "{}" "${PACK_FOLDER}/{}" \;)
- uses: actions/upload-artifact@v2
with:
name: codeql-ruby-queries
path: |
ruby/target/packs/*
retention-days: 1
package:
runs-on: ubuntu-latest
needs: [build, compile-queries]
steps:
- uses: actions/checkout@v2
- uses: actions/download-artifact@v2
with:
name: ruby.dbscheme
path: ruby/ruby
- uses: actions/download-artifact@v2
with:
name: extractor-ubuntu-latest
path: ruby/linux64
- uses: actions/download-artifact@v2
with:
name: extractor-windows-latest
path: ruby/win64
- uses: actions/download-artifact@v2
with:
name: extractor-macos-latest
path: ruby/osx64
- run: |
mkdir -p ruby
cp -r codeql-extractor.yml tools ql/lib/ruby.dbscheme.stats ruby/
mkdir -p ruby/tools/{linux64,osx64,win64}
cp linux64/ruby-autobuilder ruby/tools/linux64/autobuilder
cp osx64/ruby-autobuilder ruby/tools/osx64/autobuilder
cp win64/ruby-autobuilder.exe ruby/tools/win64/autobuilder.exe
cp linux64/ruby-extractor ruby/tools/linux64/extractor
cp osx64/ruby-extractor ruby/tools/osx64/extractor
cp win64/ruby-extractor.exe ruby/tools/win64/extractor.exe
chmod +x ruby/tools/{linux64,osx64}/{autobuilder,extractor}
zip -rq codeql-ruby.zip ruby
- uses: actions/upload-artifact@v2
with:
name: codeql-ruby-pack
path: ruby/codeql-ruby.zip
retention-days: 1
- uses: actions/download-artifact@v2
with:
name: codeql-ruby-queries
path: ruby/qlpacks
- run: |
echo '{
"provide": [
"ruby/codeql-extractor.yml",
"qlpacks/*/*/*/qlpack.yml"
]
}' > .codeqlmanifest.json
zip -rq codeql-ruby-bundle.zip .codeqlmanifest.json ruby qlpacks
- uses: actions/upload-artifact@v2
with:
name: codeql-ruby-bundle
path: ruby/codeql-ruby-bundle.zip
retention-days: 1
test:
defaults:
run:
working-directory: ${{ github.workspace }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
needs: [package]
steps:
- uses: actions/checkout@v2
with:
repository: Shopify/example-ruby-app
ref: 67a0decc5eb550f3a9228eda53925c3afd40dfe9
- name: Fetch CodeQL
shell: bash
run: |
LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | grep -v beta | sort --version-sort | tail -1)
gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql.zip "$LATEST"
unzip -q codeql.zip
env:
GITHUB_TOKEN: ${{ github.token }}
working-directory: ${{ runner.temp }}
- name: Download Ruby bundle
uses: actions/download-artifact@v2
with:
name: codeql-ruby-bundle
path: ${{ runner.temp }}
- name: Unzip Ruby bundle
shell: bash
run: unzip -q -d "${{ runner.temp }}/ruby-bundle" "${{ runner.temp }}/codeql-ruby-bundle.zip"
- name: Prepare test files
shell: bash
run: |
echo "import ruby select count(File f)" > "test.ql"
echo "| 4 |" > "test.expected"
echo 'name: sample-tests
version: 0.0.0
dependencies:
codeql/ruby-all: 0.0.1
extractor: ruby
tests: .
' > qlpack.yml
- name: Run QL test
shell: bash
run: |
"${{ runner.temp }}/codeql/codeql" test run --search-path "${{ runner.temp }}/ruby-bundle" --additional-packs "${{ runner.temp }}/ruby-bundle" .
- name: Create database
shell: bash
run: |
"${{ runner.temp }}/codeql/codeql" database create --search-path "${{ runner.temp }}/ruby-bundle" --language ruby --source-root . ../database
- name: Analyze database
shell: bash
run: |
"${{ runner.temp }}/codeql/codeql" database analyze --search-path "${{ runner.temp }}/ruby-bundle" --format=sarifv2.1.0 --output=out.sarif ../database ruby-code-scanning.qls

View File

@@ -1,73 +0,0 @@
name: "Ruby: Collect database stats"
on:
push:
branches:
- main
- "rc/*"
paths:
- ruby/ql/lib/ruby.dbscheme
- .github/workflows/ruby-dataset-measure.yml
pull_request:
branches:
- main
- "rc/*"
paths:
- ruby/ql/lib/ruby.dbscheme
- .github/workflows/ruby-dataset-measure.yml
workflow_dispatch:
jobs:
measure:
env:
CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
strategy:
fail-fast: false
matrix:
repo: [rails/rails, discourse/discourse, spree/spree]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ./.github/actions/fetch-codeql
- uses: ./ruby/actions/create-extractor-pack
- name: Checkout ${{ matrix.repo }}
uses: actions/checkout@v2
with:
repository: ${{ matrix.repo }}
path: ${{ github.workspace }}/repo
- name: Create database
run: |
codeql database create \
--search-path "${{ github.workspace }}/ruby" \
--threads 4 \
--language ruby --source-root "${{ github.workspace }}/repo" \
"${{ runner.temp }}/database"
- name: Measure database
run: |
mkdir -p "stats/${{ matrix.repo }}"
codeql dataset measure --threads 4 --output "stats/${{ matrix.repo }}/stats.xml" "${{ runner.temp }}/database/db-ruby"
- uses: actions/upload-artifact@v2
with:
name: measurements
path: stats
retention-days: 1
merge:
runs-on: ubuntu-latest
needs: measure
steps:
- uses: actions/checkout@v2
- uses: actions/download-artifact@v2
with:
name: measurements
path: stats
- run: |
python -m pip install --user lxml
find stats -name 'stats.xml' | sort | xargs python ruby/scripts/merge_stats.py --output ruby/ql/lib/ruby.dbscheme.stats --normalise ruby_tokeninfo
- uses: actions/upload-artifact@v2
with:
name: ruby.dbscheme.stats
path: ruby/ql/lib/ruby.dbscheme.stats

View File

@@ -1,50 +0,0 @@
name: "Ruby: Run QL Tests"
on:
push:
paths:
- "ruby/**"
- .github/workflows/ruby-qltest.yml
branches:
- main
- "rc/*"
pull_request:
paths:
- "ruby/**"
- .github/workflows/ruby-qltest.yml
branches:
- main
- "rc/*"
env:
CARGO_TERM_COLOR: always
defaults:
run:
working-directory: ruby
jobs:
qltest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ./.github/actions/fetch-codeql
- uses: ./ruby/actions/create-extractor-pack
- name: Run QL tests
run: |
codeql test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}/ruby" --additional-packs "${{ github.workspace }}" --consistency-queries ql/consistency-queries ql/test
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Check QL formatting
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
- name: Check QL compilation
run: |
codeql query compile --check-only --threads=4 --warnings=error --search-path "${{ github.workspace }}/ruby" --additional-packs "${{ github.workspace }}" "ql/src" "ql/examples"
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Check DB upgrade scripts
run: |
echo >empty.trap
codeql dataset import -S ql/lib/upgrades/initial/ruby.dbscheme testdb empty.trap
codeql dataset upgrade testdb --additional-packs ql/lib
diff -q testdb/ruby.dbscheme ql/lib/ruby.dbscheme

View File

@@ -1,20 +0,0 @@
name: Check synchronized files
on:
push:
branches:
- main
- 'rc/*'
pull_request:
branches:
- main
- 'rc/*'
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Check synchronized files
run: python config/sync-files.py

6
.gitignore vendored
View File

@@ -24,9 +24,3 @@
/codeql/
csharp/extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
# Avoid committing cached package components
.codeql
# Compiled class file
*.class

View File

@@ -3,7 +3,6 @@
/java/ @github/codeql-java
/javascript/ @github/codeql-javascript
/python/ @github/codeql-python
/ruby/ @github/codeql-ruby
# Make @xcorail (GitHub Security Lab) a code owner for experimental queries so he gets pinged when we promote a query out of experimental
/cpp/**/experimental/**/* @github/codeql-c-analysis @xcorail
@@ -11,7 +10,6 @@
/java/**/experimental/**/* @github/codeql-java @xcorail
/javascript/**/experimental/**/* @github/codeql-javascript @xcorail
/python/**/experimental/**/* @github/codeql-python @xcorail
/ruby/**/experimental/**/* @github/codeql-ruby @xcorail
# Notify members of codeql-go about PRs to the shared data-flow library files
/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @github/codeql-java @github/codeql-go
@@ -24,4 +22,4 @@
/docs/codeql-cli/ @github/codeql-cli-reviewers
/docs/codeql-for-visual-studio-code/ @github/codeql-vscode-reviewers
/docs/ql-language-reference/ @github/codeql-frontend-reviewers
/docs/query-*-style-guide.md @github/codeql-analysis-reviewers
/docs/query-*-style-guide.md @github/codeql-analysis-reviewers

View File

@@ -11,14 +11,13 @@ If you have an idea for a query that you would like to share with other CodeQL u
1. **Directory structure**
There are six language-specific query directories in this repository:
There are five language-specific query directories in this repository:
* C/C++: `cpp/ql/src`
* C#: `csharp/ql/src`
* Java: `java/ql/src`
* JavaScript: `javascript/ql/src`
* Python: `python/ql/src`
* Ruby: `ruby/ql/src`
Each language-specific directory contains further subdirectories that group queries based on their `@tags` or purpose.
- Experimental queries and libraries are stored in the `experimental` subdirectory within each language-specific directory in the [CodeQL repository](https://github.com/github/codeql). For example, experimental Java queries and libraries are stored in `java/ql/src/experimental` and any corresponding tests in `java/ql/test/experimental`.

View File

@@ -24,17 +24,14 @@
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll"
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll"
],
"DataFlow Java/C++/C#/Python Common": [
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll",
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll"
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll"
],
"TaintTracking::Configuration Java/C++/C#/Python": [
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
@@ -52,21 +49,18 @@
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking1/TaintTrackingImpl.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking2/TaintTrackingImpl.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking4/TaintTrackingImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking4/TaintTrackingImpl.qll"
],
"DataFlow Java/C++/C#/Python Consistency checks": [
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll",
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll",
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplConsistency.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplConsistency.qll"
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplConsistency.qll"
],
"DataFlow Java/C# Flow Summaries": [
"java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll"
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll"
],
"SsaReadPosition Java/C#": [
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
@@ -373,10 +367,8 @@
],
"Inline Test Expectations": [
"cpp/ql/test/TestUtilities/InlineExpectationsTest.qll",
"csharp/ql/test/TestUtilities/InlineExpectationsTest.qll",
"java/ql/test/TestUtilities/InlineExpectationsTest.qll",
"python/ql/test/TestUtilities/InlineExpectationsTest.qll",
"ruby/ql/test/TestUtilities/InlineExpectationsTest.qll"
"python/ql/test/TestUtilities/InlineExpectationsTest.qll"
],
"C++ ExternalAPIs": [
"cpp/ql/src/Security/CWE/CWE-020/ExternalAPIs.qll",
@@ -448,9 +440,7 @@
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll",
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll",
"csharp/ql/lib/semmle/code/cil/internal/SsaImplCommon.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImplCommon.qll",
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll"
"csharp/ql/lib/semmle/code/cil/internal/SsaImplCommon.qll"
],
"CryptoAlgorithms Python/JS": [
"javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll",
@@ -470,23 +460,6 @@
],
"ReDoS Polynomial Python/JS": [
"javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll",
"ruby/ql/lib/codeql/ruby/regexp/SuperlinearBackTracking.qll"
],
"CFG": [
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",
"ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll"
],
"TypeTracker": [
"python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll",
"ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll"
],
"CodeQL Tutorial": [
"cpp/ql/lib/tutorial.qll",
"csharp/ql/lib/tutorial.qll",
"java/ql/lib/tutorial.qll",
"javascript/ql/lib/tutorial.qll",
"python/ql/lib/tutorial.qll",
"ruby/ql/lib/tutorial.qll"
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll"
]
}
}

View File

@@ -1,2 +0,0 @@
lgtm,codescanning
* A new query (`cpp/cleartext-transmission`) has been added. This is similar to the `cpp/cleartext-storage-file`, `cpp/cleartext-storage-buffer` and `cpp/cleartext-storage-database` queries but looks for cases where sensitive information is most likely transmitted over a network.

View File

@@ -1,2 +0,0 @@
lgtm,codescanning
* The "Uncontrolled data used in OS command" (`cpp/command-line-injection`) query has been enhanced to reduce false positive results and its `@precision` increased to `high`

View File

@@ -1,2 +0,0 @@
lgtm,codescanning
* Several improvements made to the `NullTermination.qll` library and the 'Potential improper null termination' (cpp/improper-null-termination). These changes reduce the number of false positive results for this query and related query 'User-controlled data may not be null terminated' (cpp/user-controlled-null-termination-tainted).

View File

@@ -1,3 +0,0 @@
codescanning
* Problems with extraction that in most cases won't break the analysis in a significant way are now reported as warnings rather than errors.
* The failed extractor invocations query now has severity `error`.

View File

@@ -1,4 +0,0 @@
lgtm,codescanning
* The QL library `semmle.code.cpp.commons.Exclusions` now contains a predicate
`isFromSystemMacroDefinition` for identifying code that originates from a
macro outside the project being analyzed.

View File

@@ -1,2 +0,0 @@
lgtm,codescanning
* A new query `cpp/non-https-url` has been added for C/C++. The query flags uses of `http` URLs that might be better replaced with `https`.

View File

@@ -52,8 +52,11 @@ module PrivateCleartextWrite {
class WriteSink extends Sink {
WriteSink() {
this.asExpr() = any(FileWrite f).getASource() or
this.asExpr() = any(BufferWrite b).getAChild()
exists(FileWrite f, BufferWrite b |
this.asExpr() = f.getASource()
or
this.asExpr() = b.getAChild()
)
}
}
}

View File

@@ -13,25 +13,26 @@ import cpp
/** A string for `match` that identifies strings that look like they represent private data. */
private string privateNames() {
result =
[
// Inspired by the list on https://cwe.mitre.org/data/definitions/359.html
// Government identifiers, such as Social Security Numbers
"%social%security%number%",
// Contact information, such as home addresses and telephone numbers
"%postcode%", "%zipcode%",
// result = "%telephone%" or
// Geographic location - where the user is (or was)
"%latitude%", "%longitude%",
// Financial data - such as credit card numbers, salary, bank accounts, and debts
"%creditcard%", "%salary%", "%bankaccount%",
// Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc.
// result = "%email%" or
// result = "%mobile%" or
"%employer%",
// Health - medical conditions, insurance status, prescription records
"%medical%"
]
// Inspired by the list on https://cwe.mitre.org/data/definitions/359.html
// Government identifiers, such as Social Security Numbers
result = "%social%security%number%" or
// Contact information, such as home addresses and telephone numbers
result = "%postcode%" or
result = "%zipcode%" or
// result = "%telephone%" or
// Geographic location - where the user is (or was)
result = "%latitude%" or
result = "%longitude%" or
// Financial data - such as credit card numbers, salary, bank accounts, and debts
result = "%creditcard%" or
result = "%salary%" or
result = "%bankaccount%" or
// Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc.
// result = "%email%" or
// result = "%mobile%" or
result = "%employer%" or
// Health - medical conditions, insurance status, prescription records
result = "%medical%"
}
/** An expression that might contain private data. */

View File

@@ -15,7 +15,7 @@ class ExternalData extends @externalDataElement {
* Gets the path of the file this data was loaded from, with its
* extension replaced by `.ql`.
*/
string getQueryPath() { result = this.getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") }
string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") }
/** Gets the number of fields in this data item. */
int getNumFields() { result = 1 + max(int i | externalData(this, _, i, _) | i) }
@@ -24,22 +24,22 @@ class ExternalData extends @externalDataElement {
string getField(int i) { externalData(this, _, i, result) }
/** Gets the integer value of the `i`th field of this data item. */
int getFieldAsInt(int i) { result = this.getField(i).toInt() }
int getFieldAsInt(int i) { result = getField(i).toInt() }
/** Gets the floating-point value of the `i`th field of this data item. */
float getFieldAsFloat(int i) { result = this.getField(i).toFloat() }
float getFieldAsFloat(int i) { result = getField(i).toFloat() }
/** Gets the value of the `i`th field of this data item, interpreted as a date. */
date getFieldAsDate(int i) { result = this.getField(i).toDate() }
date getFieldAsDate(int i) { result = getField(i).toDate() }
/** Gets a textual representation of this data item. */
string toString() { result = this.getQueryPath() + ": " + this.buildTupleString(0) }
string toString() { result = getQueryPath() + ": " + buildTupleString(0) }
/** Gets a textual representation of this data item, starting with the `n`th field. */
private string buildTupleString(int n) {
n = this.getNumFields() - 1 and result = this.getField(n)
n = getNumFields() - 1 and result = getField(n)
or
n < this.getNumFields() - 1 and result = this.getField(n) + "," + this.buildTupleString(n + 1)
n < getNumFields() - 1 and result = getField(n) + "," + buildTupleString(n + 1)
}
}
@@ -53,8 +53,8 @@ class DefectExternalData extends ExternalData {
}
/** Gets the URL associated with this data item. */
string getURL() { result = this.getField(0) }
string getURL() { result = getField(0) }
/** Gets the message associated with this data item. */
string getMessage() { result = this.getField(1) }
string getMessage() { result = getField(1) }
}

View File

@@ -237,7 +237,7 @@ class Class extends UserType {
exists(ClassDerivation cd | cd.getBaseClass() = base |
result =
this.accessOfBaseMemberMulti(cd.getDerivedClass(),
fieldInBase.accessInDirectDerived(cd.getASpecifier()))
fieldInBase.accessInDirectDerived(cd.getASpecifier().(AccessSpecifier)))
)
}
@@ -261,20 +261,21 @@ class Class extends UserType {
* includes the case of `base` = `this`.
*/
AccessSpecifier accessOfBaseMember(Declaration member) {
result = this.accessOfBaseMember(member.getDeclaringType(), member.getASpecifier())
result =
this.accessOfBaseMember(member.getDeclaringType(), member.getASpecifier().(AccessSpecifier))
}
/**
* DEPRECATED: name changed to `hasImplicitCopyConstructor` to reflect that
* `= default` members are no longer included.
*/
deprecated predicate hasGeneratedCopyConstructor() { this.hasImplicitCopyConstructor() }
deprecated predicate hasGeneratedCopyConstructor() { hasImplicitCopyConstructor() }
/**
* DEPRECATED: name changed to `hasImplicitCopyAssignmentOperator` to
* reflect that `= default` members are no longer included.
*/
deprecated predicate hasGeneratedCopyAssignmentOperator() { this.hasImplicitCopyConstructor() }
deprecated predicate hasGeneratedCopyAssignmentOperator() { hasImplicitCopyConstructor() }
/**
* Holds if this class, struct or union has an implicitly-declared copy
@@ -318,7 +319,7 @@ class Class extends UserType {
exists(Type t | t = this.getAFieldSubobjectType().getUnspecifiedType() |
// Note: Overload resolution is not implemented -- all copy
// constructors are considered equal.
this.cannotAccessCopyConstructorOnAny(t)
this.cannotAccessCopyConstructorOnAny(t.(Class))
)
or
// - T has direct or virtual base class that cannot be copied (has deleted,
@@ -391,7 +392,7 @@ class Class extends UserType {
exists(Type t | t = this.getAFieldSubobjectType().getUnspecifiedType() |
// Note: Overload resolution is not implemented -- all copy assignment
// operators are considered equal.
this.cannotAccessCopyAssignmentOperatorOnAny(t)
this.cannotAccessCopyAssignmentOperatorOnAny(t.(Class))
)
or
exists(Class c | c = this.getADirectOrVirtualBase() |
@@ -486,7 +487,7 @@ class Class extends UserType {
exists(ClassDerivation cd |
// Add the offset of the direct base class and the offset of `baseClass`
// within that direct base class.
cd = this.getADerivation() and
cd = getADerivation() and
result = cd.getBaseClass().getANonVirtualBaseClassByteOffset(baseClass) + cd.getByteOffset()
)
}
@@ -501,12 +502,12 @@ class Class extends UserType {
*/
int getABaseClassByteOffset(Class baseClass) {
// Handle the non-virtual case.
result = this.getANonVirtualBaseClassByteOffset(baseClass)
result = getANonVirtualBaseClassByteOffset(baseClass)
or
exists(Class virtualBaseClass, int virtualBaseOffset, int offsetFromVirtualBase |
// Look for the base class as a non-virtual base of a direct or indirect
// virtual base, adding the two offsets.
this.getVirtualBaseClassByteOffset(virtualBaseClass) = virtualBaseOffset and
getVirtualBaseClassByteOffset(virtualBaseClass) = virtualBaseOffset and
offsetFromVirtualBase = virtualBaseClass.getANonVirtualBaseClassByteOffset(baseClass) and
result = virtualBaseOffset + offsetFromVirtualBase
)
@@ -622,11 +623,11 @@ class Class extends UserType {
* inherits one).
*/
predicate isPolymorphic() {
exists(MemberFunction f | f.getDeclaringType() = this.getABaseClass*() and f.isVirtual())
exists(MemberFunction f | f.getDeclaringType() = getABaseClass*() and f.isVirtual())
}
override predicate involvesTemplateParameter() {
this.getATemplateArgument().(Type).involvesTemplateParameter()
getATemplateArgument().(Type).involvesTemplateParameter()
}
/** Holds if this class, struct or union was declared 'final'. */
@@ -764,7 +765,7 @@ class ClassDerivation extends Locatable, @derivation {
* };
* ```
*/
Class getBaseClass() { result = this.getBaseType().getUnderlyingType() }
Class getBaseClass() { result = getBaseType().getUnderlyingType() }
override string getAPrimaryQlClass() { result = "ClassDerivation" }
@@ -817,7 +818,7 @@ class ClassDerivation extends Locatable, @derivation {
predicate hasSpecifier(string s) { this.getASpecifier().hasName(s) }
/** Holds if the derivation is for a virtual base class. */
predicate isVirtual() { this.hasSpecifier("virtual") }
predicate isVirtual() { hasSpecifier("virtual") }
/** Gets the location of the derivation. */
override Location getLocation() { derivations(underlyingElement(this), _, _, _, result) }
@@ -845,7 +846,7 @@ class ClassDerivation extends Locatable, @derivation {
* ```
*/
class LocalClass extends Class {
LocalClass() { this.isLocal() }
LocalClass() { isLocal() }
override string getAPrimaryQlClass() { not this instanceof LocalStruct and result = "LocalClass" }
@@ -988,9 +989,9 @@ class ClassTemplateSpecialization extends Class {
TemplateClass getPrimaryTemplate() {
// Ignoring template arguments, the primary template has the same name
// as each of its specializations.
result.getSimpleName() = this.getSimpleName() and
result.getSimpleName() = getSimpleName() and
// It is in the same namespace as its specializations.
result.getNamespace() = this.getNamespace() and
result.getNamespace() = getNamespace() and
// It is distinguished by the fact that each of its template arguments
// is a distinct template parameter.
count(TemplateParameter tp | tp = result.getATemplateArgument()) =
@@ -1107,7 +1108,7 @@ deprecated class Interface extends Class {
* ```
*/
class VirtualClassDerivation extends ClassDerivation {
VirtualClassDerivation() { this.hasSpecifier("virtual") }
VirtualClassDerivation() { hasSpecifier("virtual") }
override string getAPrimaryQlClass() { result = "VirtualClassDerivation" }
}
@@ -1135,7 +1136,7 @@ class VirtualBaseClass extends Class {
VirtualClassDerivation getAVirtualDerivation() { result.getBaseClass() = this }
/** A class/struct that is derived from this one using virtual inheritance. */
Class getAVirtuallyDerivedClass() { result = this.getAVirtualDerivation().getDerivedClass() }
Class getAVirtuallyDerivedClass() { result = getAVirtualDerivation().getDerivedClass() }
}
/**
@@ -1154,7 +1155,7 @@ class ProxyClass extends UserType {
override string getAPrimaryQlClass() { result = "ProxyClass" }
/** Gets the location of the proxy class. */
override Location getLocation() { result = this.getTemplateParameter().getDefinitionLocation() }
override Location getLocation() { result = getTemplateParameter().getDefinitionLocation() }
/** Gets the template parameter for which this is the proxy class. */
TemplateParameter getTemplateParameter() {

View File

@@ -184,7 +184,7 @@ class Declaration extends Locatable, @declaration {
predicate hasDefinition() { exists(this.getDefinition()) }
/** DEPRECATED: Use `hasDefinition` instead. */
predicate isDefined() { this.hasDefinition() }
predicate isDefined() { hasDefinition() }
/** Gets the preferred location of this declaration, if any. */
override Location getLocation() { none() }
@@ -209,7 +209,7 @@ class Declaration extends Locatable, @declaration {
predicate isStatic() { this.hasSpecifier("static") }
/** Holds if this declaration is a member of a class/struct/union. */
predicate isMember() { this.hasDeclaringType() }
predicate isMember() { hasDeclaringType() }
/** Holds if this declaration is a member of a class/struct/union. */
predicate hasDeclaringType() { exists(this.getDeclaringType()) }
@@ -226,14 +226,14 @@ class Declaration extends Locatable, @declaration {
* When called on a template, this will return a template parameter type for
* both typed and non-typed parameters.
*/
final Locatable getATemplateArgument() { result = this.getTemplateArgument(_) }
final Locatable getATemplateArgument() { result = getTemplateArgument(_) }
/**
* Gets a template argument used to instantiate this declaration from a template.
* When called on a template, this will return a non-typed template
* parameter value.
*/
final Locatable getATemplateArgumentKind() { result = this.getTemplateArgumentKind(_) }
final Locatable getATemplateArgumentKind() { result = getTemplateArgumentKind(_) }
/**
* Gets the `i`th template argument used to instantiate this declaration from a
@@ -252,9 +252,9 @@ class Declaration extends Locatable, @declaration {
* `getTemplateArgument(1)` return `1`.
*/
final Locatable getTemplateArgument(int index) {
if exists(this.getTemplateArgumentValue(index))
then result = this.getTemplateArgumentValue(index)
else result = this.getTemplateArgumentType(index)
if exists(getTemplateArgumentValue(index))
then result = getTemplateArgumentValue(index)
else result = getTemplateArgumentType(index)
}
/**
@@ -275,13 +275,14 @@ class Declaration extends Locatable, @declaration {
* `getTemplateArgumentKind(0)`.
*/
final Locatable getTemplateArgumentKind(int index) {
exists(this.getTemplateArgumentValue(index)) and
result = this.getTemplateArgumentType(index)
if exists(getTemplateArgumentValue(index))
then result = getTemplateArgumentType(index)
else none()
}
/** Gets the number of template arguments for this declaration. */
final int getNumberOfTemplateArguments() {
result = count(int i | exists(this.getTemplateArgument(i)))
result = count(int i | exists(getTemplateArgument(i)))
}
private Type getTemplateArgumentType(int index) {
@@ -327,9 +328,9 @@ class DeclarationEntry extends Locatable, TDeclarationEntry {
* available), or the name declared by this entry otherwise.
*/
string getCanonicalName() {
if this.getDeclaration().hasDefinition()
then result = this.getDeclaration().getDefinition().getName()
else result = this.getName()
if getDeclaration().hasDefinition()
then result = getDeclaration().getDefinition().getName()
else result = getName()
}
/**
@@ -370,18 +371,18 @@ class DeclarationEntry extends Locatable, TDeclarationEntry {
/**
* Holds if this declaration entry has a specifier with the given name.
*/
predicate hasSpecifier(string specifier) { this.getASpecifier() = specifier }
predicate hasSpecifier(string specifier) { getASpecifier() = specifier }
/** Holds if this declaration entry is a definition. */
predicate isDefinition() { none() } // overridden in subclasses
override string toString() {
if this.isDefinition()
then result = "definition of " + this.getName()
if isDefinition()
then result = "definition of " + getName()
else
if this.getName() = this.getCanonicalName()
then result = "declaration of " + this.getName()
else result = "declaration of " + this.getCanonicalName() + " as " + this.getName()
if getName() = getCanonicalName()
then result = "declaration of " + getName()
else result = "declaration of " + getCanonicalName() + " as " + getName()
}
}
@@ -490,7 +491,8 @@ class AccessHolder extends Declaration, TAccessHolder {
*/
pragma[inline]
predicate canAccessMember(Declaration member, Class derived) {
this.couldAccessMember(member.getDeclaringType(), member.getASpecifier(), derived)
this.couldAccessMember(member.getDeclaringType(), member.getASpecifier().(AccessSpecifier),
derived)
}
/**
@@ -579,7 +581,7 @@ private class DirectAccessHolder extends Element {
// transitive closure with a restricted base case.
this.thisCanAccessClassStep(base, derived)
or
exists(Class between | this.thisCanAccessClassTrans(base, between) |
exists(Class between | thisCanAccessClassTrans(base, between) |
isDirectPublicBaseOf(between, derived) or
this.thisCanAccessClassStep(between, derived)
)

View File

@@ -61,7 +61,7 @@ class ElementBase extends @element {
/**
* Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs.
*/
final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") }
final string getPrimaryQlClasses() { result = concat(getAPrimaryQlClass(), ",") }
/**
* Gets the name of a primary CodeQL class to which this element belongs.
@@ -206,9 +206,9 @@ class Element extends ElementBase {
/** Gets the closest `Element` enclosing this one. */
cached
Element getEnclosingElement() {
result = this.getEnclosingElementPref()
result = getEnclosingElementPref()
or
not exists(this.getEnclosingElementPref()) and
not exists(getEnclosingElementPref()) and
(
this = result.(Class).getAMember()
or
@@ -281,7 +281,7 @@ private predicate isFromUninstantiatedTemplateRec(Element e, Element template) {
* ```
*/
class StaticAssert extends Locatable, @static_assert {
override string toString() { result = "static_assert(..., \"" + this.getMessage() + "\")" }
override string toString() { result = "static_assert(..., \"" + getMessage() + "\")" }
/**
* Gets the expression which this static assertion ensures is true.

View File

@@ -85,7 +85,7 @@ class Enum extends UserType, IntegralOrEnumType {
* ```
*/
class LocalEnum extends Enum {
LocalEnum() { this.isLocal() }
LocalEnum() { isLocal() }
override string getAPrimaryQlClass() { result = "LocalEnum" }
}

View File

@@ -38,7 +38,7 @@ class Container extends Locatable, @container {
* DEPRECATED: Use `getLocation` instead.
* Gets a URL representing the location of this container.
*
* For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls).
* For more information see [Providing URLs](https://help.semmle.com/QL/learn-ql/ql/locations.html#providing-urls).
*/
deprecated string getURL() { none() } // overridden by subclasses
@@ -52,7 +52,7 @@ class Container extends Locatable, @container {
*/
string getRelativePath() {
exists(string absPath, string pref |
absPath = this.getAbsolutePath() and sourceLocationPrefix(pref)
absPath = getAbsolutePath() and sourceLocationPrefix(pref)
|
absPath = pref and result = ""
or
@@ -79,7 +79,7 @@ class Container extends Locatable, @container {
* </table>
*/
string getBaseName() {
result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1)
result = getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1)
}
/**
@@ -105,9 +105,7 @@ class Container extends Locatable, @container {
* <tr><td>"/tmp/x.tar.gz"</td><td>"gz"</td></tr>
* </table>
*/
string getExtension() {
result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3)
}
string getExtension() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) }
/**
* Gets the stem of this container, that is, the prefix of its base name up to
@@ -126,9 +124,7 @@ class Container extends Locatable, @container {
* <tr><td>"/tmp/x.tar.gz"</td><td>"x.tar"</td></tr>
* </table>
*/
string getStem() {
result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1)
}
string getStem() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) }
/** Gets the parent container of this file or folder, if any. */
Container getParentContainer() {
@@ -139,20 +135,20 @@ class Container extends Locatable, @container {
Container getAChildContainer() { this = result.getParentContainer() }
/** Gets a file in this container. */
File getAFile() { result = this.getAChildContainer() }
File getAFile() { result = getAChildContainer() }
/** Gets the file in this container that has the given `baseName`, if any. */
File getFile(string baseName) {
result = this.getAFile() and
result = getAFile() and
result.getBaseName() = baseName
}
/** Gets a sub-folder in this container. */
Folder getAFolder() { result = this.getAChildContainer() }
Folder getAFolder() { result = getAChildContainer() }
/** Gets the sub-folder in this container that has the given `baseName`, if any. */
Folder getFolder(string baseName) {
result = this.getAFolder() and
result = getAFolder() and
result.getBaseName() = baseName
}
@@ -161,7 +157,7 @@ class Container extends Locatable, @container {
*
* This is the absolute path of the container.
*/
override string toString() { result = this.getAbsolutePath() }
override string toString() { result = getAbsolutePath() }
}
/**

View File

@@ -43,26 +43,26 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
*/
string getFullSignature() {
exists(string name, string templateArgs, string args |
result = name + templateArgs + args + " -> " + this.getType().toString() and
name = this.getQualifiedName() and
result = name + templateArgs + args + " -> " + getType().toString() and
name = getQualifiedName() and
(
if exists(this.getATemplateArgument())
if exists(getATemplateArgument())
then
templateArgs =
"<" +
concat(int i |
exists(this.getTemplateArgument(i))
exists(getTemplateArgument(i))
|
this.getTemplateArgument(i).toString(), ", " order by i
getTemplateArgument(i).toString(), ", " order by i
) + ">"
else templateArgs = ""
) and
args =
"(" +
concat(int i |
exists(this.getParameter(i))
exists(getParameter(i))
|
this.getParameter(i).getType().toString(), ", " order by i
getParameter(i).getType().toString(), ", " order by i
) + ")"
)
}
@@ -70,7 +70,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
/** Gets a specifier of this function. */
override Specifier getASpecifier() {
funspecifiers(underlyingElement(this), unresolveElement(result)) or
result.hasName(this.getADeclarationEntry().getASpecifier())
result.hasName(getADeclarationEntry().getASpecifier())
}
/** Gets an attribute of this function. */
@@ -149,7 +149,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
* Holds if this function is declared with `__attribute__((naked))` or
* `__declspec(naked)`.
*/
predicate isNaked() { this.getAnAttribute().hasName("naked") }
predicate isNaked() { getAnAttribute().hasName("naked") }
/**
* Holds if this function has a trailing return type.
@@ -172,7 +172,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
* Gets the return type of this function after specifiers have been deeply
* stripped and typedefs have been resolved.
*/
Type getUnspecifiedType() { result = this.getType().getUnspecifiedType() }
Type getUnspecifiedType() { result = getType().getUnspecifiedType() }
/**
* Gets the nth parameter of this function. There is no result for the
@@ -206,7 +206,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
int getEffectiveNumberOfParameters() {
// This method is overridden in `MemberFunction`, where the result is
// adjusted to account for the implicit `this` parameter.
result = this.getNumberOfParameters()
result = getNumberOfParameters()
}
/**
@@ -216,7 +216,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
* return `int p1, int p2`.
*/
string getParameterString() {
result = concat(int i | | min(this.getParameter(i).getTypedName()), ", " order by i)
result = concat(int i | | min(getParameter(i).getTypedName()), ", " order by i)
}
/** Gets a call to this function. */
@@ -229,7 +229,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
*/
override FunctionDeclarationEntry getADeclarationEntry() {
if fun_decls(_, underlyingElement(this), _, _, _)
then this.declEntry(result)
then declEntry(result)
else
exists(Function f |
this.isConstructedFrom(f) and
@@ -250,7 +250,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
* Gets the location of a `FunctionDeclarationEntry` corresponding to this
* declaration.
*/
override Location getADeclarationLocation() { result = this.getADeclarationEntry().getLocation() }
override Location getADeclarationLocation() { result = getADeclarationEntry().getLocation() }
/** Holds if this Function is a Template specialization. */
predicate isSpecialization() {
@@ -265,14 +265,14 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
* definition, if any.
*/
override FunctionDeclarationEntry getDefinition() {
result = this.getADeclarationEntry() and
result = getADeclarationEntry() and
result.isDefinition()
}
/** Gets the location of the definition, if any. */
override Location getDefinitionLocation() {
if exists(this.getDefinition())
then result = this.getDefinition().getLocation()
if exists(getDefinition())
then result = getDefinition().getLocation()
else exists(Function f | this.isConstructedFrom(f) and result = f.getDefinition().getLocation())
}
@@ -281,7 +281,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
* definition, if possible.)
*/
override Location getLocation() {
if exists(this.getDefinition())
if exists(getDefinition())
then result = this.getDefinitionLocation()
else result = this.getADeclarationLocation()
}
@@ -299,7 +299,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
BlockStmt getBlock() { result.getParentScope() = this }
/** Holds if this function has an entry point. */
predicate hasEntryPoint() { exists(this.getEntryPoint()) }
predicate hasEntryPoint() { exists(getEntryPoint()) }
/**
* Gets the first node in this function's control flow graph.
@@ -392,7 +392,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
* Holds if this function has C linkage, as specified by one of its
* declaration entries. For example: `extern "C" void foo();`.
*/
predicate hasCLinkage() { this.getADeclarationEntry().hasCLinkage() }
predicate hasCLinkage() { getADeclarationEntry().hasCLinkage() }
/**
* Holds if this function is constructed from `f` as a result
@@ -409,27 +409,27 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
* several functions that are not linked together have been compiled. An
* example would be a project with many 'main' functions.
*/
predicate isMultiplyDefined() { strictcount(this.getFile()) > 1 }
predicate isMultiplyDefined() { strictcount(getFile()) > 1 }
/** Holds if this function is a varargs function. */
predicate isVarargs() { this.hasSpecifier("varargs") }
predicate isVarargs() { hasSpecifier("varargs") }
/** Gets a type that is specified to be thrown by the function. */
Type getAThrownType() { result = this.getADeclarationEntry().getAThrownType() }
Type getAThrownType() { result = getADeclarationEntry().getAThrownType() }
/**
* Gets the `i`th type specified to be thrown by the function.
*/
Type getThrownType(int i) { result = this.getADeclarationEntry().getThrownType(i) }
Type getThrownType(int i) { result = getADeclarationEntry().getThrownType(i) }
/** Holds if the function has an exception specification. */
predicate hasExceptionSpecification() { this.getADeclarationEntry().hasExceptionSpecification() }
predicate hasExceptionSpecification() { getADeclarationEntry().hasExceptionSpecification() }
/** Holds if this function has a `throw()` exception specification. */
predicate isNoThrow() { this.getADeclarationEntry().isNoThrow() }
predicate isNoThrow() { getADeclarationEntry().isNoThrow() }
/** Holds if this function has a `noexcept` exception specification. */
predicate isNoExcept() { this.getADeclarationEntry().isNoExcept() }
predicate isNoExcept() { getADeclarationEntry().isNoExcept() }
/**
* Gets a function that overloads this one.
@@ -539,7 +539,7 @@ private predicate candGetAnOverloadNonMember(string name, Namespace namespace, F
*/
class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
/** Gets the function which is being declared or defined. */
override Function getDeclaration() { result = this.getFunction() }
override Function getDeclaration() { result = getFunction() }
override string getAPrimaryQlClass() { result = "FunctionDeclarationEntry" }
@@ -586,7 +586,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
* case, catch) plus the number of branching expressions (`?`, `&&`,
* `||`) plus one.
*/
int getCyclomaticComplexity() { result = 1 + cyclomaticComplexityBranches(this.getBlock()) }
int getCyclomaticComplexity() { result = 1 + cyclomaticComplexityBranches(getBlock()) }
/**
* If this is a function definition, get the block containing the
@@ -594,7 +594,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
*/
BlockStmt getBlock() {
this.isDefinition() and
result = this.getFunction().getBlock() and
result = getFunction().getBlock() and
result.getFile() = this.getFile()
}
@@ -604,7 +604,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
*/
pragma[noopt]
int getNumberOfLines() {
exists(BlockStmt b, Location l, int start, int end, int diff | b = this.getBlock() |
exists(BlockStmt b, Location l, int start, int end, int diff | b = getBlock() |
l = b.getLocation() and
start = l.getStartLine() and
end = l.getEndLine() and
@@ -618,7 +618,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
* declaration.
*/
ParameterDeclarationEntry getAParameterDeclarationEntry() {
result = this.getParameterDeclarationEntry(_)
result = getParameterDeclarationEntry(_)
}
/**
@@ -639,8 +639,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
* return 'int p1, int p2'.
*/
string getParameterString() {
result =
concat(int i | | min(this.getParameterDeclarationEntry(i).getTypedName()), ", " order by i)
result = concat(int i | | min(getParameterDeclarationEntry(i).getTypedName()), ", " order by i)
}
/**
@@ -648,10 +647,10 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
*
* `extern "C" void foo();`
*/
predicate hasCLinkage() { this.getASpecifier() = "c_linkage" }
predicate hasCLinkage() { getASpecifier() = "c_linkage" }
/** Holds if this declaration entry has a void parameter list. */
predicate hasVoidParamList() { this.getASpecifier() = "void_param_list" }
predicate hasVoidParamList() { getASpecifier() = "void_param_list" }
/** Holds if this declaration is also a definition of its function. */
override predicate isDefinition() { fun_def(underlyingElement(this)) }
@@ -666,7 +665,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
predicate isImplicit() { fun_implicit(underlyingElement(this)) }
/** Gets a type that is specified to be thrown by the declared function. */
Type getAThrownType() { result = this.getThrownType(_) }
Type getAThrownType() { result = getThrownType(_) }
/**
* Gets the `i`th type specified to be thrown by the declared function
@@ -691,8 +690,8 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
predicate hasExceptionSpecification() {
fun_decl_throws(underlyingElement(this), _, _) or
fun_decl_noexcept(underlyingElement(this), _) or
this.isNoThrow() or
this.isNoExcept()
isNoThrow() or
isNoExcept()
}
/**
@@ -764,7 +763,7 @@ class Operator extends Function {
*/
class TemplateFunction extends Function {
TemplateFunction() {
is_function_template(underlyingElement(this)) and exists(this.getATemplateArgument())
is_function_template(underlyingElement(this)) and exists(getATemplateArgument())
}
override string getAPrimaryQlClass() { result = "TemplateFunction" }

View File

@@ -23,7 +23,7 @@ class Include extends PreprocessorDirective, @ppd_include {
* Gets the token which occurs after `#include`, for example `"filename"`
* or `<filename>`.
*/
string getIncludeText() { result = this.getHead() }
string getIncludeText() { result = getHead() }
/** Gets the file directly included by this `#include`. */
File getIncludedFile() { includes(underlyingElement(this), unresolveElement(result)) }
@@ -53,7 +53,7 @@ class Include extends PreprocessorDirective, @ppd_include {
* ```
*/
class IncludeNext extends Include, @ppd_include_next {
override string toString() { result = "#include_next " + this.getIncludeText() }
override string toString() { result = "#include_next " + getIncludeText() }
}
/**
@@ -65,5 +65,5 @@ class IncludeNext extends Include, @ppd_include_next {
* ```
*/
class Import extends Include, @ppd_objc_import {
override string toString() { result = "#import " + this.getIncludeText() }
override string toString() { result = "#import " + getIncludeText() }
}

View File

@@ -34,8 +34,8 @@ class Initializer extends ControlFlowNode, @initialiser {
override predicate fromSource() { not this.getLocation() instanceof UnknownLocation }
override string toString() {
if exists(this.getDeclaration())
then result = "initializer for " + max(this.getDeclaration().getName())
if exists(getDeclaration())
then result = "initializer for " + max(getDeclaration().getName())
else result = "initializer"
}

View File

@@ -61,7 +61,7 @@ class Location extends @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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -79,8 +79,8 @@ class Location extends @location {
/** Holds if location `l` is completely contained within this one. */
predicate subsumes(Location l) {
exists(File f | f = this.getFile() |
exists(int thisStart, int thisEnd | this.charLoc(f, thisStart, thisEnd) |
exists(File f | f = getFile() |
exists(int thisStart, int thisEnd | charLoc(f, thisStart, thisEnd) |
exists(int lStart, int lEnd | l.charLoc(f, lStart, lEnd) |
thisStart <= lStart and lEnd <= thisEnd
)
@@ -97,10 +97,10 @@ class Location extends @location {
* see `subsumes`.
*/
predicate charLoc(File f, int start, int end) {
f = this.getFile() and
f = getFile() and
exists(int maxCols | maxCols = maxCols(f) |
start = this.getStartLine() * maxCols + this.getStartColumn() and
end = this.getEndLine() * maxCols + this.getEndColumn()
start = getStartLine() * maxCols + getStartColumn() and
end = getEndLine() * maxCols + getEndColumn()
)
}
}
@@ -144,7 +144,7 @@ class Locatable extends Element { }
* expressions, one for statements and one for other program elements.
*/
class UnknownLocation extends Location {
UnknownLocation() { this.getFile().getAbsolutePath() = "" }
UnknownLocation() { getFile().getAbsolutePath() = "" }
}
/**

View File

@@ -44,10 +44,10 @@ class Macro extends PreprocessorDirective, @ppd_define {
* Gets the name of the macro. For example, `MAX` in
* `#define MAX(x,y) (((x)>(y))?(x):(y))`.
*/
string getName() { result = this.getHead().splitAt("(", 0) }
string getName() { result = getHead().splitAt("(", 0) }
/** Holds if the macro has name `name`. */
predicate hasName(string name) { this.getName() = name }
predicate hasName(string name) { getName() = name }
}
/**
@@ -130,7 +130,7 @@ class MacroAccess extends Locatable, @macroinvocation {
override string toString() { result = this.getMacro().getHead() }
/** Gets the name of the accessed macro. */
string getMacroName() { result = this.getMacro().getName() }
string getMacroName() { result = getMacro().getName() }
}
/**
@@ -197,8 +197,8 @@ class MacroInvocation extends MacroAccess {
* expression. In other cases, it may have multiple results or no results.
*/
Expr getExpr() {
result = this.getAnExpandedElement() and
not result.getParent() = this.getAnExpandedElement() and
result = getAnExpandedElement() and
not result.getParent() = getAnExpandedElement() and
not result instanceof Conversion
}
@@ -208,8 +208,8 @@ class MacroInvocation extends MacroAccess {
* element is not a statement (for example if it is an expression).
*/
Stmt getStmt() {
result = this.getAnExpandedElement() and
not result.getParent() = this.getAnExpandedElement()
result = getAnExpandedElement() and
not result.getParent() = getAnExpandedElement()
}
/**
@@ -278,7 +278,7 @@ deprecated class MacroInvocationExpr extends Expr {
MacroInvocation getInvocation() { result.getExpr() = this }
/** Gets the name of the invoked macro. */
string getMacroName() { result = this.getInvocation().getMacroName() }
string getMacroName() { result = getInvocation().getMacroName() }
}
/**
@@ -298,7 +298,7 @@ deprecated class MacroInvocationStmt extends Stmt {
MacroInvocation getInvocation() { result.getStmt() = this }
/** Gets the name of the invoked macro. */
string getMacroName() { result = this.getInvocation().getMacroName() }
string getMacroName() { result = getInvocation().getMacroName() }
}
/** Holds if `l` is the location of a macro. */

View File

@@ -36,9 +36,7 @@ class MemberFunction extends Function {
* `this` parameter.
*/
override int getEffectiveNumberOfParameters() {
if this.isStatic()
then result = this.getNumberOfParameters()
else result = this.getNumberOfParameters() + 1
if isStatic() then result = getNumberOfParameters() else result = getNumberOfParameters() + 1
}
/** Holds if this member is private. */
@@ -51,13 +49,13 @@ class MemberFunction extends Function {
predicate isPublic() { this.hasSpecifier("public") }
/** Holds if this declaration has the lvalue ref-qualifier */
predicate isLValueRefQualified() { this.hasSpecifier("&") }
predicate isLValueRefQualified() { hasSpecifier("&") }
/** Holds if this declaration has the rvalue ref-qualifier */
predicate isRValueRefQualified() { this.hasSpecifier("&&") }
predicate isRValueRefQualified() { hasSpecifier("&&") }
/** Holds if this declaration has a ref-qualifier */
predicate isRefQualified() { this.isLValueRefQualified() or this.isRValueRefQualified() }
predicate isRefQualified() { isLValueRefQualified() or isRValueRefQualified() }
/** Holds if this function overrides that function. */
predicate overrides(MemberFunction that) {
@@ -75,10 +73,10 @@ class MemberFunction extends Function {
* class body.
*/
FunctionDeclarationEntry getClassBodyDeclarationEntry() {
if strictcount(this.getADeclarationEntry()) = 1
then result = this.getDefinition()
if strictcount(getADeclarationEntry()) = 1
then result = getDefinition()
else (
result = this.getADeclarationEntry() and result != this.getDefinition()
result = getADeclarationEntry() and result != getDefinition()
)
}
@@ -200,7 +198,7 @@ class Constructor extends MemberFunction {
* compiler-generated action which initializes a base class or member
* variable.
*/
ConstructorInit getAnInitializer() { result = this.getInitializer(_) }
ConstructorInit getAnInitializer() { result = getInitializer(_) }
/**
* Gets an entry in the constructor's initializer list, or a
@@ -222,8 +220,8 @@ class ImplicitConversionFunction extends MemberFunction {
functions(underlyingElement(this), _, 4)
or
// ConversionConstructor (deprecated)
strictcount(Parameter p | p = this.getAParameter() and not p.hasInitializer()) = 1 and
not this.hasSpecifier("explicit")
strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and
not hasSpecifier("explicit")
}
/** Gets the type this `ImplicitConversionFunction` takes as input. */
@@ -250,8 +248,8 @@ class ImplicitConversionFunction extends MemberFunction {
*/
deprecated class ConversionConstructor extends Constructor, ImplicitConversionFunction {
ConversionConstructor() {
strictcount(Parameter p | p = this.getAParameter() and not p.hasInitializer()) = 1 and
not this.hasSpecifier("explicit")
strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and
not hasSpecifier("explicit")
}
override string getAPrimaryQlClass() {
@@ -303,15 +301,15 @@ class CopyConstructor extends Constructor {
hasCopySignature(this) and
(
// The rest of the parameters all have default values
forall(int i | i > 0 and exists(this.getParameter(i)) | this.getParameter(i).hasInitializer())
forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer())
or
// or this is a template class, in which case the default values have
// not been extracted even if they exist. In that case, we assume that
// there are default values present since that is the most common case
// in real-world code.
this.getDeclaringType() instanceof TemplateClass
getDeclaringType() instanceof TemplateClass
) and
not exists(this.getATemplateArgument())
not exists(getATemplateArgument())
}
override string getAPrimaryQlClass() { result = "CopyConstructor" }
@@ -327,8 +325,8 @@ class CopyConstructor extends Constructor {
// type-checked for each template instantiation; if an argument in an
// instantiation fails to type-check then the corresponding parameter has
// no default argument in the instantiation.
this.getDeclaringType() instanceof TemplateClass and
this.getNumberOfParameters() > 1
getDeclaringType() instanceof TemplateClass and
getNumberOfParameters() > 1
}
}
@@ -360,15 +358,15 @@ class MoveConstructor extends Constructor {
hasMoveSignature(this) and
(
// The rest of the parameters all have default values
forall(int i | i > 0 and exists(this.getParameter(i)) | this.getParameter(i).hasInitializer())
forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer())
or
// or this is a template class, in which case the default values have
// not been extracted even if they exist. In that case, we assume that
// there are default values present since that is the most common case
// in real-world code.
this.getDeclaringType() instanceof TemplateClass
getDeclaringType() instanceof TemplateClass
) and
not exists(this.getATemplateArgument())
not exists(getATemplateArgument())
}
override string getAPrimaryQlClass() { result = "MoveConstructor" }
@@ -384,8 +382,8 @@ class MoveConstructor extends Constructor {
// type-checked for each template instantiation; if an argument in an
// instantiation fails to type-check then the corresponding parameter has
// no default argument in the instantiation.
this.getDeclaringType() instanceof TemplateClass and
this.getNumberOfParameters() > 1
getDeclaringType() instanceof TemplateClass and
getNumberOfParameters() > 1
}
}
@@ -428,7 +426,7 @@ class Destructor extends MemberFunction {
* Gets a compiler-generated action which destructs a base class or member
* variable.
*/
DestructorDestruction getADestruction() { result = this.getDestruction(_) }
DestructorDestruction getADestruction() { result = getDestruction(_) }
/**
* Gets a compiler-generated action which destructs a base class or member
@@ -477,16 +475,16 @@ class ConversionOperator extends MemberFunction, ImplicitConversionFunction {
*/
class CopyAssignmentOperator extends Operator {
CopyAssignmentOperator() {
this.hasName("operator=") and
hasName("operator=") and
(
hasCopySignature(this)
or
// Unlike CopyConstructor, this member allows a non-reference
// parameter.
this.getParameter(0).getUnspecifiedType() = this.getDeclaringType()
getParameter(0).getUnspecifiedType() = getDeclaringType()
) and
not exists(this.getParameter(1)) and
not exists(this.getATemplateArgument())
not exists(getATemplateArgument())
}
override string getAPrimaryQlClass() { result = "CopyAssignmentOperator" }
@@ -509,10 +507,10 @@ class CopyAssignmentOperator extends Operator {
*/
class MoveAssignmentOperator extends Operator {
MoveAssignmentOperator() {
this.hasName("operator=") and
hasName("operator=") and
hasMoveSignature(this) and
not exists(this.getParameter(1)) and
not exists(this.getATemplateArgument())
not exists(getATemplateArgument())
}
override string getAPrimaryQlClass() { result = "MoveAssignmentOperator" }

View File

@@ -38,8 +38,8 @@ class Namespace extends NameQualifyingElement, @namespace {
* unless the namespace has exactly one declaration entry.
*/
override Location getLocation() {
if strictcount(this.getADeclarationEntry()) = 1
then result = this.getADeclarationEntry().getLocation()
if strictcount(getADeclarationEntry()) = 1
then result = getADeclarationEntry().getLocation()
else result instanceof UnknownDefaultLocation
}
@@ -50,7 +50,7 @@ class Namespace extends NameQualifyingElement, @namespace {
predicate hasName(string name) { name = this.getName() }
/** Holds if this namespace is anonymous. */
predicate isAnonymous() { this.hasName("(unnamed namespace)") }
predicate isAnonymous() { hasName("(unnamed namespace)") }
/** Gets the name of the parent namespace, if it exists. */
private string getParentName() {
@@ -60,9 +60,9 @@ class Namespace extends NameQualifyingElement, @namespace {
/** Gets the qualified name of this namespace. For example: `a::b`. */
string getQualifiedName() {
if exists(this.getParentName())
then result = this.getParentNamespace().getQualifiedName() + "::" + this.getName()
else result = this.getName()
if exists(getParentName())
then result = getParentNamespace().getQualifiedName() + "::" + getName()
else result = getName()
}
/** Gets the parent namespace, if any. */
@@ -99,7 +99,7 @@ class Namespace extends NameQualifyingElement, @namespace {
/** Gets a version of the `QualifiedName` that is more suitable for display purposes. */
string getFriendlyName() { result = this.getQualifiedName() }
final override string toString() { result = this.getFriendlyName() }
final override string toString() { result = getFriendlyName() }
/** Gets a declaration of (part of) this namespace. */
NamespaceDeclarationEntry getADeclarationEntry() { result.getNamespace() = this }

View File

@@ -40,12 +40,12 @@ class Parameter extends LocalScopeVariable, @parameter {
*/
override string getName() {
exists(VariableDeclarationEntry vde |
vde = this.getANamedDeclarationEntry() and result = vde.getName()
vde = getANamedDeclarationEntry() and result = vde.getName()
|
vde.isDefinition() or not this.getANamedDeclarationEntry().isDefinition()
vde.isDefinition() or not getANamedDeclarationEntry().isDefinition()
)
or
not exists(this.getANamedDeclarationEntry()) and
not exists(getANamedDeclarationEntry()) and
result = "(unnamed parameter " + this.getIndex().toString() + ")"
}
@@ -58,12 +58,8 @@ class Parameter extends LocalScopeVariable, @parameter {
*/
string getTypedName() {
exists(string typeString, string nameString |
(
if exists(this.getType().getName())
then typeString = this.getType().getName()
else typeString = ""
) and
(if exists(this.getName()) then nameString = this.getName() else nameString = "") and
(if exists(getType().getName()) then typeString = getType().getName() else typeString = "") and
(if exists(getName()) then nameString = getName() else nameString = "") and
(
if typeString != "" and nameString != ""
then result = typeString + " " + nameString
@@ -73,7 +69,7 @@ class Parameter extends LocalScopeVariable, @parameter {
}
private VariableDeclarationEntry getANamedDeclarationEntry() {
result = this.getAnEffectiveDeclarationEntry() and result.getName() != ""
result = getAnEffectiveDeclarationEntry() and result.getName() != ""
}
/**
@@ -86,13 +82,13 @@ class Parameter extends LocalScopeVariable, @parameter {
* own).
*/
private VariableDeclarationEntry getAnEffectiveDeclarationEntry() {
if this.getFunction().isConstructedFrom(_)
if getFunction().isConstructedFrom(_)
then
exists(Function prototypeInstantiation |
prototypeInstantiation.getParameter(this.getIndex()) = result.getVariable() and
this.getFunction().isConstructedFrom(prototypeInstantiation)
prototypeInstantiation.getParameter(getIndex()) = result.getVariable() and
getFunction().isConstructedFrom(prototypeInstantiation)
)
else result = this.getADeclarationEntry()
else result = getADeclarationEntry()
}
/**
@@ -118,7 +114,7 @@ class Parameter extends LocalScopeVariable, @parameter {
* `getName()` is not "(unnamed parameter i)" (where `i` is the index
* of the parameter).
*/
predicate isNamed() { exists(this.getANamedDeclarationEntry()) }
predicate isNamed() { exists(getANamedDeclarationEntry()) }
/**
* Gets the function to which this parameter belongs, if it is a function
@@ -161,9 +157,9 @@ class Parameter extends LocalScopeVariable, @parameter {
*/
override Location getLocation() {
exists(VariableDeclarationEntry vde |
vde = this.getAnEffectiveDeclarationEntry() and result = vde.getLocation()
vde = getAnEffectiveDeclarationEntry() and result = vde.getLocation()
|
vde.isDefinition() or not this.getAnEffectiveDeclarationEntry().isDefinition()
vde.isDefinition() or not getAnEffectiveDeclarationEntry().isDefinition()
)
}
}

View File

@@ -29,8 +29,8 @@ class PreprocessorDirective extends Locatable, @preprocdirect {
PreprocessorBranch getAGuard() {
exists(PreprocessorEndif e, int line |
result.getEndIf() = e and
e.getFile() = this.getFile() and
result.getFile() = this.getFile() and
e.getFile() = getFile() and
result.getFile() = getFile() and
line = this.getLocation().getStartLine() and
result.getLocation().getStartLine() < line and
line < e.getLocation().getEndLine()
@@ -69,9 +69,7 @@ class PreprocessorBranchDirective extends PreprocessorDirective, TPreprocessorBr
* directives in different translation units, then there can be more than
* one result.
*/
PreprocessorEndif getEndIf() {
preprocpair(unresolveElement(this.getIf()), unresolveElement(result))
}
PreprocessorEndif getEndIf() { preprocpair(unresolveElement(getIf()), unresolveElement(result)) }
/**
* Gets the next `#elif`, `#else` or `#endif` matching this branching
@@ -139,7 +137,7 @@ class PreprocessorBranch extends PreprocessorBranchDirective, @ppd_branch {
* which evaluated it, or was not taken by any translation unit which
* evaluated it.
*/
predicate wasPredictable() { not (this.wasTaken() and this.wasNotTaken()) }
predicate wasPredictable() { not (wasTaken() and wasNotTaken()) }
}
/**
@@ -270,7 +268,7 @@ class PreprocessorUndef extends PreprocessorDirective, @ppd_undef {
/**
* Gets the name of the macro that is undefined.
*/
string getName() { result = this.getHead() }
string getName() { result = getHead() }
}
/**

View File

@@ -105,8 +105,8 @@ private class DumpType extends Type {
// for a `SpecifiedType`, insert the qualifiers after
// `getDeclaratorSuffixBeforeQualifiers()`.
result =
this.getTypeSpecifier() + this.getDeclaratorPrefix() +
this.getDeclaratorSuffixBeforeQualifiers() + this.getDeclaratorSuffix()
getTypeSpecifier() + getDeclaratorPrefix() + getDeclaratorSuffixBeforeQualifiers() +
getDeclaratorSuffix()
}
/**
@@ -147,35 +147,29 @@ private class DumpType extends Type {
}
private class BuiltInDumpType extends DumpType, BuiltInType {
override string getTypeSpecifier() { result = this.toString() }
override string getTypeSpecifier() { result = toString() }
}
private class IntegralDumpType extends BuiltInDumpType, IntegralType {
override string getTypeSpecifier() { result = this.getCanonicalArithmeticType().toString() }
override string getTypeSpecifier() { result = getCanonicalArithmeticType().toString() }
}
private class DerivedDumpType extends DumpType, DerivedType {
override string getTypeSpecifier() { result = this.getBaseType().(DumpType).getTypeSpecifier() }
override string getTypeSpecifier() { result = getBaseType().(DumpType).getTypeSpecifier() }
override string getDeclaratorSuffixBeforeQualifiers() {
result = this.getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers()
result = getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers()
}
override string getDeclaratorSuffix() {
result = this.getBaseType().(DumpType).getDeclaratorSuffix()
}
override string getDeclaratorSuffix() { result = getBaseType().(DumpType).getDeclaratorSuffix() }
}
private class DecltypeDumpType extends DumpType, Decltype {
override string getTypeSpecifier() { result = this.getBaseType().(DumpType).getTypeSpecifier() }
override string getTypeSpecifier() { result = getBaseType().(DumpType).getTypeSpecifier() }
override string getDeclaratorPrefix() {
result = this.getBaseType().(DumpType).getDeclaratorPrefix()
}
override string getDeclaratorPrefix() { result = getBaseType().(DumpType).getDeclaratorPrefix() }
override string getDeclaratorSuffix() {
result = this.getBaseType().(DumpType).getDeclaratorSuffix()
}
override string getDeclaratorSuffix() { result = getBaseType().(DumpType).getDeclaratorSuffix() }
}
private class PointerIshDumpType extends DerivedDumpType {
@@ -186,10 +180,10 @@ private class PointerIshDumpType extends DerivedDumpType {
override string getDeclaratorPrefix() {
exists(string declarator |
result = this.getBaseType().(DumpType).getDeclaratorPrefix() + declarator and
if this.getBaseType().getUnspecifiedType() instanceof ArrayType
then declarator = "(" + this.getDeclaratorToken() + ")"
else declarator = this.getDeclaratorToken()
result = getBaseType().(DumpType).getDeclaratorPrefix() + declarator and
if getBaseType().getUnspecifiedType() instanceof ArrayType
then declarator = "(" + getDeclaratorToken() + ")"
else declarator = getDeclaratorToken()
)
}
@@ -212,13 +206,13 @@ private class RValueReferenceDumpType extends PointerIshDumpType, RValueReferenc
}
private class PointerToMemberDumpType extends DumpType, PointerToMemberType {
override string getTypeSpecifier() { result = this.getBaseType().(DumpType).getTypeSpecifier() }
override string getTypeSpecifier() { result = getBaseType().(DumpType).getTypeSpecifier() }
override string getDeclaratorPrefix() {
exists(string declarator, string parenDeclarator, Type baseType |
declarator = this.getClass().(DumpType).getTypeIdentityString() + "::*" and
result = this.getBaseType().(DumpType).getDeclaratorPrefix() + " " + parenDeclarator and
baseType = this.getBaseType().getUnspecifiedType() and
declarator = getClass().(DumpType).getTypeIdentityString() + "::*" and
result = getBaseType().(DumpType).getDeclaratorPrefix() + " " + parenDeclarator and
baseType = getBaseType().getUnspecifiedType() and
if baseType instanceof ArrayType or baseType instanceof RoutineType
then parenDeclarator = "(" + declarator
else parenDeclarator = declarator
@@ -227,44 +221,38 @@ private class PointerToMemberDumpType extends DumpType, PointerToMemberType {
override string getDeclaratorSuffixBeforeQualifiers() {
exists(Type baseType |
baseType = this.getBaseType().getUnspecifiedType() and
baseType = getBaseType().getUnspecifiedType() and
if baseType instanceof ArrayType or baseType instanceof RoutineType
then result = ")" + this.getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers()
else result = this.getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers()
then result = ")" + getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers()
else result = getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers()
)
}
override string getDeclaratorSuffix() {
result = this.getBaseType().(DumpType).getDeclaratorSuffix()
}
override string getDeclaratorSuffix() { result = getBaseType().(DumpType).getDeclaratorSuffix() }
}
private class ArrayDumpType extends DerivedDumpType, ArrayType {
override string getDeclaratorPrefix() {
result = this.getBaseType().(DumpType).getDeclaratorPrefix()
}
override string getDeclaratorPrefix() { result = getBaseType().(DumpType).getDeclaratorPrefix() }
override string getDeclaratorSuffixBeforeQualifiers() {
if exists(this.getArraySize())
if exists(getArraySize())
then
result =
"[" + this.getArraySize().toString() + "]" +
this.getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers()
else result = "[]" + this.getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers()
"[" + getArraySize().toString() + "]" +
getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers()
else result = "[]" + getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers()
}
}
private class FunctionPointerIshDumpType extends DerivedDumpType, FunctionPointerIshType {
override string getDeclaratorSuffixBeforeQualifiers() {
result = ")" + this.getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers()
result = ")" + getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers()
}
override string getDeclaratorSuffix() {
result = this.getBaseType().(DumpType).getDeclaratorSuffix()
}
override string getDeclaratorSuffix() { result = getBaseType().(DumpType).getDeclaratorSuffix() }
override string getDeclaratorPrefix() {
result = this.getBaseType().(DumpType).getDeclaratorPrefix() + "(" + this.getDeclaratorToken()
result = getBaseType().(DumpType).getDeclaratorPrefix() + "(" + getDeclaratorToken()
}
/**
@@ -286,10 +274,10 @@ private class BlockDumpType extends FunctionPointerIshDumpType, BlockType {
}
private class RoutineDumpType extends DumpType, RoutineType {
override string getTypeSpecifier() { result = this.getReturnType().(DumpType).getTypeSpecifier() }
override string getTypeSpecifier() { result = getReturnType().(DumpType).getTypeSpecifier() }
override string getDeclaratorPrefix() {
result = this.getReturnType().(DumpType).getDeclaratorPrefix()
result = getReturnType().(DumpType).getDeclaratorPrefix()
}
language[monotonicAggregates]
@@ -297,41 +285,39 @@ private class RoutineDumpType extends DumpType, RoutineType {
result =
"(" +
concat(int i |
exists(this.getParameterType(i))
exists(getParameterType(i))
|
getParameterTypeString(this.getParameterType(i)), ", " order by i
getParameterTypeString(getParameterType(i)), ", " order by i
) + ")"
}
override string getDeclaratorSuffix() {
result =
this.getReturnType().(DumpType).getDeclaratorSuffixBeforeQualifiers() +
this.getReturnType().(DumpType).getDeclaratorSuffix()
getReturnType().(DumpType).getDeclaratorSuffixBeforeQualifiers() +
getReturnType().(DumpType).getDeclaratorSuffix()
}
}
private class SpecifiedDumpType extends DerivedDumpType, SpecifiedType {
override string getDeclaratorPrefix() {
exists(string basePrefix |
basePrefix = this.getBaseType().(DumpType).getDeclaratorPrefix() and
if this.getBaseType().getUnspecifiedType() instanceof RoutineType
basePrefix = getBaseType().(DumpType).getDeclaratorPrefix() and
if getBaseType().getUnspecifiedType() instanceof RoutineType
then result = basePrefix
else result = basePrefix + " " + this.getSpecifierString()
else result = basePrefix + " " + getSpecifierString()
)
}
override string getDeclaratorSuffixBeforeQualifiers() {
exists(string baseSuffix |
baseSuffix = this.getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers() and
if this.getBaseType().getUnspecifiedType() instanceof RoutineType
then result = baseSuffix + " " + this.getSpecifierString()
baseSuffix = getBaseType().(DumpType).getDeclaratorSuffixBeforeQualifiers() and
if getBaseType().getUnspecifiedType() instanceof RoutineType
then result = baseSuffix + " " + getSpecifierString()
else result = baseSuffix
)
}
override string getDeclaratorSuffix() {
result = this.getBaseType().(DumpType).getDeclaratorSuffix()
}
override string getDeclaratorSuffix() { result = getBaseType().(DumpType).getDeclaratorSuffix() }
}
private class UserDumpType extends DumpType, DumpDeclaration, UserType {
@@ -344,18 +330,18 @@ private class UserDumpType extends DumpType, DumpDeclaration, UserType {
// "lambda [] type at line 12, col. 40"
// Use `min(getSimpleName())` to work around an extractor bug where a lambda can have different names
// from different compilation units.
simpleName = "(" + min(this.getSimpleName()) + ")"
else simpleName = this.getSimpleName()
simpleName = "(" + min(getSimpleName()) + ")"
else simpleName = getSimpleName()
) and
result = getScopePrefix(this) + simpleName + this.getTemplateArgumentsString()
result = getScopePrefix(this) + simpleName + getTemplateArgumentsString()
)
}
override string getTypeSpecifier() { result = this.getIdentityString() }
override string getTypeSpecifier() { result = getIdentityString() }
}
private class DumpProxyClass extends UserDumpType, ProxyClass {
override string getIdentityString() { result = this.getName() }
override string getIdentityString() { result = getName() }
}
private class DumpVariable extends DumpDeclaration, Variable {
@@ -374,9 +360,9 @@ private class DumpVariable extends DumpDeclaration, Variable {
private class DumpFunction extends DumpDeclaration, Function {
override string getIdentityString() {
result =
this.getType().(DumpType).getTypeSpecifier() + this.getType().(DumpType).getDeclaratorPrefix()
+ " " + getScopePrefix(this) + this.getName() + this.getTemplateArgumentsString() +
this.getDeclaratorSuffixBeforeQualifiers() + this.getDeclaratorSuffix()
getType().(DumpType).getTypeSpecifier() + getType().(DumpType).getDeclaratorPrefix() + " " +
getScopePrefix(this) + getName() + getTemplateArgumentsString() +
getDeclaratorSuffixBeforeQualifiers() + getDeclaratorSuffix()
}
language[monotonicAggregates]
@@ -384,29 +370,28 @@ private class DumpFunction extends DumpDeclaration, Function {
result =
"(" +
concat(int i |
exists(this.getParameter(i).getType())
exists(getParameter(i).getType())
|
getParameterTypeString(this.getParameter(i).getType()), ", " order by i
) + ")" + this.getQualifierString()
getParameterTypeString(getParameter(i).getType()), ", " order by i
) + ")" + getQualifierString()
}
private string getQualifierString() {
if exists(this.getACVQualifier())
if exists(getACVQualifier())
then
result =
" " + strictconcat(string qualifier | qualifier = this.getACVQualifier() | qualifier, " ")
result = " " + strictconcat(string qualifier | qualifier = getACVQualifier() | qualifier, " ")
else result = ""
}
private string getACVQualifier() {
result = this.getASpecifier().getName() and
result = getASpecifier().getName() and
result = ["const", "volatile"]
}
private string getDeclaratorSuffix() {
result =
this.getType().(DumpType).getDeclaratorSuffixBeforeQualifiers() +
this.getType().(DumpType).getDeclaratorSuffix()
getType().(DumpType).getDeclaratorSuffixBeforeQualifiers() +
getType().(DumpType).getDeclaratorSuffix()
}
}

View File

@@ -31,7 +31,11 @@ class Specifier extends Element, @specifier {
* A C/C++ function specifier: `inline`, `virtual`, or `explicit`.
*/
class FunctionSpecifier extends Specifier {
FunctionSpecifier() { this.hasName(["inline", "virtual", "explicit"]) }
FunctionSpecifier() {
this.hasName("inline") or
this.hasName("virtual") or
this.hasName("explicit")
}
override string getAPrimaryQlClass() { result = "FunctionSpecifier" }
}
@@ -41,7 +45,13 @@ class FunctionSpecifier extends Specifier {
* or `mutable".
*/
class StorageClassSpecifier extends Specifier {
StorageClassSpecifier() { this.hasName(["auto", "register", "static", "extern", "mutable"]) }
StorageClassSpecifier() {
this.hasName("auto") or
this.hasName("register") or
this.hasName("static") or
this.hasName("extern") or
this.hasName("mutable")
}
override string getAPrimaryQlClass() { result = "StorageClassSpecifier" }
}
@@ -50,7 +60,11 @@ class StorageClassSpecifier extends Specifier {
* A C++ access specifier: `public`, `protected`, or `private`.
*/
class AccessSpecifier extends Specifier {
AccessSpecifier() { this.hasName(["public", "protected", "private"]) }
AccessSpecifier() {
this.hasName("public") or
this.hasName("protected") or
this.hasName("private")
}
/**
* Gets the visibility of a field with access specifier `this` if it is
@@ -126,7 +140,7 @@ class Attribute extends Element, @attribute {
AttributeArgument getArgument(int i) { result.getAttribute() = this and result.getIndex() = i }
/** Gets an argument of the attribute. */
AttributeArgument getAnArgument() { result = this.getArgument(_) }
AttributeArgument getAnArgument() { result = getArgument(_) }
}
/**
@@ -152,7 +166,7 @@ class StdAttribute extends Attribute, @stdattribute {
* Holds if this attribute has the given namespace and name.
*/
predicate hasQualifiedName(string namespace, string name) {
namespace = this.getNamespace() and this.hasName(name)
namespace = getNamespace() and hasName(name)
}
}
@@ -170,7 +184,7 @@ class Declspec extends Attribute, @declspec { }
*/
class MicrosoftAttribute extends Attribute, @msattribute {
AttributeArgument getNamedArgument(string name) {
result = this.getAnArgument() and result.getName() = name
result = getAnArgument() and result.getName() = name
}
}
@@ -198,13 +212,13 @@ class AlignAs extends Attribute, @alignas {
* ```
*/
class FormatAttribute extends GnuAttribute {
FormatAttribute() { this.getName() = "format" }
FormatAttribute() { getName() = "format" }
/**
* Gets the archetype of this format attribute, for example
* `"printf"`.
*/
string getArchetype() { result = this.getArgument(0).getValueText() }
string getArchetype() { result = getArgument(0).getValueText() }
/**
* Gets the index in (1-based) format attribute notation associated
@@ -222,7 +236,7 @@ class FormatAttribute extends GnuAttribute {
* Gets the (0-based) index of the format string,
* according to this attribute.
*/
int getFormatIndex() { result = this.getArgument(1).getValueInt() - this.firstArgumentNumber() }
int getFormatIndex() { result = getArgument(1).getValueInt() - firstArgumentNumber() }
/**
* Gets the (0-based) index of the first format argument (if any),
@@ -230,8 +244,8 @@ class FormatAttribute extends GnuAttribute {
*/
int getFirstFormatArgIndex() {
exists(int val |
val = this.getArgument(2).getValueInt() and
result = val - this.firstArgumentNumber() and
val = getArgument(2).getValueInt() and
result = val - firstArgumentNumber() and
not val = 0 // indicates a `vprintf` style format function with arguments not directly available.
)
}
@@ -263,7 +277,7 @@ class AttributeArgument extends Element, @attribute_arg {
/**
* Gets the value of this argument, if its value is integral.
*/
int getValueInt() { result = this.getValueText().toInt() }
int getValueInt() { result = getValueText().toInt() }
/**
* Gets the value of this argument, if its value is a type.
@@ -290,11 +304,11 @@ class AttributeArgument extends Element, @attribute_arg {
then result = "empty argument"
else
exists(string prefix, string tail |
(if exists(this.getName()) then prefix = this.getName() + "=" else prefix = "") and
(if exists(getName()) then prefix = getName() + "=" else prefix = "") and
(
if exists(@attribute_arg_type self | self = underlyingElement(this))
then tail = this.getValueType().getName()
else tail = this.getValueText()
then tail = getValueType().getName()
else tail = getValueText()
) and
result = prefix + tail
)

View File

@@ -41,7 +41,7 @@ class Struct extends Class {
* ```
*/
class LocalStruct extends Struct {
LocalStruct() { this.isLocal() }
LocalStruct() { isLocal() }
override string getAPrimaryQlClass() { not this instanceof LocalUnion and result = "LocalStruct" }
}

View File

@@ -10,8 +10,8 @@ import semmle.code.cpp.File
*/
private class GoogleTestHeader extends File {
GoogleTestHeader() {
this.getBaseName() = "gtest.h" and
this.getParentContainer().getBaseName() = "gtest"
getBaseName() = "gtest.h" and
getParentContainer().getBaseName() = "gtest"
}
}
@@ -30,8 +30,8 @@ private class GoogleTest extends MacroInvocation {
*/
private class BoostTestFolder extends Folder {
BoostTestFolder() {
this.getBaseName() = "test" and
this.getParentContainer().getBaseName() = "boost"
getBaseName() = "test" and
getParentContainer().getBaseName() = "boost"
}
}
@@ -49,7 +49,7 @@ private class BoostTest extends MacroInvocation {
* The `cppunit` directory.
*/
private class CppUnitFolder extends Folder {
CppUnitFolder() { this.getBaseName() = "cppunit" }
CppUnitFolder() { getBaseName() = "cppunit" }
}
/**
@@ -57,8 +57,8 @@ private class CppUnitFolder extends Folder {
*/
private class CppUnitClass extends Class {
CppUnitClass() {
this.getFile().getParentContainer+() instanceof CppUnitFolder and
this.getNamespace().getParentNamespace*().getName() = "CppUnit"
getFile().getParentContainer+() instanceof CppUnitFolder and
getNamespace().getParentNamespace*().getName() = "CppUnit"
}
}

View File

@@ -81,7 +81,7 @@ class Type extends Locatable, @type {
* Holds if this type refers to type `t` (by default,
* a type always refers to itself).
*/
predicate refersTo(Type t) { this.refersToDirectly*(t) }
predicate refersTo(Type t) { refersToDirectly*(t) }
/**
* Holds if this type refers to type `t` directly.
@@ -1080,11 +1080,11 @@ class DerivedType extends Type, @derivedtype {
override predicate refersToDirectly(Type t) { t = this.getBaseType() }
override predicate involvesReference() { this.getBaseType().involvesReference() }
override predicate involvesReference() { getBaseType().involvesReference() }
override predicate involvesTemplateParameter() { this.getBaseType().involvesTemplateParameter() }
override predicate involvesTemplateParameter() { getBaseType().involvesTemplateParameter() }
override Type stripType() { result = this.getBaseType().stripType() }
override Type stripType() { result = getBaseType().stripType() }
/**
* Holds if this type has the `__autoreleasing` specifier or if it points to
@@ -1165,35 +1165,33 @@ class Decltype extends Type, @decltype {
*/
predicate parenthesesWouldChangeMeaning() { decltypes(underlyingElement(this), _, _, true) }
override Type getUnderlyingType() { result = this.getBaseType().getUnderlyingType() }
override Type getUnderlyingType() { result = getBaseType().getUnderlyingType() }
override Type stripTopLevelSpecifiers() { result = this.getBaseType().stripTopLevelSpecifiers() }
override Type stripTopLevelSpecifiers() { result = getBaseType().stripTopLevelSpecifiers() }
override Type stripType() { result = this.getBaseType().stripType() }
override Type stripType() { result = getBaseType().stripType() }
override Type resolveTypedefs() { result = this.getBaseType().resolveTypedefs() }
override Type resolveTypedefs() { result = getBaseType().resolveTypedefs() }
override Location getLocation() { result = this.getExpr().getLocation() }
override Location getLocation() { result = getExpr().getLocation() }
override string toString() { result = "decltype(...)" }
override string getName() { none() }
override int getSize() { result = this.getBaseType().getSize() }
override int getSize() { result = getBaseType().getSize() }
override int getAlignment() { result = this.getBaseType().getAlignment() }
override int getAlignment() { result = getBaseType().getAlignment() }
override int getPointerIndirectionLevel() {
result = this.getBaseType().getPointerIndirectionLevel()
}
override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() }
override string explain() {
result = "decltype resulting in {" + this.getBaseType().explain() + "}"
}
override predicate involvesReference() { this.getBaseType().involvesReference() }
override predicate involvesReference() { getBaseType().involvesReference() }
override predicate involvesTemplateParameter() { this.getBaseType().involvesTemplateParameter() }
override predicate involvesTemplateParameter() { getBaseType().involvesTemplateParameter() }
override predicate isDeeplyConst() { this.getBaseType().isDeeplyConst() }
@@ -1225,7 +1223,7 @@ class PointerType extends DerivedType {
override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConst() }
override Type resolveTypedefs() {
result.(PointerType).getBaseType() = this.getBaseType().resolveTypedefs()
result.(PointerType).getBaseType() = getBaseType().resolveTypedefs()
}
}
@@ -1242,9 +1240,7 @@ class ReferenceType extends DerivedType {
override string getAPrimaryQlClass() { result = "ReferenceType" }
override int getPointerIndirectionLevel() {
result = this.getBaseType().getPointerIndirectionLevel()
}
override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() }
override string explain() { result = "reference to {" + this.getBaseType().explain() + "}" }
@@ -1255,7 +1251,7 @@ class ReferenceType extends DerivedType {
override predicate involvesReference() { any() }
override Type resolveTypedefs() {
result.(ReferenceType).getBaseType() = this.getBaseType().resolveTypedefs()
result.(ReferenceType).getBaseType() = getBaseType().resolveTypedefs()
}
}
@@ -1334,11 +1330,11 @@ class SpecifiedType extends DerivedType {
}
override Type resolveTypedefs() {
result.(SpecifiedType).getBaseType() = this.getBaseType().resolveTypedefs() and
result.getASpecifier() = this.getASpecifier()
result.(SpecifiedType).getBaseType() = getBaseType().resolveTypedefs() and
result.getASpecifier() = getASpecifier()
}
override Type stripTopLevelSpecifiers() { result = this.getBaseType().stripTopLevelSpecifiers() }
override Type stripTopLevelSpecifiers() { result = getBaseType().stripTopLevelSpecifiers() }
}
/**
@@ -1437,8 +1433,7 @@ class GNUVectorType extends DerivedType {
override int getAlignment() { arraysizes(underlyingElement(this), _, _, result) }
override string explain() {
result =
"GNU " + this.getNumElements() + " element vector of {" + this.getBaseType().explain() + "}"
result = "GNU " + getNumElements() + " element vector of {" + this.getBaseType().explain() + "}"
}
override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConst() }
@@ -1473,9 +1468,7 @@ class FunctionReferenceType extends FunctionPointerIshType {
override string getAPrimaryQlClass() { result = "FunctionReferenceType" }
override int getPointerIndirectionLevel() {
result = this.getBaseType().getPointerIndirectionLevel()
}
override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() }
override string explain() {
result = "reference to {" + this.getBaseType().(RoutineType).explain() + "}"
@@ -1542,8 +1535,8 @@ class FunctionPointerIshType extends DerivedType {
int getNumberOfParameters() { result = count(int i | exists(this.getParameterType(i))) }
override predicate involvesTemplateParameter() {
this.getReturnType().involvesTemplateParameter() or
this.getAParameterType().involvesTemplateParameter()
getReturnType().involvesTemplateParameter() or
getAParameterType().involvesTemplateParameter()
}
override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConst() }
@@ -1588,7 +1581,7 @@ class PointerToMemberType extends Type, @ptrtomember {
this.getBaseType().explain() + "}"
}
override predicate involvesTemplateParameter() { this.getBaseType().involvesTemplateParameter() }
override predicate involvesTemplateParameter() { getBaseType().involvesTemplateParameter() }
override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConst() }
}
@@ -1657,6 +1650,7 @@ class RoutineType extends Type, @routinetype {
i = 0 and result = "" and not exists(this.getAParameterType())
or
(
exists(this.getParameterType(i)) and
if i < max(int j | exists(this.getParameterType(j)))
then
// Not the last one
@@ -1677,8 +1671,8 @@ class RoutineType extends Type, @routinetype {
override predicate isDeeplyConstBelow() { none() } // Current limitation: no such thing as a const routine type
override predicate involvesTemplateParameter() {
this.getReturnType().involvesTemplateParameter() or
this.getAParameterType().involvesTemplateParameter()
getReturnType().involvesTemplateParameter() or
getAParameterType().involvesTemplateParameter()
}
}

View File

@@ -25,7 +25,7 @@ class TypedefType extends UserType {
override Type getUnderlyingType() { result = this.getBaseType().getUnderlyingType() }
override Type stripTopLevelSpecifiers() { result = this.getBaseType().stripTopLevelSpecifiers() }
override Type stripTopLevelSpecifiers() { result = getBaseType().stripTopLevelSpecifiers() }
override int getSize() { result = this.getBaseType().getSize() }
@@ -43,11 +43,11 @@ class TypedefType extends UserType {
result = this.getBaseType().getASpecifier()
}
override predicate involvesReference() { this.getBaseType().involvesReference() }
override predicate involvesReference() { getBaseType().involvesReference() }
override Type resolveTypedefs() { result = this.getBaseType().resolveTypedefs() }
override Type resolveTypedefs() { result = getBaseType().resolveTypedefs() }
override Type stripType() { result = this.getBaseType().stripType() }
override Type stripType() { result = getBaseType().stripType() }
}
/**
@@ -90,7 +90,7 @@ class UsingAliasTypedefType extends TypedefType {
* ```
*/
class LocalTypedefType extends TypedefType {
LocalTypedefType() { this.isLocal() }
LocalTypedefType() { isLocal() }
override string getAPrimaryQlClass() { result = "LocalTypedefType" }
}

View File

@@ -37,7 +37,7 @@ class Union extends Struct {
* ```
*/
class LocalUnion extends Union {
LocalUnion() { this.isLocal() }
LocalUnion() { isLocal() }
override string getAPrimaryQlClass() { result = "LocalUnion" }
}

View File

@@ -30,19 +30,19 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @
* Gets the simple name of this type, without any template parameters. For example
* if the name of the type is `"myType<int>"`, the simple name is just `"myType"`.
*/
string getSimpleName() { result = this.getName().regexpReplaceAll("<.*", "") }
string getSimpleName() { result = getName().regexpReplaceAll("<.*", "") }
override predicate hasName(string name) { usertypes(underlyingElement(this), name, _) }
/** Holds if this type is anonymous. */
predicate isAnonymous() { this.getName().matches("(unnamed%") }
predicate isAnonymous() { getName().matches("(unnamed%") }
override predicate hasSpecifier(string s) { Type.super.hasSpecifier(s) }
override Specifier getASpecifier() { result = Type.super.getASpecifier() }
override Location getLocation() {
if this.hasDefinition()
if hasDefinition()
then result = this.getDefinitionLocation()
else result = this.getADeclarationLocation()
}
@@ -53,16 +53,16 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @
else exists(Class t | this.(Class).isConstructedFrom(t) and result = t.getADeclarationEntry())
}
override Location getADeclarationLocation() { result = this.getADeclarationEntry().getLocation() }
override Location getADeclarationLocation() { result = getADeclarationEntry().getLocation() }
override TypeDeclarationEntry getDefinition() {
result = this.getADeclarationEntry() and
result = getADeclarationEntry() and
result.isDefinition()
}
override Location getDefinitionLocation() {
if exists(this.getDefinition())
then result = this.getDefinition().getLocation()
if exists(getDefinition())
then result = getDefinition().getLocation()
else
exists(Class t |
this.(Class).isConstructedFrom(t) and result = t.getDefinition().getLocation()
@@ -80,7 +80,7 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @
* Holds if this is a local type (that is, a type that has a directly-enclosing
* function).
*/
predicate isLocal() { exists(this.getEnclosingFunction()) }
predicate isLocal() { exists(getEnclosingFunction()) }
/*
* Dummy implementations of inherited methods. This class must not be
@@ -107,9 +107,9 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @
* ```
*/
class TypeDeclarationEntry extends DeclarationEntry, @type_decl {
override UserType getDeclaration() { result = this.getType() }
override UserType getDeclaration() { result = getType() }
override string getName() { result = this.getType().getName() }
override string getName() { result = getType().getName() }
override string getAPrimaryQlClass() { result = "TypeDeclarationEntry" }

View File

@@ -104,17 +104,17 @@ class Variable extends Declaration, @variable {
override VariableDeclarationEntry getADeclarationEntry() { result.getDeclaration() = this }
override Location getADeclarationLocation() { result = this.getADeclarationEntry().getLocation() }
override Location getADeclarationLocation() { result = getADeclarationEntry().getLocation() }
override VariableDeclarationEntry getDefinition() {
result = this.getADeclarationEntry() and
result = getADeclarationEntry() and
result.isDefinition()
}
override Location getDefinitionLocation() { result = this.getDefinition().getLocation() }
override Location getDefinitionLocation() { result = getDefinition().getLocation() }
override Location getLocation() {
if exists(this.getDefinition())
if exists(getDefinition())
then result = this.getDefinitionLocation()
else result = this.getADeclarationLocation()
}
@@ -199,7 +199,7 @@ class Variable extends Declaration, @variable {
* ```
*/
class VariableDeclarationEntry extends DeclarationEntry, @var_decl {
override Variable getDeclaration() { result = this.getVariable() }
override Variable getDeclaration() { result = getVariable() }
override string getAPrimaryQlClass() { result = "VariableDeclarationEntry" }
@@ -276,33 +276,32 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry {
int getIndex() { param_decl_bind(underlyingElement(this), result, _) }
private string getAnonymousParameterDescription() {
not exists(this.getName()) and
not exists(getName()) and
exists(string idx |
idx =
((this.getIndex() + 1).toString() + "th")
((getIndex() + 1).toString() + "th")
.replaceAll("1th", "1st")
.replaceAll("2th", "2nd")
.replaceAll("3th", "3rd")
.replaceAll("11st", "11th")
.replaceAll("12nd", "12th")
.replaceAll("13rd", "13th") and
if exists(this.getCanonicalName())
then
result = "declaration of " + this.getCanonicalName() + " as anonymous " + idx + " parameter"
if exists(getCanonicalName())
then result = "declaration of " + getCanonicalName() + " as anonymous " + idx + " parameter"
else result = "declaration of " + idx + " parameter"
)
}
override string toString() {
this.isDefinition() and
result = "definition of " + this.getName()
isDefinition() and
result = "definition of " + getName()
or
not this.isDefinition() and
if this.getName() = this.getCanonicalName()
then result = "declaration of " + this.getName()
else result = "declaration of " + this.getCanonicalName() + " as " + this.getName()
not isDefinition() and
if getName() = getCanonicalName()
then result = "declaration of " + getName()
else result = "declaration of " + getCanonicalName() + " as " + getName()
or
result = this.getAnonymousParameterDescription()
result = getAnonymousParameterDescription()
}
/**
@@ -312,12 +311,8 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry {
*/
string getTypedName() {
exists(string typeString, string nameString |
(
if exists(this.getType().getName())
then typeString = this.getType().getName()
else typeString = ""
) and
(if exists(this.getName()) then nameString = this.getName() else nameString = "") and
(if exists(getType().getName()) then typeString = getType().getName() else typeString = "") and
(if exists(getName()) then nameString = getName() else nameString = "") and
if typeString != "" and nameString != ""
then result = typeString + " " + nameString
else result = typeString + nameString
@@ -545,7 +540,7 @@ class MemberVariable extends Variable, @membervariable {
}
/** Holds if this member is mutable. */
predicate isMutable() { this.getADeclarationEntry().hasSpecifier("mutable") }
predicate isMutable() { getADeclarationEntry().hasSpecifier("mutable") }
private Type getAType() { membervariables(underlyingElement(this), unresolveElement(result), _) }
}

View File

@@ -24,7 +24,7 @@ class XMLLocatable extends @xmllocatable, TXMLLocatable {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -108,7 +108,7 @@ class XMLParent extends @xmlparent {
}
/** Gets the text value contained in this XML parent. */
string getTextValue() { result = this.allCharactersString() }
string getTextValue() { result = allCharactersString() }
/** Gets a printable representation of this XML parent. */
string toString() { result = this.getName() }
@@ -119,7 +119,7 @@ class XMLFile extends XMLParent, File {
XMLFile() { xmlEncoding(this, _) }
/** Gets a printable representation of this XML file. */
override string toString() { result = this.getName() }
override string toString() { result = getName() }
/** Gets the name of this XML file. */
override string getName() { result = File.super.getAbsolutePath() }
@@ -129,14 +129,14 @@ class XMLFile extends XMLParent, File {
*
* Gets the path of this XML file.
*/
deprecated string getPath() { result = this.getAbsolutePath() }
deprecated string getPath() { result = getAbsolutePath() }
/**
* DEPRECATED: Use `getParentContainer().getAbsolutePath()` instead.
*
* Gets the path of the folder that contains this XML file.
*/
deprecated string getFolder() { result = this.getParentContainer().getAbsolutePath() }
deprecated string getFolder() { result = getParentContainer().getAbsolutePath() }
/** Gets the encoding of this XML file. */
string getEncoding() { xmlEncoding(this, result) }
@@ -200,7 +200,7 @@ class XMLDTD extends XMLLocatable, @xmldtd {
*/
class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
/** Holds if this XML element has the given `name`. */
predicate hasName(string name) { name = this.getName() }
predicate hasName(string name) { name = getName() }
/** Gets the name of this XML element. */
override string getName() { xmlElements(this, result, _, _, _) }
@@ -239,7 +239,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
string getAttributeValue(string name) { result = this.getAttribute(name).getValue() }
/** Gets a printable representation of this XML element. */
override string toString() { result = this.getName() }
override string toString() { result = getName() }
}
/**

View File

@@ -375,8 +375,8 @@ class Wchar_t extends Type {
class MicrosoftInt8Type extends IntegralType {
MicrosoftInt8Type() {
this instanceof CharType and
not this.isExplicitlyUnsigned() and
not this.isExplicitlySigned()
not isExplicitlyUnsigned() and
not isExplicitlySigned()
}
}
@@ -391,8 +391,8 @@ class MicrosoftInt8Type extends IntegralType {
class MicrosoftInt16Type extends IntegralType {
MicrosoftInt16Type() {
this instanceof ShortType and
not this.isExplicitlyUnsigned() and
not this.isExplicitlySigned()
not isExplicitlyUnsigned() and
not isExplicitlySigned()
}
}
@@ -407,8 +407,8 @@ class MicrosoftInt16Type extends IntegralType {
class MicrosoftInt32Type extends IntegralType {
MicrosoftInt32Type() {
this instanceof IntType and
not this.isExplicitlyUnsigned() and
not this.isExplicitlySigned()
not isExplicitlyUnsigned() and
not isExplicitlySigned()
}
}
@@ -423,8 +423,8 @@ class MicrosoftInt32Type extends IntegralType {
class MicrosoftInt64Type extends IntegralType {
MicrosoftInt64Type() {
this instanceof LongLongType and
not this.isExplicitlyUnsigned() and
not this.isExplicitlySigned()
not isExplicitlyUnsigned() and
not isExplicitlySigned()
}
}

View File

@@ -33,7 +33,7 @@ DependencyOptions getDependencyOptions() { any() }
class DependsSource extends Element {
DependsSource() {
// not inside a template instantiation
not exists(Element other | this.isFromTemplateInstantiation(other)) or
not exists(Element other | isFromTemplateInstantiation(other)) or
// allow DeclarationEntrys of template specializations
this.(DeclarationEntry).getDeclaration().(Function).isConstructedFrom(_) or
this.(DeclarationEntry).getDeclaration().(Class).isConstructedFrom(_)
@@ -275,7 +275,7 @@ private predicate dependsOnDeclarationEntry(Element src, DeclarationEntry dest)
dependsOnTransitive(src, mid) and
not mid instanceof Type and
not mid instanceof EnumConstant and
getDeclarationEntries(mid, dest) and
getDeclarationEntries(mid, dest.(DeclarationEntry)) and
not dest instanceof TypeDeclarationEntry
)
or
@@ -283,9 +283,9 @@ private predicate dependsOnDeclarationEntry(Element src, DeclarationEntry dest)
// dependency from a Type / Variable / Function use -> any (visible) definition
dependsOnTransitive(src, mid) and
not mid instanceof EnumConstant and
getDeclarationEntries(mid, dest) and
getDeclarationEntries(mid, dest.(DeclarationEntry)) and
// must be definition
dest.isDefinition()
dest.(DeclarationEntry).isDefinition()
)
}
@@ -307,7 +307,7 @@ private predicate dependsOnFull(DependsSource src, Symbol dest, int category) {
// dependency from a Variable / Function use -> non-visible definition (link time)
dependsOnTransitive(src, mid) and
not mid instanceof EnumConstant and
getDeclarationEntries(mid, dest) and
getDeclarationEntries(mid, dest.(DeclarationEntry)) and
not dest instanceof TypeDeclarationEntry and
// must be definition
dest.(DeclarationEntry).isDefinition() and

View File

@@ -81,8 +81,8 @@ predicate functionContainsPreprocCode(Function f) {
}
/**
* Holds if `e` is completely or partially from a macro invocation `mi`, as
* opposed to being passed in as an argument.
* Holds if `e` is completely or partially from a macro definition, as opposed
* to being passed in as an argument.
*
* In the following example, the call to `f` is from a macro definition,
* while `y`, `+`, `1`, and `;` are not. This assumes that no identifier apart
@@ -93,8 +93,8 @@ predicate functionContainsPreprocCode(Function f) {
* M(y + 1);
* ```
*/
private predicate isFromMacroInvocation(Element e, MacroInvocation mi) {
exists(Location eLocation, Location miLocation |
predicate isFromMacroDefinition(Element e) {
exists(MacroInvocation mi, Location eLocation, Location miLocation |
mi.getAnExpandedElement() = e and
eLocation = e.getLocation() and
miLocation = mi.getLocation() and
@@ -109,36 +109,3 @@ private predicate isFromMacroInvocation(Element e, MacroInvocation mi) {
eLocation.getEndColumn() >= miLocation.getEndColumn()
)
}
/**
* Holds if `e` is completely or partially from a macro definition, as opposed
* to being passed in as an argument.
*
* In the following example, the call to `f` is from a macro definition,
* while `y`, `+`, `1`, and `;` are not. This assumes that no identifier apart
* from `M` refers to a macro.
* ```
* #define M(x) f(x)
* ...
* M(y + 1);
* ```
*/
predicate isFromMacroDefinition(Element e) { isFromMacroInvocation(e, _) }
/**
* Holds if `e` is completely or partially from a _system macro_ definition, as
* opposed to being passed in as an argument. A system macro is a macro whose
* definition is outside the source directory of the database.
*
* If the system macro is invoked through a non-system macro, then this
* predicate does not hold.
*
* See also `isFromMacroDefinition`.
*/
predicate isFromSystemMacroDefinition(Element e) {
exists(MacroInvocation mi |
isFromMacroInvocation(e, mi) and
// Has no relative path in the database, meaning it's a system file.
not exists(mi.getMacro().getFile().getRelativePath())
)
}

View File

@@ -1,35 +1,18 @@
import cpp
private import semmle.code.cpp.models.interfaces.ArrayFunction
private import semmle.code.cpp.models.implementations.Strcat
import semmle.code.cpp.dataflow.DataFlow
/**
* Holds if the expression `e` assigns something including `va` to a
* stack variable `v0`.
*/
private predicate mayAddNullTerminatorHelper(Expr e, VariableAccess va, StackVariable v0) {
exists(Expr val |
exprDefinition(v0, e, val) and // `e` is `v0 := val`
val.getAChild*() = va
)
}
bindingset[n1, n2]
private predicate controlFlowNodeSuccessorTransitive(ControlFlowNode n1, ControlFlowNode n2) {
exists(BasicBlock bb1, int pos1, BasicBlock bb2, int pos2 |
pragma[only_bind_into](bb1).getNode(pos1) = n1 and
pragma[only_bind_into](bb2).getNode(pos2) = n2 and
(
bb1 = bb2 and pos1 < pos2
or
bb1.getASuccessor+() = bb2
)
private predicate mayAddNullTerminatorHelper(Expr e, VariableAccess va, Expr e0) {
exists(StackVariable v0, Expr val |
exprDefinition(v0, e, val) and
val.getAChild*() = va and
mayAddNullTerminator(e0, v0.getAnAccess())
)
}
/**
* Holds if the expression `e` may add a null terminator to the string
* accessed by `va`.
* Holds if the expression `e` may add a null terminator to the string in
* variable `v`.
*/
predicate mayAddNullTerminator(Expr e, VariableAccess va) {
// Assignment: dereferencing or array access
@@ -46,10 +29,14 @@ predicate mayAddNullTerminator(Expr e, VariableAccess va) {
)
or
// Assignment to another stack variable
exists(StackVariable v0, Expr e0 |
mayAddNullTerminatorHelper(e, va, v0) and
mayAddNullTerminator(pragma[only_bind_into](e0), pragma[only_bind_into](v0.getAnAccess())) and
controlFlowNodeSuccessorTransitive(e, e0)
exists(Expr e0, BasicBlock bb, int pos, BasicBlock bb0, int pos0 |
mayAddNullTerminatorHelper(e, va, e0) and
bb.getNode(pos) = e and
bb0.getNode(pos0) = e0
|
bb = bb0 and pos < pos0
or
bb.getASuccessor+() = bb0
)
or
// Assignment to non-stack variable
@@ -58,28 +45,22 @@ predicate mayAddNullTerminator(Expr e, VariableAccess va) {
ae.getRValue().getAChild*() = va
)
or
// Function calls...
// Function call: library function, varargs function, function
// containing assembler code, or function where the relevant
// parameter is potentially added a null terminator.
exists(Call c, Function f, int i |
e = c and
f = c.getTarget() and
not functionArgumentMustBeNullTerminated(f, i) and
c.getAnArgumentSubExpr(i) = va
|
// library function
not f.hasEntryPoint()
not f.hasEntryPoint() and not functionArgumentMustBeNullTerminated(f, i)
or
// function where the relevant parameter is potentially added a null terminator
mayAddNullTerminator(_, f.getParameter(i).getAnAccess())
or
// varargs function
f.isVarargs() and i >= f.getNumberOfParameters()
or
// function containing assembler code
exists(AsmStmt s | s.getEnclosingFunction() = f)
or
// function where the relevant parameter is returned (leaking it to be potentially null terminated elsewhere)
DataFlow::localFlow(DataFlow::parameterNode(f.getParameter(i)),
DataFlow::exprNode(any(ReturnStmt rs).getExpr()))
)
or
// Call without target (e.g., function pointer call)
@@ -131,9 +112,14 @@ predicate variableMustBeNullTerminated(VariableAccess va) {
variableMustBeNullTerminated(use) and
// Simplified: check that `p` may not be null terminated on *any*
// path to `use` (including the one found via `parameterUsePair`)
not exists(Expr e |
mayAddNullTerminator(pragma[only_bind_into](e), p.getAnAccess()) and
controlFlowNodeSuccessorTransitive(e, use)
not exists(Expr e, BasicBlock bb1, int pos1, BasicBlock bb2, int pos2 |
mayAddNullTerminator(e, p.getAnAccess()) and
bb1.getNode(pos1) = e and
bb2.getNode(pos2) = use
|
bb1 = bb2 and pos1 < pos2
or
bb1.getASuccessor+() = bb2
)
)
)

View File

@@ -6,11 +6,9 @@ import semmle.code.cpp.Type
import semmle.code.cpp.commons.CommonType
import semmle.code.cpp.commons.StringAnalysis
import semmle.code.cpp.models.interfaces.FormattingFunction
private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
class PrintfFormatAttribute extends FormatAttribute {
PrintfFormatAttribute() { this.getArchetype() = ["printf", "__printf__"] }
PrintfFormatAttribute() { getArchetype() = ["printf", "__printf__"] }
}
/**
@@ -22,13 +20,13 @@ class AttributeFormattingFunction extends FormattingFunction {
AttributeFormattingFunction() {
exists(PrintfFormatAttribute printf_attrib |
printf_attrib = this.getAnAttribute() and
printf_attrib = getAnAttribute() and
exists(printf_attrib.getFirstFormatArgIndex()) // exclude `vprintf` style format functions
)
}
override int getFormatParameterIndex() {
forex(PrintfFormatAttribute printf_attrib | printf_attrib = this.getAnAttribute() |
forex(PrintfFormatAttribute printf_attrib | printf_attrib = getAnAttribute() |
result = printf_attrib.getFormatIndex()
)
}
@@ -134,7 +132,7 @@ deprecated predicate variadicFormatter(Function f, int formatParamIndex) {
class UserDefinedFormattingFunction extends FormattingFunction {
override string getAPrimaryQlClass() { result = "UserDefinedFormattingFunction" }
UserDefinedFormattingFunction() { this.isVarargs() and callsVariadicFormatter(this, _, _, _) }
UserDefinedFormattingFunction() { isVarargs() and callsVariadicFormatter(this, _, _, _) }
override int getFormatParameterIndex() { callsVariadicFormatter(this, _, result, _) }
@@ -177,7 +175,9 @@ class FormattingFunctionCall extends Expr {
/**
* Gets the index at which the format string occurs in the argument list.
*/
int getFormatParameterIndex() { result = this.getTarget().getFormatParameterIndex() }
int getFormatParameterIndex() {
result = this.getTarget().(FormattingFunction).getFormatParameterIndex()
}
/**
* Gets the format expression used in this call.
@@ -191,7 +191,7 @@ class FormattingFunctionCall extends Expr {
exists(int i |
result = this.getArgument(i) and
n >= 0 and
n = i - this.getTarget().getFirstFormatArgumentIndex()
n = i - getTarget().(FormattingFunction).getFirstFormatArgumentIndex()
)
}
@@ -251,35 +251,8 @@ class FormattingFunctionCall extends Expr {
int getNumFormatArgument() {
result = count(this.getFormatArgument(_)) and
// format arguments must be known
exists(this.getTarget().getFirstFormatArgumentIndex())
exists(getTarget().(FormattingFunction).getFirstFormatArgumentIndex())
}
/**
* Gets the argument, if any, to which the output is written. If `isStream` is
* `true`, the output argument is a stream (that is, this call behaves like
* `fprintf`). If `isStream` is `false`, the output argument is a buffer (that
* is, this call behaves like `sprintf`)
*/
Expr getOutputArgument(boolean isStream) {
result =
this.(Call)
.getArgument(this.(Call)
.getTarget()
.(FormattingFunction)
.getOutputParameterIndex(isStream))
}
}
/**
* Gets the number of digits required to represent the integer represented by `f`.
*
* `f` is assumed to be nonnegative.
*/
bindingset[f]
private int lengthInBase10(float f) {
f = 0 and result = 1
or
result = f.log10().floor() + 1
}
/**
@@ -301,27 +274,33 @@ class FormatLiteral extends Literal {
* a `char *` (either way, `%S` will have the opposite meaning).
* DEPRECATED: Use getDefaultCharType() instead.
*/
deprecated predicate isWideCharDefault() { this.getUse().getTarget().isWideCharDefault() }
deprecated predicate isWideCharDefault() {
getUse().getTarget().(FormattingFunction).isWideCharDefault()
}
/**
* Gets the default character type expected for `%s` by this format literal. Typically
* `char` or `wchar_t`.
*/
Type getDefaultCharType() { result = this.getUse().getTarget().getDefaultCharType() }
Type getDefaultCharType() {
result = getUse().getTarget().(FormattingFunction).getDefaultCharType()
}
/**
* Gets the non-default character type expected for `%S` by this format literal. Typically
* `wchar_t` or `char`. On some snapshots there may be multiple results where we can't tell
* which is correct for a particular function.
*/
Type getNonDefaultCharType() { result = this.getUse().getTarget().getNonDefaultCharType() }
Type getNonDefaultCharType() {
result = getUse().getTarget().(FormattingFunction).getNonDefaultCharType()
}
/**
* Gets the wide character type for this format literal. This is usually `wchar_t`. On some
* snapshots there may be multiple results where we can't tell which is correct for a
* particular function.
*/
Type getWideCharType() { result = this.getUse().getTarget().getWideCharType() }
Type getWideCharType() { result = getUse().getTarget().(FormattingFunction).getWideCharType() }
/**
* Holds if this `FormatLiteral` is in a context that supports
@@ -359,7 +338,7 @@ class FormatLiteral extends Literal {
}
private string getFlagRegexp() {
if this.isMicrosoft() then result = "[-+ #0']*" else result = "[-+ #0'I]*"
if isMicrosoft() then result = "[-+ #0']*" else result = "[-+ #0'I]*"
}
private string getFieldWidthRegexp() { result = "(?:[1-9][0-9]*|\\*|\\*[0-9]+\\$)?" }
@@ -367,13 +346,13 @@ class FormatLiteral extends Literal {
private string getPrecRegexp() { result = "(?:\\.(?:[0-9]*|\\*|\\*[0-9]+\\$))?" }
private string getLengthRegexp() {
if this.isMicrosoft()
if isMicrosoft()
then result = "(?:hh?|ll?|L|q|j|z|t|w|I32|I64|I)?"
else result = "(?:hh?|ll?|L|q|j|z|Z|t)?"
}
private string getConvCharRegexp() {
if this.isMicrosoft()
if isMicrosoft()
then result = "[aAcCdeEfFgGimnopsSuxXZ@]"
else result = "[aAcCdeEfFgGimnopsSuxX@]"
}
@@ -753,16 +732,16 @@ class FormatLiteral extends Literal {
* Gets the argument type required by the nth conversion specifier.
*/
Type getConversionType(int n) {
result = this.getConversionType1(n) or
result = this.getConversionType1b(n) or
result = this.getConversionType2(n) or
result = this.getConversionType3(n) or
result = this.getConversionType4(n) or
result = this.getConversionType6(n) or
result = this.getConversionType7(n) or
result = this.getConversionType8(n) or
result = this.getConversionType9(n) or
result = this.getConversionType10(n)
result = getConversionType1(n) or
result = getConversionType1b(n) or
result = getConversionType2(n) or
result = getConversionType3(n) or
result = getConversionType4(n) or
result = getConversionType6(n) or
result = getConversionType7(n) or
result = getConversionType8(n) or
result = getConversionType9(n) or
result = getConversionType10(n)
}
private Type getConversionType1(int n) {
@@ -792,15 +771,15 @@ class FormatLiteral extends Literal {
or
conv = ["c", "C"] and
len = ["l", "w"] and
result = this.getWideCharType()
result = getWideCharType()
or
conv = "c" and
(len != "l" and len != "w" and len != "h") and
result = this.getDefaultCharType()
result = getDefaultCharType()
or
conv = "C" and
(len != "l" and len != "w" and len != "h") and
result = this.getNonDefaultCharType()
result = getNonDefaultCharType()
)
)
}
@@ -837,15 +816,15 @@ class FormatLiteral extends Literal {
or
conv = ["s", "S"] and
len = ["l", "w"] and
result.(PointerType).getBaseType() = this.getWideCharType()
result.(PointerType).getBaseType() = getWideCharType()
or
conv = "s" and
(len != "l" and len != "w" and len != "h") and
result.(PointerType).getBaseType() = this.getDefaultCharType()
result.(PointerType).getBaseType() = getDefaultCharType()
or
conv = "S" and
(len != "l" and len != "w" and len != "h") and
result.(PointerType).getBaseType() = this.getNonDefaultCharType()
result.(PointerType).getBaseType() = getNonDefaultCharType()
)
)
}
@@ -900,19 +879,19 @@ class FormatLiteral extends Literal {
exists(string len, string conv |
this.parseConvSpec(n, _, _, _, _, _, len, conv) and
(len != "l" and len != "w" and len != "h") and
this.getUse().getTarget().getFormatCharType().getSize() > 1 and // wide function
getUse().getTarget().(FormattingFunction).getFormatCharType().getSize() > 1 and // wide function
(
conv = "c" and
result = this.getNonDefaultCharType()
result = getNonDefaultCharType()
or
conv = "C" and
result = this.getDefaultCharType()
result = getDefaultCharType()
or
conv = "s" and
result.(PointerType).getBaseType() = this.getNonDefaultCharType()
result.(PointerType).getBaseType() = getNonDefaultCharType()
or
conv = "S" and
result.(PointerType).getBaseType() = this.getDefaultCharType()
result.(PointerType).getBaseType() = getDefaultCharType()
)
)
}
@@ -945,13 +924,9 @@ class FormatLiteral extends Literal {
* not account for positional arguments (`$`).
*/
int getFormatArgumentIndexFor(int n, int mode) {
this.hasFormatArgumentIndexFor(n, mode) and
hasFormatArgumentIndexFor(n, mode) and
(3 * n) + mode =
rank[result + 1](int n2, int mode2 |
this.hasFormatArgumentIndexFor(n2, mode2)
|
(3 * n2) + mode2
)
rank[result + 1](int n2, int mode2 | hasFormatArgumentIndexFor(n2, mode2) | (3 * n2) + mode2)
}
/**
@@ -961,7 +936,7 @@ class FormatLiteral extends Literal {
int getNumArgNeeded(int n) {
exists(this.getConvSpecOffset(n)) and
exists(this.getConversionChar(n)) and
result = count(int mode | this.hasFormatArgumentIndexFor(n, mode))
result = count(int mode | hasFormatArgumentIndexFor(n, mode))
}
/**
@@ -973,7 +948,7 @@ class FormatLiteral extends Literal {
// At least one conversion specifier has a parameter field, in which case,
// they all should have.
result = max(string s | this.getParameterField(_) = s + "$" | s.toInt())
else result = count(int n, int mode | this.hasFormatArgumentIndexFor(n, mode))
else result = count(int n, int mode | hasFormatArgumentIndexFor(n, mode))
}
/**
@@ -1060,89 +1035,65 @@ class FormatLiteral extends Literal {
or
this.getConversionChar(n).toLowerCase() = ["d", "i"] and
// e.g. -2^31 = "-2147483648"
len =
min(float cand |
// The first case handles length sub-specifiers
// Subtract one in the exponent because one bit is for the sign.
// Add 1 to account for the possible sign in the output.
cand = 1 + lengthInBase10(2.pow(this.getIntegralDisplayType(n).getSize() * 8 - 1))
or
// The second case uses range analysis to deduce a length that's shorter than the length
// of the number -2^31.
exists(Expr arg, float lower, float upper |
arg = this.getUse().getConversionArgument(n) and
lower = lowerBound(arg.getFullyConverted()) and
upper = upperBound(arg.getFullyConverted())
|
cand =
max(int cand0 |
// Include the sign bit in the length if it can be negative
(
if lower < 0
then cand0 = 1 + lengthInBase10(lower.abs())
else cand0 = lengthInBase10(lower)
)
or
(
if upper < 0
then cand0 = 1 + lengthInBase10(upper.abs())
else cand0 = lengthInBase10(upper)
)
)
)
)
exists(int sizeBits |
sizeBits =
min(int bits |
bits = getIntegralDisplayType(n).getSize() * 8
or
exists(IntegralType t |
t = getUse().getConversionArgument(n).getType().getUnderlyingType()
|
t.isSigned() and bits = t.getSize() * 8
)
) and
len = 1 + ((sizeBits - 1) / 10.0.log2()).ceil()
// this calculation is as %u (below) only we take out the sign bit (- 1) and allow a whole
// character for it to be expressed as '-'.
)
or
this.getConversionChar(n).toLowerCase() = "u" and
// e.g. 2^32 - 1 = "4294967295"
len =
min(float cand |
// The first case handles length sub-specifiers
cand = 2.pow(this.getIntegralDisplayType(n).getSize() * 8)
or
// The second case uses range analysis to deduce a length that's shorter than
// the length of the number 2^31 - 1.
exists(Expr arg, float lower |
arg = this.getUse().getConversionArgument(n) and
lower = lowerBound(arg.getFullyConverted())
|
cand =
max(float cand0 |
// If lower can be negative we use `(unsigned)-1` as the candidate value.
lower < 0 and
cand0 = 2.pow(any(IntType t | t.isUnsigned()).getSize() * 8)
or
cand0 = upperBound(arg.getFullyConverted())
)
)
|
lengthInBase10(cand)
)
exists(int sizeBits |
sizeBits =
min(int bits |
bits = getIntegralDisplayType(n).getSize() * 8
or
exists(IntegralType t |
t = getUse().getConversionArgument(n).getType().getUnderlyingType()
|
t.isUnsigned() and bits = t.getSize() * 8
)
) and
len = (sizeBits / 10.0.log2()).ceil()
// convert the size from bits to decimal characters, and round up as you can't have
// fractional characters (10.0.log2() is the number of bits expressed per decimal character)
)
or
this.getConversionChar(n).toLowerCase() = "x" and
// e.g. "12345678"
exists(int sizeBytes, int baseLen |
sizeBytes =
min(int bytes |
bytes = this.getIntegralDisplayType(n).getSize()
bytes = getIntegralDisplayType(n).getSize()
or
exists(IntegralType t |
t = this.getUse().getConversionArgument(n).getType().getUnderlyingType()
t = getUse().getConversionArgument(n).getType().getUnderlyingType()
|
t.isUnsigned() and bytes = t.getSize()
)
) and
baseLen = sizeBytes * 2 and
(
if this.hasAlternateFlag(n) then len = 2 + baseLen else len = baseLen // "0x"
if hasAlternateFlag(n) then len = 2 + baseLen else len = baseLen // "0x"
)
)
or
this.getConversionChar(n).toLowerCase() = "p" and
exists(PointerType ptrType, int baseLen |
ptrType = this.getFullyConverted().getType() and
ptrType = getFullyConverted().getType() and
baseLen = max(ptrType.getSize() * 2) and // e.g. "0x1234567812345678"; exact format is platform dependent
(
if this.hasAlternateFlag(n) then len = 2 + baseLen else len = baseLen // "0x"
if hasAlternateFlag(n) then len = 2 + baseLen else len = baseLen // "0x"
)
)
or
@@ -1151,17 +1102,17 @@ class FormatLiteral extends Literal {
exists(int sizeBits, int baseLen |
sizeBits =
min(int bits |
bits = this.getIntegralDisplayType(n).getSize() * 8
bits = getIntegralDisplayType(n).getSize() * 8
or
exists(IntegralType t |
t = this.getUse().getConversionArgument(n).getType().getUnderlyingType()
t = getUse().getConversionArgument(n).getType().getUnderlyingType()
|
t.isUnsigned() and bits = t.getSize() * 8
)
) and
baseLen = (sizeBits / 3.0).ceil() and
(
if this.hasAlternateFlag(n) then len = 1 + baseLen else len = baseLen // "0"
if hasAlternateFlag(n) then len = 1 + baseLen else len = baseLen // "0"
)
)
or
@@ -1184,8 +1135,8 @@ class FormatLiteral extends Literal {
*/
int getMaxConvertedLengthLimited(int n) {
if this.getConversionChar(n).toLowerCase() = "f"
then result = this.getMaxConvertedLength(n).minimum(8)
else result = this.getMaxConvertedLength(n)
then result = getMaxConvertedLength(n).minimum(8)
else result = getMaxConvertedLength(n)
}
/**

View File

@@ -24,7 +24,7 @@ abstract class ScanfFunction extends Function {
* Holds if the default meaning of `%s` is a `wchar_t*` string
* (rather than a `char*`).
*/
predicate isWideCharDefault() { exists(this.getName().indexOf("wscanf")) }
predicate isWideCharDefault() { exists(getName().indexOf("wscanf")) }
}
/**
@@ -34,10 +34,10 @@ class Scanf extends ScanfFunction {
Scanf() {
this instanceof TopLevelFunction and
(
this.hasGlobalOrStdOrBslName("scanf") or // scanf(format, args...)
this.hasGlobalOrStdOrBslName("wscanf") or // wscanf(format, args...)
this.hasGlobalName("_scanf_l") or // _scanf_l(format, locale, args...)
this.hasGlobalName("_wscanf_l") // _wscanf_l(format, locale, args...)
hasGlobalOrStdOrBslName("scanf") or // scanf(format, args...)
hasGlobalOrStdOrBslName("wscanf") or // wscanf(format, args...)
hasGlobalName("_scanf_l") or // _scanf_l(format, locale, args...)
hasGlobalName("_wscanf_l") // _wscanf_l(format, locale, args...)
)
}
@@ -53,10 +53,10 @@ class Fscanf extends ScanfFunction {
Fscanf() {
this instanceof TopLevelFunction and
(
this.hasGlobalOrStdOrBslName("fscanf") or // fscanf(src_stream, format, args...)
this.hasGlobalOrStdOrBslName("fwscanf") or // fwscanf(src_stream, format, args...)
this.hasGlobalName("_fscanf_l") or // _fscanf_l(src_stream, format, locale, args...)
this.hasGlobalName("_fwscanf_l") // _fwscanf_l(src_stream, format, locale, args...)
hasGlobalOrStdOrBslName("fscanf") or // fscanf(src_stream, format, args...)
hasGlobalOrStdOrBslName("fwscanf") or // fwscanf(src_stream, format, args...)
hasGlobalName("_fscanf_l") or // _fscanf_l(src_stream, format, locale, args...)
hasGlobalName("_fwscanf_l") // _fwscanf_l(src_stream, format, locale, args...)
)
}
@@ -72,10 +72,10 @@ class Sscanf extends ScanfFunction {
Sscanf() {
this instanceof TopLevelFunction and
(
this.hasGlobalOrStdOrBslName("sscanf") or // sscanf(src_stream, format, args...)
this.hasGlobalOrStdOrBslName("swscanf") or // swscanf(src, format, args...)
this.hasGlobalName("_sscanf_l") or // _sscanf_l(src, format, locale, args...)
this.hasGlobalName("_swscanf_l") // _swscanf_l(src, format, locale, args...)
hasGlobalOrStdOrBslName("sscanf") or // sscanf(src_stream, format, args...)
hasGlobalOrStdOrBslName("swscanf") or // swscanf(src, format, args...)
hasGlobalName("_sscanf_l") or // _sscanf_l(src, format, locale, args...)
hasGlobalName("_swscanf_l") // _swscanf_l(src, format, locale, args...)
)
}
@@ -91,10 +91,10 @@ class Snscanf extends ScanfFunction {
Snscanf() {
this instanceof TopLevelFunction and
(
this.hasGlobalName("_snscanf") or // _snscanf(src, max_amount, format, args...)
this.hasGlobalName("_snwscanf") or // _snwscanf(src, max_amount, format, args...)
this.hasGlobalName("_snscanf_l") or // _snscanf_l(src, max_amount, format, locale, args...)
this.hasGlobalName("_snwscanf_l") // _snwscanf_l(src, max_amount, format, locale, args...)
hasGlobalName("_snscanf") or // _snscanf(src, max_amount, format, args...)
hasGlobalName("_snwscanf") or // _snwscanf(src, max_amount, format, args...)
hasGlobalName("_snscanf_l") or // _snscanf_l(src, max_amount, format, locale, args...)
hasGlobalName("_snwscanf_l") // _snwscanf_l(src, max_amount, format, locale, args...)
// note that the max_amount is not a limit on the output length, it's an input length
// limit used with non null-terminated strings.
)
@@ -120,18 +120,18 @@ class ScanfFunctionCall extends FunctionCall {
/**
* Gets the `scanf`-like function that is called.
*/
ScanfFunction getScanfFunction() { result = this.getTarget() }
ScanfFunction getScanfFunction() { result = getTarget() }
/**
* Gets the position at which the input string or stream parameter occurs,
* if this function call does not read from standard input.
*/
int getInputParameterIndex() { result = this.getScanfFunction().getInputParameterIndex() }
int getInputParameterIndex() { result = getScanfFunction().getInputParameterIndex() }
/**
* Gets the position at which the format parameter occurs.
*/
int getFormatParameterIndex() { result = this.getScanfFunction().getFormatParameterIndex() }
int getFormatParameterIndex() { result = getScanfFunction().getFormatParameterIndex() }
/**
* Gets the format expression used in this call.
@@ -142,7 +142,7 @@ class ScanfFunctionCall extends FunctionCall {
* Holds if the default meaning of `%s` is a `wchar_t*` string
* (rather than a `char*`).
*/
predicate isWideCharDefault() { this.getScanfFunction().isWideCharDefault() }
predicate isWideCharDefault() { getScanfFunction().isWideCharDefault() }
}
/**
@@ -158,7 +158,7 @@ class ScanfFormatLiteral extends Expr {
ScanfFunctionCall getUse() { result.getFormat() = this }
/** Holds if the default meaning of `%s` is a `wchar_t*` (rather than a `char*`). */
predicate isWideCharDefault() { this.getUse().getTarget().(ScanfFunction).isWideCharDefault() }
predicate isWideCharDefault() { getUse().getTarget().(ScanfFunction).isWideCharDefault() }
/**
* Gets the format string itself, transformed as follows:

View File

@@ -40,8 +40,8 @@ abstract class MutexType extends Type {
* Gets a call that locks or tries to lock any mutex of this type.
*/
FunctionCall getLockAccess() {
result = this.getMustlockAccess() or
result = this.getTrylockAccess()
result = getMustlockAccess() or
result = getTrylockAccess()
}
/**
@@ -63,22 +63,22 @@ abstract class MutexType extends Type {
/**
* DEPRECATED: use mustlockAccess(fc, arg) instead.
*/
deprecated Function getMustlockFunction() { result = this.getMustlockAccess().getTarget() }
deprecated Function getMustlockFunction() { result = getMustlockAccess().getTarget() }
/**
* DEPRECATED: use trylockAccess(fc, arg) instead.
*/
deprecated Function getTrylockFunction() { result = this.getTrylockAccess().getTarget() }
deprecated Function getTrylockFunction() { result = getTrylockAccess().getTarget() }
/**
* DEPRECATED: use lockAccess(fc, arg) instead.
*/
deprecated Function getLockFunction() { result = this.getLockAccess().getTarget() }
deprecated Function getLockFunction() { result = getLockAccess().getTarget() }
/**
* DEPRECATED: use unlockAccess(fc, arg) instead.
*/
deprecated Function getUnlockFunction() { result = this.getUnlockAccess().getTarget() }
deprecated Function getUnlockFunction() { result = getUnlockAccess().getTarget() }
}
/**
@@ -155,17 +155,17 @@ class DefaultMutexType extends MutexType {
override predicate mustlockAccess(FunctionCall fc, Expr arg) {
fc.getTarget() = mustlockCandidate() and
this.lockArgType(fc, arg)
lockArgType(fc, arg)
}
override predicate trylockAccess(FunctionCall fc, Expr arg) {
fc.getTarget() = trylockCandidate() and
this.lockArgType(fc, arg)
lockArgType(fc, arg)
}
override predicate unlockAccess(FunctionCall fc, Expr arg) {
fc.getTarget() = unlockCandidate() and
this.lockArgType(fc, arg)
lockArgType(fc, arg)
}
}

View File

@@ -194,14 +194,14 @@ class BasicBlock extends ControlFlowNodeBase {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*
* Yields no result if this basic block spans multiple source files.
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.hasLocationInfoInternal(filepath, startline, startcolumn, filepath, endline, endcolumn)
hasLocationInfoInternal(filepath, startline, startcolumn, filepath, endline, endcolumn)
}
pragma[noinline]
@@ -276,7 +276,7 @@ class EntryBasicBlock extends BasicBlock {
*/
class ExitBasicBlock extends BasicBlock {
ExitBasicBlock() {
this.getEnd() instanceof Function or
aborting(this.getEnd())
getEnd() instanceof Function or
aborting(getEnd())
}
}

View File

@@ -66,7 +66,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase {
*/
ControlFlowNode getATrueSuccessor() {
qlCFGTrueSuccessor(this, result) and
result = this.getASuccessor()
result = getASuccessor()
}
/**
@@ -75,7 +75,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase {
*/
ControlFlowNode getAFalseSuccessor() {
qlCFGFalseSuccessor(this, result) and
result = this.getASuccessor()
result = getASuccessor()
}
/** Gets the `BasicBlock` containing this control-flow node. */

View File

@@ -25,7 +25,7 @@ predicate definitionUsePair(SemanticStackVariable var, Expr def, Expr use) {
* Holds if the definition `def` of some stack variable can reach `node`, which
* is a definition or use, without crossing definitions of the same variable.
*/
predicate definitionReaches(Expr def, Expr node) { def.(Def).reaches(true, _, node) }
predicate definitionReaches(Expr def, Expr node) { def.(Def).reaches(true, _, node.(DefOrUse)) }
private predicate hasAddressOfAccess(SemanticStackVariable var) {
var.getAnAccess().isAddressOfAccessNonConst()

View File

@@ -121,7 +121,7 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardCondition {
override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) {
exists(boolean testIsTrue |
this.comparesLt(left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue)
comparesLt(left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue)
)
}
@@ -135,7 +135,7 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardCondition {
override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) {
exists(boolean testIsTrue |
this.comparesEq(left, right, k, areEqual, testIsTrue) and this.controls(block, testIsTrue)
comparesEq(left, right, k, areEqual, testIsTrue) and this.controls(block, testIsTrue)
)
}
}
@@ -147,29 +147,27 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardCondition {
private class GuardConditionFromShortCircuitNot extends GuardCondition, NotExpr {
GuardConditionFromShortCircuitNot() {
not exists(Instruction inst | this.getFullyConverted() = inst.getAST()) and
exists(IRGuardCondition ir | this.getOperand() = ir.getAST())
exists(IRGuardCondition ir | getOperand() = ir.getAST())
}
override predicate controls(BasicBlock controlled, boolean testIsTrue) {
this.getOperand().(GuardCondition).controls(controlled, testIsTrue.booleanNot())
getOperand().(GuardCondition).controls(controlled, testIsTrue.booleanNot())
}
override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
this.getOperand()
.(GuardCondition)
.comparesLt(left, right, k, isLessThan, testIsTrue.booleanNot())
getOperand().(GuardCondition).comparesLt(left, right, k, isLessThan, testIsTrue.booleanNot())
}
override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) {
this.getOperand().(GuardCondition).ensuresLt(left, right, k, block, isLessThan.booleanNot())
getOperand().(GuardCondition).ensuresLt(left, right, k, block, isLessThan.booleanNot())
}
override predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) {
this.getOperand().(GuardCondition).comparesEq(left, right, k, areEqual, testIsTrue.booleanNot())
getOperand().(GuardCondition).comparesEq(left, right, k, areEqual, testIsTrue.booleanNot())
}
override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) {
this.getOperand().(GuardCondition).ensuresEq(left, right, k, block, areEqual.booleanNot())
getOperand().(GuardCondition).ensuresEq(left, right, k, block, areEqual.booleanNot())
}
}
@@ -305,9 +303,9 @@ class IRGuardCondition extends Instruction {
cached
predicate controlsEdge(IRBlock pred, IRBlock succ, boolean testIsTrue) {
pred.getASuccessor() = succ and
this.controls(pred, testIsTrue)
controls(pred, testIsTrue)
or
succ = this.getBranchSuccessor(testIsTrue) and
succ = getBranchSuccessor(testIsTrue) and
branch.getCondition() = this and
branch.getBlock() = pred
}

View File

@@ -73,19 +73,19 @@ abstract deprecated class LocalScopeVariableReachability extends string {
*/
exists(BasicBlock bb, int i |
this.isSource(source, v) and
isSource(source, v) and
bb.getNode(i) = source and
not bb.isUnreachable()
|
exists(int j |
j > i and
sink = bb.getNode(j) and
this.isSink(sink, v) and
not exists(int k | this.isBarrier(bb.getNode(k), v) | k in [i + 1 .. j - 1])
isSink(sink, v) and
not exists(int k | isBarrier(bb.getNode(k), v) | k in [i + 1 .. j - 1])
)
or
not exists(int k | this.isBarrier(bb.getNode(k), v) | k > i) and
this.bbSuccessorEntryReaches(bb, v, sink, _)
not exists(int k | isBarrier(bb.getNode(k), v) | k > i) and
bbSuccessorEntryReaches(bb, v, sink, _)
)
}
@@ -97,11 +97,11 @@ abstract deprecated class LocalScopeVariableReachability extends string {
bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
succSkipsFirstLoopAlwaysTrueUponEntry)
|
this.bbEntryReachesLocally(succ, v, node) and
bbEntryReachesLocally(succ, v, node) and
succSkipsFirstLoopAlwaysTrueUponEntry = false
or
not this.isBarrier(succ.getNode(_), v) and
this.bbSuccessorEntryReaches(succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry)
not isBarrier(succ.getNode(_), v) and
bbSuccessorEntryReaches(succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry)
)
}
@@ -110,7 +110,7 @@ abstract deprecated class LocalScopeVariableReachability extends string {
) {
exists(int n |
node = bb.getNode(n) and
this.isSink(node, v)
isSink(node, v)
|
not exists(this.firstBarrierIndexIn(bb, v))
or
@@ -119,7 +119,7 @@ abstract deprecated class LocalScopeVariableReachability extends string {
}
private int firstBarrierIndexIn(BasicBlock bb, SemanticStackVariable v) {
result = min(int m | this.isBarrier(bb.getNode(m), v))
result = min(int m | isBarrier(bb.getNode(m), v))
}
}
@@ -271,7 +271,7 @@ abstract deprecated class LocalScopeVariableReachabilityWithReassignment extends
* accounts for loops where the condition is provably true upon entry.
*/
override predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
this.reachesTo(source, v, sink, _)
reachesTo(source, v, sink, _)
}
/**
@@ -281,21 +281,21 @@ abstract deprecated class LocalScopeVariableReachabilityWithReassignment extends
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink, SemanticStackVariable v0
) {
exists(ControlFlowNode def |
this.actualSourceReaches(source, v, def, v0) and
actualSourceReaches(source, v, def, v0) and
LocalScopeVariableReachability.super.reaches(def, v0, sink) and
this.isSinkActual(sink, v0)
isSinkActual(sink, v0)
)
}
private predicate actualSourceReaches(
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0
) {
this.isSourceActual(source, v) and def = source and v0 = v
isSourceActual(source, v) and def = source and v0 = v
or
exists(ControlFlowNode source1, SemanticStackVariable v1 |
this.actualSourceReaches(source, v, source1, v1)
actualSourceReaches(source, v, source1, v1)
|
this.reassignment(source1, v1, def, v0)
reassignment(source1, v1, def, v0)
)
}
@@ -307,14 +307,14 @@ abstract deprecated class LocalScopeVariableReachabilityWithReassignment extends
}
final override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
this.isSourceActual(node, v)
isSourceActual(node, v)
or
// Reassignment generates a new (non-actual) source
this.reassignment(_, _, node, v)
reassignment(_, _, node, v)
}
final override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
this.isSinkActual(node, v)
isSinkActual(node, v)
or
// Reassignment generates a new (non-actual) sink
exprDefinition(_, node, v.getAnAccess())
@@ -347,21 +347,21 @@ abstract deprecated class LocalScopeVariableReachabilityExt extends string {
/** See `LocalScopeVariableReachability.reaches`. */
predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
exists(BasicBlock bb, int i |
this.isSource(source, v) and
isSource(source, v) and
bb.getNode(i) = source and
not bb.isUnreachable()
|
exists(int j |
j > i and
sink = bb.getNode(j) and
this.isSink(sink, v) and
not exists(int k | this.isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) |
isSink(sink, v) and
not exists(int k | isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) |
k in [i .. j - 1]
)
)
or
not exists(int k | this.isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) | k >= i) and
this.bbSuccessorEntryReaches(source, bb, v, sink, _)
not exists(int k | isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) | k >= i) and
bbSuccessorEntryReaches(source, bb, v, sink, _)
)
}
@@ -372,22 +372,22 @@ abstract deprecated class LocalScopeVariableReachabilityExt extends string {
exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
succSkipsFirstLoopAlwaysTrueUponEntry) and
not this.isBarrier(source, bb.getEnd(), succ.getStart(), v)
not isBarrier(source, bb.getEnd(), succ.getStart(), v)
|
this.bbEntryReachesLocally(source, succ, v, node) and
bbEntryReachesLocally(source, succ, v, node) and
succSkipsFirstLoopAlwaysTrueUponEntry = false
or
not exists(int k | this.isBarrier(source, succ.getNode(k), succ.getNode(k + 1), v)) and
this.bbSuccessorEntryReaches(source, succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry)
not exists(int k | isBarrier(source, succ.getNode(k), succ.getNode(k + 1), v)) and
bbSuccessorEntryReaches(source, succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry)
)
}
private predicate bbEntryReachesLocally(
ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node
) {
this.isSource(source, v) and
exists(int n | node = bb.getNode(n) and this.isSink(node, v) |
not exists(int m | m < n | this.isBarrier(source, bb.getNode(m), bb.getNode(m + 1), v))
isSource(source, v) and
exists(int n | node = bb.getNode(n) and isSink(node, v) |
not exists(int m | m < n | isBarrier(source, bb.getNode(m), bb.getNode(m + 1), v))
)
}
}

View File

@@ -59,10 +59,10 @@ class SsaDefinition extends ControlFlowNodeBase {
ControlFlowNode getDefinition() { result = this }
/** Gets the `BasicBlock` containing this definition. */
BasicBlock getBasicBlock() { result.contains(this.getDefinition()) }
BasicBlock getBasicBlock() { result.contains(getDefinition()) }
/** Holds if this definition is a phi node for variable `v`. */
predicate isPhiNode(StackVariable v) { exists(StandardSSA x | x.phi_node(v, this)) }
predicate isPhiNode(StackVariable v) { exists(StandardSSA x | x.phi_node(v, this.(BasicBlock))) }
/** Gets the location of this definition. */
Location getLocation() { result = this.(ControlFlowNode).getLocation() }

View File

@@ -292,7 +292,7 @@ library class SSAHelper extends int {
*/
cached
string toString(ControlFlowNode node, StackVariable v) {
if phi_node(v, node)
if phi_node(v, node.(BasicBlock))
then result = "SSA phi(" + v.getName() + ")"
else (
ssa_defn(v, node, _, _) and result = "SSA def(" + v.getName() + ")"

View File

@@ -72,19 +72,19 @@ abstract class StackVariableReachability extends string {
*/
exists(BasicBlock bb, int i |
this.isSource(source, v) and
isSource(source, v) and
bb.getNode(i) = source and
not bb.isUnreachable()
|
exists(int j |
j > i and
sink = bb.getNode(j) and
this.isSink(sink, v) and
not exists(int k | this.isBarrier(bb.getNode(k), v) | k in [i + 1 .. j - 1])
isSink(sink, v) and
not exists(int k | isBarrier(bb.getNode(k), v) | k in [i + 1 .. j - 1])
)
or
not exists(int k | this.isBarrier(bb.getNode(k), v) | k > i) and
this.bbSuccessorEntryReaches(bb, v, sink, _)
not exists(int k | isBarrier(bb.getNode(k), v) | k > i) and
bbSuccessorEntryReaches(bb, v, sink, _)
)
}
@@ -96,11 +96,11 @@ abstract class StackVariableReachability extends string {
bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
succSkipsFirstLoopAlwaysTrueUponEntry)
|
this.bbEntryReachesLocally(succ, v, node) and
bbEntryReachesLocally(succ, v, node) and
succSkipsFirstLoopAlwaysTrueUponEntry = false
or
not this.isBarrier(succ.getNode(_), v) and
this.bbSuccessorEntryReaches(succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry)
not isBarrier(succ.getNode(_), v) and
bbSuccessorEntryReaches(succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry)
)
}
@@ -109,7 +109,7 @@ abstract class StackVariableReachability extends string {
) {
exists(int n |
node = bb.getNode(n) and
this.isSink(node, v)
isSink(node, v)
|
not exists(this.firstBarrierIndexIn(bb, v))
or
@@ -118,7 +118,7 @@ abstract class StackVariableReachability extends string {
}
private int firstBarrierIndexIn(BasicBlock bb, SemanticStackVariable v) {
result = min(int m | this.isBarrier(bb.getNode(m), v))
result = min(int m | isBarrier(bb.getNode(m), v))
}
}
@@ -268,7 +268,7 @@ abstract class StackVariableReachabilityWithReassignment extends StackVariableRe
* accounts for loops where the condition is provably true upon entry.
*/
override predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
this.reachesTo(source, v, sink, _)
reachesTo(source, v, sink, _)
}
/**
@@ -278,21 +278,21 @@ abstract class StackVariableReachabilityWithReassignment extends StackVariableRe
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink, SemanticStackVariable v0
) {
exists(ControlFlowNode def |
this.actualSourceReaches(source, v, def, v0) and
actualSourceReaches(source, v, def, v0) and
StackVariableReachability.super.reaches(def, v0, sink) and
this.isSinkActual(sink, v0)
isSinkActual(sink, v0)
)
}
private predicate actualSourceReaches(
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0
) {
this.isSourceActual(source, v) and def = source and v0 = v
isSourceActual(source, v) and def = source and v0 = v
or
exists(ControlFlowNode source1, SemanticStackVariable v1 |
this.actualSourceReaches(source, v, source1, v1)
actualSourceReaches(source, v, source1, v1)
|
this.reassignment(source1, v1, def, v0)
reassignment(source1, v1, def, v0)
)
}
@@ -304,14 +304,14 @@ abstract class StackVariableReachabilityWithReassignment extends StackVariableRe
}
final override predicate isSource(ControlFlowNode node, StackVariable v) {
this.isSourceActual(node, v)
isSourceActual(node, v)
or
// Reassignment generates a new (non-actual) source
this.reassignment(_, _, node, v)
reassignment(_, _, node, v)
}
final override predicate isSink(ControlFlowNode node, StackVariable v) {
this.isSinkActual(node, v)
isSinkActual(node, v)
or
// Reassignment generates a new (non-actual) sink
exprDefinition(_, node, v.getAnAccess())
@@ -342,21 +342,21 @@ abstract class StackVariableReachabilityExt extends string {
/** See `StackVariableReachability.reaches`. */
predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
exists(BasicBlock bb, int i |
this.isSource(source, v) and
isSource(source, v) and
bb.getNode(i) = source and
not bb.isUnreachable()
|
exists(int j |
j > i and
sink = bb.getNode(j) and
this.isSink(sink, v) and
not exists(int k | this.isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) |
isSink(sink, v) and
not exists(int k | isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) |
k in [i .. j - 1]
)
)
or
not exists(int k | this.isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) | k >= i) and
this.bbSuccessorEntryReaches(source, bb, v, sink, _)
not exists(int k | isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) | k >= i) and
bbSuccessorEntryReaches(source, bb, v, sink, _)
)
}
@@ -367,22 +367,22 @@ abstract class StackVariableReachabilityExt extends string {
exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
succSkipsFirstLoopAlwaysTrueUponEntry) and
not this.isBarrier(source, bb.getEnd(), succ.getStart(), v)
not isBarrier(source, bb.getEnd(), succ.getStart(), v)
|
this.bbEntryReachesLocally(source, succ, v, node) and
bbEntryReachesLocally(source, succ, v, node) and
succSkipsFirstLoopAlwaysTrueUponEntry = false
or
not exists(int k | this.isBarrier(source, succ.getNode(k), succ.getNode(k + 1), v)) and
this.bbSuccessorEntryReaches(source, succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry)
not exists(int k | isBarrier(source, succ.getNode(k), succ.getNode(k + 1), v)) and
bbSuccessorEntryReaches(source, succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry)
)
}
private predicate bbEntryReachesLocally(
ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node
) {
this.isSource(source, v) and
exists(int n | node = bb.getNode(n) and this.isSink(node, v) |
not exists(int m | m < n | this.isBarrier(source, bb.getNode(m), bb.getNode(m + 1), v))
isSource(source, v) and
exists(int n | node = bb.getNode(n) and isSink(node, v) |
not exists(int m | m < n | isBarrier(source, bb.getNode(m), bb.getNode(m + 1), v))
)
}
}

View File

@@ -80,7 +80,7 @@ class SubBasicBlock extends ControlFlowNodeBase {
* returns a 0-based position, while `getRankInBasicBlock` returns a 1-based
* position.
*/
deprecated int getPosInBasicBlock(BasicBlock bb) { result = this.getRankInBasicBlock(bb) - 1 }
deprecated int getPosInBasicBlock(BasicBlock bb) { result = getRankInBasicBlock(bb) - 1 }
pragma[noinline]
private int getIndexInBasicBlock(BasicBlock bb) { this = bb.getNode(result) }
@@ -102,7 +102,7 @@ class SubBasicBlock extends ControlFlowNodeBase {
exists(BasicBlock bb |
exists(int outerIndex |
result = bb.getNode(outerIndex) and
index = this.outerToInnerIndex(bb, outerIndex)
index = outerToInnerIndex(bb, outerIndex)
)
)
}

View File

@@ -231,7 +231,7 @@ private class PostOrderInitializer extends Initializer {
or
this.getDeclaration() = for.getRangeVariable()
or
this.getDeclaration() = for.getBeginEndDeclaration().getADeclaration()
this.getDeclaration() = for.getBeginEndDeclaration().(DeclStmt).getADeclaration()
)
}
}
@@ -1143,7 +1143,7 @@ private class ExceptionSource extends Node {
this.reachesParent(mid) and
not mid = any(TryStmt try).getStmt() and
not mid = any(MicrosoftTryStmt try).getStmt() and
parent = mid.getParentNode()
parent = mid.(Node).getParentNode()
)
}

View File

@@ -344,13 +344,14 @@ private int convertIntToType(int val, IntegralType t) {
then if val = 0 then result = 0 else result = 1
else
if t.isUnsigned()
then val >= 0 and val.bitShiftRight(t.getSize() * 8) = 0 and result = val
then if val >= 0 and val.bitShiftRight(t.getSize() * 8) = 0 then result = val else none()
else
if val >= 0 and val.bitShiftRight(t.getSize() * 8 - 1) = 0
then result = val
else (
(-(val + 1)).bitShiftRight(t.getSize() * 8 - 1) = 0 and result = val
)
else
if (-(val + 1)).bitShiftRight(t.getSize() * 8 - 1) = 0
then result = val
else none()
}
/**
@@ -385,7 +386,7 @@ library class ExprEvaluator extends int {
abstract predicate interesting(Expr e);
/** Gets the value of (interesting) expression `e`, if any. */
int getValue(Expr e) { result = this.getValueInternal(e, e) }
int getValue(Expr e) { result = getValueInternal(e, e) }
/**
* When evaluating a syntactic subexpression of `e`, we may
@@ -425,9 +426,9 @@ library class ExprEvaluator extends int {
* calculates the values bottom-up.
*/
predicate interestingInternal(Expr e, Expr req, boolean sub) {
this.interesting(e) and req = e and sub = true
interesting(e) and req = e and sub = true
or
exists(Expr mid | this.interestingInternal(e, mid, sub) |
exists(Expr mid | interestingInternal(e, mid, sub) |
req = mid.(NotExpr).getOperand() or
req = mid.(BinaryLogicalOperation).getAnOperand() or
req = mid.(RelationalOperation).getAnOperand() or
@@ -442,36 +443,36 @@ library class ExprEvaluator extends int {
)
or
exists(VariableAccess va, Variable v, boolean sub1 |
this.interestingVariableAccess(e, va, v, sub1) and
interestingVariableAccess(e, va, v, sub1) and
req = v.getAnAssignedValue() and
(sub1 = true implies not this.ignoreVariableAssignment(e, v, req)) and
(sub1 = true implies not ignoreVariableAssignment(e, v, req)) and
sub = false
)
or
exists(Function f |
this.interestingFunction(e, f) and
interestingFunction(e, f) and
returnStmt(f, req) and
sub = false
)
}
private predicate interestingVariableAccess(Expr e, VariableAccess va, Variable v, boolean sub) {
this.interestingInternal(e, va, sub) and
interestingInternal(e, va, sub) and
v = getVariableTarget(va) and
(
v.hasInitializer()
or
sub = true and this.allowVariableWithoutInitializer(e, v)
sub = true and allowVariableWithoutInitializer(e, v)
) and
tractableVariable(v) and
forall(StmtParent def | nonAnalyzableVariableDefinition(v, def) |
sub = true and
this.ignoreNonAnalyzableVariableDefinition(e, v, def)
ignoreNonAnalyzableVariableDefinition(e, v, def)
)
}
private predicate interestingFunction(Expr e, Function f) {
exists(FunctionCall fc | this.interestingInternal(e, fc, _) |
exists(FunctionCall fc | interestingInternal(e, fc, _) |
f = fc.getTarget() and
not obviouslyNonConstant(f) and
not f.getUnspecifiedType() instanceof VoidType
@@ -481,10 +482,10 @@ library class ExprEvaluator extends int {
/** Gets the value of subexpressions `req` for expression `e`, if any. */
private int getValueInternal(Expr e, Expr req) {
(
this.interestingInternal(e, req, true) and
interestingInternal(e, req, true) and
(
result = req.(CompileTimeConstantInt).getIntValue() or
result = this.getCompoundValue(e, req)
result = getCompoundValue(e, req.(CompileTimeVariableExpr))
) and
(
req.getUnderlyingType().(IntegralType).isSigned() or
@@ -495,126 +496,109 @@ library class ExprEvaluator extends int {
/** Gets the value of compound subexpressions `val` for expression `e`, if any. */
private int getCompoundValue(Expr e, CompileTimeVariableExpr val) {
this.interestingInternal(e, val, true) and
interestingInternal(e, val, true) and
(
exists(NotExpr req | req = val |
result = 1 and this.getValueInternal(e, req.getOperand()) = 0
result = 1 and getValueInternal(e, req.getOperand()) = 0
or
result = 0 and this.getValueInternal(e, req.getOperand()) != 0
result = 0 and getValueInternal(e, req.getOperand()) != 0
)
or
exists(LogicalAndExpr req | req = val |
result = 1 and
this.getValueInternal(e, req.getLeftOperand()) != 0 and
this.getValueInternal(e, req.getRightOperand()) != 0
getValueInternal(e, req.getLeftOperand()) != 0 and
getValueInternal(e, req.getRightOperand()) != 0
or
result = 0 and this.getValueInternal(e, req.getAnOperand()) = 0
result = 0 and getValueInternal(e, req.getAnOperand()) = 0
)
or
exists(LogicalOrExpr req | req = val |
result = 1 and this.getValueInternal(e, req.getAnOperand()) != 0
result = 1 and getValueInternal(e, req.getAnOperand()) != 0
or
result = 0 and
this.getValueInternal(e, req.getLeftOperand()) = 0 and
this.getValueInternal(e, req.getRightOperand()) = 0
getValueInternal(e, req.getLeftOperand()) = 0 and
getValueInternal(e, req.getRightOperand()) = 0
)
or
exists(LTExpr req | req = val |
result = 1 and
this.getValueInternal(e, req.getLeftOperand()) <
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) < getValueInternal(e, req.getRightOperand())
or
result = 0 and
this.getValueInternal(e, req.getLeftOperand()) >=
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) >= getValueInternal(e, req.getRightOperand())
)
or
exists(GTExpr req | req = val |
result = 1 and
this.getValueInternal(e, req.getLeftOperand()) >
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) > getValueInternal(e, req.getRightOperand())
or
result = 0 and
this.getValueInternal(e, req.getLeftOperand()) <=
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) <= getValueInternal(e, req.getRightOperand())
)
or
exists(LEExpr req | req = val |
result = 1 and
this.getValueInternal(e, req.getLeftOperand()) <=
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) <= getValueInternal(e, req.getRightOperand())
or
result = 0 and
this.getValueInternal(e, req.getLeftOperand()) >
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) > getValueInternal(e, req.getRightOperand())
)
or
exists(GEExpr req | req = val |
result = 1 and
this.getValueInternal(e, req.getLeftOperand()) >=
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) >= getValueInternal(e, req.getRightOperand())
or
result = 0 and
this.getValueInternal(e, req.getLeftOperand()) <
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) < getValueInternal(e, req.getRightOperand())
)
or
exists(EQExpr req | req = val |
result = 1 and
this.getValueInternal(e, req.getLeftOperand()) =
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) = getValueInternal(e, req.getRightOperand())
or
result = 0 and
this.getValueInternal(e, req.getLeftOperand()) !=
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) != getValueInternal(e, req.getRightOperand())
)
or
exists(NEExpr req | req = val |
result = 0 and
this.getValueInternal(e, req.getLeftOperand()) =
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) = getValueInternal(e, req.getRightOperand())
or
result = 1 and
this.getValueInternal(e, req.getLeftOperand()) !=
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) != getValueInternal(e, req.getRightOperand())
)
or
exists(AddExpr req | req = val |
result =
this.getValueInternal(e, req.getLeftOperand()) +
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) + getValueInternal(e, req.getRightOperand())
)
or
exists(SubExpr req | req = val |
result =
this.getValueInternal(e, req.getLeftOperand()) -
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) - getValueInternal(e, req.getRightOperand())
)
or
exists(MulExpr req | req = val |
result =
this.getValueInternal(e, req.getLeftOperand()) *
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) * getValueInternal(e, req.getRightOperand())
)
or
exists(RemExpr req | req = val |
result =
this.getValueInternal(e, req.getLeftOperand()) %
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) % getValueInternal(e, req.getRightOperand())
)
or
exists(DivExpr req | req = val |
result =
this.getValueInternal(e, req.getLeftOperand()) /
this.getValueInternal(e, req.getRightOperand())
getValueInternal(e, req.getLeftOperand()) / getValueInternal(e, req.getRightOperand())
)
or
exists(AssignExpr req | req = val | result = this.getValueInternal(e, req.getRValue()))
exists(AssignExpr req | req = val | result = getValueInternal(e, req.getRValue()))
or
result = this.getVariableValue(e, val)
result = getVariableValue(e, val.(VariableAccess))
or
exists(FunctionCall call | call = val and not callWithMultipleTargets(call) |
result = this.getFunctionValue(call.getTarget())
result = getFunctionValue(call.getTarget())
)
)
}
@@ -622,7 +606,7 @@ library class ExprEvaluator extends int {
language[monotonicAggregates]
private int getVariableValue(Expr e, VariableAccess va) {
exists(Variable v |
this.interestingVariableAccess(e, va, v, true) and
interestingVariableAccess(e, va, v, true) and
// All assignments must have the same int value
result =
unique(Expr value |
@@ -636,16 +620,14 @@ library class ExprEvaluator extends int {
/** Holds if the function `f` is considered by the analysis and may return `ret`. */
pragma[noinline]
private predicate interestingReturnValue(Function f, Expr ret) {
this.interestingFunction(_, f) and
interestingFunction(_, f) and
returnStmt(f, ret)
}
private int getFunctionValue(Function f) {
// All returns must have the same int value
// And it must have at least one return
forex(Expr ret | this.interestingReturnValue(f, ret) |
result = this.getValueInternalNonSubExpr(ret)
)
forex(Expr ret | interestingReturnValue(f, ret) | result = getValueInternalNonSubExpr(ret))
}
/**
@@ -660,10 +642,10 @@ library class ExprEvaluator extends int {
* omitted).
*/
private int getValueInternalNonSubExpr(Expr req) {
this.interestingInternal(_, req, false) and
interestingInternal(_, req, false) and
(
result = req.(CompileTimeConstantInt).getIntValue() or
result = this.getCompoundValueNonSubExpr(req)
result = getCompoundValueNonSubExpr(req.(CompileTimeVariableExpr))
) and
(
req.getUnderlyingType().(IntegralType).isSigned() or
@@ -674,131 +656,131 @@ library class ExprEvaluator extends int {
private int getCompoundValueNonSubExpr(CompileTimeVariableExpr val) {
(
exists(NotExpr req | req = val |
result = 1 and this.getValueInternalNonSubExpr(req.getOperand()) = 0
result = 1 and getValueInternalNonSubExpr(req.getOperand()) = 0
or
result = 0 and this.getValueInternalNonSubExpr(req.getOperand()) != 0
result = 0 and getValueInternalNonSubExpr(req.getOperand()) != 0
)
or
exists(LogicalAndExpr req | req = val |
result = 1 and
this.getValueInternalNonSubExpr(req.getLeftOperand()) != 0 and
this.getValueInternalNonSubExpr(req.getRightOperand()) != 0
getValueInternalNonSubExpr(req.getLeftOperand()) != 0 and
getValueInternalNonSubExpr(req.getRightOperand()) != 0
or
result = 0 and this.getValueInternalNonSubExpr(req.getAnOperand()) = 0
result = 0 and getValueInternalNonSubExpr(req.getAnOperand()) = 0
)
or
exists(LogicalOrExpr req | req = val |
result = 1 and this.getValueInternalNonSubExpr(req.getAnOperand()) != 0
result = 1 and getValueInternalNonSubExpr(req.getAnOperand()) != 0
or
result = 0 and
this.getValueInternalNonSubExpr(req.getLeftOperand()) = 0 and
this.getValueInternalNonSubExpr(req.getRightOperand()) = 0
getValueInternalNonSubExpr(req.getLeftOperand()) = 0 and
getValueInternalNonSubExpr(req.getRightOperand()) = 0
)
or
exists(LTExpr req | req = val |
result = 1 and
this.getValueInternalNonSubExpr(req.getLeftOperand()) <
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) <
getValueInternalNonSubExpr(req.getRightOperand())
or
result = 0 and
this.getValueInternalNonSubExpr(req.getLeftOperand()) >=
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) >=
getValueInternalNonSubExpr(req.getRightOperand())
)
or
exists(GTExpr req | req = val |
result = 1 and
this.getValueInternalNonSubExpr(req.getLeftOperand()) >
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) >
getValueInternalNonSubExpr(req.getRightOperand())
or
result = 0 and
this.getValueInternalNonSubExpr(req.getLeftOperand()) <=
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) <=
getValueInternalNonSubExpr(req.getRightOperand())
)
or
exists(LEExpr req | req = val |
result = 1 and
this.getValueInternalNonSubExpr(req.getLeftOperand()) <=
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) <=
getValueInternalNonSubExpr(req.getRightOperand())
or
result = 0 and
this.getValueInternalNonSubExpr(req.getLeftOperand()) >
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) >
getValueInternalNonSubExpr(req.getRightOperand())
)
or
exists(GEExpr req | req = val |
result = 1 and
this.getValueInternalNonSubExpr(req.getLeftOperand()) >=
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) >=
getValueInternalNonSubExpr(req.getRightOperand())
or
result = 0 and
this.getValueInternalNonSubExpr(req.getLeftOperand()) <
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) <
getValueInternalNonSubExpr(req.getRightOperand())
)
or
exists(EQExpr req | req = val |
result = 1 and
this.getValueInternalNonSubExpr(req.getLeftOperand()) =
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) =
getValueInternalNonSubExpr(req.getRightOperand())
or
result = 0 and
this.getValueInternalNonSubExpr(req.getLeftOperand()) !=
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) !=
getValueInternalNonSubExpr(req.getRightOperand())
)
or
exists(NEExpr req | req = val |
result = 0 and
this.getValueInternalNonSubExpr(req.getLeftOperand()) =
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) =
getValueInternalNonSubExpr(req.getRightOperand())
or
result = 1 and
this.getValueInternalNonSubExpr(req.getLeftOperand()) !=
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) !=
getValueInternalNonSubExpr(req.getRightOperand())
)
or
exists(AddExpr req | req = val |
result =
this.getValueInternalNonSubExpr(req.getLeftOperand()) +
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) +
getValueInternalNonSubExpr(req.getRightOperand())
)
or
exists(SubExpr req | req = val |
result =
this.getValueInternalNonSubExpr(req.getLeftOperand()) -
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) -
getValueInternalNonSubExpr(req.getRightOperand())
)
or
exists(MulExpr req | req = val |
result =
this.getValueInternalNonSubExpr(req.getLeftOperand()) *
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) *
getValueInternalNonSubExpr(req.getRightOperand())
)
or
exists(RemExpr req | req = val |
result =
this.getValueInternalNonSubExpr(req.getLeftOperand()) %
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) %
getValueInternalNonSubExpr(req.getRightOperand())
)
or
exists(DivExpr req | req = val |
result =
this.getValueInternalNonSubExpr(req.getLeftOperand()) /
this.getValueInternalNonSubExpr(req.getRightOperand())
getValueInternalNonSubExpr(req.getLeftOperand()) /
getValueInternalNonSubExpr(req.getRightOperand())
)
or
exists(AssignExpr req | req = val | result = this.getValueInternalNonSubExpr(req.getRValue()))
exists(AssignExpr req | req = val | result = getValueInternalNonSubExpr(req.getRValue()))
or
result = this.getVariableValueNonSubExpr(val)
result = getVariableValueNonSubExpr(val.(VariableAccess))
or
exists(FunctionCall call | call = val and not callWithMultipleTargets(call) |
result = this.getFunctionValue(call.getTarget())
result = getFunctionValue(call.getTarget())
)
)
}
private int getVariableValueNonSubExpr(VariableAccess va) {
// All assignments must have the same int value
result = this.getMinVariableValueNonSubExpr(va) and
result = this.getMaxVariableValueNonSubExpr(va)
result = getMinVariableValueNonSubExpr(va) and
result = getMaxVariableValueNonSubExpr(va)
}
/**
@@ -809,9 +791,8 @@ library class ExprEvaluator extends int {
pragma[noopt]
private int getMinVariableValueNonSubExpr(VariableAccess va) {
exists(Variable v |
this.interestingVariableAccess(_, va, v, false) and
result =
min(Expr value | value = v.getAnAssignedValue() | this.getValueInternalNonSubExpr(value))
interestingVariableAccess(_, va, v, false) and
result = min(Expr value | value = v.getAnAssignedValue() | getValueInternalNonSubExpr(value))
)
}
@@ -823,9 +804,8 @@ library class ExprEvaluator extends int {
pragma[noopt]
private int getMaxVariableValueNonSubExpr(VariableAccess va) {
exists(Variable v |
this.interestingVariableAccess(_, va, v, false) and
result =
max(Expr value | value = v.getAnAssignedValue() | this.getValueInternalNonSubExpr(value))
interestingVariableAccess(_, va, v, false) and
result = max(Expr value | value = v.getAnAssignedValue() | getValueInternalNonSubExpr(value))
)
}
}
@@ -988,9 +968,9 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator {
abstract predicate isLoopBody(Expr e, StmtParent s);
private predicate isLoopBodyDescendant(Expr e, StmtParent s) {
this.isLoopBody(e, s)
isLoopBody(e, s)
or
exists(StmtParent mid | this.isLoopBodyDescendant(e, mid) |
exists(StmtParent mid | isLoopBodyDescendant(e, mid) |
s = mid.(Stmt).getAChild() or
s = mid.(Expr).getAChild()
)
@@ -998,13 +978,13 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator {
// Same as `interestingInternal(e, sub, true)` but avoids negative recursion
private predicate interestingSubExpr(Expr e, Expr sub) {
this.interesting(e) and e = sub
interesting(e) and e = sub
or
exists(Expr mid | this.interestingSubExpr(e, mid) and sub = mid.getAChild())
exists(Expr mid | interestingSubExpr(e, mid) and sub = mid.getAChild())
}
private predicate maybeInterestingVariable(Expr e, Variable v) {
exists(VariableAccess va | this.interestingSubExpr(e, va) | va.getTarget() = v)
exists(VariableAccess va | interestingSubExpr(e, va) | va.getTarget() = v)
}
/**
@@ -1016,9 +996,9 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator {
* definition of `v`.
*/
private predicate reachesLoopEntryFromLoopBody(Expr e, Variable v, StmtParent valueOrDef) {
this.maybeInterestingVariable(e, v) and
maybeInterestingVariable(e, v) and
(valueOrDef = v.getAnAssignedValue() or nonAnalyzableVariableDefinition(v, valueOrDef)) and
this.isLoopBodyDescendant(e, valueOrDef) and
isLoopBodyDescendant(e, valueOrDef) and
/*
* Use primitive basic blocks in reachability analysis for better performance.
* This is similar to the pattern used in e.g. `DefinitionsAndUses` and
@@ -1028,16 +1008,16 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator {
exists(PrimitiveBasicBlock bb1, int pos1 | bb1.getNode(pos1) = valueOrDef |
// Reaches in same basic block
exists(int pos2 |
this.loopEntryAt(bb1, pos2, e) and
loopEntryAt(bb1, pos2, e) and
pos2 > pos1 and
not exists(int k | this.assignmentAt(bb1, k, v) | k in [pos1 + 1 .. pos2 - 1])
not exists(int k | assignmentAt(bb1, k, v) | k in [pos1 + 1 .. pos2 - 1])
)
or
// Reaches in a successor block
exists(PrimitiveBasicBlock bb2 |
bb2 = bb1.getASuccessor() and
not exists(int pos3 | this.assignmentAt(bb1, pos3, v) and pos3 > pos1) and
this.bbReachesLoopEntry(bb2, e, v)
not exists(int pos3 | assignmentAt(bb1, pos3, v) and pos3 > pos1) and
bbReachesLoopEntry(bb2, e, v)
)
)
}
@@ -1045,12 +1025,12 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator {
private predicate loopEntryAt(PrimitiveBasicBlock bb, int pos, Expr e) {
exists(Node cfn |
bb.getNode(pos) = cfn and
this.isLoopEntry(e, cfn)
isLoopEntry(e, cfn)
)
}
private predicate assignmentAt(PrimitiveBasicBlock bb, int pos, Variable v) {
this.maybeInterestingVariable(_, v) and
maybeInterestingVariable(_, v) and
bb.getNode(pos) = v.getAnAssignedValue()
}
@@ -1059,19 +1039,19 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator {
* the loop belonging to `e` without crossing an assignment to `v`.
*/
private predicate bbReachesLoopEntry(PrimitiveBasicBlock bb, Expr e, Variable v) {
this.bbReachesLoopEntryLocally(bb, e, v)
bbReachesLoopEntryLocally(bb, e, v)
or
exists(PrimitiveBasicBlock succ | succ = bb.getASuccessor() |
this.bbReachesLoopEntry(succ, e, v) and
not this.assignmentAt(bb, _, v)
bbReachesLoopEntry(succ, e, v) and
not assignmentAt(bb, _, v)
)
}
private predicate bbReachesLoopEntryLocally(PrimitiveBasicBlock bb, Expr e, Variable v) {
exists(int pos |
this.loopEntryAt(bb, pos, e) and
this.maybeInterestingVariable(e, v) and
not exists(int pos1 | this.assignmentAt(bb, pos1, v) | pos1 < pos)
loopEntryAt(bb, pos, e) and
maybeInterestingVariable(e, v) and
not exists(int pos1 | assignmentAt(bb, pos1, v) | pos1 < pos)
)
}
@@ -1105,10 +1085,10 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator {
* ```
*/
override predicate ignoreNonAnalyzableVariableDefinition(Expr e, Variable v, StmtParent def) {
this.maybeInterestingVariable(e, v) and
maybeInterestingVariable(e, v) and
nonAnalyzableVariableDefinition(v, def) and
this.isLoopBodyDescendant(e, def) and
not this.reachesLoopEntryFromLoopBody(e, v, def)
isLoopBodyDescendant(e, def) and
not reachesLoopEntryFromLoopBody(e, v, def)
}
/**
@@ -1141,10 +1121,10 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator {
* ```
*/
override predicate ignoreVariableAssignment(Expr e, Variable v, Expr value) {
this.maybeInterestingVariable(e, v) and
maybeInterestingVariable(e, v) and
value = v.getAnAssignedValue() and
this.isLoopBodyDescendant(e, value) and
not this.reachesLoopEntryFromLoopBody(e, v, value)
isLoopBodyDescendant(e, value) and
not reachesLoopEntryFromLoopBody(e, v, value)
}
}

View File

@@ -10,7 +10,6 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -95,22 +94,6 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -127,12 +110,12 @@ abstract class Configuration extends string {
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
predicate hasFlowTo(Node sink) { hasFlow(_, sink) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
@@ -261,8 +244,6 @@ private class ParamNodeEx extends NodeEx {
}
int getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
private class RetNodeEx extends NodeEx {
@@ -366,8 +347,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -383,8 +363,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -420,20 +399,6 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -454,7 +419,7 @@ private module Stage1 {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
@@ -584,7 +549,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -779,12 +744,8 @@ private module Stage1 {
returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
@@ -970,8 +931,6 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1039,7 +998,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1250,7 +1209,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1435,12 +1394,8 @@ private module Stage2 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -1651,8 +1606,6 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1734,7 +1687,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1945,7 +1898,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2130,12 +2083,8 @@ private module Stage3 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2190,8 +2139,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
) and
accessPathApproxCostLimits(apLimit, tupleLimit) and
apLimit < tails and
tupleLimit < (tails - 1) * nodes and
not tc.forceHighPrecision()
tupleLimit < (tails - 1) * nodes
)
}
@@ -2403,8 +2351,6 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2500,7 +2446,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2711,7 +2657,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2896,12 +2842,8 @@ private module Stage4 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2974,8 +2916,6 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
int getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
override string toString() { result = p + ": " + ap }
predicate hasLocationInfo(
@@ -3033,15 +2973,12 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
* expected to be expensive. Holds with `unfold = true` otherwise.
*/
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
if apa.getHead().forceHighPrecision()
then unfold = true
else
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
}
/**
@@ -3103,11 +3040,7 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3119,10 +3052,17 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3226,7 +3166,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
}
override string toString() {
result = "[" + this.toStringImpl(true) + this.length().toString() + ")]"
result = "[" + this.toStringImpl(true) + length().toString() + ")]"
or
result = "[" + this.toStringImpl(false)
}
@@ -3308,7 +3248,7 @@ class PathNode extends TPathNode {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3365,11 +3305,9 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + ppAp() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3437,48 +3375,24 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override PathNodeImpl getASuccessorImpl() {
// an intermediate step to another intermediate node
result = this.getSuccMid()
result = getSuccMid()
or
// a final step to a sink
result = this.getSuccMid().projectToSink()
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
override predicate isSource() {
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3542,7 +3456,7 @@ private predicate pathStep(
exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp()
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
or
pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone
or
@@ -3619,20 +3533,18 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
apa = ap.getApprox()
)
}
pragma[nomagic]
pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3645,14 +3557,12 @@ private predicate parameterCand(
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
AccessPath ap
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
pathIntoArg(mid, i, outercc, call, ap, apa) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration())
)
}
@@ -3661,23 +3571,18 @@ private predicate pathIntoCallable0(
* before and after entering the callable are `outercc` and `innercc`,
* respectively.
*/
pragma[nomagic]
private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
p.isParameterOf(callable, i) and
(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
sc = TSummaryCtxNone()
)
|
if recordDataFlowCallSite(call, callable)
@@ -3701,23 +3606,18 @@ private predicate paramFlowsThrough(
ap = mid.getAp() and
apa = ap.getApprox() and
pos = sc.getParameterPos() and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
pragma[nomagic]
private predicate pathThroughCallable0(
DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap,
AccessPathApprox apa, Configuration config
AccessPathApprox apa
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call, config) and
paramFlowsThrough(kind, innercc, sc, ap, apa, config)
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3727,9 +3627,9 @@ private predicate pathThroughCallable0(
*/
pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config |
pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3740,15 +3640,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
unbindConf(arg.getConfiguration()))
}
/**
@@ -3781,17 +3679,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3800,12 +3689,11 @@ 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(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4145,7 +4033,7 @@ private module FlowExploration {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn

View File

@@ -10,7 +10,6 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -95,22 +94,6 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -127,12 +110,12 @@ abstract class Configuration extends string {
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
predicate hasFlowTo(Node sink) { hasFlow(_, sink) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
@@ -261,8 +244,6 @@ private class ParamNodeEx extends NodeEx {
}
int getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
private class RetNodeEx extends NodeEx {
@@ -366,8 +347,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -383,8 +363,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -420,20 +399,6 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -454,7 +419,7 @@ private module Stage1 {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
@@ -584,7 +549,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -779,12 +744,8 @@ private module Stage1 {
returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
@@ -970,8 +931,6 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1039,7 +998,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1250,7 +1209,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1435,12 +1394,8 @@ private module Stage2 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -1651,8 +1606,6 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1734,7 +1687,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1945,7 +1898,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2130,12 +2083,8 @@ private module Stage3 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2190,8 +2139,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
) and
accessPathApproxCostLimits(apLimit, tupleLimit) and
apLimit < tails and
tupleLimit < (tails - 1) * nodes and
not tc.forceHighPrecision()
tupleLimit < (tails - 1) * nodes
)
}
@@ -2403,8 +2351,6 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2500,7 +2446,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2711,7 +2657,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2896,12 +2842,8 @@ private module Stage4 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2974,8 +2916,6 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
int getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
override string toString() { result = p + ": " + ap }
predicate hasLocationInfo(
@@ -3033,15 +2973,12 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
* expected to be expensive. Holds with `unfold = true` otherwise.
*/
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
if apa.getHead().forceHighPrecision()
then unfold = true
else
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
}
/**
@@ -3103,11 +3040,7 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3119,10 +3052,17 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3226,7 +3166,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
}
override string toString() {
result = "[" + this.toStringImpl(true) + this.length().toString() + ")]"
result = "[" + this.toStringImpl(true) + length().toString() + ")]"
or
result = "[" + this.toStringImpl(false)
}
@@ -3308,7 +3248,7 @@ class PathNode extends TPathNode {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3365,11 +3305,9 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + ppAp() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3437,48 +3375,24 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override PathNodeImpl getASuccessorImpl() {
// an intermediate step to another intermediate node
result = this.getSuccMid()
result = getSuccMid()
or
// a final step to a sink
result = this.getSuccMid().projectToSink()
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
override predicate isSource() {
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3542,7 +3456,7 @@ private predicate pathStep(
exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp()
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
or
pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone
or
@@ -3619,20 +3533,18 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
apa = ap.getApprox()
)
}
pragma[nomagic]
pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3645,14 +3557,12 @@ private predicate parameterCand(
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
AccessPath ap
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
pathIntoArg(mid, i, outercc, call, ap, apa) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration())
)
}
@@ -3661,23 +3571,18 @@ private predicate pathIntoCallable0(
* before and after entering the callable are `outercc` and `innercc`,
* respectively.
*/
pragma[nomagic]
private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
p.isParameterOf(callable, i) and
(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
sc = TSummaryCtxNone()
)
|
if recordDataFlowCallSite(call, callable)
@@ -3701,23 +3606,18 @@ private predicate paramFlowsThrough(
ap = mid.getAp() and
apa = ap.getApprox() and
pos = sc.getParameterPos() and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
pragma[nomagic]
private predicate pathThroughCallable0(
DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap,
AccessPathApprox apa, Configuration config
AccessPathApprox apa
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call, config) and
paramFlowsThrough(kind, innercc, sc, ap, apa, config)
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3727,9 +3627,9 @@ private predicate pathThroughCallable0(
*/
pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config |
pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3740,15 +3640,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
unbindConf(arg.getConfiguration()))
}
/**
@@ -3781,17 +3679,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3800,12 +3689,11 @@ 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(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4145,7 +4033,7 @@ private module FlowExploration {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn

View File

@@ -10,7 +10,6 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -95,22 +94,6 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -127,12 +110,12 @@ abstract class Configuration extends string {
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
predicate hasFlowTo(Node sink) { hasFlow(_, sink) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
@@ -261,8 +244,6 @@ private class ParamNodeEx extends NodeEx {
}
int getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
private class RetNodeEx extends NodeEx {
@@ -366,8 +347,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -383,8 +363,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -420,20 +399,6 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -454,7 +419,7 @@ private module Stage1 {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
@@ -584,7 +549,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -779,12 +744,8 @@ private module Stage1 {
returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
@@ -970,8 +931,6 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1039,7 +998,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1250,7 +1209,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1435,12 +1394,8 @@ private module Stage2 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -1651,8 +1606,6 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1734,7 +1687,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1945,7 +1898,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2130,12 +2083,8 @@ private module Stage3 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2190,8 +2139,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
) and
accessPathApproxCostLimits(apLimit, tupleLimit) and
apLimit < tails and
tupleLimit < (tails - 1) * nodes and
not tc.forceHighPrecision()
tupleLimit < (tails - 1) * nodes
)
}
@@ -2403,8 +2351,6 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2500,7 +2446,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2711,7 +2657,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2896,12 +2842,8 @@ private module Stage4 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2974,8 +2916,6 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
int getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
override string toString() { result = p + ": " + ap }
predicate hasLocationInfo(
@@ -3033,15 +2973,12 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
* expected to be expensive. Holds with `unfold = true` otherwise.
*/
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
if apa.getHead().forceHighPrecision()
then unfold = true
else
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
}
/**
@@ -3103,11 +3040,7 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3119,10 +3052,17 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3226,7 +3166,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
}
override string toString() {
result = "[" + this.toStringImpl(true) + this.length().toString() + ")]"
result = "[" + this.toStringImpl(true) + length().toString() + ")]"
or
result = "[" + this.toStringImpl(false)
}
@@ -3308,7 +3248,7 @@ class PathNode extends TPathNode {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3365,11 +3305,9 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + ppAp() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3437,48 +3375,24 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override PathNodeImpl getASuccessorImpl() {
// an intermediate step to another intermediate node
result = this.getSuccMid()
result = getSuccMid()
or
// a final step to a sink
result = this.getSuccMid().projectToSink()
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
override predicate isSource() {
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3542,7 +3456,7 @@ private predicate pathStep(
exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp()
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
or
pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone
or
@@ -3619,20 +3533,18 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
apa = ap.getApprox()
)
}
pragma[nomagic]
pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3645,14 +3557,12 @@ private predicate parameterCand(
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
AccessPath ap
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
pathIntoArg(mid, i, outercc, call, ap, apa) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration())
)
}
@@ -3661,23 +3571,18 @@ private predicate pathIntoCallable0(
* before and after entering the callable are `outercc` and `innercc`,
* respectively.
*/
pragma[nomagic]
private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
p.isParameterOf(callable, i) and
(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
sc = TSummaryCtxNone()
)
|
if recordDataFlowCallSite(call, callable)
@@ -3701,23 +3606,18 @@ private predicate paramFlowsThrough(
ap = mid.getAp() and
apa = ap.getApprox() and
pos = sc.getParameterPos() and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
pragma[nomagic]
private predicate pathThroughCallable0(
DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap,
AccessPathApprox apa, Configuration config
AccessPathApprox apa
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call, config) and
paramFlowsThrough(kind, innercc, sc, ap, apa, config)
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3727,9 +3627,9 @@ private predicate pathThroughCallable0(
*/
pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config |
pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3740,15 +3640,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
unbindConf(arg.getConfiguration()))
}
/**
@@ -3781,17 +3679,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3800,12 +3689,11 @@ 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(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4145,7 +4033,7 @@ private module FlowExploration {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn

View File

@@ -10,7 +10,6 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -95,22 +94,6 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -127,12 +110,12 @@ abstract class Configuration extends string {
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
predicate hasFlowTo(Node sink) { hasFlow(_, sink) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
@@ -261,8 +244,6 @@ private class ParamNodeEx extends NodeEx {
}
int getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
private class RetNodeEx extends NodeEx {
@@ -366,8 +347,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -383,8 +363,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -420,20 +399,6 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -454,7 +419,7 @@ private module Stage1 {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
@@ -584,7 +549,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -779,12 +744,8 @@ private module Stage1 {
returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
@@ -970,8 +931,6 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1039,7 +998,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1250,7 +1209,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1435,12 +1394,8 @@ private module Stage2 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -1651,8 +1606,6 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1734,7 +1687,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1945,7 +1898,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2130,12 +2083,8 @@ private module Stage3 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2190,8 +2139,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
) and
accessPathApproxCostLimits(apLimit, tupleLimit) and
apLimit < tails and
tupleLimit < (tails - 1) * nodes and
not tc.forceHighPrecision()
tupleLimit < (tails - 1) * nodes
)
}
@@ -2403,8 +2351,6 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2500,7 +2446,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2711,7 +2657,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2896,12 +2842,8 @@ private module Stage4 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2974,8 +2916,6 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
int getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
override string toString() { result = p + ": " + ap }
predicate hasLocationInfo(
@@ -3033,15 +2973,12 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
* expected to be expensive. Holds with `unfold = true` otherwise.
*/
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
if apa.getHead().forceHighPrecision()
then unfold = true
else
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
}
/**
@@ -3103,11 +3040,7 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3119,10 +3052,17 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3226,7 +3166,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
}
override string toString() {
result = "[" + this.toStringImpl(true) + this.length().toString() + ")]"
result = "[" + this.toStringImpl(true) + length().toString() + ")]"
or
result = "[" + this.toStringImpl(false)
}
@@ -3308,7 +3248,7 @@ class PathNode extends TPathNode {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3365,11 +3305,9 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + ppAp() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3437,48 +3375,24 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override PathNodeImpl getASuccessorImpl() {
// an intermediate step to another intermediate node
result = this.getSuccMid()
result = getSuccMid()
or
// a final step to a sink
result = this.getSuccMid().projectToSink()
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
override predicate isSource() {
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3542,7 +3456,7 @@ private predicate pathStep(
exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp()
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
or
pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone
or
@@ -3619,20 +3533,18 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
apa = ap.getApprox()
)
}
pragma[nomagic]
pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3645,14 +3557,12 @@ private predicate parameterCand(
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
AccessPath ap
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
pathIntoArg(mid, i, outercc, call, ap, apa) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration())
)
}
@@ -3661,23 +3571,18 @@ private predicate pathIntoCallable0(
* before and after entering the callable are `outercc` and `innercc`,
* respectively.
*/
pragma[nomagic]
private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
p.isParameterOf(callable, i) and
(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
sc = TSummaryCtxNone()
)
|
if recordDataFlowCallSite(call, callable)
@@ -3701,23 +3606,18 @@ private predicate paramFlowsThrough(
ap = mid.getAp() and
apa = ap.getApprox() and
pos = sc.getParameterPos() and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
pragma[nomagic]
private predicate pathThroughCallable0(
DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap,
AccessPathApprox apa, Configuration config
AccessPathApprox apa
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call, config) and
paramFlowsThrough(kind, innercc, sc, ap, apa, config)
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3727,9 +3627,9 @@ private predicate pathThroughCallable0(
*/
pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config |
pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3740,15 +3640,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
unbindConf(arg.getConfiguration()))
}
/**
@@ -3781,17 +3679,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3800,12 +3689,11 @@ 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(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4145,7 +4033,7 @@ private module FlowExploration {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn

View File

@@ -2,42 +2,6 @@ private import DataFlowImplSpecific::Private
private import DataFlowImplSpecific::Public
import Cached
module DataFlowImplCommonPublic {
private newtype TFlowFeature =
TFeatureHasSourceCallContext() or
TFeatureHasSinkCallContext() or
TFeatureEqualSourceSinkCallContext()
/** A flow configuration feature for use in `Configuration::getAFeature()`. */
class FlowFeature extends TFlowFeature {
string toString() { none() }
}
/**
* A flow configuration feature that implies that sources have some existing
* call context.
*/
class FeatureHasSourceCallContext extends FlowFeature, TFeatureHasSourceCallContext {
override string toString() { result = "FeatureHasSourceCallContext" }
}
/**
* A flow configuration feature that implies that sinks have some existing
* call context.
*/
class FeatureHasSinkCallContext extends FlowFeature, TFeatureHasSinkCallContext {
override string toString() { result = "FeatureHasSinkCallContext" }
}
/**
* A flow configuration feature that implies that source-sink pairs have some
* shared existing call context.
*/
class FeatureEqualSourceSinkCallContext extends FlowFeature, TFeatureEqualSourceSinkCallContext {
override string toString() { result = "FeatureEqualSourceSinkCallContext" }
}
}
/**
* The cost limits for the `AccessPathFront` to `AccessPathApprox` expansion.
*
@@ -287,7 +251,7 @@ private module Cached {
predicate forceCachingInSameStage() { any() }
cached
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = nodeGetEnclosingCallable(n) }
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() }
cached
predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) {
@@ -352,7 +316,9 @@ private module Cached {
}
cached
predicate parameterNode(Node p, DataFlowCallable c, int pos) { isParameterNode(p, c, pos) }
predicate parameterNode(Node n, DataFlowCallable c, int i) {
n.(ParameterNode).isParameterOf(c, i)
}
cached
predicate argumentNode(Node n, DataFlowCall call, int pos) {
@@ -835,9 +801,6 @@ private module Cached {
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
}
cached
predicate allowParameterReturnInSelfCached(ParamNode p) { allowParameterReturnInSelf(p) }
cached
newtype TCallContext =
TAnyCallContext() or
@@ -974,7 +937,7 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall {
}
override predicate relevantFor(DataFlowCallable callable) {
recordDataFlowCallSite(this.getCall(), callable)
recordDataFlowCallSite(getCall(), callable)
}
override predicate matchesCall(DataFlowCall call) { call = this.getCall() }
@@ -1273,13 +1236,6 @@ class TypedContent extends MkTypedContent {
/** Gets a textual representation of this content. */
string toString() { result = c.toString() }
/**
* Holds if access paths with this `TypedContent` at their head always should
* be tracked at high precision. This disables adaptive access path precision
* for such access paths.
*/
predicate forceHighPrecision() { forceHighPrecision(c) }
}
/**
@@ -1294,7 +1250,7 @@ abstract class AccessPathFront extends TAccessPathFront {
TypedContent getHead() { this = TFrontHead(result) }
predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) }
predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) }
}
class AccessPathFrontNil extends AccessPathFront, TFrontNil {

View File

@@ -31,7 +31,7 @@ module Consistency {
query predicate uniqueEnclosingCallable(Node n, string msg) {
exists(int c |
n instanceof RelevantNode and
c = count(nodeGetEnclosingCallable(n)) and
c = count(n.getEnclosingCallable()) and
c != 1 and
msg = "Node should have one enclosing callable but has " + c + "."
)
@@ -85,13 +85,13 @@ module Consistency {
}
query predicate parameterCallable(ParameterNode p, string msg) {
exists(DataFlowCallable c | isParameterNode(p, c, _) and c != nodeGetEnclosingCallable(p)) and
exists(DataFlowCallable c | p.isParameterOf(c, _) and c != p.getEnclosingCallable()) and
msg = "Callable mismatch for parameter."
}
query predicate localFlowIsLocal(Node n1, Node n2, string msg) {
simpleLocalFlowStep(n1, n2) and
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
n1.getEnclosingCallable() != n2.getEnclosingCallable() and
msg = "Local flow step does not preserve enclosing callable."
}
@@ -106,7 +106,7 @@ module Consistency {
query predicate unreachableNodeCCtx(Node n, DataFlowCall call, string msg) {
isUnreachableInCall(n, call) and
exists(DataFlowCallable c |
c = nodeGetEnclosingCallable(n) and
c = n.getEnclosingCallable() and
not viableCallable(call) = c
) and
msg = "Call context for isUnreachableInCall is inconsistent with call graph."
@@ -120,7 +120,7 @@ module Consistency {
n.(ArgumentNode).argumentOf(call, _) and
msg = "ArgumentNode and call does not share enclosing callable."
) and
nodeGetEnclosingCallable(n) != call.getEnclosingCallable()
n.getEnclosingCallable() != call.getEnclosingCallable()
}
// This predicate helps the compiler forget that in some languages
@@ -151,7 +151,7 @@ module Consistency {
}
query predicate postIsInSameCallable(PostUpdateNode n, string msg) {
nodeGetEnclosingCallable(n) != nodeGetEnclosingCallable(n.getPreUpdateNode()) and
n.getEnclosingCallable() != n.getPreUpdateNode().getEnclosingCallable() and
msg = "PostUpdateNode does not share callable with its pre-update node."
}
@@ -175,7 +175,6 @@ module Consistency {
query predicate postWithInFlow(Node n, string msg) {
isPostUpdateNode(n) and
not clearsContent(n, _) and
simpleLocalFlowStep(_, n) and
msg = "PostUpdateNode should not be the target of local flow."
}

View File

@@ -10,7 +10,6 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -95,22 +94,6 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -127,12 +110,12 @@ abstract class Configuration extends string {
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
predicate hasFlowTo(Node sink) { hasFlow(_, sink) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
@@ -261,8 +244,6 @@ private class ParamNodeEx extends NodeEx {
}
int getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
private class RetNodeEx extends NodeEx {
@@ -366,8 +347,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -383,8 +363,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -420,20 +399,6 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -454,7 +419,7 @@ private module Stage1 {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
@@ -584,7 +549,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -779,12 +744,8 @@ private module Stage1 {
returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
@@ -970,8 +931,6 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1039,7 +998,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1250,7 +1209,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1435,12 +1394,8 @@ private module Stage2 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -1651,8 +1606,6 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1734,7 +1687,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1945,7 +1898,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2130,12 +2083,8 @@ private module Stage3 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2190,8 +2139,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
) and
accessPathApproxCostLimits(apLimit, tupleLimit) and
apLimit < tails and
tupleLimit < (tails - 1) * nodes and
not tc.forceHighPrecision()
tupleLimit < (tails - 1) * nodes
)
}
@@ -2403,8 +2351,6 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2500,7 +2446,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2711,7 +2657,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2896,12 +2842,8 @@ private module Stage4 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2974,8 +2916,6 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
int getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
override string toString() { result = p + ": " + ap }
predicate hasLocationInfo(
@@ -3033,15 +2973,12 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
* expected to be expensive. Holds with `unfold = true` otherwise.
*/
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
if apa.getHead().forceHighPrecision()
then unfold = true
else
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
}
/**
@@ -3103,11 +3040,7 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3119,10 +3052,17 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3226,7 +3166,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
}
override string toString() {
result = "[" + this.toStringImpl(true) + this.length().toString() + ")]"
result = "[" + this.toStringImpl(true) + length().toString() + ")]"
or
result = "[" + this.toStringImpl(false)
}
@@ -3308,7 +3248,7 @@ class PathNode extends TPathNode {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3365,11 +3305,9 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + ppAp() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3437,48 +3375,24 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override PathNodeImpl getASuccessorImpl() {
// an intermediate step to another intermediate node
result = this.getSuccMid()
result = getSuccMid()
or
// a final step to a sink
result = this.getSuccMid().projectToSink()
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
override predicate isSource() {
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3542,7 +3456,7 @@ private predicate pathStep(
exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp()
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
or
pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone
or
@@ -3619,20 +3533,18 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
apa = ap.getApprox()
)
}
pragma[nomagic]
pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3645,14 +3557,12 @@ private predicate parameterCand(
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
AccessPath ap
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
pathIntoArg(mid, i, outercc, call, ap, apa) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration())
)
}
@@ -3661,23 +3571,18 @@ private predicate pathIntoCallable0(
* before and after entering the callable are `outercc` and `innercc`,
* respectively.
*/
pragma[nomagic]
private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
p.isParameterOf(callable, i) and
(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
sc = TSummaryCtxNone()
)
|
if recordDataFlowCallSite(call, callable)
@@ -3701,23 +3606,18 @@ private predicate paramFlowsThrough(
ap = mid.getAp() and
apa = ap.getApprox() and
pos = sc.getParameterPos() and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
pragma[nomagic]
private predicate pathThroughCallable0(
DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap,
AccessPathApprox apa, Configuration config
AccessPathApprox apa
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call, config) and
paramFlowsThrough(kind, innercc, sc, ap, apa, config)
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3727,9 +3627,9 @@ private predicate pathThroughCallable0(
*/
pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config |
pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3740,15 +3640,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
unbindConf(arg.getConfiguration()))
}
/**
@@ -3781,17 +3679,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3800,12 +3689,11 @@ 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(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4145,7 +4033,7 @@ private module FlowExploration {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn

View File

@@ -3,12 +3,6 @@ private import DataFlowUtil
private import DataFlowDispatch
private import FlowVar
/** Gets the callable in which this node occurs. */
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) { p.isParameterOf(c, pos) }
/** Gets the instance argument of a non-static call. */
private Node getInstanceArgument(Call call) {
result.asExpr() = call.getQualifier()
@@ -225,13 +219,15 @@ class DataFlowExpr = Expr;
class DataFlowType = Type;
/** A function call relevant for data flow. */
class DataFlowCall extends Expr instanceof Call {
class DataFlowCall extends Expr {
DataFlowCall() { this instanceof Call }
/**
* Gets the nth argument for this call.
*
* The range of `n` is from `0` to `getNumberOfArguments() - 1`.
*/
Expr getArgument(int n) { result = super.getArgument(n) }
Expr getArgument(int n) { result = this.(Call).getArgument(n) }
/** Gets the data flow node corresponding to this call. */
ExprNode getNode() { result.getExpr() = this }
@@ -244,12 +240,6 @@ predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub impl
int accessPathLimit() { result = 5 }
/**
* Holds if access paths with `c` at their head always should be tracked at high
* precision. This disables adaptive access path precision for such access paths.
*/
predicate forceHighPrecision(Content c) { none() }
/** The unit type. */
private newtype TUnit = TMkUnit()
@@ -293,12 +283,3 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { no
/** Extra data-flow steps needed for lambda flow analysis. */
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
/**
* Holds if flow is allowed to pass from parameter `p` and back to itself as a
* side-effect, resulting in a summary from `p` to itself.
*
* One example would be to allow flow like `p.foo = p.bar;`, which is disallowed
* by default as a heuristic.
*/
predicate allowParameterReturnInSelf(ParameterNode p) { none() }

View File

@@ -101,18 +101,18 @@ class Node extends TNode {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/**
* Gets an upper bound on the type of this node.
*/
Type getTypeBound() { result = this.getType() }
Type getTypeBound() { result = getType() }
}
/**
@@ -293,11 +293,11 @@ abstract class PostUpdateNode extends Node {
*/
abstract Node getPreUpdateNode();
override Function getFunction() { result = this.getPreUpdateNode().getFunction() }
override Function getFunction() { result = getPreUpdateNode().getFunction() }
override Type getType() { result = this.getPreUpdateNode().getType() }
override Type getType() { result = getPreUpdateNode().getType() }
override Location getLocation() { result = this.getPreUpdateNode().getLocation() }
override Location getLocation() { result = getPreUpdateNode().getLocation() }
}
abstract private class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode {
@@ -309,7 +309,7 @@ abstract private class PartialDefinitionNode extends PostUpdateNode, TPartialDef
PartialDefinition getPartialDefinition() { result = pd }
override string toString() { result = this.getPreUpdateNode().toString() + " [post update]" }
override string toString() { result = getPreUpdateNode().toString() + " [post update]" }
}
private class VariablePartialDefinitionNode extends PartialDefinitionNode {
@@ -380,13 +380,13 @@ private class ObjectInitializerNode extends PostUpdateNode, TExprNode {
class PreObjectInitializerNode extends Node, TPreObjectInitializerNode {
Expr getExpr() { this = TPreObjectInitializerNode(result) }
override Function getFunction() { result = this.getExpr().getEnclosingFunction() }
override Function getFunction() { result = getExpr().getEnclosingFunction() }
override Type getType() { result = this.getExpr().getType() }
override Type getType() { result = getExpr().getType() }
override Location getLocation() { result = this.getExpr().getLocation() }
override Location getLocation() { result = getExpr().getLocation() }
override string toString() { result = this.getExpr().toString() + " [pre init]" }
override string toString() { result = getExpr().toString() + " [pre init]" }
}
/**
@@ -401,7 +401,7 @@ private class PostConstructorInitThis extends PostUpdateNode, TPostConstructorIn
}
override string toString() {
result = this.getPreUpdateNode().getConstructorFieldInit().toString() + " [post-this]"
result = getPreUpdateNode().getConstructorFieldInit().toString() + " [post-this]"
}
}
@@ -416,17 +416,15 @@ private class PostConstructorInitThis extends PostUpdateNode, TPostConstructorIn
class PreConstructorInitThis extends Node, TPreConstructorInitThis {
ConstructorFieldInit getConstructorFieldInit() { this = TPreConstructorInitThis(result) }
override Constructor getFunction() {
result = this.getConstructorFieldInit().getEnclosingFunction()
}
override Constructor getFunction() { result = getConstructorFieldInit().getEnclosingFunction() }
override PointerType getType() {
result.getBaseType() = this.getConstructorFieldInit().getEnclosingFunction().getDeclaringType()
result.getBaseType() = getConstructorFieldInit().getEnclosingFunction().getDeclaringType()
}
override Location getLocation() { result = this.getConstructorFieldInit().getLocation() }
override Location getLocation() { result = getConstructorFieldInit().getLocation() }
override string toString() { result = this.getConstructorFieldInit().toString() + " [pre-this]" }
override string toString() { result = getConstructorFieldInit().toString() + " [pre-this]" }
}
/**

View File

@@ -354,7 +354,7 @@ module FlowVar_internal {
result = def.getAUse(v)
or
exists(SsaDefinition descendentDef |
this.getASuccessorSsaVar+() = TSsaVar(descendentDef, _) and
getASuccessorSsaVar+() = TSsaVar(descendentDef, _) and
result = descendentDef.getAUse(v)
)
)
@@ -515,7 +515,7 @@ module FlowVar_internal {
this.bbInLoopCondition(bbInside) and
not this.bbInLoop(bbOutside) and
bbOutside = bbInside.getASuccessor() and
not this.reachesWithoutAssignment(bbInside, v)
not reachesWithoutAssignment(bbInside, v)
}
/**
@@ -546,7 +546,7 @@ module FlowVar_internal {
private predicate bbInLoop(BasicBlock bb) {
bbDominates(this.(Loop).getStmt(), bb)
or
this.bbInLoopCondition(bb)
bbInLoopCondition(bb)
}
/** Holds if `sbb` is inside this loop. */
@@ -563,7 +563,7 @@ module FlowVar_internal {
bb = this.(Loop).getStmt() and
v = this.getARelevantVariable()
or
this.reachesWithoutAssignment(bb.getAPredecessor(), v) and
reachesWithoutAssignment(bb.getAPredecessor(), v) and
this.bbInLoop(bb)
) and
not assignsToVar(bb, v)

View File

@@ -80,7 +80,7 @@ class SubBasicBlock extends ControlFlowNodeBase {
* returns a 0-based position, while `getRankInBasicBlock` returns a 1-based
* position.
*/
deprecated int getPosInBasicBlock(BasicBlock bb) { result = this.getRankInBasicBlock(bb) - 1 }
deprecated int getPosInBasicBlock(BasicBlock bb) { result = getRankInBasicBlock(bb) - 1 }
pragma[noinline]
private int getIndexInBasicBlock(BasicBlock bb) { this = bb.getNode(result) }
@@ -102,7 +102,7 @@ class SubBasicBlock extends ControlFlowNodeBase {
exists(BasicBlock bb |
exists(int outerIndex |
result = bb.getNode(outerIndex) and
index = this.outerToInnerIndex(bb, outerIndex)
index = outerToInnerIndex(bb, outerIndex)
)
)
}

View File

@@ -75,26 +75,24 @@ abstract class Configuration extends DataFlow::Configuration {
predicate isSanitizer(DataFlow::Node node) { none() }
final override predicate isBarrier(DataFlow::Node node) {
this.isSanitizer(node) or
isSanitizer(node) or
defaultTaintSanitizer(node)
}
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
predicate isSanitizerOut(DataFlow::Node node) { none() }
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
/**
* Holds if the additional taint propagation step from `node1` to `node2`
@@ -103,7 +101,7 @@ abstract class Configuration extends DataFlow::Configuration {
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
this.isAdditionalTaintStep(node1, node2) or
isAdditionalTaintStep(node1, node2) or
defaultAdditionalTaintStep(node1, node2)
}

View File

@@ -75,26 +75,24 @@ abstract class Configuration extends DataFlow::Configuration {
predicate isSanitizer(DataFlow::Node node) { none() }
final override predicate isBarrier(DataFlow::Node node) {
this.isSanitizer(node) or
isSanitizer(node) or
defaultTaintSanitizer(node)
}
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
predicate isSanitizerOut(DataFlow::Node node) { none() }
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
/**
* Holds if the additional taint propagation step from `node1` to `node2`
@@ -103,7 +101,7 @@ abstract class Configuration extends DataFlow::Configuration {
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
this.isAdditionalTaintStep(node1, node2) or
isAdditionalTaintStep(node1, node2) or
defaultAdditionalTaintStep(node1, node2)
}

View File

@@ -203,7 +203,7 @@ class PointerFieldAccess extends FieldAccess {
PointerFieldAccess() {
exists(PointerType t |
t = this.getQualifier().getFullyConverted().getUnspecifiedType() and
t = getQualifier().getFullyConverted().getUnspecifiedType() and
t.getBaseType() instanceof Class
)
}
@@ -218,9 +218,7 @@ class PointerFieldAccess extends FieldAccess {
class DotFieldAccess extends FieldAccess {
override string getAPrimaryQlClass() { result = "DotFieldAccess" }
DotFieldAccess() {
exists(Class c | c = this.getQualifier().getFullyConverted().getUnspecifiedType())
}
DotFieldAccess() { exists(Class c | c = getQualifier().getFullyConverted().getUnspecifiedType()) }
}
/**

View File

@@ -148,7 +148,7 @@ class PostfixIncrExpr extends IncrementOperation, PostfixCrementOperation, @post
override int getPrecedence() { result = 17 }
override string toString() { result = "... " + this.getOperator() }
override string toString() { result = "... " + getOperator() }
}
/**
@@ -166,7 +166,7 @@ class PostfixDecrExpr extends DecrementOperation, PostfixCrementOperation, @post
override int getPrecedence() { result = 17 }
override string toString() { result = "... " + this.getOperator() }
override string toString() { result = "... " + getOperator() }
}
/**

View File

@@ -35,12 +35,12 @@ class BuiltInVarArgsStart extends VarArgsExpr, @vastartexpr {
/**
* Gets the `va_list` argument.
*/
final Expr getVAList() { result = this.getChild(0) }
final Expr getVAList() { result = getChild(0) }
/**
* Gets the argument that specifies the last named parameter before the ellipsis.
*/
final VariableAccess getLastNamedParameter() { result = this.getChild(1) }
final VariableAccess getLastNamedParameter() { result = getChild(1) }
}
/**
@@ -60,7 +60,7 @@ class BuiltInVarArgsEnd extends VarArgsExpr, @vaendexpr {
/**
* Gets the `va_list` argument.
*/
final Expr getVAList() { result = this.getChild(0) }
final Expr getVAList() { result = getChild(0) }
}
/**
@@ -78,7 +78,7 @@ class BuiltInVarArg extends VarArgsExpr, @vaargexpr {
/**
* Gets the `va_list` argument.
*/
final Expr getVAList() { result = this.getChild(0) }
final Expr getVAList() { result = getChild(0) }
}
/**
@@ -98,12 +98,12 @@ class BuiltInVarArgCopy extends VarArgsExpr, @vacopyexpr {
/**
* Gets the destination `va_list` argument.
*/
final Expr getDestinationVAList() { result = this.getChild(0) }
final Expr getDestinationVAList() { result = getChild(0) }
/**
* Gets the the source `va_list` argument.
*/
final Expr getSourceVAList() { result = this.getChild(1) }
final Expr getSourceVAList() { result = getChild(1) }
}
/**

View File

@@ -71,10 +71,10 @@ class Call extends Expr, NameQualifiableElement, TCall {
* at index 2, respectively.
*/
Expr getAnArgumentSubExpr(int index) {
result = this.getArgument(index)
result = getArgument(index)
or
exists(Expr mid |
mid = this.getAnArgumentSubExpr(index) and
mid = getAnArgumentSubExpr(index) and
not mid instanceof Call and
not mid instanceof SizeofOperator and
result = mid.getAChild()
@@ -167,27 +167,27 @@ class FunctionCall extends Call, @funbindexpr {
override string getAPrimaryQlClass() { result = "FunctionCall" }
/** Gets an explicit template argument for this call. */
Locatable getAnExplicitTemplateArgument() { result = this.getExplicitTemplateArgument(_) }
Locatable getAnExplicitTemplateArgument() { result = getExplicitTemplateArgument(_) }
/** Gets an explicit template argument value for this call. */
Locatable getAnExplicitTemplateArgumentKind() { result = this.getExplicitTemplateArgumentKind(_) }
Locatable getAnExplicitTemplateArgumentKind() { result = getExplicitTemplateArgumentKind(_) }
/** Gets a template argument for this call. */
Locatable getATemplateArgument() { result = this.getTarget().getATemplateArgument() }
Locatable getATemplateArgument() { result = getTarget().getATemplateArgument() }
/** Gets a template argument value for this call. */
Locatable getATemplateArgumentKind() { result = this.getTarget().getATemplateArgumentKind() }
Locatable getATemplateArgumentKind() { result = getTarget().getATemplateArgumentKind() }
/** Gets the nth explicit template argument for this call. */
Locatable getExplicitTemplateArgument(int n) {
n < this.getNumberOfExplicitTemplateArguments() and
result = this.getTemplateArgument(n)
n < getNumberOfExplicitTemplateArguments() and
result = getTemplateArgument(n)
}
/** Gets the nth explicit template argument value for this call. */
Locatable getExplicitTemplateArgumentKind(int n) {
n < this.getNumberOfExplicitTemplateArguments() and
result = this.getTemplateArgumentKind(n)
n < getNumberOfExplicitTemplateArguments() and
result = getTemplateArgumentKind(n)
}
/** Gets the number of explicit template arguments for this call. */
@@ -198,19 +198,19 @@ class FunctionCall extends Call, @funbindexpr {
}
/** Gets the number of template arguments for this call. */
int getNumberOfTemplateArguments() { result = count(int i | exists(this.getTemplateArgument(i))) }
int getNumberOfTemplateArguments() { result = count(int i | exists(getTemplateArgument(i))) }
/** Gets the nth template argument for this call (indexed from 0). */
Locatable getTemplateArgument(int n) { result = this.getTarget().getTemplateArgument(n) }
Locatable getTemplateArgument(int n) { result = getTarget().getTemplateArgument(n) }
/** Gets the nth template argument value for this call (indexed from 0). */
Locatable getTemplateArgumentKind(int n) { result = this.getTarget().getTemplateArgumentKind(n) }
Locatable getTemplateArgumentKind(int n) { result = getTarget().getTemplateArgumentKind(n) }
/** Holds if any template arguments for this call are implicit / deduced. */
predicate hasImplicitTemplateArguments() {
exists(int i |
exists(this.getTemplateArgument(i)) and
not exists(this.getExplicitTemplateArgument(i))
exists(getTemplateArgument(i)) and
not exists(getExplicitTemplateArgument(i))
)
}
@@ -233,9 +233,9 @@ class FunctionCall extends Call, @funbindexpr {
* visible at the call site.
*/
Type getExpectedReturnType() {
if this.getTargetType() instanceof RoutineType
then result = this.getTargetType().(RoutineType).getReturnType()
else result = this.getTarget().getType()
if getTargetType() instanceof RoutineType
then result = getTargetType().(RoutineType).getReturnType()
else result = getTarget().getType()
}
/**
@@ -247,9 +247,9 @@ class FunctionCall extends Call, @funbindexpr {
* was visible at the call site.
*/
Type getExpectedParameterType(int n) {
if this.getTargetType() instanceof RoutineType
then result = this.getTargetType().(RoutineType).getParameterType(n)
else result = this.getTarget().getParameter(n).getType()
if getTargetType() instanceof RoutineType
then result = getTargetType().(RoutineType).getParameterType(n)
else result = getTarget().getParameter(n).getType()
}
/**
@@ -263,7 +263,7 @@ class FunctionCall extends Call, @funbindexpr {
/**
* Gets the type of this expression, that is, the return type of the function being called.
*/
override Type getType() { result = this.getExpectedReturnType() }
override Type getType() { result = getExpectedReturnType() }
/**
* Holds if this is a call to a virtual function.
@@ -280,7 +280,7 @@ class FunctionCall extends Call, @funbindexpr {
/** Gets a textual representation of this function call. */
override string toString() {
if exists(this.getTarget())
if exists(getTarget())
then result = "call to " + this.getTarget().getName()
else result = "call to unknown function"
}
@@ -288,15 +288,15 @@ class FunctionCall extends Call, @funbindexpr {
override predicate mayBeImpure() {
this.getChild(_).mayBeImpure() or
this.getTarget().mayHaveSideEffects() or
this.isVirtual() or
this.getTarget().getAnAttribute().getName() = "weak"
isVirtual() or
getTarget().getAnAttribute().getName() = "weak"
}
override predicate mayBeGloballyImpure() {
this.getChild(_).mayBeGloballyImpure() or
this.getTarget().mayHaveSideEffects() or
this.isVirtual() or
this.getTarget().getAnAttribute().getName() = "weak"
isVirtual() or
getTarget().getAnAttribute().getName() = "weak"
}
}
@@ -367,7 +367,7 @@ class OverloadedPointerDereferenceExpr extends FunctionCall {
* ```
*/
class OverloadedArrayExpr extends FunctionCall {
OverloadedArrayExpr() { this.getTarget().hasName("operator[]") }
OverloadedArrayExpr() { getTarget().hasName("operator[]") }
override string getAPrimaryQlClass() { result = "OverloadedArrayExpr" }
@@ -585,7 +585,7 @@ class ConstructorFieldInit extends ConstructorInit, @ctorfieldinit {
*/
Expr getExpr() { result = this.getChild(0) }
override string toString() { result = "constructor init of field " + this.getTarget().getName() }
override string toString() { result = "constructor init of field " + getTarget().getName() }
override predicate mayBeImpure() { this.getExpr().mayBeImpure() }

View File

@@ -188,8 +188,8 @@ private predicate isPointerToMemberOrNullPointer(Type type) {
class ArithmeticConversion extends Cast {
ArithmeticConversion() {
conversionkinds(underlyingElement(this), 0) and
isArithmeticOrEnum(this.getUnspecifiedType()) and
isArithmeticOrEnum(this.getExpr().getUnspecifiedType())
isArithmeticOrEnum(getUnspecifiedType()) and
isArithmeticOrEnum(getExpr().getUnspecifiedType())
}
override string getSemanticConversionString() { result = "arithmetic conversion" }
@@ -204,8 +204,8 @@ class ArithmeticConversion extends Cast {
*/
class IntegralConversion extends ArithmeticConversion {
IntegralConversion() {
isIntegralOrEnum(this.getUnspecifiedType()) and
isIntegralOrEnum(this.getExpr().getUnspecifiedType())
isIntegralOrEnum(getUnspecifiedType()) and
isIntegralOrEnum(getExpr().getUnspecifiedType())
}
override string getAPrimaryQlClass() {
@@ -224,8 +224,8 @@ class IntegralConversion extends ArithmeticConversion {
*/
class FloatingPointConversion extends ArithmeticConversion {
FloatingPointConversion() {
this.getUnspecifiedType() instanceof FloatingPointType and
this.getExpr().getUnspecifiedType() instanceof FloatingPointType
getUnspecifiedType() instanceof FloatingPointType and
getExpr().getUnspecifiedType() instanceof FloatingPointType
}
override string getAPrimaryQlClass() {
@@ -244,8 +244,8 @@ class FloatingPointConversion extends ArithmeticConversion {
*/
class FloatingPointToIntegralConversion extends ArithmeticConversion {
FloatingPointToIntegralConversion() {
isIntegralOrEnum(this.getUnspecifiedType()) and
this.getExpr().getUnspecifiedType() instanceof FloatingPointType
isIntegralOrEnum(getUnspecifiedType()) and
getExpr().getUnspecifiedType() instanceof FloatingPointType
}
override string getAPrimaryQlClass() {
@@ -264,8 +264,8 @@ class FloatingPointToIntegralConversion extends ArithmeticConversion {
*/
class IntegralToFloatingPointConversion extends ArithmeticConversion {
IntegralToFloatingPointConversion() {
this.getUnspecifiedType() instanceof FloatingPointType and
isIntegralOrEnum(this.getExpr().getUnspecifiedType())
getUnspecifiedType() instanceof FloatingPointType and
isIntegralOrEnum(getExpr().getUnspecifiedType())
}
override string getAPrimaryQlClass() {
@@ -290,8 +290,8 @@ class IntegralToFloatingPointConversion extends ArithmeticConversion {
class PointerConversion extends Cast {
PointerConversion() {
conversionkinds(underlyingElement(this), 0) and
isPointerOrNullPointer(this.getUnspecifiedType()) and
isPointerOrNullPointer(this.getExpr().getUnspecifiedType())
isPointerOrNullPointer(getUnspecifiedType()) and
isPointerOrNullPointer(getExpr().getUnspecifiedType())
}
override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerConversion" }
@@ -315,8 +315,8 @@ class PointerToMemberConversion extends Cast {
PointerToMemberConversion() {
conversionkinds(underlyingElement(this), 0) and
exists(Type fromType, Type toType |
fromType = this.getExpr().getUnspecifiedType() and
toType = this.getUnspecifiedType() and
fromType = getExpr().getUnspecifiedType() and
toType = getUnspecifiedType() and
isPointerToMemberOrNullPointer(fromType) and
isPointerToMemberOrNullPointer(toType) and
// A conversion from nullptr to nullptr is a `PointerConversion`, not a
@@ -345,8 +345,8 @@ class PointerToMemberConversion extends Cast {
class PointerToIntegralConversion extends Cast {
PointerToIntegralConversion() {
conversionkinds(underlyingElement(this), 0) and
isIntegralOrEnum(this.getUnspecifiedType()) and
isPointerOrNullPointer(this.getExpr().getUnspecifiedType())
isIntegralOrEnum(getUnspecifiedType()) and
isPointerOrNullPointer(getExpr().getUnspecifiedType())
}
override string getAPrimaryQlClass() {
@@ -366,8 +366,8 @@ class PointerToIntegralConversion extends Cast {
class IntegralToPointerConversion extends Cast {
IntegralToPointerConversion() {
conversionkinds(underlyingElement(this), 0) and
isPointerOrNullPointer(this.getUnspecifiedType()) and
isIntegralOrEnum(this.getExpr().getUnspecifiedType())
isPointerOrNullPointer(getUnspecifiedType()) and
isIntegralOrEnum(getExpr().getUnspecifiedType())
}
override string getAPrimaryQlClass() {
@@ -403,7 +403,7 @@ class BoolConversion extends Cast {
class VoidConversion extends Cast {
VoidConversion() {
conversionkinds(underlyingElement(this), 0) and
this.getUnspecifiedType() instanceof VoidType
getUnspecifiedType() instanceof VoidType
}
override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "VoidConversion" }
@@ -434,8 +434,8 @@ class InheritanceConversion extends Cast {
* conversion is to an indirect virtual base class.
*/
final ClassDerivation getDerivation() {
result.getBaseClass() = this.getBaseClass() and
result.getDerivedClass() = this.getDerivedClass()
result.getBaseClass() = getBaseClass() and
result.getDerivedClass() = getDerivedClass()
}
/**
@@ -490,12 +490,12 @@ class BaseClassConversion extends InheritanceConversion {
override Class getBaseClass() { result = getConversionClass(this) }
override Class getDerivedClass() { result = getConversionClass(this.getExpr()) }
override Class getDerivedClass() { result = getConversionClass(getExpr()) }
/**
* Holds if this conversion is to a virtual base class.
*/
predicate isVirtual() { this.getDerivation().isVirtual() or not exists(this.getDerivation()) }
predicate isVirtual() { getDerivation().isVirtual() or not exists(getDerivation()) }
}
/**
@@ -515,7 +515,7 @@ class DerivedClassConversion extends InheritanceConversion {
override string getSemanticConversionString() { result = "derived class conversion" }
override Class getBaseClass() { result = getConversionClass(this.getExpr()) }
override Class getBaseClass() { result = getConversionClass(getExpr()) }
override Class getDerivedClass() { result = getConversionClass(this) }
}
@@ -637,8 +637,8 @@ class DynamicCast extends Cast, @dynamic_cast {
*/
class UuidofOperator extends Expr, @uuidof {
override string toString() {
if exists(this.getTypeOperand())
then result = "__uuidof(" + this.getTypeOperand().getName() + ")"
if exists(getTypeOperand())
then result = "__uuidof(" + getTypeOperand().getName() + ")"
else result = "__uuidof(0)"
}

View File

@@ -26,12 +26,12 @@ class Expr extends StmtParent, @expr {
Function getEnclosingFunction() { result = exprEnclosingElement(this) }
/** Gets the nearest enclosing set of curly braces around this expression in the source, if any. */
BlockStmt getEnclosingBlock() { result = this.getEnclosingStmt().getEnclosingBlock() }
BlockStmt getEnclosingBlock() { result = getEnclosingStmt().getEnclosingBlock() }
override Stmt getEnclosingStmt() {
result = this.getParent().(Expr).getEnclosingStmt()
or
result = this.getParent()
result = this.getParent().(Stmt)
or
exists(Expr other | result = other.getEnclosingStmt() and other.getConversion() = this)
or
@@ -219,13 +219,13 @@ class Expr extends StmtParent, @expr {
* Holds if this expression is a _glvalue_. A _glvalue_ is either an _lvalue_ or an
* _xvalue_.
*/
predicate isGLValueCategory() { this.isLValueCategory() or this.isXValueCategory() }
predicate isGLValueCategory() { isLValueCategory() or isXValueCategory() }
/**
* Holds if this expression is an _rvalue_. An _rvalue_ is either a _prvalue_ or an
* _xvalue_.
*/
predicate isRValueCategory() { this.isPRValueCategory() or this.isXValueCategory() }
predicate isRValueCategory() { isPRValueCategory() or isXValueCategory() }
/**
* Gets a string representation of the value category of the expression.
@@ -240,15 +240,15 @@ class Expr extends StmtParent, @expr {
* `hasLValueToRvalueConversion()` holds.
*/
string getValueCategoryString() {
this.isLValueCategory() and
isLValueCategory() and
result = "lvalue"
or
this.isXValueCategory() and
isXValueCategory() and
result = "xvalue"
or
(
this.isPRValueCategory() and
if this.hasLValueToRValueConversion() then result = "prvalue(load)" else result = "prvalue"
isPRValueCategory() and
if hasLValueToRValueConversion() then result = "prvalue(load)" else result = "prvalue"
)
}
@@ -263,7 +263,7 @@ class Expr extends StmtParent, @expr {
* such as an expression inside a sizeof.
*/
predicate isUnevaluated() {
exists(Element e | e = this.getParentWithConversions+() |
exists(Element e | e = getParentWithConversions+() |
e instanceof SizeofOperator
or
exists(Expr e2 |
@@ -279,7 +279,7 @@ class Expr extends StmtParent, @expr {
e instanceof AlignofOperator
)
or
exists(Decltype d | d.getExpr() = this.getParentWithConversions*())
exists(Decltype d | d.getExpr() = getParentWithConversions*())
}
/**
@@ -725,7 +725,7 @@ class PointerDereferenceExpr extends UnaryOperation, @indirect {
*
* Gets the expression that is being dereferenced.
*/
deprecated Expr getExpr() { result = this.getOperand() }
deprecated Expr getExpr() { result = getOperand() }
override string getOperator() { result = "*" }
@@ -780,15 +780,15 @@ class NewOrNewArrayExpr extends Expr, @any_new_expr {
* Gets the alignment argument passed to the allocation function, if any.
*/
Expr getAlignmentArgument() {
this.hasAlignedAllocation() and
hasAlignedAllocation() and
(
// If we have an allocator call, the alignment is the second argument to
// that call.
result = this.getAllocatorCall().getArgument(1)
result = getAllocatorCall().getArgument(1)
or
// Otherwise, the alignment winds up as child number 3 of the `new`
// itself.
result = this.getChild(3)
result = getChild(3)
)
}
@@ -916,7 +916,7 @@ class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr {
* Gets the element type of the array being allocated.
*/
Type getAllocatedElementType() {
result = this.getType().getUnderlyingType().(PointerType).getBaseType()
result = getType().getUnderlyingType().(PointerType).getBaseType()
}
/**
@@ -946,12 +946,7 @@ class DeleteExpr extends Expr, @delete_expr {
*/
Type getDeletedObjectType() {
result =
this.getExpr()
.getFullyConverted()
.getType()
.stripTopLevelSpecifiers()
.(PointerType)
.getBaseType()
getExpr().getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType()
}
/**
@@ -962,7 +957,7 @@ class DeleteExpr extends Expr, @delete_expr {
/**
* Gets the destructor to be called to destroy the object, if any.
*/
Destructor getDestructor() { result = this.getDestructorCall().getTarget() }
Destructor getDestructor() { result = getDestructorCall().getTarget() }
/**
* Gets the `operator delete` that deallocates storage. Does not hold
@@ -1025,12 +1020,7 @@ class DeleteArrayExpr extends Expr, @delete_array_expr {
*/
Type getDeletedElementType() {
result =
this.getExpr()
.getFullyConverted()
.getType()
.stripTopLevelSpecifiers()
.(PointerType)
.getBaseType()
getExpr().getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType()
}
/**
@@ -1044,7 +1034,7 @@ class DeleteArrayExpr extends Expr, @delete_array_expr {
/**
* Gets the destructor to be called to destroy each element in the array, if any.
*/
Destructor getDestructor() { result = this.getDestructorCall().getTarget() }
Destructor getDestructor() { result = getDestructorCall().getTarget() }
/**
* Gets the `operator delete[]` that deallocates storage.
@@ -1111,7 +1101,7 @@ class StmtExpr extends Expr, @expr_stmt {
* x = ({ dosomething(); a+b; });
* ```
*/
Expr getResultExpr() { result = getStmtResultExpr(this.getStmt()) }
Expr getResultExpr() { result = getStmtResultExpr(getStmt()) }
}
/** Get the result expression of a statement. (Helper function for StmtExpr.) */
@@ -1240,20 +1230,20 @@ class FoldExpr extends Expr, @foldexpr {
predicate isRightFold() { fold(underlyingElement(this), _, false) }
/** Holds if this is a unary fold expression. */
predicate isUnaryFold() { this.getNumChild() = 1 }
predicate isUnaryFold() { getNumChild() = 1 }
/** Holds if this is a binary fold expression. */
predicate isBinaryFold() { this.getNumChild() = 2 }
predicate isBinaryFold() { getNumChild() = 2 }
/**
* Gets the child expression containing the unexpanded parameter pack.
*/
Expr getPackExpr() {
this.isUnaryFold() and
result = this.getChild(0)
result = getChild(0)
or
this.isBinaryFold() and
if this.isRightFold() then result = this.getChild(0) else result = this.getChild(1)
if this.isRightFold() then result = getChild(0) else result = getChild(1)
}
/**
@@ -1261,7 +1251,7 @@ class FoldExpr extends Expr, @foldexpr {
*/
Expr getInitExpr() {
this.isBinaryFold() and
if this.isRightFold() then result = this.getChild(1) else result = this.getChild(0)
if this.isRightFold() then result = getChild(1) else result = getChild(0)
}
}

View File

@@ -24,7 +24,7 @@ class LambdaExpression extends Expr, @lambdaexpr {
/**
* Gets an implicitly or explicitly captured value of this lambda expression.
*/
LambdaCapture getACapture() { result = this.getCapture(_) }
LambdaCapture getACapture() { result = getCapture(_) }
/**
* Gets the nth implicitly or explicitly captured value of this lambda expression.
@@ -58,13 +58,13 @@ class LambdaExpression extends Expr, @lambdaexpr {
* - The return type.
* - The statements comprising the lambda body.
*/
Operator getLambdaFunction() { result = this.getType().(Closure).getLambdaFunction() }
Operator getLambdaFunction() { result = getType().(Closure).getLambdaFunction() }
/**
* Gets the initializer that initializes the captured variables in the closure, if any.
* A lambda that does not capture any variables will not have an initializer.
*/
ClassAggregateLiteral getInitializer() { result = this.getChild(0) }
ClassAggregateLiteral getInitializer() { result = getChild(0) }
}
/**
@@ -103,7 +103,7 @@ class Closure extends Class {
* ```
*/
class LambdaCapture extends Locatable, @lambdacapture {
override string toString() { result = this.getField().getName() }
override string toString() { result = getField().getName() }
override string getAPrimaryQlClass() { result = "LambdaCapture" }

View File

@@ -60,12 +60,12 @@ class TextLiteral extends Literal {
/** Gets a hex escape sequence that appears in the character or string literal (see [lex.ccon] in the C++ Standard). */
string getAHexEscapeSequence(int occurrence, int offset) {
result = this.getValueText().regexpFind("(?<!\\\\)\\\\x[0-9a-fA-F]+", occurrence, offset)
result = getValueText().regexpFind("(?<!\\\\)\\\\x[0-9a-fA-F]+", occurrence, offset)
}
/** Gets an octal escape sequence that appears in the character or string literal (see [lex.ccon] in the C++ Standard). */
string getAnOctalEscapeSequence(int occurrence, int offset) {
result = this.getValueText().regexpFind("(?<!\\\\)\\\\[0-7]{1,3}", occurrence, offset)
result = getValueText().regexpFind("(?<!\\\\)\\\\[0-7]{1,3}", occurrence, offset)
}
/**
@@ -75,27 +75,27 @@ class TextLiteral extends Literal {
string getANonStandardEscapeSequence(int occurrence, int offset) {
// Find all single character escape sequences (ignoring the start of octal escape sequences),
// together with anything starting like a hex escape sequence but not followed by a hex digit.
result = this.getValueText().regexpFind("\\\\[^x0-7\\s]|\\\\x[^0-9a-fA-F]", occurrence, offset) and
result = getValueText().regexpFind("\\\\[^x0-7\\s]|\\\\x[^0-9a-fA-F]", occurrence, offset) and
// From these, exclude all standard escape sequences.
not result = this.getAStandardEscapeSequence(_, _)
not result = getAStandardEscapeSequence(_, _)
}
/** Gets a simple escape sequence that appears in the char or string literal (see [lex.ccon] in the C++ Standard). */
string getASimpleEscapeSequence(int occurrence, int offset) {
result = this.getValueText().regexpFind("\\\\['\"?\\\\abfnrtv]", occurrence, offset)
result = getValueText().regexpFind("\\\\['\"?\\\\abfnrtv]", occurrence, offset)
}
/** Gets a standard escape sequence that appears in the char or string literal (see [lex.ccon] in the C++ Standard). */
string getAStandardEscapeSequence(int occurrence, int offset) {
result = this.getASimpleEscapeSequence(occurrence, offset) or
result = this.getAnOctalEscapeSequence(occurrence, offset) or
result = this.getAHexEscapeSequence(occurrence, offset)
result = getASimpleEscapeSequence(occurrence, offset) or
result = getAnOctalEscapeSequence(occurrence, offset) or
result = getAHexEscapeSequence(occurrence, offset)
}
/**
* Gets the length of the string literal (including null) before escape sequences added by the extractor.
*/
int getOriginalLength() { result = this.getValue().length() + 1 }
int getOriginalLength() { result = getValue().length() + 1 }
}
/**
@@ -216,7 +216,7 @@ class ClassAggregateLiteral extends AggregateLiteral {
(
// If the field has an explicit initializer expression, then the field is
// initialized.
exists(this.getFieldExpr(field))
exists(getFieldExpr(field))
or
// If the type is not a union, all fields without initializers are value
// initialized.
@@ -224,7 +224,7 @@ class ClassAggregateLiteral extends AggregateLiteral {
or
// If the type is a union, and there are no explicit initializers, then
// the first declared field is value initialized.
not exists(this.getAChild()) and
not exists(getAChild()) and
field.getInitializationOrder() = 0
)
}
@@ -239,8 +239,8 @@ class ClassAggregateLiteral extends AggregateLiteral {
*/
pragma[inline]
predicate isValueInitialized(Field field) {
this.isInitialized(field) and
not exists(this.getFieldExpr(field))
isInitialized(field) and
not exists(getFieldExpr(field))
}
}
@@ -285,7 +285,7 @@ class ArrayOrVectorAggregateLiteral extends AggregateLiteral {
bindingset[elementIndex]
predicate isInitialized(int elementIndex) {
elementIndex >= 0 and
elementIndex < this.getArraySize()
elementIndex < getArraySize()
}
/**
@@ -298,8 +298,8 @@ class ArrayOrVectorAggregateLiteral extends AggregateLiteral {
*/
bindingset[elementIndex]
predicate isValueInitialized(int elementIndex) {
this.isInitialized(elementIndex) and
not exists(this.getElementExpr(elementIndex))
isInitialized(elementIndex) and
not exists(getElementExpr(elementIndex))
}
}

View File

@@ -31,7 +31,7 @@ private predicate addressConstantVariable(Variable v) {
private predicate constantAddressLValue(Expr lvalue) {
lvalue.(VariableAccess).getTarget() =
any(Variable v |
v.isStatic()
v.(Variable).isStatic()
or
v instanceof GlobalOrNamespaceVariable
)

View File

@@ -173,7 +173,7 @@ class LocalVariable extends LocalScopeVariable, @localvariable { }
class VariableDeclarationEntry extends @var_decl {
string toString() { result = "QualifiedName DeclarationEntry" }
Variable getDeclaration() { result = this.getVariable() }
Variable getDeclaration() { result = getVariable() }
/**
* Gets the variable which is being declared or defined.

View File

@@ -4,7 +4,7 @@ private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.DataFlow3
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.ResolveCall
private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch
private import semmle.code.cpp.controlflow.IRGuards
private import semmle.code.cpp.models.interfaces.Taint
private import semmle.code.cpp.models.interfaces.DataFlow
@@ -355,6 +355,20 @@ predicate taintedIncludingGlobalVars(Expr source, Element tainted, string global
*/
GlobalOrNamespaceVariable globalVarFromId(string id) { id = result.getQualifiedName() }
/**
* Resolve potential target function(s) for `call`.
*
* If `call` is a call through a function pointer (`ExprCall`) or
* targets a virtual method, simple data flow analysis is performed
* in order to identify target(s).
*/
Function resolveCall(Call call) {
exists(CallInstruction callInstruction |
callInstruction.getAST() = call and
result = Dispatch::viableCallable(callInstruction)
)
}
/**
* Provides definitions for augmenting source/sink pairs with data-flow paths
* between them. From a `@kind path-problem` query, import this module in the
@@ -465,7 +479,7 @@ module TaintedWithPath {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -474,24 +488,6 @@ module TaintedWithPath {
}
}
/**
* INTERNAL: Do not use.
*/
module Private {
/** Gets a predecessor `PathNode` of `pathNode`, if any. */
PathNode getAPredecessor(PathNode pathNode) { edges(result, pathNode) }
/** Gets the element that `pathNode` wraps, if any. */
Element getElementFromPathNode(PathNode pathNode) {
exists(DataFlow::Node node | node = pathNode.(WrapPathNode).inner().getNode() |
result = node.asExpr() or
result = node.asParameter()
)
or
result = pathNode.(EndpointPathNode).inner()
}
}
private class WrapPathNode extends PathNode, TWrapPathNode {
DataFlow3::PathNode inner() { this = TWrapPathNode(result) }

View File

@@ -1,23 +0,0 @@
/**
* Provides a predicate for non-contextual virtual dispatch and function
* pointer resolution.
*/
import cpp
private import semmle.code.cpp.ir.ValueNumbering
private import internal.DataFlowDispatch
private import semmle.code.cpp.ir.IR
/**
* Resolve potential target function(s) for `call`.
*
* If `call` is a call through a function pointer (`ExprCall`) or its target is
* a virtual member function, simple data flow analysis is performed in order
* to identify the possible target(s).
*/
Function resolveCall(Call call) {
exists(CallInstruction callInstruction |
callInstruction.getAST() = call and
result = viableCallable(callInstruction)
)
}

View File

@@ -63,10 +63,8 @@ private module VirtualDispatch {
|
// Call argument
exists(DataFlowCall call, int i |
other
.(DataFlow::ParameterNode)
.isParameterOf(pragma[only_bind_into](call).getStaticCallTarget(), i) and
src.(ArgumentNode).argumentOf(call, pragma[only_bind_into](pragma[only_bind_out](i)))
other.(DataFlow::ParameterNode).isParameterOf(call.getStaticCallTarget(), i) and
src.(ArgumentNode).argumentOf(call, i)
) and
allowOtherFromArg = true and
allowFromArg = true
@@ -130,7 +128,6 @@ private module VirtualDispatch {
*
* Used to fix a join ordering issue in flowsFrom.
*/
pragma[noinline]
private predicate returnNodeWithKindAndEnclosingCallable(
ReturnNode node, ReturnKind kind, DataFlowCallable callable
) {

View File

@@ -10,7 +10,6 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -95,22 +94,6 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -127,12 +110,12 @@ abstract class Configuration extends string {
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
predicate hasFlowTo(Node sink) { hasFlow(_, sink) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
@@ -261,8 +244,6 @@ private class ParamNodeEx extends NodeEx {
}
int getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
private class RetNodeEx extends NodeEx {
@@ -366,8 +347,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -383,8 +363,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -420,20 +399,6 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -454,7 +419,7 @@ private module Stage1 {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
@@ -584,7 +549,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -779,12 +744,8 @@ private module Stage1 {
returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
@@ -970,8 +931,6 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1039,7 +998,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1250,7 +1209,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1435,12 +1394,8 @@ private module Stage2 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -1651,8 +1606,6 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1734,7 +1687,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1945,7 +1898,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2130,12 +2083,8 @@ private module Stage3 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2190,8 +2139,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
) and
accessPathApproxCostLimits(apLimit, tupleLimit) and
apLimit < tails and
tupleLimit < (tails - 1) * nodes and
not tc.forceHighPrecision()
tupleLimit < (tails - 1) * nodes
)
}
@@ -2403,8 +2351,6 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2500,7 +2446,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2711,7 +2657,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2896,12 +2842,8 @@ private module Stage4 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2974,8 +2916,6 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
int getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
override string toString() { result = p + ": " + ap }
predicate hasLocationInfo(
@@ -3033,15 +2973,12 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
* expected to be expensive. Holds with `unfold = true` otherwise.
*/
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
if apa.getHead().forceHighPrecision()
then unfold = true
else
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
}
/**
@@ -3103,11 +3040,7 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3119,10 +3052,17 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3226,7 +3166,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
}
override string toString() {
result = "[" + this.toStringImpl(true) + this.length().toString() + ")]"
result = "[" + this.toStringImpl(true) + length().toString() + ")]"
or
result = "[" + this.toStringImpl(false)
}
@@ -3308,7 +3248,7 @@ class PathNode extends TPathNode {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3365,11 +3305,9 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + ppAp() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3437,48 +3375,24 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override PathNodeImpl getASuccessorImpl() {
// an intermediate step to another intermediate node
result = this.getSuccMid()
result = getSuccMid()
or
// a final step to a sink
result = this.getSuccMid().projectToSink()
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
override predicate isSource() {
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3542,7 +3456,7 @@ private predicate pathStep(
exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp()
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
or
pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone
or
@@ -3619,20 +3533,18 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
apa = ap.getApprox()
)
}
pragma[nomagic]
pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3645,14 +3557,12 @@ private predicate parameterCand(
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
AccessPath ap
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
pathIntoArg(mid, i, outercc, call, ap, apa) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration())
)
}
@@ -3661,23 +3571,18 @@ private predicate pathIntoCallable0(
* before and after entering the callable are `outercc` and `innercc`,
* respectively.
*/
pragma[nomagic]
private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
p.isParameterOf(callable, i) and
(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
sc = TSummaryCtxNone()
)
|
if recordDataFlowCallSite(call, callable)
@@ -3701,23 +3606,18 @@ private predicate paramFlowsThrough(
ap = mid.getAp() and
apa = ap.getApprox() and
pos = sc.getParameterPos() and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
pragma[nomagic]
private predicate pathThroughCallable0(
DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap,
AccessPathApprox apa, Configuration config
AccessPathApprox apa
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call, config) and
paramFlowsThrough(kind, innercc, sc, ap, apa, config)
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3727,9 +3627,9 @@ private predicate pathThroughCallable0(
*/
pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config |
pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3740,15 +3640,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
unbindConf(arg.getConfiguration()))
}
/**
@@ -3781,17 +3679,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3800,12 +3689,11 @@ 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(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4145,7 +4033,7 @@ private module FlowExploration {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn

View File

@@ -10,7 +10,6 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -95,22 +94,6 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -127,12 +110,12 @@ abstract class Configuration extends string {
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
predicate hasFlowTo(Node sink) { hasFlow(_, sink) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
@@ -261,8 +244,6 @@ private class ParamNodeEx extends NodeEx {
}
int getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
private class RetNodeEx extends NodeEx {
@@ -366,8 +347,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -383,8 +363,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -420,20 +399,6 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -454,7 +419,7 @@ private module Stage1 {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
@@ -584,7 +549,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -779,12 +744,8 @@ private module Stage1 {
returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
@@ -970,8 +931,6 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1039,7 +998,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1250,7 +1209,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1435,12 +1394,8 @@ private module Stage2 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -1651,8 +1606,6 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1734,7 +1687,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1945,7 +1898,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2130,12 +2083,8 @@ private module Stage3 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2190,8 +2139,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
) and
accessPathApproxCostLimits(apLimit, tupleLimit) and
apLimit < tails and
tupleLimit < (tails - 1) * nodes and
not tc.forceHighPrecision()
tupleLimit < (tails - 1) * nodes
)
}
@@ -2403,8 +2351,6 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2500,7 +2446,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2711,7 +2657,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2896,12 +2842,8 @@ private module Stage4 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2974,8 +2916,6 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
int getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
override string toString() { result = p + ": " + ap }
predicate hasLocationInfo(
@@ -3033,15 +2973,12 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
* expected to be expensive. Holds with `unfold = true` otherwise.
*/
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
if apa.getHead().forceHighPrecision()
then unfold = true
else
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
}
/**
@@ -3103,11 +3040,7 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3119,10 +3052,17 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3226,7 +3166,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
}
override string toString() {
result = "[" + this.toStringImpl(true) + this.length().toString() + ")]"
result = "[" + this.toStringImpl(true) + length().toString() + ")]"
or
result = "[" + this.toStringImpl(false)
}
@@ -3308,7 +3248,7 @@ class PathNode extends TPathNode {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3365,11 +3305,9 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + ppAp() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3437,48 +3375,24 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override PathNodeImpl getASuccessorImpl() {
// an intermediate step to another intermediate node
result = this.getSuccMid()
result = getSuccMid()
or
// a final step to a sink
result = this.getSuccMid().projectToSink()
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
override predicate isSource() {
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3542,7 +3456,7 @@ private predicate pathStep(
exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp()
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
or
pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone
or
@@ -3619,20 +3533,18 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
apa = ap.getApprox()
)
}
pragma[nomagic]
pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3645,14 +3557,12 @@ private predicate parameterCand(
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
AccessPath ap
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
pathIntoArg(mid, i, outercc, call, ap, apa) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration())
)
}
@@ -3661,23 +3571,18 @@ private predicate pathIntoCallable0(
* before and after entering the callable are `outercc` and `innercc`,
* respectively.
*/
pragma[nomagic]
private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
p.isParameterOf(callable, i) and
(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
sc = TSummaryCtxNone()
)
|
if recordDataFlowCallSite(call, callable)
@@ -3701,23 +3606,18 @@ private predicate paramFlowsThrough(
ap = mid.getAp() and
apa = ap.getApprox() and
pos = sc.getParameterPos() and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
pragma[nomagic]
private predicate pathThroughCallable0(
DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap,
AccessPathApprox apa, Configuration config
AccessPathApprox apa
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call, config) and
paramFlowsThrough(kind, innercc, sc, ap, apa, config)
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3727,9 +3627,9 @@ private predicate pathThroughCallable0(
*/
pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config |
pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3740,15 +3640,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
unbindConf(arg.getConfiguration()))
}
/**
@@ -3781,17 +3679,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3800,12 +3689,11 @@ 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(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4145,7 +4033,7 @@ private module FlowExploration {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn

View File

@@ -10,7 +10,6 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -95,22 +94,6 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -127,12 +110,12 @@ abstract class Configuration extends string {
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
predicate hasFlowTo(Node sink) { hasFlow(_, sink) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
@@ -261,8 +244,6 @@ private class ParamNodeEx extends NodeEx {
}
int getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
private class RetNodeEx extends NodeEx {
@@ -366,8 +347,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -383,8 +363,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -420,20 +399,6 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -454,7 +419,7 @@ private module Stage1 {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
@@ -584,7 +549,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -779,12 +744,8 @@ private module Stage1 {
returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
@@ -970,8 +931,6 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1039,7 +998,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1250,7 +1209,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1435,12 +1394,8 @@ private module Stage2 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -1651,8 +1606,6 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1734,7 +1687,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1945,7 +1898,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2130,12 +2083,8 @@ private module Stage3 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2190,8 +2139,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
) and
accessPathApproxCostLimits(apLimit, tupleLimit) and
apLimit < tails and
tupleLimit < (tails - 1) * nodes and
not tc.forceHighPrecision()
tupleLimit < (tails - 1) * nodes
)
}
@@ -2403,8 +2351,6 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2500,7 +2446,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2711,7 +2657,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2896,12 +2842,8 @@ private module Stage4 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2974,8 +2916,6 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
int getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
override string toString() { result = p + ": " + ap }
predicate hasLocationInfo(
@@ -3033,15 +2973,12 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
* expected to be expensive. Holds with `unfold = true` otherwise.
*/
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
if apa.getHead().forceHighPrecision()
then unfold = true
else
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
}
/**
@@ -3103,11 +3040,7 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3119,10 +3052,17 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3226,7 +3166,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
}
override string toString() {
result = "[" + this.toStringImpl(true) + this.length().toString() + ")]"
result = "[" + this.toStringImpl(true) + length().toString() + ")]"
or
result = "[" + this.toStringImpl(false)
}
@@ -3308,7 +3248,7 @@ class PathNode extends TPathNode {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3365,11 +3305,9 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + ppAp() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3437,48 +3375,24 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override PathNodeImpl getASuccessorImpl() {
// an intermediate step to another intermediate node
result = this.getSuccMid()
result = getSuccMid()
or
// a final step to a sink
result = this.getSuccMid().projectToSink()
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
override predicate isSource() {
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3542,7 +3456,7 @@ private predicate pathStep(
exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp()
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
or
pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone
or
@@ -3619,20 +3533,18 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
apa = ap.getApprox()
)
}
pragma[nomagic]
pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3645,14 +3557,12 @@ private predicate parameterCand(
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
AccessPath ap
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
pathIntoArg(mid, i, outercc, call, ap, apa) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration())
)
}
@@ -3661,23 +3571,18 @@ private predicate pathIntoCallable0(
* before and after entering the callable are `outercc` and `innercc`,
* respectively.
*/
pragma[nomagic]
private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
p.isParameterOf(callable, i) and
(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
sc = TSummaryCtxNone()
)
|
if recordDataFlowCallSite(call, callable)
@@ -3701,23 +3606,18 @@ private predicate paramFlowsThrough(
ap = mid.getAp() and
apa = ap.getApprox() and
pos = sc.getParameterPos() and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
pragma[nomagic]
private predicate pathThroughCallable0(
DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap,
AccessPathApprox apa, Configuration config
AccessPathApprox apa
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call, config) and
paramFlowsThrough(kind, innercc, sc, ap, apa, config)
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3727,9 +3627,9 @@ private predicate pathThroughCallable0(
*/
pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config |
pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3740,15 +3640,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
unbindConf(arg.getConfiguration()))
}
/**
@@ -3781,17 +3679,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3800,12 +3689,11 @@ 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(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4145,7 +4033,7 @@ private module FlowExploration {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn

View File

@@ -10,7 +10,6 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -95,22 +94,6 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -127,12 +110,12 @@ abstract class Configuration extends string {
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
predicate hasFlowTo(Node sink) { hasFlow(_, sink) }
/**
* Holds if data may flow from some source to `sink` for this configuration.
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
/**
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
@@ -261,8 +244,6 @@ private class ParamNodeEx extends NodeEx {
}
int getPosition() { this.isParameterOf(_, result) }
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
}
private class RetNodeEx extends NodeEx {
@@ -366,8 +347,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -383,8 +363,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
not fullBarrier(node2, config)
)
}
@@ -420,20 +399,6 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -454,7 +419,7 @@ private module Stage1 {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
@@ -584,7 +549,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -779,12 +744,8 @@ private module Stage1 {
returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and
exists(ap) and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = p.getPosition()
)
}
@@ -970,8 +931,6 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1039,7 +998,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1250,7 +1209,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1435,12 +1394,8 @@ private module Stage2 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -1651,8 +1606,6 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1734,7 +1687,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1945,7 +1898,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2130,12 +2083,8 @@ private module Stage3 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2190,8 +2139,7 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
) and
accessPathApproxCostLimits(apLimit, tupleLimit) and
apLimit < tails and
tupleLimit < (tails - 1) * nodes and
not tc.forceHighPrecision()
tupleLimit < (tails - 1) * nodes
)
}
@@ -2403,8 +2351,6 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2500,7 +2446,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
cc = ccNone() and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2711,7 +2657,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2896,12 +2842,8 @@ private module Stage4 {
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
p.getPosition() = pos and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
p.allowParameterReturnInSelf()
)
// we don't expect a parameter to return stored in itself
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
@@ -2974,8 +2916,6 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
int getParameterPos() { p.isParameterOf(_, result) }
ParamNodeEx getParamNode() { result = p }
override string toString() { result = p + ": " + ap }
predicate hasLocationInfo(
@@ -3033,15 +2973,12 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
* expected to be expensive. Holds with `unfold = true` otherwise.
*/
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
if apa.getHead().forceHighPrecision()
then unfold = true
else
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
exists(int aps, int nodes, int apLimit, int tupleLimit |
aps = countPotentialAps(apa, config) and
nodes = countNodesUsingAccessPath(apa, config) and
accessPathCostLimits(apLimit, tupleLimit) and
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
)
}
/**
@@ -3103,11 +3040,7 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3119,10 +3052,17 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3226,7 +3166,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
}
override string toString() {
result = "[" + this.toStringImpl(true) + this.length().toString() + ")]"
result = "[" + this.toStringImpl(true) + length().toString() + ")]"
or
result = "[" + this.toStringImpl(false)
}
@@ -3308,7 +3248,7 @@ class PathNode extends TPathNode {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3365,11 +3305,9 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
}
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toString() { result = this.getNodeEx().toString() + ppAp() }
override string toStringWithContext() {
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
}
override string toStringWithContext() { result = this.getNodeEx().toString() + ppAp() + ppCtx() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -3437,48 +3375,24 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
override PathNodeImpl getASuccessorImpl() {
// an intermediate step to another intermediate node
result = this.getSuccMid()
result = getSuccMid()
or
// a final step to a sink
result = this.getSuccMid().projectToSink()
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
override predicate isSource() {
sourceNode(node, config) and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3542,7 +3456,7 @@ private predicate pathStep(
exists(TypedContent tc | pathReadStep(mid, node, ap.push(tc), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _, _) and ap = mid.getAp()
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
or
pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone
or
@@ -3619,20 +3533,18 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
*/
pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
Configuration config
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgNode arg |
arg = mid.getNodeEx().asNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
ap = mid.getAp() and
apa = ap.getApprox() and
config = mid.getConfiguration()
apa = ap.getApprox()
)
}
pragma[nomagic]
pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3645,14 +3557,12 @@ private predicate parameterCand(
pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
AccessPath ap, Configuration config
AccessPath ap
) {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
pathIntoArg(mid, i, outercc, call, ap, apa) and
callable = resolveCall(call, outercc) and
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
pragma[only_bind_into](config))
parameterCand(callable, any(int j | j <= i and j >= i), apa, mid.getConfiguration())
)
}
@@ -3661,23 +3571,18 @@ private predicate pathIntoCallable0(
* before and after entering the callable are `outercc` and `innercc`,
* respectively.
*/
pragma[nomagic]
private predicate pathIntoCallable(
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call, Configuration config
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
pathIntoCallable0(mid, callable, i, outercc, call, ap) and
p.isParameterOf(callable, i) and
(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
sc = TSummaryCtxNone()
)
|
if recordDataFlowCallSite(call, callable)
@@ -3701,23 +3606,18 @@ private predicate paramFlowsThrough(
ap = mid.getAp() and
apa = ap.getApprox() and
pos = sc.getParameterPos() and
// we don't expect a parameter to return stored in itself, unless explicitly allowed
(
not kind.(ParamUpdateReturnKind).getPosition() = pos
or
sc.getParamNode().allowParameterReturnInSelf()
)
not kind.(ParamUpdateReturnKind).getPosition() = pos
)
}
pragma[nomagic]
private predicate pathThroughCallable0(
DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap,
AccessPathApprox apa, Configuration config
AccessPathApprox apa
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call, config) and
paramFlowsThrough(kind, innercc, sc, ap, apa, config)
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3727,9 +3627,9 @@ private predicate pathThroughCallable0(
*/
pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa, Configuration config |
pathThroughCallable0(call, mid, kind, cc, ap, apa, config) and
out = getAnOutNodeFlow(kind, call, apa, config)
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3740,15 +3640,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
unbindConf(arg.getConfiguration()))
}
/**
@@ -3781,17 +3679,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3800,12 +3689,11 @@ 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(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4145,7 +4033,7 @@ private module FlowExploration {
* 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/).
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn

View File

@@ -2,42 +2,6 @@ private import DataFlowImplSpecific::Private
private import DataFlowImplSpecific::Public
import Cached
module DataFlowImplCommonPublic {
private newtype TFlowFeature =
TFeatureHasSourceCallContext() or
TFeatureHasSinkCallContext() or
TFeatureEqualSourceSinkCallContext()
/** A flow configuration feature for use in `Configuration::getAFeature()`. */
class FlowFeature extends TFlowFeature {
string toString() { none() }
}
/**
* A flow configuration feature that implies that sources have some existing
* call context.
*/
class FeatureHasSourceCallContext extends FlowFeature, TFeatureHasSourceCallContext {
override string toString() { result = "FeatureHasSourceCallContext" }
}
/**
* A flow configuration feature that implies that sinks have some existing
* call context.
*/
class FeatureHasSinkCallContext extends FlowFeature, TFeatureHasSinkCallContext {
override string toString() { result = "FeatureHasSinkCallContext" }
}
/**
* A flow configuration feature that implies that source-sink pairs have some
* shared existing call context.
*/
class FeatureEqualSourceSinkCallContext extends FlowFeature, TFeatureEqualSourceSinkCallContext {
override string toString() { result = "FeatureEqualSourceSinkCallContext" }
}
}
/**
* The cost limits for the `AccessPathFront` to `AccessPathApprox` expansion.
*
@@ -287,7 +251,7 @@ private module Cached {
predicate forceCachingInSameStage() { any() }
cached
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = nodeGetEnclosingCallable(n) }
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() }
cached
predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) {
@@ -352,7 +316,9 @@ private module Cached {
}
cached
predicate parameterNode(Node p, DataFlowCallable c, int pos) { isParameterNode(p, c, pos) }
predicate parameterNode(Node n, DataFlowCallable c, int i) {
n.(ParameterNode).isParameterOf(c, i)
}
cached
predicate argumentNode(Node n, DataFlowCall call, int pos) {
@@ -835,9 +801,6 @@ private module Cached {
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
}
cached
predicate allowParameterReturnInSelfCached(ParamNode p) { allowParameterReturnInSelf(p) }
cached
newtype TCallContext =
TAnyCallContext() or
@@ -974,7 +937,7 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall {
}
override predicate relevantFor(DataFlowCallable callable) {
recordDataFlowCallSite(this.getCall(), callable)
recordDataFlowCallSite(getCall(), callable)
}
override predicate matchesCall(DataFlowCall call) { call = this.getCall() }
@@ -1273,13 +1236,6 @@ class TypedContent extends MkTypedContent {
/** Gets a textual representation of this content. */
string toString() { result = c.toString() }
/**
* Holds if access paths with this `TypedContent` at their head always should
* be tracked at high precision. This disables adaptive access path precision
* for such access paths.
*/
predicate forceHighPrecision() { forceHighPrecision(c) }
}
/**
@@ -1294,7 +1250,7 @@ abstract class AccessPathFront extends TAccessPathFront {
TypedContent getHead() { this = TFrontHead(result) }
predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) }
predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) }
}
class AccessPathFrontNil extends AccessPathFront, TFrontNil {

View File

@@ -31,7 +31,7 @@ module Consistency {
query predicate uniqueEnclosingCallable(Node n, string msg) {
exists(int c |
n instanceof RelevantNode and
c = count(nodeGetEnclosingCallable(n)) and
c = count(n.getEnclosingCallable()) and
c != 1 and
msg = "Node should have one enclosing callable but has " + c + "."
)
@@ -85,13 +85,13 @@ module Consistency {
}
query predicate parameterCallable(ParameterNode p, string msg) {
exists(DataFlowCallable c | isParameterNode(p, c, _) and c != nodeGetEnclosingCallable(p)) and
exists(DataFlowCallable c | p.isParameterOf(c, _) and c != p.getEnclosingCallable()) and
msg = "Callable mismatch for parameter."
}
query predicate localFlowIsLocal(Node n1, Node n2, string msg) {
simpleLocalFlowStep(n1, n2) and
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
n1.getEnclosingCallable() != n2.getEnclosingCallable() and
msg = "Local flow step does not preserve enclosing callable."
}
@@ -106,7 +106,7 @@ module Consistency {
query predicate unreachableNodeCCtx(Node n, DataFlowCall call, string msg) {
isUnreachableInCall(n, call) and
exists(DataFlowCallable c |
c = nodeGetEnclosingCallable(n) and
c = n.getEnclosingCallable() and
not viableCallable(call) = c
) and
msg = "Call context for isUnreachableInCall is inconsistent with call graph."
@@ -120,7 +120,7 @@ module Consistency {
n.(ArgumentNode).argumentOf(call, _) and
msg = "ArgumentNode and call does not share enclosing callable."
) and
nodeGetEnclosingCallable(n) != call.getEnclosingCallable()
n.getEnclosingCallable() != call.getEnclosingCallable()
}
// This predicate helps the compiler forget that in some languages
@@ -151,7 +151,7 @@ module Consistency {
}
query predicate postIsInSameCallable(PostUpdateNode n, string msg) {
nodeGetEnclosingCallable(n) != nodeGetEnclosingCallable(n.getPreUpdateNode()) and
n.getEnclosingCallable() != n.getPreUpdateNode().getEnclosingCallable() and
msg = "PostUpdateNode does not share callable with its pre-update node."
}
@@ -175,7 +175,6 @@ module Consistency {
query predicate postWithInFlow(Node n, string msg) {
isPostUpdateNode(n) and
not clearsContent(n, _) and
simpleLocalFlowStep(_, n) and
msg = "PostUpdateNode should not be the target of local flow."
}

View File

@@ -3,12 +3,6 @@ private import DataFlowUtil
private import semmle.code.cpp.ir.IR
private import DataFlowDispatch
/** Gets the callable in which this node occurs. */
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) { p.isParameterOf(c, pos) }
/**
* A data flow node that occurs as the argument of a call and is passed as-is
* to the callable. Instance arguments (`this` pointer) and read side effects
@@ -112,9 +106,11 @@ class ReturnNode extends InstructionNode {
Instruction primary;
ReturnNode() {
exists(ReturnValueInstruction ret | instr = ret and primary = ret)
exists(ReturnValueInstruction ret | instr = ret.getReturnValue() and primary = ret)
or
exists(ReturnIndirectionInstruction rii | instr = rii and primary = rii)
exists(ReturnIndirectionInstruction rii |
instr = rii.getSideEffectOperand().getAnyDef() and primary = rii
)
}
/** Gets the kind of this returned value. */
@@ -188,16 +184,108 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
*/
predicate jumpStep(Node n1, Node n2) { none() }
private predicate fieldStoreStepNoChi(Node node1, FieldContent f, PostUpdateNode node2) {
exists(StoreInstruction store, Class c |
store = node2.asInstruction() and
store.getSourceValueOperand() = node1.asOperand() and
getWrittenField(store, f.(FieldContent).getAField(), c) and
f.hasOffset(c, _, _)
)
}
private FieldAddressInstruction getFieldInstruction(Instruction instr) {
result = instr or
result = instr.(CopyValueInstruction).getUnary()
}
pragma[noinline]
private predicate getWrittenField(Instruction instr, Field f, Class c) {
exists(FieldAddressInstruction fa |
fa =
getFieldInstruction([
instr.(StoreInstruction).getDestinationAddress(),
instr.(WriteSideEffectInstruction).getDestinationAddress()
]) and
f = fa.getField() and
c = f.getDeclaringType()
)
}
private predicate fieldStoreStepChi(Node node1, FieldContent f, PostUpdateNode node2) {
exists(ChiPartialOperand operand, ChiInstruction chi |
chi.getPartialOperand() = operand and
node1.asOperand() = operand and
node2.asInstruction() = chi and
exists(Class c |
c = chi.getResultType() and
exists(int startBit, int endBit |
chi.getUpdatedInterval(startBit, endBit) and
f.hasOffset(c, startBit, endBit)
)
or
getWrittenField(operand.getDef(), f.getAField(), c) and
f.hasOffset(c, _, _)
)
)
}
private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode node2) {
exists(a) and
exists(ChiPartialOperand operand, ChiInstruction chi, StoreInstruction store |
chi.getPartialOperand() = operand and
store = operand.getDef() and
node1.asOperand() = operand and
// This `ChiInstruction` will always have a non-conflated result because both `ArrayStoreNode`
// and `PointerStoreNode` require it in their characteristic predicates.
node2.asInstruction() = chi and
(
// `x[i] = taint()`
// This matches the characteristic predicate in `ArrayStoreNode`.
store.getDestinationAddress() instanceof PointerAddInstruction
or
// `*p = taint()`
// This matches the characteristic predicate in `PointerStoreNode`.
store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction
)
)
}
/**
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
* Thus, `node2` references an object with a field `f` that contains the
* value of `node1`.
*/
predicate storeStep(StoreNodeInstr node1, FieldContent f, StoreNodeInstr node2) {
exists(FieldAddressInstruction fai |
node1.getInstruction() = fai and
node2.getInstruction() = fai.getObjectAddress() and
f.getField() = fai.getField()
predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
fieldStoreStepNoChi(node1, f, node2) or
fieldStoreStepChi(node1, f, node2) or
arrayStoreStepChi(node1, f, node2) or
fieldStoreStepAfterArraySuppression(node1, f, node2)
}
// This predicate pushes the correct `FieldContent` onto the access path when the
// `suppressArrayRead` predicate has popped off an `ArrayContent`.
private predicate fieldStoreStepAfterArraySuppression(
Node node1, FieldContent f, PostUpdateNode node2
) {
exists(WriteSideEffectInstruction write, ChiInstruction chi, Class c |
not chi.isResultConflated() and
node1.asInstruction() = chi and
node2.asInstruction() = chi and
chi.getPartial() = write and
getWrittenField(write, f.getAField(), c) and
f.hasOffset(c, _, _)
)
}
bindingset[result, i]
private int unbindInt(int i) { i <= result and i >= result }
pragma[noinline]
private predicate getLoadedField(LoadInstruction load, Field f, Class c) {
exists(FieldAddressInstruction fa |
fa = load.getSourceAddress() and
f = fa.getField() and
c = f.getDeclaringType()
)
}
@@ -206,14 +294,122 @@ predicate storeStep(StoreNodeInstr node1, FieldContent f, StoreNodeInstr node2)
* Thus, `node1` references an object with a field `f` whose value ends up in
* `node2`.
*/
predicate readStep(ReadNode node1, FieldContent f, ReadNode node2) {
exists(FieldAddressInstruction fai |
node1.getInstruction() = fai.getObjectAddress() and
node2.getInstruction() = fai and
f.getField() = fai.getField()
private predicate fieldReadStep(Node node1, FieldContent f, Node node2) {
exists(LoadOperand operand |
node2.asOperand() = operand and
node1.asInstruction() = operand.getAnyDef() and
exists(Class c |
c = operand.getAnyDef().getResultType() and
exists(int startBit, int endBit |
operand.getUsedInterval(unbindInt(startBit), unbindInt(endBit)) and
f.hasOffset(c, startBit, endBit)
)
or
getLoadedField(operand.getUse(), f.getAField(), c) and
f.hasOffset(c, _, _)
)
)
}
/**
* When a store step happens in a function that looks like an array write such as:
* ```cpp
* void f(int* pa) {
* pa = source();
* }
* ```
* it can be a write to an array, but it can also happen that `f` is called as `f(&a.x)`. If that is
* the case, the `ArrayContent` that was written by the call to `f` should be popped off the access
* path, and a `FieldContent` containing `x` should be pushed instead.
* So this case pops `ArrayContent` off the access path, and the `fieldStoreStepAfterArraySuppression`
* predicate in `storeStep` ensures that we push the right `FieldContent` onto the access path.
*/
predicate suppressArrayRead(Node node1, ArrayContent a, Node node2) {
exists(a) and
exists(WriteSideEffectInstruction write, ChiInstruction chi |
node1.asInstruction() = write and
node2.asInstruction() = chi and
chi.getPartial() = write and
getWrittenField(write, _, _)
)
}
private class ArrayToPointerConvertInstruction extends ConvertInstruction {
ArrayToPointerConvertInstruction() {
this.getUnary().getResultType() instanceof ArrayType and
this.getResultType() instanceof PointerType
}
}
private Instruction skipOneCopyValueInstructionRec(CopyValueInstruction copy) {
copy.getUnary() = result and not result instanceof CopyValueInstruction
or
result = skipOneCopyValueInstructionRec(copy.getUnary())
}
private Instruction skipCopyValueInstructions(Operand op) {
not result instanceof CopyValueInstruction and result = op.getDef()
or
result = skipOneCopyValueInstructionRec(op.getDef())
}
private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) {
exists(a) and
// Explicit dereferences such as `*p` or `p[i]` where `p` is a pointer or array.
exists(LoadOperand operand, Instruction address |
operand.isDefinitionInexact() and
node1.asInstruction() = operand.getAnyDef() and
operand = node2.asOperand() and
address = skipCopyValueInstructions(operand.getAddressOperand()) and
(
address instanceof LoadInstruction or
address instanceof ArrayToPointerConvertInstruction or
address instanceof PointerOffsetInstruction
)
)
}
/**
* In cases such as:
* ```cpp
* void f(int* pa) {
* *pa = source();
* }
* ...
* int x;
* f(&x);
* use(x);
* ```
* the load on `x` in `use(x)` will exactly overlap with its definition (in this case the definition
* is a `WriteSideEffect`). This predicate pops the `ArrayContent` (pushed by the store in `f`)
* from the access path.
*/
private predicate exactReadStep(Node node1, ArrayContent a, Node node2) {
exists(a) and
exists(WriteSideEffectInstruction write, ChiInstruction chi |
not chi.isResultConflated() and
chi.getPartial() = write and
node1.asInstruction() = write and
node2.asInstruction() = chi and
// To distinquish this case from the `arrayReadStep` case we require that the entire variable was
// overwritten by the `WriteSideEffectInstruction` (i.e., there is a load that reads the
// entire variable).
exists(LoadInstruction load | load.getSourceValue() = chi)
)
}
/**
* Holds if data can flow from `node1` to `node2` via a read of `f`.
* Thus, `node1` references an object with a field `f` whose value ends up in
* `node2`.
*/
predicate readStep(Node node1, Content f, Node node2) {
fieldReadStep(node1, f, node2) or
arrayReadStep(node1, f, node2) or
exactReadStep(node1, f, node2) or
suppressArrayRead(node1, f, node2)
}
/**
* Holds if values stored inside content `c` are cleared at node `n`.
*/
@@ -245,7 +441,7 @@ private predicate suppressUnusedNode(Node n) { any() }
// Java QL library compatibility wrappers
//////////////////////////////////////////////////////////////////////////////
/** A node that performs a type cast. */
class CastNode extends Node {
class CastNode extends InstructionNode {
CastNode() { none() } // stub implementation
}
@@ -270,12 +466,6 @@ predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub impl
int accessPathLimit() { result = 5 }
/**
* Holds if access paths with `c` at their head always should be tracked at high
* precision. This disables adaptive access path precision for such access paths.
*/
predicate forceHighPrecision(Content c) { none() }
/** The unit type. */
private newtype TUnit = TMkUnit()
@@ -311,12 +501,3 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { no
/** Extra data-flow steps needed for lambda flow analysis. */
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
/**
* Holds if flow is allowed to pass from parameter `p` and back to itself as a
* side-effect, resulting in a summary from `p` to itself.
*
* One example would be to allow flow like `p.foo = p.bar;`, which is disallowed
* by default as a heuristic.
*/
predicate allowParameterReturnInSelf(ParameterNode p) { none() }

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