mirror of
https://github.com/github/codeql.git
synced 2026-07-05 11:35:30 +02:00
Compare commits
1 Commits
codeql-cli
...
codeql-ci-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
375a4f3c69 |
8
.bazelrc
8
.bazelrc
@@ -1,9 +1,3 @@
|
|||||||
common --enable_platform_specific_config
|
build --repo_env=CC=clang --repo_env=CXX=clang++ --cxxopt="-std=c++17"
|
||||||
|
|
||||||
build --repo_env=CC=clang --repo_env=CXX=clang++
|
|
||||||
|
|
||||||
build:linux --cxxopt=-std=c++20
|
|
||||||
build:macos --cxxopt=-std=c++20 --cpu=darwin_x86_64
|
|
||||||
build:windows --cxxopt=/std:c++20 --cxxopt=/Zc:preprocessor
|
|
||||||
|
|
||||||
try-import %workspace%/local.bazelrc
|
try-import %workspace%/local.bazelrc
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
6.3.1
|
6.1.2
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"extensions": [
|
"extensions": [
|
||||||
"rust-lang.rust-analyzer",
|
"rust-lang.rust",
|
||||||
"bungcip.better-toml",
|
"bungcip.better-toml",
|
||||||
"github.vscode-codeql",
|
"github.vscode-codeql",
|
||||||
"hbenl.vscode-test-explorer",
|
"hbenl.vscode-test-explorer",
|
||||||
|
|||||||
3
.github/labeler.yml
vendored
3
.github/labeler.yml
vendored
@@ -11,7 +11,7 @@ Go:
|
|||||||
- change-notes/**/*go.*
|
- change-notes/**/*go.*
|
||||||
|
|
||||||
Java:
|
Java:
|
||||||
- any: [ 'java/**/*', '!java/kotlin-extractor/**/*', '!java/ql/test/kotlin/**/*' ]
|
- any: [ 'java/**/*', '!java/kotlin-extractor/**/*', '!java/kotlin-explorer/**/*', '!java/ql/test/kotlin/**/*' ]
|
||||||
- change-notes/**/*java.*
|
- change-notes/**/*java.*
|
||||||
|
|
||||||
JS:
|
JS:
|
||||||
@@ -20,6 +20,7 @@ JS:
|
|||||||
|
|
||||||
Kotlin:
|
Kotlin:
|
||||||
- java/kotlin-extractor/**/*
|
- java/kotlin-extractor/**/*
|
||||||
|
- java/kotlin-explorer/**/*
|
||||||
- java/ql/test/kotlin/**/*
|
- java/ql/test/kotlin/**/*
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
|||||||
5
.github/workflows/check-change-note.yml
vendored
5
.github/workflows/check-change-note.yml
vendored
@@ -11,6 +11,7 @@ on:
|
|||||||
- "*/ql/lib/**/*.yml"
|
- "*/ql/lib/**/*.yml"
|
||||||
- "!**/experimental/**"
|
- "!**/experimental/**"
|
||||||
- "!ql/**"
|
- "!ql/**"
|
||||||
|
- "!swift/**"
|
||||||
- ".github/workflows/check-change-note.yml"
|
- ".github/workflows/check-change-note.yml"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -26,9 +27,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
gh api 'repos/${{github.repository}}/pulls/${{github.event.number}}/files' --paginate --jq 'any(.[].filename ; test("/change-notes/.*[.]md$"))' |
|
gh api 'repos/${{github.repository}}/pulls/${{github.event.number}}/files' --paginate --jq 'any(.[].filename ; test("/change-notes/.*[.]md$"))' |
|
||||||
grep true -c
|
grep true -c
|
||||||
- name: Fail if the change note filename doesn't match the expected format. The file name must be of the form 'YYYY-MM-DD.md', 'YYYY-MM-DD-{title}.md', where '{title}' is arbitrary text, or released/x.y.z.md for released change-notes
|
- name: Fail if the change note filename doesn't match the expected format. The file name must be of the form 'YYYY-MM-DD.md' or 'YYYY-MM-DD-{title}.md', where '{title}' is arbitrary text.
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
gh api 'repos/${{github.repository}}/pulls/${{github.event.number}}/files' --paginate --jq '[.[].filename | select(test("/change-notes/.*[.]md$"))] | all(test("/change-notes/[0-9]{4}-[0-9]{2}-[0-9]{2}.*[.]md$") or test("/change-notes/released/[0-9]*[.][0-9]*[.][0-9]*[.]md$"))' |
|
gh api 'repos/${{github.repository}}/pulls/${{github.event.number}}/files' --paginate --jq '[.[].filename | select(test("/change-notes/.*[.]md$"))] | all(test("/change-notes/[0-9]{4}-[0-9]{2}-[0-9]{2}.*[.]md$"))' |
|
||||||
grep true -c
|
grep true -c
|
||||||
|
|||||||
29
.github/workflows/check-implicit-this.yml
vendored
29
.github/workflows/check-implicit-this.yml
vendored
@@ -1,29 +0,0 @@
|
|||||||
name: "Check implicit this warnings"
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- "**qlpack.yml"
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- "rc/*"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Check that implicit this warnings is enabled for all packs
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
EXIT_CODE=0
|
|
||||||
packs="$(find . -iname 'qlpack.yml')"
|
|
||||||
for pack_file in ${packs}; do
|
|
||||||
option="$(yq '.warnOnImplicitThis' ${pack_file})"
|
|
||||||
if [ "${option}" != "true" ]; then
|
|
||||||
echo "::error file=${pack_file}::warnOnImplicitThis property must be set to 'true' for pack ${pack_file}"
|
|
||||||
EXIT_CODE=1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
exit "${EXIT_CODE}"
|
|
||||||
@@ -10,7 +10,6 @@ on:
|
|||||||
- "*/ql/src/**/*.qll"
|
- "*/ql/src/**/*.qll"
|
||||||
- "*/ql/lib/**/*.ql"
|
- "*/ql/lib/**/*.ql"
|
||||||
- "*/ql/lib/**/*.qll"
|
- "*/ql/lib/**/*.qll"
|
||||||
- "*/ql/lib/ext/**/*.yml"
|
|
||||||
- "misc/scripts/library-coverage/*.py"
|
- "misc/scripts/library-coverage/*.py"
|
||||||
# input data files
|
# input data files
|
||||||
- "*/documentation/library-coverage/cwe-sink.csv"
|
- "*/documentation/library-coverage/cwe-sink.csv"
|
||||||
|
|||||||
10
.github/workflows/go-tests-other-os.yml
vendored
10
.github/workflows/go-tests-other-os.yml
vendored
@@ -7,17 +7,15 @@ on:
|
|||||||
- .github/workflows/go-tests-other-os.yml
|
- .github/workflows/go-tests-other-os.yml
|
||||||
- .github/actions/**
|
- .github/actions/**
|
||||||
- codeql-workspace.yml
|
- codeql-workspace.yml
|
||||||
env:
|
|
||||||
GO_VERSION: '~1.21.0'
|
|
||||||
jobs:
|
jobs:
|
||||||
test-mac:
|
test-mac:
|
||||||
name: Test MacOS
|
name: Test MacOS
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Go ${{ env.GO_VERSION }}
|
- name: Set up Go 1.20
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.GO_VERSION }}
|
go-version: '1.20'
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
@@ -49,10 +47,10 @@ jobs:
|
|||||||
name: Test Windows
|
name: Test Windows
|
||||||
runs-on: windows-latest-xl
|
runs-on: windows-latest-xl
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Go ${{ env.GO_VERSION }}
|
- name: Set up Go 1.20
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.GO_VERSION }}
|
go-version: '1.20'
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
|
|||||||
6
.github/workflows/go-tests.yml
vendored
6
.github/workflows/go-tests.yml
vendored
@@ -15,17 +15,15 @@ on:
|
|||||||
- .github/workflows/go-tests.yml
|
- .github/workflows/go-tests.yml
|
||||||
- .github/actions/**
|
- .github/actions/**
|
||||||
- codeql-workspace.yml
|
- codeql-workspace.yml
|
||||||
env:
|
|
||||||
GO_VERSION: '~1.21.0'
|
|
||||||
jobs:
|
jobs:
|
||||||
test-linux:
|
test-linux:
|
||||||
name: Test Linux (Ubuntu)
|
name: Test Linux (Ubuntu)
|
||||||
runs-on: ubuntu-latest-xl
|
runs-on: ubuntu-latest-xl
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Go ${{ env.GO_VERSION }}
|
- name: Set up Go 1.20
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.GO_VERSION }}
|
go-version: '1.20'
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
|
|||||||
2
.github/workflows/ql-for-ql-build.yml
vendored
2
.github/workflows/ql-for-ql-build.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
ql/extractor-pack/
|
ql/extractor-pack/
|
||||||
ql/target/release/buramu
|
ql/target/release/buramu
|
||||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('shared/tree-sitter-extractor') }}-${{ hashFiles('ql/**/*.rs') }}
|
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-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@v3
|
uses: actions/cache@v3
|
||||||
|
|||||||
2
.github/workflows/ruby-build.yml
vendored
2
.github/workflows/ruby-build.yml
vendored
@@ -61,7 +61,7 @@ jobs:
|
|||||||
ruby/extractor/target/release/codeql-extractor-ruby
|
ruby/extractor/target/release/codeql-extractor-ruby
|
||||||
ruby/extractor/target/release/codeql-extractor-ruby.exe
|
ruby/extractor/target/release/codeql-extractor-ruby.exe
|
||||||
ruby/extractor/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
ruby/extractor/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/Cargo.lock') }}-${{ hashFiles('shared/tree-sitter-extractor') }}-${{ hashFiles('ruby/extractor/**/*.rs') }}
|
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/Cargo.lock') }}--${{ hashFiles('ruby/extractor/**/*.rs') }}
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v3
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
|
|||||||
1
.github/workflows/ruby-qltest.yml
vendored
1
.github/workflows/ruby-qltest.yml
vendored
@@ -14,7 +14,6 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- "ruby/**"
|
- "ruby/**"
|
||||||
- "shared/**"
|
|
||||||
- .github/workflows/ruby-qltest.yml
|
- .github/workflows/ruby-qltest.yml
|
||||||
- .github/actions/fetch-codeql/action.yml
|
- .github/actions/fetch-codeql/action.yml
|
||||||
- codeql-workspace.yml
|
- codeql-workspace.yml
|
||||||
|
|||||||
2
.github/workflows/swift.yml
vendored
2
.github/workflows/swift.yml
vendored
@@ -16,7 +16,6 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- rc/*
|
- rc/*
|
||||||
- codeql-cli-*
|
|
||||||
push:
|
push:
|
||||||
paths:
|
paths:
|
||||||
- "swift/**"
|
- "swift/**"
|
||||||
@@ -31,7 +30,6 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- rc/*
|
- rc/*
|
||||||
- codeql-cli-*
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# not using a matrix as you cannot depend on a specific job in a matrix, and we want to start linux checks
|
# not using a matrix as you cannot depend on a specific job in a matrix, and we want to start linux checks
|
||||||
|
|||||||
2
.github/workflows/sync-files.yml
vendored
2
.github/workflows/sync-files.yml
vendored
@@ -17,6 +17,4 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Check synchronized files
|
- name: Check synchronized files
|
||||||
run: python config/sync-files.py
|
run: python config/sync-files.py
|
||||||
- name: Check dbscheme fragments
|
|
||||||
run: python config/sync-dbscheme-fragments.py
|
|
||||||
|
|
||||||
|
|||||||
46
.github/workflows/tree-sitter-extractor-test.yml
vendored
46
.github/workflows/tree-sitter-extractor-test.yml
vendored
@@ -1,46 +0,0 @@
|
|||||||
name: Test tree-sitter-extractor
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- "shared/tree-sitter-extractor/**"
|
|
||||||
- .github/workflows/tree-sitter-extractor-test.yml
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- "rc/*"
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- "shared/tree-sitter-extractor/**"
|
|
||||||
- .github/workflows/tree-sitter-extractor-test.yml
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- "rc/*"
|
|
||||||
|
|
||||||
env:
|
|
||||||
CARGO_TERM_COLOR: always
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: shared/tree-sitter-extractor
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Check formatting
|
|
||||||
run: cargo fmt --all -- --check
|
|
||||||
- name: Run tests
|
|
||||||
run: cargo test --verbose
|
|
||||||
fmt:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Check formatting
|
|
||||||
run: cargo fmt --check
|
|
||||||
clippy:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Run clippy
|
|
||||||
run: cargo clippy -- --no-deps -D warnings -A clippy::new_without_default -A clippy::too_many_arguments
|
|
||||||
@@ -5,9 +5,9 @@ repos:
|
|||||||
rev: v3.2.0
|
rev: v3.2.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)|.*\.patch
|
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)|.*\.patch
|
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
rev: v13.0.1
|
rev: v13.0.1
|
||||||
@@ -21,11 +21,6 @@ repos:
|
|||||||
- id: autopep8
|
- id: autopep8
|
||||||
files: ^misc/codegen/.*\.py
|
files: ^misc/codegen/.*\.py
|
||||||
|
|
||||||
- repo: https://github.com/warchant/pre-commit-buildifier
|
|
||||||
rev: 0.0.2
|
|
||||||
hooks:
|
|
||||||
- id: buildifier
|
|
||||||
|
|
||||||
- repo: local
|
- repo: local
|
||||||
hooks:
|
hooks:
|
||||||
- id: codeql-format
|
- id: codeql-format
|
||||||
|
|||||||
18
.vscode/tasks.json
vendored
18
.vscode/tasks.json
vendored
@@ -22,22 +22,6 @@
|
|||||||
"command": "${config:python.pythonPath}",
|
"command": "${config:python.pythonPath}",
|
||||||
},
|
},
|
||||||
"problemMatcher": []
|
"problemMatcher": []
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Accept .expected changes from CI",
|
|
||||||
"type": "process",
|
|
||||||
// Non-Windows OS will usually have Python 3 already installed at /usr/bin/python3.
|
|
||||||
"command": "python3",
|
|
||||||
"args": [
|
|
||||||
"misc/scripts/accept-expected-changes-from-ci.py"
|
|
||||||
],
|
|
||||||
"group": "build",
|
|
||||||
"windows": {
|
|
||||||
// On Windows, use whatever Python interpreter is configured for this workspace. The default is
|
|
||||||
// just `python`, so if Python is already on the path, this will find it.
|
|
||||||
"command": "${config:python.pythonPath}",
|
|
||||||
},
|
|
||||||
"problemMatcher": []
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
/swift/ @github/codeql-swift
|
/swift/ @github/codeql-swift
|
||||||
/misc/codegen/ @github/codeql-swift
|
/misc/codegen/ @github/codeql-swift
|
||||||
/java/kotlin-extractor/ @github/codeql-kotlin
|
/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
|
||||||
@@ -39,6 +40,3 @@ WORKSPACE.bazel @github/codeql-ci-reviewers
|
|||||||
/.github/workflows/ql-for-ql-* @github/codeql-ql-for-ql-reviewers
|
/.github/workflows/ql-for-ql-* @github/codeql-ql-for-ql-reviewers
|
||||||
/.github/workflows/ruby-* @github/codeql-ruby
|
/.github/workflows/ruby-* @github/codeql-ruby
|
||||||
/.github/workflows/swift.yml @github/codeql-swift
|
/.github/workflows/swift.yml @github/codeql-swift
|
||||||
|
|
||||||
# Misc
|
|
||||||
/misc/scripts/accept-expected-changes-from-ci.py @RasmusWL
|
|
||||||
|
|||||||
@@ -14,16 +14,14 @@ If you have an idea for a query that you would like to share with other CodeQL u
|
|||||||
|
|
||||||
1. **Directory structure**
|
1. **Directory structure**
|
||||||
|
|
||||||
There are eight language-specific query directories in this repository:
|
There are six language-specific query directories in this repository:
|
||||||
|
|
||||||
* C/C++: `cpp/ql/src`
|
* C/C++: `cpp/ql/src`
|
||||||
* C#: `csharp/ql/src`
|
* C#: `csharp/ql/src`
|
||||||
* Go: `go/ql/src`
|
* Java: `java/ql/src`
|
||||||
* Java/Kotlin: `java/ql/src`
|
|
||||||
* JavaScript: `javascript/ql/src`
|
* JavaScript: `javascript/ql/src`
|
||||||
* Python: `python/ql/src`
|
* Python: `python/ql/src`
|
||||||
* Ruby: `ruby/ql/src`
|
* Ruby: `ruby/ql/src`
|
||||||
* Swift: `swift/ql/src`
|
|
||||||
|
|
||||||
Each language-specific directory contains further subdirectories that group queries based on their `@tags` or purpose.
|
Each language-specific directory contains further subdirectories that group queries based on their `@tags` or purpose.
|
||||||
- Experimental queries and libraries are stored in the `experimental` subdirectory within each language-specific directory in the [CodeQL repository](https://github.com/github/codeql). For example, experimental Java queries and libraries are stored in `java/ql/src/experimental` and any corresponding tests in `java/ql/test/experimental`.
|
- Experimental queries and libraries are stored in the `experimental` subdirectory within each language-specific directory in the [CodeQL repository](https://github.com/github/codeql). For example, experimental Java queries and libraries are stored in `java/ql/src/experimental` and any corresponding tests in `java/ql/test/experimental`.
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# Do not integrate this change
|
||||||
|
|
||||||
# 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.
|
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.
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ provide:
|
|||||||
- "*/ql/test/qlpack.yml"
|
- "*/ql/test/qlpack.yml"
|
||||||
- "*/ql/examples/qlpack.yml"
|
- "*/ql/examples/qlpack.yml"
|
||||||
- "*/ql/consistency-queries/qlpack.yml"
|
- "*/ql/consistency-queries/qlpack.yml"
|
||||||
- "*/ql/automodel/src/qlpack.yml"
|
|
||||||
- "*/ql/automodel/test/qlpack.yml"
|
|
||||||
- "shared/*/qlpack.yml"
|
- "shared/*/qlpack.yml"
|
||||||
- "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml"
|
- "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml"
|
||||||
- "go/ql/config/legacy-support/qlpack.yml"
|
- "go/ql/config/legacy-support/qlpack.yml"
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"files": [
|
|
||||||
"javascript/ql/lib/semmlecode.javascript.dbscheme",
|
|
||||||
"python/ql/lib/semmlecode.python.dbscheme",
|
|
||||||
"ruby/ql/lib/ruby.dbscheme",
|
|
||||||
"ql/ql/src/ql.dbscheme"
|
|
||||||
],
|
|
||||||
"fragments": [
|
|
||||||
"/*- External data -*/",
|
|
||||||
"/*- Files and folders -*/",
|
|
||||||
"/*- Diagnostic messages -*/",
|
|
||||||
"/*- Diagnostic messages: severity -*/",
|
|
||||||
"/*- Source location prefix -*/",
|
|
||||||
"/*- Lines of code -*/",
|
|
||||||
"/*- Configuration files with key value pairs -*/",
|
|
||||||
"/*- YAML -*/",
|
|
||||||
"/*- XML Files -*/",
|
|
||||||
"/*- XML: sourceline -*/",
|
|
||||||
"/*- DEPRECATED: External defects and metrics -*/",
|
|
||||||
"/*- DEPRECATED: Snapshot date -*/",
|
|
||||||
"/*- DEPRECATED: Duplicate code -*/",
|
|
||||||
"/*- DEPRECATED: Version control data -*/",
|
|
||||||
"/*- JavaScript-specific part -*/",
|
|
||||||
"/*- Ruby dbscheme -*/",
|
|
||||||
"/*- Erb dbscheme -*/",
|
|
||||||
"/*- QL dbscheme -*/",
|
|
||||||
"/*- Dbscheme dbscheme -*/",
|
|
||||||
"/*- Yaml dbscheme -*/",
|
|
||||||
"/*- Blame dbscheme -*/",
|
|
||||||
"/*- JSON dbscheme -*/",
|
|
||||||
"/*- Python dbscheme -*/"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,24 @@
|
|||||||
{
|
{
|
||||||
|
"DataFlow Java/C++/C#/Go/Python/Ruby/Swift": [
|
||||||
|
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlow.qll",
|
||||||
|
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlow.qll",
|
||||||
|
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlow.qll",
|
||||||
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlow.qll",
|
||||||
|
"go/ql/lib/semmle/go/dataflow/internal/DataFlow.qll",
|
||||||
|
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlow.qll",
|
||||||
|
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlow.qll",
|
||||||
|
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlow.qll"
|
||||||
|
],
|
||||||
|
"DataFlowImpl Java/C++/C#/Go/Python/Ruby/Swift": [
|
||||||
|
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll",
|
||||||
|
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll",
|
||||||
|
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll",
|
||||||
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll",
|
||||||
|
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll",
|
||||||
|
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll",
|
||||||
|
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll",
|
||||||
|
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll"
|
||||||
|
],
|
||||||
"DataFlow Java/C++/C#/Go/Python/Ruby/Swift Legacy Configuration": [
|
"DataFlow Java/C++/C#/Go/Python/Ruby/Swift Legacy Configuration": [
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll",
|
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll",
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll",
|
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll",
|
||||||
@@ -22,16 +42,38 @@
|
|||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll",
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll",
|
||||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl1.qll",
|
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl1.qll",
|
||||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll",
|
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll",
|
||||||
|
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImplForStringsNewReplacer.qll",
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl1.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl1.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",
|
||||||
|
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplForRegExp.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl1.qll",
|
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl1.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/DataFlowImplForHttpClientLibraries.qll",
|
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForHttpClientLibraries.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForPathname.qll",
|
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForPathname.qll",
|
||||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl1.qll"
|
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl1.qll"
|
||||||
],
|
],
|
||||||
|
"DataFlow Java/C++/C#/Go/Python/Ruby/Swift Common": [
|
||||||
|
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
|
||||||
|
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll",
|
||||||
|
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll",
|
||||||
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll",
|
||||||
|
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImplCommon.qll",
|
||||||
|
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll",
|
||||||
|
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll",
|
||||||
|
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplCommon.qll"
|
||||||
|
],
|
||||||
|
"TaintTracking Java/C++/C#/Go/Python/Ruby/Swift": [
|
||||||
|
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTracking.qll",
|
||||||
|
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTracking.qll",
|
||||||
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTracking.qll",
|
||||||
|
"go/ql/lib/semmle/go/dataflow/internal/tainttracking1/TaintTracking.qll",
|
||||||
|
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTracking.qll",
|
||||||
|
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking1/TaintTracking.qll",
|
||||||
|
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTracking.qll",
|
||||||
|
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTracking.qll"
|
||||||
|
],
|
||||||
"TaintTracking Legacy Configuration Java/C++/C#/Go/Python/Ruby/Swift": [
|
"TaintTracking Legacy Configuration Java/C++/C#/Go/Python/Ruby/Swift": [
|
||||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||||
@@ -55,6 +97,15 @@
|
|||||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||||
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
|
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
|
||||||
],
|
],
|
||||||
|
"DataFlow Java/C++/C#/Python/Ruby/Swift Consistency checks": [
|
||||||
|
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll",
|
||||||
|
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll",
|
||||||
|
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll",
|
||||||
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll",
|
||||||
|
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplConsistency.qll",
|
||||||
|
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplConsistency.qll",
|
||||||
|
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplConsistency.qll"
|
||||||
|
],
|
||||||
"DataFlow Java/C#/Go/Ruby/Python/Swift Flow Summaries": [
|
"DataFlow Java/C#/Go/Ruby/Python/Swift Flow Summaries": [
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll",
|
"java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll",
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll",
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll",
|
||||||
@@ -461,17 +512,17 @@
|
|||||||
"SensitiveDataHeuristics Python/JS": [
|
"SensitiveDataHeuristics Python/JS": [
|
||||||
"javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll",
|
"javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll",
|
||||||
"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"
|
||||||
"swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll"
|
],
|
||||||
|
"CFG": [
|
||||||
|
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",
|
||||||
|
"ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll",
|
||||||
|
"swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImplShared.qll"
|
||||||
],
|
],
|
||||||
"TypeTracker": [
|
"TypeTracker": [
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll"
|
"ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll"
|
||||||
],
|
],
|
||||||
"SummaryTypeTracker": [
|
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll",
|
|
||||||
"ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll"
|
|
||||||
],
|
|
||||||
"AccessPathSyntax": [
|
"AccessPathSyntax": [
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/AccessPathSyntax.qll",
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/AccessPathSyntax.qll",
|
||||||
"go/ql/lib/semmle/go/dataflow/internal/AccessPathSyntax.qll",
|
"go/ql/lib/semmle/go/dataflow/internal/AccessPathSyntax.qll",
|
||||||
@@ -547,9 +598,5 @@
|
|||||||
"EncryptionKeySizes Python/Java": [
|
"EncryptionKeySizes Python/Java": [
|
||||||
"python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll",
|
"python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll",
|
||||||
"java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll"
|
"java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll"
|
||||||
],
|
|
||||||
"Python model summaries test extension": [
|
|
||||||
"python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ext.yml",
|
|
||||||
"python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ext.yml"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import pathlib
|
|
||||||
import re
|
|
||||||
|
|
||||||
|
|
||||||
def make_groups(blocks):
|
|
||||||
groups = {}
|
|
||||||
for block in blocks:
|
|
||||||
groups.setdefault("".join(block["lines"]), []).append(block)
|
|
||||||
return list(groups.values())
|
|
||||||
|
|
||||||
|
|
||||||
def validate_fragments(fragments):
|
|
||||||
ok = True
|
|
||||||
for header, blocks in fragments.items():
|
|
||||||
groups = make_groups(blocks)
|
|
||||||
if len(groups) > 1:
|
|
||||||
ok = False
|
|
||||||
print("Warning: dbscheme fragments with header '{}' are different for {}".format(header, ["{}:{}:{}".format(
|
|
||||||
group[0]["file"], group[0]["start"], group[0]["end"]) for group in groups]))
|
|
||||||
return ok
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
script_path = os.path.realpath(__file__)
|
|
||||||
script_dir = os.path.dirname(script_path)
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
prog=os.path.basename(script_path),
|
|
||||||
description='Sync dbscheme fragments across files.'
|
|
||||||
)
|
|
||||||
parser.add_argument('files', metavar='dbscheme_file', type=pathlib.Path, nargs='*', default=[],
|
|
||||||
help='dbscheme files to check')
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
with open(os.path.join(script_dir, "dbscheme-fragments.json"), "r") as f:
|
|
||||||
config = json.load(f)
|
|
||||||
|
|
||||||
fragment_headers = set(config["fragments"])
|
|
||||||
fragments = {}
|
|
||||||
ok = True
|
|
||||||
for file in args.files + config["files"]:
|
|
||||||
with open(os.path.join(os.path.dirname(script_dir), file), "r") as dbscheme:
|
|
||||||
header = None
|
|
||||||
line_number = 1
|
|
||||||
block = {"file": file, "start": line_number,
|
|
||||||
"end": None, "lines": []}
|
|
||||||
|
|
||||||
def end_block():
|
|
||||||
block["end"] = line_number - 1
|
|
||||||
if len(block["lines"]) > 0:
|
|
||||||
if header is None:
|
|
||||||
if re.match(r'(?m)\A(\s|//.*$|/\*(\**[^\*])*\*+/)*\Z', "".join(block["lines"])):
|
|
||||||
# Ignore comments at the beginning of the file
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
ok = False
|
|
||||||
print("Warning: dbscheme fragment without header: {}:{}:{}".format(
|
|
||||||
block["file"], block["start"], block["end"]))
|
|
||||||
else:
|
|
||||||
fragments.setdefault(header, []).append(block)
|
|
||||||
for line in dbscheme:
|
|
||||||
m = re.match(r"^\/\*-.*-\*\/$", line)
|
|
||||||
if m:
|
|
||||||
end_block()
|
|
||||||
header = line.strip()
|
|
||||||
if header not in fragment_headers:
|
|
||||||
ok = False
|
|
||||||
print("Warning: unknown header for dbscheme fragment: '{}': {}:{}".format(
|
|
||||||
header, file, line_number))
|
|
||||||
block = {"file": file, "start": line_number,
|
|
||||||
"end": None, "lines": []}
|
|
||||||
block["lines"].append(line)
|
|
||||||
line_number += 1
|
|
||||||
block["lines"].append('\n')
|
|
||||||
line_number += 1
|
|
||||||
end_block()
|
|
||||||
if not ok or not validate_fragments(fragments):
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -327,7 +327,7 @@ namespace Semmle.Autobuild.Cpp.Tests
|
|||||||
{
|
{
|
||||||
Actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test.sln -DisableParallelProcessing"] = 1;
|
Actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test.sln -DisableParallelProcessing"] = 1;
|
||||||
Actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test.sln -DisableParallelProcessing"] = 0;
|
Actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test.sln -DisableParallelProcessing"] = 0;
|
||||||
Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program^ Files^ ^(x86^)\Microsoft^ Visual^ Studio^ 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && msbuild C:\Project\test.sln /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"""] = 0;
|
Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && msbuild C:\Project\test.sln /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"""] = 0;
|
||||||
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "";
|
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "";
|
||||||
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1;
|
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1;
|
||||||
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0;
|
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
|||||||
description: Remove _Float128 type
|
|
||||||
compatibility: full
|
|
||||||
@@ -2,4 +2,3 @@ name: codeql/cpp-downgrades
|
|||||||
groups: cpp
|
groups: cpp
|
||||||
downgrades: .
|
downgrades: .
|
||||||
library: true
|
library: true
|
||||||
warnOnImplicitThis: true
|
|
||||||
|
|||||||
@@ -4,4 +4,3 @@ groups:
|
|||||||
- examples
|
- examples
|
||||||
dependencies:
|
dependencies:
|
||||||
codeql/cpp-all: ${workspace}
|
codeql/cpp-all: ${workspace}
|
||||||
warnOnImplicitThis: true
|
|
||||||
|
|||||||
@@ -1,95 +1,3 @@
|
|||||||
## 0.9.2
|
|
||||||
|
|
||||||
### Deprecated APIs
|
|
||||||
|
|
||||||
* `getAllocatorCall` on `DeleteExpr` and `DeleteArrayExpr` has been deprecated. `getDeallocatorCall` should be used instead.
|
|
||||||
|
|
||||||
### New Features
|
|
||||||
|
|
||||||
* Added `DeleteOrDeleteArrayExpr` as a super type of `DeleteExpr` and `DeleteArrayExpr`
|
|
||||||
|
|
||||||
### Minor Analysis Improvements
|
|
||||||
|
|
||||||
* `delete` and `delete[]` are now modeled as calls to the relevant `operator delete` in the IR. In the case of a dynamic delete call a new instruction `VirtualDeleteFunctionAddress` is used to represent a function that dispatches to the correct delete implementation.
|
|
||||||
* Only the 2 level indirection of `argv` (corresponding to `**argv`) is consided for `FlowSource`.
|
|
||||||
|
|
||||||
## 0.9.1
|
|
||||||
|
|
||||||
No user-facing changes.
|
|
||||||
|
|
||||||
## 0.9.0
|
|
||||||
|
|
||||||
### Breaking Changes
|
|
||||||
|
|
||||||
* The `shouldPrintFunction` predicate from `PrintAstConfiguration` has been replaced by `shouldPrintDeclaration`. Users should now override `shouldPrintDeclaration` if they want to limit the declarations that should be printed.
|
|
||||||
* The `shouldPrintFunction` predicate from `PrintIRConfiguration` has been replaced by `shouldPrintDeclaration`. Users should now override `shouldPrintDeclaration` if they want to limit the declarations that should be printed.
|
|
||||||
|
|
||||||
### Major Analysis Improvements
|
|
||||||
|
|
||||||
* The `PrintAST` library now also prints global and namespace variables and their initializers.
|
|
||||||
|
|
||||||
### Minor Analysis Improvements
|
|
||||||
|
|
||||||
* The `_Float128x` type is no longer exposed as a builtin type. As this type could not occur any code base, this should only affect queries that explicitly looked at the builtin types.
|
|
||||||
|
|
||||||
## 0.8.1
|
|
||||||
|
|
||||||
### Deprecated APIs
|
|
||||||
|
|
||||||
* The library `semmle.code.cpp.dataflow.DataFlow` has been deprecated. Please use `semmle.code.cpp.dataflow.new.DataFlow` instead.
|
|
||||||
|
|
||||||
### New Features
|
|
||||||
|
|
||||||
* The `DataFlow::StateConfigSig` signature module has gained default implementations for `isBarrier/2` and `isAdditionalFlowStep/4`.
|
|
||||||
Hence it is no longer needed to provide `none()` implementations of these predicates if they are not needed.
|
|
||||||
|
|
||||||
### Minor Analysis Improvements
|
|
||||||
|
|
||||||
* Data flow configurations can now include a predicate `neverSkip(Node node)`
|
|
||||||
in order to ensure inclusion of certain nodes in the path explanations. The
|
|
||||||
predicate defaults to the end-points of the additional flow steps provided in
|
|
||||||
the configuration, which means that such steps now always are visible by
|
|
||||||
default in path explanations.
|
|
||||||
* The `IRGuards` library has improved handling of pointer addition and subtraction operations.
|
|
||||||
|
|
||||||
## 0.8.0
|
|
||||||
|
|
||||||
### New Features
|
|
||||||
|
|
||||||
* The `ProductFlow::StateConfigSig` signature now includes default predicates for `isBarrier1`, `isBarrier2`, `isAdditionalFlowStep1`, and `isAdditionalFlowStep1`. Hence, it is no longer needed to provide `none()` implementations of these predicates if they are not needed.
|
|
||||||
|
|
||||||
### Minor Analysis Improvements
|
|
||||||
|
|
||||||
* Deleted the deprecated `getURL` predicate from the `Container`, `Folder`, and `File` classes. Use the `getLocation` predicate instead.
|
|
||||||
|
|
||||||
## 0.7.4
|
|
||||||
|
|
||||||
No user-facing changes.
|
|
||||||
|
|
||||||
## 0.7.3
|
|
||||||
|
|
||||||
### Minor Analysis Improvements
|
|
||||||
|
|
||||||
* Deleted the deprecated `hasCopyConstructor` predicate from the `Class` class in `Class.qll`.
|
|
||||||
* Deleted many deprecated predicates and classes with uppercase `AST`, `SSA`, `CFG`, `API`, etc. in their names. Use the PascalCased versions instead.
|
|
||||||
* Deleted the deprecated `CodeDuplication.qll` file.
|
|
||||||
|
|
||||||
## 0.7.2
|
|
||||||
|
|
||||||
### New Features
|
|
||||||
|
|
||||||
* Added an AST-based interface (`semmle.code.cpp.rangeanalysis.new.RangeAnalysis`) for the relative range analysis library.
|
|
||||||
* A new predicate `BarrierGuard::getAnIndirectBarrierNode` has been added to the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow`) to mark indirect expressions as barrier nodes using the `BarrierGuard` API.
|
|
||||||
|
|
||||||
### Major Analysis Improvements
|
|
||||||
|
|
||||||
* In the intermediate representation, handling of control flow after non-returning calls has been improved. This should remove false positives in queries that use the intermedite representation or libraries based on it, including the new data flow library.
|
|
||||||
|
|
||||||
### Minor Analysis Improvements
|
|
||||||
|
|
||||||
* The `StdNamespace` class now also includes all inline namespaces that are children of `std` namespace.
|
|
||||||
* The new dataflow (`semmle.code.cpp.dataflow.new.DataFlow`) and taint-tracking libraries (`semmle.code.cpp.dataflow.new.TaintTracking`) now support tracking flow through static local variables.
|
|
||||||
|
|
||||||
## 0.7.1
|
## 0.7.1
|
||||||
|
|
||||||
No user-facing changes.
|
No user-facing changes.
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* The new dataflow (`semmle.code.cpp.dataflow.new.DataFlow`) and taint-tracking libraries (`semmle.code.cpp.dataflow.new.TaintTracking`) now support tracking flow through static local variables.
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
## 0.7.2
|
|
||||||
|
|
||||||
### New Features
|
|
||||||
|
|
||||||
* Added an AST-based interface (`semmle.code.cpp.rangeanalysis.new.RangeAnalysis`) for the relative range analysis library.
|
|
||||||
* A new predicate `BarrierGuard::getAnIndirectBarrierNode` has been added to the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow`) to mark indirect expressions as barrier nodes using the `BarrierGuard` API.
|
|
||||||
|
|
||||||
### Major Analysis Improvements
|
|
||||||
|
|
||||||
* In the intermediate representation, handling of control flow after non-returning calls has been improved. This should remove false positives in queries that use the intermedite representation or libraries based on it, including the new data flow library.
|
|
||||||
|
|
||||||
### Minor Analysis Improvements
|
|
||||||
|
|
||||||
* The `StdNamespace` class now also includes all inline namespaces that are children of `std` namespace.
|
|
||||||
* The new dataflow (`semmle.code.cpp.dataflow.new.DataFlow`) and taint-tracking libraries (`semmle.code.cpp.dataflow.new.TaintTracking`) now support tracking flow through static local variables.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
## 0.7.3
|
|
||||||
|
|
||||||
### Minor Analysis Improvements
|
|
||||||
|
|
||||||
* Deleted the deprecated `hasCopyConstructor` predicate from the `Class` class in `Class.qll`.
|
|
||||||
* Deleted many deprecated predicates and classes with uppercase `AST`, `SSA`, `CFG`, `API`, etc. in their names. Use the PascalCased versions instead.
|
|
||||||
* Deleted the deprecated `CodeDuplication.qll` file.
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
## 0.7.4
|
|
||||||
|
|
||||||
No user-facing changes.
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
## 0.8.0
|
|
||||||
|
|
||||||
### New Features
|
|
||||||
|
|
||||||
* The `ProductFlow::StateConfigSig` signature now includes default predicates for `isBarrier1`, `isBarrier2`, `isAdditionalFlowStep1`, and `isAdditionalFlowStep1`. Hence, it is no longer needed to provide `none()` implementations of these predicates if they are not needed.
|
|
||||||
|
|
||||||
### Minor Analysis Improvements
|
|
||||||
|
|
||||||
* Deleted the deprecated `getURL` predicate from the `Container`, `Folder`, and `File` classes. Use the `getLocation` predicate instead.
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
## 0.8.1
|
|
||||||
|
|
||||||
### Deprecated APIs
|
|
||||||
|
|
||||||
* The library `semmle.code.cpp.dataflow.DataFlow` has been deprecated. Please use `semmle.code.cpp.dataflow.new.DataFlow` instead.
|
|
||||||
|
|
||||||
### New Features
|
|
||||||
|
|
||||||
* The `DataFlow::StateConfigSig` signature module has gained default implementations for `isBarrier/2` and `isAdditionalFlowStep/4`.
|
|
||||||
Hence it is no longer needed to provide `none()` implementations of these predicates if they are not needed.
|
|
||||||
|
|
||||||
### Minor Analysis Improvements
|
|
||||||
|
|
||||||
* Data flow configurations can now include a predicate `neverSkip(Node node)`
|
|
||||||
in order to ensure inclusion of certain nodes in the path explanations. The
|
|
||||||
predicate defaults to the end-points of the additional flow steps provided in
|
|
||||||
the configuration, which means that such steps now always are visible by
|
|
||||||
default in path explanations.
|
|
||||||
* The `IRGuards` library has improved handling of pointer addition and subtraction operations.
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
## 0.9.0
|
|
||||||
|
|
||||||
### Breaking Changes
|
|
||||||
|
|
||||||
* The `shouldPrintFunction` predicate from `PrintAstConfiguration` has been replaced by `shouldPrintDeclaration`. Users should now override `shouldPrintDeclaration` if they want to limit the declarations that should be printed.
|
|
||||||
* The `shouldPrintFunction` predicate from `PrintIRConfiguration` has been replaced by `shouldPrintDeclaration`. Users should now override `shouldPrintDeclaration` if they want to limit the declarations that should be printed.
|
|
||||||
|
|
||||||
### Major Analysis Improvements
|
|
||||||
|
|
||||||
* The `PrintAST` library now also prints global and namespace variables and their initializers.
|
|
||||||
|
|
||||||
### Minor Analysis Improvements
|
|
||||||
|
|
||||||
* The `_Float128x` type is no longer exposed as a builtin type. As this type could not occur any code base, this should only affect queries that explicitly looked at the builtin types.
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
## 0.9.1
|
|
||||||
|
|
||||||
No user-facing changes.
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
## 0.9.2
|
|
||||||
|
|
||||||
### Deprecated APIs
|
|
||||||
|
|
||||||
* `getAllocatorCall` on `DeleteExpr` and `DeleteArrayExpr` has been deprecated. `getDeallocatorCall` should be used instead.
|
|
||||||
|
|
||||||
### New Features
|
|
||||||
|
|
||||||
* Added `DeleteOrDeleteArrayExpr` as a super type of `DeleteExpr` and `DeleteArrayExpr`
|
|
||||||
|
|
||||||
### Minor Analysis Improvements
|
|
||||||
|
|
||||||
* `delete` and `delete[]` are now modeled as calls to the relevant `operator delete` in the IR. In the case of a dynamic delete call a new instruction `VirtualDeleteFunctionAddress` is used to represent a function that dispatches to the correct delete implementation.
|
|
||||||
* Only the 2 level indirection of `argv` (corresponding to `**argv`) is consided for `FlowSource`.
|
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.9.2
|
lastReleaseVersion: 0.7.1
|
||||||
|
|||||||
@@ -1,29 +1,7 @@
|
|||||||
/**
|
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||||
* Provides a library for global (inter-procedural) data flow analysis of two
|
|
||||||
* values "simultaneously". This can be used, for example, if you want to track
|
|
||||||
* a memory allocation as well as the size of the allocation.
|
|
||||||
*
|
|
||||||
* Intuitively, you can think of this as regular dataflow, but where each node
|
|
||||||
* in the dataflow graph has been replaced by a pair of nodes `(node1, node2)`,
|
|
||||||
* and two node pairs `(n11, n12)`, `(n21, n22)` is then connected by a dataflow
|
|
||||||
* edge if there's a regular dataflow edge between `n11` and `n21`, and `n12`
|
|
||||||
* and `n22`.
|
|
||||||
*
|
|
||||||
* Note that the above intuition does not reflect the actual implementation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import semmle.code.cpp.dataflow.new.DataFlow
|
|
||||||
private import DataFlowPrivate
|
|
||||||
private import DataFlowUtil
|
|
||||||
private import DataFlowImplCommon
|
|
||||||
private import codeql.util.Unit
|
private import codeql.util.Unit
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides classes for performing global (inter-procedural) data flow analyses
|
|
||||||
* on a product dataflow graph.
|
|
||||||
*/
|
|
||||||
module ProductFlow {
|
module ProductFlow {
|
||||||
/** An input configuration for product data-flow. */
|
|
||||||
signature module ConfigSig {
|
signature module ConfigSig {
|
||||||
/**
|
/**
|
||||||
* Holds if `(source1, source2)` is a relevant data flow source.
|
* Holds if `(source1, source2)` is a relevant data flow source.
|
||||||
@@ -87,35 +65,8 @@ module ProductFlow {
|
|||||||
* dataflow graph.
|
* dataflow graph.
|
||||||
*/
|
*/
|
||||||
default predicate isBarrierIn2(DataFlow::Node node) { none() }
|
default predicate isBarrierIn2(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow in the first
|
|
||||||
* projection of the product dataflow graph.
|
|
||||||
*
|
|
||||||
* This can be overridden to a smaller value to improve performance (a
|
|
||||||
* value of 0 disables field flow), or a larger value to get more results.
|
|
||||||
*/
|
|
||||||
default int fieldFlowBranchLimit1() {
|
|
||||||
// NOTE: This should be synchronized with the default value in the shared dataflow library
|
|
||||||
result = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow in the second
|
|
||||||
* projection of the product dataflow graph.
|
|
||||||
*
|
|
||||||
* This can be overridden to a smaller value to improve performance (a
|
|
||||||
* value of 0 disables field flow), or a larger value to get more results.
|
|
||||||
*/
|
|
||||||
default int fieldFlowBranchLimit2() {
|
|
||||||
// NOTE: This should be synchronized with the default value in the shared dataflow library
|
|
||||||
result = 2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The output of a global data flow computation.
|
|
||||||
*/
|
|
||||||
module Global<ConfigSig Config> {
|
module Global<ConfigSig Config> {
|
||||||
private module StateConfig implements StateConfigSig {
|
private module StateConfig implements StateConfigSig {
|
||||||
class FlowState1 = Unit;
|
class FlowState1 = Unit;
|
||||||
@@ -184,7 +135,6 @@ module ProductFlow {
|
|||||||
import GlobalWithState<StateConfig>
|
import GlobalWithState<StateConfig>
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An input configuration for data flow using flow state. */
|
|
||||||
signature module StateConfigSig {
|
signature module StateConfigSig {
|
||||||
bindingset[this]
|
bindingset[this]
|
||||||
class FlowState1;
|
class FlowState1;
|
||||||
@@ -216,13 +166,13 @@ module ProductFlow {
|
|||||||
* Holds if data flow through `node` is prohibited through the first projection of the product
|
* Holds if data flow through `node` is prohibited through the first projection of the product
|
||||||
* dataflow graph when the flow state is `state`.
|
* dataflow graph when the flow state is `state`.
|
||||||
*/
|
*/
|
||||||
default predicate isBarrier1(DataFlow::Node node, FlowState1 state) { none() }
|
predicate isBarrier1(DataFlow::Node node, FlowState1 state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if data flow through `node` is prohibited through the second projection of the product
|
* Holds if data flow through `node` is prohibited through the second projection of the product
|
||||||
* dataflow graph when the flow state is `state`.
|
* dataflow graph when the flow state is `state`.
|
||||||
*/
|
*/
|
||||||
default predicate isBarrier2(DataFlow::Node node, FlowState2 state) { none() }
|
predicate isBarrier2(DataFlow::Node node, FlowState2 state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if data flow through `node` is prohibited through the first projection of the product
|
* Holds if data flow through `node` is prohibited through the first projection of the product
|
||||||
@@ -261,11 +211,9 @@ module ProductFlow {
|
|||||||
*
|
*
|
||||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||||
*/
|
*/
|
||||||
default predicate isAdditionalFlowStep1(
|
predicate isAdditionalFlowStep1(
|
||||||
DataFlow::Node node1, FlowState1 state1, DataFlow::Node node2, FlowState1 state2
|
DataFlow::Node node1, FlowState1 state1, DataFlow::Node node2, FlowState1 state2
|
||||||
) {
|
);
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
||||||
@@ -279,11 +227,9 @@ module ProductFlow {
|
|||||||
*
|
*
|
||||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||||
*/
|
*/
|
||||||
default predicate isAdditionalFlowStep2(
|
predicate isAdditionalFlowStep2(
|
||||||
DataFlow::Node node1, FlowState2 state1, DataFlow::Node node2, FlowState2 state2
|
DataFlow::Node node1, FlowState2 state1, DataFlow::Node node2, FlowState2 state2
|
||||||
) {
|
);
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if data flow into `node` is prohibited in the first projection of the product
|
* Holds if data flow into `node` is prohibited in the first projection of the product
|
||||||
@@ -296,35 +242,8 @@ module ProductFlow {
|
|||||||
* dataflow graph.
|
* dataflow graph.
|
||||||
*/
|
*/
|
||||||
default predicate isBarrierIn2(DataFlow::Node node) { none() }
|
default predicate isBarrierIn2(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow in the first
|
|
||||||
* projection of the product dataflow graph.
|
|
||||||
*
|
|
||||||
* This can be overridden to a smaller value to improve performance (a
|
|
||||||
* value of 0 disables field flow), or a larger value to get more results.
|
|
||||||
*/
|
|
||||||
default int fieldFlowBranchLimit1() {
|
|
||||||
// NOTE: This should be synchronized with the default value in the shared dataflow library
|
|
||||||
result = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow in the second
|
|
||||||
* projection of the product dataflow graph.
|
|
||||||
*
|
|
||||||
* This can be overridden to a smaller value to improve performance (a
|
|
||||||
* value of 0 disables field flow), or a larger value to get more results.
|
|
||||||
*/
|
|
||||||
default int fieldFlowBranchLimit2() {
|
|
||||||
// NOTE: This should be synchronized with the default value in the shared dataflow library
|
|
||||||
result = 2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The output of a global data flow computation.
|
|
||||||
*/
|
|
||||||
module GlobalWithState<StateConfigSig Config> {
|
module GlobalWithState<StateConfigSig Config> {
|
||||||
class PathNode1 = Flow1::PathNode;
|
class PathNode1 = Flow1::PathNode;
|
||||||
|
|
||||||
@@ -338,29 +257,12 @@ module ProductFlow {
|
|||||||
|
|
||||||
class FlowState2 = Config::FlowState2;
|
class FlowState2 = Config::FlowState2;
|
||||||
|
|
||||||
/** Holds if data can flow from `(source1, source2)` to `(sink1, sink2)`. */
|
|
||||||
predicate flowPath(
|
predicate flowPath(
|
||||||
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode sink1, Flow2::PathNode sink2
|
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode sink1, Flow2::PathNode sink2
|
||||||
) {
|
) {
|
||||||
reachable(source1, source2, sink1, sink2)
|
reachable(source1, source2, sink1, sink2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if data can flow from `(source1, source2)` to `(sink1, sink2)`. */
|
|
||||||
predicate flow(
|
|
||||||
DataFlow::Node source1, DataFlow::Node source2, DataFlow::Node sink1, DataFlow::Node sink2
|
|
||||||
) {
|
|
||||||
exists(
|
|
||||||
Flow1::PathNode pSource1, Flow2::PathNode pSource2, Flow1::PathNode pSink1,
|
|
||||||
Flow2::PathNode pSink2
|
|
||||||
|
|
|
||||||
pSource1.getNode() = source1 and
|
|
||||||
pSource2.getNode() = source2 and
|
|
||||||
pSink1.getNode() = sink1 and
|
|
||||||
pSink2.getNode() = sink2 and
|
|
||||||
flowPath(pSource1, pSource2, pSink1, pSink2)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Config1 implements DataFlow::StateConfigSig {
|
private module Config1 implements DataFlow::StateConfigSig {
|
||||||
class FlowState = FlowState1;
|
class FlowState = FlowState1;
|
||||||
|
|
||||||
@@ -383,13 +285,11 @@ module ProductFlow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn1(node) }
|
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn1(node) }
|
||||||
|
|
||||||
int fieldFlowBranchLimit() { result = Config::fieldFlowBranchLimit1() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Flow1 = DataFlow::GlobalWithState<Config1>;
|
module Flow1 = DataFlow::GlobalWithState<Config1>;
|
||||||
|
|
||||||
private module Config2 implements DataFlow::StateConfigSig {
|
module Config2 implements DataFlow::StateConfigSig {
|
||||||
class FlowState = FlowState2;
|
class FlowState = FlowState2;
|
||||||
|
|
||||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||||
@@ -417,91 +317,29 @@ module ProductFlow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn2(node) }
|
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn2(node) }
|
||||||
|
|
||||||
int fieldFlowBranchLimit() { result = Config::fieldFlowBranchLimit2() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Flow2 = DataFlow::GlobalWithState<Config2>;
|
module Flow2 = DataFlow::GlobalWithState<Config2>;
|
||||||
|
|
||||||
private predicate isSourcePair(Flow1::PathNode node1, Flow2::PathNode node2) {
|
|
||||||
Config::isSourcePair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState())
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate isSinkPair(Flow1::PathNode node1, Flow2::PathNode node2) {
|
|
||||||
Config::isSinkPair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState())
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdReachableInterprocEntry(Flow1::PathNode node1, Flow2::PathNode node2) {
|
private predicate reachableInterprocEntry(
|
||||||
isSourcePair(node1, node2)
|
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode node1, Flow2::PathNode node2
|
||||||
|
) {
|
||||||
|
Config::isSourcePair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState()) and
|
||||||
|
node1 = source1 and
|
||||||
|
node2 = source2
|
||||||
or
|
or
|
||||||
fwdIsSuccessor(_, _, node1, node2)
|
exists(
|
||||||
}
|
Flow1::PathNode midEntry1, Flow2::PathNode midEntry2, Flow1::PathNode midExit1,
|
||||||
|
Flow2::PathNode midExit2
|
||||||
pragma[nomagic]
|
|
|
||||||
private predicate fwdIsSuccessorExit(
|
reachableInterprocEntry(source1, source2, midEntry1, midEntry2) and
|
||||||
Flow1::PathNode mid1, Flow2::PathNode mid2, Flow1::PathNode succ1, Flow2::PathNode succ2
|
interprocEdgePair(midExit1, midExit2, node1, node2) and
|
||||||
) {
|
localPathStep1*(midEntry1, midExit1) and
|
||||||
isSinkPair(mid1, mid2) and
|
localPathStep2*(midEntry2, midExit2)
|
||||||
succ1 = mid1 and
|
|
||||||
succ2 = mid2
|
|
||||||
or
|
|
||||||
interprocEdgePair(mid1, mid2, succ1, succ2)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate fwdIsSuccessor1(
|
|
||||||
Flow1::PathNode pred1, Flow2::PathNode pred2, Flow1::PathNode mid1, Flow2::PathNode mid2,
|
|
||||||
Flow1::PathNode succ1, Flow2::PathNode succ2
|
|
||||||
) {
|
|
||||||
fwdReachableInterprocEntry(pred1, pred2) and
|
|
||||||
localPathStep1*(pred1, mid1) and
|
|
||||||
fwdIsSuccessorExit(pragma[only_bind_into](mid1), pragma[only_bind_into](mid2), succ1, succ2)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate fwdIsSuccessor2(
|
|
||||||
Flow1::PathNode pred1, Flow2::PathNode pred2, Flow1::PathNode mid1, Flow2::PathNode mid2,
|
|
||||||
Flow1::PathNode succ1, Flow2::PathNode succ2
|
|
||||||
) {
|
|
||||||
fwdReachableInterprocEntry(pred1, pred2) and
|
|
||||||
localPathStep2*(pred2, mid2) and
|
|
||||||
fwdIsSuccessorExit(pragma[only_bind_into](mid1), pragma[only_bind_into](mid2), succ1, succ2)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate fwdIsSuccessor(
|
|
||||||
Flow1::PathNode pred1, Flow2::PathNode pred2, Flow1::PathNode succ1, Flow2::PathNode succ2
|
|
||||||
) {
|
|
||||||
exists(Flow1::PathNode mid1, Flow2::PathNode mid2 |
|
|
||||||
fwdIsSuccessor1(pred1, pred2, mid1, mid2, succ1, succ2) and
|
|
||||||
fwdIsSuccessor2(pred1, pred2, mid1, mid2, succ1, succ2)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate revReachableInterprocEntry(Flow1::PathNode node1, Flow2::PathNode node2) {
|
|
||||||
fwdReachableInterprocEntry(node1, node2) and
|
|
||||||
isSinkPair(node1, node2)
|
|
||||||
or
|
|
||||||
exists(Flow1::PathNode succ1, Flow2::PathNode succ2 |
|
|
||||||
revReachableInterprocEntry(succ1, succ2) and
|
|
||||||
fwdIsSuccessor(node1, node2, succ1, succ2)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TNodePair =
|
|
||||||
TMkNodePair(Flow1::PathNode node1, Flow2::PathNode node2) {
|
|
||||||
revReachableInterprocEntry(node1, node2)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate pathSucc(TNodePair n1, TNodePair n2) {
|
|
||||||
exists(Flow1::PathNode n11, Flow2::PathNode n12, Flow1::PathNode n21, Flow2::PathNode n22 |
|
|
||||||
n1 = TMkNodePair(n11, n12) and
|
|
||||||
n2 = TMkNodePair(n21, n22) and
|
|
||||||
fwdIsSuccessor(n11, n12, n21, n22)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate pathSuccPlus(TNodePair n1, TNodePair n2) = fastTC(pathSucc/2)(n1, n2)
|
|
||||||
|
|
||||||
private predicate localPathStep1(Flow1::PathNode pred, Flow1::PathNode succ) {
|
private predicate localPathStep1(Flow1::PathNode pred, Flow1::PathNode succ) {
|
||||||
Flow1::PathGraph::edges(pred, succ) and
|
Flow1::PathGraph::edges(pred, succ) and
|
||||||
pragma[only_bind_out](pred.getNode().getEnclosingCallable()) =
|
pragma[only_bind_out](pred.getNode().getEnclosingCallable()) =
|
||||||
@@ -514,133 +352,43 @@ module ProductFlow {
|
|||||||
pragma[only_bind_out](succ.getNode().getEnclosingCallable())
|
pragma[only_bind_out](succ.getNode().getEnclosingCallable())
|
||||||
}
|
}
|
||||||
|
|
||||||
private newtype TKind =
|
|
||||||
TInto(DataFlowCall call) {
|
|
||||||
intoImpl1(_, _, call) or
|
|
||||||
intoImpl2(_, _, call)
|
|
||||||
} or
|
|
||||||
TOutOf(DataFlowCall call) {
|
|
||||||
outImpl1(_, _, call) or
|
|
||||||
outImpl2(_, _, call)
|
|
||||||
} or
|
|
||||||
TJump()
|
|
||||||
|
|
||||||
private predicate intoImpl1(Flow1::PathNode pred1, Flow1::PathNode succ1, DataFlowCall call) {
|
|
||||||
Flow1::PathGraph::edges(pred1, succ1) and
|
|
||||||
pred1.getNode().(ArgumentNode).getCall() = call and
|
|
||||||
succ1.getNode() instanceof ParameterNode
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate into1(Flow1::PathNode pred1, Flow1::PathNode succ1, TKind kind) {
|
|
||||||
exists(DataFlowCall call |
|
|
||||||
kind = TInto(call) and
|
|
||||||
intoImpl1(pred1, succ1, call)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate outImpl1(Flow1::PathNode pred1, Flow1::PathNode succ1, DataFlowCall call) {
|
|
||||||
Flow1::PathGraph::edges(pred1, succ1) and
|
|
||||||
exists(ReturnKindExt returnKind |
|
|
||||||
succ1.getNode() = returnKind.getAnOutNode(call) and
|
|
||||||
pred1.getNode().(ReturnNodeExt).getKind() = returnKind
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate out1(Flow1::PathNode pred1, Flow1::PathNode succ1, TKind kind) {
|
|
||||||
exists(DataFlowCall call |
|
|
||||||
outImpl1(pred1, succ1, call) and
|
|
||||||
kind = TOutOf(call)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate intoImpl2(Flow2::PathNode pred2, Flow2::PathNode succ2, DataFlowCall call) {
|
|
||||||
Flow2::PathGraph::edges(pred2, succ2) and
|
|
||||||
pred2.getNode().(ArgumentNode).getCall() = call and
|
|
||||||
succ2.getNode() instanceof ParameterNode
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate into2(Flow2::PathNode pred2, Flow2::PathNode succ2, TKind kind) {
|
|
||||||
exists(DataFlowCall call |
|
|
||||||
kind = TInto(call) and
|
|
||||||
intoImpl2(pred2, succ2, call)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate outImpl2(Flow2::PathNode pred2, Flow2::PathNode succ2, DataFlowCall call) {
|
|
||||||
Flow2::PathGraph::edges(pred2, succ2) and
|
|
||||||
exists(ReturnKindExt returnKind |
|
|
||||||
succ2.getNode() = returnKind.getAnOutNode(call) and
|
|
||||||
pred2.getNode().(ReturnNodeExt).getKind() = returnKind
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate out2(Flow2::PathNode pred2, Flow2::PathNode succ2, TKind kind) {
|
|
||||||
exists(DataFlowCall call |
|
|
||||||
kind = TOutOf(call) and
|
|
||||||
outImpl2(pred2, succ2, call)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate interprocEdge1(
|
private predicate interprocEdge1(
|
||||||
Declaration predDecl, Declaration succDecl, Flow1::PathNode pred1, Flow1::PathNode succ1,
|
Declaration predDecl, Declaration succDecl, Flow1::PathNode pred1, Flow1::PathNode succ1
|
||||||
TKind kind
|
|
||||||
) {
|
) {
|
||||||
Flow1::PathGraph::edges(pred1, succ1) and
|
Flow1::PathGraph::edges(pred1, succ1) and
|
||||||
predDecl != succDecl and
|
predDecl != succDecl and
|
||||||
pred1.getNode().getEnclosingCallable() = predDecl and
|
pred1.getNode().getEnclosingCallable() = predDecl and
|
||||||
succ1.getNode().getEnclosingCallable() = succDecl and
|
succ1.getNode().getEnclosingCallable() = succDecl
|
||||||
(
|
|
||||||
into1(pred1, succ1, kind)
|
|
||||||
or
|
|
||||||
out1(pred1, succ1, kind)
|
|
||||||
or
|
|
||||||
kind = TJump() and
|
|
||||||
not into1(pred1, succ1, _) and
|
|
||||||
not out1(pred1, succ1, _)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate interprocEdge2(
|
private predicate interprocEdge2(
|
||||||
Declaration predDecl, Declaration succDecl, Flow2::PathNode pred2, Flow2::PathNode succ2,
|
Declaration predDecl, Declaration succDecl, Flow2::PathNode pred2, Flow2::PathNode succ2
|
||||||
TKind kind
|
|
||||||
) {
|
) {
|
||||||
Flow2::PathGraph::edges(pred2, succ2) and
|
Flow2::PathGraph::edges(pred2, succ2) and
|
||||||
predDecl != succDecl and
|
predDecl != succDecl and
|
||||||
pred2.getNode().getEnclosingCallable() = predDecl and
|
pred2.getNode().getEnclosingCallable() = predDecl and
|
||||||
succ2.getNode().getEnclosingCallable() = succDecl and
|
succ2.getNode().getEnclosingCallable() = succDecl
|
||||||
(
|
|
||||||
into2(pred2, succ2, kind)
|
|
||||||
or
|
|
||||||
out2(pred2, succ2, kind)
|
|
||||||
or
|
|
||||||
kind = TJump() and
|
|
||||||
not into2(pred2, succ2, _) and
|
|
||||||
not out2(pred2, succ2, _)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate interprocEdgePair(
|
private predicate interprocEdgePair(
|
||||||
Flow1::PathNode pred1, Flow2::PathNode pred2, Flow1::PathNode succ1, Flow2::PathNode succ2
|
Flow1::PathNode pred1, Flow2::PathNode pred2, Flow1::PathNode succ1, Flow2::PathNode succ2
|
||||||
) {
|
) {
|
||||||
exists(Declaration predDecl, Declaration succDecl, TKind kind |
|
exists(Declaration predDecl, Declaration succDecl |
|
||||||
interprocEdge1(predDecl, succDecl, pred1, succ1, kind) and
|
interprocEdge1(predDecl, succDecl, pred1, succ1) and
|
||||||
interprocEdge2(predDecl, succDecl, pred2, succ2, kind)
|
interprocEdge2(predDecl, succDecl, pred2, succ2)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate reachable(
|
private predicate reachable(
|
||||||
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode sink1, Flow2::PathNode sink2
|
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode sink1, Flow2::PathNode sink2
|
||||||
) {
|
) {
|
||||||
isSourcePair(source1, source2) and
|
exists(Flow1::PathNode mid1, Flow2::PathNode mid2 |
|
||||||
isSinkPair(sink1, sink2) and
|
reachableInterprocEntry(source1, source2, mid1, mid2) and
|
||||||
exists(TNodePair n1, TNodePair n2 |
|
Config::isSinkPair(sink1.getNode(), sink1.getState(), sink2.getNode(), sink2.getState()) and
|
||||||
n1 = TMkNodePair(source1, source2) and
|
localPathStep1*(mid1, sink1) and
|
||||||
n2 = TMkNodePair(sink1, sink2)
|
localPathStep2*(mid2, sink2)
|
||||||
|
|
|
||||||
pathSuccPlus(n1, n2) or
|
|
||||||
n1 = n2
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,7 +238,7 @@ class NoReason extends Reason, TNoReason {
|
|||||||
class CondReason extends Reason, TCondReason {
|
class CondReason extends Reason, TCondReason {
|
||||||
IRGuardCondition getCond() { this = TCondReason(result) }
|
IRGuardCondition getCond() { this = TCondReason(result) }
|
||||||
|
|
||||||
override string toString() { result = this.getCond().toString() }
|
override string toString() { result = getCond().toString() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -260,14 +260,14 @@ private predicate typeBound(IRIntegerType typ, int lowerbound, int upperbound) {
|
|||||||
private class NarrowingCastInstruction extends ConvertInstruction {
|
private class NarrowingCastInstruction extends ConvertInstruction {
|
||||||
NarrowingCastInstruction() {
|
NarrowingCastInstruction() {
|
||||||
not this instanceof SafeCastInstruction and
|
not this instanceof SafeCastInstruction and
|
||||||
typeBound(this.getResultIRType(), _, _)
|
typeBound(getResultIRType(), _, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the lower bound of the resulting type. */
|
/** Gets the lower bound of the resulting type. */
|
||||||
int getLowerBound() { typeBound(this.getResultIRType(), result, _) }
|
int getLowerBound() { typeBound(getResultIRType(), result, _) }
|
||||||
|
|
||||||
/** Gets the upper bound of the resulting type. */
|
/** Gets the upper bound of the resulting type. */
|
||||||
int getUpperBound() { typeBound(this.getResultIRType(), _, result) }
|
int getUpperBound() { typeBound(getResultIRType(), _, result) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -109,8 +109,8 @@ private predicate safeCast(IRIntegerType fromtyp, IRIntegerType totyp) {
|
|||||||
*/
|
*/
|
||||||
class PtrToPtrCastInstruction extends ConvertInstruction {
|
class PtrToPtrCastInstruction extends ConvertInstruction {
|
||||||
PtrToPtrCastInstruction() {
|
PtrToPtrCastInstruction() {
|
||||||
this.getResultIRType() instanceof IRAddressType and
|
getResultIRType() instanceof IRAddressType and
|
||||||
this.getUnary().getResultIRType() instanceof IRAddressType
|
getUnary().getResultIRType() instanceof IRAddressType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ class PtrToPtrCastInstruction extends ConvertInstruction {
|
|||||||
* that cannot overflow or underflow.
|
* that cannot overflow or underflow.
|
||||||
*/
|
*/
|
||||||
class SafeIntCastInstruction extends ConvertInstruction {
|
class SafeIntCastInstruction extends ConvertInstruction {
|
||||||
SafeIntCastInstruction() { safeCast(this.getUnary().getResultIRType(), this.getResultIRType()) }
|
SafeIntCastInstruction() { safeCast(getUnary().getResultIRType(), getResultIRType()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ private class ConstantBitwiseAndExprRange extends SimpleRangeAnalysisExpr {
|
|||||||
// If an operand can have negative values, the lower bound is unconstrained.
|
// If an operand can have negative values, the lower bound is unconstrained.
|
||||||
// Otherwise, the lower bound is zero.
|
// Otherwise, the lower bound is zero.
|
||||||
exists(float lLower, float rLower |
|
exists(float lLower, float rLower |
|
||||||
lLower = getFullyConvertedLowerBounds(this.getLeftOperand()) and
|
lLower = getFullyConvertedLowerBounds(getLeftOperand()) and
|
||||||
rLower = getFullyConvertedLowerBounds(this.getRightOperand()) and
|
rLower = getFullyConvertedLowerBounds(getRightOperand()) and
|
||||||
(
|
(
|
||||||
(lLower < 0 or rLower < 0) and
|
(lLower < 0 or rLower < 0) and
|
||||||
result = exprMinVal(this)
|
result = exprMinVal(this)
|
||||||
@@ -68,10 +68,10 @@ private class ConstantBitwiseAndExprRange extends SimpleRangeAnalysisExpr {
|
|||||||
// If an operand can have negative values, the upper bound is unconstrained.
|
// If an operand can have negative values, the upper bound is unconstrained.
|
||||||
// Otherwise, the upper bound is the minimum of the upper bounds of the operands
|
// Otherwise, the upper bound is the minimum of the upper bounds of the operands
|
||||||
exists(float lLower, float lUpper, float rLower, float rUpper |
|
exists(float lLower, float lUpper, float rLower, float rUpper |
|
||||||
lLower = getFullyConvertedLowerBounds(this.getLeftOperand()) and
|
lLower = getFullyConvertedLowerBounds(getLeftOperand()) and
|
||||||
lUpper = getFullyConvertedUpperBounds(this.getLeftOperand()) and
|
lUpper = getFullyConvertedUpperBounds(getLeftOperand()) and
|
||||||
rLower = getFullyConvertedLowerBounds(this.getRightOperand()) and
|
rLower = getFullyConvertedLowerBounds(getRightOperand()) and
|
||||||
rUpper = getFullyConvertedUpperBounds(this.getRightOperand()) and
|
rUpper = getFullyConvertedUpperBounds(getRightOperand()) and
|
||||||
(
|
(
|
||||||
(lLower < 0 or rLower < 0) and
|
(lLower < 0 or rLower < 0) and
|
||||||
result = exprMaxVal(this)
|
result = exprMaxVal(this)
|
||||||
@@ -85,6 +85,6 @@ private class ConstantBitwiseAndExprRange extends SimpleRangeAnalysisExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override predicate dependsOnChild(Expr child) {
|
override predicate dependsOnChild(Expr child) {
|
||||||
child = this.getLeftOperand() or child = this.getRightOperand()
|
child = getLeftOperand() or child = getRightOperand()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class ConstantRShiftExprRange extends SimpleRangeAnalysisExpr {
|
|||||||
* We don't handle the case where `a` and `b` are both non-constant values.
|
* We don't handle the case where `a` and `b` are both non-constant values.
|
||||||
*/
|
*/
|
||||||
ConstantRShiftExprRange() {
|
ConstantRShiftExprRange() {
|
||||||
this.getUnspecifiedType() instanceof IntegralType and
|
getUnspecifiedType() instanceof IntegralType and
|
||||||
exists(Expr l, Expr r |
|
exists(Expr l, Expr r |
|
||||||
l = this.(RShiftExpr).getLeftOperand() and
|
l = this.(RShiftExpr).getLeftOperand() and
|
||||||
r = this.(RShiftExpr).getRightOperand()
|
r = this.(RShiftExpr).getRightOperand()
|
||||||
@@ -84,10 +84,10 @@ class ConstantRShiftExprRange extends SimpleRangeAnalysisExpr {
|
|||||||
|
|
||||||
override float getLowerBounds() {
|
override float getLowerBounds() {
|
||||||
exists(int lLower, int lUpper, int rLower, int rUpper |
|
exists(int lLower, int lUpper, int rLower, int rUpper |
|
||||||
lLower = getFullyConvertedLowerBounds(this.getLeftOperand()) and
|
lLower = getFullyConvertedLowerBounds(getLeftOperand()) and
|
||||||
lUpper = getFullyConvertedUpperBounds(this.getLeftOperand()) and
|
lUpper = getFullyConvertedUpperBounds(getLeftOperand()) and
|
||||||
rLower = getFullyConvertedLowerBounds(this.getRightOperand()) and
|
rLower = getFullyConvertedLowerBounds(getRightOperand()) and
|
||||||
rUpper = getFullyConvertedUpperBounds(this.getRightOperand()) and
|
rUpper = getFullyConvertedUpperBounds(getRightOperand()) and
|
||||||
lLower <= lUpper and
|
lLower <= lUpper and
|
||||||
rLower <= rUpper
|
rLower <= rUpper
|
||||||
|
|
|
|
||||||
@@ -95,8 +95,8 @@ class ConstantRShiftExprRange extends SimpleRangeAnalysisExpr {
|
|||||||
lLower < 0
|
lLower < 0
|
||||||
or
|
or
|
||||||
not (
|
not (
|
||||||
isValidShiftExprShift(rLower, this.getLeftOperand()) and
|
isValidShiftExprShift(rLower, getLeftOperand()) and
|
||||||
isValidShiftExprShift(rUpper, this.getLeftOperand())
|
isValidShiftExprShift(rUpper, getLeftOperand())
|
||||||
)
|
)
|
||||||
then
|
then
|
||||||
// We don't want to deal with shifting negative numbers at the moment,
|
// We don't want to deal with shifting negative numbers at the moment,
|
||||||
@@ -111,10 +111,10 @@ class ConstantRShiftExprRange extends SimpleRangeAnalysisExpr {
|
|||||||
|
|
||||||
override float getUpperBounds() {
|
override float getUpperBounds() {
|
||||||
exists(int lLower, int lUpper, int rLower, int rUpper |
|
exists(int lLower, int lUpper, int rLower, int rUpper |
|
||||||
lLower = getFullyConvertedLowerBounds(this.getLeftOperand()) and
|
lLower = getFullyConvertedLowerBounds(getLeftOperand()) and
|
||||||
lUpper = getFullyConvertedUpperBounds(this.getLeftOperand()) and
|
lUpper = getFullyConvertedUpperBounds(getLeftOperand()) and
|
||||||
rLower = getFullyConvertedLowerBounds(this.getRightOperand()) and
|
rLower = getFullyConvertedLowerBounds(getRightOperand()) and
|
||||||
rUpper = getFullyConvertedUpperBounds(this.getRightOperand()) and
|
rUpper = getFullyConvertedUpperBounds(getRightOperand()) and
|
||||||
lLower <= lUpper and
|
lLower <= lUpper and
|
||||||
rLower <= rUpper
|
rLower <= rUpper
|
||||||
|
|
|
|
||||||
@@ -122,8 +122,8 @@ class ConstantRShiftExprRange extends SimpleRangeAnalysisExpr {
|
|||||||
lLower < 0
|
lLower < 0
|
||||||
or
|
or
|
||||||
not (
|
not (
|
||||||
isValidShiftExprShift(rLower, this.getLeftOperand()) and
|
isValidShiftExprShift(rLower, getLeftOperand()) and
|
||||||
isValidShiftExprShift(rUpper, this.getLeftOperand())
|
isValidShiftExprShift(rUpper, getLeftOperand())
|
||||||
)
|
)
|
||||||
then
|
then
|
||||||
// We don't want to deal with shifting negative numbers at the moment,
|
// We don't want to deal with shifting negative numbers at the moment,
|
||||||
@@ -137,7 +137,7 @@ class ConstantRShiftExprRange extends SimpleRangeAnalysisExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override predicate dependsOnChild(Expr child) {
|
override predicate dependsOnChild(Expr child) {
|
||||||
child = this.getLeftOperand() or child = this.getRightOperand()
|
child = getLeftOperand() or child = getRightOperand()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ class ConstantLShiftExprRange extends SimpleRangeAnalysisExpr {
|
|||||||
* We don't handle the case where `a` and `b` are both non-constant values.
|
* We don't handle the case where `a` and `b` are both non-constant values.
|
||||||
*/
|
*/
|
||||||
ConstantLShiftExprRange() {
|
ConstantLShiftExprRange() {
|
||||||
this.getUnspecifiedType() instanceof IntegralType and
|
getUnspecifiedType() instanceof IntegralType and
|
||||||
exists(Expr l, Expr r |
|
exists(Expr l, Expr r |
|
||||||
l = this.(LShiftExpr).getLeftOperand() and
|
l = this.(LShiftExpr).getLeftOperand() and
|
||||||
r = this.(LShiftExpr).getRightOperand()
|
r = this.(LShiftExpr).getRightOperand()
|
||||||
@@ -197,10 +197,10 @@ class ConstantLShiftExprRange extends SimpleRangeAnalysisExpr {
|
|||||||
|
|
||||||
override float getLowerBounds() {
|
override float getLowerBounds() {
|
||||||
exists(int lLower, int lUpper, int rLower, int rUpper |
|
exists(int lLower, int lUpper, int rLower, int rUpper |
|
||||||
lLower = getFullyConvertedLowerBounds(this.getLeftOperand()) and
|
lLower = getFullyConvertedLowerBounds(getLeftOperand()) and
|
||||||
lUpper = getFullyConvertedUpperBounds(this.getLeftOperand()) and
|
lUpper = getFullyConvertedUpperBounds(getLeftOperand()) and
|
||||||
rLower = getFullyConvertedLowerBounds(this.getRightOperand()) and
|
rLower = getFullyConvertedLowerBounds(getRightOperand()) and
|
||||||
rUpper = getFullyConvertedUpperBounds(this.getRightOperand()) and
|
rUpper = getFullyConvertedUpperBounds(getRightOperand()) and
|
||||||
lLower <= lUpper and
|
lLower <= lUpper and
|
||||||
rLower <= rUpper
|
rLower <= rUpper
|
||||||
|
|
|
|
||||||
@@ -208,8 +208,8 @@ class ConstantLShiftExprRange extends SimpleRangeAnalysisExpr {
|
|||||||
lLower < 0
|
lLower < 0
|
||||||
or
|
or
|
||||||
not (
|
not (
|
||||||
isValidShiftExprShift(rLower, this.getLeftOperand()) and
|
isValidShiftExprShift(rLower, getLeftOperand()) and
|
||||||
isValidShiftExprShift(rUpper, this.getLeftOperand())
|
isValidShiftExprShift(rUpper, getLeftOperand())
|
||||||
)
|
)
|
||||||
then
|
then
|
||||||
// We don't want to deal with shifting negative numbers at the moment,
|
// We don't want to deal with shifting negative numbers at the moment,
|
||||||
@@ -228,10 +228,10 @@ class ConstantLShiftExprRange extends SimpleRangeAnalysisExpr {
|
|||||||
|
|
||||||
override float getUpperBounds() {
|
override float getUpperBounds() {
|
||||||
exists(int lLower, int lUpper, int rLower, int rUpper |
|
exists(int lLower, int lUpper, int rLower, int rUpper |
|
||||||
lLower = getFullyConvertedLowerBounds(this.getLeftOperand()) and
|
lLower = getFullyConvertedLowerBounds(getLeftOperand()) and
|
||||||
lUpper = getFullyConvertedUpperBounds(this.getLeftOperand()) and
|
lUpper = getFullyConvertedUpperBounds(getLeftOperand()) and
|
||||||
rLower = getFullyConvertedLowerBounds(this.getRightOperand()) and
|
rLower = getFullyConvertedLowerBounds(getRightOperand()) and
|
||||||
rUpper = getFullyConvertedUpperBounds(this.getRightOperand()) and
|
rUpper = getFullyConvertedUpperBounds(getRightOperand()) and
|
||||||
lLower <= lUpper and
|
lLower <= lUpper and
|
||||||
rLower <= rUpper
|
rLower <= rUpper
|
||||||
|
|
|
|
||||||
@@ -239,8 +239,8 @@ class ConstantLShiftExprRange extends SimpleRangeAnalysisExpr {
|
|||||||
lLower < 0
|
lLower < 0
|
||||||
or
|
or
|
||||||
not (
|
not (
|
||||||
isValidShiftExprShift(rLower, this.getLeftOperand()) and
|
isValidShiftExprShift(rLower, getLeftOperand()) and
|
||||||
isValidShiftExprShift(rUpper, this.getLeftOperand())
|
isValidShiftExprShift(rUpper, getLeftOperand())
|
||||||
)
|
)
|
||||||
then
|
then
|
||||||
// We don't want to deal with shifting negative numbers at the moment,
|
// We don't want to deal with shifting negative numbers at the moment,
|
||||||
@@ -258,6 +258,6 @@ class ConstantLShiftExprRange extends SimpleRangeAnalysisExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override predicate dependsOnChild(Expr child) {
|
override predicate dependsOnChild(Expr child) {
|
||||||
child = this.getLeftOperand() or child = this.getRightOperand()
|
child = getLeftOperand() or child = getRightOperand()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,23 +83,20 @@ private class ExprRangeNode extends DataFlow::ExprNode {
|
|||||||
private string getCallBounds(Call e) {
|
private string getCallBounds(Call e) {
|
||||||
result =
|
result =
|
||||||
getExprBoundAsString(e) + "(" +
|
getExprBoundAsString(e) + "(" +
|
||||||
concat(Expr arg, int i |
|
concat(Expr arg, int i | arg = e.getArgument(i) | getIntegralBounds(arg) order by i, ",") +
|
||||||
arg = e.getArgument(i)
|
")"
|
||||||
|
|
|
||||||
this.getIntegralBounds(arg), "," order by i
|
|
||||||
) + ")"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override string toString() {
|
override string toString() {
|
||||||
exists(Expr e | e = this.getExpr() |
|
exists(Expr e | e = getExpr() |
|
||||||
if hasIntegralOrReferenceIntegralType(e)
|
if hasIntegralOrReferenceIntegralType(e)
|
||||||
then
|
then
|
||||||
result = super.toString() + ": " + this.getOperationBounds(e)
|
result = super.toString() + ": " + getOperationBounds(e)
|
||||||
or
|
or
|
||||||
result = super.toString() + ": " + this.getCallBounds(e)
|
result = super.toString() + ": " + getCallBounds(e)
|
||||||
or
|
or
|
||||||
not exists(this.getOperationBounds(e)) and
|
not exists(getOperationBounds(e)) and
|
||||||
not exists(this.getCallBounds(e)) and
|
not exists(getCallBounds(e)) and
|
||||||
result = super.toString() + ": " + getExprBoundAsString(e)
|
result = super.toString() + ": " + getExprBoundAsString(e)
|
||||||
else result = super.toString()
|
else result = super.toString()
|
||||||
)
|
)
|
||||||
@@ -111,8 +108,8 @@ private class ExprRangeNode extends DataFlow::ExprNode {
|
|||||||
*/
|
*/
|
||||||
private class ReferenceArgumentRangeNode extends DataFlow::DefinitionByReferenceNode {
|
private class ReferenceArgumentRangeNode extends DataFlow::DefinitionByReferenceNode {
|
||||||
override string toString() {
|
override string toString() {
|
||||||
if hasIntegralOrReferenceIntegralType(this.asDefiningArgument())
|
if hasIntegralOrReferenceIntegralType(asDefiningArgument())
|
||||||
then result = super.toString() + ": " + getExprBoundAsString(this.getArgument())
|
then result = super.toString() + ": " + getExprBoundAsString(getArgument())
|
||||||
else result = super.toString()
|
else result = super.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ private import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysi
|
|||||||
*/
|
*/
|
||||||
class StrlenLiteralRangeExpr extends SimpleRangeAnalysisExpr, FunctionCall {
|
class StrlenLiteralRangeExpr extends SimpleRangeAnalysisExpr, FunctionCall {
|
||||||
StrlenLiteralRangeExpr() {
|
StrlenLiteralRangeExpr() {
|
||||||
this.getTarget().hasGlobalOrStdName("strlen") and this.getArgument(0).isConstant()
|
getTarget().hasGlobalOrStdName("strlen") and getArgument(0).isConstant()
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getLowerBounds() { result = this.getArgument(0).getValue().length() }
|
override int getLowerBounds() { result = getArgument(0).getValue().length() }
|
||||||
|
|
||||||
override int getUpperBounds() { result = this.getArgument(0).getValue().length() }
|
override int getUpperBounds() { result = getArgument(0).getValue().length() }
|
||||||
|
|
||||||
override predicate dependsOnChild(Expr e) { none() }
|
override predicate dependsOnChild(Expr e) { none() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysisExpr
|
|||||||
private class SelfSub extends SimpleRangeAnalysisExpr, SubExpr {
|
private class SelfSub extends SimpleRangeAnalysisExpr, SubExpr {
|
||||||
SelfSub() {
|
SelfSub() {
|
||||||
// Match `x - x` but not `myInt - (unsigned char)myInt`.
|
// Match `x - x` but not `myInt - (unsigned char)myInt`.
|
||||||
this.getLeftOperand().getExplicitlyConverted().(VariableAccess).getTarget() =
|
getLeftOperand().getExplicitlyConverted().(VariableAccess).getTarget() =
|
||||||
this.getRightOperand().getExplicitlyConverted().(VariableAccess).getTarget()
|
getRightOperand().getExplicitlyConverted().(VariableAccess).getTarget()
|
||||||
}
|
}
|
||||||
|
|
||||||
override float getLowerBounds() { result = 0 }
|
override float getLowerBounds() { result = 0 }
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ external string selectedSourceFile();
|
|||||||
|
|
||||||
class Cfg extends PrintAstConfiguration {
|
class Cfg extends PrintAstConfiguration {
|
||||||
/**
|
/**
|
||||||
* Holds if the AST for `decl` should be printed.
|
* Holds if the AST for `func` should be printed.
|
||||||
* Print All declarations from the selected file.
|
* Print All functions from the selected file.
|
||||||
*/
|
*/
|
||||||
override predicate shouldPrintDeclaration(Declaration decl) {
|
override predicate shouldPrintFunction(Function func) {
|
||||||
decl.getFile() = getFileBySourceArchiveName(selectedSourceFile())
|
func.getFile() = getFileBySourceArchiveName(selectedSourceFile())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
name: codeql/cpp-all
|
name: codeql/cpp-all
|
||||||
version: 0.9.2
|
version: 0.7.2-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dbscheme: semmlecode.cpp.dbscheme
|
dbscheme: semmlecode.cpp.dbscheme
|
||||||
extractor: cpp
|
extractor: cpp
|
||||||
library: true
|
library: true
|
||||||
upgrades: upgrades
|
upgrades: upgrades
|
||||||
dependencies:
|
dependencies:
|
||||||
codeql/dataflow: ${workspace}
|
|
||||||
codeql/ssa: ${workspace}
|
codeql/ssa: ${workspace}
|
||||||
codeql/tutorial: ${workspace}
|
codeql/tutorial: ${workspace}
|
||||||
codeql/util: ${workspace}
|
codeql/util: ${workspace}
|
||||||
warnOnImplicitThis: true
|
|
||||||
|
|||||||
@@ -176,6 +176,20 @@ class Class extends UserType {
|
|||||||
/** Holds if this class, struct or union has a constructor. */
|
/** Holds if this class, struct or union has a constructor. */
|
||||||
predicate hasConstructor() { exists(this.getAConstructor()) }
|
predicate hasConstructor() { exists(this.getAConstructor()) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this class has a copy constructor that is either explicitly
|
||||||
|
* declared (though possibly `= delete`) or is auto-generated, non-trivial
|
||||||
|
* and called from somewhere.
|
||||||
|
*
|
||||||
|
* DEPRECATED: There is more than one reasonable definition of what it means
|
||||||
|
* to have a copy constructor, and we do not want to promote one particular
|
||||||
|
* definition by naming it with this predicate. Having a copy constructor
|
||||||
|
* could mean that such a member is declared or defined in the source or that
|
||||||
|
* it is callable by a particular caller. For C++11, there's also a question
|
||||||
|
* of whether to include members that are defaulted or deleted.
|
||||||
|
*/
|
||||||
|
deprecated predicate hasCopyConstructor() { this.getAMemberFunction() instanceof CopyConstructor }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like accessOfBaseMember but returns multiple results if there are multiple
|
* Like accessOfBaseMember but returns multiple results if there are multiple
|
||||||
* paths to `base` through the inheritance graph.
|
* paths to `base` through the inheritance graph.
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class Compilation extends @compilation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a file compiled during this invocation. */
|
/** Gets a file compiled during this invocation. */
|
||||||
File getAFileCompiled() { result = this.getFileCompiled(_) }
|
File getAFileCompiled() { result = getFileCompiled(_) }
|
||||||
|
|
||||||
/** Gets the `i`th file compiled during this invocation */
|
/** Gets the `i`th file compiled during this invocation */
|
||||||
File getFileCompiled(int i) { compilation_compiling_files(this, i, unresolveElement(result)) }
|
File getFileCompiled(int i) { compilation_compiling_files(this, i, unresolveElement(result)) }
|
||||||
@@ -74,7 +74,7 @@ class Compilation extends @compilation {
|
|||||||
/**
|
/**
|
||||||
* Gets an argument passed to the extractor on this invocation.
|
* Gets an argument passed to the extractor on this invocation.
|
||||||
*/
|
*/
|
||||||
string getAnArgument() { result = this.getArgument(_) }
|
string getAnArgument() { result = getArgument(_) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the `i`th argument passed to the extractor on this invocation.
|
* Gets the `i`th argument passed to the extractor on this invocation.
|
||||||
|
|||||||
@@ -39,8 +39,7 @@ class Field extends MemberVariable {
|
|||||||
* complete most-derived object.
|
* complete most-derived object.
|
||||||
*/
|
*/
|
||||||
int getAByteOffsetIn(Class mostDerivedClass) {
|
int getAByteOffsetIn(Class mostDerivedClass) {
|
||||||
result =
|
result = mostDerivedClass.getABaseClassByteOffset(getDeclaringType()) + getByteOffset()
|
||||||
mostDerivedClass.getABaseClassByteOffset(this.getDeclaringType()) + this.getByteOffset()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,10 +116,10 @@ class BitField extends Field {
|
|||||||
int getBitOffset() { fieldoffsets(underlyingElement(this), _, result) }
|
int getBitOffset() { fieldoffsets(underlyingElement(this), _, result) }
|
||||||
|
|
||||||
/** Holds if this bitfield is anonymous. */
|
/** Holds if this bitfield is anonymous. */
|
||||||
predicate isAnonymous() { this.hasName("(unnamed bitfield)") }
|
predicate isAnonymous() { hasName("(unnamed bitfield)") }
|
||||||
|
|
||||||
override predicate isInitializable() {
|
override predicate isInitializable() {
|
||||||
// Anonymous bitfields are not initializable.
|
// Anonymous bitfields are not initializable.
|
||||||
not this.isAnonymous()
|
not isAnonymous()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,14 @@ class Container extends Locatable, @container {
|
|||||||
*/
|
*/
|
||||||
string getAbsolutePath() { none() } // overridden by subclasses
|
string getAbsolutePath() { none() } // overridden by subclasses
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED: Use `getLocation` instead.
|
||||||
|
* Gets a URL representing the location of this container.
|
||||||
|
*
|
||||||
|
* For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls).
|
||||||
|
*/
|
||||||
|
deprecated string getURL() { none() } // overridden by subclasses
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the relative path of this file or folder from the root folder of the
|
* Gets the relative path of this file or folder from the root folder of the
|
||||||
* analyzed source location. The relative path of the root folder itself is
|
* analyzed source location. The relative path of the root folder itself is
|
||||||
@@ -175,6 +183,12 @@ class Folder extends Container, @folder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "Folder" }
|
override string getAPrimaryQlClass() { result = "Folder" }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED: Use `getLocation` instead.
|
||||||
|
* Gets the URL of this folder.
|
||||||
|
*/
|
||||||
|
deprecated override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -199,6 +213,12 @@ class File extends Container, @file {
|
|||||||
result.hasLocationInfo(_, 0, 0, 0, 0)
|
result.hasLocationInfo(_, 0, 0, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED: Use `getLocation` instead.
|
||||||
|
* Gets the URL of this file.
|
||||||
|
*/
|
||||||
|
deprecated override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
|
||||||
|
|
||||||
/** Holds if this file was compiled as C (at any point). */
|
/** Holds if this file was compiled as C (at any point). */
|
||||||
predicate compiledAsC() { fileannotations(underlyingElement(this), 1, "compiled as c", "1") }
|
predicate compiledAsC() { fileannotations(underlyingElement(this), 1, "compiled as c", "1") }
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ class LinkTarget extends @link_target {
|
|||||||
* captured as part of the snapshot, then everything is grouped together
|
* captured as part of the snapshot, then everything is grouped together
|
||||||
* into a single dummy link target.
|
* into a single dummy link target.
|
||||||
*/
|
*/
|
||||||
predicate isDummy() { this.getBinary().getAbsolutePath() = "" }
|
predicate isDummy() { getBinary().getAbsolutePath() = "" }
|
||||||
|
|
||||||
/** Gets a textual representation of this element. */
|
/** Gets a textual representation of this element. */
|
||||||
string toString() { result = this.getBinary().getAbsolutePath() }
|
string toString() { result = getBinary().getAbsolutePath() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a function which was compiled into this link target, or had its
|
* Gets a function which was compiled into this link target, or had its
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class Macro extends PreprocessorDirective, @ppd_define {
|
|||||||
* Gets the name of the macro. For example, `MAX` in
|
* Gets the name of the macro. For example, `MAX` in
|
||||||
* `#define MAX(x,y) (((x)>(y))?(x):(y))`.
|
* `#define MAX(x,y) (((x)>(y))?(x):(y))`.
|
||||||
*/
|
*/
|
||||||
string getName() { result = this.getHead().regexpCapture("([^(]*+).*", 1) }
|
string getName() { result = this.getHead().splitAt("(", 0) }
|
||||||
|
|
||||||
/** Holds if the macro has name `name`. */
|
/** Holds if the macro has name `name`. */
|
||||||
predicate hasName(string name) { this.getName() = name }
|
predicate hasName(string name) { this.getName() = name }
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class NameQualifier extends NameQualifiableElement, @namequalifier {
|
|||||||
* Gets the expression ultimately qualified by the chain of name
|
* Gets the expression ultimately qualified by the chain of name
|
||||||
* qualifiers. For example, `f()` in `N1::N2::f()`.
|
* qualifiers. For example, `f()` in `N1::N2::f()`.
|
||||||
*/
|
*/
|
||||||
Expr getExpr() { result = this.getQualifiedElement+() }
|
Expr getExpr() { result = getQualifiedElement+() }
|
||||||
|
|
||||||
/** Gets a location for this name qualifier. */
|
/** Gets a location for this name qualifier. */
|
||||||
override Location getLocation() { namequalifiers(underlyingElement(this), _, _, result) }
|
override Location getLocation() { namequalifiers(underlyingElement(this), _, _, result) }
|
||||||
@@ -56,12 +56,12 @@ class NameQualifier extends NameQualifiableElement, @namequalifier {
|
|||||||
if nqe instanceof SpecialNameQualifyingElement
|
if nqe instanceof SpecialNameQualifyingElement
|
||||||
then
|
then
|
||||||
exists(Access a |
|
exists(Access a |
|
||||||
a = this.getQualifiedElement() and
|
a = getQualifiedElement() and
|
||||||
result = a.getTarget().getDeclaringType()
|
result = a.getTarget().getDeclaringType()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(FunctionCall c |
|
exists(FunctionCall c |
|
||||||
c = this.getQualifiedElement() and
|
c = getQualifiedElement() and
|
||||||
result = c.getTarget().getDeclaringType()
|
result = c.getTarget().getDeclaringType()
|
||||||
)
|
)
|
||||||
else result = nqe
|
else result = nqe
|
||||||
@@ -109,7 +109,7 @@ class NameQualifiableElement extends Element, @namequalifiableelement {
|
|||||||
* namespace.
|
* namespace.
|
||||||
*/
|
*/
|
||||||
predicate hasGlobalQualifiedName() {
|
predicate hasGlobalQualifiedName() {
|
||||||
this.getNameQualifier*().getQualifyingElement() instanceof GlobalNamespace
|
getNameQualifier*().getQualifyingElement() instanceof GlobalNamespace
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,7 +119,7 @@ class NameQualifiableElement extends Element, @namequalifiableelement {
|
|||||||
*/
|
*/
|
||||||
predicate hasSuperQualifiedName() {
|
predicate hasSuperQualifiedName() {
|
||||||
exists(NameQualifier nq, SpecialNameQualifyingElement snqe |
|
exists(NameQualifier nq, SpecialNameQualifyingElement snqe |
|
||||||
nq = this.getNameQualifier*() and
|
nq = getNameQualifier*() and
|
||||||
namequalifiers(unresolveElement(nq), _, unresolveElement(snqe), _) and
|
namequalifiers(unresolveElement(nq), _, unresolveElement(snqe), _) and
|
||||||
snqe.getName() = "__super"
|
snqe.getName() = "__super"
|
||||||
)
|
)
|
||||||
@@ -164,5 +164,5 @@ library class SpecialNameQualifyingElement extends NameQualifyingElement,
|
|||||||
/** Gets the name of this special qualifying element. */
|
/** Gets the name of this special qualifying element. */
|
||||||
override string getName() { specialnamequalifyingelements(underlyingElement(this), result) }
|
override string getName() { specialnamequalifyingelements(underlyingElement(this), result) }
|
||||||
|
|
||||||
override string toString() { result = this.getName() }
|
override string toString() { result = getName() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -230,12 +230,8 @@ class GlobalNamespace extends Namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The C++ `std::` namespace and its inline namespaces.
|
* The C++ `std::` namespace.
|
||||||
*/
|
*/
|
||||||
class StdNamespace extends Namespace {
|
class StdNamespace extends Namespace {
|
||||||
StdNamespace() {
|
StdNamespace() { this.hasName("std") and this.getParentNamespace() instanceof GlobalNamespace }
|
||||||
this.hasName("std") and this.getParentNamespace() instanceof GlobalNamespace
|
|
||||||
or
|
|
||||||
this.isInline() and this.getParentNamespace() instanceof StdNamespace
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class NestedFieldAccess extends FieldAccess {
|
|||||||
|
|
||||||
NestedFieldAccess() {
|
NestedFieldAccess() {
|
||||||
ultimateQualifier = getUltimateQualifier(this) and
|
ultimateQualifier = getUltimateQualifier(this) and
|
||||||
this.getTarget() = getANestedField(ultimateQualifier.getType().stripType())
|
getTarget() = getANestedField(ultimateQualifier.getType().stripType())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,9 +6,11 @@ private import PrintAST
|
|||||||
* that requests that function, or no `PrintASTConfiguration` exists.
|
* that requests that function, or no `PrintASTConfiguration` exists.
|
||||||
*/
|
*/
|
||||||
private predicate shouldPrintDeclaration(Declaration decl) {
|
private predicate shouldPrintDeclaration(Declaration decl) {
|
||||||
not (decl instanceof Function or decl instanceof GlobalOrNamespaceVariable)
|
not decl instanceof Function
|
||||||
or
|
or
|
||||||
exists(PrintAstConfiguration config | config.shouldPrintDeclaration(decl))
|
not exists(PrintAstConfiguration c)
|
||||||
|
or
|
||||||
|
exists(PrintAstConfiguration config | config.shouldPrintFunction(decl))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import cpp
|
|||||||
import PrintAST
|
import PrintAST
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Temporarily tweak this class or make a copy to control which declarations are
|
* Temporarily tweak this class or make a copy to control which functions are
|
||||||
* printed.
|
* printed.
|
||||||
*/
|
*/
|
||||||
class Cfg extends PrintAstConfiguration {
|
class Cfg extends PrintAstConfiguration {
|
||||||
/**
|
/**
|
||||||
* TWEAK THIS PREDICATE AS NEEDED.
|
* TWEAK THIS PREDICATE AS NEEDED.
|
||||||
* Holds if the AST for `decl` should be printed.
|
* Holds if the AST for `func` should be printed.
|
||||||
*/
|
*/
|
||||||
override predicate shouldPrintDeclaration(Declaration decl) { any() }
|
override predicate shouldPrintFunction(Function func) { any() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* Provides queries to pretty-print a C++ AST as a graph.
|
* Provides queries to pretty-print a C++ AST as a graph.
|
||||||
*
|
*
|
||||||
* By default, this will print the AST for all functions and global and namespace variables in
|
* By default, this will print the AST for all functions in the database. To change this behavior,
|
||||||
* the database. To change this behavior, extend `PrintASTConfiguration` and override
|
* extend `PrintASTConfiguration` and override `shouldPrintFunction` to hold for only the functions
|
||||||
* `shouldPrintDeclaration` to hold for only the declarations you wish to view the AST for.
|
* you wish to view the AST for.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
@@ -12,7 +12,7 @@ private import semmle.code.cpp.Print
|
|||||||
private newtype TPrintAstConfiguration = MkPrintAstConfiguration()
|
private newtype TPrintAstConfiguration = MkPrintAstConfiguration()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The query can extend this class to control which declarations are printed.
|
* The query can extend this class to control which functions are printed.
|
||||||
*/
|
*/
|
||||||
class PrintAstConfiguration extends TPrintAstConfiguration {
|
class PrintAstConfiguration extends TPrintAstConfiguration {
|
||||||
/**
|
/**
|
||||||
@@ -21,16 +21,17 @@ class PrintAstConfiguration extends TPrintAstConfiguration {
|
|||||||
string toString() { result = "PrintASTConfiguration" }
|
string toString() { result = "PrintASTConfiguration" }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the AST for `decl` should be printed. By default, holds for all
|
* Holds if the AST for `func` should be printed. By default, holds for all
|
||||||
* functions and global and namespace variables. Currently, does not support any
|
* functions.
|
||||||
* other declaration types.
|
|
||||||
*/
|
*/
|
||||||
predicate shouldPrintDeclaration(Declaration decl) { any() }
|
predicate shouldPrintFunction(Function func) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate shouldPrintDeclaration(Declaration decl) {
|
/** DEPRECATED: Alias for PrintAstConfiguration */
|
||||||
exists(PrintAstConfiguration config | config.shouldPrintDeclaration(decl)) and
|
deprecated class PrintASTConfiguration = PrintAstConfiguration;
|
||||||
(decl instanceof Function or decl instanceof GlobalOrNamespaceVariable)
|
|
||||||
|
private predicate shouldPrintFunction(Function func) {
|
||||||
|
exists(PrintAstConfiguration config | config.shouldPrintFunction(func))
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[s]
|
bindingset[s]
|
||||||
@@ -71,7 +72,7 @@ private predicate locationSortKeys(Locatable ast, string file, int line, int col
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private Declaration getAnEnclosingDeclaration(Locatable ast) {
|
private Function getEnclosingFunction(Locatable ast) {
|
||||||
result = ast.(Expr).getEnclosingFunction()
|
result = ast.(Expr).getEnclosingFunction()
|
||||||
or
|
or
|
||||||
result = ast.(Stmt).getEnclosingFunction()
|
result = ast.(Stmt).getEnclosingFunction()
|
||||||
@@ -80,10 +81,6 @@ private Declaration getAnEnclosingDeclaration(Locatable ast) {
|
|||||||
or
|
or
|
||||||
result = ast.(Parameter).getFunction()
|
result = ast.(Parameter).getFunction()
|
||||||
or
|
or
|
||||||
result = ast.(Expr).getEnclosingDeclaration()
|
|
||||||
or
|
|
||||||
result = ast.(Initializer).getDeclaration()
|
|
||||||
or
|
|
||||||
result = ast
|
result = ast
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,21 +89,21 @@ private Declaration getAnEnclosingDeclaration(Locatable ast) {
|
|||||||
* nodes for things like parameter lists and constructor init lists.
|
* nodes for things like parameter lists and constructor init lists.
|
||||||
*/
|
*/
|
||||||
private newtype TPrintAstNode =
|
private newtype TPrintAstNode =
|
||||||
TAstNode(Locatable ast) { shouldPrintDeclaration(getAnEnclosingDeclaration(ast)) } or
|
TAstNode(Locatable ast) { shouldPrintFunction(getEnclosingFunction(ast)) } or
|
||||||
TDeclarationEntryNode(DeclStmt stmt, DeclarationEntry entry) {
|
TDeclarationEntryNode(DeclStmt stmt, DeclarationEntry entry) {
|
||||||
// We create a unique node for each pair of (stmt, entry), to avoid having one node with
|
// We create a unique node for each pair of (stmt, entry), to avoid having one node with
|
||||||
// multiple parents due to extractor bug CPP-413.
|
// multiple parents due to extractor bug CPP-413.
|
||||||
stmt.getADeclarationEntry() = entry and
|
stmt.getADeclarationEntry() = entry and
|
||||||
shouldPrintDeclaration(stmt.getEnclosingFunction())
|
shouldPrintFunction(stmt.getEnclosingFunction())
|
||||||
} or
|
} or
|
||||||
TParametersNode(Function func) { shouldPrintDeclaration(func) } or
|
TParametersNode(Function func) { shouldPrintFunction(func) } or
|
||||||
TConstructorInitializersNode(Constructor ctor) {
|
TConstructorInitializersNode(Constructor ctor) {
|
||||||
ctor.hasEntryPoint() and
|
ctor.hasEntryPoint() and
|
||||||
shouldPrintDeclaration(ctor)
|
shouldPrintFunction(ctor)
|
||||||
} or
|
} or
|
||||||
TDestructorDestructionsNode(Destructor dtor) {
|
TDestructorDestructionsNode(Destructor dtor) {
|
||||||
dtor.hasEntryPoint() and
|
dtor.hasEntryPoint() and
|
||||||
shouldPrintDeclaration(dtor)
|
shouldPrintFunction(dtor)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -133,7 +130,7 @@ class PrintAstNode extends TPrintAstNode {
|
|||||||
// The exact value of `childIndex` doesn't matter, as long as we preserve the correct order.
|
// The exact value of `childIndex` doesn't matter, as long as we preserve the correct order.
|
||||||
result =
|
result =
|
||||||
rank[childIndex](PrintAstNode child, int nonConvertedIndex, boolean isConverted |
|
rank[childIndex](PrintAstNode child, int nonConvertedIndex, boolean isConverted |
|
||||||
this.childAndAccessorPredicate(child, _, nonConvertedIndex, isConverted)
|
childAndAccessorPredicate(child, _, nonConvertedIndex, isConverted)
|
||||||
|
|
|
|
||||||
// Unconverted children come first, then sort by original child index within each group.
|
// Unconverted children come first, then sort by original child index within each group.
|
||||||
child order by isConverted, nonConvertedIndex
|
child order by isConverted, nonConvertedIndex
|
||||||
@@ -146,7 +143,7 @@ class PrintAstNode extends TPrintAstNode {
|
|||||||
*/
|
*/
|
||||||
private PrintAstNode getConvertedChild(int childIndex) {
|
private PrintAstNode getConvertedChild(int childIndex) {
|
||||||
exists(Expr expr |
|
exists(Expr expr |
|
||||||
expr = this.getChildInternal(childIndex).(AstNode).getAst() and
|
expr = getChildInternal(childIndex).(AstNode).getAst() and
|
||||||
expr.getFullyConverted() instanceof Conversion and
|
expr.getFullyConverted() instanceof Conversion and
|
||||||
result.(AstNode).getAst() = expr.getFullyConverted() and
|
result.(AstNode).getAst() = expr.getFullyConverted() and
|
||||||
not expr instanceof Conversion
|
not expr instanceof Conversion
|
||||||
@@ -158,21 +155,21 @@ class PrintAstNode extends TPrintAstNode {
|
|||||||
* at index `childIndex`, if that node has any conversions.
|
* at index `childIndex`, if that node has any conversions.
|
||||||
*/
|
*/
|
||||||
private string getConvertedChildAccessorPredicate(int childIndex) {
|
private string getConvertedChildAccessorPredicate(int childIndex) {
|
||||||
exists(this.getConvertedChild(childIndex)) and
|
exists(getConvertedChild(childIndex)) and
|
||||||
result = this.getChildAccessorPredicateInternal(childIndex) + ".getFullyConverted()"
|
result = getChildAccessorPredicateInternal(childIndex) + ".getFullyConverted()"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this node should be printed in the output. By default, all nodes
|
* Holds if this node should be printed in the output. By default, all nodes
|
||||||
* within functions and global and namespace variables are printed, but the query
|
* within a function are printed, but the query can override
|
||||||
* can override `PrintASTConfiguration.shouldPrintDeclaration` to filter the output.
|
* `PrintASTConfiguration.shouldPrintFunction` to filter the output.
|
||||||
*/
|
*/
|
||||||
final predicate shouldPrint() { shouldPrintDeclaration(this.getEnclosingDeclaration()) }
|
final predicate shouldPrint() { shouldPrintFunction(getEnclosingFunction()) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the children of this node.
|
* Gets the children of this node.
|
||||||
*/
|
*/
|
||||||
final PrintAstNode getAChild() { result = this.getChild(_) }
|
final PrintAstNode getAChild() { result = getChild(_) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the parent of this node, if any.
|
* Gets the parent of this node, if any.
|
||||||
@@ -190,7 +187,7 @@ class PrintAstNode extends TPrintAstNode {
|
|||||||
*/
|
*/
|
||||||
string getProperty(string key) {
|
string getProperty(string key) {
|
||||||
key = "semmle.label" and
|
key = "semmle.label" and
|
||||||
result = this.toString()
|
result = toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -204,12 +201,12 @@ class PrintAstNode extends TPrintAstNode {
|
|||||||
private predicate childAndAccessorPredicate(
|
private predicate childAndAccessorPredicate(
|
||||||
PrintAstNode child, string childPredicate, int nonConvertedIndex, boolean isConverted
|
PrintAstNode child, string childPredicate, int nonConvertedIndex, boolean isConverted
|
||||||
) {
|
) {
|
||||||
child = this.getChildInternal(nonConvertedIndex) and
|
child = getChildInternal(nonConvertedIndex) and
|
||||||
childPredicate = this.getChildAccessorPredicateInternal(nonConvertedIndex) and
|
childPredicate = getChildAccessorPredicateInternal(nonConvertedIndex) and
|
||||||
isConverted = false
|
isConverted = false
|
||||||
or
|
or
|
||||||
child = this.getConvertedChild(nonConvertedIndex) and
|
child = getConvertedChild(nonConvertedIndex) and
|
||||||
childPredicate = this.getConvertedChildAccessorPredicate(nonConvertedIndex) and
|
childPredicate = getConvertedChildAccessorPredicate(nonConvertedIndex) and
|
||||||
isConverted = true
|
isConverted = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +218,7 @@ class PrintAstNode extends TPrintAstNode {
|
|||||||
// The exact value of `childIndex` doesn't matter, as long as we preserve the correct order.
|
// The exact value of `childIndex` doesn't matter, as long as we preserve the correct order.
|
||||||
result =
|
result =
|
||||||
rank[childIndex](string childPredicate, int nonConvertedIndex, boolean isConverted |
|
rank[childIndex](string childPredicate, int nonConvertedIndex, boolean isConverted |
|
||||||
this.childAndAccessorPredicate(_, childPredicate, nonConvertedIndex, isConverted)
|
childAndAccessorPredicate(_, childPredicate, nonConvertedIndex, isConverted)
|
||||||
|
|
|
|
||||||
// Unconverted children come first, then sort by original child index within each group.
|
// Unconverted children come first, then sort by original child index within each group.
|
||||||
childPredicate order by isConverted, nonConvertedIndex
|
childPredicate order by isConverted, nonConvertedIndex
|
||||||
@@ -235,18 +232,14 @@ class PrintAstNode extends TPrintAstNode {
|
|||||||
abstract string getChildAccessorPredicateInternal(int childIndex);
|
abstract string getChildAccessorPredicateInternal(int childIndex);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the `Declaration` that contains this node.
|
* Gets the `Function` that contains this node.
|
||||||
*/
|
*/
|
||||||
private Declaration getEnclosingDeclaration() { result = this.getParent*().getDeclaration() }
|
private Function getEnclosingFunction() { result = getParent*().(FunctionNode).getFunction() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the `Declaration` this node represents.
|
|
||||||
*/
|
|
||||||
private Declaration getDeclaration() {
|
|
||||||
result = this.(AstNode).getAst() and shouldPrintDeclaration(result)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for PrintAstNode */
|
||||||
|
deprecated class PrintASTNode = PrintAstNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that restricts the elements that we compute `qlClass` for.
|
* Class that restricts the elements that we compute `qlClass` for.
|
||||||
*/
|
*/
|
||||||
@@ -260,7 +253,7 @@ private class PrintableElement extends Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
string getAPrimaryQlClass0() { result = this.getAPrimaryQlClass() }
|
string getAPrimaryQlClass0() { result = getAPrimaryQlClass() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -288,9 +281,12 @@ abstract class BaseAstNode extends PrintAstNode {
|
|||||||
final Locatable getAst() { result = ast }
|
final Locatable getAst() { result = ast }
|
||||||
|
|
||||||
/** DEPRECATED: Alias for getAst */
|
/** DEPRECATED: Alias for getAst */
|
||||||
deprecated Locatable getAST() { result = this.getAst() }
|
deprecated Locatable getAST() { result = getAst() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for BaseAstNode */
|
||||||
|
deprecated class BaseASTNode = BaseAstNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node representing an AST node other than a `DeclarationEntry`.
|
* A node representing an AST node other than a `DeclarationEntry`.
|
||||||
*/
|
*/
|
||||||
@@ -298,6 +294,9 @@ abstract class AstNode extends BaseAstNode, TAstNode {
|
|||||||
AstNode() { this = TAstNode(ast) }
|
AstNode() { this = TAstNode(ast) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for AstNode */
|
||||||
|
deprecated class ASTNode = AstNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node representing an `Expr`.
|
* A node representing an `Expr`.
|
||||||
*/
|
*/
|
||||||
@@ -312,7 +311,7 @@ class ExprNode extends AstNode {
|
|||||||
result = super.getProperty(key)
|
result = super.getProperty(key)
|
||||||
or
|
or
|
||||||
key = "Value" and
|
key = "Value" and
|
||||||
result = qlClass(expr) + this.getValue()
|
result = qlClass(expr) + getValue()
|
||||||
or
|
or
|
||||||
key = "Type" and
|
key = "Type" and
|
||||||
result = qlClass(expr.getType()) + expr.getType().toString()
|
result = qlClass(expr.getType()) + expr.getType().toString()
|
||||||
@@ -322,7 +321,7 @@ class ExprNode extends AstNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||||
result = getChildAccessorWithoutConversions(ast, this.getChildInternal(childIndex).getAst())
|
result = getChildAccessorWithoutConversions(ast, getChildInternal(childIndex).getAst())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -442,7 +441,7 @@ class StmtNode extends AstNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||||
result = getChildAccessorWithoutConversions(ast, this.getChildInternal(childIndex).getAst())
|
result = getChildAccessorWithoutConversions(ast, getChildInternal(childIndex).getAst())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,7 +517,7 @@ class ParametersNode extends PrintAstNode, TParametersNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||||
exists(this.getChildInternal(childIndex)) and
|
exists(getChildInternal(childIndex)) and
|
||||||
result = "getParameter(" + childIndex.toString() + ")"
|
result = "getParameter(" + childIndex.toString() + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -545,7 +544,7 @@ class ConstructorInitializersNode extends PrintAstNode, TConstructorInitializers
|
|||||||
}
|
}
|
||||||
|
|
||||||
final override string getChildAccessorPredicateInternal(int childIndex) {
|
final override string getChildAccessorPredicateInternal(int childIndex) {
|
||||||
exists(this.getChildInternal(childIndex)) and
|
exists(getChildInternal(childIndex)) and
|
||||||
result = "getInitializer(" + childIndex.toString() + ")"
|
result = "getInitializer(" + childIndex.toString() + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,7 +571,7 @@ class DestructorDestructionsNode extends PrintAstNode, TDestructorDestructionsNo
|
|||||||
}
|
}
|
||||||
|
|
||||||
final override string getChildAccessorPredicateInternal(int childIndex) {
|
final override string getChildAccessorPredicateInternal(int childIndex) {
|
||||||
exists(this.getChildInternal(childIndex)) and
|
exists(getChildInternal(childIndex)) and
|
||||||
result = "getDestruction(" + childIndex.toString() + ")"
|
result = "getDestruction(" + childIndex.toString() + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -582,53 +581,16 @@ class DestructorDestructionsNode extends PrintAstNode, TDestructorDestructionsNo
|
|||||||
final Destructor getDestructor() { result = dtor }
|
final Destructor getDestructor() { result = dtor }
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract private class FunctionOrGlobalOrNamespaceVariableNode extends AstNode {
|
|
||||||
override string toString() { result = qlClass(ast) + getIdentityString(ast) }
|
|
||||||
|
|
||||||
private int getOrder() {
|
|
||||||
this =
|
|
||||||
rank[result](FunctionOrGlobalOrNamespaceVariableNode node, Declaration decl, string file,
|
|
||||||
int line, int column |
|
|
||||||
node.getAst() = decl and
|
|
||||||
locationSortKeys(decl, file, line, column)
|
|
||||||
|
|
|
||||||
node order by file, line, column, getIdentityString(decl)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override string getProperty(string key) {
|
|
||||||
result = super.getProperty(key)
|
|
||||||
or
|
|
||||||
key = "semmle.order" and result = this.getOrder().toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A node representing a `GlobalOrNamespaceVariable`.
|
|
||||||
*/
|
|
||||||
class GlobalOrNamespaceVariableNode extends FunctionOrGlobalOrNamespaceVariableNode {
|
|
||||||
GlobalOrNamespaceVariable var;
|
|
||||||
|
|
||||||
GlobalOrNamespaceVariableNode() { var = ast }
|
|
||||||
|
|
||||||
override PrintAstNode getChildInternal(int childIndex) {
|
|
||||||
childIndex = 0 and
|
|
||||||
result.(AstNode).getAst() = var.getInitializer()
|
|
||||||
}
|
|
||||||
|
|
||||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
|
||||||
childIndex = 0 and result = "getInitializer()"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node representing a `Function`.
|
* A node representing a `Function`.
|
||||||
*/
|
*/
|
||||||
class FunctionNode extends FunctionOrGlobalOrNamespaceVariableNode {
|
class FunctionNode extends AstNode {
|
||||||
Function func;
|
Function func;
|
||||||
|
|
||||||
FunctionNode() { func = ast }
|
FunctionNode() { func = ast }
|
||||||
|
|
||||||
|
override string toString() { result = qlClass(func) + getIdentityString(func) }
|
||||||
|
|
||||||
override PrintAstNode getChildInternal(int childIndex) {
|
override PrintAstNode getChildInternal(int childIndex) {
|
||||||
childIndex = 0 and
|
childIndex = 0 and
|
||||||
result.(ParametersNode).getFunction() = func
|
result.(ParametersNode).getFunction() = func
|
||||||
@@ -652,10 +614,31 @@ class FunctionNode extends FunctionOrGlobalOrNamespaceVariableNode {
|
|||||||
or
|
or
|
||||||
childIndex = 3 and result = "<destructions>"
|
childIndex = 3 and result = "<destructions>"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getOrder() {
|
||||||
|
this =
|
||||||
|
rank[result](FunctionNode node, Function function, string file, int line, int column |
|
||||||
|
node.getAst() = function and
|
||||||
|
locationSortKeys(function, file, line, column)
|
||||||
|
|
|
||||||
|
node order by file, line, column, getIdentityString(function)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getProperty(string key) {
|
||||||
|
result = super.getProperty(key)
|
||||||
|
or
|
||||||
|
key = "semmle.order" and result = getOrder().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the `Function` this node represents.
|
||||||
|
*/
|
||||||
|
final Function getFunction() { result = func }
|
||||||
}
|
}
|
||||||
|
|
||||||
private string getChildAccessorWithoutConversions(Locatable parent, Element child) {
|
private string getChildAccessorWithoutConversions(Locatable parent, Element child) {
|
||||||
shouldPrintDeclaration(getAnEnclosingDeclaration(parent)) and
|
shouldPrintFunction(getEnclosingFunction(parent)) and
|
||||||
(
|
(
|
||||||
exists(Stmt s | s = parent |
|
exists(Stmt s | s = parent |
|
||||||
namedStmtChildPredicates(s, child, result)
|
namedStmtChildPredicates(s, child, result)
|
||||||
@@ -674,7 +657,7 @@ private string getChildAccessorWithoutConversions(Locatable parent, Element chil
|
|||||||
}
|
}
|
||||||
|
|
||||||
private predicate namedStmtChildPredicates(Locatable s, Element e, string pred) {
|
private predicate namedStmtChildPredicates(Locatable s, Element e, string pred) {
|
||||||
shouldPrintDeclaration(getAnEnclosingDeclaration(s)) and
|
shouldPrintFunction(getEnclosingFunction(s)) and
|
||||||
(
|
(
|
||||||
exists(int n | s.(BlockStmt).getStmt(n) = e and pred = "getStmt(" + n + ")")
|
exists(int n | s.(BlockStmt).getStmt(n) = e and pred = "getStmt(" + n + ")")
|
||||||
or
|
or
|
||||||
@@ -762,14 +745,12 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred)
|
|||||||
}
|
}
|
||||||
|
|
||||||
private predicate namedExprChildPredicates(Expr expr, Element ele, string pred) {
|
private predicate namedExprChildPredicates(Expr expr, Element ele, string pred) {
|
||||||
shouldPrintDeclaration(expr.getEnclosingDeclaration()) and
|
shouldPrintFunction(expr.getEnclosingFunction()) and
|
||||||
(
|
(
|
||||||
expr.(Access).getTarget() = ele and pred = "getTarget()"
|
expr.(Access).getTarget() = ele and pred = "getTarget()"
|
||||||
or
|
or
|
||||||
expr.(VariableAccess).getQualifier() = ele and pred = "getQualifier()"
|
expr.(VariableAccess).getQualifier() = ele and pred = "getQualifier()"
|
||||||
or
|
or
|
||||||
expr.(FunctionAccess).getQualifier() = ele and pred = "getQualifier()"
|
|
||||||
or
|
|
||||||
exists(Field f |
|
exists(Field f |
|
||||||
expr.(ClassAggregateLiteral).getAFieldExpr(f) = ele and
|
expr.(ClassAggregateLiteral).getAFieldExpr(f) = ele and
|
||||||
pred = "getAFieldExpr(" + f.toString() + ")"
|
pred = "getAFieldExpr(" + f.toString() + ")"
|
||||||
@@ -826,11 +807,17 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
|
|||||||
or
|
or
|
||||||
expr.(Conversion).getExpr() = ele and pred = "getExpr()"
|
expr.(Conversion).getExpr() = ele and pred = "getExpr()"
|
||||||
or
|
or
|
||||||
expr.(DeleteOrDeleteArrayExpr).getDeallocatorCall() = ele and pred = "getDeallocatorCall()"
|
expr.(DeleteArrayExpr).getAllocatorCall() = ele and pred = "getAllocatorCall()"
|
||||||
or
|
or
|
||||||
expr.(DeleteOrDeleteArrayExpr).getDestructorCall() = ele and pred = "getDestructorCall()"
|
expr.(DeleteArrayExpr).getDestructorCall() = ele and pred = "getDestructorCall()"
|
||||||
or
|
or
|
||||||
expr.(DeleteOrDeleteArrayExpr).getExpr() = ele and pred = "getExpr()"
|
expr.(DeleteArrayExpr).getExpr() = ele and pred = "getExpr()"
|
||||||
|
or
|
||||||
|
expr.(DeleteExpr).getAllocatorCall() = ele and pred = "getAllocatorCall()"
|
||||||
|
or
|
||||||
|
expr.(DeleteExpr).getDestructorCall() = ele and pred = "getDestructorCall()"
|
||||||
|
or
|
||||||
|
expr.(DeleteExpr).getExpr() = ele and pred = "getExpr()"
|
||||||
or
|
or
|
||||||
expr.(DestructorFieldDestruction).getExpr() = ele and pred = "getExpr()"
|
expr.(DestructorFieldDestruction).getExpr() = ele and pred = "getExpr()"
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -814,6 +814,9 @@ private predicate floatingPointTypeMapping(
|
|||||||
// _Float128
|
// _Float128
|
||||||
kind = 49 and base = 2 and domain = TRealDomain() and realKind = 49 and extended = false
|
kind = 49 and base = 2 and domain = TRealDomain() and realKind = 49 and extended = false
|
||||||
or
|
or
|
||||||
|
// _Float128x
|
||||||
|
kind = 50 and base = 2 and domain = TRealDomain() and realKind = 50 and extended = true
|
||||||
|
or
|
||||||
// _Float16
|
// _Float16
|
||||||
kind = 52 and base = 2 and domain = TRealDomain() and realKind = 52 and extended = false
|
kind = 52 and base = 2 and domain = TRealDomain() and realKind = 52 and extended = false
|
||||||
or
|
or
|
||||||
@@ -1696,28 +1699,7 @@ class AutoType extends TemplateParameter {
|
|||||||
|
|
||||||
private predicate suppressUnusedThis(Type t) { any() }
|
private predicate suppressUnusedThis(Type t) { any() }
|
||||||
|
|
||||||
/**
|
/** A source code location referring to a type */
|
||||||
* A source code location referring to a user-defined type.
|
|
||||||
*
|
|
||||||
* Note that only _user-defined_ types have `TypeMention`s. In particular,
|
|
||||||
* built-in types, and derived types with built-in types as their base don't
|
|
||||||
* have any `TypeMention`s. For example, given
|
|
||||||
* ```cpp
|
|
||||||
* struct S { ... };
|
|
||||||
* void f(S s1, int i1) {
|
|
||||||
* S s2;
|
|
||||||
* S* s3;
|
|
||||||
* S& s4 = s2;
|
|
||||||
* decltype(s2) s5;
|
|
||||||
*
|
|
||||||
* int i2;
|
|
||||||
* int* i3;
|
|
||||||
* int i4[10];
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
* there will be a `TypeMention` for the mention of `S` at `S s1`, `S s2`, and `S& s4 = s2`,
|
|
||||||
* but not at `decltype(s2) s5`. Additionally, there will be no `TypeMention`s for `int`.
|
|
||||||
*/
|
|
||||||
class TypeMention extends Locatable, @type_mention {
|
class TypeMention extends Locatable, @type_mention {
|
||||||
override string toString() { result = "type mention" }
|
override string toString() { result = "type mention" }
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import cpp
|
|||||||
*/
|
*/
|
||||||
deprecated class StrcatFunction extends Function {
|
deprecated class StrcatFunction extends Function {
|
||||||
StrcatFunction() {
|
StrcatFunction() {
|
||||||
this.getName() =
|
getName() =
|
||||||
[
|
[
|
||||||
"strcat", // strcat(dst, src)
|
"strcat", // strcat(dst, src)
|
||||||
"strncat", // strncat(dst, src, max_amount)
|
"strncat", // strncat(dst, src, max_amount)
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ library class DefOrUse extends ControlFlowNodeBase {
|
|||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate reaches_helper(boolean isDef, SemanticStackVariable v, BasicBlock bb, int i) {
|
private predicate reaches_helper(boolean isDef, SemanticStackVariable v, BasicBlock bb, int i) {
|
||||||
this.getVariable(isDef) = v and
|
getVariable(isDef) = v and
|
||||||
bb.getNode(i) = this
|
bb.getNode(i) = this
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,21 +118,21 @@ library class DefOrUse extends ControlFlowNodeBase {
|
|||||||
* predicates are duplicated for now.
|
* predicates are duplicated for now.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exists(BasicBlock bb, int i | this.reaches_helper(isDef, v, bb, i) |
|
exists(BasicBlock bb, int i | reaches_helper(isDef, v, bb, i) |
|
||||||
exists(int j |
|
exists(int j |
|
||||||
j > i and
|
j > i and
|
||||||
(bbDefAt(bb, j, v, defOrUse) or bbUseAt(bb, j, v, defOrUse)) and
|
(bbDefAt(bb, j, v, defOrUse) or bbUseAt(bb, j, v, defOrUse)) and
|
||||||
not exists(int k | this.firstBarrierAfterThis(isDef, k, v) and k < j)
|
not exists(int k | firstBarrierAfterThis(isDef, k, v) and k < j)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
not this.firstBarrierAfterThis(isDef, _, v) and
|
not firstBarrierAfterThis(isDef, _, v) and
|
||||||
bbSuccessorEntryReachesDefOrUse(bb, v, defOrUse, _)
|
bbSuccessorEntryReachesDefOrUse(bb, v, defOrUse, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate firstBarrierAfterThis(boolean isDef, int j, SemanticStackVariable v) {
|
private predicate firstBarrierAfterThis(boolean isDef, int j, SemanticStackVariable v) {
|
||||||
exists(BasicBlock bb, int i |
|
exists(BasicBlock bb, int i |
|
||||||
this.getVariable(isDef) = v and
|
getVariable(isDef) = v and
|
||||||
bb.getNode(i) = this and
|
bb.getNode(i) = this and
|
||||||
j = min(int k | bbBarrierAt(bb, k, v, _) and k > i)
|
j = min(int k | bbBarrierAt(bb, k, v, _) and k > i)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -627,20 +627,6 @@ private predicate sub_lt(
|
|||||||
x = int_value(rhs.getRight()) and
|
x = int_value(rhs.getRight()) and
|
||||||
k = c - x
|
k = c - x
|
||||||
)
|
)
|
||||||
or
|
|
||||||
exists(PointerSubInstruction lhs, int c, int x |
|
|
||||||
compares_lt(cmp, lhs.getAUse(), right, c, isLt, testIsTrue) and
|
|
||||||
left = lhs.getLeftOperand() and
|
|
||||||
x = int_value(lhs.getRight()) and
|
|
||||||
k = c + x
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(PointerSubInstruction rhs, int c, int x |
|
|
||||||
compares_lt(cmp, left, rhs.getAUse(), c, isLt, testIsTrue) and
|
|
||||||
right = rhs.getLeftOperand() and
|
|
||||||
x = int_value(rhs.getRight()) and
|
|
||||||
k = c - x
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// left + x < right + c => left < right + (c-x)
|
// left + x < right + c => left < right + (c-x)
|
||||||
@@ -667,26 +653,6 @@ private predicate add_lt(
|
|||||||
) and
|
) and
|
||||||
k = c + x
|
k = c + x
|
||||||
)
|
)
|
||||||
or
|
|
||||||
exists(PointerAddInstruction lhs, int c, int x |
|
|
||||||
compares_lt(cmp, lhs.getAUse(), right, c, isLt, testIsTrue) and
|
|
||||||
(
|
|
||||||
left = lhs.getLeftOperand() and x = int_value(lhs.getRight())
|
|
||||||
or
|
|
||||||
left = lhs.getRightOperand() and x = int_value(lhs.getLeft())
|
|
||||||
) and
|
|
||||||
k = c - x
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(PointerAddInstruction rhs, int c, int x |
|
|
||||||
compares_lt(cmp, left, rhs.getAUse(), c, isLt, testIsTrue) and
|
|
||||||
(
|
|
||||||
right = rhs.getLeftOperand() and x = int_value(rhs.getRight())
|
|
||||||
or
|
|
||||||
right = rhs.getRightOperand() and x = int_value(rhs.getLeft())
|
|
||||||
) and
|
|
||||||
k = c + x
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// left - x == right + c => left == right + (c+x)
|
// left - x == right + c => left == right + (c+x)
|
||||||
@@ -707,20 +673,6 @@ private predicate sub_eq(
|
|||||||
x = int_value(rhs.getRight()) and
|
x = int_value(rhs.getRight()) and
|
||||||
k = c - x
|
k = c - x
|
||||||
)
|
)
|
||||||
or
|
|
||||||
exists(PointerSubInstruction lhs, int c, int x |
|
|
||||||
compares_eq(cmp, lhs.getAUse(), right, c, areEqual, testIsTrue) and
|
|
||||||
left = lhs.getLeftOperand() and
|
|
||||||
x = int_value(lhs.getRight()) and
|
|
||||||
k = c + x
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(PointerSubInstruction rhs, int c, int x |
|
|
||||||
compares_eq(cmp, left, rhs.getAUse(), c, areEqual, testIsTrue) and
|
|
||||||
right = rhs.getLeftOperand() and
|
|
||||||
x = int_value(rhs.getRight()) and
|
|
||||||
k = c - x
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// left + x == right + c => left == right + (c-x)
|
// left + x == right + c => left == right + (c-x)
|
||||||
@@ -747,26 +699,6 @@ private predicate add_eq(
|
|||||||
) and
|
) and
|
||||||
k = c + x
|
k = c + x
|
||||||
)
|
)
|
||||||
or
|
|
||||||
exists(PointerAddInstruction lhs, int c, int x |
|
|
||||||
compares_eq(cmp, lhs.getAUse(), right, c, areEqual, testIsTrue) and
|
|
||||||
(
|
|
||||||
left = lhs.getLeftOperand() and x = int_value(lhs.getRight())
|
|
||||||
or
|
|
||||||
left = lhs.getRightOperand() and x = int_value(lhs.getLeft())
|
|
||||||
) and
|
|
||||||
k = c - x
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(PointerAddInstruction rhs, int c, int x |
|
|
||||||
compares_eq(cmp, left, rhs.getAUse(), c, areEqual, testIsTrue) and
|
|
||||||
(
|
|
||||||
right = rhs.getLeftOperand() and x = int_value(rhs.getRight())
|
|
||||||
or
|
|
||||||
right = rhs.getRightOperand() and x = int_value(rhs.getLeft())
|
|
||||||
) and
|
|
||||||
k = c + x
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The int value of integer constant expression. */
|
/** The int value of integer constant expression. */
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ library class StandardSsa extends SsaHelper {
|
|||||||
StandardSsa() { this = 0 }
|
StandardSsa() { this = 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for StandardSsa */
|
||||||
|
deprecated class StandardSSA = StandardSsa;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A definition of one or more SSA variables, including phi node definitions.
|
* A definition of one or more SSA variables, including phi node definitions.
|
||||||
* An _SSA variable_, as defined in the literature, is effectively the pair of
|
* An _SSA variable_, as defined in the literature, is effectively the pair of
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ library class SsaHelper extends int {
|
|||||||
* Remove any custom phi nodes that are invalid.
|
* Remove any custom phi nodes that are invalid.
|
||||||
*/
|
*/
|
||||||
private predicate sanitized_custom_phi_node(StackVariable v, BasicBlock b) {
|
private predicate sanitized_custom_phi_node(StackVariable v, BasicBlock b) {
|
||||||
this.custom_phi_node(v, b) and
|
custom_phi_node(v, b) and
|
||||||
not addressTakenVariable(v) and
|
not addressTakenVariable(v) and
|
||||||
not isReferenceVar(v) and
|
not isReferenceVar(v) and
|
||||||
b.isReachable()
|
b.isReachable()
|
||||||
@@ -142,7 +142,7 @@ library class SsaHelper extends int {
|
|||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
predicate phi_node(StackVariable v, BasicBlock b) {
|
predicate phi_node(StackVariable v, BasicBlock b) {
|
||||||
this.frontier_phi_node(v, b) or this.sanitized_custom_phi_node(v, b)
|
frontier_phi_node(v, b) or sanitized_custom_phi_node(v, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -154,15 +154,14 @@ library class SsaHelper extends int {
|
|||||||
*/
|
*/
|
||||||
private predicate frontier_phi_node(StackVariable v, BasicBlock b) {
|
private predicate frontier_phi_node(StackVariable v, BasicBlock b) {
|
||||||
exists(BasicBlock x |
|
exists(BasicBlock x |
|
||||||
dominanceFrontier(x, b) and
|
dominanceFrontier(x, b) and ssa_defn_rec(pragma[only_bind_into](v), pragma[only_bind_into](x))
|
||||||
this.ssa_defn_rec(pragma[only_bind_into](v), pragma[only_bind_into](x))
|
|
||||||
) and
|
) and
|
||||||
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
|
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
|
||||||
live_at_start_of_bb(pragma[only_bind_into](v), b)
|
live_at_start_of_bb(pragma[only_bind_into](v), b)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate ssa_defn_rec(StackVariable v, BasicBlock b) {
|
private predicate ssa_defn_rec(StackVariable v, BasicBlock b) {
|
||||||
this.phi_node(v, b)
|
phi_node(v, b)
|
||||||
or
|
or
|
||||||
variableUpdate(v, _, b, _)
|
variableUpdate(v, _, b, _)
|
||||||
}
|
}
|
||||||
@@ -173,7 +172,7 @@ library class SsaHelper extends int {
|
|||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
predicate ssa_defn(StackVariable v, ControlFlowNode node, BasicBlock b, int index) {
|
predicate ssa_defn(StackVariable v, ControlFlowNode node, BasicBlock b, int index) {
|
||||||
this.phi_node(v, b) and b.getStart() = node and index = -1
|
phi_node(v, b) and b.getStart() = node and index = -1
|
||||||
or
|
or
|
||||||
variableUpdate(v, node, b, index)
|
variableUpdate(v, node, b, index)
|
||||||
}
|
}
|
||||||
@@ -197,7 +196,7 @@ library class SsaHelper extends int {
|
|||||||
* basic blocks.
|
* basic blocks.
|
||||||
*/
|
*/
|
||||||
private predicate defUseRank(StackVariable v, BasicBlock b, int rankix, int i) {
|
private predicate defUseRank(StackVariable v, BasicBlock b, int rankix, int i) {
|
||||||
i = rank[rankix](int j | this.ssa_defn(v, _, b, j) or ssa_use(v, _, b, j))
|
i = rank[rankix](int j | ssa_defn(v, _, b, j) or ssa_use(v, _, b, j))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -207,7 +206,7 @@ library class SsaHelper extends int {
|
|||||||
* the block.
|
* the block.
|
||||||
*/
|
*/
|
||||||
private int lastRank(StackVariable v, BasicBlock b) {
|
private int lastRank(StackVariable v, BasicBlock b) {
|
||||||
result = max(int rankix | this.defUseRank(v, b, rankix, _)) + 1
|
result = max(int rankix | defUseRank(v, b, rankix, _)) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -216,8 +215,8 @@ library class SsaHelper extends int {
|
|||||||
*/
|
*/
|
||||||
private predicate ssaDefRank(StackVariable v, ControlFlowNode def, BasicBlock b, int rankix) {
|
private predicate ssaDefRank(StackVariable v, ControlFlowNode def, BasicBlock b, int rankix) {
|
||||||
exists(int i |
|
exists(int i |
|
||||||
this.ssa_defn(v, def, b, i) and
|
ssa_defn(v, def, b, i) and
|
||||||
this.defUseRank(v, b, rankix, i)
|
defUseRank(v, b, rankix, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,21 +232,21 @@ library class SsaHelper extends int {
|
|||||||
// use is understood to happen _before_ the definition. Phi nodes are
|
// use is understood to happen _before_ the definition. Phi nodes are
|
||||||
// at rankidx -1 and will therefore always reach the first node in the
|
// at rankidx -1 and will therefore always reach the first node in the
|
||||||
// basic block.
|
// basic block.
|
||||||
this.ssaDefRank(v, def, b, rankix - 1)
|
ssaDefRank(v, def, b, rankix - 1)
|
||||||
or
|
or
|
||||||
this.ssaDefReachesRank(v, def, b, rankix - 1) and
|
ssaDefReachesRank(v, def, b, rankix - 1) and
|
||||||
rankix <= this.lastRank(v, b) and // Without this, the predicate would be infinite.
|
rankix <= lastRank(v, b) and // Without this, the predicate would be infinite.
|
||||||
not this.ssaDefRank(v, _, b, rankix - 1) // Range is inclusive of but not past next def.
|
not ssaDefRank(v, _, b, rankix - 1) // Range is inclusive of but not past next def.
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if SSA variable `(v, def)` reaches the end of block `b`. */
|
/** Holds if SSA variable `(v, def)` reaches the end of block `b`. */
|
||||||
cached
|
cached
|
||||||
predicate ssaDefinitionReachesEndOfBB(StackVariable v, ControlFlowNode def, BasicBlock b) {
|
predicate ssaDefinitionReachesEndOfBB(StackVariable v, ControlFlowNode def, BasicBlock b) {
|
||||||
live_at_exit_of_bb(v, b) and this.ssaDefReachesRank(v, def, b, this.lastRank(v, b))
|
live_at_exit_of_bb(v, b) and ssaDefReachesRank(v, def, b, lastRank(v, b))
|
||||||
or
|
or
|
||||||
exists(BasicBlock idom |
|
exists(BasicBlock idom |
|
||||||
this.ssaDefinitionReachesEndOfBB(v, def, idom) and
|
ssaDefinitionReachesEndOfBB(v, def, idom) and
|
||||||
this.noDefinitionsSinceIDominator(v, idom, b)
|
noDefinitionsSinceIDominator(v, idom, b)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +260,7 @@ library class SsaHelper extends int {
|
|||||||
private predicate noDefinitionsSinceIDominator(StackVariable v, BasicBlock idom, BasicBlock b) {
|
private predicate noDefinitionsSinceIDominator(StackVariable v, BasicBlock idom, BasicBlock b) {
|
||||||
bbIDominates(idom, b) and // It is sufficient to traverse the dominator graph, cf. discussion above.
|
bbIDominates(idom, b) and // It is sufficient to traverse the dominator graph, cf. discussion above.
|
||||||
live_at_exit_of_bb(v, b) and
|
live_at_exit_of_bb(v, b) and
|
||||||
not this.ssa_defn(v, _, b, _)
|
not ssa_defn(v, _, b, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -270,8 +269,8 @@ library class SsaHelper extends int {
|
|||||||
*/
|
*/
|
||||||
private predicate ssaDefinitionReachesUseWithinBB(StackVariable v, ControlFlowNode def, Expr use) {
|
private predicate ssaDefinitionReachesUseWithinBB(StackVariable v, ControlFlowNode def, Expr use) {
|
||||||
exists(BasicBlock b, int rankix, int i |
|
exists(BasicBlock b, int rankix, int i |
|
||||||
this.ssaDefReachesRank(v, def, b, rankix) and
|
ssaDefReachesRank(v, def, b, rankix) and
|
||||||
this.defUseRank(v, b, rankix, i) and
|
defUseRank(v, b, rankix, i) and
|
||||||
ssa_use(v, use, b, i)
|
ssa_use(v, use, b, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -280,12 +279,12 @@ library class SsaHelper extends int {
|
|||||||
* Holds if SSA variable `(v, def)` reaches the control-flow node `use`.
|
* Holds if SSA variable `(v, def)` reaches the control-flow node `use`.
|
||||||
*/
|
*/
|
||||||
private predicate ssaDefinitionReaches(StackVariable v, ControlFlowNode def, Expr use) {
|
private predicate ssaDefinitionReaches(StackVariable v, ControlFlowNode def, Expr use) {
|
||||||
this.ssaDefinitionReachesUseWithinBB(v, def, use)
|
ssaDefinitionReachesUseWithinBB(v, def, use)
|
||||||
or
|
or
|
||||||
exists(BasicBlock b |
|
exists(BasicBlock b |
|
||||||
ssa_use(v, use, b, _) and
|
ssa_use(v, use, b, _) and
|
||||||
this.ssaDefinitionReachesEndOfBB(v, def, b.getAPredecessor()) and
|
ssaDefinitionReachesEndOfBB(v, def, b.getAPredecessor()) and
|
||||||
not this.ssaDefinitionReachesUseWithinBB(v, _, use)
|
not ssaDefinitionReachesUseWithinBB(v, _, use)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,10 +294,10 @@ library class SsaHelper extends int {
|
|||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
string toString(ControlFlowNode node, StackVariable v) {
|
string toString(ControlFlowNode node, StackVariable v) {
|
||||||
if this.phi_node(v, node)
|
if phi_node(v, node)
|
||||||
then result = "SSA phi(" + v.getName() + ")"
|
then result = "SSA phi(" + v.getName() + ")"
|
||||||
else (
|
else (
|
||||||
this.ssa_defn(v, node, _, _) and result = "SSA def(" + v.getName() + ")"
|
ssa_defn(v, node, _, _) and result = "SSA def(" + v.getName() + ")"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,7 +307,10 @@ library class SsaHelper extends int {
|
|||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
VariableAccess getAUse(ControlFlowNode def, StackVariable v) {
|
VariableAccess getAUse(ControlFlowNode def, StackVariable v) {
|
||||||
this.ssaDefinitionReaches(v, def, result) and
|
ssaDefinitionReaches(v, def, result) and
|
||||||
ssa_use(v, result, _, _)
|
ssa_use(v, result, _, _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for SsaHelper */
|
||||||
|
deprecated class SSAHelper = SsaHelper;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import cpp
|
|||||||
*/
|
*/
|
||||||
abstract class StackVariableReachability extends string {
|
abstract class StackVariableReachability extends string {
|
||||||
bindingset[this]
|
bindingset[this]
|
||||||
StackVariableReachability() { this.length() >= 0 }
|
StackVariableReachability() { length() >= 0 }
|
||||||
|
|
||||||
/** Holds if `node` is a source for the reachability analysis using variable `v`. */
|
/** Holds if `node` is a source for the reachability analysis using variable `v`. */
|
||||||
abstract predicate isSource(ControlFlowNode node, StackVariable v);
|
abstract predicate isSource(ControlFlowNode node, StackVariable v);
|
||||||
@@ -227,7 +227,7 @@ predicate bbSuccessorEntryReachesLoopInvariant(
|
|||||||
*/
|
*/
|
||||||
abstract class StackVariableReachabilityWithReassignment extends StackVariableReachability {
|
abstract class StackVariableReachabilityWithReassignment extends StackVariableReachability {
|
||||||
bindingset[this]
|
bindingset[this]
|
||||||
StackVariableReachabilityWithReassignment() { this.length() >= 0 }
|
StackVariableReachabilityWithReassignment() { length() >= 0 }
|
||||||
|
|
||||||
/** Override this predicate rather than `isSource` (`isSource` is used internally). */
|
/** Override this predicate rather than `isSource` (`isSource` is used internally). */
|
||||||
abstract predicate isSourceActual(ControlFlowNode node, StackVariable v);
|
abstract predicate isSourceActual(ControlFlowNode node, StackVariable v);
|
||||||
@@ -330,7 +330,7 @@ abstract class StackVariableReachabilityWithReassignment extends StackVariableRe
|
|||||||
*/
|
*/
|
||||||
abstract class StackVariableReachabilityExt extends string {
|
abstract class StackVariableReachabilityExt extends string {
|
||||||
bindingset[this]
|
bindingset[this]
|
||||||
StackVariableReachabilityExt() { this.length() >= 0 }
|
StackVariableReachabilityExt() { length() >= 0 }
|
||||||
|
|
||||||
/** `node` is a source for the reachability analysis using variable `v`. */
|
/** `node` is a source for the reachability analysis using variable `v`. */
|
||||||
abstract predicate isSource(ControlFlowNode node, StackVariable v);
|
abstract predicate isSource(ControlFlowNode node, StackVariable v);
|
||||||
|
|||||||
@@ -332,12 +332,21 @@ private Node getControlOrderChildSparse(Node n, int i) {
|
|||||||
n = any(ConditionDeclExpr cd | i = 0 and result = cd.getInitializingExpr())
|
n = any(ConditionDeclExpr cd | i = 0 and result = cd.getInitializingExpr())
|
||||||
or
|
or
|
||||||
n =
|
n =
|
||||||
any(DeleteOrDeleteArrayExpr del |
|
any(DeleteExpr del |
|
||||||
i = 0 and result = del.getExpr()
|
i = 0 and result = del.getExpr()
|
||||||
or
|
or
|
||||||
i = 1 and result = del.getDestructorCall()
|
i = 1 and result = del.getDestructorCall()
|
||||||
or
|
or
|
||||||
i = 2 and result = del.getDeallocatorCall()
|
i = 2 and result = del.getAllocatorCall()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
n =
|
||||||
|
any(DeleteArrayExpr del |
|
||||||
|
i = 0 and result = del.getExpr()
|
||||||
|
or
|
||||||
|
i = 1 and result = del.getDestructorCall()
|
||||||
|
or
|
||||||
|
i = 2 and result = del.getAllocatorCall()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
n =
|
n =
|
||||||
@@ -1376,6 +1385,9 @@ private module Cached {
|
|||||||
conditionalSuccessor(n1, _, n2)
|
conditionalSuccessor(n1, _, n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for qlCfgSuccessor */
|
||||||
|
deprecated predicate qlCFGSuccessor = qlCfgSuccessor/2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `n2` is a control-flow node such that the control-flow
|
* Holds if `n2` is a control-flow node such that the control-flow
|
||||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is true.
|
* edge `(n1, n2)` may be taken when `n1` is an expression that is true.
|
||||||
@@ -1386,6 +1398,9 @@ private module Cached {
|
|||||||
not conditionalSuccessor(n1, false, n2)
|
not conditionalSuccessor(n1, false, n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for qlCfgTrueSuccessor */
|
||||||
|
deprecated predicate qlCFGTrueSuccessor = qlCfgTrueSuccessor/2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `n2` is a control-flow node such that the control-flow
|
* Holds if `n2` is a control-flow node such that the control-flow
|
||||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is false.
|
* edge `(n1, n2)` may be taken when `n1` is an expression that is false.
|
||||||
@@ -1395,4 +1410,7 @@ private module Cached {
|
|||||||
conditionalSuccessor(n1, false, n2) and
|
conditionalSuccessor(n1, false, n2) and
|
||||||
not conditionalSuccessor(n1, true, n2)
|
not conditionalSuccessor(n1, true, n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for qlCfgFalseSuccessor */
|
||||||
|
deprecated predicate qlCFGFalseSuccessor = qlCfgFalseSuccessor/2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,14 +20,10 @@
|
|||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow` instead.
|
|
||||||
*
|
|
||||||
* Provides classes for performing local (intra-procedural) and
|
* Provides classes for performing local (intra-procedural) and
|
||||||
* global (inter-procedural) data flow analyses.
|
* global (inter-procedural) data flow analyses.
|
||||||
*/
|
*/
|
||||||
deprecated module DataFlow {
|
module DataFlow {
|
||||||
private import semmle.code.cpp.dataflow.internal.DataFlowImplSpecific
|
import semmle.code.cpp.dataflow.internal.DataFlow
|
||||||
private import codeql.dataflow.DataFlow
|
|
||||||
import DataFlowMake<CppOldDataFlow>
|
|
||||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl1
|
import semmle.code.cpp.dataflow.internal.DataFlowImpl1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,9 @@
|
|||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow2` instead.
|
|
||||||
*
|
|
||||||
* Provides classes for performing local (intra-procedural) and
|
* Provides classes for performing local (intra-procedural) and
|
||||||
* global (inter-procedural) data flow analyses.
|
* global (inter-procedural) data flow analyses.
|
||||||
*/
|
*/
|
||||||
deprecated module DataFlow2 {
|
module DataFlow2 {
|
||||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl2
|
import semmle.code.cpp.dataflow.internal.DataFlowImpl2
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,9 @@
|
|||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow3` instead.
|
|
||||||
*
|
|
||||||
* Provides classes for performing local (intra-procedural) and
|
* Provides classes for performing local (intra-procedural) and
|
||||||
* global (inter-procedural) data flow analyses.
|
* global (inter-procedural) data flow analyses.
|
||||||
*/
|
*/
|
||||||
deprecated module DataFlow3 {
|
module DataFlow3 {
|
||||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl3
|
import semmle.code.cpp.dataflow.internal.DataFlowImpl3
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,9 @@
|
|||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow4` instead.
|
|
||||||
*
|
|
||||||
* Provides classes for performing local (intra-procedural) and
|
* Provides classes for performing local (intra-procedural) and
|
||||||
* global (inter-procedural) data flow analyses.
|
* global (inter-procedural) data flow analyses.
|
||||||
*/
|
*/
|
||||||
deprecated module DataFlow4 {
|
module DataFlow4 {
|
||||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl4
|
import semmle.code.cpp.dataflow.internal.DataFlowImpl4
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,16 +19,10 @@ import semmle.code.cpp.dataflow.DataFlow
|
|||||||
import semmle.code.cpp.dataflow.DataFlow2
|
import semmle.code.cpp.dataflow.DataFlow2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.TaintTracking` instead.
|
|
||||||
*
|
|
||||||
* Provides classes for performing local (intra-procedural) and
|
* Provides classes for performing local (intra-procedural) and
|
||||||
* global (inter-procedural) taint-tracking analyses.
|
* global (inter-procedural) taint-tracking analyses.
|
||||||
*/
|
*/
|
||||||
deprecated module TaintTracking {
|
module TaintTracking {
|
||||||
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingParameter::Public
|
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTracking
|
||||||
private import semmle.code.cpp.dataflow.internal.DataFlowImplSpecific
|
|
||||||
private import semmle.code.cpp.dataflow.internal.TaintTrackingImplSpecific
|
|
||||||
private import codeql.dataflow.TaintTracking
|
|
||||||
import TaintFlowMake<CppOldDataFlow, CppOldTaintTracking>
|
|
||||||
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl
|
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.TaintTracking2` instead.
|
|
||||||
*
|
|
||||||
* Provides classes for performing local (intra-procedural) and
|
* Provides classes for performing local (intra-procedural) and
|
||||||
* global (inter-procedural) taint-tracking analyses.
|
* global (inter-procedural) taint-tracking analyses.
|
||||||
*/
|
*/
|
||||||
deprecated module TaintTracking2 {
|
module TaintTracking2 {
|
||||||
import semmle.code.cpp.dataflow.internal.tainttracking2.TaintTrackingImpl
|
import semmle.code.cpp.dataflow.internal.tainttracking2.TaintTrackingImpl
|
||||||
}
|
}
|
||||||
|
|||||||
412
cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlow.qll
Normal file
412
cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlow.qll
Normal file
@@ -0,0 +1,412 @@
|
|||||||
|
/**
|
||||||
|
* Provides an implementation of global (interprocedural) data flow. This file
|
||||||
|
* re-exports the local (intraprocedural) data flow analysis from
|
||||||
|
* `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed
|
||||||
|
* through the `Global` and `GlobalWithState` modules.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private import DataFlowImplCommon
|
||||||
|
private import DataFlowImplSpecific::Private
|
||||||
|
import DataFlowImplSpecific::Public
|
||||||
|
import DataFlowImplCommonPublic
|
||||||
|
private import DataFlowImpl
|
||||||
|
|
||||||
|
/** An input configuration for data flow. */
|
||||||
|
signature module ConfigSig {
|
||||||
|
/**
|
||||||
|
* Holds if `source` is a relevant data flow source.
|
||||||
|
*/
|
||||||
|
predicate isSource(Node source);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `sink` is a relevant data flow sink.
|
||||||
|
*/
|
||||||
|
predicate isSink(Node sink);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow through `node` is prohibited. This completely removes
|
||||||
|
* `node` from the data flow graph.
|
||||||
|
*/
|
||||||
|
default predicate isBarrier(Node node) { none() }
|
||||||
|
|
||||||
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
|
default predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
|
default predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||||
|
*/
|
||||||
|
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
|
* taken at `node`.
|
||||||
|
*/
|
||||||
|
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
|
* This can be overridden to a smaller value to improve performance (a
|
||||||
|
* value of 0 disables field flow), or a larger value to get more results.
|
||||||
|
*/
|
||||||
|
default int fieldFlowBranchLimit() { result = 2 }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a data flow configuration feature to add restrictions to the set of
|
||||||
|
* valid flow paths.
|
||||||
|
*
|
||||||
|
* - `FeatureHasSourceCallContext`:
|
||||||
|
* Assume that sources have some existing call context to disallow
|
||||||
|
* conflicting return-flow directly following the source.
|
||||||
|
* - `FeatureHasSinkCallContext`:
|
||||||
|
* Assume that sinks have some existing call context to disallow
|
||||||
|
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||||
|
* - `FeatureEqualSourceSinkCallContext`:
|
||||||
|
* Implies both of the above and additionally ensures that the entire flow
|
||||||
|
* path preserves the call context.
|
||||||
|
*
|
||||||
|
* These features are generally not relevant for typical end-to-end data flow
|
||||||
|
* queries, but should only be used for constructing paths that need to
|
||||||
|
* somehow be pluggable in another path context.
|
||||||
|
*/
|
||||||
|
default FlowFeature getAFeature() { none() }
|
||||||
|
|
||||||
|
/** Holds if sources should be grouped in the result of `flowPath`. */
|
||||||
|
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||||
|
|
||||||
|
/** Holds if sinks should be grouped in the result of `flowPath`. */
|
||||||
|
default predicate sinkGrouping(Node sink, string sinkGroup) { 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 (as it is in a `path-problem` query).
|
||||||
|
*/
|
||||||
|
default predicate includeHiddenNodes() { none() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** An input configuration for data flow using flow state. */
|
||||||
|
signature module StateConfigSig {
|
||||||
|
bindingset[this]
|
||||||
|
class FlowState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `source` is a relevant data flow source with the given initial
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSource(Node source, FlowState state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||||
|
*/
|
||||||
|
predicate isSink(Node sink, FlowState state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow through `node` is prohibited. This completely removes
|
||||||
|
* `node` from the data flow graph.
|
||||||
|
*/
|
||||||
|
default predicate isBarrier(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow through `node` is prohibited when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isBarrier(Node node, FlowState state);
|
||||||
|
|
||||||
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
|
default predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
|
default predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||||
|
*/
|
||||||
|
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||||
|
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||||
|
*/
|
||||||
|
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
|
* taken at `node`.
|
||||||
|
*/
|
||||||
|
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
|
* This can be overridden to a smaller value to improve performance (a
|
||||||
|
* value of 0 disables field flow), or a larger value to get more results.
|
||||||
|
*/
|
||||||
|
default int fieldFlowBranchLimit() { result = 2 }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a data flow configuration feature to add restrictions to the set of
|
||||||
|
* valid flow paths.
|
||||||
|
*
|
||||||
|
* - `FeatureHasSourceCallContext`:
|
||||||
|
* Assume that sources have some existing call context to disallow
|
||||||
|
* conflicting return-flow directly following the source.
|
||||||
|
* - `FeatureHasSinkCallContext`:
|
||||||
|
* Assume that sinks have some existing call context to disallow
|
||||||
|
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||||
|
* - `FeatureEqualSourceSinkCallContext`:
|
||||||
|
* Implies both of the above and additionally ensures that the entire flow
|
||||||
|
* path preserves the call context.
|
||||||
|
*
|
||||||
|
* These features are generally not relevant for typical end-to-end data flow
|
||||||
|
* queries, but should only be used for constructing paths that need to
|
||||||
|
* somehow be pluggable in another path context.
|
||||||
|
*/
|
||||||
|
default FlowFeature getAFeature() { none() }
|
||||||
|
|
||||||
|
/** Holds if sources should be grouped in the result of `flowPath`. */
|
||||||
|
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||||
|
|
||||||
|
/** Holds if sinks should be grouped in the result of `flowPath`. */
|
||||||
|
default predicate sinkGrouping(Node sink, string sinkGroup) { 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 (as it is in a `path-problem` query).
|
||||||
|
*/
|
||||||
|
default predicate includeHiddenNodes() { none() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the exploration limit for `partialFlow` and `partialFlowRev`
|
||||||
|
* measured in approximate number of interprocedural steps.
|
||||||
|
*/
|
||||||
|
signature int explorationLimitSig();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The output of a global data flow computation.
|
||||||
|
*/
|
||||||
|
signature module GlobalFlowSig {
|
||||||
|
/**
|
||||||
|
* A `Node` augmented with a call context (except for sinks) and an access path.
|
||||||
|
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||||
|
*/
|
||||||
|
class PathNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data can flow from `source` to `sink`.
|
||||||
|
*
|
||||||
|
* The corresponding paths are generated from the end-points and the graph
|
||||||
|
* included in the module `PathGraph`.
|
||||||
|
*/
|
||||||
|
predicate flowPath(PathNode source, PathNode sink);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data can flow from `source` to `sink`.
|
||||||
|
*/
|
||||||
|
predicate flow(Node source, Node sink);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data can flow from some source to `sink`.
|
||||||
|
*/
|
||||||
|
predicate flowTo(Node sink);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data can flow from some source to `sink`.
|
||||||
|
*/
|
||||||
|
predicate flowToExpr(DataFlowExpr sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a global data flow computation.
|
||||||
|
*/
|
||||||
|
module Global<ConfigSig Config> implements GlobalFlowSig {
|
||||||
|
private module C implements FullStateConfigSig {
|
||||||
|
import DefaultState<Config>
|
||||||
|
import Config
|
||||||
|
}
|
||||||
|
|
||||||
|
import Impl<C>
|
||||||
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Use `Global` instead. */
|
||||||
|
deprecated module Make<ConfigSig Config> implements GlobalFlowSig {
|
||||||
|
import Global<Config>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a global data flow computation using flow state.
|
||||||
|
*/
|
||||||
|
module GlobalWithState<StateConfigSig Config> implements GlobalFlowSig {
|
||||||
|
private module C implements FullStateConfigSig {
|
||||||
|
import Config
|
||||||
|
}
|
||||||
|
|
||||||
|
import Impl<C>
|
||||||
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Use `GlobalWithState` instead. */
|
||||||
|
deprecated module MakeWithState<StateConfigSig Config> implements GlobalFlowSig {
|
||||||
|
import GlobalWithState<Config>
|
||||||
|
}
|
||||||
|
|
||||||
|
signature class PathNodeSig {
|
||||||
|
/** Gets a textual representation of this element. */
|
||||||
|
string 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 filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
);
|
||||||
|
|
||||||
|
/** Gets the underlying `Node`. */
|
||||||
|
Node getNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
signature module PathGraphSig<PathNodeSig PathNode> {
|
||||||
|
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||||
|
predicate edges(PathNode a, PathNode b);
|
||||||
|
|
||||||
|
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||||
|
predicate nodes(PathNode n, string key, string val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||||
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
|
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||||
|
*/
|
||||||
|
predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a `PathGraph` from two `PathGraph`s by disjoint union.
|
||||||
|
*/
|
||||||
|
module MergePathGraph<
|
||||||
|
PathNodeSig PathNode1, PathNodeSig PathNode2, PathGraphSig<PathNode1> Graph1,
|
||||||
|
PathGraphSig<PathNode2> Graph2>
|
||||||
|
{
|
||||||
|
private newtype TPathNode =
|
||||||
|
TPathNode1(PathNode1 p) or
|
||||||
|
TPathNode2(PathNode2 p)
|
||||||
|
|
||||||
|
/** A node in a graph of path explanations that is formed by disjoint union of the two given graphs. */
|
||||||
|
class PathNode extends TPathNode {
|
||||||
|
/** Gets this as a projection on the first given `PathGraph`. */
|
||||||
|
PathNode1 asPathNode1() { this = TPathNode1(result) }
|
||||||
|
|
||||||
|
/** Gets this as a projection on the second given `PathGraph`. */
|
||||||
|
PathNode2 asPathNode2() { this = TPathNode2(result) }
|
||||||
|
|
||||||
|
/** Gets a textual representation of this element. */
|
||||||
|
string toString() {
|
||||||
|
result = this.asPathNode1().toString() or
|
||||||
|
result = this.asPathNode2().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 filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
this.asPathNode1().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) or
|
||||||
|
this.asPathNode2().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the underlying `Node`. */
|
||||||
|
Node getNode() {
|
||||||
|
result = this.asPathNode1().getNode() or
|
||||||
|
result = this.asPathNode2().getNode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||||
|
*/
|
||||||
|
module PathGraph implements PathGraphSig<PathNode> {
|
||||||
|
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||||
|
query predicate edges(PathNode a, PathNode b) {
|
||||||
|
Graph1::edges(a.asPathNode1(), b.asPathNode1()) or
|
||||||
|
Graph2::edges(a.asPathNode2(), b.asPathNode2())
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||||
|
query predicate nodes(PathNode n, string key, string val) {
|
||||||
|
Graph1::nodes(n.asPathNode1(), key, val) or
|
||||||
|
Graph2::nodes(n.asPathNode2(), key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||||
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
|
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||||
|
*/
|
||||||
|
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||||
|
Graph1::subpaths(arg.asPathNode1(), par.asPathNode1(), ret.asPathNode1(), out.asPathNode1()) or
|
||||||
|
Graph2::subpaths(arg.asPathNode2(), par.asPathNode2(), ret.asPathNode2(), out.asPathNode2())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a `PathGraph` from three `PathGraph`s by disjoint union.
|
||||||
|
*/
|
||||||
|
module MergePathGraph3<
|
||||||
|
PathNodeSig PathNode1, PathNodeSig PathNode2, PathNodeSig PathNode3,
|
||||||
|
PathGraphSig<PathNode1> Graph1, PathGraphSig<PathNode2> Graph2, PathGraphSig<PathNode3> Graph3>
|
||||||
|
{
|
||||||
|
private module MergedInner = MergePathGraph<PathNode1, PathNode2, Graph1, Graph2>;
|
||||||
|
|
||||||
|
private module Merged =
|
||||||
|
MergePathGraph<MergedInner::PathNode, PathNode3, MergedInner::PathGraph, Graph3>;
|
||||||
|
|
||||||
|
/** A node in a graph of path explanations that is formed by disjoint union of the three given graphs. */
|
||||||
|
class PathNode instanceof Merged::PathNode {
|
||||||
|
/** Gets this as a projection on the first given `PathGraph`. */
|
||||||
|
PathNode1 asPathNode1() { result = super.asPathNode1().asPathNode1() }
|
||||||
|
|
||||||
|
/** Gets this as a projection on the second given `PathGraph`. */
|
||||||
|
PathNode2 asPathNode2() { result = super.asPathNode1().asPathNode2() }
|
||||||
|
|
||||||
|
/** Gets this as a projection on the third given `PathGraph`. */
|
||||||
|
PathNode3 asPathNode3() { result = super.asPathNode2() }
|
||||||
|
|
||||||
|
/** Gets a textual representation of this element. */
|
||||||
|
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 filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the underlying `Node`. */
|
||||||
|
Node getNode() { result = super.getNode() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||||
|
*/
|
||||||
|
module PathGraph = Merged::PathGraph;
|
||||||
|
}
|
||||||
@@ -5,8 +5,8 @@ private import DataFlowUtil
|
|||||||
/**
|
/**
|
||||||
* Gets a function that might be called by `call`.
|
* Gets a function that might be called by `call`.
|
||||||
*/
|
*/
|
||||||
Function viableCallable(DataFlowCall call) {
|
Function viableCallable(Call call) {
|
||||||
result = call.(Call).getTarget()
|
result = call.getTarget()
|
||||||
or
|
or
|
||||||
// If the target of the call does not have a body in the snapshot, it might
|
// If the target of the call does not have a body in the snapshot, it might
|
||||||
// be because the target is just a header declaration, and the real target
|
// be because the target is just a header declaration, and the real target
|
||||||
@@ -58,13 +58,13 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam
|
|||||||
* Holds if the set of viable implementations that can be called by `call`
|
* Holds if the set of viable implementations that can be called by `call`
|
||||||
* might be improved by knowing the call context.
|
* might be improved by knowing the call context.
|
||||||
*/
|
*/
|
||||||
predicate mayBenefitFromCallContext(DataFlowCall call, Function f) { none() }
|
predicate mayBenefitFromCallContext(Call call, Function f) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
* restricted to those `call`s for which a context might make a difference.
|
* restricted to those `call`s for which a context might make a difference.
|
||||||
*/
|
*/
|
||||||
Function viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { none() }
|
Function viableImplInCallContext(Call call, Call ctx) { none() }
|
||||||
|
|
||||||
/** A parameter position represented by an integer. */
|
/** A parameter position represented by an integer. */
|
||||||
class ParameterPosition extends int {
|
class ParameterPosition extends int {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -276,8 +276,6 @@ private module Config implements FullStateConfigSig {
|
|||||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
predicate isSink(Node sink, FlowState state) {
|
predicate isSink(Node sink, FlowState state) {
|
||||||
getConfig(state).isSink(sink, getState(state))
|
getConfig(state).isSink(sink, getState(state))
|
||||||
or
|
or
|
||||||
@@ -315,8 +313,6 @@ private module Config implements FullStateConfigSig {
|
|||||||
any(Configuration config).allowImplicitRead(node, c)
|
any(Configuration config).allowImplicitRead(node, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate neverSkip(Node node) { none() }
|
|
||||||
|
|
||||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||||
|
|
||||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||||
|
|||||||
@@ -276,8 +276,6 @@ private module Config implements FullStateConfigSig {
|
|||||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
predicate isSink(Node sink, FlowState state) {
|
predicate isSink(Node sink, FlowState state) {
|
||||||
getConfig(state).isSink(sink, getState(state))
|
getConfig(state).isSink(sink, getState(state))
|
||||||
or
|
or
|
||||||
@@ -315,8 +313,6 @@ private module Config implements FullStateConfigSig {
|
|||||||
any(Configuration config).allowImplicitRead(node, c)
|
any(Configuration config).allowImplicitRead(node, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate neverSkip(Node node) { none() }
|
|
||||||
|
|
||||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||||
|
|
||||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||||
|
|||||||
@@ -276,8 +276,6 @@ private module Config implements FullStateConfigSig {
|
|||||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
predicate isSink(Node sink, FlowState state) {
|
predicate isSink(Node sink, FlowState state) {
|
||||||
getConfig(state).isSink(sink, getState(state))
|
getConfig(state).isSink(sink, getState(state))
|
||||||
or
|
or
|
||||||
@@ -315,8 +313,6 @@ private module Config implements FullStateConfigSig {
|
|||||||
any(Configuration config).allowImplicitRead(node, c)
|
any(Configuration config).allowImplicitRead(node, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate neverSkip(Node node) { none() }
|
|
||||||
|
|
||||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||||
|
|
||||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||||
|
|||||||
@@ -276,8 +276,6 @@ private module Config implements FullStateConfigSig {
|
|||||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
predicate isSink(Node sink, FlowState state) {
|
predicate isSink(Node sink, FlowState state) {
|
||||||
getConfig(state).isSink(sink, getState(state))
|
getConfig(state).isSink(sink, getState(state))
|
||||||
or
|
or
|
||||||
@@ -315,8 +313,6 @@ private module Config implements FullStateConfigSig {
|
|||||||
any(Configuration config).allowImplicitRead(node, c)
|
any(Configuration config).allowImplicitRead(node, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate neverSkip(Node node) { none() }
|
|
||||||
|
|
||||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||||
|
|
||||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -3,25 +3,288 @@
|
|||||||
* data-flow classes and predicates.
|
* data-flow classes and predicates.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private import cpp
|
private import DataFlowImplSpecific::Private
|
||||||
private import DataFlowImplSpecific
|
private import DataFlowImplSpecific::Public
|
||||||
private import TaintTrackingImplSpecific
|
private import tainttracking1.TaintTrackingParameter::Private
|
||||||
private import codeql.dataflow.internal.DataFlowImplConsistency
|
private import tainttracking1.TaintTrackingParameter::Public
|
||||||
|
|
||||||
private module Input implements InputSig<CppOldDataFlow> {
|
module Consistency {
|
||||||
predicate argHasPostUpdateExclude(Private::ArgumentNode n) {
|
private newtype TConsistencyConfiguration = MkConsistencyConfiguration()
|
||||||
// Is the null pointer (or something that's not really a pointer)
|
|
||||||
exists(n.asExpr().getValue())
|
/** A class for configuring the consistency queries. */
|
||||||
or
|
class ConsistencyConfiguration extends TConsistencyConfiguration {
|
||||||
// Isn't a pointer or is a pointer to const
|
string toString() { none() }
|
||||||
forall(DerivedType dt | dt = n.asExpr().getActualType() |
|
|
||||||
dt.getBaseType().isConst()
|
/** Holds if `n` should be excluded from the consistency test `uniqueEnclosingCallable`. */
|
||||||
or
|
predicate uniqueEnclosingCallableExclude(Node n) { none() }
|
||||||
dt.getBaseType() instanceof RoutineType
|
|
||||||
|
/** Holds if `call` should be excluded from the consistency test `uniqueCallEnclosingCallable`. */
|
||||||
|
predicate uniqueCallEnclosingCallableExclude(DataFlowCall call) { none() }
|
||||||
|
|
||||||
|
/** Holds if `n` should be excluded from the consistency test `uniqueNodeLocation`. */
|
||||||
|
predicate uniqueNodeLocationExclude(Node n) { none() }
|
||||||
|
|
||||||
|
/** Holds if `n` should be excluded from the consistency test `missingLocation`. */
|
||||||
|
predicate missingLocationExclude(Node n) { none() }
|
||||||
|
|
||||||
|
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
|
||||||
|
predicate postWithInFlowExclude(Node n) { none() }
|
||||||
|
|
||||||
|
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
|
||||||
|
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
|
||||||
|
|
||||||
|
/** Holds if `n` should be excluded from the consistency test `reverseRead`. */
|
||||||
|
predicate reverseReadExclude(Node n) { none() }
|
||||||
|
|
||||||
|
/** Holds if `n` should be excluded from the consistency test `postHasUniquePre`. */
|
||||||
|
predicate postHasUniquePreExclude(PostUpdateNode n) { none() }
|
||||||
|
|
||||||
|
/** Holds if `n` should be excluded from the consistency test `uniquePostUpdate`. */
|
||||||
|
predicate uniquePostUpdateExclude(Node n) { none() }
|
||||||
|
|
||||||
|
/** Holds if `(call, ctx)` should be excluded from the consistency test `viableImplInCallContextTooLargeExclude`. */
|
||||||
|
predicate viableImplInCallContextTooLargeExclude(
|
||||||
|
DataFlowCall call, DataFlowCall ctx, DataFlowCallable callable
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodeAtPosition`. */
|
||||||
|
predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodePosition`. */
|
||||||
|
predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RelevantNode extends Node {
|
||||||
|
RelevantNode() {
|
||||||
|
this instanceof ArgumentNode or
|
||||||
|
this instanceof ParameterNode or
|
||||||
|
this instanceof ReturnNode or
|
||||||
|
this = getAnOutNode(_, _) or
|
||||||
|
simpleLocalFlowStep(this, _) or
|
||||||
|
simpleLocalFlowStep(_, this) or
|
||||||
|
jumpStep(this, _) or
|
||||||
|
jumpStep(_, this) or
|
||||||
|
storeStep(this, _, _) or
|
||||||
|
storeStep(_, _, this) or
|
||||||
|
readStep(this, _, _) or
|
||||||
|
readStep(_, _, this) or
|
||||||
|
defaultAdditionalTaintStep(this, _) or
|
||||||
|
defaultAdditionalTaintStep(_, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate uniqueEnclosingCallable(Node n, string msg) {
|
||||||
|
exists(int c |
|
||||||
|
n instanceof RelevantNode and
|
||||||
|
c = count(nodeGetEnclosingCallable(n)) and
|
||||||
|
c != 1 and
|
||||||
|
not any(ConsistencyConfiguration conf).uniqueEnclosingCallableExclude(n) and
|
||||||
|
msg = "Node should have one enclosing callable but has " + c + "."
|
||||||
)
|
)
|
||||||
// The above list of cases isn't exhaustive, but it narrows down the
|
}
|
||||||
// consistency alerts enough that most of them are interesting.
|
|
||||||
|
query predicate uniqueCallEnclosingCallable(DataFlowCall call, string msg) {
|
||||||
|
exists(int c |
|
||||||
|
c = count(call.getEnclosingCallable()) and
|
||||||
|
c != 1 and
|
||||||
|
not any(ConsistencyConfiguration conf).uniqueCallEnclosingCallableExclude(call) and
|
||||||
|
msg = "Call should have one enclosing callable but has " + c + "."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate uniqueType(Node n, string msg) {
|
||||||
|
exists(int c |
|
||||||
|
n instanceof RelevantNode and
|
||||||
|
c = count(getNodeType(n)) and
|
||||||
|
c != 1 and
|
||||||
|
msg = "Node should have one type but has " + c + "."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate uniqueNodeLocation(Node n, string msg) {
|
||||||
|
exists(int c |
|
||||||
|
c =
|
||||||
|
count(string filepath, int startline, int startcolumn, int endline, int endcolumn |
|
||||||
|
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
) and
|
||||||
|
c != 1 and
|
||||||
|
not any(ConsistencyConfiguration conf).uniqueNodeLocationExclude(n) and
|
||||||
|
msg = "Node should have one location but has " + c + "."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate missingLocation(string msg) {
|
||||||
|
exists(int c |
|
||||||
|
c =
|
||||||
|
strictcount(Node n |
|
||||||
|
not n.hasLocationInfo(_, _, _, _, _) and
|
||||||
|
not any(ConsistencyConfiguration conf).missingLocationExclude(n)
|
||||||
|
) and
|
||||||
|
msg = "Nodes without location: " + c
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate uniqueNodeToString(Node n, string msg) {
|
||||||
|
exists(int c |
|
||||||
|
c = count(n.toString()) and
|
||||||
|
c != 1 and
|
||||||
|
msg = "Node should have one toString but has " + c + "."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate missingToString(string msg) {
|
||||||
|
exists(int c |
|
||||||
|
c = strictcount(Node n | not exists(n.toString())) and
|
||||||
|
msg = "Nodes without toString: " + c
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate parameterCallable(ParameterNode p, string msg) {
|
||||||
|
exists(DataFlowCallable c | isParameterNode(p, c, _) and c != nodeGetEnclosingCallable(p)) and
|
||||||
|
msg = "Callable mismatch for parameter."
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate localFlowIsLocal(Node n1, Node n2, string msg) {
|
||||||
|
simpleLocalFlowStep(n1, n2) and
|
||||||
|
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
|
||||||
|
msg = "Local flow step does not preserve enclosing callable."
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate readStepIsLocal(Node n1, Node n2, string msg) {
|
||||||
|
readStep(n1, _, n2) and
|
||||||
|
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
|
||||||
|
msg = "Read step does not preserve enclosing callable."
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate storeStepIsLocal(Node n1, Node n2, string msg) {
|
||||||
|
storeStep(n1, _, n2) and
|
||||||
|
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
|
||||||
|
msg = "Store step does not preserve enclosing callable."
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataFlowType typeRepr() { result = getNodeType(_) }
|
||||||
|
|
||||||
|
query predicate compatibleTypesReflexive(DataFlowType t, string msg) {
|
||||||
|
t = typeRepr() and
|
||||||
|
not compatibleTypes(t, t) and
|
||||||
|
msg = "Type compatibility predicate is not reflexive."
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate unreachableNodeCCtx(Node n, DataFlowCall call, string msg) {
|
||||||
|
isUnreachableInCall(n, call) and
|
||||||
|
exists(DataFlowCallable c |
|
||||||
|
c = nodeGetEnclosingCallable(n) and
|
||||||
|
not viableCallable(call) = c
|
||||||
|
) and
|
||||||
|
msg = "Call context for isUnreachableInCall is inconsistent with call graph."
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate localCallNodes(DataFlowCall call, Node n, string msg) {
|
||||||
|
(
|
||||||
|
n = getAnOutNode(call, _) and
|
||||||
|
msg = "OutNode and call does not share enclosing callable."
|
||||||
|
or
|
||||||
|
n.(ArgumentNode).argumentOf(call, _) and
|
||||||
|
msg = "ArgumentNode and call does not share enclosing callable."
|
||||||
|
) and
|
||||||
|
nodeGetEnclosingCallable(n) != call.getEnclosingCallable()
|
||||||
|
}
|
||||||
|
|
||||||
|
// This predicate helps the compiler forget that in some languages
|
||||||
|
// it is impossible for a result of `getPreUpdateNode` to be an
|
||||||
|
// instance of `PostUpdateNode`.
|
||||||
|
private Node getPre(PostUpdateNode n) {
|
||||||
|
result = n.getPreUpdateNode()
|
||||||
|
or
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate postIsNotPre(PostUpdateNode n, string msg) {
|
||||||
|
getPre(n) = n and
|
||||||
|
msg = "PostUpdateNode should not equal its pre-update node."
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate postHasUniquePre(PostUpdateNode n, string msg) {
|
||||||
|
not any(ConsistencyConfiguration conf).postHasUniquePreExclude(n) and
|
||||||
|
exists(int c |
|
||||||
|
c = count(n.getPreUpdateNode()) and
|
||||||
|
c != 1 and
|
||||||
|
msg = "PostUpdateNode should have one pre-update node but has " + c + "."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate uniquePostUpdate(Node n, string msg) {
|
||||||
|
not any(ConsistencyConfiguration conf).uniquePostUpdateExclude(n) and
|
||||||
|
1 < strictcount(PostUpdateNode post | post.getPreUpdateNode() = n) and
|
||||||
|
msg = "Node has multiple PostUpdateNodes."
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate postIsInSameCallable(PostUpdateNode n, string msg) {
|
||||||
|
nodeGetEnclosingCallable(n) != nodeGetEnclosingCallable(n.getPreUpdateNode()) and
|
||||||
|
msg = "PostUpdateNode does not share callable with its pre-update node."
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate hasPost(Node n) { exists(PostUpdateNode post | post.getPreUpdateNode() = n) }
|
||||||
|
|
||||||
|
query predicate reverseRead(Node n, string msg) {
|
||||||
|
exists(Node n2 | readStep(n, _, n2) and hasPost(n2) and not hasPost(n)) and
|
||||||
|
not any(ConsistencyConfiguration conf).reverseReadExclude(n) and
|
||||||
|
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
|
||||||
|
not hasPost(n) and
|
||||||
|
not any(ConsistencyConfiguration c).argHasPostUpdateExclude(n) and
|
||||||
|
msg = "ArgumentNode is missing PostUpdateNode."
|
||||||
|
}
|
||||||
|
|
||||||
|
// This predicate helps the compiler forget that in some languages
|
||||||
|
// it is impossible for a `PostUpdateNode` to be the target of
|
||||||
|
// `simpleLocalFlowStep`.
|
||||||
|
private predicate isPostUpdateNode(Node n) { n instanceof PostUpdateNode or none() }
|
||||||
|
|
||||||
|
query predicate postWithInFlow(Node n, string msg) {
|
||||||
|
isPostUpdateNode(n) and
|
||||||
|
not clearsContent(n, _) and
|
||||||
|
simpleLocalFlowStep(_, n) and
|
||||||
|
not any(ConsistencyConfiguration c).postWithInFlowExclude(n) and
|
||||||
|
msg = "PostUpdateNode should not be the target of local flow."
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate viableImplInCallContextTooLarge(
|
||||||
|
DataFlowCall call, DataFlowCall ctx, DataFlowCallable callable
|
||||||
|
) {
|
||||||
|
callable = viableImplInCallContext(call, ctx) and
|
||||||
|
not callable = viableCallable(call) and
|
||||||
|
not any(ConsistencyConfiguration c).viableImplInCallContextTooLargeExclude(call, ctx, callable)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate uniqueParameterNodeAtPosition(
|
||||||
|
DataFlowCallable c, ParameterPosition pos, Node p, string msg
|
||||||
|
) {
|
||||||
|
not any(ConsistencyConfiguration conf).uniqueParameterNodeAtPositionExclude(c, pos, p) and
|
||||||
|
isParameterNode(p, c, pos) and
|
||||||
|
not exists(unique(Node p0 | isParameterNode(p0, c, pos))) and
|
||||||
|
msg = "Parameters with overlapping positions."
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate uniqueParameterNodePosition(
|
||||||
|
DataFlowCallable c, ParameterPosition pos, Node p, string msg
|
||||||
|
) {
|
||||||
|
not any(ConsistencyConfiguration conf).uniqueParameterNodePositionExclude(c, pos, p) and
|
||||||
|
isParameterNode(p, c, pos) and
|
||||||
|
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
|
||||||
|
msg = "Parameter node with multiple positions."
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate uniqueContentApprox(Content c, string msg) {
|
||||||
|
not exists(unique(ContentApprox approx | approx = getContentApprox(c))) and
|
||||||
|
msg = "Non-unique content approximation."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module Consistency = MakeConsistency<CppOldDataFlow, CppOldTaintTracking, Input>;
|
|
||||||
|
|||||||
@@ -276,8 +276,6 @@ private module Config implements FullStateConfigSig {
|
|||||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
predicate isSink(Node sink, FlowState state) {
|
predicate isSink(Node sink, FlowState state) {
|
||||||
getConfig(state).isSink(sink, getState(state))
|
getConfig(state).isSink(sink, getState(state))
|
||||||
or
|
or
|
||||||
@@ -315,8 +313,6 @@ private module Config implements FullStateConfigSig {
|
|||||||
any(Configuration config).allowImplicitRead(node, c)
|
any(Configuration config).allowImplicitRead(node, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate neverSkip(Node node) { none() }
|
|
||||||
|
|
||||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||||
|
|
||||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Provides C++-specific definitions for use in the data flow library.
|
* Provides C++-specific definitions for use in the data flow library.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private import codeql.dataflow.DataFlow
|
|
||||||
|
|
||||||
module Private {
|
module Private {
|
||||||
import DataFlowPrivate
|
import DataFlowPrivate
|
||||||
import DataFlowDispatch
|
import DataFlowDispatch
|
||||||
@@ -12,10 +9,3 @@ module Private {
|
|||||||
module Public {
|
module Public {
|
||||||
import DataFlowUtil
|
import DataFlowUtil
|
||||||
}
|
}
|
||||||
|
|
||||||
module CppOldDataFlow implements InputSig {
|
|
||||||
import Private
|
|
||||||
import Public
|
|
||||||
|
|
||||||
Node exprNode(DataFlowExpr e) { result = Public::exprNode(e) }
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ private import cpp
|
|||||||
private import DataFlowUtil
|
private import DataFlowUtil
|
||||||
private import DataFlowDispatch
|
private import DataFlowDispatch
|
||||||
private import FlowVar
|
private import FlowVar
|
||||||
|
private import DataFlowImplConsistency
|
||||||
private import codeql.util.Unit
|
private import codeql.util.Unit
|
||||||
|
|
||||||
/** Gets the callable in which this node occurs. */
|
/** Gets the callable in which this node occurs. */
|
||||||
@@ -152,11 +153,10 @@ predicate jumpStep(Node n1, Node n2) { none() }
|
|||||||
* Thus, `node2` references an object with a field `f` that contains the
|
* Thus, `node2` references an object with a field `f` that contains the
|
||||||
* value of `node1`.
|
* value of `node1`.
|
||||||
*/
|
*/
|
||||||
predicate storeStep(Node node1, ContentSet f, Node node2) {
|
predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
|
||||||
exists(ClassAggregateLiteral aggr, Field field |
|
exists(ClassAggregateLiteral aggr, Field field |
|
||||||
// The following lines requires `node2` to be both an `ExprNode` and a
|
// The following line requires `node2` to be both an `ExprNode` and a
|
||||||
// `PostUpdateNode`, which means it must be an `ObjectInitializerNode`.
|
// `PostUpdateNode`, which means it must be an `ObjectInitializerNode`.
|
||||||
node2 instanceof PostUpdateNode and
|
|
||||||
node2.asExpr() = aggr and
|
node2.asExpr() = aggr and
|
||||||
f.(FieldContent).getField() = field and
|
f.(FieldContent).getField() = field and
|
||||||
aggr.getAFieldExpr(field) = node1.asExpr()
|
aggr.getAFieldExpr(field) = node1.asExpr()
|
||||||
@@ -167,13 +167,12 @@ predicate storeStep(Node node1, ContentSet f, Node node2) {
|
|||||||
node1.asExpr() = a and
|
node1.asExpr() = a and
|
||||||
a.getLValue() = fa
|
a.getLValue() = fa
|
||||||
) and
|
) and
|
||||||
node2.(PostUpdateNode).getPreUpdateNode().asExpr() = fa.getQualifier() and
|
node2.getPreUpdateNode().asExpr() = fa.getQualifier() and
|
||||||
f.(FieldContent).getField() = fa.getTarget()
|
f.(FieldContent).getField() = fa.getTarget()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(ConstructorFieldInit cfi |
|
exists(ConstructorFieldInit cfi |
|
||||||
node2.(PostUpdateNode).getPreUpdateNode().(PreConstructorInitThis).getConstructorFieldInit() =
|
node2.getPreUpdateNode().(PreConstructorInitThis).getConstructorFieldInit() = cfi and
|
||||||
cfi and
|
|
||||||
f.(FieldContent).getField() = cfi.getTarget() and
|
f.(FieldContent).getField() = cfi.getTarget() and
|
||||||
node1.asExpr() = cfi.getExpr()
|
node1.asExpr() = cfi.getExpr()
|
||||||
)
|
)
|
||||||
@@ -184,7 +183,7 @@ predicate storeStep(Node node1, ContentSet f, Node node2) {
|
|||||||
* Thus, `node1` references an object with a field `f` whose value ends up in
|
* Thus, `node1` references an object with a field `f` whose value ends up in
|
||||||
* `node2`.
|
* `node2`.
|
||||||
*/
|
*/
|
||||||
predicate readStep(Node node1, ContentSet f, Node node2) {
|
predicate readStep(Node node1, Content f, Node node2) {
|
||||||
exists(FieldAccess fr |
|
exists(FieldAccess fr |
|
||||||
node1.asExpr() = fr.getQualifier() and
|
node1.asExpr() = fr.getQualifier() and
|
||||||
fr.getTarget() = f.(FieldContent).getField() and
|
fr.getTarget() = f.(FieldContent).getField() and
|
||||||
@@ -196,7 +195,7 @@ predicate readStep(Node node1, ContentSet f, Node node2) {
|
|||||||
/**
|
/**
|
||||||
* Holds if values stored inside content `c` are cleared at node `n`.
|
* Holds if values stored inside content `c` are cleared at node `n`.
|
||||||
*/
|
*/
|
||||||
predicate clearsContent(Node n, ContentSet c) {
|
predicate clearsContent(Node n, Content c) {
|
||||||
none() // stub implementation
|
none() // stub implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,8 +205,6 @@ predicate clearsContent(Node n, ContentSet c) {
|
|||||||
*/
|
*/
|
||||||
predicate expectsContent(Node n, ContentSet c) { none() }
|
predicate expectsContent(Node n, ContentSet c) { none() }
|
||||||
|
|
||||||
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { 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
|
||||||
@@ -260,6 +257,8 @@ class DataFlowCall extends Expr instanceof Call {
|
|||||||
|
|
||||||
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation
|
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation
|
||||||
|
|
||||||
|
int accessPathLimit() { result = 5 }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if access paths with `c` at their head always should be tracked at high
|
* Holds if access paths with `c` at their head always should be tracked at high
|
||||||
* precision. This disables adaptive access path precision for such access paths.
|
* precision. This disables adaptive access path precision for such access paths.
|
||||||
@@ -296,6 +295,22 @@ class ContentApprox = Unit;
|
|||||||
pragma[inline]
|
pragma[inline]
|
||||||
ContentApprox getContentApprox(Content c) { any() }
|
ContentApprox getContentApprox(Content c) { any() }
|
||||||
|
|
||||||
|
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
|
||||||
|
override predicate argHasPostUpdateExclude(ArgumentNode n) {
|
||||||
|
// Is the null pointer (or something that's not really a pointer)
|
||||||
|
exists(n.asExpr().getValue())
|
||||||
|
or
|
||||||
|
// Isn't a pointer or is a pointer to const
|
||||||
|
forall(DerivedType dt | dt = n.asExpr().getActualType() |
|
||||||
|
dt.getBaseType().isConst()
|
||||||
|
or
|
||||||
|
dt.getBaseType() instanceof RoutineType
|
||||||
|
)
|
||||||
|
// The above list of cases isn't exhaustive, but it narrows down the
|
||||||
|
// consistency alerts enough that most of them are interesting.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an additional term that is added to the `join` and `branch` computations to reflect
|
* Gets an additional term that is added to the `join` and `branch` computations to reflect
|
||||||
* an additional forward or backwards branching factor that is not taken into account
|
* an additional forward or backwards branching factor that is not taken into account
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides C++-specific definitions for use in the taint tracking library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private import codeql.dataflow.TaintTracking
|
|
||||||
private import DataFlowImplSpecific
|
|
||||||
|
|
||||||
module CppOldTaintTracking implements InputSig<CppOldDataFlow> {
|
|
||||||
import TaintTrackingUtil
|
|
||||||
}
|
|
||||||
@@ -39,7 +39,7 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
|||||||
* of `c` at sinks and inputs to additional taint steps.
|
* of `c` at sinks and inputs to additional taint steps.
|
||||||
*/
|
*/
|
||||||
bindingset[node]
|
bindingset[node]
|
||||||
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { none() }
|
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::Content c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `node` should be a sanitizer in all global taint flow configurations
|
* Holds if `node` should be a sanitizer in all global taint flow configurations
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* Provides classes for performing local (intra-procedural) and
|
||||||
|
* global (inter-procedural) taint-tracking analyses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import TaintTrackingParameter::Public
|
||||||
|
private import TaintTrackingParameter::Private
|
||||||
|
|
||||||
|
private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
|
||||||
|
DataFlowInternal::FullStateConfigSig
|
||||||
|
{
|
||||||
|
import Config
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
Config::isBarrier(node) or defaultTaintSanitizer(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
|
Config::isAdditionalFlowStep(node1, node2) or
|
||||||
|
defaultAdditionalTaintStep(node1, node2)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||||
|
Config::allowImplicitRead(node, c)
|
||||||
|
or
|
||||||
|
(
|
||||||
|
Config::isSink(node, _) or
|
||||||
|
Config::isAdditionalFlowStep(node, _) or
|
||||||
|
Config::isAdditionalFlowStep(node, _, _, _)
|
||||||
|
) and
|
||||||
|
defaultImplicitTaintRead(node, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a global taint tracking computation.
|
||||||
|
*/
|
||||||
|
module Global<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||||
|
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||||
|
import DataFlowInternal::DefaultState<Config>
|
||||||
|
import Config
|
||||||
|
}
|
||||||
|
|
||||||
|
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||||
|
import AddTaintDefaults<Config0>
|
||||||
|
}
|
||||||
|
|
||||||
|
import DataFlowInternal::Impl<C>
|
||||||
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Use `Global` instead. */
|
||||||
|
deprecated module Make<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||||
|
import Global<Config>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a global taint tracking computation using flow state.
|
||||||
|
*/
|
||||||
|
module GlobalWithState<DataFlow::StateConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||||
|
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||||
|
import Config
|
||||||
|
}
|
||||||
|
|
||||||
|
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||||
|
import AddTaintDefaults<Config0>
|
||||||
|
}
|
||||||
|
|
||||||
|
import DataFlowInternal::Impl<C>
|
||||||
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Use `GlobalWithState` instead. */
|
||||||
|
deprecated module MakeWithState<DataFlow::StateConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||||
|
import GlobalWithState<Config>
|
||||||
|
}
|
||||||
@@ -26,8 +26,6 @@ import cpp
|
|||||||
* global (inter-procedural) data flow analyses.
|
* global (inter-procedural) data flow analyses.
|
||||||
*/
|
*/
|
||||||
module DataFlow {
|
module DataFlow {
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
import semmle.code.cpp.ir.dataflow.internal.DataFlow
|
||||||
private import codeql.dataflow.DataFlow
|
|
||||||
import DataFlowMake<CppDataFlow>
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1
|
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,6 @@ import semmle.code.cpp.dataflow.new.DataFlow2
|
|||||||
* global (inter-procedural) taint-tracking analyses.
|
* global (inter-procedural) taint-tracking analyses.
|
||||||
*/
|
*/
|
||||||
module TaintTracking {
|
module TaintTracking {
|
||||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingParameter::Public
|
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTracking
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific
|
|
||||||
private import codeql.dataflow.TaintTracking
|
|
||||||
import TaintFlowMake<CppDataFlow, CppTaintTracking>
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl
|
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -368,11 +368,6 @@ class FunctionAccess extends Access, @routineexpr {
|
|||||||
/** Gets the accessed function. */
|
/** Gets the accessed function. */
|
||||||
override Function getTarget() { funbind(underlyingElement(this), unresolveElement(result)) }
|
override Function getTarget() { funbind(underlyingElement(this), unresolveElement(result)) }
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the expression generating the function being accessed.
|
|
||||||
*/
|
|
||||||
Expr getQualifier() { this.getChild(-1) = result }
|
|
||||||
|
|
||||||
/** Gets a textual representation of this function access. */
|
/** Gets a textual representation of this function access. */
|
||||||
override string toString() {
|
override string toString() {
|
||||||
if exists(this.getTarget())
|
if exists(this.getTarget())
|
||||||
|
|||||||
@@ -76,9 +76,9 @@ class GTExpr extends RelationalOperation, @gtexpr {
|
|||||||
|
|
||||||
override string getOperator() { result = ">" }
|
override string getOperator() { result = ">" }
|
||||||
|
|
||||||
override Expr getGreaterOperand() { result = this.getLeftOperand() }
|
override Expr getGreaterOperand() { result = getLeftOperand() }
|
||||||
|
|
||||||
override Expr getLesserOperand() { result = this.getRightOperand() }
|
override Expr getLesserOperand() { result = getRightOperand() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,9 +92,9 @@ class LTExpr extends RelationalOperation, @ltexpr {
|
|||||||
|
|
||||||
override string getOperator() { result = "<" }
|
override string getOperator() { result = "<" }
|
||||||
|
|
||||||
override Expr getGreaterOperand() { result = this.getRightOperand() }
|
override Expr getGreaterOperand() { result = getRightOperand() }
|
||||||
|
|
||||||
override Expr getLesserOperand() { result = this.getLeftOperand() }
|
override Expr getLesserOperand() { result = getLeftOperand() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -108,9 +108,9 @@ class GEExpr extends RelationalOperation, @geexpr {
|
|||||||
|
|
||||||
override string getOperator() { result = ">=" }
|
override string getOperator() { result = ">=" }
|
||||||
|
|
||||||
override Expr getGreaterOperand() { result = this.getLeftOperand() }
|
override Expr getGreaterOperand() { result = getLeftOperand() }
|
||||||
|
|
||||||
override Expr getLesserOperand() { result = this.getRightOperand() }
|
override Expr getLesserOperand() { result = getRightOperand() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,7 +124,7 @@ class LEExpr extends RelationalOperation, @leexpr {
|
|||||||
|
|
||||||
override string getOperator() { result = "<=" }
|
override string getOperator() { result = "<=" }
|
||||||
|
|
||||||
override Expr getGreaterOperand() { result = this.getRightOperand() }
|
override Expr getGreaterOperand() { result = getRightOperand() }
|
||||||
|
|
||||||
override Expr getLesserOperand() { result = this.getLeftOperand() }
|
override Expr getLesserOperand() { result = getLeftOperand() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,19 +152,7 @@ class Expr extends StmtParent, @expr {
|
|||||||
else result = this.getValue()
|
else result = this.getValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Holds if this expression has a value that can be determined at compile time. */
|
||||||
* Holds if this expression has a value that can be determined at compile time.
|
|
||||||
*
|
|
||||||
* An expression has a value that can be determined at compile time when:
|
|
||||||
* - it is a compile-time constant, e.g., a literal value or the result of a constexpr
|
|
||||||
* compile-time constant;
|
|
||||||
* - it is an address of a (member) function, an address of a constexpr variable
|
|
||||||
* initialized to a constant address, or an address of an lvalue, or any of the
|
|
||||||
* previous with a constant value added to or subtracted from the address;
|
|
||||||
* - it is a reference to a (member) function, a reference to a constexpr variable
|
|
||||||
* initialized to a constant address, or a reference to an lvalue;
|
|
||||||
* - it is a non-template parameter of a uninstantiated template.
|
|
||||||
*/
|
|
||||||
cached
|
cached
|
||||||
predicate isConstant() {
|
predicate isConstant() {
|
||||||
valuebind(_, underlyingElement(this))
|
valuebind(_, underlyingElement(this))
|
||||||
@@ -932,30 +920,45 @@ class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr {
|
|||||||
Expr getExtent() { result = this.getChild(2) }
|
Expr getExtent() { result = this.getChild(2) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TDeleteOrDeleteArrayExpr = @delete_expr or @delete_array_expr;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A C++ `delete` or `delete[]` expression.
|
* A C++ `delete` (non-array) expression.
|
||||||
|
* ```
|
||||||
|
* delete ptr;
|
||||||
|
* ```
|
||||||
*/
|
*/
|
||||||
class DeleteOrDeleteArrayExpr extends Expr, TDeleteOrDeleteArrayExpr {
|
class DeleteExpr extends Expr, @delete_expr {
|
||||||
|
override string toString() { result = "delete" }
|
||||||
|
|
||||||
|
override string getAPrimaryQlClass() { result = "DeleteExpr" }
|
||||||
|
|
||||||
override int getPrecedence() { result = 16 }
|
override int getPrecedence() { result = 16 }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the compile-time type of the object being deleted.
|
||||||
|
*/
|
||||||
|
Type getDeletedObjectType() {
|
||||||
|
result =
|
||||||
|
this.getExpr()
|
||||||
|
.getFullyConverted()
|
||||||
|
.getType()
|
||||||
|
.stripTopLevelSpecifiers()
|
||||||
|
.(PointerType)
|
||||||
|
.getBaseType()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the call to a destructor that occurs prior to the object's memory being deallocated, if any.
|
* Gets the call to a destructor that occurs prior to the object's memory being deallocated, if any.
|
||||||
*
|
|
||||||
* In the case of `delete[]` at runtime, the destructor will be called once for each element in the array, but the
|
|
||||||
* destructor call only exists once in the AST.
|
|
||||||
*/
|
*/
|
||||||
DestructorCall getDestructorCall() { result = this.getChild(1) }
|
DestructorCall getDestructorCall() { result = this.getChild(1) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the destructor to be called to destroy the object or array, if any.
|
* Gets the destructor to be called to destroy the object, if any.
|
||||||
*/
|
*/
|
||||||
Destructor getDestructor() { result = this.getDestructorCall().getTarget() }
|
Destructor getDestructor() { result = this.getDestructorCall().getTarget() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the `operator delete` or `operator delete[]` that deallocates storage.
|
* Gets the `operator delete` that deallocates storage. Does not hold
|
||||||
* Does not hold if the type being destroyed has a virtual destructor. In that case, the
|
* if the type being destroyed has a virtual destructor. In that case, the
|
||||||
* `operator delete` that will be called is determined at runtime based on the
|
* `operator delete` that will be called is determined at runtime based on the
|
||||||
* dynamic type of the object.
|
* dynamic type of the object.
|
||||||
*/
|
*/
|
||||||
@@ -963,19 +966,6 @@ class DeleteOrDeleteArrayExpr extends Expr, TDeleteOrDeleteArrayExpr {
|
|||||||
expr_deallocator(underlyingElement(this), unresolveElement(result), _)
|
expr_deallocator(underlyingElement(this), unresolveElement(result), _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: use `getDeallocatorCall` instead.
|
|
||||||
*/
|
|
||||||
deprecated FunctionCall getAllocatorCall() { result = this.getChild(0) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the call to a non-default `operator delete`/`delete[]` that deallocates storage, if any.
|
|
||||||
*
|
|
||||||
* This will only be present when the type being deleted has a custom `operator delete` and
|
|
||||||
* does not have a virtual destructor.
|
|
||||||
*/
|
|
||||||
FunctionCall getDeallocatorCall() { result = this.getChild(0) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the deallocation function expects a size argument.
|
* Holds if the deallocation function expects a size argument.
|
||||||
*/
|
*/
|
||||||
@@ -997,38 +987,16 @@ class DeleteOrDeleteArrayExpr extends Expr, TDeleteOrDeleteArrayExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the object or array being deleted.
|
* Gets the call to a non-default `operator delete` that deallocates storage, if any.
|
||||||
|
*
|
||||||
|
* This will only be present when the type being deleted has a custom `operator delete`.
|
||||||
*/
|
*/
|
||||||
Expr getExpr() {
|
FunctionCall getAllocatorCall() { result = this.getChild(0) }
|
||||||
// If there is a destructor call, the object being deleted is the qualifier
|
|
||||||
// otherwise it is the third child.
|
|
||||||
result = this.getChild(3) or result = this.getDestructorCall().getQualifier()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A C++ `delete` (non-array) expression.
|
|
||||||
* ```
|
|
||||||
* delete ptr;
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
class DeleteExpr extends DeleteOrDeleteArrayExpr, @delete_expr {
|
|
||||||
override string toString() { result = "delete" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "DeleteExpr" }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the compile-time type of the object being deleted.
|
* Gets the object being deleted.
|
||||||
*/
|
*/
|
||||||
Type getDeletedObjectType() {
|
Expr getExpr() { result = this.getChild(3) or result = this.getChild(1).getChild(-1) }
|
||||||
result =
|
|
||||||
this.getExpr()
|
|
||||||
.getFullyConverted()
|
|
||||||
.getType()
|
|
||||||
.stripTopLevelSpecifiers()
|
|
||||||
.(PointerType)
|
|
||||||
.getBaseType()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1037,11 +1005,13 @@ class DeleteExpr extends DeleteOrDeleteArrayExpr, @delete_expr {
|
|||||||
* delete[] arr;
|
* delete[] arr;
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class DeleteArrayExpr extends DeleteOrDeleteArrayExpr, @delete_array_expr {
|
class DeleteArrayExpr extends Expr, @delete_array_expr {
|
||||||
override string toString() { result = "delete[]" }
|
override string toString() { result = "delete[]" }
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "DeleteArrayExpr" }
|
override string getAPrimaryQlClass() { result = "DeleteArrayExpr" }
|
||||||
|
|
||||||
|
override int getPrecedence() { result = 16 }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the element type of the array being deleted.
|
* Gets the element type of the array being deleted.
|
||||||
*/
|
*/
|
||||||
@@ -1054,6 +1024,58 @@ class DeleteArrayExpr extends DeleteOrDeleteArrayExpr, @delete_array_expr {
|
|||||||
.(PointerType)
|
.(PointerType)
|
||||||
.getBaseType()
|
.getBaseType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the call to a destructor that occurs prior to the array's memory being deallocated, if any.
|
||||||
|
*
|
||||||
|
* At runtime, the destructor will be called once for each element in the array, but the
|
||||||
|
* destructor call only exists once in the AST.
|
||||||
|
*/
|
||||||
|
DestructorCall getDestructorCall() { result = this.getChild(1) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the destructor to be called to destroy each element in the array, if any.
|
||||||
|
*/
|
||||||
|
Destructor getDestructor() { result = this.getDestructorCall().getTarget() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the `operator delete[]` that deallocates storage.
|
||||||
|
*/
|
||||||
|
Function getDeallocator() {
|
||||||
|
expr_deallocator(underlyingElement(this), unresolveElement(result), _)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the deallocation function expects a size argument.
|
||||||
|
*/
|
||||||
|
predicate hasSizedDeallocation() {
|
||||||
|
exists(int form |
|
||||||
|
expr_deallocator(underlyingElement(this), _, form) and
|
||||||
|
form.bitAnd(1) != 0 // Bit zero is the "size" bit
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the deallocation function expects an alignment argument.
|
||||||
|
*/
|
||||||
|
predicate hasAlignedDeallocation() {
|
||||||
|
exists(int form |
|
||||||
|
expr_deallocator(underlyingElement(this), _, form) and
|
||||||
|
form.bitAnd(2) != 0 // Bit one is the "alignment" bit
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the call to a non-default `operator delete` that deallocates storage, if any.
|
||||||
|
*
|
||||||
|
* This will only be present when the type being deleted has a custom `operator delete`.
|
||||||
|
*/
|
||||||
|
FunctionCall getAllocatorCall() { result = this.getChild(0) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the array being deleted.
|
||||||
|
*/
|
||||||
|
Expr getExpr() { result = this.getChild(3) or result = this.getChild(1).getChild(-1) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
* This file contains the actual implementation of `PrintIR.ql`. For test cases and very small
|
* This file contains the actual implementation of `PrintIR.ql`. For test cases and very small
|
||||||
* databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most
|
* databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most
|
||||||
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
|
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
|
||||||
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
|
* `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to
|
||||||
* to dump.
|
* dump.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import implementation.aliased_ssa.PrintIR
|
import implementation.aliased_ssa.PrintIR
|
||||||
|
|||||||
@@ -22,8 +22,6 @@
|
|||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
module DataFlow {
|
module DataFlow {
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
import semmle.code.cpp.ir.dataflow.internal.DataFlow
|
||||||
private import codeql.dataflow.DataFlow
|
|
||||||
import DataFlowMake<CppDataFlow>
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1
|
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,6 @@ import semmle.code.cpp.ir.dataflow.DataFlow
|
|||||||
import semmle.code.cpp.ir.dataflow.DataFlow2
|
import semmle.code.cpp.ir.dataflow.DataFlow2
|
||||||
|
|
||||||
module TaintTracking {
|
module TaintTracking {
|
||||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingParameter::Public
|
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTracking
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific
|
|
||||||
private import codeql.dataflow.TaintTracking
|
|
||||||
import TaintFlowMake<CppDataFlow, CppTaintTracking>
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl
|
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user