mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
Merge branch 'main' into jty/python/emailInjection
This commit is contained in:
2
.bazelrc
2
.bazelrc
@@ -1,3 +1,3 @@
|
|||||||
build --copt="-std=c++17"
|
build --repo_env=CC=clang --repo_env=CXX=clang++ --copt="-std=c++17"
|
||||||
|
|
||||||
try-import %workspace%/local.bazelrc
|
try-import %workspace%/local.bazelrc
|
||||||
|
|||||||
@@ -1,27 +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",
|
|
||||||
"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,6 +3,8 @@
|
|||||||
"rust-lang.rust",
|
"rust-lang.rust",
|
||||||
"bungcip.better-toml",
|
"bungcip.better-toml",
|
||||||
"github.vscode-codeql",
|
"github.vscode-codeql",
|
||||||
|
"hbenl.vscode-test-explorer",
|
||||||
|
"ms-vscode.test-adapter-converter",
|
||||||
"slevesque.vscode-zipexplorer"
|
"slevesque.vscode-zipexplorer"
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
|
|||||||
9
.gitattributes
vendored
9
.gitattributes
vendored
@@ -39,6 +39,7 @@
|
|||||||
*.py text
|
*.py text
|
||||||
*.lua text
|
*.lua text
|
||||||
*.expected text
|
*.expected text
|
||||||
|
*.go text
|
||||||
|
|
||||||
# Explicitly set a bunch of known extensions to binary, because Git < 2.10 will treat
|
# Explicitly set a bunch of known extensions to binary, because Git < 2.10 will treat
|
||||||
# `* text=auto eol=lf` as `* text eol=lf`
|
# `* text=auto eol=lf` as `* text eol=lf`
|
||||||
@@ -52,6 +53,14 @@
|
|||||||
java/ql/test/stubs/**/*.java linguist-generated=true
|
java/ql/test/stubs/**/*.java linguist-generated=true
|
||||||
java/ql/test/experimental/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
|
# For some languages, upgrade script testing references really old dbscheme
|
||||||
# files from legacy upgrades that have CRLF line endings. Since upgrade
|
# files from legacy upgrades that have CRLF line endings. Since upgrade
|
||||||
# resolution relies on object hashes, we must suppress line ending conversion
|
# resolution relies on object hashes, we must suppress line ending conversion
|
||||||
|
|||||||
8
.github/dependabot.yml
vendored
8
.github/dependabot.yml
vendored
@@ -16,3 +16,11 @@ updates:
|
|||||||
directory: "ruby/autobuilder"
|
directory: "ruby/autobuilder"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
|
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
ignore:
|
||||||
|
- dependency-name: '*'
|
||||||
|
update-types: ['version-update:semver-patch', 'version-update:semver-minor']
|
||||||
|
|||||||
8
.github/labeler.yml
vendored
8
.github/labeler.yml
vendored
@@ -11,7 +11,7 @@ Java:
|
|||||||
- change-notes/**/*java.*
|
- change-notes/**/*java.*
|
||||||
|
|
||||||
JS:
|
JS:
|
||||||
- javascript/**/*
|
- any: [ 'javascript/**/*', '!javascript/ql/experimental/adaptivethreatmodeling/**/*' ]
|
||||||
- change-notes/**/*javascript*
|
- change-notes/**/*javascript*
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
@@ -21,6 +21,10 @@ Python:
|
|||||||
Ruby:
|
Ruby:
|
||||||
- ruby/**/*
|
- ruby/**/*
|
||||||
- change-notes/**/*ruby*
|
- change-notes/**/*ruby*
|
||||||
|
|
||||||
|
Swift:
|
||||||
|
- swift/**/*
|
||||||
|
- change-notes/**/*swift*
|
||||||
|
|
||||||
documentation:
|
documentation:
|
||||||
- "**/*.qhelp"
|
- "**/*.qhelp"
|
||||||
@@ -28,4 +32,4 @@ documentation:
|
|||||||
- docs/**/*
|
- docs/**/*
|
||||||
|
|
||||||
"QL-for-QL":
|
"QL-for-QL":
|
||||||
- ql/**/*
|
- ql/**/*
|
||||||
|
|||||||
14
.github/problem-matchers/codeql-query-format.json
vendored
Normal file
14
.github/problem-matchers/codeql-query-format.json
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"problemMatcher": [
|
||||||
|
{
|
||||||
|
"owner": "codeql-query-format",
|
||||||
|
"pattern": [
|
||||||
|
{
|
||||||
|
"regexp": "^((.*) would change by autoformatting\\.)$",
|
||||||
|
"file": 2,
|
||||||
|
"message": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
17
.github/problem-matchers/codeql-syntax-check.json
vendored
Normal file
17
.github/problem-matchers/codeql-syntax-check.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"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
Normal file
14
.github/problem-matchers/codeql-test-run.json
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"problemMatcher": [
|
||||||
|
{
|
||||||
|
"owner": "codeql-test-run",
|
||||||
|
"pattern": [
|
||||||
|
{
|
||||||
|
"regexp": "(\\[.*\\] FAILED\\((RESULT|COMPILATION)\\) (.*))$",
|
||||||
|
"file": 3,
|
||||||
|
"message": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
13
.github/problem-matchers/make.json
vendored
Normal file
13
.github/problem-matchers/make.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"problemMatcher": [
|
||||||
|
{
|
||||||
|
"owner": "make",
|
||||||
|
"pattern": [
|
||||||
|
{
|
||||||
|
"regexp": "^(make: \\*\\*\\* .*)$",
|
||||||
|
"message": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
5
.github/workflows/check-qldoc.yml
vendored
5
.github/workflows/check-qldoc.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
|
|
||||||
@@ -30,7 +30,8 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
EXIT_CODE=0
|
EXIT_CODE=0
|
||||||
changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -o '^[a-z]*/ql/lib' || true; } | sort -u)"
|
# TODO: remove the swift exception from the regex when we fix generated QLdoc
|
||||||
|
changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -Po '^(?!swift)[a-z]*/ql/lib' || true; } | sort -u)"
|
||||||
for pack_dir in ${changed_lib_packs}; do
|
for pack_dir in ${changed_lib_packs}; do
|
||||||
lang="${pack_dir%/ql/lib}"
|
lang="${pack_dir%/ql/lib}"
|
||||||
gh codeql generate library-doc-coverage --output="${RUNNER_TEMP}/${lang}-current.txt" --dir="${pack_dir}"
|
gh codeql generate library-doc-coverage --output="${RUNNER_TEMP}/${lang}-current.txt" --dir="${pack_dir}"
|
||||||
|
|||||||
2
.github/workflows/close-stale.yml
vendored
2
.github/workflows/close-stale.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v3
|
- uses: actions/stale@v5
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Comment or remove the `Stale` label in order to avoid having this issue closed in 7 days.'
|
stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Comment or remove the `Stale` label in order to avoid having this issue closed in 7 days.'
|
||||||
|
|||||||
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@@ -28,12 +28,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Setup dotnet
|
- name: Setup dotnet
|
||||||
uses: actions/setup-dotnet@v1
|
uses: actions/setup-dotnet@v2
|
||||||
with:
|
with:
|
||||||
dotnet-version: 6.0.101
|
dotnet-version: 6.0.202
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
# uses: github/codeql-action/autobuild@main
|
# uses: github/codeql-action/autobuild@main
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
|
|
||||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||||
# and modify them (or add more) to build your code if your project
|
# and modify them (or add more) to build your code if your project
|
||||||
|
|||||||
43
.github/workflows/csv-coverage-metrics.yml
vendored
43
.github/workflows/csv-coverage-metrics.yml
vendored
@@ -14,11 +14,11 @@ on:
|
|||||||
- ".github/workflows/csv-coverage-metrics.yml"
|
- ".github/workflows/csv-coverage-metrics.yml"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish:
|
publish-java:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Setup CodeQL
|
- name: Setup CodeQL
|
||||||
uses: ./.github/actions/fetch-codeql
|
uses: ./.github/actions/fetch-codeql
|
||||||
- name: Create empty database
|
- name: Create empty database
|
||||||
@@ -31,13 +31,40 @@ jobs:
|
|||||||
- name: Capture coverage information
|
- name: Capture coverage information
|
||||||
run: |
|
run: |
|
||||||
DATABASE="${{ runner.temp }}/java-database"
|
DATABASE="${{ runner.temp }}/java-database"
|
||||||
codeql database analyze --format=sarif-latest --output=metrics.sarif -- "$DATABASE" ./java/ql/src/Metrics/Summaries/FrameworkCoverage.ql
|
codeql database analyze --format=sarif-latest --output=metrics-java.sarif -- "$DATABASE" ./java/ql/src/Metrics/Summaries/FrameworkCoverage.ql
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: metrics.sarif
|
name: metrics-java.sarif
|
||||||
path: metrics.sarif
|
path: metrics-java.sarif
|
||||||
retention-days: 20
|
retention-days: 20
|
||||||
- name: Upload SARIF file
|
- name: Upload SARIF file
|
||||||
uses: github/codeql-action/upload-sarif@v1
|
uses: github/codeql-action/upload-sarif@main
|
||||||
with:
|
with:
|
||||||
sarif_file: metrics.sarif
|
sarif_file: metrics-java.sarif
|
||||||
|
|
||||||
|
publish-csharp:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Setup CodeQL
|
||||||
|
uses: ./.github/actions/fetch-codeql
|
||||||
|
- name: Create empty database
|
||||||
|
run: |
|
||||||
|
DATABASE="${{ runner.temp }}/csharp-database"
|
||||||
|
PROJECT="${{ runner.temp }}/csharp-project"
|
||||||
|
dotnet new classlib --language=C# --output="$PROJECT"
|
||||||
|
codeql database create "$DATABASE" --language=csharp --source-root="$PROJECT" --command 'dotnet build /t:rebuild csharp-project.csproj /p:UseSharedCompilation=false'
|
||||||
|
- name: Capture coverage information
|
||||||
|
run: |
|
||||||
|
DATABASE="${{ runner.temp }}/csharp-database"
|
||||||
|
codeql database analyze --format=sarif-latest --output=metrics-csharp.sarif -- "$DATABASE" ./csharp/ql/src/Metrics/Summaries/FrameworkCoverage.ql
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: metrics-csharp.sarif
|
||||||
|
path: metrics-csharp.sarif
|
||||||
|
retention-days: 20
|
||||||
|
- name: Upload SARIF file
|
||||||
|
uses: github/codeql-action/upload-sarif@main
|
||||||
|
with:
|
||||||
|
sarif_file: metrics-csharp.sarif
|
||||||
|
|||||||
14
.github/workflows/csv-coverage-pr-artifacts.yml
vendored
14
.github/workflows/csv-coverage-pr-artifacts.yml
vendored
@@ -28,11 +28,11 @@ jobs:
|
|||||||
GITHUB_CONTEXT: ${{ toJSON(github.event) }}
|
GITHUB_CONTEXT: ${{ toJSON(github.event) }}
|
||||||
run: echo "$GITHUB_CONTEXT"
|
run: echo "$GITHUB_CONTEXT"
|
||||||
- name: Clone self (github/codeql) - MERGE
|
- name: Clone self (github/codeql) - MERGE
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: merge
|
path: merge
|
||||||
- name: Clone self (github/codeql) - BASE
|
- name: Clone self (github/codeql) - BASE
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
path: base
|
path: base
|
||||||
@@ -41,7 +41,7 @@ jobs:
|
|||||||
git log -1 --format='%H'
|
git log -1 --format='%H'
|
||||||
working-directory: base
|
working-directory: base
|
||||||
- name: Set up Python 3.8
|
- name: Set up Python 3.8
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
- name: Download CodeQL CLI
|
- name: Download CodeQL CLI
|
||||||
@@ -69,21 +69,21 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python base/misc/scripts/library-coverage/compare-folders.py out_base out_merge comparison.md
|
python base/misc/scripts/library-coverage/compare-folders.py out_base out_merge comparison.md
|
||||||
- name: Upload CSV package list
|
- name: Upload CSV package list
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: csv-framework-coverage-merge
|
name: csv-framework-coverage-merge
|
||||||
path: |
|
path: |
|
||||||
out_merge/framework-coverage-*.csv
|
out_merge/framework-coverage-*.csv
|
||||||
out_merge/framework-coverage-*.rst
|
out_merge/framework-coverage-*.rst
|
||||||
- name: Upload CSV package list
|
- name: Upload CSV package list
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: csv-framework-coverage-base
|
name: csv-framework-coverage-base
|
||||||
path: |
|
path: |
|
||||||
out_base/framework-coverage-*.csv
|
out_base/framework-coverage-*.csv
|
||||||
out_base/framework-coverage-*.rst
|
out_base/framework-coverage-*.rst
|
||||||
- name: Upload comparison results
|
- name: Upload comparison results
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: comparison
|
name: comparison
|
||||||
path: |
|
path: |
|
||||||
@@ -93,7 +93,7 @@ jobs:
|
|||||||
mkdir -p pr
|
mkdir -p pr
|
||||||
echo ${{ github.event.pull_request.number }} > pr/NR
|
echo ${{ github.event.pull_request.number }} > pr/NR
|
||||||
- name: Upload PR number
|
- name: Upload PR number
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: pr
|
name: pr
|
||||||
path: pr/
|
path: pr/
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ jobs:
|
|||||||
GITHUB_CONTEXT: ${{ toJSON(github.event) }}
|
GITHUB_CONTEXT: ${{ toJSON(github.event) }}
|
||||||
run: echo "$GITHUB_CONTEXT"
|
run: echo "$GITHUB_CONTEXT"
|
||||||
- name: Clone self (github/codeql)
|
- name: Clone self (github/codeql)
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Set up Python 3.8
|
- name: Set up Python 3.8
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
|
|
||||||
|
|||||||
@@ -10,16 +10,16 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone self (github/codeql)
|
- name: Clone self (github/codeql)
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: script
|
path: script
|
||||||
- name: Clone self (github/codeql) for analysis
|
- name: Clone self (github/codeql) for analysis
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: codeqlModels
|
path: codeqlModels
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Set up Python 3.8
|
- name: Set up Python 3.8
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
- name: Download CodeQL CLI
|
- name: Download CodeQL CLI
|
||||||
@@ -35,7 +35,7 @@ jobs:
|
|||||||
echo $CLI
|
echo $CLI
|
||||||
PATH="$PATH:$CLI" python script/misc/scripts/library-coverage/generate-timeseries.py codeqlModels
|
PATH="$PATH:$CLI" python script/misc/scripts/library-coverage/generate-timeseries.py codeqlModels
|
||||||
- name: Upload timeseries CSV
|
- name: Upload timeseries CSV
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: framework-coverage-timeseries
|
name: framework-coverage-timeseries
|
||||||
path: framework-coverage-timeseries-*.csv
|
path: framework-coverage-timeseries-*.csv
|
||||||
|
|||||||
4
.github/workflows/csv-coverage-update.yml
vendored
4
.github/workflows/csv-coverage-update.yml
vendored
@@ -17,12 +17,12 @@ jobs:
|
|||||||
GITHUB_CONTEXT: ${{ toJSON(github.event) }}
|
GITHUB_CONTEXT: ${{ toJSON(github.event) }}
|
||||||
run: echo "$GITHUB_CONTEXT"
|
run: echo "$GITHUB_CONTEXT"
|
||||||
- name: Clone self (github/codeql)
|
- name: Clone self (github/codeql)
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: ql
|
path: ql
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Set up Python 3.8
|
- name: Set up Python 3.8
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
- name: Download CodeQL CLI
|
- name: Download CodeQL CLI
|
||||||
|
|||||||
10
.github/workflows/csv-coverage.yml
vendored
10
.github/workflows/csv-coverage.yml
vendored
@@ -14,16 +14,16 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone self (github/codeql)
|
- name: Clone self (github/codeql)
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: script
|
path: script
|
||||||
- name: Clone self (github/codeql) for analysis
|
- name: Clone self (github/codeql) for analysis
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: codeqlModels
|
path: codeqlModels
|
||||||
ref: ${{ github.event.inputs.qlModelShaOverride || github.ref }}
|
ref: ${{ github.event.inputs.qlModelShaOverride || github.ref }}
|
||||||
- name: Set up Python 3.8
|
- name: Set up Python 3.8
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
- name: Download CodeQL CLI
|
- name: Download CodeQL CLI
|
||||||
@@ -37,12 +37,12 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
PATH="$PATH:codeql-cli/codeql" python script/misc/scripts/library-coverage/generate-report.py ci codeqlModels script
|
PATH="$PATH:codeql-cli/codeql" python script/misc/scripts/library-coverage/generate-report.py ci codeqlModels script
|
||||||
- name: Upload CSV package list
|
- name: Upload CSV package list
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: framework-coverage-csv
|
name: framework-coverage-csv
|
||||||
path: framework-coverage-*.csv
|
path: framework-coverage-*.csv
|
||||||
- name: Upload RST package list
|
- name: Upload RST package list
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: framework-coverage-rst
|
name: framework-coverage-rst
|
||||||
path: framework-coverage-*.rst
|
path: framework-coverage-*.rst
|
||||||
|
|||||||
161
.github/workflows/go-tests.yml
vendored
Normal file
161
.github/workflows/go-tests.yml
vendored
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
name: "Go: Run Tests"
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "go/**"
|
||||||
|
- .github/workflows/go-tests.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
|
||||||
7
.github/workflows/js-ml-tests.yml
vendored
7
.github/workflows/js-ml-tests.yml
vendored
@@ -12,6 +12,7 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- "javascript/ql/experimental/adaptivethreatmodeling/**"
|
- "javascript/ql/experimental/adaptivethreatmodeling/**"
|
||||||
- .github/workflows/js-ml-tests.yml
|
- .github/workflows/js-ml-tests.yml
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
@@ -22,7 +23,7 @@ jobs:
|
|||||||
name: Check QL formatting
|
name: Check QL formatting
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ jobs:
|
|||||||
name: Check QL compilation
|
name: Check QL compilation
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ jobs:
|
|||||||
name: Run QL tests
|
name: Run QL tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/labeler.yml
vendored
2
.github/workflows/labeler.yml
vendored
@@ -6,6 +6,6 @@ jobs:
|
|||||||
triage:
|
triage:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/labeler@v2
|
- uses: actions/labeler@v4
|
||||||
with:
|
with:
|
||||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
|
|||||||
8
.github/workflows/mad_modelDiff.yml
vendored
8
.github/workflows/mad_modelDiff.yml
vendored
@@ -27,12 +27,12 @@ jobs:
|
|||||||
slug: ${{fromJson(github.event.inputs.projects || '["apache/commons-codec", "apache/commons-io", "apache/commons-beanutils", "apache/commons-logging", "apache/commons-fileupload", "apache/commons-lang", "apache/commons-validator", "apache/commons-csv", "apache/dubbo"]' )}}
|
slug: ${{fromJson(github.event.inputs.projects || '["apache/commons-codec", "apache/commons-io", "apache/commons-beanutils", "apache/commons-logging", "apache/commons-fileupload", "apache/commons-lang", "apache/commons-validator", "apache/commons-csv", "apache/dubbo"]' )}}
|
||||||
steps:
|
steps:
|
||||||
- name: Clone github/codeql from PR
|
- name: Clone github/codeql from PR
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
if: github.event.pull_request
|
if: github.event.pull_request
|
||||||
with:
|
with:
|
||||||
path: codeql-pr
|
path: codeql-pr
|
||||||
- name: Clone github/codeql from main
|
- name: Clone github/codeql from main
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: codeql-main
|
path: codeql-main
|
||||||
ref: main
|
ref: main
|
||||||
@@ -91,12 +91,12 @@ jobs:
|
|||||||
name="diff_${basename/_main.qll/""}"
|
name="diff_${basename/_main.qll/""}"
|
||||||
(diff -w -u $m $t | diff2html -i stdin -F $MODELS/$name.html) || true
|
(diff -w -u $m $t | diff2html -i stdin -F $MODELS/$name.html) || true
|
||||||
done
|
done
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: models
|
name: models
|
||||||
path: tmp-models/*.qll
|
path: tmp-models/*.qll
|
||||||
retention-days: 20
|
retention-days: 20
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: diffs
|
name: diffs
|
||||||
path: tmp-models/*.html
|
path: tmp-models/*.html
|
||||||
|
|||||||
6
.github/workflows/mad_regenerate-models.yml
vendored
6
.github/workflows/mad_regenerate-models.yml
vendored
@@ -26,11 +26,11 @@ jobs:
|
|||||||
ref: "placeholder"
|
ref: "placeholder"
|
||||||
steps:
|
steps:
|
||||||
- name: Clone self (github/codeql)
|
- name: Clone self (github/codeql)
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Setup CodeQL binaries
|
- name: Setup CodeQL binaries
|
||||||
uses: ./.github/actions/fetch-codeql
|
uses: ./.github/actions/fetch-codeql
|
||||||
- name: Clone repositories
|
- name: Clone repositories
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: repos/${{ matrix.ref }}
|
path: repos/${{ matrix.ref }}
|
||||||
ref: ${{ matrix.ref }}
|
ref: ${{ matrix.ref }}
|
||||||
@@ -55,7 +55,7 @@ jobs:
|
|||||||
find java -name "*.qll" -print0 | xargs -0 git add
|
find java -name "*.qll" -print0 | xargs -0 git add
|
||||||
git status
|
git status
|
||||||
git diff --cached > models.patch
|
git diff --cached > models.patch
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: patch
|
name: patch
|
||||||
path: models.patch
|
path: models.patch
|
||||||
|
|||||||
53
.github/workflows/post-pr-comment.yml
vendored
53
.github/workflows/post-pr-comment.yml
vendored
@@ -1,12 +1,17 @@
|
|||||||
name: Post pull-request comment
|
# This workflow is the second part of the process described in
|
||||||
|
# .github/workflows/qhelp-pr-preview.yml
|
||||||
|
# See that file for more info.
|
||||||
|
|
||||||
|
name: Post PR comment
|
||||||
on:
|
on:
|
||||||
workflow_run:
|
workflow_run:
|
||||||
workflows: ["Query help preview"]
|
workflows: [Render QHelp changes]
|
||||||
types:
|
types:
|
||||||
- completed
|
- completed
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
actions: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
post_comment:
|
post_comment:
|
||||||
@@ -17,15 +22,53 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
|
WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
|
||||||
- run: |
|
|
||||||
PR="$(grep -o '^[0-9]\+$' pr.txt)"
|
- name: Check that PR SHA matches workflow SHA
|
||||||
|
run: |
|
||||||
|
PR="$(grep -o '^[0-9]\+$' pr_number.txt)"
|
||||||
PR_HEAD_SHA="$(gh api "/repos/${GITHUB_REPOSITORY}/pulls/${PR}" --jq .head.sha)"
|
PR_HEAD_SHA="$(gh api "/repos/${GITHUB_REPOSITORY}/pulls/${PR}" --jq .head.sha)"
|
||||||
# Check that the pull-request head SHA matches the head SHA of the workflow run
|
# Check that the pull-request head SHA matches the head SHA of the workflow run
|
||||||
if [ "${WORKFLOW_RUN_HEAD_SHA}" != "${PR_HEAD_SHA}" ]; then
|
if [ "${WORKFLOW_RUN_HEAD_SHA}" != "${PR_HEAD_SHA}" ]; then
|
||||||
echo "PR head SHA ${PR_HEAD_SHA} does not match workflow_run event SHA ${WORKFLOW_RUN_HEAD_SHA}. Stopping." 1>&2
|
echo "PR head SHA ${PR_HEAD_SHA} does not match workflow_run event SHA ${WORKFLOW_RUN_HEAD_SHA}. Stopping." 1>&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
gh pr comment "${PR}" --repo "${GITHUB_REPOSITORY}" -F comment.txt
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
WORKFLOW_RUN_HEAD_SHA: ${{ github.event.workflow_run.head_commit.id }}
|
WORKFLOW_RUN_HEAD_SHA: ${{ github.event.workflow_run.head_commit.id }}
|
||||||
|
|
||||||
|
- name: Create or update comment
|
||||||
|
run: |
|
||||||
|
COMMENT_PREFIX="QHelp previews"
|
||||||
|
COMMENT_AUTHOR="github-actions[bot]"
|
||||||
|
PR_NUMBER="$(grep -o '^[0-9]\+$' pr_number.txt)"
|
||||||
|
|
||||||
|
# If there is no existing comment, comment_id.txt will contain just a
|
||||||
|
# newline (due to jq & gh behaviour). This will cause grep to fail, so
|
||||||
|
# we catch that.
|
||||||
|
RAW_COMMENT_ID=$(grep -o '^[0-9]\+$' comment_id.txt || true)
|
||||||
|
|
||||||
|
if [ $RAW_COMMENT_ID ]
|
||||||
|
then
|
||||||
|
# Fetch existing comment, and validate:
|
||||||
|
# - comment belongs to the PR with number $PR_NUMBER
|
||||||
|
# - comment starts with the expected prefix ("QHelp previews")
|
||||||
|
# - comment author is github-actions[bot]
|
||||||
|
FILTER='select(.issue_url | endswith($repo+"/issues/"+$pr))
|
||||||
|
| select(.body | startswith($prefix))
|
||||||
|
| select(.user.login == $author)
|
||||||
|
| .id'
|
||||||
|
COMMENT_ID=$(gh api "repos/${GITHUB_REPOSITORY}/issues/comments/${RAW_COMMENT_ID}" | jq --arg repo "${GITHUB_REPOSITORY}" --arg pr "${PR_NUMBER}" --arg prefix "${COMMENT_PREFIX}" --arg author "${COMMENT_AUTHOR}" "${FILTER}")
|
||||||
|
if [ $COMMENT_ID ]
|
||||||
|
then
|
||||||
|
# Update existing comment
|
||||||
|
jq --rawfile body comment_body.txt '{"body":$body}' -n | gh api "repos/${GITHUB_REPOSITORY}/issues/comments/${COMMENT_ID}" -X PATCH --input -
|
||||||
|
else
|
||||||
|
echo "Comment ${RAW_COMMENT_ID} did not pass validations: not editing." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Create new comment
|
||||||
|
jq --rawfile body comment_body.txt '{"body":$body}' -n | gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" -X POST --input -
|
||||||
|
fi
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
|||||||
57
.github/workflows/qhelp-pr-preview.yml
vendored
57
.github/workflows/qhelp-pr-preview.yml
vendored
@@ -1,7 +1,25 @@
|
|||||||
name: Query help preview
|
# This workflow checks for any changes in .qhelp files in pull requests.
|
||||||
|
# For any changed files, it renders them to markdown in a file called `comment_body.txt`.
|
||||||
|
# It then checks if there's an existing comment on the pull request generated by
|
||||||
|
# this workflow, and writes the comment ID to `comment_id.txt`.
|
||||||
|
# It also writes the PR number to `pr_number.txt`.
|
||||||
|
# These three files are uploaded as an artifact.
|
||||||
|
|
||||||
|
# When this workflow completes, the workflow "Post PR comment" runs.
|
||||||
|
# It downloads the artifact and adds a comment to the PR with the rendered
|
||||||
|
# QHelp.
|
||||||
|
|
||||||
|
# The task is split like this because creating PR comments requires extra
|
||||||
|
# permissions that we don't want to expose to PRs from external forks.
|
||||||
|
|
||||||
|
# For more info see:
|
||||||
|
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run
|
||||||
|
# https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token
|
||||||
|
name: Render QHelp changes
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
pull-requests: read
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -15,13 +33,17 @@ jobs:
|
|||||||
qhelp:
|
qhelp:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- run: echo "${{ github.event.number }}" > pr.txt
|
- run: echo "${PR_NUMBER}" > pr_number.txt
|
||||||
- uses: actions/upload-artifact@v2
|
env:
|
||||||
|
PR_NUMBER: ${{ github.event.number }}
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: comment
|
name: comment
|
||||||
path: pr.txt
|
path: pr_number.txt
|
||||||
|
if-no-files-found: error
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
@@ -36,7 +58,7 @@ jobs:
|
|||||||
- name: QHelp preview
|
- name: QHelp preview
|
||||||
run: |
|
run: |
|
||||||
EXIT_CODE=0
|
EXIT_CODE=0
|
||||||
echo "QHelp previews:" > comment.txt
|
echo "QHelp previews:" > comment_body.txt
|
||||||
while read -r -d $'\0' path; do
|
while read -r -d $'\0' path; do
|
||||||
if [ ! -f "${path}" ]; then
|
if [ ! -f "${path}" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
@@ -52,12 +74,29 @@ jobs:
|
|||||||
echo '```'
|
echo '```'
|
||||||
fi
|
fi
|
||||||
echo "</details>"
|
echo "</details>"
|
||||||
done < "${RUNNER_TEMP}/paths.txt" >> comment.txt
|
done < "${RUNNER_TEMP}/paths.txt" >> comment_body.txt
|
||||||
exit "${EXIT_CODE}"
|
exit "${EXIT_CODE}"
|
||||||
|
|
||||||
- if: always()
|
- if: always()
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: comment
|
name: comment
|
||||||
path: comment.txt
|
path: comment_body.txt
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
- name: Save ID of existing QHelp comment (if it exists)
|
||||||
|
run: |
|
||||||
|
# Find the latest comment starting with "QHelp previews"
|
||||||
|
COMMENT_PREFIX="QHelp previews"
|
||||||
|
gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" --paginate | jq --arg prefix "${COMMENT_PREFIX}" '[.[] | select(.body|startswith($prefix)) | .id] | max' > comment_id.txt
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
PR_NUMBER: ${{ github.event.number }}
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: comment
|
||||||
|
path: comment_id.txt
|
||||||
|
if-no-files-found: error
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|||||||
30
.github/workflows/ql-for-ql-build.yml
vendored
30
.github/workflows/ql-for-ql-build.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
queries:
|
queries:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Find codeql
|
- name: Find codeql
|
||||||
id: find-codeql
|
id: find-codeql
|
||||||
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
- name: Cache queries
|
- name: Cache queries
|
||||||
id: cache-queries
|
id: cache-queries
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ${{ runner.temp }}/query-pack.zip
|
path: ${{ runner.temp }}/query-pack.zip
|
||||||
key: queries-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}
|
key: queries-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}
|
||||||
@@ -44,7 +44,7 @@ jobs:
|
|||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
PACKZIP: ${{ runner.temp }}/query-pack.zip
|
PACKZIP: ${{ runner.temp }}/query-pack.zip
|
||||||
- name: Upload query pack
|
- name: Upload query pack
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: query-pack-zip
|
name: query-pack-zip
|
||||||
path: ${{ runner.temp }}/query-pack.zip
|
path: ${{ runner.temp }}/query-pack.zip
|
||||||
@@ -56,10 +56,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Cache entire extractor
|
- name: Cache entire extractor
|
||||||
id: cache-extractor
|
id: cache-extractor
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
ql/target/release/ql-autobuilder
|
ql/target/release/ql-autobuilder
|
||||||
@@ -69,7 +69,7 @@ jobs:
|
|||||||
key: ${{ runner.os }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
|
key: ${{ runner.os }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
|
||||||
- name: Cache cargo
|
- name: Cache cargo
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cargo/registry
|
~/.cargo/registry
|
||||||
@@ -91,7 +91,7 @@ jobs:
|
|||||||
- name: Generate dbscheme
|
- name: Generate dbscheme
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||||
run: ql/target/release/ql-generator --dbscheme ql/ql/src/ql.dbscheme --library ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll
|
run: ql/target/release/ql-generator --dbscheme ql/ql/src/ql.dbscheme --library ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: extractor-ubuntu-latest
|
name: extractor-ubuntu-latest
|
||||||
path: |
|
path: |
|
||||||
@@ -108,12 +108,12 @@ jobs:
|
|||||||
- queries
|
- queries
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: query-pack-zip
|
name: query-pack-zip
|
||||||
path: query-pack-zip
|
path: query-pack-zip
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: extractor-ubuntu-latest
|
name: extractor-ubuntu-latest
|
||||||
path: linux64
|
path: linux64
|
||||||
@@ -131,7 +131,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
cd pack
|
cd pack
|
||||||
zip -rq ../codeql-ql.zip .
|
zip -rq ../codeql-ql.zip .
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: codeql-ql-pack
|
name: codeql-ql-pack
|
||||||
path: codeql-ql.zip
|
path: codeql-ql.zip
|
||||||
@@ -140,14 +140,14 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
folder: [cpp, csharp, java, javascript, python, ql, ruby]
|
folder: [cpp, csharp, java, javascript, python, ql, ruby, swift, go]
|
||||||
|
|
||||||
needs:
|
needs:
|
||||||
- package
|
- package
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Download pack
|
- name: Download pack
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: codeql-ql-pack
|
name: codeql-ql-pack
|
||||||
path: ${{ runner.temp }}/codeql-ql-pack-artifact
|
path: ${{ runner.temp }}/codeql-ql-pack-artifact
|
||||||
@@ -166,7 +166,7 @@ jobs:
|
|||||||
PACK: ${{ runner.temp }}/pack
|
PACK: ${{ runner.temp }}/pack
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Create CodeQL config file
|
- name: Create CodeQL config file
|
||||||
run: |
|
run: |
|
||||||
echo "paths:" > ${CONF}
|
echo "paths:" > ${CONF}
|
||||||
@@ -196,7 +196,7 @@ jobs:
|
|||||||
- name: Copy sarif file to CWD
|
- name: Copy sarif file to CWD
|
||||||
run: cp ../results/ql.sarif ./${{ matrix.folder }}.sarif
|
run: cp ../results/ql.sarif ./${{ matrix.folder }}.sarif
|
||||||
- name: Sarif as artifact
|
- name: Sarif as artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.folder }}.sarif
|
name: ${{ matrix.folder }}.sarif
|
||||||
path: ${{ matrix.folder }}.sarif
|
path: ${{ matrix.folder }}.sarif
|
||||||
|
|||||||
17
.github/workflows/ql-for-ql-dataset_measure.yml
vendored
17
.github/workflows/ql-for-ql-dataset_measure.yml
vendored
@@ -19,17 +19,16 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
repo:
|
repo:
|
||||||
- github/codeql
|
- github/codeql
|
||||||
- github/codeql-go
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Find codeql
|
- name: Find codeql
|
||||||
id: find-codeql
|
id: find-codeql
|
||||||
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
||||||
with:
|
with:
|
||||||
languages: javascript # does not matter
|
languages: javascript # does not matter
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cargo/registry
|
~/.cargo/registry
|
||||||
@@ -41,7 +40,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
- name: Checkout ${{ matrix.repo }}
|
- name: Checkout ${{ matrix.repo }}
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: ${{ matrix.repo }}
|
repository: ${{ matrix.repo }}
|
||||||
path: ${{ github.workspace }}/repo
|
path: ${{ github.workspace }}/repo
|
||||||
@@ -60,7 +59,7 @@ jobs:
|
|||||||
"${CODEQL}" dataset measure --threads 4 --output "stats/${{ matrix.repo }}/stats.xml" "${{ runner.temp }}/database/db-ql"
|
"${CODEQL}" dataset measure --threads 4 --output "stats/${{ matrix.repo }}/stats.xml" "${{ runner.temp }}/database/db-ql"
|
||||||
env:
|
env:
|
||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: measurements
|
name: measurements
|
||||||
path: stats
|
path: stats
|
||||||
@@ -70,15 +69,15 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: measure
|
needs: measure
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: measurements
|
name: measurements
|
||||||
path: stats
|
path: stats
|
||||||
- run: |
|
- run: |
|
||||||
python -m pip install --user lxml
|
python -m pip install --user lxml
|
||||||
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
|
find stats -name 'stats.xml' -print0 | sort -z | xargs -0 python ruby/scripts/merge_stats.py --output ql/ql/src/ql.dbscheme.stats --normalise ql_tokeninfo
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ql.dbscheme.stats
|
name: ql.dbscheme.stats
|
||||||
path: ql/ql/src/ql.dbscheme.stats
|
path: ql/ql/src/ql.dbscheme.stats
|
||||||
|
|||||||
4
.github/workflows/ql-for-ql-tests.yml
vendored
4
.github/workflows/ql-for-ql-tests.yml
vendored
@@ -17,13 +17,13 @@ jobs:
|
|||||||
qltest:
|
qltest:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Find codeql
|
- name: Find codeql
|
||||||
id: find-codeql
|
id: find-codeql
|
||||||
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
||||||
with:
|
with:
|
||||||
languages: javascript # does not matter
|
languages: javascript # does not matter
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cargo/registry
|
~/.cargo/registry
|
||||||
|
|||||||
22
.github/workflows/query-list.yml
vendored
22
.github/workflows/query-list.yml
vendored
@@ -17,33 +17,23 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone self (github/codeql)
|
- name: Clone self (github/codeql)
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: codeql
|
path: codeql
|
||||||
- name: Clone github/codeql-go
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
repository: 'github/codeql-go'
|
|
||||||
path: codeql-go
|
|
||||||
- name: Set up Python 3.8
|
- name: Set up Python 3.8
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
- name: Download CodeQL CLI
|
- name: Download CodeQL CLI
|
||||||
uses: dsaltares/fetch-gh-release-asset@aa37ae5c44d3c9820bc12fe675e8670ecd93bd1c
|
# Look under the `codeql` directory, as this is where we checked out the `github/codeql` repo
|
||||||
with:
|
uses: ./codeql/.github/actions/fetch-codeql
|
||||||
repo: "github/codeql-cli-binaries"
|
|
||||||
version: "latest"
|
|
||||||
file: "codeql-linux64.zip"
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Unzip CodeQL CLI
|
- name: Unzip CodeQL CLI
|
||||||
run: unzip -d codeql-cli codeql-linux64.zip
|
run: unzip -d codeql-cli codeql-linux64.zip
|
||||||
- name: Build code scanning query list
|
- name: Build code scanning query list
|
||||||
run: |
|
run: |
|
||||||
PATH="$PATH:codeql-cli/codeql" python codeql/misc/scripts/generate-code-scanning-query-list.py > code-scanning-query-list.csv
|
python codeql/misc/scripts/generate-code-scanning-query-list.py > code-scanning-query-list.csv
|
||||||
- name: Upload code scanning query list
|
- name: Upload code scanning query list
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: code-scanning-query-list
|
name: code-scanning-query-list
|
||||||
path: code-scanning-query-list.csv
|
path: code-scanning-query-list.csv
|
||||||
|
|
||||||
|
|||||||
34
.github/workflows/ruby-build.yml
vendored
34
.github/workflows/ruby-build.yml
vendored
@@ -38,13 +38,13 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Install GNU tar
|
- name: Install GNU tar
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
run: |
|
run: |
|
||||||
brew install gnu-tar
|
brew install gnu-tar
|
||||||
echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH
|
echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cargo/registry
|
~/.cargo/registry
|
||||||
@@ -62,17 +62,17 @@ jobs:
|
|||||||
- name: Generate dbscheme
|
- name: Generate dbscheme
|
||||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||||
run: target/release/ruby-generator --dbscheme ql/lib/ruby.dbscheme --library ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
run: target/release/ruby-generator --dbscheme ql/lib/ruby.dbscheme --library ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||||
with:
|
with:
|
||||||
name: ruby.dbscheme
|
name: ruby.dbscheme
|
||||||
path: ruby/ql/lib/ruby.dbscheme
|
path: ruby/ql/lib/ruby.dbscheme
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||||
with:
|
with:
|
||||||
name: TreeSitter.qll
|
name: TreeSitter.qll
|
||||||
path: ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
path: ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: extractor-${{ matrix.os }}
|
name: extractor-${{ matrix.os }}
|
||||||
path: |
|
path: |
|
||||||
@@ -86,7 +86,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
|
CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Fetch CodeQL
|
- name: Fetch CodeQL
|
||||||
run: |
|
run: |
|
||||||
LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | grep -v beta | sort --version-sort | tail -1)
|
LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | grep -v beta | sort --version-sort | tail -1)
|
||||||
@@ -102,7 +102,7 @@ jobs:
|
|||||||
PACK_FOLDER=$(readlink -f target/packs/codeql/ruby-queries/*)
|
PACK_FOLDER=$(readlink -f target/packs/codeql/ruby-queries/*)
|
||||||
codeql/codeql generate query-help --format=sarifv2.1.0 --output="${PACK_FOLDER}/rules.sarif" ql/src
|
codeql/codeql generate query-help --format=sarifv2.1.0 --output="${PACK_FOLDER}/rules.sarif" ql/src
|
||||||
(cd ql/src; find queries \( -name '*.qhelp' -o -name '*.rb' -o -name '*.erb' \) -exec bash -c 'mkdir -p "'"${PACK_FOLDER}"'/$(dirname "{}")"' \; -exec cp "{}" "${PACK_FOLDER}/{}" \;)
|
(cd ql/src; find queries \( -name '*.qhelp' -o -name '*.rb' -o -name '*.erb' \) -exec bash -c 'mkdir -p "'"${PACK_FOLDER}"'/$(dirname "{}")"' \; -exec cp "{}" "${PACK_FOLDER}/{}" \;)
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: codeql-ruby-queries
|
name: codeql-ruby-queries
|
||||||
path: |
|
path: |
|
||||||
@@ -113,20 +113,20 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [build, compile-queries]
|
needs: [build, compile-queries]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ruby.dbscheme
|
name: ruby.dbscheme
|
||||||
path: ruby/ruby
|
path: ruby/ruby
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: extractor-ubuntu-latest
|
name: extractor-ubuntu-latest
|
||||||
path: ruby/linux64
|
path: ruby/linux64
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: extractor-windows-latest
|
name: extractor-windows-latest
|
||||||
path: ruby/win64
|
path: ruby/win64
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: extractor-macos-latest
|
name: extractor-macos-latest
|
||||||
path: ruby/osx64
|
path: ruby/osx64
|
||||||
@@ -142,12 +142,12 @@ jobs:
|
|||||||
cp win64/ruby-extractor.exe ruby/tools/win64/extractor.exe
|
cp win64/ruby-extractor.exe ruby/tools/win64/extractor.exe
|
||||||
chmod +x ruby/tools/{linux64,osx64}/{autobuilder,extractor}
|
chmod +x ruby/tools/{linux64,osx64}/{autobuilder,extractor}
|
||||||
zip -rq codeql-ruby.zip ruby
|
zip -rq codeql-ruby.zip ruby
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: codeql-ruby-pack
|
name: codeql-ruby-pack
|
||||||
path: ruby/codeql-ruby.zip
|
path: ruby/codeql-ruby.zip
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: codeql-ruby-queries
|
name: codeql-ruby-queries
|
||||||
path: ruby/qlpacks
|
path: ruby/qlpacks
|
||||||
@@ -159,7 +159,7 @@ jobs:
|
|||||||
]
|
]
|
||||||
}' > .codeqlmanifest.json
|
}' > .codeqlmanifest.json
|
||||||
zip -rq codeql-ruby-bundle.zip .codeqlmanifest.json ruby qlpacks
|
zip -rq codeql-ruby-bundle.zip .codeqlmanifest.json ruby qlpacks
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: codeql-ruby-bundle
|
name: codeql-ruby-bundle
|
||||||
path: ruby/codeql-ruby-bundle.zip
|
path: ruby/codeql-ruby-bundle.zip
|
||||||
@@ -177,7 +177,7 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
needs: [package]
|
needs: [package]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: Shopify/example-ruby-app
|
repository: Shopify/example-ruby-app
|
||||||
ref: 67a0decc5eb550f3a9228eda53925c3afd40dfe9
|
ref: 67a0decc5eb550f3a9228eda53925c3afd40dfe9
|
||||||
@@ -191,7 +191,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ github.token }}
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
working-directory: ${{ runner.temp }}
|
working-directory: ${{ runner.temp }}
|
||||||
- name: Download Ruby bundle
|
- name: Download Ruby bundle
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: codeql-ruby-bundle
|
name: codeql-ruby-bundle
|
||||||
path: ${{ runner.temp }}
|
path: ${{ runner.temp }}
|
||||||
|
|||||||
12
.github/workflows/ruby-dataset-measure.yml
vendored
12
.github/workflows/ruby-dataset-measure.yml
vendored
@@ -27,14 +27,14 @@ jobs:
|
|||||||
repo: [rails/rails, discourse/discourse, spree/spree, ruby/ruby]
|
repo: [rails/rails, discourse/discourse, spree/spree, ruby/ruby]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
|
|
||||||
- uses: ./ruby/actions/create-extractor-pack
|
- uses: ./ruby/actions/create-extractor-pack
|
||||||
|
|
||||||
- name: Checkout ${{ matrix.repo }}
|
- name: Checkout ${{ matrix.repo }}
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: ${{ matrix.repo }}
|
repository: ${{ matrix.repo }}
|
||||||
path: ${{ github.workspace }}/repo
|
path: ${{ github.workspace }}/repo
|
||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir -p "stats/${{ matrix.repo }}"
|
mkdir -p "stats/${{ matrix.repo }}"
|
||||||
codeql dataset measure --threads 4 --output "stats/${{ matrix.repo }}/stats.xml" "${{ runner.temp }}/database/db-ruby"
|
codeql dataset measure --threads 4 --output "stats/${{ matrix.repo }}/stats.xml" "${{ runner.temp }}/database/db-ruby"
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: measurements
|
name: measurements
|
||||||
path: stats
|
path: stats
|
||||||
@@ -59,15 +59,15 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: measure
|
needs: measure
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: measurements
|
name: measurements
|
||||||
path: stats
|
path: stats
|
||||||
- run: |
|
- run: |
|
||||||
python -m pip install --user lxml
|
python -m pip install --user lxml
|
||||||
find stats -name 'stats.xml' | sort | xargs python ruby/scripts/merge_stats.py --output ruby/ql/lib/ruby.dbscheme.stats --normalise ruby_tokeninfo
|
find stats -name 'stats.xml' | sort | xargs python ruby/scripts/merge_stats.py --output ruby/ql/lib/ruby.dbscheme.stats --normalise ruby_tokeninfo
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ruby.dbscheme.stats
|
name: ruby.dbscheme.stats
|
||||||
path: ruby/ql/lib/ruby.dbscheme.stats
|
path: ruby/ql/lib/ruby.dbscheme.stats
|
||||||
|
|||||||
8
.github/workflows/ruby-qltest.yml
vendored
8
.github/workflows/ruby-qltest.yml
vendored
@@ -27,14 +27,14 @@ jobs:
|
|||||||
qlformat:
|
qlformat:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
- name: Check QL formatting
|
- name: Check QL formatting
|
||||||
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
|
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
|
||||||
qlcompile:
|
qlcompile:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
- name: Check QL compilation
|
- name: Check QL compilation
|
||||||
run: |
|
run: |
|
||||||
@@ -44,7 +44,7 @@ jobs:
|
|||||||
qlupgrade:
|
qlupgrade:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
- name: Check DB upgrade scripts
|
- name: Check DB upgrade scripts
|
||||||
run: |
|
run: |
|
||||||
@@ -67,7 +67,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
slice: ["1/2", "2/2"]
|
slice: ["1/2", "2/2"]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
- uses: ./ruby/actions/create-extractor-pack
|
- uses: ./ruby/actions/create-extractor-pack
|
||||||
- name: Run QL tests
|
- name: Run QL tests
|
||||||
|
|||||||
32
.github/workflows/swift-codegen.yml
vendored
Normal file
32
.github/workflows/swift-codegen.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: "Swift: Check code generation"
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "swift/**"
|
||||||
|
- .github/workflows/swift-codegen.yml
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
codegen:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: ./.github/actions/fetch-codeql
|
||||||
|
- uses: bazelbuild/setup-bazelisk@v2
|
||||||
|
- name: Run unit tests
|
||||||
|
run: |
|
||||||
|
bazel test //swift/codegen/test --test_output=errors
|
||||||
|
- name: Check that QL generated code was checked in
|
||||||
|
run: |
|
||||||
|
bazel run //swift/codegen
|
||||||
|
git add swift
|
||||||
|
git diff --exit-code --stat HEAD
|
||||||
|
- name: Generate C++ files
|
||||||
|
run: |
|
||||||
|
bazel run //swift/codegen:cppcodegen -- --cpp-output=$PWD/swift-generated-headers
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: swift-generated-headers
|
||||||
|
path: swift-generated-headers/*.h
|
||||||
18
.github/workflows/swift-qltest.yml
vendored
18
.github/workflows/swift-qltest.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
qlformat:
|
qlformat:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
- name: Check QL formatting
|
- name: Check QL formatting
|
||||||
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
|
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
|
||||||
@@ -26,20 +26,9 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
os : [ubuntu-20.04, macos-latest]
|
os : [ubuntu-20.04, macos-latest]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
- name: Install bazelisk - Linux
|
- uses: bazelbuild/setup-bazelisk@v2
|
||||||
if: runner.os == 'Linux'
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y wget
|
|
||||||
wget https://github.com/bazelbuild/bazelisk/releases/download/v1.11.0/bazelisk-linux-amd64
|
|
||||||
mv bazelisk-linux-amd64 /usr/local/bin/bazel
|
|
||||||
chmod +x /usr/local/bin/bazel
|
|
||||||
- name: Install bazelisk - macOS
|
|
||||||
if: runner.os == 'MacOS'
|
|
||||||
run: |
|
|
||||||
brew install bazelisk
|
|
||||||
- name: Build Swift extractor
|
- name: Build Swift extractor
|
||||||
run: |
|
run: |
|
||||||
bazel run //swift:create-extractor-pack
|
bazel run //swift:create-extractor-pack
|
||||||
@@ -48,4 +37,3 @@ jobs:
|
|||||||
codeql test run --threads=0 --ram 5000 --search-path "${{ github.workspace }}/swift/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition ql/test
|
codeql test run --threads=0 --ram 5000 --search-path "${{ github.workspace }}/swift/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition ql/test
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/sync-files.yml
vendored
2
.github/workflows/sync-files.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
sync:
|
sync:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Check synchronized files
|
- name: Check synchronized files
|
||||||
run: python config/sync-files.py
|
run: python config/sync-files.py
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/validate-change-notes.yml
vendored
2
.github/workflows/validate-change-notes.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup CodeQL
|
- name: Setup CodeQL
|
||||||
uses: ./.github/actions/fetch-codeql
|
uses: ./.github/actions/fetch-codeql
|
||||||
|
|||||||
19
.gitignore
vendored
19
.gitignore
vendored
@@ -9,6 +9,7 @@
|
|||||||
# qltest projects and artifacts
|
# qltest projects and artifacts
|
||||||
*/ql/test/**/*.testproj
|
*/ql/test/**/*.testproj
|
||||||
*/ql/test/**/*.actual
|
*/ql/test/**/*.actual
|
||||||
|
*/ql/test/**/go.sum
|
||||||
|
|
||||||
# Visual studio temporaries, except a file used by QL4VS
|
# Visual studio temporaries, except a file used by QL4VS
|
||||||
.vs/*
|
.vs/*
|
||||||
@@ -20,6 +21,9 @@
|
|||||||
# python virtual environment folder
|
# python virtual environment folder
|
||||||
.venv/
|
.venv/
|
||||||
|
|
||||||
|
# binary files created by pytest-cov
|
||||||
|
.coverage
|
||||||
|
|
||||||
# It's useful (though not required) to be able to unpack codeql in the ql checkout itself
|
# It's useful (though not required) to be able to unpack codeql in the ql checkout itself
|
||||||
/codeql/
|
/codeql/
|
||||||
|
|
||||||
@@ -34,5 +38,20 @@ csharp/extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
|
|||||||
# links created by bazel
|
# links created by bazel
|
||||||
/bazel-*
|
/bazel-*
|
||||||
|
|
||||||
|
# local bazel options
|
||||||
|
/local.bazelrc
|
||||||
|
|
||||||
# CLion project files
|
# CLion project files
|
||||||
/.clwb
|
/.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
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ path_classifiers:
|
|||||||
test:
|
test:
|
||||||
- csharp/ql/src
|
- csharp/ql/src
|
||||||
- csharp/ql/test
|
- csharp/ql/test
|
||||||
|
- go/ql/test
|
||||||
- javascript/extractor/parser-tests
|
- javascript/extractor/parser-tests
|
||||||
- javascript/extractor/tests
|
- javascript/extractor/tests
|
||||||
- javascript/ql/src
|
- javascript/ql/src
|
||||||
@@ -13,6 +14,9 @@ path_classifiers:
|
|||||||
- python/ql/src
|
- python/ql/src
|
||||||
- python/ql/test
|
- python/ql/test
|
||||||
|
|
||||||
|
example:
|
||||||
|
- go/ql/src
|
||||||
|
|
||||||
queries:
|
queries:
|
||||||
- include: "*"
|
- include: "*"
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,51 @@
|
|||||||
# See https://pre-commit.com for more information
|
# See https://pre-commit.com for more information
|
||||||
# See https://pre-commit.com/hooks.html for more hooks
|
# See https://pre-commit.com/hooks.html for more hooks
|
||||||
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)
|
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v3.2.0
|
rev: v3.2.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)
|
||||||
|
|
||||||
- repo: local
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
|
rev: v13.0.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: codeql-format
|
- id: clang-format
|
||||||
|
files: ^swift/.*\.(h|c|cpp)$
|
||||||
|
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: codeql-format
|
||||||
name: Fix QL file formatting
|
name: Fix QL file formatting
|
||||||
files: \.qll?$
|
files: \.qll?$
|
||||||
language: system
|
language: system
|
||||||
entry: codeql query format --in-place
|
entry: codeql query format --in-place
|
||||||
|
|
||||||
- id: sync-files
|
- id: sync-files
|
||||||
name: Fix files required to be identical
|
name: Fix files required to be identical
|
||||||
|
files: \.(qll?|qhelp)$
|
||||||
language: system
|
language: system
|
||||||
entry: python3 config/sync-files.py --latest
|
entry: python3 config/sync-files.py --latest
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
|
|
||||||
- id: qhelp
|
- id: qhelp
|
||||||
name: Check query help generation
|
name: Check query help generation
|
||||||
files: \.qhelp$
|
files: \.qhelp$
|
||||||
language: system
|
language: system
|
||||||
entry: python3 misc/scripts/check-qhelp.py
|
entry: python3 misc/scripts/check-qhelp.py
|
||||||
|
|
||||||
|
- id: swift-codegen
|
||||||
|
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
|
||||||
|
pass_filenames: false
|
||||||
|
|
||||||
|
- id: swift-codegen-unit-tests
|
||||||
|
name: Run Swift code generation unit tests
|
||||||
|
files: ^swift/codegen/.*\.py$
|
||||||
|
language: system
|
||||||
|
entry: bazel test //swift/codegen/test
|
||||||
|
pass_filenames: false
|
||||||
|
|||||||
15
CODEOWNERS
15
CODEOWNERS
@@ -1,9 +1,13 @@
|
|||||||
/cpp/ @github/codeql-c-analysis
|
/cpp/ @github/codeql-c-analysis
|
||||||
/csharp/ @github/codeql-csharp
|
/csharp/ @github/codeql-csharp
|
||||||
|
/go/ @github/codeql-go
|
||||||
/java/ @github/codeql-java
|
/java/ @github/codeql-java
|
||||||
/javascript/ @github/codeql-javascript
|
/javascript/ @github/codeql-javascript
|
||||||
/python/ @github/codeql-python
|
/python/ @github/codeql-python
|
||||||
/ruby/ @github/codeql-ruby
|
/ruby/ @github/codeql-ruby
|
||||||
|
/swift/ @github/codeql-c
|
||||||
|
/java/kotlin-extractor/ @github/codeql-kotlin
|
||||||
|
/java/kotlin-explorer/ @github/codeql-kotlin
|
||||||
|
|
||||||
# ML-powered queries
|
# ML-powered queries
|
||||||
/javascript/ql/experimental/adaptivethreatmodeling/ @github/codeql-ml-powered-queries-reviewers
|
/javascript/ql/experimental/adaptivethreatmodeling/ @github/codeql-ml-powered-queries-reviewers
|
||||||
@@ -27,3 +31,14 @@
|
|||||||
# Bazel
|
# Bazel
|
||||||
**/*.bazel @github/codeql-ci-reviewers
|
**/*.bazel @github/codeql-ci-reviewers
|
||||||
**/*.bzl @github/codeql-ci-reviewers
|
**/*.bzl @github/codeql-ci-reviewers
|
||||||
|
|
||||||
|
# Documentation etc
|
||||||
|
/*.md @github/code-scanning-product
|
||||||
|
/LICENSE @github/code-scanning-product
|
||||||
|
|
||||||
|
# Workflows
|
||||||
|
/.github/workflows/ @github/codeql-ci-reviewers
|
||||||
|
/.github/workflows/go-* @github/codeql-go
|
||||||
|
/.github/workflows/js-ml-tests.yml @github/codeql-ml-powered-queries-reviewers
|
||||||
|
/.github/workflows/ql-for-ql-* @github/codeql-ql-for-ql-reviewers
|
||||||
|
/.github/workflows/ruby-* @github/codeql-ruby
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
We welcome contributions to our CodeQL libraries and queries. Got an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE).
|
We welcome contributions to our CodeQL libraries and queries. Got an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE).
|
||||||
|
|
||||||
There is lots of useful documentation to help you write queries, ranging from information about query file structure to tutorials for specific target languages. For more information on the documentation available, see [CodeQL queries](https://help.semmle.com/QL/learn-ql/writing-queries/writing-queries.html) on [help.semmle.com](https://help.semmle.com).
|
There is lots of useful documentation to help you write queries, ranging from information about query file structure to tutorials for specific target languages. For more information on the documentation available, see [CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/codeql-queries) on [codeql.github.com](https://codeql.github.com).
|
||||||
|
|
||||||
## Change notes
|
## Change notes
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ If you have an idea for a query that you would like to share with other CodeQL u
|
|||||||
|
|
||||||
3. **Formatting**
|
3. **Formatting**
|
||||||
|
|
||||||
- The queries and libraries must be autoformatted, for example using the "Format Document" command in [CodeQL for Visual Studio Code](https://help.semmle.com/codeql/codeql-for-vscode/procedures/about-codeql-for-vscode.html).
|
- The queries and libraries must be autoformatted, for example using the "Format Document" command in [CodeQL for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/about-codeql-for-visual-studio-code).
|
||||||
|
|
||||||
If you prefer, you can either:
|
If you prefer, you can either:
|
||||||
1. install the [pre-commit framework](https://pre-commit.com/) and install the configured hooks on this repo via `pre-commit install`, or
|
1. install the [pre-commit framework](https://pre-commit.com/) and install the configured hooks on this repo via `pre-commit install`, or
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# CodeQL
|
# 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. For the queries, libraries, and extractor that power Go analysis, visit the [CodeQL for Go repository](https://github.com/github/codeql-go).
|
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.
|
||||||
|
|
||||||
## How do I learn CodeQL and run queries?
|
## How do I learn CodeQL and run queries?
|
||||||
|
|
||||||
@@ -13,7 +13,9 @@ We welcome contributions to our standard library and standard checks. Do you hav
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
The code in this repository is licensed under the [MIT License](LICENSE) by [GitHub](https://github.com). The use of CodeQL on open source code is licensed under specific [Terms & Conditions](https://securitylab.github.com/tools/codeql/license/) UNLESS you have a commercial license in place. If you'd like to use CodeQL with a commercial codebase, please [contact us](https://github.com/enterprise/contact) for further help.
|
The code in this repository is licensed under the [MIT License](LICENSE) by [GitHub](https://github.com).
|
||||||
|
|
||||||
|
The CodeQL CLI (including the CodeQL engine) is hosted in a [different repository](https://github.com/github/codeql-cli-binaries) and is [licensed separately](https://github.com/github/codeql-cli-binaries/blob/main/LICENSE.md). If you'd like to use the CodeQL CLI to analyze closed-source code, you will need a separate commercial license; please [contact us](https://github.com/enterprise/contact) for further help.
|
||||||
|
|
||||||
## Visual Studio Code integration
|
## Visual Studio Code integration
|
||||||
|
|
||||||
|
|||||||
32
codeql-workspace.yml
Normal file
32
codeql-workspace.yml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
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,13 +22,15 @@
|
|||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll",
|
"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/DataFlowImpl4.qll",
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.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/DataFlowImpl.qll",
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.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/DataFlowImpl3.qll",
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.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/DataFlowImpl.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll",
|
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll"
|
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll",
|
||||||
|
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll"
|
||||||
],
|
],
|
||||||
"DataFlow Java/C++/C#/Python Common": [
|
"DataFlow Java/C++/C#/Python Common": [
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
|
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
|
||||||
@@ -36,7 +38,8 @@
|
|||||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll",
|
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll",
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll",
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll",
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll"
|
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll",
|
||||||
|
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplCommon.qll"
|
||||||
],
|
],
|
||||||
"TaintTracking::Configuration Java/C++/C#/Python": [
|
"TaintTracking::Configuration Java/C++/C#/Python": [
|
||||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||||
@@ -51,12 +54,14 @@
|
|||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll",
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll",
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||||
|
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking1/TaintTrackingImpl.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking2/TaintTrackingImpl.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking4/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/tainttracking1/TaintTrackingImpl.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforlibraries/TaintTrackingImpl.qll"
|
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforlibraries/TaintTrackingImpl.qll",
|
||||||
|
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
|
||||||
],
|
],
|
||||||
"DataFlow Java/C++/C#/Python Consistency checks": [
|
"DataFlow Java/C++/C#/Python Consistency checks": [
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll",
|
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll",
|
||||||
@@ -64,7 +69,8 @@
|
|||||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll",
|
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll",
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll",
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll",
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplConsistency.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplConsistency.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplConsistency.qll"
|
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplConsistency.qll",
|
||||||
|
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplConsistency.qll"
|
||||||
],
|
],
|
||||||
"DataFlow Java/C# Flow Summaries": [
|
"DataFlow Java/C# Flow Summaries": [
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll",
|
"java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll",
|
||||||
@@ -457,7 +463,8 @@
|
|||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll",
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll",
|
||||||
"csharp/ql/lib/semmle/code/cil/internal/SsaImplCommon.qll",
|
"csharp/ql/lib/semmle/code/cil/internal/SsaImplCommon.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImplCommon.qll",
|
"ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImplCommon.qll",
|
||||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll"
|
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll",
|
||||||
|
"swift/ql/lib/codeql/swift/dataflow/internal/SsaImplCommon.qll"
|
||||||
],
|
],
|
||||||
"CryptoAlgorithms Python/JS/Ruby": [
|
"CryptoAlgorithms Python/JS/Ruby": [
|
||||||
"javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll",
|
"javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll",
|
||||||
@@ -474,20 +481,23 @@
|
|||||||
"python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll",
|
"python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll"
|
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll"
|
||||||
],
|
],
|
||||||
"ReDoS Util Python/JS/Ruby": [
|
"ReDoS Util Python/JS/Ruby/Java": [
|
||||||
"javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll",
|
"javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll",
|
||||||
"python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll",
|
"python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll"
|
"ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll",
|
||||||
|
"java/ql/lib/semmle/code/java/security/performance/ReDoSUtil.qll"
|
||||||
],
|
],
|
||||||
"ReDoS Exponential Python/JS/Ruby": [
|
"ReDoS Exponential Python/JS/Ruby/Java": [
|
||||||
"javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll",
|
"javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll",
|
||||||
"python/ql/lib/semmle/python/security/performance/ExponentialBackTracking.qll",
|
"python/ql/lib/semmle/python/security/performance/ExponentialBackTracking.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll"
|
"ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll",
|
||||||
|
"java/ql/lib/semmle/code/java/security/performance/ExponentialBackTracking.qll"
|
||||||
],
|
],
|
||||||
"ReDoS Polynomial Python/JS/Ruby": [
|
"ReDoS Polynomial Python/JS/Ruby/Java": [
|
||||||
"javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
|
"javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
|
||||||
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll",
|
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll"
|
"ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll",
|
||||||
|
"java/ql/lib/semmle/code/java/security/performance/SuperlinearBackTracking.qll"
|
||||||
],
|
],
|
||||||
"BadTagFilterQuery Python/JS/Ruby": [
|
"BadTagFilterQuery Python/JS/Ruby": [
|
||||||
"javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll",
|
"javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll",
|
||||||
@@ -496,7 +506,8 @@
|
|||||||
],
|
],
|
||||||
"CFG": [
|
"CFG": [
|
||||||
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",
|
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll"
|
"ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll",
|
||||||
|
"swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImplShared.qll"
|
||||||
],
|
],
|
||||||
"TypeTracker": [
|
"TypeTracker": [
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll",
|
||||||
@@ -549,5 +560,9 @@
|
|||||||
"HttpToFileAccessCustomizations JS/Ruby": [
|
"HttpToFileAccessCustomizations JS/Ruby": [
|
||||||
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessCustomizations.qll",
|
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessCustomizations.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/security/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"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
1
conftest.py
Normal file
1
conftest.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# this empty file adds the repo root to PYTHON_PATH when running pytest
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
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
|
||||||
2111
cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/old.dbscheme
Normal file
2111
cpp/downgrades/cf72c8898d19eb1b3374432cf79d8276cb07ad43/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
|||||||
|
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
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
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,3 +1,30 @@
|
|||||||
|
## 0.2.1
|
||||||
|
|
||||||
|
## 0.2.0
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* The signature of `allowImplicitRead` on `DataFlow::Configuration` and `TaintTracking::Configuration` has changed from `allowImplicitRead(DataFlow::Node node, DataFlow::Content c)` to `allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c)`.
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* More Windows pool allocation functions are now detected as `AllocationFunction`s.
|
||||||
|
* The `semmle.code.cpp.commons.Buffer` library has been enhanced to handle array members of classes that do not specify a size.
|
||||||
|
|
||||||
|
## 0.1.0
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* The recently added flow-state versions of `isBarrierIn`, `isBarrierOut`, `isSanitizerIn`, and `isSanitizerOut` in the data flow and taint tracking libraries have been removed.
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
* A new library `semmle.code.cpp.security.PrivateData` has been added. The new library heuristically detects variables and functions dealing with sensitive private data, such as e-mail addresses and credit card numbers.
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* The `semmle.code.cpp.security.SensitiveExprs` library has been enhanced with some additional rules for detecting credentials.
|
||||||
|
|
||||||
## 0.0.13
|
## 0.0.13
|
||||||
|
|
||||||
## 0.0.12
|
## 0.0.12
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: feature
|
|
||||||
---
|
|
||||||
* A new library `semmle.code.cpp.security.PrivateData` has been added. The new library heuristically detects variables and functions dealing with sensitive private data, such as e-mail addresses and credit card numbers.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: minorAnalysis
|
|
||||||
---
|
|
||||||
* The `semmle.code.cpp.security.SensitiveExprs` library has been enhanced with some additional rules for detecting credentials.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: breaking
|
|
||||||
---
|
|
||||||
The recently added flow-state versions of `isBarrierIn`, `isBarrierOut`, `isSanitizerIn`, and `isSanitizerOut` in the data flow and taint tracking libraries have been removed.
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: feature
|
||||||
|
---
|
||||||
|
* 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,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: deprecated
|
||||||
|
---
|
||||||
|
* 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.
|
||||||
13
cpp/ql/lib/change-notes/released/0.1.0.md
Normal file
13
cpp/ql/lib/change-notes/released/0.1.0.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
## 0.1.0
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* The recently added flow-state versions of `isBarrierIn`, `isBarrierOut`, `isSanitizerIn`, and `isSanitizerOut` in the data flow and taint tracking libraries have been removed.
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
* A new library `semmle.code.cpp.security.PrivateData` has been added. The new library heuristically detects variables and functions dealing with sensitive private data, such as e-mail addresses and credit card numbers.
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* The `semmle.code.cpp.security.SensitiveExprs` library has been enhanced with some additional rules for detecting credentials.
|
||||||
10
cpp/ql/lib/change-notes/released/0.2.0.md
Normal file
10
cpp/ql/lib/change-notes/released/0.2.0.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
## 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
cpp/ql/lib/change-notes/released/0.2.1.md
Normal file
1
cpp/ql/lib/change-notes/released/0.2.1.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
## 0.2.1
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.0.13
|
lastReleaseVersion: 0.2.1
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-all
|
name: codeql/cpp-all
|
||||||
version: 0.1.0-dev
|
version: 0.2.2-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dbscheme: semmlecode.cpp.dbscheme
|
dbscheme: semmlecode.cpp.dbscheme
|
||||||
extractor: cpp
|
extractor: cpp
|
||||||
|
|||||||
@@ -109,10 +109,7 @@ class Element extends ElementBase {
|
|||||||
then
|
then
|
||||||
exists(MacroInvocation mi |
|
exists(MacroInvocation mi |
|
||||||
this = mi.getAGeneratedElement() and
|
this = mi.getAGeneratedElement() and
|
||||||
not exists(MacroInvocation closer |
|
not hasCloserMacroInvocation(this, mi) and
|
||||||
this = closer.getAGeneratedElement() and
|
|
||||||
mi = closer.getParentInvocation+()
|
|
||||||
) and
|
|
||||||
result = mi.getMacro()
|
result = mi.getMacro()
|
||||||
)
|
)
|
||||||
else result = this
|
else result = this
|
||||||
@@ -236,6 +233,14 @@ class Element extends ElementBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
private predicate hasCloserMacroInvocation(Element elem, MacroInvocation mi) {
|
||||||
|
exists(MacroInvocation closer |
|
||||||
|
elem = closer.getAGeneratedElement() and
|
||||||
|
mi = closer.getParentInvocation()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate isFromTemplateInstantiationRec(Element e, Element instantiation) {
|
private predicate isFromTemplateInstantiationRec(Element e, Element instantiation) {
|
||||||
instantiation.(Function).isConstructedFrom(_) and
|
instantiation.(Function).isConstructedFrom(_) and
|
||||||
e = instantiation
|
e = instantiation
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
import semmle.code.cpp.Variable
|
import semmle.code.cpp.Variable
|
||||||
import semmle.code.cpp.Enum
|
import semmle.code.cpp.Enum
|
||||||
import semmle.code.cpp.exprs.Access
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A C structure member or C++ non-static member variable. For example the
|
* A C structure member or C++ non-static member variable. For example the
|
||||||
@@ -32,7 +31,7 @@ class Field extends MemberVariable {
|
|||||||
int getByteOffset() { fieldoffsets(underlyingElement(this), result, _) }
|
int getByteOffset() { fieldoffsets(underlyingElement(this), result, _) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the byte offset within `mostDerivedClass` of each occurence of this
|
* Gets the byte offset within `mostDerivedClass` of each occurrence of this
|
||||||
* field within `mostDerivedClass` itself or a base class subobject of
|
* field within `mostDerivedClass` itself or a base class subobject of
|
||||||
* `mostDerivedClass`.
|
* `mostDerivedClass`.
|
||||||
* Note that for fields of virtual base classes, and non-virtual base classes
|
* 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);
|
* int z = min(5, 7);
|
||||||
* ```
|
* ```
|
||||||
* The full signature of the function called on the last line would be
|
* 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
|
* `min<int>(int, int) -> int`, and the full signature of the uninstantiated
|
||||||
* template on the first line would be "min<T>(T, T) -> T".
|
* template on the first line would be `min<T>(T, T) -> T`.
|
||||||
*/
|
*/
|
||||||
string getFullSignature() {
|
string getFullSignature() {
|
||||||
exists(string name, string templateArgs, string args |
|
exists(string name, string templateArgs, string args |
|
||||||
|
|||||||
@@ -663,18 +663,24 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred)
|
|||||||
or
|
or
|
||||||
s.(ComputedGotoStmt).getExpr() = e and pred = "getExpr()"
|
s.(ComputedGotoStmt).getExpr() = e and pred = "getExpr()"
|
||||||
or
|
or
|
||||||
|
s.(ConstexprIfStmt).getInitialization() = e and pred = "getInitialization()"
|
||||||
|
or
|
||||||
s.(ConstexprIfStmt).getCondition() = e and pred = "getCondition()"
|
s.(ConstexprIfStmt).getCondition() = e and pred = "getCondition()"
|
||||||
or
|
or
|
||||||
s.(ConstexprIfStmt).getThen() = e and pred = "getThen()"
|
s.(ConstexprIfStmt).getThen() = e and pred = "getThen()"
|
||||||
or
|
or
|
||||||
s.(ConstexprIfStmt).getElse() = e and pred = "getElse()"
|
s.(ConstexprIfStmt).getElse() = e and pred = "getElse()"
|
||||||
or
|
or
|
||||||
|
s.(IfStmt).getInitialization() = e and pred = "getInitialization()"
|
||||||
|
or
|
||||||
s.(IfStmt).getCondition() = e and pred = "getCondition()"
|
s.(IfStmt).getCondition() = e and pred = "getCondition()"
|
||||||
or
|
or
|
||||||
s.(IfStmt).getThen() = e and pred = "getThen()"
|
s.(IfStmt).getThen() = e and pred = "getThen()"
|
||||||
or
|
or
|
||||||
s.(IfStmt).getElse() = e and pred = "getElse()"
|
s.(IfStmt).getElse() = e and pred = "getElse()"
|
||||||
or
|
or
|
||||||
|
s.(SwitchStmt).getInitialization() = e and pred = "getInitialization()"
|
||||||
|
or
|
||||||
s.(SwitchStmt).getExpr() = e and pred = "getExpr()"
|
s.(SwitchStmt).getExpr() = e and pred = "getExpr()"
|
||||||
or
|
or
|
||||||
s.(SwitchStmt).getStmt() = e and pred = "getStmt()"
|
s.(SwitchStmt).getStmt() = e and pred = "getStmt()"
|
||||||
|
|||||||
@@ -10,11 +10,18 @@ import semmle.code.cpp.dataflow.DataFlow
|
|||||||
* char data[1]; // v
|
* char data[1]; // v
|
||||||
* };
|
* };
|
||||||
* ```
|
* ```
|
||||||
* This requires that `v` is an array of size 0 or 1.
|
* or
|
||||||
|
* ```
|
||||||
|
* struct myStruct { // c
|
||||||
|
* int amount;
|
||||||
|
* char data[]; // v
|
||||||
|
* };
|
||||||
|
* ```
|
||||||
|
* This requires that `v` is an array of size 0 or 1, or that the array has no size.
|
||||||
*/
|
*/
|
||||||
predicate memberMayBeVarSize(Class c, MemberVariable v) {
|
predicate memberMayBeVarSize(Class c, MemberVariable v) {
|
||||||
c = v.getDeclaringType() and
|
c = v.getDeclaringType() and
|
||||||
v.getUnspecifiedType().(ArrayType).getArraySize() <= 1
|
exists(ArrayType t | t = v.getUnspecifiedType() | not t.getArraySize() > 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,11 +34,11 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
|||||||
result = bufferVar.getUnspecifiedType().(ArrayType).getSize() and
|
result = bufferVar.getUnspecifiedType().(ArrayType).getSize() and
|
||||||
why = bufferVar and
|
why = bufferVar and
|
||||||
not memberMayBeVarSize(_, bufferVar) and
|
not memberMayBeVarSize(_, bufferVar) and
|
||||||
not result = 0 // zero sized arrays are likely to have special usage, for example
|
// zero sized arrays are likely to have special usage, for example
|
||||||
or
|
|
||||||
// behaving a bit like a 'union' overlapping other fields.
|
// behaving a bit like a 'union' overlapping other fields.
|
||||||
// buffer is an initialized array
|
not result = 0
|
||||||
// e.g. int buffer[] = {1, 2, 3};
|
or
|
||||||
|
// buffer is an initialized array, e.g., int buffer[] = {1, 2, 3};
|
||||||
why = bufferVar.getInitializer().getExpr() and
|
why = bufferVar.getInitializer().getExpr() and
|
||||||
(
|
(
|
||||||
why instanceof AggregateLiteral or
|
why instanceof AggregateLiteral or
|
||||||
@@ -40,13 +47,18 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
|||||||
result = why.(Expr).getType().(ArrayType).getSize() and
|
result = why.(Expr).getType().(ArrayType).getSize() and
|
||||||
not exists(bufferVar.getUnspecifiedType().(ArrayType).getSize())
|
not exists(bufferVar.getUnspecifiedType().(ArrayType).getSize())
|
||||||
or
|
or
|
||||||
exists(Class parentClass, VariableAccess parentPtr |
|
exists(Class parentClass, VariableAccess parentPtr, int bufferSize |
|
||||||
// buffer is the parentPtr->bufferVar of a 'variable size struct'
|
// buffer is the parentPtr->bufferVar of a 'variable size struct'
|
||||||
memberMayBeVarSize(parentClass, bufferVar) and
|
memberMayBeVarSize(parentClass, bufferVar) and
|
||||||
why = bufferVar and
|
why = bufferVar and
|
||||||
parentPtr = bufferExpr.(VariableAccess).getQualifier() and
|
parentPtr = bufferExpr.(VariableAccess).getQualifier() and
|
||||||
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
|
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
|
||||||
result = getBufferSize(parentPtr, _) + bufferVar.getType().getSize() - parentClass.getSize()
|
(
|
||||||
|
if exists(bufferVar.getType().getSize())
|
||||||
|
then bufferSize = bufferVar.getType().getSize()
|
||||||
|
else bufferSize = 0
|
||||||
|
) and
|
||||||
|
result = getBufferSize(parentPtr, _) + bufferSize - parentClass.getSize()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -872,7 +872,7 @@ class FormatLiteral extends Literal {
|
|||||||
|
|
||||||
private Type getConversionType1(int n) {
|
private Type getConversionType1(int n) {
|
||||||
exists(string cnv | cnv = this.getConversionChar(n) |
|
exists(string cnv | cnv = this.getConversionChar(n) |
|
||||||
cnv.regexpMatch("d|i") and
|
cnv = ["d", "i"] and
|
||||||
result = this.getIntegralConversion(n) and
|
result = this.getIntegralConversion(n) and
|
||||||
not result.getUnderlyingType().(IntegralType).isExplicitlySigned() and
|
not result.getUnderlyingType().(IntegralType).isExplicitlySigned() and
|
||||||
not result.getUnderlyingType().(IntegralType).isExplicitlyUnsigned()
|
not result.getUnderlyingType().(IntegralType).isExplicitlyUnsigned()
|
||||||
@@ -912,7 +912,7 @@ class FormatLiteral extends Literal {
|
|||||||
|
|
||||||
private Type getConversionType2(int n) {
|
private Type getConversionType2(int n) {
|
||||||
exists(string cnv | cnv = this.getConversionChar(n) |
|
exists(string cnv | cnv = this.getConversionChar(n) |
|
||||||
cnv.regexpMatch("o|u|x|X") and
|
cnv = ["o", "u", "x", "X"] and
|
||||||
result = this.getIntegralConversion(n) and
|
result = this.getIntegralConversion(n) and
|
||||||
result.getUnderlyingType().(IntegralType).isUnsigned()
|
result.getUnderlyingType().(IntegralType).isUnsigned()
|
||||||
)
|
)
|
||||||
@@ -920,7 +920,7 @@ class FormatLiteral extends Literal {
|
|||||||
|
|
||||||
private Type getConversionType3(int n) {
|
private Type getConversionType3(int n) {
|
||||||
exists(string cnv | cnv = this.getConversionChar(n) |
|
exists(string cnv | cnv = this.getConversionChar(n) |
|
||||||
cnv.regexpMatch("a|A|e|E|f|F|g|G") and result = this.getFloatingPointConversion(n)
|
cnv = ["a", "A", "e", "E", "f", "F", "g", "G"] and result = this.getFloatingPointConversion(n)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1312,7 +1312,7 @@ class FormatLiteral extends Literal {
|
|||||||
len =
|
len =
|
||||||
min(int v |
|
min(int v |
|
||||||
v = this.getPrecision(n) or
|
v = this.getPrecision(n) or
|
||||||
v = this.getUse().getFormatArgument(n).(AnalysedString).getMaxLength() - 1 // (don't count null terminator)
|
v = this.getUse().getFormatArgument(n).(AnalyzedString).getMaxLength() - 1 // (don't count null terminator)
|
||||||
) and
|
) and
|
||||||
reason = TValueFlowAnalysis()
|
reason = TValueFlowAnalysis()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -27,11 +27,14 @@ predicate canValueFlow(Expr fromExpr, Expr toExpr) {
|
|||||||
fromExpr = toExpr.(ConditionalExpr).getElse()
|
fromExpr = toExpr.(ConditionalExpr).getElse()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for AnalyzedString */
|
||||||
|
deprecated class AnalysedString = AnalyzedString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An analysed null terminated string.
|
* An analyzed null terminated string.
|
||||||
*/
|
*/
|
||||||
class AnalysedString extends Expr {
|
class AnalyzedString extends Expr {
|
||||||
AnalysedString() {
|
AnalyzedString() {
|
||||||
this.getUnspecifiedType() instanceof ArrayType or
|
this.getUnspecifiedType() instanceof ArrayType or
|
||||||
this.getUnspecifiedType() instanceof PointerType
|
this.getUnspecifiedType() instanceof PointerType
|
||||||
}
|
}
|
||||||
@@ -41,15 +44,15 @@ class AnalysedString extends Expr {
|
|||||||
* can be calculated.
|
* can be calculated.
|
||||||
*/
|
*/
|
||||||
int getMaxLength() {
|
int getMaxLength() {
|
||||||
// take the longest AnalysedString it's value could 'flow' from; however if even one doesn't
|
// take the longest AnalyzedString its value could 'flow' from; however if even one doesn't
|
||||||
// return a value (this essentially means 'infinity') we can't return a value either.
|
// return a value (this essentially means 'infinity') we can't return a value either.
|
||||||
result =
|
result =
|
||||||
max(AnalysedString expr, int toMax |
|
max(AnalyzedString expr, int toMax |
|
||||||
canValueFlow*(expr, this) and toMax = expr.(StringLiteral).getOriginalLength()
|
canValueFlow*(expr, this) and toMax = expr.(StringLiteral).getOriginalLength()
|
||||||
|
|
|
|
||||||
toMax
|
toMax
|
||||||
) and // maximum length
|
) and // maximum length
|
||||||
forall(AnalysedString expr | canValueFlow(expr, this) | exists(expr.getMaxLength())) // all sources return a value (recursive)
|
forall(AnalyzedString expr | canValueFlow(expr, this) | exists(expr.getMaxLength())) // all sources return a value (recursive)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -708,30 +708,33 @@ private predicate straightLineSparse(Node scope, int i, Node ni, Spec spec) {
|
|||||||
or
|
or
|
||||||
scope =
|
scope =
|
||||||
any(SwitchStmt s |
|
any(SwitchStmt s |
|
||||||
|
// SwitchStmt [-> init] -> expr
|
||||||
i = -1 and ni = s and spec.isAt()
|
i = -1 and ni = s and spec.isAt()
|
||||||
or
|
or
|
||||||
i = 0 and ni = s.getExpr() and spec.isAround()
|
i = 0 and ni = s.getInitialization() and spec.isAround()
|
||||||
|
or
|
||||||
|
i = 1 and ni = s.getExpr() and spec.isAround()
|
||||||
or
|
or
|
||||||
// If the switch body is not a block then this step is skipped, and the
|
// If the switch body is not a block then this step is skipped, and the
|
||||||
// expression jumps directly to the cases.
|
// expression jumps directly to the cases.
|
||||||
i = 1 and ni = s.getStmt().(BlockStmt) and spec.isAt()
|
i = 2 and ni = s.getStmt().(BlockStmt) and spec.isAt()
|
||||||
or
|
or
|
||||||
i = 2 and ni = s.getASwitchCase() and spec.isBefore()
|
i = 3 and ni = s.getASwitchCase() and spec.isBefore()
|
||||||
or
|
or
|
||||||
// If there is no default case, we can jump to after the block. Note: `i`
|
// If there is no default case, we can jump to after the block. Note: `i`
|
||||||
// is same value as above.
|
// is same value as above.
|
||||||
not s.getASwitchCase() instanceof DefaultCase and
|
not s.getASwitchCase() instanceof DefaultCase and
|
||||||
i = 2 and
|
i = 3 and
|
||||||
ni = s.getStmt() and
|
ni = s.getStmt() and
|
||||||
spec.isAfter()
|
spec.isAfter()
|
||||||
or
|
or
|
||||||
i = 3 and /* BARRIER */ ni = s and spec.isBarrier()
|
i = 4 and /* BARRIER */ ni = s and spec.isBarrier()
|
||||||
or
|
or
|
||||||
i = 4 and ni = s.getStmt() and spec.isAfter()
|
i = 5 and ni = s.getStmt() and spec.isAfter()
|
||||||
or
|
or
|
||||||
i = 5 and ni = s and spec.isAroundDestructors()
|
i = 6 and ni = s and spec.isAroundDestructors()
|
||||||
or
|
or
|
||||||
i = 6 and ni = s and spec.isAfter()
|
i = 7 and ni = s and spec.isAfter()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
scope =
|
scope =
|
||||||
@@ -836,8 +839,15 @@ private predicate subEdge(Pos p1, Node n1, Node n2, Pos p2) {
|
|||||||
p2.nodeAt(n2, f)
|
p2.nodeAt(n2, f)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// IfStmt -> condition ; { then, else } ->
|
// IfStmt -> [ init -> ] condition ; { then, else } ->
|
||||||
exists(IfStmt s |
|
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
|
p1.nodeAt(n1, s) and
|
||||||
p2.nodeBefore(n2, s.getCondition())
|
p2.nodeBefore(n2, s.getCondition())
|
||||||
or
|
or
|
||||||
@@ -851,8 +861,15 @@ private predicate subEdge(Pos p1, Node n1, Node n2, Pos p2) {
|
|||||||
p2.nodeAfter(n2, s)
|
p2.nodeAfter(n2, s)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// ConstexprIfStmt -> condition ; { then, else } -> // same as IfStmt
|
// ConstexprIfStmt -> [ init -> ] condition ; { then, else } -> // same as IfStmt
|
||||||
exists(ConstexprIfStmt s |
|
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
|
p1.nodeAt(n1, s) and
|
||||||
p2.nodeBefore(n2, s.getCondition())
|
p2.nodeBefore(n2, s.getCondition())
|
||||||
or
|
or
|
||||||
@@ -953,7 +970,7 @@ private predicate subEdge(Pos p1, Node n1, Node n2, Pos p2) {
|
|||||||
private predicate subEdgeIncludingDestructors(Pos p1, Node n1, Node n2, Pos p2) {
|
private predicate subEdgeIncludingDestructors(Pos p1, Node n1, Node n2, Pos p2) {
|
||||||
subEdge(p1, n1, n2, p2)
|
subEdge(p1, n1, n2, p2)
|
||||||
or
|
or
|
||||||
// If `n1` has sub-nodes to accomodate destructors, but there are none to be
|
// If `n1` has sub-nodes to accommodate destructors, but there are none to be
|
||||||
// called, connect the "before destructors" node directly to the "after
|
// called, connect the "before destructors" node directly to the "after
|
||||||
// destructors" node. For performance, only do this when the nodes exist.
|
// destructors" node. For performance, only do this when the nodes exist.
|
||||||
exists(Pos afterDtors | afterDtors.isAfterDestructors() | subEdge(afterDtors, n1, _, _)) and
|
exists(Pos afterDtors | afterDtors.isAfterDestructors() | subEdge(afterDtors, n1, _, _)) and
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -170,6 +170,14 @@ abstract class Configuration extends string {
|
|||||||
*/
|
*/
|
||||||
int explorationLimit() { none() }
|
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
|
* 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
|
* approximate distance between `node` and the closest source is `dist` and
|
||||||
@@ -485,8 +493,9 @@ private predicate additionalJumpStateStep(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -496,6 +505,37 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -573,9 +613,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -599,10 +639,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,6 +660,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -712,9 +762,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -740,10 +790,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -762,7 +812,8 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
pragma[nomagic]
|
||||||
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -861,8 +912,8 @@ private module Stage1 {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -872,7 +923,10 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
@@ -1147,11 +1201,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
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]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1574,7 +1643,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1612,10 +1681,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1706,7 +1789,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1729,9 +1813,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1752,8 +1836,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1926,7 +2010,34 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1935,8 +2046,13 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2363,7 +2479,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -2401,10 +2517,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3190,7 +3320,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3228,10 +3358,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3300,17 +3444,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -3506,7 +3661,7 @@ private newtype TPathNode =
|
|||||||
* of dereference operations needed to get from the value in the node to the
|
* 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.
|
* tracked object. The final type indicates the type of the tracked object.
|
||||||
*/
|
*/
|
||||||
abstract private class AccessPath extends TAccessPath {
|
private class AccessPath extends TAccessPath {
|
||||||
/** Gets the head of this access path, if any. */
|
/** Gets the head of this access path, if any. */
|
||||||
abstract TypedContent getHead();
|
abstract TypedContent getHead();
|
||||||
|
|
||||||
@@ -3721,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode {
|
|||||||
abstract NodeEx getNodeEx();
|
abstract NodeEx getNodeEx();
|
||||||
|
|
||||||
predicate isHidden() {
|
predicate isHidden() {
|
||||||
hiddenNode(this.getNodeEx().asNode()) and
|
not this.getConfiguration().includeHiddenNodes() and
|
||||||
not this.isSource() and
|
(
|
||||||
not this instanceof PathNodeSink
|
hiddenNode(this.getNodeEx().asNode()) and
|
||||||
or
|
not this.isSource() and
|
||||||
this.getNodeEx() instanceof TNodeImplicitRead
|
not this instanceof PathNodeSink
|
||||||
|
or
|
||||||
|
this.getNodeEx() instanceof TNodeImplicitRead
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ppAp() {
|
private string ppAp() {
|
||||||
@@ -4202,10 +4360,16 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* 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
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4213,15 +4377,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode 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 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4557,7 +4719,11 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4573,7 +4739,11 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -170,6 +170,14 @@ abstract class Configuration extends string {
|
|||||||
*/
|
*/
|
||||||
int explorationLimit() { none() }
|
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
|
* 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
|
* approximate distance between `node` and the closest source is `dist` and
|
||||||
@@ -485,8 +493,9 @@ private predicate additionalJumpStateStep(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -496,6 +505,37 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -573,9 +613,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -599,10 +639,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,6 +660,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -712,9 +762,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -740,10 +790,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -762,7 +812,8 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
pragma[nomagic]
|
||||||
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -861,8 +912,8 @@ private module Stage1 {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -872,7 +923,10 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
@@ -1147,11 +1201,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
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]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1574,7 +1643,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1612,10 +1681,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1706,7 +1789,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1729,9 +1813,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1752,8 +1836,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1926,7 +2010,34 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1935,8 +2046,13 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2363,7 +2479,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -2401,10 +2517,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3190,7 +3320,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3228,10 +3358,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3300,17 +3444,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -3506,7 +3661,7 @@ private newtype TPathNode =
|
|||||||
* of dereference operations needed to get from the value in the node to the
|
* 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.
|
* tracked object. The final type indicates the type of the tracked object.
|
||||||
*/
|
*/
|
||||||
abstract private class AccessPath extends TAccessPath {
|
private class AccessPath extends TAccessPath {
|
||||||
/** Gets the head of this access path, if any. */
|
/** Gets the head of this access path, if any. */
|
||||||
abstract TypedContent getHead();
|
abstract TypedContent getHead();
|
||||||
|
|
||||||
@@ -3721,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode {
|
|||||||
abstract NodeEx getNodeEx();
|
abstract NodeEx getNodeEx();
|
||||||
|
|
||||||
predicate isHidden() {
|
predicate isHidden() {
|
||||||
hiddenNode(this.getNodeEx().asNode()) and
|
not this.getConfiguration().includeHiddenNodes() and
|
||||||
not this.isSource() and
|
(
|
||||||
not this instanceof PathNodeSink
|
hiddenNode(this.getNodeEx().asNode()) and
|
||||||
or
|
not this.isSource() and
|
||||||
this.getNodeEx() instanceof TNodeImplicitRead
|
not this instanceof PathNodeSink
|
||||||
|
or
|
||||||
|
this.getNodeEx() instanceof TNodeImplicitRead
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ppAp() {
|
private string ppAp() {
|
||||||
@@ -4202,10 +4360,16 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* 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
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4213,15 +4377,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode 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 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4557,7 +4719,11 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4573,7 +4739,11 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -170,6 +170,14 @@ abstract class Configuration extends string {
|
|||||||
*/
|
*/
|
||||||
int explorationLimit() { none() }
|
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
|
* 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
|
* approximate distance between `node` and the closest source is `dist` and
|
||||||
@@ -485,8 +493,9 @@ private predicate additionalJumpStateStep(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -496,6 +505,37 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -573,9 +613,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -599,10 +639,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,6 +660,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -712,9 +762,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -740,10 +790,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -762,7 +812,8 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
pragma[nomagic]
|
||||||
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -861,8 +912,8 @@ private module Stage1 {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -872,7 +923,10 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
@@ -1147,11 +1201,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
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]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1574,7 +1643,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1612,10 +1681,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1706,7 +1789,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1729,9 +1813,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1752,8 +1836,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1926,7 +2010,34 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1935,8 +2046,13 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2363,7 +2479,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -2401,10 +2517,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3190,7 +3320,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3228,10 +3358,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3300,17 +3444,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -3506,7 +3661,7 @@ private newtype TPathNode =
|
|||||||
* of dereference operations needed to get from the value in the node to the
|
* 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.
|
* tracked object. The final type indicates the type of the tracked object.
|
||||||
*/
|
*/
|
||||||
abstract private class AccessPath extends TAccessPath {
|
private class AccessPath extends TAccessPath {
|
||||||
/** Gets the head of this access path, if any. */
|
/** Gets the head of this access path, if any. */
|
||||||
abstract TypedContent getHead();
|
abstract TypedContent getHead();
|
||||||
|
|
||||||
@@ -3721,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode {
|
|||||||
abstract NodeEx getNodeEx();
|
abstract NodeEx getNodeEx();
|
||||||
|
|
||||||
predicate isHidden() {
|
predicate isHidden() {
|
||||||
hiddenNode(this.getNodeEx().asNode()) and
|
not this.getConfiguration().includeHiddenNodes() and
|
||||||
not this.isSource() and
|
(
|
||||||
not this instanceof PathNodeSink
|
hiddenNode(this.getNodeEx().asNode()) and
|
||||||
or
|
not this.isSource() and
|
||||||
this.getNodeEx() instanceof TNodeImplicitRead
|
not this instanceof PathNodeSink
|
||||||
|
or
|
||||||
|
this.getNodeEx() instanceof TNodeImplicitRead
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ppAp() {
|
private string ppAp() {
|
||||||
@@ -4202,10 +4360,16 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* 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
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4213,15 +4377,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode 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 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4557,7 +4719,11 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4573,7 +4739,11 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -170,6 +170,14 @@ abstract class Configuration extends string {
|
|||||||
*/
|
*/
|
||||||
int explorationLimit() { none() }
|
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
|
* 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
|
* approximate distance between `node` and the closest source is `dist` and
|
||||||
@@ -485,8 +493,9 @@ private predicate additionalJumpStateStep(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -496,6 +505,37 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -573,9 +613,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -599,10 +639,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,6 +660,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -712,9 +762,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -740,10 +790,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -762,7 +812,8 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
pragma[nomagic]
|
||||||
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -861,8 +912,8 @@ private module Stage1 {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -872,7 +923,10 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
@@ -1147,11 +1201,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
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]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1574,7 +1643,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1612,10 +1681,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1706,7 +1789,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1729,9 +1813,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1752,8 +1836,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1926,7 +2010,34 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1935,8 +2046,13 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2363,7 +2479,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -2401,10 +2517,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3190,7 +3320,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3228,10 +3358,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3300,17 +3444,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -3506,7 +3661,7 @@ private newtype TPathNode =
|
|||||||
* of dereference operations needed to get from the value in the node to the
|
* 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.
|
* tracked object. The final type indicates the type of the tracked object.
|
||||||
*/
|
*/
|
||||||
abstract private class AccessPath extends TAccessPath {
|
private class AccessPath extends TAccessPath {
|
||||||
/** Gets the head of this access path, if any. */
|
/** Gets the head of this access path, if any. */
|
||||||
abstract TypedContent getHead();
|
abstract TypedContent getHead();
|
||||||
|
|
||||||
@@ -3721,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode {
|
|||||||
abstract NodeEx getNodeEx();
|
abstract NodeEx getNodeEx();
|
||||||
|
|
||||||
predicate isHidden() {
|
predicate isHidden() {
|
||||||
hiddenNode(this.getNodeEx().asNode()) and
|
not this.getConfiguration().includeHiddenNodes() and
|
||||||
not this.isSource() and
|
(
|
||||||
not this instanceof PathNodeSink
|
hiddenNode(this.getNodeEx().asNode()) and
|
||||||
or
|
not this.isSource() and
|
||||||
this.getNodeEx() instanceof TNodeImplicitRead
|
not this instanceof PathNodeSink
|
||||||
|
or
|
||||||
|
this.getNodeEx() instanceof TNodeImplicitRead
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ppAp() {
|
private string ppAp() {
|
||||||
@@ -4202,10 +4360,16 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* 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
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4213,15 +4377,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode 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 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4557,7 +4719,11 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4573,7 +4739,11 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -216,10 +216,9 @@ private module LambdaFlow {
|
|||||||
or
|
or
|
||||||
// jump step
|
// jump step
|
||||||
exists(Node mid, DataFlowType t0 |
|
exists(Node mid, DataFlowType t0 |
|
||||||
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and
|
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, lastCall) and
|
||||||
toReturn = false and
|
toReturn = false and
|
||||||
toJump = true and
|
toJump = true
|
||||||
lastCall = TDataFlowCallNone()
|
|
||||||
|
|
|
|
||||||
jumpStepCached(node, mid) and
|
jumpStepCached(node, mid) and
|
||||||
t = t0
|
t = t0
|
||||||
@@ -305,7 +304,7 @@ cached
|
|||||||
private module Cached {
|
private module Cached {
|
||||||
/**
|
/**
|
||||||
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
|
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
|
||||||
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
|
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and thereby
|
||||||
* collapsing the two stages.
|
* collapsing the two stages.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
@@ -326,7 +325,10 @@ private module Cached {
|
|||||||
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
|
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
|
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) }
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||||
@@ -373,7 +375,7 @@ private module Cached {
|
|||||||
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
||||||
// is obtained by popping the head of the access path stack) is compatible with
|
// is obtained by popping the head of the access path stack) is compatible with
|
||||||
// the type of `x.f`.
|
// the type of `x.f`.
|
||||||
read(_, _, n)
|
readSet(_, _, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
@@ -469,7 +471,7 @@ private module Cached {
|
|||||||
// read
|
// read
|
||||||
exists(Node mid |
|
exists(Node mid |
|
||||||
parameterValueFlowCand(p, mid, false) and
|
parameterValueFlowCand(p, mid, false) and
|
||||||
read(mid, _, node) and
|
readSet(mid, _, node) and
|
||||||
read = true
|
read = true
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -657,8 +659,10 @@ private module Cached {
|
|||||||
* Holds if `arg` flows to `out` through a call using only
|
* Holds if `arg` flows to `out` through a call using only
|
||||||
* value-preserving steps and a single read step, not taking call
|
* value-preserving steps and a single read step, not taking call
|
||||||
* contexts into account, thus representing a getter-step.
|
* contexts into account, thus representing a getter-step.
|
||||||
|
*
|
||||||
|
* This predicate is exposed for testing only.
|
||||||
*/
|
*/
|
||||||
predicate getterStep(ArgNode arg, Content c, Node out) {
|
predicate getterStep(ArgNode arg, ContentSet c, Node out) {
|
||||||
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -781,8 +785,12 @@ private module Cached {
|
|||||||
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate store(
|
cached
|
||||||
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
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
|
storeStep(node1, c, node2) and
|
||||||
contentType = getNodeDataFlowType(node1) and
|
contentType = getNodeDataFlowType(node1) and
|
||||||
@@ -794,14 +802,19 @@ private module Cached {
|
|||||||
|
|
|
|
||||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
||||||
or
|
or
|
||||||
read(n2, c, n1) and
|
readSet(n2, c, n1) and
|
||||||
contentType = getNodeDataFlowType(n1) and
|
contentType = getNodeDataFlowType(n1) and
|
||||||
containerType = getNodeDataFlowType(n2)
|
containerType = getNodeDataFlowType(n2)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
private predicate store(
|
||||||
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
|
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||||
|
) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
c = cs.getAStoreContent() and storeSet(node1, cs, node2, contentType, containerType)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if data can flow from `node1` to `node2` via a direct assignment to
|
* Holds if data can flow from `node1` to `node2` via a direct assignment to
|
||||||
@@ -932,16 +945,16 @@ class CastingNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private predicate readStepWithTypes(
|
private predicate readStepWithTypes(
|
||||||
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
|
Node n1, DataFlowType container, ContentSet c, Node n2, DataFlowType content
|
||||||
) {
|
) {
|
||||||
read(n1, c, n2) and
|
readSet(n1, c, n2) and
|
||||||
container = getNodeDataFlowType(n1) and
|
container = getNodeDataFlowType(n1) and
|
||||||
content = getNodeDataFlowType(n2)
|
content = getNodeDataFlowType(n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
private newtype TReadStepTypesOption =
|
private newtype TReadStepTypesOption =
|
||||||
TReadStepTypesNone() or
|
TReadStepTypesNone() or
|
||||||
TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) {
|
TReadStepTypesSome(DataFlowType container, ContentSet c, DataFlowType content) {
|
||||||
readStepWithTypes(_, container, c, _, content)
|
readStepWithTypes(_, container, c, _, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -950,7 +963,7 @@ private class ReadStepTypesOption extends TReadStepTypesOption {
|
|||||||
|
|
||||||
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
|
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
|
||||||
|
|
||||||
Content getContent() { this = TReadStepTypesSome(_, result, _) }
|
ContentSet getContent() { this = TReadStepTypesSome(_, result, _) }
|
||||||
|
|
||||||
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
|
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
|
||||||
|
|
||||||
@@ -1325,8 +1338,6 @@ abstract class AccessPathFront extends TAccessPathFront {
|
|||||||
abstract boolean toBoolNonEmpty();
|
abstract boolean toBoolNonEmpty();
|
||||||
|
|
||||||
TypedContent getHead() { this = TFrontHead(result) }
|
TypedContent getHead() { this = TFrontHead(result) }
|
||||||
|
|
||||||
predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -170,6 +170,14 @@ abstract class Configuration extends string {
|
|||||||
*/
|
*/
|
||||||
int explorationLimit() { none() }
|
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
|
* 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
|
* approximate distance between `node` and the closest source is `dist` and
|
||||||
@@ -485,8 +493,9 @@ private predicate additionalJumpStateStep(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -496,6 +505,37 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -573,9 +613,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -599,10 +639,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,6 +660,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -712,9 +762,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -740,10 +790,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -762,7 +812,8 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
pragma[nomagic]
|
||||||
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -861,8 +912,8 @@ private module Stage1 {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -872,7 +923,10 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
@@ -1147,11 +1201,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
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]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1574,7 +1643,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1612,10 +1681,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1706,7 +1789,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1729,9 +1813,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1752,8 +1836,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1926,7 +2010,34 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1935,8 +2046,13 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2363,7 +2479,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -2401,10 +2517,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3190,7 +3320,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3228,10 +3358,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3300,17 +3444,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -3506,7 +3661,7 @@ private newtype TPathNode =
|
|||||||
* of dereference operations needed to get from the value in the node to the
|
* 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.
|
* tracked object. The final type indicates the type of the tracked object.
|
||||||
*/
|
*/
|
||||||
abstract private class AccessPath extends TAccessPath {
|
private class AccessPath extends TAccessPath {
|
||||||
/** Gets the head of this access path, if any. */
|
/** Gets the head of this access path, if any. */
|
||||||
abstract TypedContent getHead();
|
abstract TypedContent getHead();
|
||||||
|
|
||||||
@@ -3721,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode {
|
|||||||
abstract NodeEx getNodeEx();
|
abstract NodeEx getNodeEx();
|
||||||
|
|
||||||
predicate isHidden() {
|
predicate isHidden() {
|
||||||
hiddenNode(this.getNodeEx().asNode()) and
|
not this.getConfiguration().includeHiddenNodes() and
|
||||||
not this.isSource() and
|
(
|
||||||
not this instanceof PathNodeSink
|
hiddenNode(this.getNodeEx().asNode()) and
|
||||||
or
|
not this.isSource() and
|
||||||
this.getNodeEx() instanceof TNodeImplicitRead
|
not this instanceof PathNodeSink
|
||||||
|
or
|
||||||
|
this.getNodeEx() instanceof TNodeImplicitRead
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ppAp() {
|
private string ppAp() {
|
||||||
@@ -4202,10 +4360,16 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* 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
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4213,15 +4377,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode 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 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4557,7 +4719,11 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4573,7 +4739,11 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -198,6 +198,12 @@ predicate clearsContent(Node n, Content c) {
|
|||||||
none() // stub implementation
|
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. */
|
/** Gets the type of `n` used for type pruning. */
|
||||||
Type getNodeType(Node n) {
|
Type getNodeType(Node n) {
|
||||||
suppressUnusedNode(n) and
|
suppressUnusedNode(n) and
|
||||||
|
|||||||
@@ -821,6 +821,34 @@ private class CollectionContent extends Content, TCollectionContent {
|
|||||||
override string toString() { result = "<element>" }
|
override string toString() { result = "<element>" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity that represents a set of `Content`s.
|
||||||
|
*
|
||||||
|
* The set may be interpreted differently depending on whether it is
|
||||||
|
* stored into (`getAStoreContent`) or read from (`getAReadContent`).
|
||||||
|
*/
|
||||||
|
class ContentSet instanceof Content {
|
||||||
|
/** Gets a content that may be stored into when storing into this set. */
|
||||||
|
Content getAStoreContent() { result = this }
|
||||||
|
|
||||||
|
/** Gets a content that may be read from when reading from this set. */
|
||||||
|
Content getAReadContent() { result = this }
|
||||||
|
|
||||||
|
/** Gets a textual representation of this content set. */
|
||||||
|
string toString() { result = super.toString() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this element is at the specified location.
|
||||||
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
|
* For more information, see
|
||||||
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
|
*/
|
||||||
|
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||||
|
super.hasLocationInfo(path, sl, sc, el, ec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A guard that validates some expression.
|
* A guard that validates some expression.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -549,7 +549,7 @@ module FlowVar_internal {
|
|||||||
bb = this.(Loop).getStmt() and
|
bb = this.(Loop).getStmt() and
|
||||||
v = this.getARelevantVariable()
|
v = this.getARelevantVariable()
|
||||||
or
|
or
|
||||||
this.reachesWithoutAssignment(bb.getAPredecessor(), v) and
|
this.reachesWithoutAssignment(pragma[only_bind_out](bb.getAPredecessor()), v) and
|
||||||
this.bbInLoop(bb)
|
this.bbInLoop(bb)
|
||||||
) and
|
) and
|
||||||
not assignsToVar(bb, v)
|
not assignsToVar(bb, v)
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||||
defaultImplicitTaintRead(node, c)
|
defaultImplicitTaintRead(node, c)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||||
defaultImplicitTaintRead(node, c)
|
defaultImplicitTaintRead(node, c)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -170,6 +170,14 @@ abstract class Configuration extends string {
|
|||||||
*/
|
*/
|
||||||
int explorationLimit() { none() }
|
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
|
* 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
|
* approximate distance between `node` and the closest source is `dist` and
|
||||||
@@ -485,8 +493,9 @@ private predicate additionalJumpStateStep(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -496,6 +505,37 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -573,9 +613,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -599,10 +639,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,6 +660,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -712,9 +762,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -740,10 +790,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -762,7 +812,8 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
pragma[nomagic]
|
||||||
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -861,8 +912,8 @@ private module Stage1 {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -872,7 +923,10 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
@@ -1147,11 +1201,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
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]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1574,7 +1643,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1612,10 +1681,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1706,7 +1789,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1729,9 +1813,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1752,8 +1836,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1926,7 +2010,34 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1935,8 +2046,13 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2363,7 +2479,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -2401,10 +2517,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3190,7 +3320,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3228,10 +3358,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3300,17 +3444,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -3506,7 +3661,7 @@ private newtype TPathNode =
|
|||||||
* of dereference operations needed to get from the value in the node to the
|
* 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.
|
* tracked object. The final type indicates the type of the tracked object.
|
||||||
*/
|
*/
|
||||||
abstract private class AccessPath extends TAccessPath {
|
private class AccessPath extends TAccessPath {
|
||||||
/** Gets the head of this access path, if any. */
|
/** Gets the head of this access path, if any. */
|
||||||
abstract TypedContent getHead();
|
abstract TypedContent getHead();
|
||||||
|
|
||||||
@@ -3721,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode {
|
|||||||
abstract NodeEx getNodeEx();
|
abstract NodeEx getNodeEx();
|
||||||
|
|
||||||
predicate isHidden() {
|
predicate isHidden() {
|
||||||
hiddenNode(this.getNodeEx().asNode()) and
|
not this.getConfiguration().includeHiddenNodes() and
|
||||||
not this.isSource() and
|
(
|
||||||
not this instanceof PathNodeSink
|
hiddenNode(this.getNodeEx().asNode()) and
|
||||||
or
|
not this.isSource() and
|
||||||
this.getNodeEx() instanceof TNodeImplicitRead
|
not this instanceof PathNodeSink
|
||||||
|
or
|
||||||
|
this.getNodeEx() instanceof TNodeImplicitRead
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ppAp() {
|
private string ppAp() {
|
||||||
@@ -4202,10 +4360,16 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* 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
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4213,15 +4377,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode 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 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4557,7 +4719,11 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4573,7 +4739,11 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -170,6 +170,14 @@ abstract class Configuration extends string {
|
|||||||
*/
|
*/
|
||||||
int explorationLimit() { none() }
|
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
|
* 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
|
* approximate distance between `node` and the closest source is `dist` and
|
||||||
@@ -485,8 +493,9 @@ private predicate additionalJumpStateStep(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -496,6 +505,37 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -573,9 +613,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -599,10 +639,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,6 +660,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -712,9 +762,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -740,10 +790,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -762,7 +812,8 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
pragma[nomagic]
|
||||||
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -861,8 +912,8 @@ private module Stage1 {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -872,7 +923,10 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
@@ -1147,11 +1201,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
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]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1574,7 +1643,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1612,10 +1681,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1706,7 +1789,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1729,9 +1813,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1752,8 +1836,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1926,7 +2010,34 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1935,8 +2046,13 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2363,7 +2479,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -2401,10 +2517,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3190,7 +3320,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3228,10 +3358,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3300,17 +3444,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -3506,7 +3661,7 @@ private newtype TPathNode =
|
|||||||
* of dereference operations needed to get from the value in the node to the
|
* 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.
|
* tracked object. The final type indicates the type of the tracked object.
|
||||||
*/
|
*/
|
||||||
abstract private class AccessPath extends TAccessPath {
|
private class AccessPath extends TAccessPath {
|
||||||
/** Gets the head of this access path, if any. */
|
/** Gets the head of this access path, if any. */
|
||||||
abstract TypedContent getHead();
|
abstract TypedContent getHead();
|
||||||
|
|
||||||
@@ -3721,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode {
|
|||||||
abstract NodeEx getNodeEx();
|
abstract NodeEx getNodeEx();
|
||||||
|
|
||||||
predicate isHidden() {
|
predicate isHidden() {
|
||||||
hiddenNode(this.getNodeEx().asNode()) and
|
not this.getConfiguration().includeHiddenNodes() and
|
||||||
not this.isSource() and
|
(
|
||||||
not this instanceof PathNodeSink
|
hiddenNode(this.getNodeEx().asNode()) and
|
||||||
or
|
not this.isSource() and
|
||||||
this.getNodeEx() instanceof TNodeImplicitRead
|
not this instanceof PathNodeSink
|
||||||
|
or
|
||||||
|
this.getNodeEx() instanceof TNodeImplicitRead
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ppAp() {
|
private string ppAp() {
|
||||||
@@ -4202,10 +4360,16 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* 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
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4213,15 +4377,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode 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 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4557,7 +4719,11 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4573,7 +4739,11 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -170,6 +170,14 @@ abstract class Configuration extends string {
|
|||||||
*/
|
*/
|
||||||
int explorationLimit() { none() }
|
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
|
* 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
|
* approximate distance between `node` and the closest source is `dist` and
|
||||||
@@ -485,8 +493,9 @@ private predicate additionalJumpStateStep(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -496,6 +505,37 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -573,9 +613,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -599,10 +639,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,6 +660,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -712,9 +762,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -740,10 +790,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -762,7 +812,8 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
pragma[nomagic]
|
||||||
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -861,8 +912,8 @@ private module Stage1 {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -872,7 +923,10 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
@@ -1147,11 +1201,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
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]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1574,7 +1643,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1612,10 +1681,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1706,7 +1789,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1729,9 +1813,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1752,8 +1836,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1926,7 +2010,34 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1935,8 +2046,13 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2363,7 +2479,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -2401,10 +2517,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3190,7 +3320,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3228,10 +3358,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3300,17 +3444,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -3506,7 +3661,7 @@ private newtype TPathNode =
|
|||||||
* of dereference operations needed to get from the value in the node to the
|
* 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.
|
* tracked object. The final type indicates the type of the tracked object.
|
||||||
*/
|
*/
|
||||||
abstract private class AccessPath extends TAccessPath {
|
private class AccessPath extends TAccessPath {
|
||||||
/** Gets the head of this access path, if any. */
|
/** Gets the head of this access path, if any. */
|
||||||
abstract TypedContent getHead();
|
abstract TypedContent getHead();
|
||||||
|
|
||||||
@@ -3721,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode {
|
|||||||
abstract NodeEx getNodeEx();
|
abstract NodeEx getNodeEx();
|
||||||
|
|
||||||
predicate isHidden() {
|
predicate isHidden() {
|
||||||
hiddenNode(this.getNodeEx().asNode()) and
|
not this.getConfiguration().includeHiddenNodes() and
|
||||||
not this.isSource() and
|
(
|
||||||
not this instanceof PathNodeSink
|
hiddenNode(this.getNodeEx().asNode()) and
|
||||||
or
|
not this.isSource() and
|
||||||
this.getNodeEx() instanceof TNodeImplicitRead
|
not this instanceof PathNodeSink
|
||||||
|
or
|
||||||
|
this.getNodeEx() instanceof TNodeImplicitRead
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ppAp() {
|
private string ppAp() {
|
||||||
@@ -4202,10 +4360,16 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* 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
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4213,15 +4377,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode 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 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4557,7 +4719,11 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4573,7 +4739,11 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -170,6 +170,14 @@ abstract class Configuration extends string {
|
|||||||
*/
|
*/
|
||||||
int explorationLimit() { none() }
|
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
|
* 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
|
* approximate distance between `node` and the closest source is `dist` and
|
||||||
@@ -485,8 +493,9 @@ private predicate additionalJumpStateStep(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -496,6 +505,37 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -573,9 +613,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -599,10 +639,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,6 +660,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -712,9 +762,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -740,10 +790,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -762,7 +812,8 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
pragma[nomagic]
|
||||||
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -861,8 +912,8 @@ private module Stage1 {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -872,7 +923,10 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
@@ -1147,11 +1201,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
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]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1574,7 +1643,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1612,10 +1681,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1706,7 +1789,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1729,9 +1813,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1752,8 +1836,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1926,7 +2010,34 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1935,8 +2046,13 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2363,7 +2479,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -2401,10 +2517,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3190,7 +3320,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3228,10 +3358,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, 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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3300,17 +3444,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -3506,7 +3661,7 @@ private newtype TPathNode =
|
|||||||
* of dereference operations needed to get from the value in the node to the
|
* 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.
|
* tracked object. The final type indicates the type of the tracked object.
|
||||||
*/
|
*/
|
||||||
abstract private class AccessPath extends TAccessPath {
|
private class AccessPath extends TAccessPath {
|
||||||
/** Gets the head of this access path, if any. */
|
/** Gets the head of this access path, if any. */
|
||||||
abstract TypedContent getHead();
|
abstract TypedContent getHead();
|
||||||
|
|
||||||
@@ -3721,11 +3876,14 @@ abstract private class PathNodeImpl extends PathNode {
|
|||||||
abstract NodeEx getNodeEx();
|
abstract NodeEx getNodeEx();
|
||||||
|
|
||||||
predicate isHidden() {
|
predicate isHidden() {
|
||||||
hiddenNode(this.getNodeEx().asNode()) and
|
not this.getConfiguration().includeHiddenNodes() and
|
||||||
not this.isSource() and
|
(
|
||||||
not this instanceof PathNodeSink
|
hiddenNode(this.getNodeEx().asNode()) and
|
||||||
or
|
not this.isSource() and
|
||||||
this.getNodeEx() instanceof TNodeImplicitRead
|
not this instanceof PathNodeSink
|
||||||
|
or
|
||||||
|
this.getNodeEx() instanceof TNodeImplicitRead
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ppAp() {
|
private string ppAp() {
|
||||||
@@ -4202,10 +4360,16 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* 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
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4213,15 +4377,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode 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 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4557,7 +4719,11 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4573,7 +4739,11 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -216,10 +216,9 @@ private module LambdaFlow {
|
|||||||
or
|
or
|
||||||
// jump step
|
// jump step
|
||||||
exists(Node mid, DataFlowType t0 |
|
exists(Node mid, DataFlowType t0 |
|
||||||
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and
|
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, lastCall) and
|
||||||
toReturn = false and
|
toReturn = false and
|
||||||
toJump = true and
|
toJump = true
|
||||||
lastCall = TDataFlowCallNone()
|
|
||||||
|
|
|
|
||||||
jumpStepCached(node, mid) and
|
jumpStepCached(node, mid) and
|
||||||
t = t0
|
t = t0
|
||||||
@@ -305,7 +304,7 @@ cached
|
|||||||
private module Cached {
|
private module Cached {
|
||||||
/**
|
/**
|
||||||
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
|
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
|
||||||
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
|
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and thereby
|
||||||
* collapsing the two stages.
|
* collapsing the two stages.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
@@ -326,7 +325,10 @@ private module Cached {
|
|||||||
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
|
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
|
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) }
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||||
@@ -373,7 +375,7 @@ private module Cached {
|
|||||||
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
||||||
// is obtained by popping the head of the access path stack) is compatible with
|
// is obtained by popping the head of the access path stack) is compatible with
|
||||||
// the type of `x.f`.
|
// the type of `x.f`.
|
||||||
read(_, _, n)
|
readSet(_, _, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
@@ -469,7 +471,7 @@ private module Cached {
|
|||||||
// read
|
// read
|
||||||
exists(Node mid |
|
exists(Node mid |
|
||||||
parameterValueFlowCand(p, mid, false) and
|
parameterValueFlowCand(p, mid, false) and
|
||||||
read(mid, _, node) and
|
readSet(mid, _, node) and
|
||||||
read = true
|
read = true
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -657,8 +659,10 @@ private module Cached {
|
|||||||
* Holds if `arg` flows to `out` through a call using only
|
* Holds if `arg` flows to `out` through a call using only
|
||||||
* value-preserving steps and a single read step, not taking call
|
* value-preserving steps and a single read step, not taking call
|
||||||
* contexts into account, thus representing a getter-step.
|
* contexts into account, thus representing a getter-step.
|
||||||
|
*
|
||||||
|
* This predicate is exposed for testing only.
|
||||||
*/
|
*/
|
||||||
predicate getterStep(ArgNode arg, Content c, Node out) {
|
predicate getterStep(ArgNode arg, ContentSet c, Node out) {
|
||||||
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -781,8 +785,12 @@ private module Cached {
|
|||||||
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate store(
|
cached
|
||||||
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
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
|
storeStep(node1, c, node2) and
|
||||||
contentType = getNodeDataFlowType(node1) and
|
contentType = getNodeDataFlowType(node1) and
|
||||||
@@ -794,14 +802,19 @@ private module Cached {
|
|||||||
|
|
|
|
||||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
||||||
or
|
or
|
||||||
read(n2, c, n1) and
|
readSet(n2, c, n1) and
|
||||||
contentType = getNodeDataFlowType(n1) and
|
contentType = getNodeDataFlowType(n1) and
|
||||||
containerType = getNodeDataFlowType(n2)
|
containerType = getNodeDataFlowType(n2)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
private predicate store(
|
||||||
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
|
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||||
|
) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
c = cs.getAStoreContent() and storeSet(node1, cs, node2, contentType, containerType)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if data can flow from `node1` to `node2` via a direct assignment to
|
* Holds if data can flow from `node1` to `node2` via a direct assignment to
|
||||||
@@ -932,16 +945,16 @@ class CastingNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private predicate readStepWithTypes(
|
private predicate readStepWithTypes(
|
||||||
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
|
Node n1, DataFlowType container, ContentSet c, Node n2, DataFlowType content
|
||||||
) {
|
) {
|
||||||
read(n1, c, n2) and
|
readSet(n1, c, n2) and
|
||||||
container = getNodeDataFlowType(n1) and
|
container = getNodeDataFlowType(n1) and
|
||||||
content = getNodeDataFlowType(n2)
|
content = getNodeDataFlowType(n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
private newtype TReadStepTypesOption =
|
private newtype TReadStepTypesOption =
|
||||||
TReadStepTypesNone() or
|
TReadStepTypesNone() or
|
||||||
TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) {
|
TReadStepTypesSome(DataFlowType container, ContentSet c, DataFlowType content) {
|
||||||
readStepWithTypes(_, container, c, _, content)
|
readStepWithTypes(_, container, c, _, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -950,7 +963,7 @@ private class ReadStepTypesOption extends TReadStepTypesOption {
|
|||||||
|
|
||||||
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
|
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
|
||||||
|
|
||||||
Content getContent() { this = TReadStepTypesSome(_, result, _) }
|
ContentSet getContent() { this = TReadStepTypesSome(_, result, _) }
|
||||||
|
|
||||||
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
|
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
|
||||||
|
|
||||||
@@ -1325,8 +1338,6 @@ abstract class AccessPathFront extends TAccessPathFront {
|
|||||||
abstract boolean toBoolNonEmpty();
|
abstract boolean toBoolNonEmpty();
|
||||||
|
|
||||||
TypedContent getHead() { this = TFrontHead(result) }
|
TypedContent getHead() { this = TFrontHead(result) }
|
||||||
|
|
||||||
predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||||
|
|||||||
@@ -279,6 +279,12 @@ predicate clearsContent(Node n, Content c) {
|
|||||||
none() // stub implementation
|
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. */
|
/** Gets the type of `n` used for type pruning. */
|
||||||
IRType getNodeType(Node n) {
|
IRType getNodeType(Node n) {
|
||||||
suppressUnusedNode(n) and
|
suppressUnusedNode(n) and
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ private module Cached {
|
|||||||
* along the chain of addresses computed by `StoreNodeInstr.getInner` to identify field writes
|
* 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
|
* and call `storeStep` accordingly (i.e., for an expression like `a.b.c = x`, we visit `c`, then
|
||||||
* `b`, then `a`).
|
* `b`, then `a`).
|
||||||
* 2. Flow is transfered from a `WriteSideEffectInstruction` to a `StoreNodeOperand` after flow
|
* 2. Flow is transferred from a `WriteSideEffectInstruction` to a `StoreNodeOperand` after flow
|
||||||
* returns to a caller. Flow will then proceed to the defining instruction of the operand (because
|
* 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 `StoreNodeInstr` computed by `StoreNodeOperand.getInner()` is the `StoreNode` containing
|
||||||
* the defining instruction), and then along the chain computed by `StoreNodeInstr.getInner` like
|
* the defining instruction), and then along the chain computed by `StoreNodeInstr.getInner` like
|
||||||
@@ -1063,6 +1063,34 @@ private class CollectionContent extends Content, TCollectionContent {
|
|||||||
override string toString() { result = "<element>" }
|
override string toString() { result = "<element>" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity that represents a set of `Content`s.
|
||||||
|
*
|
||||||
|
* The set may be interpreted differently depending on whether it is
|
||||||
|
* stored into (`getAStoreContent`) or read from (`getAReadContent`).
|
||||||
|
*/
|
||||||
|
class ContentSet instanceof Content {
|
||||||
|
/** Gets a content that may be stored into when storing into this set. */
|
||||||
|
Content getAStoreContent() { result = this }
|
||||||
|
|
||||||
|
/** Gets a content that may be read from when reading from this set. */
|
||||||
|
Content getAReadContent() { result = this }
|
||||||
|
|
||||||
|
/** Gets a textual representation of this content set. */
|
||||||
|
string toString() { result = super.toString() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this element is at the specified location.
|
||||||
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
|
* For more information, see
|
||||||
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
|
*/
|
||||||
|
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||||
|
super.hasLocationInfo(path, sl, sc, el, ec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A guard that validates some instruction.
|
* A guard that validates some instruction.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||||
defaultImplicitTaintRead(node, c)
|
defaultImplicitTaintRead(node, c)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||||
defaultImplicitTaintRead(node, c)
|
defaultImplicitTaintRead(node, c)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||||
defaultImplicitTaintRead(node, c)
|
defaultImplicitTaintRead(node, c)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class DefaultEdge extends EdgeKind, TDefaultEdge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A "case" edge, representing the successor of a `Switch` instruction when the
|
* A "case" edge, representing the successor of a `Switch` instruction when the
|
||||||
* the condition value matches a correponding `case` label.
|
* the condition value matches a corresponding `case` label.
|
||||||
*/
|
*/
|
||||||
class CaseEdge extends EdgeKind, TCaseEdge {
|
class CaseEdge extends EdgeKind, TCaseEdge {
|
||||||
string minValue;
|
string minValue;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class ValueNumber extends TValueNumber {
|
|||||||
final Instruction getAnInstruction() { this = valueNumber(result) }
|
final Instruction getAnInstruction() { this = valueNumber(result) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets one of the instructions that was assigned this value number. The chosen instuction is
|
* Gets one of the instructions that was assigned this value number. The chosen instruction is
|
||||||
* deterministic but arbitrary. Intended for use only in debugging.
|
* deterministic but arbitrary. Intended for use only in debugging.
|
||||||
*/
|
*/
|
||||||
final Instruction getExampleInstruction() {
|
final Instruction getExampleInstruction() {
|
||||||
|
|||||||
@@ -1005,7 +1005,7 @@ predicate canReuseSsaForMemoryResult(Instruction instruction) {
|
|||||||
deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1;
|
deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expose some of the internal predicates to PrintSSA.qll. We do this by publically importing those modules in the
|
* Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the
|
||||||
* `DebugSSA` module, which is then imported by PrintSSA.
|
* `DebugSSA` module, which is then imported by PrintSSA.
|
||||||
*/
|
*/
|
||||||
module DebugSsa {
|
module DebugSsa {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class ValueNumber extends TValueNumber {
|
|||||||
final Instruction getAnInstruction() { this = valueNumber(result) }
|
final Instruction getAnInstruction() { this = valueNumber(result) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets one of the instructions that was assigned this value number. The chosen instuction is
|
* Gets one of the instructions that was assigned this value number. The chosen instruction is
|
||||||
* deterministic but arbitrary. Intended for use only in debugging.
|
* deterministic but arbitrary. Intended for use only in debugging.
|
||||||
*/
|
*/
|
||||||
final Instruction getExampleInstruction() {
|
final Instruction getExampleInstruction() {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ private import TranslatedDeclarationEntry
|
|||||||
private import TranslatedElement
|
private import TranslatedElement
|
||||||
private import TranslatedFunction
|
private import TranslatedFunction
|
||||||
private import TranslatedInitialization
|
private import TranslatedInitialization
|
||||||
private import TranslatedFunction
|
|
||||||
private import TranslatedStmt
|
private import TranslatedStmt
|
||||||
import TranslatedCall
|
import TranslatedCall
|
||||||
|
|
||||||
|
|||||||
@@ -421,20 +421,36 @@ class TranslatedCatchAnyHandler extends TranslatedHandler {
|
|||||||
class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
|
class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
|
||||||
override IfStmt stmt;
|
override IfStmt stmt;
|
||||||
|
|
||||||
override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() }
|
override Instruction getFirstInstruction() {
|
||||||
|
if hasInitialization()
|
||||||
|
then result = getInitialization().getFirstInstruction()
|
||||||
|
else result = getFirstConditionInstruction()
|
||||||
|
}
|
||||||
|
|
||||||
override TranslatedElement getChild(int id) {
|
override TranslatedElement getChild(int id) {
|
||||||
id = 0 and result = getCondition()
|
id = 0 and result = getInitialization()
|
||||||
or
|
or
|
||||||
id = 1 and result = getThen()
|
id = 1 and result = getCondition()
|
||||||
or
|
or
|
||||||
id = 2 and result = getElse()
|
id = 2 and result = getThen()
|
||||||
|
or
|
||||||
|
id = 3 and result = getElse()
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate hasInitialization() { exists(stmt.getInitialization()) }
|
||||||
|
|
||||||
|
private TranslatedStmt getInitialization() {
|
||||||
|
result = getTranslatedStmt(stmt.getInitialization())
|
||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedCondition getCondition() {
|
private TranslatedCondition getCondition() {
|
||||||
result = getTranslatedCondition(stmt.getCondition().getFullyConverted())
|
result = getTranslatedCondition(stmt.getCondition().getFullyConverted())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Instruction getFirstConditionInstruction() {
|
||||||
|
result = getCondition().getFirstInstruction()
|
||||||
|
}
|
||||||
|
|
||||||
private TranslatedStmt getThen() { result = getTranslatedStmt(stmt.getThen()) }
|
private TranslatedStmt getThen() { result = getTranslatedStmt(stmt.getThen()) }
|
||||||
|
|
||||||
private TranslatedStmt getElse() { result = getTranslatedStmt(stmt.getElse()) }
|
private TranslatedStmt getElse() { result = getTranslatedStmt(stmt.getElse()) }
|
||||||
@@ -456,6 +472,9 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||||
|
child = getInitialization() and
|
||||||
|
result = getFirstConditionInstruction()
|
||||||
|
or
|
||||||
(child = getThen() or child = getElse()) and
|
(child = getThen() or child = getElse()) and
|
||||||
result = getParent().getChildSuccessor(this)
|
result = getParent().getChildSuccessor(this)
|
||||||
}
|
}
|
||||||
@@ -698,14 +717,28 @@ class TranslatedSwitchStmt extends TranslatedStmt {
|
|||||||
result = getTranslatedExpr(stmt.getExpr().getFullyConverted())
|
result = getTranslatedExpr(stmt.getExpr().getFullyConverted())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Instruction getFirstExprInstruction() { result = getExpr().getFirstInstruction() }
|
||||||
|
|
||||||
private TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getStmt()) }
|
private TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getStmt()) }
|
||||||
|
|
||||||
override Instruction getFirstInstruction() { result = getExpr().getFirstInstruction() }
|
override Instruction getFirstInstruction() {
|
||||||
|
if hasInitialization()
|
||||||
|
then result = getInitialization().getFirstInstruction()
|
||||||
|
else result = getFirstExprInstruction()
|
||||||
|
}
|
||||||
|
|
||||||
override TranslatedElement getChild(int id) {
|
override TranslatedElement getChild(int id) {
|
||||||
id = 0 and result = getExpr()
|
id = 0 and result = getInitialization()
|
||||||
or
|
or
|
||||||
id = 1 and result = getBody()
|
id = 1 and result = getExpr()
|
||||||
|
or
|
||||||
|
id = 2 and result = getBody()
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate hasInitialization() { exists(stmt.getInitialization()) }
|
||||||
|
|
||||||
|
private TranslatedStmt getInitialization() {
|
||||||
|
result = getTranslatedStmt(stmt.getInitialization())
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||||
@@ -735,6 +768,8 @@ class TranslatedSwitchStmt extends TranslatedStmt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||||
|
child = getInitialization() and result = getFirstExprInstruction()
|
||||||
|
or
|
||||||
child = getExpr() and result = getInstruction(SwitchBranchTag())
|
child = getExpr() and result = getInstruction(SwitchBranchTag())
|
||||||
or
|
or
|
||||||
child = getBody() and result = getParent().getChildSuccessor(this)
|
child = getBody() and result = getParent().getChildSuccessor(this)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class ValueNumber extends TValueNumber {
|
|||||||
final Instruction getAnInstruction() { this = valueNumber(result) }
|
final Instruction getAnInstruction() { this = valueNumber(result) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets one of the instructions that was assigned this value number. The chosen instuction is
|
* Gets one of the instructions that was assigned this value number. The chosen instruction is
|
||||||
* deterministic but arbitrary. Intended for use only in debugging.
|
* deterministic but arbitrary. Intended for use only in debugging.
|
||||||
*/
|
*/
|
||||||
final Instruction getExampleInstruction() {
|
final Instruction getExampleInstruction() {
|
||||||
|
|||||||
@@ -1005,7 +1005,7 @@ predicate canReuseSsaForMemoryResult(Instruction instruction) {
|
|||||||
deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1;
|
deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expose some of the internal predicates to PrintSSA.qll. We do this by publically importing those modules in the
|
* Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the
|
||||||
* `DebugSSA` module, which is then imported by PrintSSA.
|
* `DebugSSA` module, which is then imported by PrintSSA.
|
||||||
*/
|
*/
|
||||||
module DebugSsa {
|
module DebugSsa {
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ private predicate isOpaqueType(Type type) {
|
|||||||
* Holds if an `IROpaqueType` with the specified `tag` and `byteSize` should exist.
|
* Holds if an `IROpaqueType` with the specified `tag` and `byteSize` should exist.
|
||||||
*/
|
*/
|
||||||
predicate hasOpaqueType(Type tag, int byteSize) {
|
predicate hasOpaqueType(Type tag, int byteSize) {
|
||||||
isOpaqueType(tag) and byteSize = getTypeSize(tag)
|
isOpaqueType(tag) and byteSize = getTypeSize(tag.getUnspecifiedType())
|
||||||
or
|
or
|
||||||
tag instanceof UnknownType and Raw::needsUnknownOpaqueType(byteSize)
|
tag instanceof UnknownType and Raw::needsUnknownOpaqueType(byteSize)
|
||||||
}
|
}
|
||||||
@@ -153,17 +153,18 @@ private IRType getIRTypeForPRValue(Type type) {
|
|||||||
exists(Type unspecifiedType | unspecifiedType = type.getUnspecifiedType() |
|
exists(Type unspecifiedType | unspecifiedType = type.getUnspecifiedType() |
|
||||||
isOpaqueType(unspecifiedType) and
|
isOpaqueType(unspecifiedType) and
|
||||||
exists(IROpaqueType opaqueType | opaqueType = result |
|
exists(IROpaqueType opaqueType | opaqueType = result |
|
||||||
opaqueType.getByteSize() = getTypeSize(type) and
|
opaqueType.getByteSize() = getTypeSize(unspecifiedType) and
|
||||||
opaqueType.getTag() = unspecifiedType
|
opaqueType.getTag() = unspecifiedType
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
unspecifiedType instanceof BoolType and result.(IRBooleanType).getByteSize() = type.getSize()
|
unspecifiedType instanceof BoolType and
|
||||||
|
result.(IRBooleanType).getByteSize() = unspecifiedType.getSize()
|
||||||
or
|
or
|
||||||
isSignedIntegerType(unspecifiedType) and
|
isSignedIntegerType(unspecifiedType) and
|
||||||
result.(IRSignedIntegerType).getByteSize() = type.getSize()
|
result.(IRSignedIntegerType).getByteSize() = unspecifiedType.getSize()
|
||||||
or
|
or
|
||||||
isUnsignedIntegerType(unspecifiedType) and
|
isUnsignedIntegerType(unspecifiedType) and
|
||||||
result.(IRUnsignedIntegerType).getByteSize() = type.getSize()
|
result.(IRUnsignedIntegerType).getByteSize() = unspecifiedType.getSize()
|
||||||
or
|
or
|
||||||
exists(FloatingPointType floatType, IRFloatingPointType irFloatType |
|
exists(FloatingPointType floatType, IRFloatingPointType irFloatType |
|
||||||
floatType = unspecifiedType and
|
floatType = unspecifiedType and
|
||||||
@@ -173,7 +174,8 @@ private IRType getIRTypeForPRValue(Type type) {
|
|||||||
irFloatType.getDomain() = floatType.getDomain()
|
irFloatType.getDomain() = floatType.getDomain()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
isPointerIshType(unspecifiedType) and result.(IRAddressType).getByteSize() = getTypeSize(type)
|
isPointerIshType(unspecifiedType) and
|
||||||
|
result.(IRAddressType).getByteSize() = getTypeSize(unspecifiedType)
|
||||||
or
|
or
|
||||||
unspecifiedType instanceof FunctionPointerIshType and
|
unspecifiedType instanceof FunctionPointerIshType and
|
||||||
result.(IRFunctionAddressType).getByteSize() = getTypeSize(type)
|
result.(IRFunctionAddressType).getByteSize() = getTypeSize(type)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user