mirror of
https://github.com/github/codeql.git
synced 2026-05-30 02:51:24 +02:00
Compare commits
1 Commits
jhelie/tes
...
jhelie/ext
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d15f09e8aa |
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
|
||||
|
||||
17
.github/labeler.yml
vendored
17
.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*
|
||||
@@ -30,7 +21,7 @@ Python:
|
||||
Ruby:
|
||||
- ruby/**/*
|
||||
- change-notes/**/*ruby*
|
||||
|
||||
|
||||
Swift:
|
||||
- swift/**/*
|
||||
- change-notes/**/*swift*
|
||||
@@ -40,5 +31,5 @@ documentation:
|
||||
- "**/*.md"
|
||||
- docs/**/*
|
||||
|
||||
"QL-for-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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v2
|
||||
with:
|
||||
dotnet-version: 6.0.202
|
||||
dotnet-version: 6.0.101
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
4
.github/workflows/csv-coverage-metrics.yml
vendored
4
.github/workflows/csv-coverage-metrics.yml
vendored
@@ -38,7 +38,7 @@ jobs:
|
||||
path: metrics-java.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
|
||||
|
||||
@@ -65,6 +65,6 @@ jobs:
|
||||
path: metrics-csharp.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-csharp.sarif
|
||||
|
||||
@@ -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@v3
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Download CodeQL CLI
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
- name: Clone self (github/codeql)
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: 3.8
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
path: codeqlModels
|
||||
fetch-depth: 0
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Download CodeQL CLI
|
||||
|
||||
2
.github/workflows/csv-coverage-update.yml
vendored
2
.github/workflows/csv-coverage-update.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
path: ql
|
||||
fetch-depth: 0
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Download CodeQL CLI
|
||||
|
||||
2
.github/workflows/csv-coverage.yml
vendored
2
.github/workflows/csv-coverage.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
path: codeqlModels
|
||||
ref: ${{ github.event.inputs.qlModelShaOverride || github.ref }}
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Download CodeQL CLI
|
||||
|
||||
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
|
||||
3
.github/workflows/js-ml-tests.yml
vendored
3
.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:
|
||||
|
||||
3
.github/workflows/labeler.yml
vendored
3
.github/workflows/labeler.yml
vendored
@@ -4,9 +4,6 @@ on:
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v4
|
||||
|
||||
2
.github/workflows/mad_modelDiff.yml
vendored
2
.github/workflows/mad_modelDiff.yml
vendored
@@ -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 ..
|
||||
}
|
||||
|
||||
2
.github/workflows/mad_regenerate-models.yml
vendored
2
.github/workflows/mad_regenerate-models.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
ref: ["placeholder"]
|
||||
include:
|
||||
- slug: "apache/commons-io"
|
||||
ref: "13258ce2d07aa0e764bbaa8020af4dcd3a02a620"
|
||||
ref: "8985de8fe74f6622a419b37a6eed0dbc484dc128"
|
||||
exclude:
|
||||
- slug: "placeholder"
|
||||
ref: "placeholder"
|
||||
|
||||
2
.github/workflows/ql-for-ql-build.yml
vendored
2
.github/workflows/ql-for-ql-build.yml
vendored
@@ -140,7 +140,7 @@ 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, swift]
|
||||
|
||||
needs:
|
||||
- package
|
||||
|
||||
@@ -19,6 +19,7 @@ jobs:
|
||||
matrix:
|
||||
repo:
|
||||
- github/codeql
|
||||
- github/codeql-go
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -76,7 +77,7 @@ jobs:
|
||||
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
|
||||
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@v3
|
||||
with:
|
||||
name: ql.dbscheme.stats
|
||||
|
||||
2
.github/workflows/ql-for-ql-tests.yml
vendored
2
.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
|
||||
|
||||
20
.github/workflows/query-list.yml
vendored
20
.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'
|
||||
@@ -22,20 +20,30 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: codeql
|
||||
- name: Clone github/codeql-go
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: 'github/codeql-go'
|
||||
path: codeql-go
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v3
|
||||
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
|
||||
with:
|
||||
name: code-scanning-query-list
|
||||
path: code-scanning-query-list.csv
|
||||
|
||||
|
||||
2
.github/workflows/ruby-build.yml
vendored
2
.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/*"
|
||||
|
||||
2
.github/workflows/ruby-qltest.yml
vendored
2
.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/*"
|
||||
|
||||
22
.github/workflows/swift-codegen.yml
vendored
22
.github/workflows/swift-codegen.yml
vendored
@@ -16,21 +16,17 @@ jobs:
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: bazelbuild/setup-bazelisk@v2
|
||||
- uses: actions/setup-python@v3
|
||||
- uses: pre-commit/action@v3.0.0
|
||||
name: Check that python code is properly formatted
|
||||
with:
|
||||
extra_args: autopep8 --all-files
|
||||
python-version: '~3.8'
|
||||
cache: 'pip'
|
||||
- name: Install python dependencies
|
||||
run: |
|
||||
pip install -r swift/codegen/requirements.txt
|
||||
- name: Run unit tests
|
||||
run: |
|
||||
bazel test //swift/codegen/test --test_output=errors
|
||||
- uses: pre-commit/action@v3.0.0
|
||||
name: Check that QL generated code was checked in
|
||||
with:
|
||||
extra_args: swift-codegen --all-files
|
||||
- name: Generate C++ files
|
||||
- name: Check that code was generated
|
||||
run: |
|
||||
bazel run //swift/codegen:codegen -- --generate=trap,cpp --cpp-output=$PWD/swift-generated-cpp-files
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: swift-generated-cpp-files
|
||||
path: swift-generated-cpp-files/**
|
||||
bazel run //swift/codegen
|
||||
git add swift
|
||||
git diff --exit-code --stat HEAD
|
||||
|
||||
8
.github/workflows/swift-qltest.yml
vendored
8
.github/workflows/swift-qltest.yml
vendored
@@ -5,7 +5,6 @@ on:
|
||||
paths:
|
||||
- "swift/**"
|
||||
- .github/workflows/swift-qltest.yml
|
||||
- codeql-workspace.yml
|
||||
branches:
|
||||
- main
|
||||
defaults:
|
||||
@@ -30,6 +29,13 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: bazelbuild/setup-bazelisk@v2
|
||||
- uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: '~3.8'
|
||||
cache: 'pip'
|
||||
- name: Install python dependencies
|
||||
run: |
|
||||
pip install -r codegen/requirements.txt
|
||||
- name: Build Swift extractor
|
||||
run: |
|
||||
bazel run //swift:create-extractor-pack
|
||||
|
||||
22
.gitignore
vendored
22
.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/*
|
||||
@@ -38,26 +37,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: "*"
|
||||
|
||||
|
||||
@@ -15,12 +15,6 @@ repos:
|
||||
- id: clang-format
|
||||
files: ^swift/.*\.(h|c|cpp)$
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-autopep8
|
||||
rev: v1.6.0
|
||||
hooks:
|
||||
- id: autopep8
|
||||
files: ^swift/codegen/.*\.py
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: codeql-format
|
||||
@@ -31,7 +25,7 @@ repos:
|
||||
|
||||
- id: sync-files
|
||||
name: Fix files required to be identical
|
||||
files: \.(qll?|qhelp|swift)$
|
||||
files: \.(qll?|qhelp)$
|
||||
language: system
|
||||
entry: python3 config/sync-files.py --latest
|
||||
pass_filenames: false
|
||||
@@ -46,7 +40,7 @@ repos:
|
||||
name: Run Swift checked in code generation
|
||||
files: ^swift/(codegen/|.*/generated/|ql/lib/(swift\.dbscheme$|codeql/swift/elements))
|
||||
language: system
|
||||
entry: bazel run //swift/codegen -- --quiet
|
||||
entry: bazel run //swift/codegen
|
||||
pass_filenames: false
|
||||
|
||||
- id: swift-codegen-unit-tests
|
||||
|
||||
@@ -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,8 +24,8 @@
|
||||
# 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
|
||||
@@ -38,7 +34,6 @@ WORKSPACE.bazel @github/codeql-ci-reviewers
|
||||
|
||||
# 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
|
||||
|
||||
@@ -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",
|
||||
@@ -453,11 +446,11 @@
|
||||
"python/ql/src/Lexical/CommentedOutCodeReferences.inc.qhelp"
|
||||
],
|
||||
"IDE Contextual Queries": [
|
||||
"cpp/ql/lib/IDEContextual.qll",
|
||||
"csharp/ql/lib/IDEContextual.qll",
|
||||
"java/ql/lib/IDEContextual.qll",
|
||||
"javascript/ql/lib/IDEContextual.qll",
|
||||
"python/ql/lib/analysis/IDEContextual.qll"
|
||||
"cpp/ql/src/IDEContextual.qll",
|
||||
"csharp/ql/src/IDEContextual.qll",
|
||||
"java/ql/src/IDEContextual.qll",
|
||||
"javascript/ql/src/IDEContextual.qll",
|
||||
"python/ql/src/analysis/IDEContextual.qll"
|
||||
],
|
||||
"SSA C#": [
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImplCommon.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"
|
||||
]
|
||||
}
|
||||
|
||||
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,42 +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
|
||||
|
||||
4
cpp/ql/lib/change-notes/2022-04-22-no-size-array.md
Normal file
4
cpp/ql/lib/change-notes/2022-04-22-no-size-array.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `semmle.code.cpp.commons.Buffer` library has been enhanced to handle array members of classes that do not specify a size.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
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)`.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* More Windows pool allocation functions are now detected as `AllocationFunction`s.
|
||||
@@ -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.1.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.3.1-dev
|
||||
version: 0.1.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -31,7 +31,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())
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -428,7 +397,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
simpleLocalFlowStepExt(n1, n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
or
|
||||
@@ -447,7 +416,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
@@ -466,7 +435,7 @@ private predicate additionalLocalStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -481,7 +450,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
jumpStepCached(n1, n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
)
|
||||
@@ -494,7 +463,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -507,7 +476,7 @@ private predicate additionalJumpStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -518,7 +487,7 @@ private predicate additionalJumpStateStep(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -529,41 +498,28 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = 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
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
store(node1.asNode(), tc, node2.asNode(), contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
@@ -837,7 +793,7 @@ private module Stage1 {
|
||||
* 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,7 +891,7 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
@@ -1225,26 +1181,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
|
||||
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]
|
||||
@@ -1705,22 +1646,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]
|
||||
@@ -1813,8 +1740,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2053,16 +1979,6 @@ private module Stage3 {
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
|
||||
@@ -2071,12 +1987,7 @@ private module Stage3 {
|
||||
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)
|
||||
)
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2541,22 +2452,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]
|
||||
@@ -3382,22 +3279,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]
|
||||
@@ -3468,25 +3351,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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3685,7 +3557,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();
|
||||
|
||||
@@ -3878,11 +3750,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. */
|
||||
@@ -3890,30 +3767,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() {
|
||||
@@ -3944,17 +3807,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)
|
||||
|
||||
@@ -3963,7 +3824,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) {
|
||||
@@ -4081,7 +3942,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) }
|
||||
}
|
||||
@@ -4396,38 +4257,34 @@ private module Subpaths {
|
||||
)
|
||||
}
|
||||
|
||||
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, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4752,10 +4609,6 @@ private module FlowExploration {
|
||||
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 fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4772,10 +4625,6 @@ private module FlowExploration {
|
||||
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
|
||||
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.
|
||||
@@ -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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -428,7 +397,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
simpleLocalFlowStepExt(n1, n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
or
|
||||
@@ -447,7 +416,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
@@ -466,7 +435,7 @@ private predicate additionalLocalStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -481,7 +450,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
jumpStepCached(n1, n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
)
|
||||
@@ -494,7 +463,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -507,7 +476,7 @@ private predicate additionalJumpStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -518,7 +487,7 @@ private predicate additionalJumpStateStep(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -529,41 +498,28 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = 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
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
store(node1.asNode(), tc, node2.asNode(), contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
@@ -837,7 +793,7 @@ private module Stage1 {
|
||||
* 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,7 +891,7 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
@@ -1225,26 +1181,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
|
||||
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]
|
||||
@@ -1705,22 +1646,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]
|
||||
@@ -1813,8 +1740,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2053,16 +1979,6 @@ private module Stage3 {
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
|
||||
@@ -2071,12 +1987,7 @@ private module Stage3 {
|
||||
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)
|
||||
)
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2541,22 +2452,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]
|
||||
@@ -3382,22 +3279,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]
|
||||
@@ -3468,25 +3351,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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3685,7 +3557,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();
|
||||
|
||||
@@ -3878,11 +3750,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. */
|
||||
@@ -3890,30 +3767,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() {
|
||||
@@ -3944,17 +3807,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)
|
||||
|
||||
@@ -3963,7 +3824,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) {
|
||||
@@ -4081,7 +3942,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) }
|
||||
}
|
||||
@@ -4396,38 +4257,34 @@ private module Subpaths {
|
||||
)
|
||||
}
|
||||
|
||||
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, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4752,10 +4609,6 @@ private module FlowExploration {
|
||||
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 fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4772,10 +4625,6 @@ private module FlowExploration {
|
||||
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
|
||||
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.
|
||||
@@ -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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -428,7 +397,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
simpleLocalFlowStepExt(n1, n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
or
|
||||
@@ -447,7 +416,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
@@ -466,7 +435,7 @@ private predicate additionalLocalStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -481,7 +450,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
jumpStepCached(n1, n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
)
|
||||
@@ -494,7 +463,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -507,7 +476,7 @@ private predicate additionalJumpStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -518,7 +487,7 @@ private predicate additionalJumpStateStep(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -529,41 +498,28 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = 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
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
store(node1.asNode(), tc, node2.asNode(), contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
@@ -837,7 +793,7 @@ private module Stage1 {
|
||||
* 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,7 +891,7 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
@@ -1225,26 +1181,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
|
||||
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]
|
||||
@@ -1705,22 +1646,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]
|
||||
@@ -1813,8 +1740,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2053,16 +1979,6 @@ private module Stage3 {
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
|
||||
@@ -2071,12 +1987,7 @@ private module Stage3 {
|
||||
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)
|
||||
)
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2541,22 +2452,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]
|
||||
@@ -3382,22 +3279,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]
|
||||
@@ -3468,25 +3351,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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3685,7 +3557,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();
|
||||
|
||||
@@ -3878,11 +3750,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. */
|
||||
@@ -3890,30 +3767,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() {
|
||||
@@ -3944,17 +3807,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)
|
||||
|
||||
@@ -3963,7 +3824,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) {
|
||||
@@ -4081,7 +3942,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) }
|
||||
}
|
||||
@@ -4396,38 +4257,34 @@ private module Subpaths {
|
||||
)
|
||||
}
|
||||
|
||||
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, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4752,10 +4609,6 @@ private module FlowExploration {
|
||||
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 fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4772,10 +4625,6 @@ private module FlowExploration {
|
||||
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
|
||||
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.
|
||||
@@ -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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -428,7 +397,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
simpleLocalFlowStepExt(n1, n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
or
|
||||
@@ -447,7 +416,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
@@ -466,7 +435,7 @@ private predicate additionalLocalStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -481,7 +450,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
jumpStepCached(n1, n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
)
|
||||
@@ -494,7 +463,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -507,7 +476,7 @@ private predicate additionalJumpStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -518,7 +487,7 @@ private predicate additionalJumpStateStep(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -529,41 +498,28 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = 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
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
store(node1.asNode(), tc, node2.asNode(), contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
@@ -837,7 +793,7 @@ private module Stage1 {
|
||||
* 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,7 +891,7 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
@@ -1225,26 +1181,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
|
||||
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]
|
||||
@@ -1705,22 +1646,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]
|
||||
@@ -1813,8 +1740,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2053,16 +1979,6 @@ private module Stage3 {
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
|
||||
@@ -2071,12 +1987,7 @@ private module Stage3 {
|
||||
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)
|
||||
)
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2541,22 +2452,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]
|
||||
@@ -3382,22 +3279,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]
|
||||
@@ -3468,25 +3351,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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3685,7 +3557,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();
|
||||
|
||||
@@ -3878,11 +3750,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. */
|
||||
@@ -3890,30 +3767,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() {
|
||||
@@ -3944,17 +3807,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)
|
||||
|
||||
@@ -3963,7 +3824,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) {
|
||||
@@ -4081,7 +3942,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) }
|
||||
}
|
||||
@@ -4396,38 +4257,34 @@ private module Subpaths {
|
||||
)
|
||||
}
|
||||
|
||||
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, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4752,10 +4609,6 @@ private module FlowExploration {
|
||||
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 fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4772,10 +4625,6 @@ private module FlowExploration {
|
||||
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
|
||||
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
|
||||
@@ -327,9 +328,6 @@ private module Cached {
|
||||
cached
|
||||
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
|
||||
|
||||
cached
|
||||
predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) }
|
||||
|
||||
cached
|
||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||
|
||||
@@ -788,31 +786,24 @@ private module Cached {
|
||||
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
|
||||
) {
|
||||
storeStep(node1, c, node2) and
|
||||
contentType = getNodeDataFlowType(node1) and
|
||||
containerType = getNodeDataFlowType(node2)
|
||||
or
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
||||
or
|
||||
readSet(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)
|
||||
exists(ContentSet cs | c = cs.getAStoreContent() |
|
||||
storeStep(node1, cs, node2) and
|
||||
contentType = getNodeDataFlowType(node1) and
|
||||
containerType = getNodeDataFlowType(node2)
|
||||
or
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, cs, contentType), n1)
|
||||
or
|
||||
readSet(n2, cs, n1) and
|
||||
contentType = getNodeDataFlowType(n1) and
|
||||
containerType = getNodeDataFlowType(n2)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -428,7 +397,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
simpleLocalFlowStepExt(n1, n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
or
|
||||
@@ -447,7 +416,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
@@ -466,7 +435,7 @@ private predicate additionalLocalStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -481,7 +450,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
jumpStepCached(n1, n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
)
|
||||
@@ -494,7 +463,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -507,7 +476,7 @@ private predicate additionalJumpStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -518,7 +487,7 @@ private predicate additionalJumpStateStep(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -529,41 +498,28 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = 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
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
store(node1.asNode(), tc, node2.asNode(), contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
@@ -837,7 +793,7 @@ private module Stage1 {
|
||||
* 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,7 +891,7 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
@@ -1225,26 +1181,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
|
||||
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]
|
||||
@@ -1705,22 +1646,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]
|
||||
@@ -1813,8 +1740,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2053,16 +1979,6 @@ private module Stage3 {
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
|
||||
@@ -2071,12 +1987,7 @@ private module Stage3 {
|
||||
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)
|
||||
)
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2541,22 +2452,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]
|
||||
@@ -3382,22 +3279,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]
|
||||
@@ -3468,25 +3351,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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3685,7 +3557,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();
|
||||
|
||||
@@ -3878,11 +3750,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. */
|
||||
@@ -3890,30 +3767,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() {
|
||||
@@ -3944,17 +3807,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)
|
||||
|
||||
@@ -3963,7 +3824,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) {
|
||||
@@ -4081,7 +3942,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) }
|
||||
}
|
||||
@@ -4396,38 +4257,34 @@ private module Subpaths {
|
||||
)
|
||||
}
|
||||
|
||||
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, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4752,10 +4609,6 @@ private module FlowExploration {
|
||||
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 fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4772,10 +4625,6 @@ private module FlowExploration {
|
||||
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
|
||||
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
|
||||
|
||||
@@ -850,34 +850,6 @@ class ContentSet instanceof Content {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 +858,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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -428,7 +397,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
simpleLocalFlowStepExt(n1, n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
or
|
||||
@@ -447,7 +416,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
@@ -466,7 +435,7 @@ private predicate additionalLocalStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -481,7 +450,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
jumpStepCached(n1, n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
)
|
||||
@@ -494,7 +463,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -507,7 +476,7 @@ private predicate additionalJumpStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -518,7 +487,7 @@ private predicate additionalJumpStateStep(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -529,41 +498,28 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = 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
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
store(node1.asNode(), tc, node2.asNode(), contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
@@ -837,7 +793,7 @@ private module Stage1 {
|
||||
* 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,7 +891,7 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
@@ -1225,26 +1181,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
|
||||
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]
|
||||
@@ -1705,22 +1646,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]
|
||||
@@ -1813,8 +1740,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2053,16 +1979,6 @@ private module Stage3 {
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
|
||||
@@ -2071,12 +1987,7 @@ private module Stage3 {
|
||||
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)
|
||||
)
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2541,22 +2452,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]
|
||||
@@ -3382,22 +3279,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]
|
||||
@@ -3468,25 +3351,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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3685,7 +3557,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();
|
||||
|
||||
@@ -3878,11 +3750,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. */
|
||||
@@ -3890,30 +3767,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() {
|
||||
@@ -3944,17 +3807,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)
|
||||
|
||||
@@ -3963,7 +3824,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) {
|
||||
@@ -4081,7 +3942,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) }
|
||||
}
|
||||
@@ -4396,38 +4257,34 @@ private module Subpaths {
|
||||
)
|
||||
}
|
||||
|
||||
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, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4752,10 +4609,6 @@ private module FlowExploration {
|
||||
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 fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4772,10 +4625,6 @@ private module FlowExploration {
|
||||
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
|
||||
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.
|
||||
@@ -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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -428,7 +397,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
simpleLocalFlowStepExt(n1, n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
or
|
||||
@@ -447,7 +416,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
@@ -466,7 +435,7 @@ private predicate additionalLocalStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -481,7 +450,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
jumpStepCached(n1, n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
)
|
||||
@@ -494,7 +463,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -507,7 +476,7 @@ private predicate additionalJumpStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -518,7 +487,7 @@ private predicate additionalJumpStateStep(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -529,41 +498,28 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = 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
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
store(node1.asNode(), tc, node2.asNode(), contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
@@ -837,7 +793,7 @@ private module Stage1 {
|
||||
* 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,7 +891,7 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
@@ -1225,26 +1181,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
|
||||
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]
|
||||
@@ -1705,22 +1646,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]
|
||||
@@ -1813,8 +1740,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2053,16 +1979,6 @@ private module Stage3 {
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
|
||||
@@ -2071,12 +1987,7 @@ private module Stage3 {
|
||||
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)
|
||||
)
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2541,22 +2452,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]
|
||||
@@ -3382,22 +3279,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]
|
||||
@@ -3468,25 +3351,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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3685,7 +3557,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();
|
||||
|
||||
@@ -3878,11 +3750,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. */
|
||||
@@ -3890,30 +3767,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() {
|
||||
@@ -3944,17 +3807,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)
|
||||
|
||||
@@ -3963,7 +3824,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) {
|
||||
@@ -4081,7 +3942,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) }
|
||||
}
|
||||
@@ -4396,38 +4257,34 @@ private module Subpaths {
|
||||
)
|
||||
}
|
||||
|
||||
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, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4752,10 +4609,6 @@ private module FlowExploration {
|
||||
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 fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4772,10 +4625,6 @@ private module FlowExploration {
|
||||
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
|
||||
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.
|
||||
@@ -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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -428,7 +397,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
simpleLocalFlowStepExt(n1, n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
or
|
||||
@@ -447,7 +416,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
@@ -466,7 +435,7 @@ private predicate additionalLocalStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -481,7 +450,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
jumpStepCached(n1, n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
)
|
||||
@@ -494,7 +463,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -507,7 +476,7 @@ private predicate additionalJumpStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -518,7 +487,7 @@ private predicate additionalJumpStateStep(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -529,41 +498,28 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = 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
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
store(node1.asNode(), tc, node2.asNode(), contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
@@ -837,7 +793,7 @@ private module Stage1 {
|
||||
* 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,7 +891,7 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
@@ -1225,26 +1181,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
|
||||
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]
|
||||
@@ -1705,22 +1646,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]
|
||||
@@ -1813,8 +1740,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2053,16 +1979,6 @@ private module Stage3 {
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
|
||||
@@ -2071,12 +1987,7 @@ private module Stage3 {
|
||||
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)
|
||||
)
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2541,22 +2452,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]
|
||||
@@ -3382,22 +3279,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]
|
||||
@@ -3468,25 +3351,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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3685,7 +3557,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();
|
||||
|
||||
@@ -3878,11 +3750,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. */
|
||||
@@ -3890,30 +3767,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() {
|
||||
@@ -3944,17 +3807,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)
|
||||
|
||||
@@ -3963,7 +3824,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) {
|
||||
@@ -4081,7 +3942,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) }
|
||||
}
|
||||
@@ -4396,38 +4257,34 @@ private module Subpaths {
|
||||
)
|
||||
}
|
||||
|
||||
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, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4752,10 +4609,6 @@ private module FlowExploration {
|
||||
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 fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4772,10 +4625,6 @@ private module FlowExploration {
|
||||
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
|
||||
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.
|
||||
@@ -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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -428,7 +397,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
simpleLocalFlowStepExt(n1, n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
or
|
||||
@@ -447,7 +416,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config)
|
||||
)
|
||||
@@ -466,7 +435,7 @@ private predicate additionalLocalStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -481,7 +450,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
jumpStepCached(n1, n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
)
|
||||
@@ -494,7 +463,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and
|
||||
config.isAdditionalFlowStep(n1, n2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -507,7 +476,7 @@ private predicate additionalJumpStateStep(
|
||||
exists(Node n1, Node n2 |
|
||||
node1.asNode() = n1 and
|
||||
node2.asNode() = n2 and
|
||||
config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||
stepFilter(node1, node2, config) and
|
||||
not stateBarrier(node1, s1, config) and
|
||||
@@ -518,7 +487,7 @@ private predicate additionalJumpStateStep(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -529,41 +498,28 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
bindingset[c]
|
||||
pragma[inline]
|
||||
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()
|
||||
c = 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
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
store(node1.asNode(), tc, node2.asNode(), contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
@@ -837,7 +793,7 @@ private module Stage1 {
|
||||
* 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,7 +891,7 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
@@ -1225,26 +1181,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
|
||||
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]
|
||||
@@ -1705,22 +1646,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]
|
||||
@@ -1813,8 +1740,7 @@ private module LocalFlowBigStep {
|
||||
private class FlowCheckNode extends NodeEx {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
clearsContentCached(this.asNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2053,16 +1979,6 @@ private module Stage3 {
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
|
||||
@@ -2071,12 +1987,7 @@ private module Stage3 {
|
||||
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)
|
||||
)
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -2541,22 +2452,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]
|
||||
@@ -3382,22 +3279,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]
|
||||
@@ -3468,25 +3351,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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3685,7 +3557,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();
|
||||
|
||||
@@ -3878,11 +3750,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. */
|
||||
@@ -3890,30 +3767,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() {
|
||||
@@ -3944,17 +3807,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)
|
||||
|
||||
@@ -3963,7 +3824,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) {
|
||||
@@ -4081,7 +3942,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) }
|
||||
}
|
||||
@@ -4396,38 +4257,34 @@ private module Subpaths {
|
||||
)
|
||||
}
|
||||
|
||||
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, _, _)
|
||||
)
|
||||
}
|
||||
@@ -4752,10 +4609,6 @@ private module FlowExploration {
|
||||
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 fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4772,10 +4625,6 @@ private module FlowExploration {
|
||||
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
|
||||
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
|
||||
@@ -327,9 +328,6 @@ private module Cached {
|
||||
cached
|
||||
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
|
||||
|
||||
cached
|
||||
predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) }
|
||||
|
||||
cached
|
||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||
|
||||
@@ -788,31 +786,24 @@ private module Cached {
|
||||
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
|
||||
) {
|
||||
storeStep(node1, c, node2) and
|
||||
contentType = getNodeDataFlowType(node1) and
|
||||
containerType = getNodeDataFlowType(node2)
|
||||
or
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
||||
or
|
||||
readSet(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)
|
||||
exists(ContentSet cs | c = cs.getAStoreContent() |
|
||||
storeStep(node1, cs, node2) and
|
||||
contentType = getNodeDataFlowType(node1) and
|
||||
containerType = getNodeDataFlowType(node2)
|
||||
or
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, cs, contentType), n1)
|
||||
or
|
||||
readSet(n2, cs, n1) and
|
||||
contentType = getNodeDataFlowType(n1) and
|
||||
containerType = getNodeDataFlowType(n2)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -37,7 +37,7 @@ private module Cached {
|
||||
* along the chain of addresses computed by `StoreNodeInstr.getInner` to identify field writes
|
||||
* and call `storeStep` accordingly (i.e., for an expression like `a.b.c = x`, we visit `c`, then
|
||||
* `b`, then `a`).
|
||||
* 2. Flow is transferred from a `WriteSideEffectInstruction` to a `StoreNodeOperand` after flow
|
||||
* 2. Flow is transfered from a `WriteSideEffectInstruction` to a `StoreNodeOperand` after flow
|
||||
* returns to a caller. Flow will then proceed to the defining instruction of the operand (because
|
||||
* the `StoreNodeInstr` computed by `StoreNodeOperand.getInner()` is the `StoreNode` containing
|
||||
* the defining instruction), and then along the chain computed by `StoreNodeInstr.getInner` like
|
||||
@@ -100,7 +100,7 @@ class Node extends TIRDataFlowNode {
|
||||
Declaration getEnclosingCallable() { none() } // overridden in subclasses
|
||||
|
||||
/** Gets the function to which this node belongs, if any. */
|
||||
Declaration getFunction() { none() } // overridden in subclasses
|
||||
Function getFunction() { none() } // overridden in subclasses
|
||||
|
||||
/** Gets the type of this node. */
|
||||
IRType getType() { none() } // overridden in subclasses
|
||||
@@ -196,7 +196,7 @@ class InstructionNode extends Node, TInstructionNode {
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override Declaration getFunction() { result = instr.getEnclosingFunction() }
|
||||
override Function getFunction() { result = instr.getEnclosingFunction() }
|
||||
|
||||
override IRType getType() { result = instr.getResultIRType() }
|
||||
|
||||
@@ -222,7 +222,7 @@ class OperandNode extends Node, TOperandNode {
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override Declaration getFunction() { result = op.getUse().getEnclosingFunction() }
|
||||
override Function getFunction() { result = op.getUse().getEnclosingFunction() }
|
||||
|
||||
override IRType getType() { result = op.getIRType() }
|
||||
|
||||
@@ -274,7 +274,7 @@ class StoreNodeInstr extends StoreNode, TStoreNodeInstr {
|
||||
/** Gets the underlying instruction. */
|
||||
Instruction getInstruction() { result = instr }
|
||||
|
||||
override Declaration getFunction() { result = this.getInstruction().getEnclosingFunction() }
|
||||
override Function getFunction() { result = this.getInstruction().getEnclosingFunction() }
|
||||
|
||||
override IRType getType() { result = this.getInstruction().getResultIRType() }
|
||||
|
||||
@@ -328,7 +328,7 @@ class StoreNodeOperand extends StoreNode, TStoreNodeOperand {
|
||||
/** Gets the underlying operand. */
|
||||
Operand getOperand() { result = operand }
|
||||
|
||||
override Declaration getFunction() { result = operand.getDef().getEnclosingFunction() }
|
||||
override Function getFunction() { result = operand.getDef().getEnclosingFunction() }
|
||||
|
||||
override IRType getType() { result = operand.getIRType() }
|
||||
|
||||
@@ -384,7 +384,7 @@ class ReadNode extends Node, TReadNode {
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override Declaration getFunction() { result = this.getInstruction().getEnclosingFunction() }
|
||||
override Function getFunction() { result = this.getInstruction().getEnclosingFunction() }
|
||||
|
||||
override IRType getType() { result = this.getInstruction().getResultIRType() }
|
||||
|
||||
@@ -436,7 +436,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
|
||||
override Function getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
|
||||
|
||||
override IRType getType() { result instanceof IRVoidType }
|
||||
|
||||
@@ -673,7 +673,7 @@ class VariableNode extends Node, TVariableNode {
|
||||
/** Gets the variable corresponding to this node. */
|
||||
Variable getVariable() { result = v }
|
||||
|
||||
override Declaration getFunction() { none() }
|
||||
override Function getFunction() { none() }
|
||||
|
||||
override Declaration getEnclosingCallable() {
|
||||
// When flow crosses from one _enclosing callable_ to another, the
|
||||
@@ -1092,56 +1092,6 @@ class ContentSet instanceof Content {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(IRGuardCondition 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(IRGuardCondition g, ValueNumber value, boolean edge |
|
||||
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
|
||||
result.asInstruction() = value.getAnInstruction() and
|
||||
g.controls(result.asInstruction().getBlock(), edge)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the guard `g` validates the instruction `instr` upon evaluating to `branch`.
|
||||
*/
|
||||
signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction instr, boolean branch);
|
||||
|
||||
/**
|
||||
* Provides a set of barrier nodes for a guard that validates an instruction.
|
||||
*
|
||||
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
|
||||
* in data flow and taint tracking.
|
||||
*/
|
||||
module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> {
|
||||
/** Gets a node that is safely guarded by the given guard check. */
|
||||
ExprNode getABarrierNode() {
|
||||
exists(IRGuardCondition g, ValueNumber value, boolean edge |
|
||||
instructionGuardChecks(g, value.getAnInstruction(), edge) and
|
||||
result.asInstruction() = value.getAnInstruction() and
|
||||
g.controls(result.asInstruction().getBlock(), edge)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `BarrierGuard` module instead.
|
||||
*
|
||||
* A guard that validates some instruction.
|
||||
*
|
||||
* To use this in a configuration, extend the class and provide a
|
||||
@@ -1150,7 +1100,7 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
|
||||
*
|
||||
* It is important that all extending classes in scope are disjoint.
|
||||
*/
|
||||
deprecated class BarrierGuard extends IRGuardCondition {
|
||||
class BarrierGuard extends IRGuardCondition {
|
||||
/** Override this predicate to hold if this guard validates `instr` upon evaluating to `b`. */
|
||||
predicate checksInstr(Instruction instr, boolean b) { none() }
|
||||
|
||||
|
||||
@@ -94,6 +94,12 @@ private string getNodeProperty(DataFlow::Node node, string key) {
|
||||
any(DataFlow::Configuration cfg).isBarrierIn(node) and kind = "in"
|
||||
or
|
||||
any(DataFlow::Configuration cfg).isBarrierOut(node) and kind = "out"
|
||||
or
|
||||
exists(DataFlow::BarrierGuard guard |
|
||||
any(DataFlow::Configuration cfg).isBarrierGuard(guard) and
|
||||
node = guard.getAGuardedNode() and
|
||||
kind = "guard(" + guard.getResultId() + ")"
|
||||
)
|
||||
|
|
||||
kind, ", "
|
||||
)
|
||||
|
||||
@@ -163,6 +163,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 from `instrIn` to `instrOut` through a call to a
|
||||
* modeled function.
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ class DefaultEdge extends EdgeKind, TDefaultEdge {
|
||||
|
||||
/**
|
||||
* A "case" edge, representing the successor of a `Switch` instruction when the
|
||||
* the condition value matches a corresponding `case` label.
|
||||
* the condition value matches a correponding `case` label.
|
||||
*/
|
||||
class CaseEdge extends EdgeKind, TCaseEdge {
|
||||
string minValue;
|
||||
|
||||
@@ -16,7 +16,7 @@ class IRConfiguration extends TIRConfiguration {
|
||||
/**
|
||||
* Holds if IR should be created for function `func`. By default, holds for all functions.
|
||||
*/
|
||||
predicate shouldCreateIRForFunction(Language::Declaration func) { any() }
|
||||
predicate shouldCreateIRForFunction(Language::Function func) { any() }
|
||||
|
||||
/**
|
||||
* Holds if the strings used as part of an IR dump should be generated for function `func`.
|
||||
@@ -25,7 +25,7 @@ class IRConfiguration extends TIRConfiguration {
|
||||
* of debug strings for IR that will not be dumped. We still generate the actual IR for these
|
||||
* functions, however, to preserve the results of any interprocedural analysis.
|
||||
*/
|
||||
predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) { any() }
|
||||
predicate shouldEvaluateDebugStringsForFunction(Language::Function func) { any() }
|
||||
}
|
||||
|
||||
private newtype TIREscapeAnalysisConfiguration = MkIREscapeAnalysisConfiguration()
|
||||
|
||||
@@ -97,7 +97,7 @@ class IRBlockBase extends TIRBlock {
|
||||
/**
|
||||
* Gets the `Function` that contains this block.
|
||||
*/
|
||||
final Language::Declaration getEnclosingFunction() {
|
||||
final Language::Function getEnclosingFunction() {
|
||||
result = getFirstInstruction(this).getEnclosingFunction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,23 +524,4 @@ module InstructionConsistency {
|
||||
"' has a `this` argument operand that is not an address, in function '$@'." and
|
||||
irFunc = getInstructionIRFunction(instr, irFuncText)
|
||||
}
|
||||
|
||||
query predicate nonUniqueIRVariable(
|
||||
Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText
|
||||
) {
|
||||
exists(VariableInstruction vi, IRVariable v1, IRVariable v2 |
|
||||
instr = vi and vi.getIRVariable() = v1 and vi.getIRVariable() = v2 and v1 != v2
|
||||
) and
|
||||
message =
|
||||
"Variable instruction '" + instr.toString() +
|
||||
"' has multiple associated variables, in function '$@'." and
|
||||
irFunc = getInstructionIRFunction(instr, irFuncText)
|
||||
or
|
||||
instr.getOpcode() instanceof Opcode::VariableAddress and
|
||||
not instr instanceof VariableInstruction and
|
||||
message =
|
||||
"Variable address instruction '" + instr.toString() +
|
||||
"' has no associated variable, in function '$@'." and
|
||||
irFunc = getInstructionIRFunction(instr, irFuncText)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ private import Imports::IRType
|
||||
* by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
class IRVariable extends TIRVariable {
|
||||
Language::Declaration func;
|
||||
Language::Function func;
|
||||
|
||||
IRVariable() {
|
||||
this = TIRUserVariable(_, _, func) or
|
||||
@@ -79,7 +79,7 @@ class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
*/
|
||||
final Language::Declaration getEnclosingFunction() { result = func }
|
||||
final Language::Function getEnclosingFunction() { result = func }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,7 +246,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
|
||||
|
||||
final override string toString() { result = "#ellipsis" }
|
||||
|
||||
final override int getIndex() { result = func.(Language::Function).getNumberOfParameters() }
|
||||
final override int getIndex() { result = func.getNumberOfParameters() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -194,7 +194,7 @@ class Instruction extends Construction::TStageInstruction {
|
||||
/**
|
||||
* Gets the function that contains this instruction.
|
||||
*/
|
||||
final Language::Declaration getEnclosingFunction() {
|
||||
final Language::Function getEnclosingFunction() {
|
||||
result = this.getEnclosingIRFunction().getFunction()
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user