mirror of
https://github.com/github/codeql.git
synced 2026-05-26 09:01:22 +02:00
Compare commits
22 Commits
nickrolfe/
...
esbena/ena
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5b198837a | ||
|
|
94b0f1adc0 | ||
|
|
f67a586fb5 | ||
|
|
df34784834 | ||
|
|
cd2761b8f2 | ||
|
|
446fbcdbe1 | ||
|
|
b3f09e0203 | ||
|
|
c466fab22d | ||
|
|
c74857f44d | ||
|
|
b65db6c07c | ||
|
|
1cea33d80e | ||
|
|
09a273927a | ||
|
|
aa37ae6b70 | ||
|
|
5f9d3e1e58 | ||
|
|
bf708b9181 | ||
|
|
6277650a0d | ||
|
|
3baa9de45d | ||
|
|
e5ddc57aa6 | ||
|
|
62bf841c5d | ||
|
|
b14feb0022 | ||
|
|
09db824078 | ||
|
|
eaba3c120f |
2
.bazelrc
2
.bazelrc
@@ -1,3 +1,3 @@
|
||||
build --repo_env=CC=clang --repo_env=CXX=clang++ --copt="-std=c++17"
|
||||
build --copt="-std=c++17"
|
||||
|
||||
try-import %workspace%/local.bazelrc
|
||||
|
||||
27
.codeqlmanifest.json
Normal file
27
.codeqlmanifest.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"provide": [
|
||||
"*/ql/src/qlpack.yml",
|
||||
"*/ql/lib/qlpack.yml",
|
||||
"*/ql/test/qlpack.yml",
|
||||
"*/ql/examples/qlpack.yml",
|
||||
"*/ql/consistency-queries/qlpack.yml",
|
||||
"cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml",
|
||||
"javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml",
|
||||
"javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml",
|
||||
"javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml",
|
||||
"csharp/ql/campaigns/Solorigate/lib/qlpack.yml",
|
||||
"csharp/ql/campaigns/Solorigate/src/qlpack.yml",
|
||||
"csharp/ql/campaigns/Solorigate/test/qlpack.yml",
|
||||
"misc/legacy-support/*/qlpack.yml",
|
||||
"misc/suite-helpers/qlpack.yml",
|
||||
"ruby/extractor-pack/codeql-extractor.yml",
|
||||
"ql/extractor-pack/codeql-extractor.yml"
|
||||
],
|
||||
"versionPolicies": {
|
||||
"default": {
|
||||
"requireChangeNotes": true,
|
||||
"committedPrereleaseSuffix": "dev",
|
||||
"committedVersion": "nextPatchRelease"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,6 @@
|
||||
"rust-lang.rust",
|
||||
"bungcip.better-toml",
|
||||
"github.vscode-codeql",
|
||||
"hbenl.vscode-test-explorer",
|
||||
"ms-vscode.test-adapter-converter",
|
||||
"slevesque.vscode-zipexplorer"
|
||||
],
|
||||
"settings": {
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.236.0/containers/cpp/.devcontainer/base.Dockerfile
|
||||
|
||||
# [Choice] Debian / Ubuntu version (use Debian 11, Ubuntu 18.04/22.04 on local arm64/Apple Silicon): debian-11, debian-10, ubuntu-22.04, ubuntu-20.04, ubuntu-18.04
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/cpp:0-ubuntu-22.04
|
||||
|
||||
USER root
|
||||
ADD root.sh /tmp/root.sh
|
||||
ADD update-codeql.sh /usr/local/bin/update-codeql
|
||||
RUN bash /tmp/root.sh && rm /tmp/root.sh
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"extensions": [
|
||||
"github.vscode-codeql",
|
||||
"hbenl.vscode-test-explorer",
|
||||
"ms-vscode.test-adapter-converter",
|
||||
"slevesque.vscode-zipexplorer",
|
||||
"ms-vscode.cpptools"
|
||||
],
|
||||
"settings": {
|
||||
"files.watcherExclude": {
|
||||
"**/target/**": true
|
||||
},
|
||||
"codeQL.runningQueries.memory": 2048
|
||||
},
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
},
|
||||
"runArgs": [
|
||||
"--cap-add=SYS_PTRACE",
|
||||
"--security-opt",
|
||||
"seccomp=unconfined"
|
||||
],
|
||||
"remoteUser": "vscode",
|
||||
"onCreateCommand": ".devcontainer/swift/user.sh"
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
set -xe
|
||||
|
||||
BAZELISK_VERSION=v1.12.0
|
||||
BAZELISK_DOWNLOAD_SHA=6b0bcb2ea15bca16fffabe6fda75803440375354c085480fe361d2cbf32501db
|
||||
|
||||
apt-get update
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get -y install --no-install-recommends \
|
||||
zlib1g-dev \
|
||||
uuid-dev \
|
||||
python3-distutils \
|
||||
python3-pip \
|
||||
bash-completion
|
||||
|
||||
# Install Bazel
|
||||
curl -fSsL -o /usr/local/bin/bazelisk https://github.com/bazelbuild/bazelisk/releases/download/${BAZELISK_VERSION}/bazelisk-linux-amd64
|
||||
echo "${BAZELISK_DOWNLOAD_SHA} */usr/local/bin/bazelisk" | sha256sum --check -
|
||||
chmod 0755 /usr/local/bin/bazelisk
|
||||
ln -s bazelisk /usr/local/bin/bazel
|
||||
|
||||
# install latest codeql
|
||||
update-codeql
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
URL=https://github.com/github/codeql-cli-binaries/releases
|
||||
LATEST_VERSION=$(curl -L -s -H 'Accept: application/json' $URL/latest | sed -e 's/.*"tag_name":"\([^"]*\)".*/\1/')
|
||||
CURRENT_VERSION=v$(codeql version 2>/dev/null | sed -ne 's/.*release \([0-9.]*\)\./\1/p')
|
||||
if [[ $CURRENT_VERSION != $LATEST_VERSION ]]; then
|
||||
if [[ $UID != 0 ]]; then
|
||||
echo "update required, please run this script with sudo:"
|
||||
echo " sudo $0"
|
||||
exit 1
|
||||
fi
|
||||
ZIP=$(mktemp codeql.XXXX.zip)
|
||||
curl -fSqL -o $ZIP $URL/download/$LATEST_VERSION/codeql-linux64.zip
|
||||
unzip -q $ZIP -d /opt
|
||||
rm $ZIP
|
||||
ln -sf /opt/codeql/codeql /usr/local/bin/codeql
|
||||
echo installed version $LATEST_VERSION
|
||||
else
|
||||
echo current version $CURRENT_VERSION is up-to-date
|
||||
fi
|
||||
@@ -1,13 +0,0 @@
|
||||
set -xe
|
||||
|
||||
# add the workspace to the codeql search path
|
||||
mkdir -p /home/vscode/.config/codeql
|
||||
echo "--search-path /workspaces/codeql" > /home/vscode/.config/codeql/config
|
||||
|
||||
# create a swift extractor pack with the current state
|
||||
cd /workspaces/codeql
|
||||
bazel run swift/create-extractor-pack
|
||||
|
||||
#install and set up pre-commit
|
||||
python3 -m pip install pre-commit --no-warn-script-location
|
||||
$HOME/.local/bin/pre-commit install
|
||||
9
.gitattributes
vendored
9
.gitattributes
vendored
@@ -39,7 +39,6 @@
|
||||
*.py text
|
||||
*.lua text
|
||||
*.expected text
|
||||
*.go text
|
||||
|
||||
# Explicitly set a bunch of known extensions to binary, because Git < 2.10 will treat
|
||||
# `* text=auto eol=lf` as `* text eol=lf`
|
||||
@@ -53,14 +52,6 @@
|
||||
java/ql/test/stubs/**/*.java linguist-generated=true
|
||||
java/ql/test/experimental/stubs/**/*.java linguist-generated=true
|
||||
|
||||
# Force git not to modify line endings for go or html files under the go/ql directory
|
||||
go/ql/**/*.go -text
|
||||
go/ql/**/*.html -text
|
||||
# Force git not to modify line endings for go dbschemes
|
||||
go/*.dbscheme -text
|
||||
# Preserve unusual line ending from codeql-go merge
|
||||
go/extractor/opencsv/CSVReader.java -text
|
||||
|
||||
# For some languages, upgrade script testing references really old dbscheme
|
||||
# files from legacy upgrades that have CRLF line endings. Since upgrade
|
||||
# resolution relies on object hashes, we must suppress line ending conversion
|
||||
|
||||
8
.github/dependabot.yml
vendored
8
.github/dependabot.yml
vendored
@@ -16,11 +16,3 @@ updates:
|
||||
directory: "ruby/autobuilder"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
ignore:
|
||||
- dependency-name: '*'
|
||||
update-types: ['version-update:semver-patch', 'version-update:semver-minor']
|
||||
|
||||
21
.github/labeler.yml
vendored
21
.github/labeler.yml
vendored
@@ -6,23 +6,14 @@
|
||||
- csharp/**/*
|
||||
- change-notes/**/*csharp*
|
||||
|
||||
Go:
|
||||
- go/**/*
|
||||
- change-notes/**/*go.*
|
||||
|
||||
Java:
|
||||
- any: [ 'java/**/*', '!java/kotlin-extractor/**/*', '!java/kotlin-explorer/**/*', '!java/ql/test/kotlin/**/*' ]
|
||||
- java/**/*
|
||||
- change-notes/**/*java.*
|
||||
|
||||
JS:
|
||||
- any: [ 'javascript/**/*', '!javascript/ql/experimental/adaptivethreatmodeling/**/*' ]
|
||||
- javascript/**/*
|
||||
- change-notes/**/*javascript*
|
||||
|
||||
Kotlin:
|
||||
- java/kotlin-extractor/**/*
|
||||
- java/kotlin-explorer/**/*
|
||||
- java/ql/test/kotlin/**/*
|
||||
|
||||
Python:
|
||||
- python/**/*
|
||||
- change-notes/**/*python*
|
||||
@@ -31,14 +22,10 @@ Ruby:
|
||||
- ruby/**/*
|
||||
- change-notes/**/*ruby*
|
||||
|
||||
Swift:
|
||||
- swift/**/*
|
||||
- change-notes/**/*swift*
|
||||
|
||||
documentation:
|
||||
- "**/*.qhelp"
|
||||
- "**/*.md"
|
||||
- docs/**/*
|
||||
|
||||
"QL-for-QL":
|
||||
- ql/**/*
|
||||
"QL-for-QL":
|
||||
- ql/**/*
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "codeql-query-format",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^((.*) would change by autoformatting\\.)$",
|
||||
"file": 2,
|
||||
"message": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "codeql-syntax-check",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^((ERROR|WARNING): .* \\((.*):(\\d+),(\\d+)-\\d+\\))$",
|
||||
"message": 1,
|
||||
"file": 3,
|
||||
"line": 4,
|
||||
"col": 5,
|
||||
"severity": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
14
.github/problem-matchers/codeql-test-run.json
vendored
14
.github/problem-matchers/codeql-test-run.json
vendored
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "codeql-test-run",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "(\\[.*\\] FAILED\\((RESULT|COMPILATION)\\) (.*))$",
|
||||
"file": 3,
|
||||
"message": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
13
.github/problem-matchers/make.json
vendored
13
.github/problem-matchers/make.json
vendored
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "make",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(make: \\*\\*\\* .*)$",
|
||||
"message": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
5
.github/workflows/check-qldoc.yml
vendored
5
.github/workflows/check-qldoc.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -30,8 +30,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
EXIT_CODE=0
|
||||
# TODO: remove the swift exception from the regex when we fix generated QLdoc
|
||||
changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -Po '^(?!swift)[a-z]*/ql/lib' || true; } | sort -u)"
|
||||
changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -o '^[a-z]*/ql/lib' || true; } | sort -u)"
|
||||
for pack_dir in ${changed_lib_packs}; do
|
||||
lang="${pack_dir%/ql/lib}"
|
||||
gh codeql generate library-doc-coverage --output="${RUNNER_TEMP}/${lang}-current.txt" --dir="${pack_dir}"
|
||||
|
||||
2
.github/workflows/close-stale.yml
vendored
2
.github/workflows/close-stale.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v5
|
||||
- uses: actions/stale@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Comment or remove the `Stale` label in order to avoid having this issue closed in 7 days.'
|
||||
|
||||
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@@ -28,12 +28,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v2
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 6.0.202
|
||||
dotnet-version: 6.0.101
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
# uses: github/codeql-action/autobuild@main
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
|
||||
43
.github/workflows/csv-coverage-metrics.yml
vendored
43
.github/workflows/csv-coverage-metrics.yml
vendored
@@ -14,11 +14,11 @@ on:
|
||||
- ".github/workflows/csv-coverage-metrics.yml"
|
||||
|
||||
jobs:
|
||||
publish-java:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup CodeQL
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
- name: Create empty database
|
||||
@@ -31,40 +31,13 @@ jobs:
|
||||
- name: Capture coverage information
|
||||
run: |
|
||||
DATABASE="${{ runner.temp }}/java-database"
|
||||
codeql database analyze --format=sarif-latest --output=metrics-java.sarif -- "$DATABASE" ./java/ql/src/Metrics/Summaries/FrameworkCoverage.ql
|
||||
- uses: actions/upload-artifact@v3
|
||||
codeql database analyze --format=sarif-latest --output=metrics.sarif -- "$DATABASE" ./java/ql/src/Metrics/Summaries/FrameworkCoverage.ql
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: metrics-java.sarif
|
||||
path: metrics-java.sarif
|
||||
name: metrics.sarif
|
||||
path: metrics.sarif
|
||||
retention-days: 20
|
||||
- name: Upload SARIF file
|
||||
uses: github/codeql-action/upload-sarif@main
|
||||
uses: github/codeql-action/upload-sarif@v1
|
||||
with:
|
||||
sarif_file: metrics-java.sarif
|
||||
|
||||
publish-csharp:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup CodeQL
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
- name: Create empty database
|
||||
run: |
|
||||
DATABASE="${{ runner.temp }}/csharp-database"
|
||||
PROJECT="${{ runner.temp }}/csharp-project"
|
||||
dotnet new classlib --language=C# --output="$PROJECT"
|
||||
codeql database create "$DATABASE" --language=csharp --source-root="$PROJECT" --command 'dotnet build /t:rebuild csharp-project.csproj /p:UseSharedCompilation=false'
|
||||
- name: Capture coverage information
|
||||
run: |
|
||||
DATABASE="${{ runner.temp }}/csharp-database"
|
||||
codeql database analyze --format=sarif-latest --output=metrics-csharp.sarif -- "$DATABASE" ./csharp/ql/src/Metrics/Summaries/FrameworkCoverage.ql
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: metrics-csharp.sarif
|
||||
path: metrics-csharp.sarif
|
||||
retention-days: 20
|
||||
- name: Upload SARIF file
|
||||
uses: github/codeql-action/upload-sarif@main
|
||||
with:
|
||||
sarif_file: metrics-csharp.sarif
|
||||
sarif_file: metrics.sarif
|
||||
|
||||
14
.github/workflows/csv-coverage-pr-artifacts.yml
vendored
14
.github/workflows/csv-coverage-pr-artifacts.yml
vendored
@@ -28,11 +28,11 @@ jobs:
|
||||
GITHUB_CONTEXT: ${{ toJSON(github.event) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
- name: Clone self (github/codeql) - MERGE
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: merge
|
||||
- name: Clone self (github/codeql) - BASE
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 2
|
||||
path: base
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
git log -1 --format='%H'
|
||||
working-directory: base
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Download CodeQL CLI
|
||||
@@ -69,21 +69,21 @@ jobs:
|
||||
run: |
|
||||
python base/misc/scripts/library-coverage/compare-folders.py out_base out_merge comparison.md
|
||||
- name: Upload CSV package list
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: csv-framework-coverage-merge
|
||||
path: |
|
||||
out_merge/framework-coverage-*.csv
|
||||
out_merge/framework-coverage-*.rst
|
||||
- name: Upload CSV package list
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: csv-framework-coverage-base
|
||||
path: |
|
||||
out_base/framework-coverage-*.csv
|
||||
out_base/framework-coverage-*.rst
|
||||
- name: Upload comparison results
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: comparison
|
||||
path: |
|
||||
@@ -93,7 +93,7 @@ jobs:
|
||||
mkdir -p pr
|
||||
echo ${{ github.event.pull_request.number }} > pr/NR
|
||||
- name: Upload PR number
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: pr
|
||||
path: pr/
|
||||
|
||||
@@ -20,9 +20,9 @@ jobs:
|
||||
GITHUB_CONTEXT: ${{ toJSON(github.event) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
- name: Clone self (github/codeql)
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
|
||||
|
||||
@@ -10,16 +10,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Clone self (github/codeql)
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: script
|
||||
- name: Clone self (github/codeql) for analysis
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: codeqlModels
|
||||
fetch-depth: 0
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Download CodeQL CLI
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
echo $CLI
|
||||
PATH="$PATH:$CLI" python script/misc/scripts/library-coverage/generate-timeseries.py codeqlModels
|
||||
- name: Upload timeseries CSV
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: framework-coverage-timeseries
|
||||
path: framework-coverage-timeseries-*.csv
|
||||
|
||||
4
.github/workflows/csv-coverage-update.yml
vendored
4
.github/workflows/csv-coverage-update.yml
vendored
@@ -17,12 +17,12 @@ jobs:
|
||||
GITHUB_CONTEXT: ${{ toJSON(github.event) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
- name: Clone self (github/codeql)
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: ql
|
||||
fetch-depth: 0
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Download CodeQL CLI
|
||||
|
||||
10
.github/workflows/csv-coverage.yml
vendored
10
.github/workflows/csv-coverage.yml
vendored
@@ -14,16 +14,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Clone self (github/codeql)
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: script
|
||||
- name: Clone self (github/codeql) for analysis
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: codeqlModels
|
||||
ref: ${{ github.event.inputs.qlModelShaOverride || github.ref }}
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Download CodeQL CLI
|
||||
@@ -37,12 +37,12 @@ jobs:
|
||||
run: |
|
||||
PATH="$PATH:codeql-cli/codeql" python script/misc/scripts/library-coverage/generate-report.py ci codeqlModels script
|
||||
- name: Upload CSV package list
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: framework-coverage-csv
|
||||
path: framework-coverage-*.csv
|
||||
- name: Upload RST package list
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: framework-coverage-rst
|
||||
path: framework-coverage-*.rst
|
||||
|
||||
162
.github/workflows/go-tests.yml
vendored
162
.github/workflows/go-tests.yml
vendored
@@ -1,162 +0,0 @@
|
||||
name: "Go: Run Tests"
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "go/**"
|
||||
- .github/workflows/go-tests.yml
|
||||
- codeql-workspace.yml
|
||||
jobs:
|
||||
|
||||
test-linux:
|
||||
name: Test Linux (Ubuntu)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.18.1
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.18.1
|
||||
id: go
|
||||
|
||||
- name: Set up CodeQL CLI
|
||||
run: |
|
||||
echo "Removing old CodeQL Directory..."
|
||||
rm -rf $HOME/codeql
|
||||
echo "Done"
|
||||
cd $HOME
|
||||
echo "Downloading CodeQL CLI..."
|
||||
LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | sort --version-sort | grep -v beta | tail -1)
|
||||
gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-linux64.zip "$LATEST"
|
||||
echo "Done"
|
||||
echo "Unpacking CodeQL CLI..."
|
||||
unzip -q codeql-linux64.zip
|
||||
rm -f codeql-linux64.zip
|
||||
echo "Done"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Enable problem matchers in repository
|
||||
shell: bash
|
||||
run: 'find .github/problem-matchers -name \*.json -exec echo "::add-matcher::{}" \;'
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd go
|
||||
env PATH=$PATH:$HOME/codeql make
|
||||
|
||||
- name: Check that all QL and Go code is autoformatted
|
||||
run: |
|
||||
cd go
|
||||
env PATH=$PATH:$HOME/codeql make check-formatting
|
||||
|
||||
- name: Compile qhelp files to markdown
|
||||
run: |
|
||||
cd go
|
||||
env PATH=$PATH:$HOME/codeql QHELP_OUT_DIR=qhelp-out make qhelp-to-markdown
|
||||
|
||||
- name: Upload qhelp markdown
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: qhelp-markdown
|
||||
path: go/qhelp-out/**/*.md
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
cd go
|
||||
env PATH=$PATH:$HOME/codeql make test
|
||||
|
||||
test-mac:
|
||||
name: Test MacOS
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- name: Set up Go 1.18.1
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.18.1
|
||||
id: go
|
||||
|
||||
- name: Set up CodeQL CLI
|
||||
run: |
|
||||
echo "Removing old CodeQL Directory..."
|
||||
rm -rf $HOME/codeql
|
||||
echo "Done"
|
||||
cd $HOME
|
||||
echo "Downloading CodeQL CLI..."
|
||||
LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | sort --version-sort | grep -v beta | tail -1)
|
||||
gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-osx64.zip "$LATEST"
|
||||
echo "Done"
|
||||
echo "Unpacking CodeQL CLI..."
|
||||
unzip -q codeql-osx64.zip
|
||||
rm -f codeql-osx64.zip
|
||||
echo "Done"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Enable problem matchers in repository
|
||||
shell: bash
|
||||
run: 'find .github/problem-matchers -name \*.json -exec echo "::add-matcher::{}" \;'
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd go
|
||||
env PATH=$PATH:$HOME/codeql make
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
cd go
|
||||
env PATH=$PATH:$HOME/codeql make test
|
||||
|
||||
test-win:
|
||||
name: Test Windows
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- name: Set up Go 1.18.1
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.18.1
|
||||
id: go
|
||||
|
||||
- name: Set up CodeQL CLI
|
||||
run: |
|
||||
echo "Removing old CodeQL Directory..."
|
||||
rm -rf $HOME/codeql
|
||||
echo "Done"
|
||||
cd "$HOME"
|
||||
echo "Downloading CodeQL CLI..."
|
||||
LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | sort --version-sort | grep -v beta | tail -1)
|
||||
gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-win64.zip "$LATEST"
|
||||
echo "Done"
|
||||
echo "Unpacking CodeQL CLI..."
|
||||
unzip -q -o codeql-win64.zip
|
||||
unzip -q -o codeql-win64.zip codeql/codeql.exe
|
||||
rm -f codeql-win64.zip
|
||||
echo "Done"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
shell:
|
||||
bash
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Enable problem matchers in repository
|
||||
shell: bash
|
||||
run: 'find .github/problem-matchers -name \*.json -exec echo "::add-matcher::{}" \;'
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
$Env:Path += ";$HOME\codeql"
|
||||
cd go
|
||||
make
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
$Env:Path += ";$HOME\codeql"
|
||||
cd go
|
||||
make test
|
||||
9
.github/workflows/js-ml-tests.yml
vendored
9
.github/workflows/js-ml-tests.yml
vendored
@@ -5,7 +5,6 @@ on:
|
||||
paths:
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/**"
|
||||
- .github/workflows/js-ml-tests.yml
|
||||
- codeql-workspace.yml
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
@@ -13,8 +12,6 @@ on:
|
||||
paths:
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/**"
|
||||
- .github/workflows/js-ml-tests.yml
|
||||
- codeql-workspace.yml
|
||||
workflow_dispatch:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -25,7 +22,7 @@ jobs:
|
||||
name: Check QL formatting
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
|
||||
@@ -38,7 +35,7 @@ jobs:
|
||||
name: Check QL compilation
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
|
||||
@@ -62,7 +59,7 @@ jobs:
|
||||
name: Run QL tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
|
||||
|
||||
5
.github/workflows/labeler.yml
vendored
5
.github/workflows/labeler.yml
vendored
@@ -4,11 +4,8 @@ on:
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v4
|
||||
- uses: actions/labeler@v2
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
||||
10
.github/workflows/mad_modelDiff.yml
vendored
10
.github/workflows/mad_modelDiff.yml
vendored
@@ -27,12 +27,12 @@ jobs:
|
||||
slug: ${{fromJson(github.event.inputs.projects || '["apache/commons-codec", "apache/commons-io", "apache/commons-beanutils", "apache/commons-logging", "apache/commons-fileupload", "apache/commons-lang", "apache/commons-validator", "apache/commons-csv", "apache/dubbo"]' )}}
|
||||
steps:
|
||||
- name: Clone github/codeql from PR
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
if: github.event.pull_request
|
||||
with:
|
||||
path: codeql-pr
|
||||
- name: Clone github/codeql from main
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: codeql-main
|
||||
ref: main
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
DATABASE=$2
|
||||
cd codeql-$QL_VARIANT
|
||||
SHORTNAME=`basename $DATABASE`
|
||||
python java/ql/src/utils/model-generator/GenerateFlowModel.py --with-summaries --with-sinks $DATABASE $MODELS/${SHORTNAME}.qll
|
||||
python java/ql/src/utils/model-generator/GenerateFlowModel.py $DATABASE $MODELS/${SHORTNAME}.qll
|
||||
mv $MODELS/${SHORTNAME}.qll $MODELS/${SHORTNAME}Generated_${QL_VARIANT}.qll
|
||||
cd ..
|
||||
}
|
||||
@@ -91,12 +91,12 @@ jobs:
|
||||
name="diff_${basename/_main.qll/""}"
|
||||
(diff -w -u $m $t | diff2html -i stdin -F $MODELS/$name.html) || true
|
||||
done
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: models
|
||||
path: tmp-models/*.qll
|
||||
retention-days: 20
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: diffs
|
||||
path: tmp-models/*.html
|
||||
|
||||
8
.github/workflows/mad_regenerate-models.yml
vendored
8
.github/workflows/mad_regenerate-models.yml
vendored
@@ -20,17 +20,17 @@ jobs:
|
||||
ref: ["placeholder"]
|
||||
include:
|
||||
- slug: "apache/commons-io"
|
||||
ref: "13258ce2d07aa0e764bbaa8020af4dcd3a02a620"
|
||||
ref: "8985de8fe74f6622a419b37a6eed0dbc484dc128"
|
||||
exclude:
|
||||
- slug: "placeholder"
|
||||
ref: "placeholder"
|
||||
steps:
|
||||
- name: Clone self (github/codeql)
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup CodeQL binaries
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
- name: Clone repositories
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: repos/${{ matrix.ref }}
|
||||
ref: ${{ matrix.ref }}
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
find java -name "*.qll" -print0 | xargs -0 git add
|
||||
git status
|
||||
git diff --cached > models.patch
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: patch
|
||||
path: models.patch
|
||||
|
||||
8
.github/workflows/qhelp-pr-preview.yml
vendored
8
.github/workflows/qhelp-pr-preview.yml
vendored
@@ -36,14 +36,14 @@ jobs:
|
||||
- run: echo "${PR_NUMBER}" > pr_number.txt
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.number }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: comment
|
||||
path: pr_number.txt
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 2
|
||||
persist-credentials: false
|
||||
@@ -78,7 +78,7 @@ jobs:
|
||||
exit "${EXIT_CODE}"
|
||||
|
||||
- if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: comment
|
||||
path: comment_body.txt
|
||||
@@ -94,7 +94,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
PR_NUMBER: ${{ github.event.number }}
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: comment
|
||||
path: comment_id.txt
|
||||
|
||||
30
.github/workflows/ql-for-ql-build.yml
vendored
30
.github/workflows/ql-for-ql-build.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
queries:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
- name: Cache queries
|
||||
id: cache-queries
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ runner.temp }}/query-pack.zip
|
||||
key: queries-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
PACKZIP: ${{ runner.temp }}/query-pack.zip
|
||||
- name: Upload query pack
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: query-pack-zip
|
||||
path: ${{ runner.temp }}/query-pack.zip
|
||||
@@ -56,10 +56,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache entire extractor
|
||||
id: cache-extractor
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
ql/target/release/ql-autobuilder
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
key: ${{ runner.os }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
|
||||
- name: Cache cargo
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
@@ -91,7 +91,7 @@ jobs:
|
||||
- name: Generate dbscheme
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
run: ql/target/release/ql-generator --dbscheme ql/ql/src/ql.dbscheme --library ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: extractor-ubuntu-latest
|
||||
path: |
|
||||
@@ -108,12 +108,12 @@ jobs:
|
||||
- queries
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: query-pack-zip
|
||||
path: query-pack-zip
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: extractor-ubuntu-latest
|
||||
path: linux64
|
||||
@@ -131,7 +131,7 @@ jobs:
|
||||
fi
|
||||
cd pack
|
||||
zip -rq ../codeql-ql.zip .
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: codeql-ql-pack
|
||||
path: codeql-ql.zip
|
||||
@@ -140,14 +140,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
folder: [cpp, csharp, java, javascript, python, ql, ruby, swift, go]
|
||||
folder: [cpp, csharp, java, javascript, python, ql, ruby]
|
||||
|
||||
needs:
|
||||
- package
|
||||
|
||||
steps:
|
||||
- name: Download pack
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: codeql-ql-pack
|
||||
path: ${{ runner.temp }}/codeql-ql-pack-artifact
|
||||
@@ -166,7 +166,7 @@ jobs:
|
||||
PACK: ${{ runner.temp }}/pack
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
- name: Create CodeQL config file
|
||||
run: |
|
||||
echo "paths:" > ${CONF}
|
||||
@@ -196,7 +196,7 @@ jobs:
|
||||
- name: Copy sarif file to CWD
|
||||
run: cp ../results/ql.sarif ./${{ matrix.folder }}.sarif
|
||||
- name: Sarif as artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ matrix.folder }}.sarif
|
||||
path: ${{ matrix.folder }}.sarif
|
||||
|
||||
17
.github/workflows/ql-for-ql-dataset_measure.yml
vendored
17
.github/workflows/ql-for-ql-dataset_measure.yml
vendored
@@ -19,16 +19,17 @@ jobs:
|
||||
matrix:
|
||||
repo:
|
||||
- github/codeql
|
||||
- github/codeql-go
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
@@ -40,7 +41,7 @@ jobs:
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
- name: Checkout ${{ matrix.repo }}
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: ${{ matrix.repo }}
|
||||
path: ${{ github.workspace }}/repo
|
||||
@@ -59,7 +60,7 @@ jobs:
|
||||
"${CODEQL}" dataset measure --threads 4 --output "stats/${{ matrix.repo }}/stats.xml" "${{ runner.temp }}/database/db-ql"
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: measurements
|
||||
path: stats
|
||||
@@ -69,15 +70,15 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: measure
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
- 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' -print0 | sort -z | xargs -0 python ruby/scripts/merge_stats.py --output ql/ql/src/ql.dbscheme.stats --normalise ql_tokeninfo
|
||||
- uses: actions/upload-artifact@v3
|
||||
find stats -name 'stats.xml' -print0 | sort -z | xargs -0 python ql/scripts/merge_stats.py --output ql/ql/src/ql.dbscheme.stats --normalise ql_tokeninfo
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ql.dbscheme.stats
|
||||
path: ql/ql/src/ql.dbscheme.stats
|
||||
|
||||
6
.github/workflows/ql-for-ql-tests.yml
vendored
6
.github/workflows/ql-for-ql-tests.yml
vendored
@@ -5,12 +5,10 @@ on:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "ql/**"
|
||||
- codeql-workspace.yml
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "ql/**"
|
||||
- codeql-workspace.yml
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
@@ -19,13 +17,13 @@ jobs:
|
||||
qltest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
|
||||
24
.github/workflows/query-list.yml
vendored
24
.github/workflows/query-list.yml
vendored
@@ -5,8 +5,6 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- 'rc/**'
|
||||
tags:
|
||||
- 'codeql-cli/*'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/query-list.yml'
|
||||
@@ -19,23 +17,33 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Clone self (github/codeql)
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: codeql
|
||||
- name: Clone github/codeql-go
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: 'github/codeql-go'
|
||||
path: codeql-go
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Download CodeQL CLI
|
||||
# Look under the `codeql` directory, as this is where we checked out the `github/codeql` repo
|
||||
uses: ./codeql/.github/actions/fetch-codeql
|
||||
uses: dsaltares/fetch-gh-release-asset@aa37ae5c44d3c9820bc12fe675e8670ecd93bd1c
|
||||
with:
|
||||
repo: "github/codeql-cli-binaries"
|
||||
version: "latest"
|
||||
file: "codeql-linux64.zip"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Unzip CodeQL CLI
|
||||
run: unzip -d codeql-cli codeql-linux64.zip
|
||||
- name: Build code scanning query list
|
||||
run: |
|
||||
python codeql/misc/scripts/generate-code-scanning-query-list.py > code-scanning-query-list.csv
|
||||
PATH="$PATH:codeql-cli/codeql" python codeql/misc/scripts/generate-code-scanning-query-list.py > code-scanning-query-list.csv
|
||||
- name: Upload code scanning query list
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: code-scanning-query-list
|
||||
path: code-scanning-query-list.csv
|
||||
|
||||
|
||||
36
.github/workflows/ruby-build.yml
vendored
36
.github/workflows/ruby-build.yml
vendored
@@ -5,7 +5,6 @@ on:
|
||||
paths:
|
||||
- "ruby/**"
|
||||
- .github/workflows/ruby-build.yml
|
||||
- codeql-workspace.yml
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
@@ -13,7 +12,6 @@ on:
|
||||
paths:
|
||||
- "ruby/**"
|
||||
- .github/workflows/ruby-build.yml
|
||||
- codeql-workspace.yml
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
@@ -40,13 +38,13 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- 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@v3
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
@@ -64,17 +62,17 @@ jobs:
|
||||
- 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@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
with:
|
||||
name: ruby.dbscheme
|
||||
path: ruby/ql/lib/ruby.dbscheme
|
||||
- uses: actions/upload-artifact@v3
|
||||
- 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@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: extractor-${{ matrix.os }}
|
||||
path: |
|
||||
@@ -88,7 +86,7 @@ jobs:
|
||||
env:
|
||||
CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- 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)
|
||||
@@ -104,7 +102,7 @@ jobs:
|
||||
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@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: codeql-ruby-queries
|
||||
path: |
|
||||
@@ -115,20 +113,20 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build, compile-queries]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: ruby.dbscheme
|
||||
path: ruby/ruby
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: extractor-ubuntu-latest
|
||||
path: ruby/linux64
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: extractor-windows-latest
|
||||
path: ruby/win64
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: extractor-macos-latest
|
||||
path: ruby/osx64
|
||||
@@ -144,12 +142,12 @@ jobs:
|
||||
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@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: codeql-ruby-pack
|
||||
path: ruby/codeql-ruby.zip
|
||||
retention-days: 1
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: codeql-ruby-queries
|
||||
path: ruby/qlpacks
|
||||
@@ -161,7 +159,7 @@ jobs:
|
||||
]
|
||||
}' > .codeqlmanifest.json
|
||||
zip -rq codeql-ruby-bundle.zip .codeqlmanifest.json ruby qlpacks
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: codeql-ruby-bundle
|
||||
path: ruby/codeql-ruby-bundle.zip
|
||||
@@ -179,7 +177,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: [package]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
repository: Shopify/example-ruby-app
|
||||
ref: 67a0decc5eb550f3a9228eda53925c3afd40dfe9
|
||||
@@ -193,7 +191,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
working-directory: ${{ runner.temp }}
|
||||
- name: Download Ruby bundle
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: codeql-ruby-bundle
|
||||
path: ${{ runner.temp }}
|
||||
|
||||
12
.github/workflows/ruby-dataset-measure.yml
vendored
12
.github/workflows/ruby-dataset-measure.yml
vendored
@@ -27,14 +27,14 @@ jobs:
|
||||
repo: [rails/rails, discourse/discourse, spree/spree, ruby/ruby]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
|
||||
- uses: ./ruby/actions/create-extractor-pack
|
||||
|
||||
- name: Checkout ${{ matrix.repo }}
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: ${{ matrix.repo }}
|
||||
path: ${{ github.workspace }}/repo
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
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@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: measurements
|
||||
path: stats
|
||||
@@ -59,15 +59,15 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: measure
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
- 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@v3
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ruby.dbscheme.stats
|
||||
path: ruby/ql/lib/ruby.dbscheme.stats
|
||||
|
||||
10
.github/workflows/ruby-qltest.yml
vendored
10
.github/workflows/ruby-qltest.yml
vendored
@@ -5,7 +5,6 @@ on:
|
||||
paths:
|
||||
- "ruby/**"
|
||||
- .github/workflows/ruby-qltest.yml
|
||||
- codeql-workspace.yml
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
@@ -13,7 +12,6 @@ on:
|
||||
paths:
|
||||
- "ruby/**"
|
||||
- .github/workflows/ruby-qltest.yml
|
||||
- codeql-workspace.yml
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
@@ -29,14 +27,14 @@ jobs:
|
||||
qlformat:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- name: Check QL formatting
|
||||
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
|
||||
qlcompile:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- name: Check QL compilation
|
||||
run: |
|
||||
@@ -46,7 +44,7 @@ jobs:
|
||||
qlupgrade:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- name: Check DB upgrade scripts
|
||||
run: |
|
||||
@@ -69,7 +67,7 @@ jobs:
|
||||
matrix:
|
||||
slice: ["1/2", "2/2"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: ./ruby/actions/create-extractor-pack
|
||||
- name: Run QL tests
|
||||
|
||||
32
.github/workflows/swift-codegen.yml
vendored
32
.github/workflows/swift-codegen.yml
vendored
@@ -1,32 +0,0 @@
|
||||
name: "Swift: Check code generation"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "swift/**"
|
||||
- .github/workflows/swift-codegen.yml
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
codegen:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: bazelbuild/setup-bazelisk@v2
|
||||
- name: Run unit tests
|
||||
run: |
|
||||
bazel test //swift/codegen/test --test_output=errors
|
||||
- name: Check that QL generated code was checked in
|
||||
run: |
|
||||
bazel run //swift/codegen
|
||||
git add swift
|
||||
git diff --exit-code HEAD
|
||||
- name: Generate C++ files
|
||||
run: |
|
||||
bazel run //swift/codegen:codegen -- --generate=trap,cpp --cpp-output=$PWD/swift-generated-headers
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: swift-generated-headers
|
||||
path: swift-generated-headers/*.h
|
||||
19
.github/workflows/swift-qltest.yml
vendored
19
.github/workflows/swift-qltest.yml
vendored
@@ -5,7 +5,6 @@ on:
|
||||
paths:
|
||||
- "swift/**"
|
||||
- .github/workflows/swift-qltest.yml
|
||||
- codeql-workspace.yml
|
||||
branches:
|
||||
- main
|
||||
defaults:
|
||||
@@ -16,7 +15,7 @@ jobs:
|
||||
qlformat:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- name: Check QL formatting
|
||||
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
|
||||
@@ -27,9 +26,20 @@ jobs:
|
||||
matrix:
|
||||
os : [ubuntu-20.04, macos-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: bazelbuild/setup-bazelisk@v2
|
||||
- name: Install bazelisk - Linux
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y wget
|
||||
wget https://github.com/bazelbuild/bazelisk/releases/download/v1.11.0/bazelisk-linux-amd64
|
||||
mv bazelisk-linux-amd64 /usr/local/bin/bazel
|
||||
chmod +x /usr/local/bin/bazel
|
||||
- name: Install bazelisk - macOS
|
||||
if: runner.os == 'MacOS'
|
||||
run: |
|
||||
brew install bazelisk
|
||||
- name: Build Swift extractor
|
||||
run: |
|
||||
bazel run //swift:create-extractor-pack
|
||||
@@ -38,3 +48,4 @@ jobs:
|
||||
codeql test run --threads=0 --ram 5000 --search-path "${{ github.workspace }}/swift/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition ql/test
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
|
||||
2
.github/workflows/sync-files.yml
vendored
2
.github/workflows/sync-files.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
- name: Check synchronized files
|
||||
run: python config/sync-files.py
|
||||
|
||||
|
||||
2
.github/workflows/validate-change-notes.yml
vendored
2
.github/workflows/validate-change-notes.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup CodeQL
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
|
||||
25
.gitignore
vendored
25
.gitignore
vendored
@@ -9,7 +9,6 @@
|
||||
# qltest projects and artifacts
|
||||
*/ql/test/**/*.testproj
|
||||
*/ql/test/**/*.actual
|
||||
*/ql/test/**/go.sum
|
||||
|
||||
# Visual studio temporaries, except a file used by QL4VS
|
||||
.vs/*
|
||||
@@ -21,9 +20,6 @@
|
||||
# python virtual environment folder
|
||||
.venv/
|
||||
|
||||
# binary files created by pytest-cov
|
||||
.coverage
|
||||
|
||||
# It's useful (though not required) to be able to unpack codeql in the ql checkout itself
|
||||
/codeql/
|
||||
|
||||
@@ -38,26 +34,5 @@ csharp/extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
|
||||
# links created by bazel
|
||||
/bazel-*
|
||||
|
||||
# local bazel options
|
||||
/local.bazelrc
|
||||
|
||||
# CLion project files
|
||||
/.clwb
|
||||
|
||||
# Go build artifacts
|
||||
go/build/*
|
||||
|
||||
# Go binaries
|
||||
go/tools/bin
|
||||
go/tools/linux64
|
||||
go/tools/osx64
|
||||
go/tools/win64
|
||||
go/tools/tokenizer.jar
|
||||
go/main
|
||||
|
||||
# node_modules folders except in the JS test suite
|
||||
node_modules/
|
||||
!/javascript/ql/test/**/node_modules/
|
||||
|
||||
# Temporary folders for working with generated models
|
||||
.model-temp
|
||||
|
||||
@@ -6,7 +6,6 @@ path_classifiers:
|
||||
test:
|
||||
- csharp/ql/src
|
||||
- csharp/ql/test
|
||||
- go/ql/test
|
||||
- javascript/extractor/parser-tests
|
||||
- javascript/extractor/tests
|
||||
- javascript/ql/src
|
||||
@@ -14,9 +13,6 @@ path_classifiers:
|
||||
- python/ql/src
|
||||
- python/ql/test
|
||||
|
||||
example:
|
||||
- go/ql/src
|
||||
|
||||
queries:
|
||||
- include: "*"
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
# See https://pre-commit.com for more information
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v3.2.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)
|
||||
- id: end-of-file-fixer
|
||||
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v13.0.1
|
||||
@@ -25,7 +24,6 @@ repos:
|
||||
|
||||
- id: sync-files
|
||||
name: Fix files required to be identical
|
||||
files: \.(qll?|qhelp|swift)$
|
||||
language: system
|
||||
entry: python3 config/sync-files.py --latest
|
||||
pass_filenames: false
|
||||
@@ -38,14 +36,7 @@ repos:
|
||||
|
||||
- id: swift-codegen
|
||||
name: Run Swift checked in code generation
|
||||
files: ^swift/(codegen/|.*/generated/|ql/lib/(swift\.dbscheme$|codeql/swift/elements))
|
||||
files: ^swift/(codegen/|.*/generated/|ql/lib/swift\.dbscheme$)
|
||||
language: system
|
||||
entry: bazel run //swift/codegen -- --quiet
|
||||
pass_filenames: false
|
||||
|
||||
- id: swift-codegen-unit-tests
|
||||
name: Run Swift code generation unit tests
|
||||
files: ^swift/codegen/.*\.py$
|
||||
language: system
|
||||
entry: bazel test //swift/codegen/test
|
||||
entry: bazel run //swift/codegen
|
||||
pass_filenames: false
|
||||
|
||||
15
CODEOWNERS
15
CODEOWNERS
@@ -1,13 +1,9 @@
|
||||
/cpp/ @github/codeql-c-analysis
|
||||
/csharp/ @github/codeql-csharp
|
||||
/go/ @github/codeql-go
|
||||
/java/ @github/codeql-java
|
||||
/javascript/ @github/codeql-javascript
|
||||
/python/ @github/codeql-python
|
||||
/ruby/ @github/codeql-ruby
|
||||
/swift/ @github/codeql-c
|
||||
/java/kotlin-extractor/ @github/codeql-kotlin
|
||||
/java/kotlin-explorer/ @github/codeql-kotlin
|
||||
|
||||
# ML-powered queries
|
||||
/javascript/ql/experimental/adaptivethreatmodeling/ @github/codeql-ml-powered-queries-reviewers
|
||||
@@ -28,17 +24,10 @@
|
||||
# QL for QL reviewers
|
||||
/ql/ @github/codeql-ql-for-ql-reviewers
|
||||
|
||||
# Bazel (excluding BUILD.bazel files)
|
||||
WORKSPACE.bazel @github/codeql-ci-reviewers
|
||||
# Bazel
|
||||
**/*.bazel @github/codeql-ci-reviewers
|
||||
**/*.bzl @github/codeql-ci-reviewers
|
||||
|
||||
# Documentation etc
|
||||
/*.md @github/code-scanning-product
|
||||
/LICENSE @github/code-scanning-product
|
||||
|
||||
# Workflows
|
||||
/.github/workflows/ @github/codeql-ci-reviewers
|
||||
/.github/workflows/go-* @github/codeql-go
|
||||
/.github/workflows/js-ml-tests.yml @github/codeql-ml-powered-queries-reviewers
|
||||
/.github/workflows/ql-for-ql-* @github/codeql-ql-for-ql-reviewers
|
||||
/.github/workflows/ruby-* @github/codeql-ruby
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
We welcome contributions to our CodeQL libraries and queries. Got an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE).
|
||||
|
||||
There is lots of useful documentation to help you write queries, ranging from information about query file structure to tutorials for specific target languages. For more information on the documentation available, see [CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/codeql-queries) on [codeql.github.com](https://codeql.github.com).
|
||||
There is lots of useful documentation to help you write queries, ranging from information about query file structure to tutorials for specific target languages. For more information on the documentation available, see [CodeQL queries](https://help.semmle.com/QL/learn-ql/writing-queries/writing-queries.html) on [help.semmle.com](https://help.semmle.com).
|
||||
|
||||
## Change notes
|
||||
|
||||
@@ -40,7 +40,7 @@ If you have an idea for a query that you would like to share with other CodeQL u
|
||||
|
||||
3. **Formatting**
|
||||
|
||||
- The queries and libraries must be autoformatted, for example using the "Format Document" command in [CodeQL for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/about-codeql-for-visual-studio-code).
|
||||
- The queries and libraries must be autoformatted, for example using the "Format Document" command in [CodeQL for Visual Studio Code](https://help.semmle.com/codeql/codeql-for-vscode/procedures/about-codeql-for-vscode.html).
|
||||
|
||||
If you prefer, you can either:
|
||||
1. install the [pre-commit framework](https://pre-commit.com/) and install the configured hooks on this repo via `pre-commit install`, or
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# CodeQL
|
||||
|
||||
This open source repository contains the standard CodeQL libraries and queries that power [GitHub Advanced Security](https://github.com/features/security/code) and the other application security products that [GitHub](https://github.com/features/security/) makes available to its customers worldwide.
|
||||
This open source repository contains the standard CodeQL libraries and queries that power [GitHub Advanced Security](https://github.com/features/security/code) and the other application security products that [GitHub](https://github.com/features/security/) makes available to its customers worldwide. For the queries, libraries, and extractor that power Go analysis, visit the [CodeQL for Go repository](https://github.com/github/codeql-go).
|
||||
|
||||
## How do I learn CodeQL and run queries?
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
provide:
|
||||
- "*/ql/src/qlpack.yml"
|
||||
- "*/ql/lib/qlpack.yml"
|
||||
- "*/ql/test/qlpack.yml"
|
||||
- "*/ql/examples/qlpack.yml"
|
||||
- "*/ql/consistency-queries/qlpack.yml"
|
||||
- "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml"
|
||||
- "go/ql/config/legacy-support/qlpack.yml"
|
||||
- "go/build/codeql-extractor-go/codeql-extractor.yml"
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml"
|
||||
# This pack is explicitly excluded from the workspace since most users
|
||||
# will want to use a version of this pack from the package cache. Internal
|
||||
# users can uncomment the following line and place a custom ML model
|
||||
# in the corresponding pack to test a custom ML model within their local
|
||||
# checkout.
|
||||
# - "javascript/ql/experimental/adaptivethreatmodeling/model/qlpack.yml"
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml"
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml"
|
||||
- "csharp/ql/campaigns/Solorigate/lib/qlpack.yml"
|
||||
- "csharp/ql/campaigns/Solorigate/src/qlpack.yml"
|
||||
- "csharp/ql/campaigns/Solorigate/test/qlpack.yml"
|
||||
- "misc/legacy-support/*/qlpack.yml"
|
||||
- "misc/suite-helpers/qlpack.yml"
|
||||
- "ruby/extractor-pack/codeql-extractor.yml"
|
||||
- "swift/extractor-pack/codeql-extractor.yml"
|
||||
- "ql/extractor-pack/codeql-extractor.ym"
|
||||
|
||||
versionPolicies:
|
||||
default:
|
||||
requireChangeNotes: true
|
||||
committedPrereleaseSuffix: dev
|
||||
committedVersion: nextPatchRelease
|
||||
@@ -22,15 +22,13 @@
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplForContentDataFlow.qll",
|
||||
"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",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll"
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll"
|
||||
],
|
||||
"DataFlow Java/C++/C#/Python Common": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
|
||||
@@ -38,8 +36,7 @@
|
||||
"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",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplCommon.qll"
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll"
|
||||
],
|
||||
"TaintTracking::Configuration Java/C++/C#/Python": [
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
@@ -60,8 +57,7 @@
|
||||
"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",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforlibraries/TaintTrackingImpl.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforlibraries/TaintTrackingImpl.qll"
|
||||
],
|
||||
"DataFlow Java/C++/C#/Python Consistency checks": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll",
|
||||
@@ -69,14 +65,12 @@
|
||||
"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",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplConsistency.qll"
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/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",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll"
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll"
|
||||
],
|
||||
"SsaReadPosition Java/C#": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
|
||||
@@ -391,8 +385,7 @@
|
||||
"java/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
||||
"python/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
||||
"ruby/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
||||
"ql/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
||||
"go/ql/test/TestUtilities/InlineExpectationsTest.qll"
|
||||
"ql/ql/test/TestUtilities/InlineExpectationsTest.qll"
|
||||
],
|
||||
"C++ ExternalAPIs": [
|
||||
"cpp/ql/src/Security/CWE/CWE-020/ExternalAPIs.qll",
|
||||
@@ -465,8 +458,7 @@
|
||||
"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",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/SsaImplCommon.qll"
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll"
|
||||
],
|
||||
"CryptoAlgorithms Python/JS/Ruby": [
|
||||
"javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll",
|
||||
@@ -483,23 +475,20 @@
|
||||
"python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll"
|
||||
],
|
||||
"ReDoS Util Python/JS/Ruby/Java": [
|
||||
"ReDoS Util Python/JS/Ruby": [
|
||||
"javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll",
|
||||
"python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll",
|
||||
"java/ql/lib/semmle/code/java/security/performance/ReDoSUtil.qll"
|
||||
"ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll"
|
||||
],
|
||||
"ReDoS Exponential Python/JS/Ruby/Java": [
|
||||
"ReDoS Exponential Python/JS/Ruby": [
|
||||
"javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll",
|
||||
"python/ql/lib/semmle/python/security/performance/ExponentialBackTracking.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll",
|
||||
"java/ql/lib/semmle/code/java/security/performance/ExponentialBackTracking.qll"
|
||||
"ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll"
|
||||
],
|
||||
"ReDoS Polynomial Python/JS/Ruby/Java": [
|
||||
"ReDoS Polynomial Python/JS/Ruby": [
|
||||
"javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
|
||||
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll",
|
||||
"java/ql/lib/semmle/code/java/security/performance/SuperlinearBackTracking.qll"
|
||||
"ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll"
|
||||
],
|
||||
"BadTagFilterQuery Python/JS/Ruby": [
|
||||
"javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll",
|
||||
@@ -508,8 +497,7 @@
|
||||
],
|
||||
"CFG": [
|
||||
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",
|
||||
"ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll",
|
||||
"swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImplShared.qll"
|
||||
"ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll"
|
||||
],
|
||||
"TypeTracker": [
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll",
|
||||
@@ -527,9 +515,7 @@
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/AccessPathSyntax.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/AccessPathSyntax.qll",
|
||||
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/AccessPathSyntax.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/AccessPathSyntax.qll",
|
||||
"python/ql/lib/semmle/python/frameworks/data/internal/AccessPathSyntax.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/AccessPathSyntax.qll"
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/AccessPathSyntax.qll"
|
||||
],
|
||||
"IncompleteUrlSubstringSanitization": [
|
||||
"javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qll",
|
||||
@@ -547,8 +533,7 @@
|
||||
],
|
||||
"ApiGraphModels": [
|
||||
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll",
|
||||
"ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll",
|
||||
"python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll"
|
||||
"ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll"
|
||||
],
|
||||
"TaintedFormatStringQuery Ruby/JS": [
|
||||
"javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatStringQuery.qll",
|
||||
@@ -565,25 +550,5 @@
|
||||
"HttpToFileAccessCustomizations JS/Ruby": [
|
||||
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessCustomizations.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessCustomizations.qll"
|
||||
],
|
||||
"Typo database": [
|
||||
"javascript/ql/src/Expressions/TypoDatabase.qll",
|
||||
"ql/ql/src/codeql_ql/style/TypoDatabase.qll"
|
||||
],
|
||||
"Swift declarations test file": [
|
||||
"swift/ql/test/extractor-tests/declarations/declarations.swift",
|
||||
"swift/ql/test/library-tests/parent/declarations.swift"
|
||||
],
|
||||
"Swift statements test file": [
|
||||
"swift/ql/test/extractor-tests/statements/statements.swift",
|
||||
"swift/ql/test/library-tests/parent/statements.swift"
|
||||
],
|
||||
"Swift expressions test file": [
|
||||
"swift/ql/test/extractor-tests/expressions/expressions.swift",
|
||||
"swift/ql/test/library-tests/parent/expressions.swift"
|
||||
],
|
||||
"Swift patterns test file": [
|
||||
"swift/ql/test/extractor-tests/patterns/patterns.swift",
|
||||
"swift/ql/test/library-tests/parent/patterns.swift"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
# this empty file adds the repo root to PYTHON_PATH when running pytest
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
description: Add relation for tracking C++ braced initializers
|
||||
compatibility: full
|
||||
braced_initialisers.rel: delete
|
||||
@@ -1,21 +0,0 @@
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Expr extends @expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Stmt extends @stmt {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
predicate isStmtWithInitializer(Stmt stmt) {
|
||||
exists(int kind | stmts(stmt, kind, _) | kind = 2 or kind = 11 or kind = 35)
|
||||
}
|
||||
|
||||
from Expr child, int index, int index_new, Element parent
|
||||
where
|
||||
exprparents(child, index, parent) and
|
||||
if isStmtWithInitializer(parent) then index_new = index - 1 else index_new = index
|
||||
select child, index_new, parent
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,22 +0,0 @@
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Stmt extends @stmt {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
predicate isStmtWithInitializer(Stmt stmt) {
|
||||
exists(int kind | stmts(stmt, kind, _) | kind = 2 or kind = 11 or kind = 35)
|
||||
}
|
||||
|
||||
from Stmt child, int index, int index_new, Element parent
|
||||
where
|
||||
stmtparents(child, index, parent) and
|
||||
(
|
||||
not isStmtWithInitializer(parent)
|
||||
or
|
||||
index > 0
|
||||
) and
|
||||
if isStmtWithInitializer(parent) then index_new = index - 1 else index_new = index
|
||||
select child, index_new, parent
|
||||
@@ -1,6 +0,0 @@
|
||||
description: Support C++17 if and switch initializers
|
||||
compatibility: partial
|
||||
if_initialization.rel: delete
|
||||
switch_initialization.rel: delete
|
||||
exprparents.rel: run exprparents.qlo
|
||||
stmtparents.rel: run stmtparents.qlo
|
||||
@@ -1,56 +1,3 @@
|
||||
## 0.3.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The `BarrierGuard` class has been deprecated. Such barriers and sanitizers can now instead be created using the new `BarrierGuard` parameterized module.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* `UserType.getADeclarationEntry()` now yields all forward declarations when the user type is a `class`, `struct`, or `union`.
|
||||
|
||||
## 0.2.3
|
||||
|
||||
### New Features
|
||||
|
||||
* An `isBraced` predicate was added to the `Initializer` class which holds when a C++ braced initializer was used in the initialization.
|
||||
|
||||
## 0.2.2
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The `AnalysedString` class in the `StringAnalysis` module has been replaced with `AnalyzedString`, to follow our style guide. The old name still exists as a deprecated alias.
|
||||
|
||||
### New Features
|
||||
|
||||
* A `getInitialization` predicate was added to the `ConstexprIfStmt`, `IfStmt`, and `SwitchStmt` classes that yields the C++17-style initializer of the `if` or `switch` statement when it exists.
|
||||
|
||||
## 0.2.1
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The signature of `allowImplicitRead` on `DataFlow::Configuration` and `TaintTracking::Configuration` has changed from `allowImplicitRead(DataFlow::Node node, DataFlow::Content c)` to `allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c)`.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* More Windows pool allocation functions are now detected as `AllocationFunction`s.
|
||||
* The `semmle.code.cpp.commons.Buffer` library has been enhanced to handle array members of classes that do not specify a size.
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The recently added flow-state versions of `isBarrierIn`, `isBarrierOut`, `isSanitizerIn`, and `isSanitizerOut` in the data flow and taint tracking libraries have been removed.
|
||||
|
||||
### New Features
|
||||
|
||||
* A new library `semmle.code.cpp.security.PrivateData` has been added. The new library heuristically detects variables and functions dealing with sensitive private data, such as e-mail addresses and credit card numbers.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `semmle.code.cpp.security.SensitiveExprs` library has been enhanced with some additional rules for detecting credentials.
|
||||
|
||||
## 0.0.13
|
||||
|
||||
## 0.0.12
|
||||
|
||||
4
cpp/ql/lib/change-notes/2022-03-28-private-data.md
Normal file
4
cpp/ql/lib/change-notes/2022-03-28-private-data.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* A new library `semmle.code.cpp.security.PrivateData` has been added. The new library heuristically detects variables and functions dealing with sensitive private data, such as e-mail addresses and credit card numbers.
|
||||
4
cpp/ql/lib/change-notes/2022-03-31-sensitive-exprs.md
Normal file
4
cpp/ql/lib/change-notes/2022-03-31-sensitive-exprs.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `semmle.code.cpp.security.SensitiveExprs` library has been enhanced with some additional rules for detecting credentials.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
The recently added flow-state versions of `isBarrierIn`, `isBarrierOut`, `isSanitizerIn`, and `isSanitizerOut` in the data flow and taint tracking libraries have been removed.
|
||||
@@ -1,13 +0,0 @@
|
||||
## 0.1.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The recently added flow-state versions of `isBarrierIn`, `isBarrierOut`, `isSanitizerIn`, and `isSanitizerOut` in the data flow and taint tracking libraries have been removed.
|
||||
|
||||
### New Features
|
||||
|
||||
* A new library `semmle.code.cpp.security.PrivateData` has been added. The new library heuristically detects variables and functions dealing with sensitive private data, such as e-mail addresses and credit card numbers.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `semmle.code.cpp.security.SensitiveExprs` library has been enhanced with some additional rules for detecting credentials.
|
||||
@@ -1,10 +0,0 @@
|
||||
## 0.2.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The signature of `allowImplicitRead` on `DataFlow::Configuration` and `TaintTracking::Configuration` has changed from `allowImplicitRead(DataFlow::Node node, DataFlow::Content c)` to `allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c)`.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* More Windows pool allocation functions are now detected as `AllocationFunction`s.
|
||||
* The `semmle.code.cpp.commons.Buffer` library has been enhanced to handle array members of classes that do not specify a size.
|
||||
@@ -1 +0,0 @@
|
||||
## 0.2.1
|
||||
@@ -1,9 +0,0 @@
|
||||
## 0.2.2
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The `AnalysedString` class in the `StringAnalysis` module has been replaced with `AnalyzedString`, to follow our style guide. The old name still exists as a deprecated alias.
|
||||
|
||||
### New Features
|
||||
|
||||
* A `getInitialization` predicate was added to the `ConstexprIfStmt`, `IfStmt`, and `SwitchStmt` classes that yields the C++17-style initializer of the `if` or `switch` statement when it exists.
|
||||
@@ -1,5 +0,0 @@
|
||||
## 0.2.3
|
||||
|
||||
### New Features
|
||||
|
||||
* An `isBraced` predicate was added to the `Initializer` class which holds when a C++ braced initializer was used in the initialization.
|
||||
@@ -1,9 +0,0 @@
|
||||
## 0.3.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The `BarrierGuard` class has been deprecated. Such barriers and sanitizers can now instead be created using the new `BarrierGuard` parameterized module.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* `UserType.getADeclarationEntry()` now yields all forward declarations when the user type is a `class`, `struct`, or `union`.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.3.0
|
||||
lastReleaseVersion: 0.0.13
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.3.0
|
||||
version: 0.1.0-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
import semmle.code.cpp.Variable
|
||||
import semmle.code.cpp.Enum
|
||||
import semmle.code.cpp.exprs.Access
|
||||
|
||||
/**
|
||||
* A C structure member or C++ non-static member variable. For example the
|
||||
@@ -31,7 +32,7 @@ class Field extends MemberVariable {
|
||||
int getByteOffset() { fieldoffsets(underlyingElement(this), result, _) }
|
||||
|
||||
/**
|
||||
* Gets the byte offset within `mostDerivedClass` of each occurrence of this
|
||||
* Gets the byte offset within `mostDerivedClass` of each occurence of this
|
||||
* field within `mostDerivedClass` itself or a base class subobject of
|
||||
* `mostDerivedClass`.
|
||||
* Note that for fields of virtual base classes, and non-virtual base classes
|
||||
|
||||
@@ -38,8 +38,8 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
|
||||
* int z = min(5, 7);
|
||||
* ```
|
||||
* The full signature of the function called on the last line would be
|
||||
* `min<int>(int, int) -> int`, and the full signature of the uninstantiated
|
||||
* template on the first line would be `min<T>(T, T) -> T`.
|
||||
* "min<int>(int, int) -> int", and the full signature of the uninstantiated
|
||||
* template on the first line would be "min<T>(T, T) -> T".
|
||||
*/
|
||||
string getFullSignature() {
|
||||
exists(string name, string templateArgs, string args |
|
||||
|
||||
@@ -51,7 +51,4 @@ class Initializer extends ControlFlowNode, @initialiser {
|
||||
override Function getControlFlowScope() { result = this.getExpr().getEnclosingFunction() }
|
||||
|
||||
override Stmt getEnclosingStmt() { result = this.getExpr().getEnclosingStmt() }
|
||||
|
||||
/** Holds if the initializer used the C++ braced initializer notation. */
|
||||
predicate isBraced() { braced_initialisers(underlyingElement(this)) }
|
||||
}
|
||||
|
||||
@@ -663,24 +663,18 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred)
|
||||
or
|
||||
s.(ComputedGotoStmt).getExpr() = e and pred = "getExpr()"
|
||||
or
|
||||
s.(ConstexprIfStmt).getInitialization() = e and pred = "getInitialization()"
|
||||
or
|
||||
s.(ConstexprIfStmt).getCondition() = e and pred = "getCondition()"
|
||||
or
|
||||
s.(ConstexprIfStmt).getThen() = e and pred = "getThen()"
|
||||
or
|
||||
s.(ConstexprIfStmt).getElse() = e and pred = "getElse()"
|
||||
or
|
||||
s.(IfStmt).getInitialization() = e and pred = "getInitialization()"
|
||||
or
|
||||
s.(IfStmt).getCondition() = e and pred = "getCondition()"
|
||||
or
|
||||
s.(IfStmt).getThen() = e and pred = "getThen()"
|
||||
or
|
||||
s.(IfStmt).getElse() = e and pred = "getElse()"
|
||||
or
|
||||
s.(SwitchStmt).getInitialization() = e and pred = "getInitialization()"
|
||||
or
|
||||
s.(SwitchStmt).getExpr() = e and pred = "getExpr()"
|
||||
or
|
||||
s.(SwitchStmt).getStmt() = e and pred = "getStmt()"
|
||||
|
||||
@@ -48,8 +48,8 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @
|
||||
}
|
||||
|
||||
override TypeDeclarationEntry getADeclarationEntry() {
|
||||
if type_decls(_, unresolveElement(this), _)
|
||||
then type_decls(underlyingElement(result), unresolveElement(this), _)
|
||||
if type_decls(_, underlyingElement(this), _)
|
||||
then type_decls(unresolveElement(result), underlyingElement(this), _)
|
||||
else exists(Class t | this.(Class).isConstructedFrom(t) and result = t.getADeclarationEntry())
|
||||
}
|
||||
|
||||
|
||||
@@ -10,18 +10,11 @@ import semmle.code.cpp.dataflow.DataFlow
|
||||
* char data[1]; // v
|
||||
* };
|
||||
* ```
|
||||
* or
|
||||
* ```
|
||||
* struct myStruct { // c
|
||||
* int amount;
|
||||
* char data[]; // v
|
||||
* };
|
||||
* ```
|
||||
* This requires that `v` is an array of size 0 or 1, or that the array has no size.
|
||||
* This requires that `v` is an array of size 0 or 1.
|
||||
*/
|
||||
predicate memberMayBeVarSize(Class c, MemberVariable v) {
|
||||
c = v.getDeclaringType() and
|
||||
exists(ArrayType t | t = v.getUnspecifiedType() | not t.getArraySize() > 1)
|
||||
v.getUnspecifiedType().(ArrayType).getArraySize() <= 1
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,18 +40,13 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
||||
result = why.(Expr).getType().(ArrayType).getSize() and
|
||||
not exists(bufferVar.getUnspecifiedType().(ArrayType).getSize())
|
||||
or
|
||||
exists(Class parentClass, VariableAccess parentPtr, int bufferSize |
|
||||
exists(Class parentClass, VariableAccess parentPtr |
|
||||
// buffer is the parentPtr->bufferVar of a 'variable size struct'
|
||||
memberMayBeVarSize(parentClass, bufferVar) and
|
||||
why = bufferVar and
|
||||
parentPtr = bufferExpr.(VariableAccess).getQualifier() and
|
||||
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
|
||||
(
|
||||
if exists(bufferVar.getType().getSize())
|
||||
then bufferSize = bufferVar.getType().getSize()
|
||||
else bufferSize = 0
|
||||
) and
|
||||
result = getBufferSize(parentPtr, _) + bufferSize - parentClass.getSize()
|
||||
result = getBufferSize(parentPtr, _) + bufferVar.getType().getSize() - parentClass.getSize()
|
||||
)
|
||||
)
|
||||
or
|
||||
|
||||
@@ -168,7 +168,7 @@ private predicate callsVariadicFormatter(
|
||||
) {
|
||||
// calls a variadic formatter with `formatParamIndex`, `outputParamIndex` linked
|
||||
exists(FunctionCall fc, int format, int output |
|
||||
variadicFormatter(pragma[only_bind_into](fc.getTarget()), type, format, output) and
|
||||
variadicFormatter(fc.getTarget(), type, format, output) and
|
||||
fc.getEnclosingFunction() = f and
|
||||
fc.getArgument(format) = f.getParameter(formatParamIndex).getAnAccess() and
|
||||
fc.getArgument(output) = f.getParameter(outputParamIndex).getAnAccess()
|
||||
@@ -176,7 +176,7 @@ private predicate callsVariadicFormatter(
|
||||
or
|
||||
// calls a variadic formatter with only `formatParamIndex` linked
|
||||
exists(FunctionCall fc, string calledType, int format, int output |
|
||||
variadicFormatter(pragma[only_bind_into](fc.getTarget()), calledType, format, output) and
|
||||
variadicFormatter(fc.getTarget(), calledType, format, output) and
|
||||
fc.getEnclosingFunction() = f and
|
||||
fc.getArgument(format) = f.getParameter(formatParamIndex).getAnAccess() and
|
||||
not fc.getArgument(output) = f.getParameter(_).getAnAccess() and
|
||||
@@ -872,7 +872,7 @@ class FormatLiteral extends Literal {
|
||||
|
||||
private Type getConversionType1(int n) {
|
||||
exists(string cnv | cnv = this.getConversionChar(n) |
|
||||
cnv = ["d", "i"] and
|
||||
cnv.regexpMatch("d|i") and
|
||||
result = this.getIntegralConversion(n) and
|
||||
not result.getUnderlyingType().(IntegralType).isExplicitlySigned() and
|
||||
not result.getUnderlyingType().(IntegralType).isExplicitlyUnsigned()
|
||||
@@ -912,7 +912,7 @@ class FormatLiteral extends Literal {
|
||||
|
||||
private Type getConversionType2(int n) {
|
||||
exists(string cnv | cnv = this.getConversionChar(n) |
|
||||
cnv = ["o", "u", "x", "X"] and
|
||||
cnv.regexpMatch("o|u|x|X") and
|
||||
result = this.getIntegralConversion(n) and
|
||||
result.getUnderlyingType().(IntegralType).isUnsigned()
|
||||
)
|
||||
@@ -920,7 +920,7 @@ class FormatLiteral extends Literal {
|
||||
|
||||
private Type getConversionType3(int n) {
|
||||
exists(string cnv | cnv = this.getConversionChar(n) |
|
||||
cnv = ["a", "A", "e", "E", "f", "F", "g", "G"] and result = this.getFloatingPointConversion(n)
|
||||
cnv.regexpMatch("a|A|e|E|f|F|g|G") and result = this.getFloatingPointConversion(n)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1312,7 +1312,7 @@ class FormatLiteral extends Literal {
|
||||
len =
|
||||
min(int v |
|
||||
v = this.getPrecision(n) or
|
||||
v = this.getUse().getFormatArgument(n).(AnalyzedString).getMaxLength() - 1 // (don't count null terminator)
|
||||
v = this.getUse().getFormatArgument(n).(AnalysedString).getMaxLength() - 1 // (don't count null terminator)
|
||||
) and
|
||||
reason = TValueFlowAnalysis()
|
||||
)
|
||||
|
||||
@@ -27,14 +27,11 @@ predicate canValueFlow(Expr fromExpr, Expr toExpr) {
|
||||
fromExpr = toExpr.(ConditionalExpr).getElse()
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for AnalyzedString */
|
||||
deprecated class AnalysedString = AnalyzedString;
|
||||
|
||||
/**
|
||||
* An analyzed null terminated string.
|
||||
* An analysed null terminated string.
|
||||
*/
|
||||
class AnalyzedString extends Expr {
|
||||
AnalyzedString() {
|
||||
class AnalysedString extends Expr {
|
||||
AnalysedString() {
|
||||
this.getUnspecifiedType() instanceof ArrayType or
|
||||
this.getUnspecifiedType() instanceof PointerType
|
||||
}
|
||||
@@ -44,15 +41,15 @@ class AnalyzedString extends Expr {
|
||||
* can be calculated.
|
||||
*/
|
||||
int getMaxLength() {
|
||||
// take the longest AnalyzedString its value could 'flow' from; however if even one doesn't
|
||||
// take the longest AnalysedString it's value could 'flow' from; however if even one doesn't
|
||||
// return a value (this essentially means 'infinity') we can't return a value either.
|
||||
result =
|
||||
max(AnalyzedString expr, int toMax |
|
||||
max(AnalysedString expr, int toMax |
|
||||
canValueFlow*(expr, this) and toMax = expr.(StringLiteral).getOriginalLength()
|
||||
|
|
||||
toMax
|
||||
) and // maximum length
|
||||
forall(AnalyzedString expr | canValueFlow(expr, this) | exists(expr.getMaxLength())) // all sources return a value (recursive)
|
||||
forall(AnalysedString expr | canValueFlow(expr, this) | exists(expr.getMaxLength())) // all sources return a value (recursive)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -708,33 +708,30 @@ private predicate straightLineSparse(Node scope, int i, Node ni, Spec spec) {
|
||||
or
|
||||
scope =
|
||||
any(SwitchStmt s |
|
||||
// SwitchStmt [-> init] -> expr
|
||||
i = -1 and ni = s and spec.isAt()
|
||||
or
|
||||
i = 0 and ni = s.getInitialization() and spec.isAround()
|
||||
or
|
||||
i = 1 and ni = s.getExpr() and spec.isAround()
|
||||
i = 0 and ni = s.getExpr() and spec.isAround()
|
||||
or
|
||||
// If the switch body is not a block then this step is skipped, and the
|
||||
// expression jumps directly to the cases.
|
||||
i = 2 and ni = s.getStmt().(BlockStmt) and spec.isAt()
|
||||
i = 1 and ni = s.getStmt().(BlockStmt) and spec.isAt()
|
||||
or
|
||||
i = 3 and ni = s.getASwitchCase() and spec.isBefore()
|
||||
i = 2 and ni = s.getASwitchCase() and spec.isBefore()
|
||||
or
|
||||
// If there is no default case, we can jump to after the block. Note: `i`
|
||||
// is same value as above.
|
||||
not s.getASwitchCase() instanceof DefaultCase and
|
||||
i = 3 and
|
||||
i = 2 and
|
||||
ni = s.getStmt() and
|
||||
spec.isAfter()
|
||||
or
|
||||
i = 4 and /* BARRIER */ ni = s and spec.isBarrier()
|
||||
i = 3 and /* BARRIER */ ni = s and spec.isBarrier()
|
||||
or
|
||||
i = 5 and ni = s.getStmt() and spec.isAfter()
|
||||
i = 4 and ni = s.getStmt() and spec.isAfter()
|
||||
or
|
||||
i = 6 and ni = s and spec.isAroundDestructors()
|
||||
i = 5 and ni = s and spec.isAroundDestructors()
|
||||
or
|
||||
i = 7 and ni = s and spec.isAfter()
|
||||
i = 6 and ni = s and spec.isAfter()
|
||||
)
|
||||
or
|
||||
scope =
|
||||
@@ -839,15 +836,8 @@ private predicate subEdge(Pos p1, Node n1, Node n2, Pos p2) {
|
||||
p2.nodeAt(n2, f)
|
||||
)
|
||||
or
|
||||
// IfStmt -> [ init -> ] condition ; { then, else } ->
|
||||
// IfStmt -> condition ; { then, else } ->
|
||||
exists(IfStmt s |
|
||||
p1.nodeAt(n1, s) and
|
||||
p2.nodeBefore(n2, s.getInitialization())
|
||||
or
|
||||
p1.nodeAfter(n1, s.getInitialization()) and
|
||||
p2.nodeBefore(n2, s.getCondition())
|
||||
or
|
||||
not exists(s.getInitialization()) and
|
||||
p1.nodeAt(n1, s) and
|
||||
p2.nodeBefore(n2, s.getCondition())
|
||||
or
|
||||
@@ -861,15 +851,8 @@ private predicate subEdge(Pos p1, Node n1, Node n2, Pos p2) {
|
||||
p2.nodeAfter(n2, s)
|
||||
)
|
||||
or
|
||||
// ConstexprIfStmt -> [ init -> ] condition ; { then, else } -> // same as IfStmt
|
||||
// ConstexprIfStmt -> condition ; { then, else } -> // same as IfStmt
|
||||
exists(ConstexprIfStmt s |
|
||||
p1.nodeAt(n1, s) and
|
||||
p2.nodeBefore(n2, s.getInitialization())
|
||||
or
|
||||
p1.nodeAfter(n1, s.getInitialization()) and
|
||||
p2.nodeBefore(n2, s.getCondition())
|
||||
or
|
||||
not exists(s.getInitialization()) and
|
||||
p1.nodeAt(n1, s) and
|
||||
p2.nodeBefore(n2, s.getCondition())
|
||||
or
|
||||
@@ -970,7 +953,7 @@ private predicate subEdge(Pos p1, Node n1, Node n2, Pos p2) {
|
||||
private predicate subEdgeIncludingDestructors(Pos p1, Node n1, Node n2, Pos p2) {
|
||||
subEdge(p1, n1, n2, p2)
|
||||
or
|
||||
// If `n1` has sub-nodes to accommodate destructors, but there are none to be
|
||||
// If `n1` has sub-nodes to accomodate destructors, but there are none to be
|
||||
// called, connect the "before destructors" node directly to the "after
|
||||
// destructors" node. For performance, only do this when the nodes exist.
|
||||
exists(Pos afterDtors | afterDtors.isAfterDestructors() | subEdge(afterDtors, n1, _, _)) and
|
||||
|
||||
@@ -90,20 +90,14 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
@@ -122,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -176,14 +170,6 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
int explorationLimit() { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
|
||||
/**
|
||||
* Holds if there is a partial data flow path from `source` to `node`. The
|
||||
* approximate distance between `node` and the closest source is `dist` and
|
||||
@@ -341,29 +327,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -377,7 +340,10 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
not config.isSink(n) and
|
||||
not config.isSink(n, _)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -386,7 +352,10 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
||||
exists(Node n | node.asNode() = n |
|
||||
config.isBarrier(n, state)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -516,9 +485,8 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -528,37 +496,6 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
expectsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -636,9 +573,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -662,10 +599,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
readSet(mid, c, node, config)
|
||||
read(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -683,16 +620,6 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -785,9 +712,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -813,10 +740,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -835,8 +762,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
@@ -935,8 +861,8 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -946,10 +872,7 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1224,26 +1147,11 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowState(state, config) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
ap = true and
|
||||
expectsContentCand(node, config)
|
||||
)
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1666,7 +1574,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1704,22 +1612,8 @@ private module Stage2 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -1812,8 +1706,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1836,9 +1729,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
read(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1859,8 +1752,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -2033,34 +1926,7 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c) and
|
||||
c = ap.getHead().getContent()
|
||||
)
|
||||
}
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -2069,13 +1935,8 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap, config) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
expectsContentCand(node, ap, config)
|
||||
)
|
||||
not clear(node, ap) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2502,7 +2363,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -2540,22 +2401,8 @@ private module Stage3 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3343,7 +3190,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3381,22 +3228,8 @@ private module Stage4 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3467,25 +3300,14 @@ private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||
nodeMayUseSummary0(n, c, state, apa, config)
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3684,7 +3506,7 @@ private newtype TPathNode =
|
||||
* of dereference operations needed to get from the value in the node to the
|
||||
* tracked object. The final type indicates the type of the tracked object.
|
||||
*/
|
||||
private class AccessPath extends TAccessPath {
|
||||
abstract private class AccessPath extends TAccessPath {
|
||||
/** Gets the head of this access path, if any. */
|
||||
abstract TypedContent getHead();
|
||||
|
||||
@@ -3877,11 +3699,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3889,30 +3716,16 @@ class PathNode extends TPathNode {
|
||||
}
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
abstract PathNode getASuccessorImpl();
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
not this.getConfiguration().includeHiddenNodes() and
|
||||
(
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
)
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
@@ -3943,17 +3756,15 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
@@ -3962,7 +3773,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
|
||||
*/
|
||||
module PathGraph {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
@@ -4080,7 +3891,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNode getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
}
|
||||
@@ -4391,42 +4202,38 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
readSet(n1, _, n2, _)
|
||||
read(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
|
||||
succ = pred.getANonHiddenSuccessor() and
|
||||
succNode = succ.getNodeEx()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
||||
not ret.isHidden() and
|
||||
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||
|
|
||||
out = out0 or out = out0.projectToSink()
|
||||
par.getNodeEx() = p and
|
||||
out0.getNodeEx() = o and
|
||||
out0.getState() = sout and
|
||||
out0.getAp() = apout and
|
||||
(out = out0 or out = out0.projectToSink())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
predicate retReach(PathNode n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getANonHiddenSuccessor() = mid and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4750,11 +4557,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4770,11 +4573,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead().getContent())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -90,20 +90,14 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
@@ -122,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -176,14 +170,6 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
int explorationLimit() { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
|
||||
/**
|
||||
* Holds if there is a partial data flow path from `source` to `node`. The
|
||||
* approximate distance between `node` and the closest source is `dist` and
|
||||
@@ -341,29 +327,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -377,7 +340,10 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
not config.isSink(n) and
|
||||
not config.isSink(n, _)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -386,7 +352,10 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
||||
exists(Node n | node.asNode() = n |
|
||||
config.isBarrier(n, state)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -516,9 +485,8 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -528,37 +496,6 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
expectsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -636,9 +573,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -662,10 +599,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
readSet(mid, c, node, config)
|
||||
read(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -683,16 +620,6 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -785,9 +712,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -813,10 +740,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -835,8 +762,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
@@ -935,8 +861,8 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -946,10 +872,7 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1224,26 +1147,11 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowState(state, config) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
ap = true and
|
||||
expectsContentCand(node, config)
|
||||
)
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1666,7 +1574,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1704,22 +1612,8 @@ private module Stage2 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -1812,8 +1706,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1836,9 +1729,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
read(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1859,8 +1752,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -2033,34 +1926,7 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c) and
|
||||
c = ap.getHead().getContent()
|
||||
)
|
||||
}
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -2069,13 +1935,8 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap, config) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
expectsContentCand(node, ap, config)
|
||||
)
|
||||
not clear(node, ap) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2502,7 +2363,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -2540,22 +2401,8 @@ private module Stage3 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3343,7 +3190,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3381,22 +3228,8 @@ private module Stage4 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3467,25 +3300,14 @@ private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||
nodeMayUseSummary0(n, c, state, apa, config)
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3684,7 +3506,7 @@ private newtype TPathNode =
|
||||
* of dereference operations needed to get from the value in the node to the
|
||||
* tracked object. The final type indicates the type of the tracked object.
|
||||
*/
|
||||
private class AccessPath extends TAccessPath {
|
||||
abstract private class AccessPath extends TAccessPath {
|
||||
/** Gets the head of this access path, if any. */
|
||||
abstract TypedContent getHead();
|
||||
|
||||
@@ -3877,11 +3699,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3889,30 +3716,16 @@ class PathNode extends TPathNode {
|
||||
}
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
abstract PathNode getASuccessorImpl();
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
not this.getConfiguration().includeHiddenNodes() and
|
||||
(
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
)
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
@@ -3943,17 +3756,15 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
@@ -3962,7 +3773,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
|
||||
*/
|
||||
module PathGraph {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
@@ -4080,7 +3891,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNode getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
}
|
||||
@@ -4391,42 +4202,38 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
readSet(n1, _, n2, _)
|
||||
read(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
|
||||
succ = pred.getANonHiddenSuccessor() and
|
||||
succNode = succ.getNodeEx()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
||||
not ret.isHidden() and
|
||||
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||
|
|
||||
out = out0 or out = out0.projectToSink()
|
||||
par.getNodeEx() = p and
|
||||
out0.getNodeEx() = o and
|
||||
out0.getState() = sout and
|
||||
out0.getAp() = apout and
|
||||
(out = out0 or out = out0.projectToSink())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
predicate retReach(PathNode n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getANonHiddenSuccessor() = mid and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4750,11 +4557,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4770,11 +4573,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead().getContent())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -90,20 +90,14 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
@@ -122,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -176,14 +170,6 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
int explorationLimit() { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
|
||||
/**
|
||||
* Holds if there is a partial data flow path from `source` to `node`. The
|
||||
* approximate distance between `node` and the closest source is `dist` and
|
||||
@@ -341,29 +327,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -377,7 +340,10 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
not config.isSink(n) and
|
||||
not config.isSink(n, _)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -386,7 +352,10 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
||||
exists(Node n | node.asNode() = n |
|
||||
config.isBarrier(n, state)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -516,9 +485,8 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -528,37 +496,6 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
expectsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -636,9 +573,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -662,10 +599,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
readSet(mid, c, node, config)
|
||||
read(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -683,16 +620,6 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -785,9 +712,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -813,10 +740,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -835,8 +762,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
@@ -935,8 +861,8 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -946,10 +872,7 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1224,26 +1147,11 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowState(state, config) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
ap = true and
|
||||
expectsContentCand(node, config)
|
||||
)
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1666,7 +1574,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1704,22 +1612,8 @@ private module Stage2 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -1812,8 +1706,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1836,9 +1729,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
read(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1859,8 +1752,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -2033,34 +1926,7 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c) and
|
||||
c = ap.getHead().getContent()
|
||||
)
|
||||
}
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -2069,13 +1935,8 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap, config) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
expectsContentCand(node, ap, config)
|
||||
)
|
||||
not clear(node, ap) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2502,7 +2363,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -2540,22 +2401,8 @@ private module Stage3 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3343,7 +3190,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3381,22 +3228,8 @@ private module Stage4 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3467,25 +3300,14 @@ private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||
nodeMayUseSummary0(n, c, state, apa, config)
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3684,7 +3506,7 @@ private newtype TPathNode =
|
||||
* of dereference operations needed to get from the value in the node to the
|
||||
* tracked object. The final type indicates the type of the tracked object.
|
||||
*/
|
||||
private class AccessPath extends TAccessPath {
|
||||
abstract private class AccessPath extends TAccessPath {
|
||||
/** Gets the head of this access path, if any. */
|
||||
abstract TypedContent getHead();
|
||||
|
||||
@@ -3877,11 +3699,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3889,30 +3716,16 @@ class PathNode extends TPathNode {
|
||||
}
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
abstract PathNode getASuccessorImpl();
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
not this.getConfiguration().includeHiddenNodes() and
|
||||
(
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
)
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
@@ -3943,17 +3756,15 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
@@ -3962,7 +3773,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
|
||||
*/
|
||||
module PathGraph {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
@@ -4080,7 +3891,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNode getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
}
|
||||
@@ -4391,42 +4202,38 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
readSet(n1, _, n2, _)
|
||||
read(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
|
||||
succ = pred.getANonHiddenSuccessor() and
|
||||
succNode = succ.getNodeEx()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
||||
not ret.isHidden() and
|
||||
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||
|
|
||||
out = out0 or out = out0.projectToSink()
|
||||
par.getNodeEx() = p and
|
||||
out0.getNodeEx() = o and
|
||||
out0.getState() = sout and
|
||||
out0.getAp() = apout and
|
||||
(out = out0 or out = out0.projectToSink())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
predicate retReach(PathNode n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getANonHiddenSuccessor() = mid and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4750,11 +4557,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4770,11 +4573,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead().getContent())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -90,20 +90,14 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
@@ -122,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -176,14 +170,6 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
int explorationLimit() { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
|
||||
/**
|
||||
* Holds if there is a partial data flow path from `source` to `node`. The
|
||||
* approximate distance between `node` and the closest source is `dist` and
|
||||
@@ -341,29 +327,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -377,7 +340,10 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
not config.isSink(n) and
|
||||
not config.isSink(n, _)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -386,7 +352,10 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
||||
exists(Node n | node.asNode() = n |
|
||||
config.isBarrier(n, state)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -516,9 +485,8 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -528,37 +496,6 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
expectsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -636,9 +573,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -662,10 +599,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
readSet(mid, c, node, config)
|
||||
read(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -683,16 +620,6 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -785,9 +712,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -813,10 +740,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -835,8 +762,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
@@ -935,8 +861,8 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -946,10 +872,7 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1224,26 +1147,11 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowState(state, config) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
ap = true and
|
||||
expectsContentCand(node, config)
|
||||
)
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1666,7 +1574,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1704,22 +1612,8 @@ private module Stage2 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -1812,8 +1706,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1836,9 +1729,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
read(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1859,8 +1752,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -2033,34 +1926,7 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c) and
|
||||
c = ap.getHead().getContent()
|
||||
)
|
||||
}
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -2069,13 +1935,8 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap, config) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
expectsContentCand(node, ap, config)
|
||||
)
|
||||
not clear(node, ap) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2502,7 +2363,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -2540,22 +2401,8 @@ private module Stage3 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3343,7 +3190,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3381,22 +3228,8 @@ private module Stage4 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3467,25 +3300,14 @@ private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||
nodeMayUseSummary0(n, c, state, apa, config)
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3684,7 +3506,7 @@ private newtype TPathNode =
|
||||
* of dereference operations needed to get from the value in the node to the
|
||||
* tracked object. The final type indicates the type of the tracked object.
|
||||
*/
|
||||
private class AccessPath extends TAccessPath {
|
||||
abstract private class AccessPath extends TAccessPath {
|
||||
/** Gets the head of this access path, if any. */
|
||||
abstract TypedContent getHead();
|
||||
|
||||
@@ -3877,11 +3699,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3889,30 +3716,16 @@ class PathNode extends TPathNode {
|
||||
}
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
abstract PathNode getASuccessorImpl();
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
not this.getConfiguration().includeHiddenNodes() and
|
||||
(
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
)
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
@@ -3943,17 +3756,15 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
@@ -3962,7 +3773,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
|
||||
*/
|
||||
module PathGraph {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
@@ -4080,7 +3891,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNode getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
}
|
||||
@@ -4391,42 +4202,38 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
readSet(n1, _, n2, _)
|
||||
read(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
|
||||
succ = pred.getANonHiddenSuccessor() and
|
||||
succNode = succ.getNodeEx()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
||||
not ret.isHidden() and
|
||||
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||
|
|
||||
out = out0 or out = out0.projectToSink()
|
||||
par.getNodeEx() = p and
|
||||
out0.getNodeEx() = o and
|
||||
out0.getState() = sout and
|
||||
out0.getAp() = apout and
|
||||
(out = out0 or out = out0.projectToSink())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
predicate retReach(PathNode n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getANonHiddenSuccessor() = mid and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4750,11 +4557,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4770,11 +4573,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead().getContent())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -216,9 +216,10 @@ private module LambdaFlow {
|
||||
or
|
||||
// jump step
|
||||
exists(Node mid, DataFlowType t0 |
|
||||
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, lastCall) and
|
||||
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and
|
||||
toReturn = false and
|
||||
toJump = true
|
||||
toJump = true and
|
||||
lastCall = TDataFlowCallNone()
|
||||
|
|
||||
jumpStepCached(node, mid) and
|
||||
t = t0
|
||||
@@ -304,7 +305,7 @@ cached
|
||||
private module Cached {
|
||||
/**
|
||||
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
|
||||
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and thereby
|
||||
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
|
||||
* collapsing the two stages.
|
||||
*/
|
||||
cached
|
||||
@@ -325,10 +326,7 @@ private module Cached {
|
||||
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
|
||||
|
||||
cached
|
||||
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
|
||||
|
||||
cached
|
||||
predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) }
|
||||
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
|
||||
|
||||
cached
|
||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||
@@ -375,7 +373,7 @@ private module Cached {
|
||||
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
||||
// is obtained by popping the head of the access path stack) is compatible with
|
||||
// the type of `x.f`.
|
||||
readSet(_, _, n)
|
||||
read(_, _, n)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -471,7 +469,7 @@ private module Cached {
|
||||
// read
|
||||
exists(Node mid |
|
||||
parameterValueFlowCand(p, mid, false) and
|
||||
readSet(mid, _, node) and
|
||||
read(mid, _, node) and
|
||||
read = true
|
||||
)
|
||||
or
|
||||
@@ -659,10 +657,8 @@ private module Cached {
|
||||
* Holds if `arg` flows to `out` through a call using only
|
||||
* value-preserving steps and a single read step, not taking call
|
||||
* contexts into account, thus representing a getter-step.
|
||||
*
|
||||
* This predicate is exposed for testing only.
|
||||
*/
|
||||
predicate getterStep(ArgNode arg, ContentSet c, Node out) {
|
||||
predicate getterStep(ArgNode arg, Content c, Node out) {
|
||||
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
||||
}
|
||||
|
||||
@@ -785,12 +781,8 @@ private module Cached {
|
||||
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
||||
}
|
||||
|
||||
cached
|
||||
predicate readSet(Node node1, ContentSet c, Node node2) { readStep(node1, c, node2) }
|
||||
|
||||
cached
|
||||
predicate storeSet(
|
||||
Node node1, ContentSet c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||
private predicate store(
|
||||
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||
) {
|
||||
storeStep(node1, c, node2) and
|
||||
contentType = getNodeDataFlowType(node1) and
|
||||
@@ -802,19 +794,14 @@ private module Cached {
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
||||
or
|
||||
readSet(n2, c, n1) and
|
||||
read(n2, c, n1) and
|
||||
contentType = getNodeDataFlowType(n1) and
|
||||
containerType = getNodeDataFlowType(n2)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate store(
|
||||
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||
) {
|
||||
exists(ContentSet cs |
|
||||
c = cs.getAStoreContent() and storeSet(node1, cs, node2, contentType, containerType)
|
||||
)
|
||||
}
|
||||
cached
|
||||
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a direct assignment to
|
||||
@@ -945,16 +932,16 @@ class CastingNode extends Node {
|
||||
}
|
||||
|
||||
private predicate readStepWithTypes(
|
||||
Node n1, DataFlowType container, ContentSet c, Node n2, DataFlowType content
|
||||
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
|
||||
) {
|
||||
readSet(n1, c, n2) and
|
||||
read(n1, c, n2) and
|
||||
container = getNodeDataFlowType(n1) and
|
||||
content = getNodeDataFlowType(n2)
|
||||
}
|
||||
|
||||
private newtype TReadStepTypesOption =
|
||||
TReadStepTypesNone() or
|
||||
TReadStepTypesSome(DataFlowType container, ContentSet c, DataFlowType content) {
|
||||
TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) {
|
||||
readStepWithTypes(_, container, c, _, content)
|
||||
}
|
||||
|
||||
@@ -963,7 +950,7 @@ private class ReadStepTypesOption extends TReadStepTypesOption {
|
||||
|
||||
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
|
||||
|
||||
ContentSet getContent() { this = TReadStepTypesSome(_, result, _) }
|
||||
Content getContent() { this = TReadStepTypesSome(_, result, _) }
|
||||
|
||||
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
|
||||
|
||||
@@ -1338,6 +1325,8 @@ abstract class AccessPathFront extends TAccessPathFront {
|
||||
abstract boolean toBoolNonEmpty();
|
||||
|
||||
TypedContent getHead() { this = TFrontHead(result) }
|
||||
|
||||
predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) }
|
||||
}
|
||||
|
||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||
|
||||
@@ -90,20 +90,14 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
@@ -122,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -176,14 +170,6 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
int explorationLimit() { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
|
||||
/**
|
||||
* Holds if there is a partial data flow path from `source` to `node`. The
|
||||
* approximate distance between `node` and the closest source is `dist` and
|
||||
@@ -341,29 +327,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -377,7 +340,10 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
not config.isSink(n) and
|
||||
not config.isSink(n, _)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -386,7 +352,10 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
||||
exists(Node n | node.asNode() = n |
|
||||
config.isBarrier(n, state)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -516,9 +485,8 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -528,37 +496,6 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
expectsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -636,9 +573,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -662,10 +599,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
readSet(mid, c, node, config)
|
||||
read(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -683,16 +620,6 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -785,9 +712,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -813,10 +740,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -835,8 +762,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
@@ -935,8 +861,8 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -946,10 +872,7 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1224,26 +1147,11 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowState(state, config) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
ap = true and
|
||||
expectsContentCand(node, config)
|
||||
)
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1666,7 +1574,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1704,22 +1612,8 @@ private module Stage2 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -1812,8 +1706,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1836,9 +1729,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
read(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1859,8 +1752,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -2033,34 +1926,7 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c) and
|
||||
c = ap.getHead().getContent()
|
||||
)
|
||||
}
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -2069,13 +1935,8 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap, config) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
expectsContentCand(node, ap, config)
|
||||
)
|
||||
not clear(node, ap) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2502,7 +2363,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -2540,22 +2401,8 @@ private module Stage3 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3343,7 +3190,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3381,22 +3228,8 @@ private module Stage4 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3467,25 +3300,14 @@ private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||
nodeMayUseSummary0(n, c, state, apa, config)
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3684,7 +3506,7 @@ private newtype TPathNode =
|
||||
* of dereference operations needed to get from the value in the node to the
|
||||
* tracked object. The final type indicates the type of the tracked object.
|
||||
*/
|
||||
private class AccessPath extends TAccessPath {
|
||||
abstract private class AccessPath extends TAccessPath {
|
||||
/** Gets the head of this access path, if any. */
|
||||
abstract TypedContent getHead();
|
||||
|
||||
@@ -3877,11 +3699,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3889,30 +3716,16 @@ class PathNode extends TPathNode {
|
||||
}
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
abstract PathNode getASuccessorImpl();
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
not this.getConfiguration().includeHiddenNodes() and
|
||||
(
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
)
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
@@ -3943,17 +3756,15 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
@@ -3962,7 +3773,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
|
||||
*/
|
||||
module PathGraph {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
@@ -4080,7 +3891,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNode getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
}
|
||||
@@ -4391,42 +4202,38 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
readSet(n1, _, n2, _)
|
||||
read(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
|
||||
succ = pred.getANonHiddenSuccessor() and
|
||||
succNode = succ.getNodeEx()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
||||
not ret.isHidden() and
|
||||
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||
|
|
||||
out = out0 or out = out0.projectToSink()
|
||||
par.getNodeEx() = p and
|
||||
out0.getNodeEx() = o and
|
||||
out0.getState() = sout and
|
||||
out0.getAp() = apout and
|
||||
(out = out0 or out = out0.projectToSink())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
predicate retReach(PathNode n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getANonHiddenSuccessor() = mid and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4750,11 +4557,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4770,11 +4573,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead().getContent())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -198,12 +198,6 @@ predicate clearsContent(Node n, Content c) {
|
||||
none() // stub implementation
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value that is being tracked is expected to be stored inside content `c`
|
||||
* at node `n`.
|
||||
*/
|
||||
predicate expectsContent(Node n, ContentSet c) { none() }
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
Type getNodeType(Node n) {
|
||||
suppressUnusedNode(n) and
|
||||
|
||||
@@ -822,62 +822,6 @@ private class CollectionContent extends Content, TCollectionContent {
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity that represents a set of `Content`s.
|
||||
*
|
||||
* The set may be interpreted differently depending on whether it is
|
||||
* stored into (`getAStoreContent`) or read from (`getAReadContent`).
|
||||
*/
|
||||
class ContentSet instanceof Content {
|
||||
/** Gets a content that may be stored into when storing into this set. */
|
||||
Content getAStoreContent() { result = this }
|
||||
|
||||
/** Gets a content that may be read from when reading from this set. */
|
||||
Content getAReadContent() { result = this }
|
||||
|
||||
/** Gets a textual representation of this content set. */
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
super.hasLocationInfo(path, sl, sc, el, ec)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
|
||||
*
|
||||
* The expression `e` is expected to be a syntactic part of the guard `g`.
|
||||
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
|
||||
* the argument `x`.
|
||||
*/
|
||||
signature predicate guardChecksSig(GuardCondition g, Expr e, boolean branch);
|
||||
|
||||
/**
|
||||
* Provides a set of barrier nodes for a guard that validates an expression.
|
||||
*
|
||||
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
|
||||
* in data flow and taint tracking.
|
||||
*/
|
||||
module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
/** Gets a node that is safely guarded by the given guard check. */
|
||||
ExprNode getABarrierNode() {
|
||||
exists(GuardCondition g, SsaDefinition def, Variable v, boolean branch |
|
||||
result.getExpr() = def.getAUse(v) and
|
||||
guardChecks(g, def.getAUse(v), branch) and
|
||||
g.controls(result.getExpr().getBasicBlock(), branch)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `BarrierGuard` module instead.
|
||||
*
|
||||
* A guard that validates some expression.
|
||||
*
|
||||
* To use this in a configuration, extend the class and provide a
|
||||
@@ -886,7 +830,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
*
|
||||
* It is important that all extending classes in scope are disjoint.
|
||||
*/
|
||||
deprecated class BarrierGuard extends GuardCondition {
|
||||
class BarrierGuard extends GuardCondition {
|
||||
/** Override this predicate to hold if this guard validates `e` upon evaluating to `b`. */
|
||||
abstract predicate checks(Expr e, boolean b);
|
||||
|
||||
|
||||
@@ -549,7 +549,7 @@ module FlowVar_internal {
|
||||
bb = this.(Loop).getStmt() and
|
||||
v = this.getARelevantVariable()
|
||||
or
|
||||
this.reachesWithoutAssignment(pragma[only_bind_out](bb.getAPredecessor()), v) and
|
||||
this.reachesWithoutAssignment(bb.getAPredecessor(), v) and
|
||||
this.bbInLoop(bb)
|
||||
) and
|
||||
not assignsToVar(bb, v)
|
||||
|
||||
@@ -47,6 +47,12 @@ predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::Content c) { n
|
||||
*/
|
||||
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `guard` should be a sanitizer guard in all global taint flow configurations
|
||||
* but not in local taint.
|
||||
*/
|
||||
predicate defaultTaintSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
|
||||
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
|
||||
|
||||
@@ -116,30 +116,20 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard)
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||
* when the flow state is `state`.
|
||||
*/
|
||||
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||
none()
|
||||
}
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
|
||||
|
||||
deprecated final override predicate isBarrierGuard(
|
||||
DataFlow::BarrierGuard guard, DataFlow::FlowState state
|
||||
) {
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||
this.isSanitizerGuard(guard, state)
|
||||
}
|
||||
|
||||
@@ -171,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
@@ -116,30 +116,20 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard)
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||
* when the flow state is `state`.
|
||||
*/
|
||||
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||
none()
|
||||
}
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
|
||||
|
||||
deprecated final override predicate isBarrierGuard(
|
||||
DataFlow::BarrierGuard guard, DataFlow::FlowState state
|
||||
) {
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||
this.isSanitizerGuard(guard, state)
|
||||
}
|
||||
|
||||
@@ -171,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
@@ -49,9 +49,6 @@ class Expr extends StmtParent, @expr {
|
||||
/** Gets the enclosing variable of this expression, if any. */
|
||||
Variable getEnclosingVariable() { result = exprEnclosingElement(this) }
|
||||
|
||||
/** Gets the enclosing variable or function of this expression. */
|
||||
Declaration getEnclosingDeclaration() { result = exprEnclosingElement(this) }
|
||||
|
||||
/** Gets a child of this expression. */
|
||||
Expr getAChild() { exists(int n | result = this.getChild(n)) }
|
||||
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
* qualified.
|
||||
*
|
||||
* This file contains classes that mirror the standard AST classes for C++, but
|
||||
* these classes are only concerned with naming.
|
||||
* these classes are only concerned with naming. The other difference is that
|
||||
* these classes don't use the `ResolveClass.qll` mechanisms like
|
||||
* `unresolveElement` because these classes should eventually be part of the
|
||||
* implementation of `ResolveClass.qll`, allowing it to match up classes when
|
||||
* their qualified names and parameters match.
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.Declaration as D
|
||||
|
||||
@@ -115,13 +115,15 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
predicate isClass(@usertype t) {
|
||||
usertypes(t, _, 1) or
|
||||
usertypes(t, _, 2) or
|
||||
usertypes(t, _, 3) or
|
||||
usertypes(t, _, 6) or
|
||||
usertypes(t, _, 10) or
|
||||
usertypes(t, _, 11) or
|
||||
usertypes(t, _, 12)
|
||||
(
|
||||
usertypes(t, _, 1) or
|
||||
usertypes(t, _, 2) or
|
||||
usertypes(t, _, 3) or
|
||||
usertypes(t, _, 6) or
|
||||
usertypes(t, _, 10) or
|
||||
usertypes(t, _, 11) or
|
||||
usertypes(t, _, 12)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
|
||||
@@ -90,20 +90,14 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
@@ -122,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -176,14 +170,6 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
int explorationLimit() { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
|
||||
/**
|
||||
* Holds if there is a partial data flow path from `source` to `node`. The
|
||||
* approximate distance between `node` and the closest source is `dist` and
|
||||
@@ -341,29 +327,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -377,7 +340,10 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
not config.isSink(n) and
|
||||
not config.isSink(n, _)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -386,7 +352,10 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
||||
exists(Node n | node.asNode() = n |
|
||||
config.isBarrier(n, state)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -516,9 +485,8 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -528,37 +496,6 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
expectsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -636,9 +573,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -662,10 +599,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
readSet(mid, c, node, config)
|
||||
read(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -683,16 +620,6 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -785,9 +712,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -813,10 +740,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -835,8 +762,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
@@ -935,8 +861,8 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -946,10 +872,7 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1224,26 +1147,11 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowState(state, config) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
ap = true and
|
||||
expectsContentCand(node, config)
|
||||
)
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1666,7 +1574,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1704,22 +1612,8 @@ private module Stage2 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -1812,8 +1706,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1836,9 +1729,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
read(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1859,8 +1752,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -2033,34 +1926,7 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c) and
|
||||
c = ap.getHead().getContent()
|
||||
)
|
||||
}
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -2069,13 +1935,8 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap, config) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
expectsContentCand(node, ap, config)
|
||||
)
|
||||
not clear(node, ap) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2502,7 +2363,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -2540,22 +2401,8 @@ private module Stage3 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3343,7 +3190,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3381,22 +3228,8 @@ private module Stage4 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3467,25 +3300,14 @@ private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||
nodeMayUseSummary0(n, c, state, apa, config)
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3684,7 +3506,7 @@ private newtype TPathNode =
|
||||
* of dereference operations needed to get from the value in the node to the
|
||||
* tracked object. The final type indicates the type of the tracked object.
|
||||
*/
|
||||
private class AccessPath extends TAccessPath {
|
||||
abstract private class AccessPath extends TAccessPath {
|
||||
/** Gets the head of this access path, if any. */
|
||||
abstract TypedContent getHead();
|
||||
|
||||
@@ -3877,11 +3699,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3889,30 +3716,16 @@ class PathNode extends TPathNode {
|
||||
}
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
abstract PathNode getASuccessorImpl();
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
not this.getConfiguration().includeHiddenNodes() and
|
||||
(
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
)
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
@@ -3943,17 +3756,15 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
@@ -3962,7 +3773,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
|
||||
*/
|
||||
module PathGraph {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
@@ -4080,7 +3891,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNode getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
}
|
||||
@@ -4391,42 +4202,38 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
readSet(n1, _, n2, _)
|
||||
read(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
|
||||
succ = pred.getANonHiddenSuccessor() and
|
||||
succNode = succ.getNodeEx()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
||||
not ret.isHidden() and
|
||||
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||
|
|
||||
out = out0 or out = out0.projectToSink()
|
||||
par.getNodeEx() = p and
|
||||
out0.getNodeEx() = o and
|
||||
out0.getState() = sout and
|
||||
out0.getAp() = apout and
|
||||
(out = out0 or out = out0.projectToSink())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
predicate retReach(PathNode n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getANonHiddenSuccessor() = mid and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4750,11 +4557,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4770,11 +4573,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead().getContent())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -90,20 +90,14 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
@@ -122,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -176,14 +170,6 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
int explorationLimit() { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
|
||||
/**
|
||||
* Holds if there is a partial data flow path from `source` to `node`. The
|
||||
* approximate distance between `node` and the closest source is `dist` and
|
||||
@@ -341,29 +327,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -377,7 +340,10 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
not config.isSink(n) and
|
||||
not config.isSink(n, _)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -386,7 +352,10 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
||||
exists(Node n | node.asNode() = n |
|
||||
config.isBarrier(n, state)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -516,9 +485,8 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -528,37 +496,6 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
expectsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -636,9 +573,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -662,10 +599,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
readSet(mid, c, node, config)
|
||||
read(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -683,16 +620,6 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -785,9 +712,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -813,10 +740,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -835,8 +762,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
@@ -935,8 +861,8 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -946,10 +872,7 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1224,26 +1147,11 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowState(state, config) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
ap = true and
|
||||
expectsContentCand(node, config)
|
||||
)
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1666,7 +1574,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1704,22 +1612,8 @@ private module Stage2 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -1812,8 +1706,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1836,9 +1729,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
read(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1859,8 +1752,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -2033,34 +1926,7 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c) and
|
||||
c = ap.getHead().getContent()
|
||||
)
|
||||
}
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -2069,13 +1935,8 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap, config) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
expectsContentCand(node, ap, config)
|
||||
)
|
||||
not clear(node, ap) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2502,7 +2363,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -2540,22 +2401,8 @@ private module Stage3 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3343,7 +3190,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3381,22 +3228,8 @@ private module Stage4 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3467,25 +3300,14 @@ private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||
nodeMayUseSummary0(n, c, state, apa, config)
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3684,7 +3506,7 @@ private newtype TPathNode =
|
||||
* of dereference operations needed to get from the value in the node to the
|
||||
* tracked object. The final type indicates the type of the tracked object.
|
||||
*/
|
||||
private class AccessPath extends TAccessPath {
|
||||
abstract private class AccessPath extends TAccessPath {
|
||||
/** Gets the head of this access path, if any. */
|
||||
abstract TypedContent getHead();
|
||||
|
||||
@@ -3877,11 +3699,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3889,30 +3716,16 @@ class PathNode extends TPathNode {
|
||||
}
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
abstract PathNode getASuccessorImpl();
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
not this.getConfiguration().includeHiddenNodes() and
|
||||
(
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
)
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
@@ -3943,17 +3756,15 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
@@ -3962,7 +3773,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
|
||||
*/
|
||||
module PathGraph {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
@@ -4080,7 +3891,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNode getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
}
|
||||
@@ -4391,42 +4202,38 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
readSet(n1, _, n2, _)
|
||||
read(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
|
||||
succ = pred.getANonHiddenSuccessor() and
|
||||
succNode = succ.getNodeEx()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
||||
not ret.isHidden() and
|
||||
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||
|
|
||||
out = out0 or out = out0.projectToSink()
|
||||
par.getNodeEx() = p and
|
||||
out0.getNodeEx() = o and
|
||||
out0.getState() = sout and
|
||||
out0.getAp() = apout and
|
||||
(out = out0 or out = out0.projectToSink())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
predicate retReach(PathNode n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getANonHiddenSuccessor() = mid and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4750,11 +4557,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4770,11 +4573,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead().getContent())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -90,20 +90,14 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
@@ -122,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -176,14 +170,6 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
int explorationLimit() { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
|
||||
/**
|
||||
* Holds if there is a partial data flow path from `source` to `node`. The
|
||||
* approximate distance between `node` and the closest source is `dist` and
|
||||
@@ -341,29 +327,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -377,7 +340,10 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
not config.isSink(n) and
|
||||
not config.isSink(n, _)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -386,7 +352,10 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
||||
exists(Node n | node.asNode() = n |
|
||||
config.isBarrier(n, state)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -516,9 +485,8 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -528,37 +496,6 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
expectsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -636,9 +573,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -662,10 +599,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
readSet(mid, c, node, config)
|
||||
read(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -683,16 +620,6 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -785,9 +712,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -813,10 +740,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -835,8 +762,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
@@ -935,8 +861,8 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -946,10 +872,7 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1224,26 +1147,11 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowState(state, config) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
ap = true and
|
||||
expectsContentCand(node, config)
|
||||
)
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1666,7 +1574,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1704,22 +1612,8 @@ private module Stage2 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -1812,8 +1706,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1836,9 +1729,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
read(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1859,8 +1752,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -2033,34 +1926,7 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c) and
|
||||
c = ap.getHead().getContent()
|
||||
)
|
||||
}
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -2069,13 +1935,8 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap, config) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
expectsContentCand(node, ap, config)
|
||||
)
|
||||
not clear(node, ap) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2502,7 +2363,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -2540,22 +2401,8 @@ private module Stage3 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3343,7 +3190,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3381,22 +3228,8 @@ private module Stage4 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3467,25 +3300,14 @@ private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||
nodeMayUseSummary0(n, c, state, apa, config)
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3684,7 +3506,7 @@ private newtype TPathNode =
|
||||
* of dereference operations needed to get from the value in the node to the
|
||||
* tracked object. The final type indicates the type of the tracked object.
|
||||
*/
|
||||
private class AccessPath extends TAccessPath {
|
||||
abstract private class AccessPath extends TAccessPath {
|
||||
/** Gets the head of this access path, if any. */
|
||||
abstract TypedContent getHead();
|
||||
|
||||
@@ -3877,11 +3699,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3889,30 +3716,16 @@ class PathNode extends TPathNode {
|
||||
}
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
abstract PathNode getASuccessorImpl();
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
not this.getConfiguration().includeHiddenNodes() and
|
||||
(
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
)
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
@@ -3943,17 +3756,15 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
@@ -3962,7 +3773,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
|
||||
*/
|
||||
module PathGraph {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
@@ -4080,7 +3891,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNode getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
}
|
||||
@@ -4391,42 +4202,38 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
readSet(n1, _, n2, _)
|
||||
read(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
|
||||
succ = pred.getANonHiddenSuccessor() and
|
||||
succNode = succ.getNodeEx()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
||||
not ret.isHidden() and
|
||||
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||
|
|
||||
out = out0 or out = out0.projectToSink()
|
||||
par.getNodeEx() = p and
|
||||
out0.getNodeEx() = o and
|
||||
out0.getState() = sout and
|
||||
out0.getAp() = apout and
|
||||
(out = out0 or out = out0.projectToSink())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
predicate retReach(PathNode n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getANonHiddenSuccessor() = mid and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4750,11 +4557,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4770,11 +4573,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead().getContent())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -90,20 +90,14 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
@@ -122,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -176,14 +170,6 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
int explorationLimit() { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
|
||||
/**
|
||||
* Holds if there is a partial data flow path from `source` to `node`. The
|
||||
* approximate distance between `node` and the closest source is `dist` and
|
||||
@@ -341,29 +327,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -377,7 +340,10 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
not config.isSink(n) and
|
||||
not config.isSink(n, _)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -386,7 +352,10 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
||||
exists(Node n | node.asNode() = n |
|
||||
config.isBarrier(n, state)
|
||||
or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -516,9 +485,8 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -528,37 +496,6 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
expectsContentCached(n.asNode(), cs) and
|
||||
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -636,9 +573,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -662,10 +599,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
readSet(mid, c, node, config)
|
||||
read(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -683,16 +620,6 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -785,9 +712,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -813,10 +740,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -835,8 +762,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
@@ -935,8 +861,8 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -946,10 +872,7 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1224,26 +1147,11 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlowState(state, config) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
ap = true and
|
||||
expectsContentCand(node, config)
|
||||
)
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1666,7 +1574,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1704,22 +1612,8 @@ private module Stage2 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -1812,8 +1706,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1836,9 +1729,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
read(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1859,8 +1752,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -2033,34 +1926,7 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||
exists(Content c |
|
||||
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||
expectsContentEx(node, c) and
|
||||
c = ap.getHead().getContent()
|
||||
)
|
||||
}
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -2069,13 +1935,8 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap, config) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
expectsContentCand(node, ap, config)
|
||||
)
|
||||
not clear(node, ap) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2502,7 +2363,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -2540,22 +2401,8 @@ private module Stage3 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3343,7 +3190,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3381,22 +3228,8 @@ private module Stage4 {
|
||||
storeStepFwd(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
private predicate validAp(Ap ap, Configuration config) {
|
||||
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||
or
|
||||
exists(TypedContent head, Ap tail |
|
||||
consCand(head, tail, config) and
|
||||
ap = apCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
storeStepCand(_, ap, tc, _, _, config)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -3467,25 +3300,14 @@ private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary0(
|
||||
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate nodeMayUseSummary(
|
||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(DataFlowCallable c |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||
nodeMayUseSummary0(n, c, state, apa, config)
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3684,7 +3506,7 @@ private newtype TPathNode =
|
||||
* of dereference operations needed to get from the value in the node to the
|
||||
* tracked object. The final type indicates the type of the tracked object.
|
||||
*/
|
||||
private class AccessPath extends TAccessPath {
|
||||
abstract private class AccessPath extends TAccessPath {
|
||||
/** Gets the head of this access path, if any. */
|
||||
abstract TypedContent getHead();
|
||||
|
||||
@@ -3877,11 +3699,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3889,30 +3716,16 @@ class PathNode extends TPathNode {
|
||||
}
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
abstract PathNode getASuccessorImpl();
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
not this.getConfiguration().includeHiddenNodes() and
|
||||
(
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
)
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
@@ -3943,17 +3756,15 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
@@ -3962,7 +3773,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
|
||||
*/
|
||||
module PathGraph {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
@@ -4080,7 +3891,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNode getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
}
|
||||
@@ -4391,42 +4202,38 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
readSet(n1, _, n2, _)
|
||||
read(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
|
||||
succ = pred.getANonHiddenSuccessor() and
|
||||
succNode = succ.getNodeEx()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
||||
not ret.isHidden() and
|
||||
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||
|
|
||||
out = out0 or out = out0.projectToSink()
|
||||
par.getNodeEx() = p and
|
||||
out0.getNodeEx() = o and
|
||||
out0.getState() = sout and
|
||||
out0.getAp() = apout and
|
||||
(out = out0 or out = out0.projectToSink())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
predicate retReach(PathNode n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getANonHiddenSuccessor() = mid and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4750,11 +4557,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4770,11 +4573,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
(
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead().getContent())
|
||||
) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -216,9 +216,10 @@ private module LambdaFlow {
|
||||
or
|
||||
// jump step
|
||||
exists(Node mid, DataFlowType t0 |
|
||||
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, lastCall) and
|
||||
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and
|
||||
toReturn = false and
|
||||
toJump = true
|
||||
toJump = true and
|
||||
lastCall = TDataFlowCallNone()
|
||||
|
|
||||
jumpStepCached(node, mid) and
|
||||
t = t0
|
||||
@@ -304,7 +305,7 @@ cached
|
||||
private module Cached {
|
||||
/**
|
||||
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
|
||||
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and thereby
|
||||
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
|
||||
* collapsing the two stages.
|
||||
*/
|
||||
cached
|
||||
@@ -325,10 +326,7 @@ private module Cached {
|
||||
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
|
||||
|
||||
cached
|
||||
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
|
||||
|
||||
cached
|
||||
predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) }
|
||||
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
|
||||
|
||||
cached
|
||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||
@@ -375,7 +373,7 @@ private module Cached {
|
||||
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
||||
// is obtained by popping the head of the access path stack) is compatible with
|
||||
// the type of `x.f`.
|
||||
readSet(_, _, n)
|
||||
read(_, _, n)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -471,7 +469,7 @@ private module Cached {
|
||||
// read
|
||||
exists(Node mid |
|
||||
parameterValueFlowCand(p, mid, false) and
|
||||
readSet(mid, _, node) and
|
||||
read(mid, _, node) and
|
||||
read = true
|
||||
)
|
||||
or
|
||||
@@ -659,10 +657,8 @@ private module Cached {
|
||||
* Holds if `arg` flows to `out` through a call using only
|
||||
* value-preserving steps and a single read step, not taking call
|
||||
* contexts into account, thus representing a getter-step.
|
||||
*
|
||||
* This predicate is exposed for testing only.
|
||||
*/
|
||||
predicate getterStep(ArgNode arg, ContentSet c, Node out) {
|
||||
predicate getterStep(ArgNode arg, Content c, Node out) {
|
||||
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
||||
}
|
||||
|
||||
@@ -785,12 +781,8 @@ private module Cached {
|
||||
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
||||
}
|
||||
|
||||
cached
|
||||
predicate readSet(Node node1, ContentSet c, Node node2) { readStep(node1, c, node2) }
|
||||
|
||||
cached
|
||||
predicate storeSet(
|
||||
Node node1, ContentSet c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||
private predicate store(
|
||||
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||
) {
|
||||
storeStep(node1, c, node2) and
|
||||
contentType = getNodeDataFlowType(node1) and
|
||||
@@ -802,19 +794,14 @@ private module Cached {
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
||||
or
|
||||
readSet(n2, c, n1) and
|
||||
read(n2, c, n1) and
|
||||
contentType = getNodeDataFlowType(n1) and
|
||||
containerType = getNodeDataFlowType(n2)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate store(
|
||||
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||
) {
|
||||
exists(ContentSet cs |
|
||||
c = cs.getAStoreContent() and storeSet(node1, cs, node2, contentType, containerType)
|
||||
)
|
||||
}
|
||||
cached
|
||||
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a direct assignment to
|
||||
@@ -945,16 +932,16 @@ class CastingNode extends Node {
|
||||
}
|
||||
|
||||
private predicate readStepWithTypes(
|
||||
Node n1, DataFlowType container, ContentSet c, Node n2, DataFlowType content
|
||||
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
|
||||
) {
|
||||
readSet(n1, c, n2) and
|
||||
read(n1, c, n2) and
|
||||
container = getNodeDataFlowType(n1) and
|
||||
content = getNodeDataFlowType(n2)
|
||||
}
|
||||
|
||||
private newtype TReadStepTypesOption =
|
||||
TReadStepTypesNone() or
|
||||
TReadStepTypesSome(DataFlowType container, ContentSet c, DataFlowType content) {
|
||||
TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) {
|
||||
readStepWithTypes(_, container, c, _, content)
|
||||
}
|
||||
|
||||
@@ -963,7 +950,7 @@ private class ReadStepTypesOption extends TReadStepTypesOption {
|
||||
|
||||
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
|
||||
|
||||
ContentSet getContent() { this = TReadStepTypesSome(_, result, _) }
|
||||
Content getContent() { this = TReadStepTypesSome(_, result, _) }
|
||||
|
||||
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
|
||||
|
||||
@@ -1338,6 +1325,8 @@ abstract class AccessPathFront extends TAccessPathFront {
|
||||
abstract boolean toBoolNonEmpty();
|
||||
|
||||
TypedContent getHead() { this = TFrontHead(result) }
|
||||
|
||||
predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) }
|
||||
}
|
||||
|
||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||
|
||||
@@ -279,12 +279,6 @@ predicate clearsContent(Node n, Content c) {
|
||||
none() // stub implementation
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value that is being tracked is expected to be stored inside content `c`
|
||||
* at node `n`.
|
||||
*/
|
||||
predicate expectsContent(Node n, ContentSet c) { none() }
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
IRType getNodeType(Node n) {
|
||||
suppressUnusedNode(n) and
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user