Compare commits

..

1 Commits

Author SHA1 Message Date
CodeQL CI
375a4f3c69 Update README.md 2023-05-03 17:50:41 +02:00
5531 changed files with 214325 additions and 319575 deletions

View File

@@ -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

View File

@@ -1 +1 @@
6.3.1 6.1.2

View File

@@ -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
View File

@@ -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:

View File

@@ -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

View File

@@ -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}"

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
View File

@@ -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": []
} }
] ]
} }

View File

@@ -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

View File

@@ -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`.

View File

@@ -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.

View File

@@ -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"

View File

@@ -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 -*/"
]
}

View File

@@ -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"
] ]
} }

View File

@@ -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()

View File

@@ -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;

View File

@@ -1,2 +0,0 @@
description: Remove _Float128 type
compatibility: full

View File

@@ -2,4 +2,3 @@ name: codeql/cpp-downgrades
groups: cpp groups: cpp
downgrades: . downgrades: .
library: true library: true
warnOnImplicitThis: true

View File

@@ -4,4 +4,3 @@ groups:
- examples - examples
dependencies: dependencies:
codeql/cpp-all: ${workspace} codeql/cpp-all: ${workspace}
warnOnImplicitThis: true

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -1,3 +0,0 @@
## 0.7.4
No user-facing changes.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -1,3 +0,0 @@
## 0.9.1
No user-facing changes.

View File

@@ -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`.

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 0.9.2 lastReleaseVersion: 0.7.1

View File

@@ -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
) )
} }
} }

View File

@@ -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) }
} }
/** /**

View File

@@ -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()) }
} }
/** /**

View File

@@ -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()
} }
} }

View File

@@ -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()
} }
} }

View File

@@ -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()
} }
} }

View File

@@ -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() }
} }

View File

@@ -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 }

View File

@@ -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())
} }
} }

View File

@@ -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

View File

@@ -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.

View File

@@ -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.

View File

@@ -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()
} }
} }

View File

@@ -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") }

View File

@@ -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

View File

@@ -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 }

View File

@@ -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() }
} }

View File

@@ -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
}
} }

View File

@@ -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())
} }
/** /**

View File

@@ -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))
} }
/** /**

View File

@@ -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() }
} }

View File

@@ -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

View File

@@ -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" }

View File

@@ -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)

View File

@@ -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)
) )

View File

@@ -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. */

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
} }

View File

@@ -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
} }

View File

@@ -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
} }

View File

@@ -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
} }

View File

@@ -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
} }

View File

@@ -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
} }

View File

@@ -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
} }

View 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;
}

View File

@@ -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

View File

@@ -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() }

View File

@@ -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() }

View File

@@ -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() }

View File

@@ -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() }

View File

@@ -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>;

View File

@@ -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() }

View File

@@ -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) }
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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

View File

@@ -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>
}

View File

@@ -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
} }

View File

@@ -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
} }

View File

@@ -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())

View File

@@ -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() }
} }

View File

@@ -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) }
} }
/** /**

View File

@@ -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

View File

@@ -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
} }

View File

@@ -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