mirror of
https://github.com/github/codeql.git
synced 2026-05-30 02:51:24 +02:00
Compare commits
3 Commits
redsun82/s
...
post-relea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cea19c4d1b | ||
|
|
89ac7a5440 | ||
|
|
febeb66f7b |
@@ -1 +0,0 @@
|
||||
DisableFormat: true
|
||||
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -71,6 +71,3 @@ go/extractor/opencsv/CSVReader.java -text
|
||||
# `javascript/ql/experimental/adaptivethreatmodeling/test/update_endpoint_test_files.py`.
|
||||
javascript/ql/experimental/adaptivethreatmodeling/test/endpoint_large_scale/autogenerated/**/*.js linguist-generated=true -merge
|
||||
javascript/ql/experimental/adaptivethreatmodeling/test/endpoint_large_scale/autogenerated/**/*.ts linguist-generated=true -merge
|
||||
|
||||
# Auto-generated modeling for Python
|
||||
python/ql/lib/semmle/python/frameworks/data/internal/subclass-capture/*.yml linguist-generated=true
|
||||
|
||||
3
.github/workflows/check-change-note.yml
vendored
3
.github/workflows/check-change-note.yml
vendored
@@ -1,8 +1,5 @@
|
||||
name: Check change note
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [labeled, unlabeled, opened, synchronize, reopened, ready_for_review]
|
||||
|
||||
3
.github/workflows/check-implicit-this.yml
vendored
3
.github/workflows/check-implicit-this.yml
vendored
@@ -9,9 +9,6 @@ on:
|
||||
- main
|
||||
- "rc/*"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
3
.github/workflows/check-qldoc.yml
vendored
3
.github/workflows/check-qldoc.yml
vendored
@@ -10,9 +10,6 @@ on:
|
||||
- main
|
||||
- "rc/*"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
qldoc:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
3
.github/workflows/check-query-ids.yml
vendored
3
.github/workflows/check-query-ids.yml
vendored
@@ -11,9 +11,6 @@ on:
|
||||
- "rc/*"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Check query IDs
|
||||
|
||||
3
.github/workflows/close-stale.yml
vendored
3
.github/workflows/close-stale.yml
vendored
@@ -5,9 +5,6 @@ on:
|
||||
schedule:
|
||||
- cron: "30 1 * * *"
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
if: github.repository == 'github/codeql'
|
||||
|
||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.101
|
||||
dotnet-version: 8.0.100
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
4
.github/workflows/compile-queries.yml
vendored
4
.github/workflows/compile-queries.yml
vendored
@@ -8,12 +8,8 @@ on:
|
||||
- "codeql-cli-*"
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
compile-queries:
|
||||
if: github.repository_owner == 'github'
|
||||
runs-on: ubuntu-latest-xl
|
||||
|
||||
steps:
|
||||
|
||||
14
.github/workflows/csharp-qltest.yml
vendored
14
.github/workflows/csharp-qltest.yml
vendored
@@ -25,9 +25,6 @@ defaults:
|
||||
run:
|
||||
working-directory: csharp
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
qlupgrade:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -49,7 +46,6 @@ jobs:
|
||||
xargs codeql execute upgrades testdb
|
||||
diff -q testdb/semmlecode.csharp.dbscheme downgrades/initial/semmlecode.csharp.dbscheme
|
||||
qltest:
|
||||
if: github.repository_owner == 'github'
|
||||
runs-on: ubuntu-latest-xl
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -78,13 +74,13 @@ jobs:
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.101
|
||||
dotnet-version: 8.0.100
|
||||
- name: Extractor unit tests
|
||||
run: |
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.1 extractor/Semmle.Util.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.1 extractor/Semmle.Extraction.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.1 autobuilder/Semmle.Autobuild.CSharp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.1 "${{ github.workspace }}/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests"
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.0 extractor/Semmle.Util.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.0 extractor/Semmle.Extraction.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.0 autobuilder/Semmle.Autobuild.CSharp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.0 "${{ github.workspace }}/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests"
|
||||
shell: bash
|
||||
stubgentest:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
4
.github/workflows/csv-coverage-metrics.yml
vendored
4
.github/workflows/csv-coverage-metrics.yml
vendored
@@ -14,10 +14,6 @@ on:
|
||||
- ".github/workflows/csv-coverage-metrics.yml"
|
||||
- ".github/actions/fetch-codeql/action.yml"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
jobs:
|
||||
publish-java:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -19,10 +19,6 @@ on:
|
||||
- main
|
||||
- "rc/*"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
generate:
|
||||
name: Generate framework coverage artifacts
|
||||
|
||||
@@ -6,10 +6,6 @@ on:
|
||||
types:
|
||||
- completed
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Check framework coverage differences and comment
|
||||
|
||||
@@ -3,9 +3,6 @@ name: Build framework coverage timeseries reports
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
4
.github/workflows/csv-coverage-update.yml
vendored
4
.github/workflows/csv-coverage-update.yml
vendored
@@ -5,10 +5,6 @@ on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
update:
|
||||
name: Update framework coverage report
|
||||
|
||||
3
.github/workflows/csv-coverage.yml
vendored
3
.github/workflows/csv-coverage.yml
vendored
@@ -7,9 +7,6 @@ on:
|
||||
description: "github/codeql repo SHA used for looking up the CSV models"
|
||||
required: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
5
.github/workflows/fast-forward.yml
vendored
5
.github/workflows/fast-forward.yml
vendored
@@ -7,14 +7,13 @@ name: Fast-forward tracking branch for selected CodeQL version
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
fast-forward:
|
||||
name: Fast-forward tracking branch for selected CodeQL version
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'github/codeql'
|
||||
permissions:
|
||||
contents: write
|
||||
env:
|
||||
BRANCH_NAME: 'lgtm.com'
|
||||
steps:
|
||||
|
||||
9
.github/workflows/go-tests-other-os.yml
vendored
9
.github/workflows/go-tests-other-os.yml
vendored
@@ -8,11 +8,7 @@ on:
|
||||
- .github/actions/**
|
||||
- codeql-workspace.yml
|
||||
env:
|
||||
GO_VERSION: '~1.22.0'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
GO_VERSION: '~1.21.0'
|
||||
jobs:
|
||||
test-mac:
|
||||
name: Test MacOS
|
||||
@@ -22,7 +18,6 @@ jobs:
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
id: go
|
||||
|
||||
- name: Check out code
|
||||
@@ -51,7 +46,6 @@ jobs:
|
||||
make test cache="${{ steps.query-cache.outputs.cache-dir }}"
|
||||
|
||||
test-win:
|
||||
if: github.repository_owner == 'github'
|
||||
name: Test Windows
|
||||
runs-on: windows-latest-xl
|
||||
steps:
|
||||
@@ -59,7 +53,6 @@ jobs:
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
id: go
|
||||
|
||||
- name: Check out code
|
||||
|
||||
9
.github/workflows/go-tests.yml
vendored
9
.github/workflows/go-tests.yml
vendored
@@ -15,16 +15,10 @@ on:
|
||||
- .github/workflows/go-tests.yml
|
||||
- .github/actions/**
|
||||
- codeql-workspace.yml
|
||||
|
||||
env:
|
||||
GO_VERSION: '~1.22.0'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
GO_VERSION: '~1.21.0'
|
||||
jobs:
|
||||
test-linux:
|
||||
if: github.repository_owner == 'github'
|
||||
name: Test Linux (Ubuntu)
|
||||
runs-on: ubuntu-latest-xl
|
||||
steps:
|
||||
@@ -32,7 +26,6 @@ jobs:
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
id: go
|
||||
|
||||
- name: Check out code
|
||||
|
||||
7
.github/workflows/labeler.yml
vendored
7
.github/workflows/labeler.yml
vendored
@@ -2,12 +2,11 @@ name: "Pull Request Labeler"
|
||||
on:
|
||||
- pull_request_target
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v4
|
||||
|
||||
12
.github/workflows/mad_modelDiff.yml
vendored
12
.github/workflows/mad_modelDiff.yml
vendored
@@ -12,7 +12,6 @@ on:
|
||||
- main
|
||||
paths:
|
||||
- "java/ql/src/utils/modelgenerator/**/*.*"
|
||||
- "misc/scripts/models-as-data/*.*"
|
||||
- ".github/workflows/mad_modelDiff.yml"
|
||||
|
||||
permissions:
|
||||
@@ -62,9 +61,8 @@ jobs:
|
||||
DATABASE=$2
|
||||
cd codeql-$QL_VARIANT
|
||||
SHORTNAME=`basename $DATABASE`
|
||||
python java/ql/src/utils/modelgenerator/GenerateFlowModel.py --with-summaries --with-sinks $DATABASE $SHORTNAME/$QL_VARIANT
|
||||
mkdir -p $MODELS/$SHORTNAME
|
||||
mv java/ql/lib/ext/generated/$SHORTNAME/$QL_VARIANT $MODELS/$SHORTNAME
|
||||
python java/ql/src/utils/modelgenerator/GenerateFlowModel.py --with-summaries --with-sinks $DATABASE ${SHORTNAME}.temp.model.yml
|
||||
mv java/ql/lib/ext/generated/${SHORTNAME}.temp.model.yml $MODELS/${SHORTNAME}Generated_${QL_VARIANT}.model.yml
|
||||
cd ..
|
||||
}
|
||||
|
||||
@@ -87,16 +85,16 @@ jobs:
|
||||
set -x
|
||||
MODELS=`pwd`/tmp-models
|
||||
ls -1 tmp-models/
|
||||
for m in $MODELS/*/main/*.model.yml ; do
|
||||
for m in $MODELS/*_main.model.yml ; do
|
||||
t="${m/main/"pr"}"
|
||||
basename=`basename $m`
|
||||
name="diff_${basename/.model.yml/""}"
|
||||
name="diff_${basename/_main.model.yml/""}"
|
||||
(diff -w -u $m $t | diff2html -i stdin -F $MODELS/$name.html) || true
|
||||
done
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: models
|
||||
path: tmp-models/**/**/*.model.yml
|
||||
path: tmp-models/*.model.yml
|
||||
retention-days: 20
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
|
||||
3
.github/workflows/mad_regenerate-models.yml
vendored
3
.github/workflows/mad_regenerate-models.yml
vendored
@@ -11,9 +11,6 @@ on:
|
||||
- ".github/workflows/mad_regenerate-models.yml"
|
||||
- ".github/actions/fetch-codeql/action.yml"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
regenerate-models:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
2
.github/workflows/qhelp-pr-preview.yml
vendored
2
.github/workflows/qhelp-pr-preview.yml
vendored
@@ -77,7 +77,7 @@ jobs:
|
||||
done < "${RUNNER_TEMP}/paths.txt" >> comment_body.txt
|
||||
exit "${EXIT_CODE}"
|
||||
|
||||
- if: ${{ !cancelled() }}
|
||||
- if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: comment
|
||||
|
||||
9
.github/workflows/ql-for-ql-build.yml
vendored
9
.github/workflows/ql-for-ql-build.yml
vendored
@@ -9,13 +9,8 @@ on:
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
if: github.repository_owner == 'github'
|
||||
runs-on: ubuntu-latest-xl
|
||||
steps:
|
||||
### Build the queries ###
|
||||
@@ -24,7 +19,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@main
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
- uses: ./.github/actions/os-version
|
||||
@@ -70,7 +65,7 @@ jobs:
|
||||
exclude:*/ql/lib/upgrades/
|
||||
exclude:java/ql/integration-tests
|
||||
- name: Upload sarif to code-scanning
|
||||
uses: github/codeql-action/upload-sarif@main
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
with:
|
||||
sarif_file: ql-for-ql.sarif
|
||||
category: ql-for-ql
|
||||
|
||||
@@ -11,10 +11,6 @@ on:
|
||||
- ql/ql/src/ql.dbscheme
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: read
|
||||
|
||||
jobs:
|
||||
measure:
|
||||
env:
|
||||
@@ -29,7 +25,7 @@ jobs:
|
||||
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@main
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
- uses: ./.github/actions/os-version
|
||||
|
||||
7
.github/workflows/ql-for-ql-tests.yml
vendored
7
.github/workflows/ql-for-ql-tests.yml
vendored
@@ -17,9 +17,6 @@ on:
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
qltest:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -27,7 +24,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@main
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
- uses: ./.github/actions/os-version
|
||||
@@ -72,7 +69,7 @@ jobs:
|
||||
echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@main
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
- uses: ./.github/actions/os-version
|
||||
|
||||
3
.github/workflows/query-list.yml
vendored
3
.github/workflows/query-list.yml
vendored
@@ -13,9 +13,6 @@ on:
|
||||
- '.github/actions/fetch-codeql/action.yml'
|
||||
- 'misc/scripts/generate-code-scanning-query-list.py'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
|
||||
4
.github/workflows/ruby-build.yml
vendored
4
.github/workflows/ruby-build.yml
vendored
@@ -32,9 +32,6 @@ defaults:
|
||||
run:
|
||||
working-directory: ruby
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
@@ -114,7 +111,6 @@ jobs:
|
||||
ruby/extractor/target/release/codeql-extractor-ruby.exe
|
||||
retention-days: 1
|
||||
compile-queries:
|
||||
if: github.repository_owner == 'github'
|
||||
runs-on: ubuntu-latest-xl
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
3
.github/workflows/ruby-dataset-measure.yml
vendored
3
.github/workflows/ruby-dataset-measure.yml
vendored
@@ -17,9 +17,6 @@ on:
|
||||
- .github/workflows/ruby-dataset-measure.yml
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
measure:
|
||||
env:
|
||||
|
||||
4
.github/workflows/ruby-qltest.yml
vendored
4
.github/workflows/ruby-qltest.yml
vendored
@@ -29,9 +29,6 @@ defaults:
|
||||
run:
|
||||
working-directory: ruby
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
qlupgrade:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -53,7 +50,6 @@ jobs:
|
||||
xargs codeql execute upgrades testdb
|
||||
diff -q testdb/ruby.dbscheme downgrades/initial/ruby.dbscheme
|
||||
qltest:
|
||||
if: github.repository_owner == 'github'
|
||||
runs-on: ubuntu-latest-xl
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
24
.github/workflows/swift.yml
vendored
24
.github/workflows/swift.yml
vendored
@@ -33,62 +33,46 @@ on:
|
||||
- rc/*
|
||||
- codeql-cli-*
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
# not using a matrix as you cannot depend on a specific job in a matrix, and we want to start linux checks
|
||||
# without waiting for the macOS build
|
||||
build-and-test-macos:
|
||||
if: github.repository_owner == 'github'
|
||||
runs-on: macos-12-xl
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./swift/actions/build-and-test
|
||||
build-and-test-linux:
|
||||
if: github.repository_owner == 'github'
|
||||
runs-on: ubuntu-latest-xl
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./swift/actions/build-and-test
|
||||
qltests-linux:
|
||||
if: github.repository_owner == 'github'
|
||||
needs: build-and-test-linux
|
||||
runs-on: ubuntu-latest-xl
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./swift/actions/run-ql-tests
|
||||
qltests-macos:
|
||||
if: ${{ github.repository_owner == 'github' && github.event_name == 'pull_request' }}
|
||||
if : ${{ github.event_name == 'pull_request' }}
|
||||
needs: build-and-test-macos
|
||||
runs-on: macos-12-xl
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./swift/actions/run-ql-tests
|
||||
integration-tests-linux:
|
||||
if: github.repository_owner == 'github'
|
||||
needs: build-and-test-linux
|
||||
runs-on: ubuntu-latest-xl
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./swift/actions/run-integration-tests
|
||||
integration-tests-macos:
|
||||
if: ${{ github.repository_owner == 'github' && github.event_name == 'pull_request' }}
|
||||
if : ${{ github.event_name == 'pull_request' }}
|
||||
needs: build-and-test-macos
|
||||
runs-on: macos-12-xl
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./swift/actions/run-integration-tests
|
||||
clang-format:
|
||||
if : ${{ github.event_name == 'pull_request' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pre-commit/action@646c83fcd040023954eafda54b4db0192ce70507
|
||||
name: Check that python code is properly formatted
|
||||
with:
|
||||
extra_args: clang-format --all-files
|
||||
codegen:
|
||||
if : ${{ github.event_name == 'pull_request' }}
|
||||
runs-on: ubuntu-latest
|
||||
@@ -98,12 +82,12 @@ jobs:
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version-file: 'swift/.python-version'
|
||||
- uses: pre-commit/action@646c83fcd040023954eafda54b4db0192ce70507
|
||||
- uses: pre-commit/action@v3.0.0
|
||||
name: Check that python code is properly formatted
|
||||
with:
|
||||
extra_args: autopep8 --all-files
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: pre-commit/action@646c83fcd040023954eafda54b4db0192ce70507
|
||||
- uses: pre-commit/action@v3.0.0
|
||||
name: Check that QL generated code was checked in
|
||||
with:
|
||||
extra_args: swift-codegen --all-files
|
||||
|
||||
3
.github/workflows/sync-files.yml
vendored
3
.github/workflows/sync-files.yml
vendored
@@ -10,9 +10,6 @@ on:
|
||||
- main
|
||||
- 'rc/*'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -23,9 +23,6 @@ defaults:
|
||||
run:
|
||||
working-directory: shared/tree-sitter-extractor
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
3
.github/workflows/validate-change-notes.yml
vendored
3
.github/workflows/validate-change-notes.yml
vendored
@@ -15,9 +15,6 @@ on:
|
||||
- ".github/workflows/validate-change-notes.yml"
|
||||
- ".github/actions/fetch-codeql/action.yml"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check-change-note:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -10,9 +10,10 @@ repos:
|
||||
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)|.*\.patch
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v17.0.6
|
||||
rev: v13.0.1
|
||||
hooks:
|
||||
- id: clang-format
|
||||
files: ^swift/.*\.(h|c|cpp)$
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-autopep8
|
||||
rev: v1.6.0
|
||||
|
||||
@@ -454,6 +454,10 @@
|
||||
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll",
|
||||
"swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll"
|
||||
],
|
||||
"SummaryTypeTracker": [
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll",
|
||||
"ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll"
|
||||
],
|
||||
"IncompleteUrlSubstringSanitization": [
|
||||
"javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qll",
|
||||
"ruby/ql/src/queries/security/cwe-020/IncompleteUrlSubstringSanitization.qll"
|
||||
@@ -473,6 +477,10 @@
|
||||
"ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModelsExtensions.qll",
|
||||
"python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModelsExtensions.qll"
|
||||
],
|
||||
"Typo database": [
|
||||
"javascript/ql/src/Expressions/TypoDatabase.qll",
|
||||
"ql/ql/src/codeql_ql/style/TypoDatabase.qll"
|
||||
],
|
||||
"Swift declarations test file": [
|
||||
"swift/ql/test/extractor-tests/declarations/declarations.swift",
|
||||
"swift/ql/test/library-tests/ast/declarations.swift"
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Expr extends @expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Stmt extends @stmt {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
predicate isStmtWithInitializer(Stmt stmt) { exists(int kind | stmts(stmt, kind, _) | kind = 29) }
|
||||
|
||||
from Expr child, int index, int index_new, Element parent
|
||||
where
|
||||
exprparents(child, index, parent) and
|
||||
if isStmtWithInitializer(parent) then index_new = index - 1 else index_new = index
|
||||
select child, index_new, parent
|
||||
@@ -1,9 +0,0 @@
|
||||
class Stmt extends @stmt {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from Stmt f, Stmt i
|
||||
where
|
||||
for_initialization(f, i) and
|
||||
f instanceof @stmt_for
|
||||
select f, i
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,20 +0,0 @@
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Stmt extends @stmt {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
predicate isStmtWithInitializer(Stmt stmt) { exists(int kind | stmts(stmt, kind, _) | kind = 29) }
|
||||
|
||||
from Stmt child, int index, int index_new, Element parent
|
||||
where
|
||||
stmtparents(child, index, parent) and
|
||||
(
|
||||
not isStmtWithInitializer(parent)
|
||||
or
|
||||
index > 0
|
||||
) and
|
||||
if isStmtWithInitializer(parent) then index_new = index - 1 else index_new = index
|
||||
select child, index_new, parent
|
||||
@@ -1,5 +0,0 @@
|
||||
description: Support C++20 range-based for initializers
|
||||
compatibility: partial
|
||||
exprparents.rel: run exprparents.qlo
|
||||
stmtparents.rel: run stmtparents.qlo
|
||||
for_initialization.rel: run for_initialization.qlo
|
||||
@@ -1,11 +0,0 @@
|
||||
class Declaration extends @declaration {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class MangledName extends @mangledname {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from Declaration d, MangledName n
|
||||
where mangled_name(d, n, _)
|
||||
select d, n
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
description: Add completness information to mangled name table
|
||||
compatibility: full
|
||||
mangled_name.rel: run mangled_name.qlo
|
||||
@@ -1,9 +0,0 @@
|
||||
class Function extends @function {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from Function fun, string name, int kind, int kind_new
|
||||
where
|
||||
functions(fun, name, kind) and
|
||||
if kind = 7 or kind = 8 then kind_new = 0 else kind_new = kind
|
||||
select fun, name, kind_new
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
description: Support more function types
|
||||
compatibility: full
|
||||
functions.rel: run functions.qlo
|
||||
@@ -1,6 +1,5 @@
|
||||
description: Support C++17 if and switch initializers
|
||||
compatibility: partial
|
||||
constexpr_if_initialization.rel: delete
|
||||
if_initialization.rel: delete
|
||||
switch_initialization.rel: delete
|
||||
exprparents.rel: run exprparents.qlo
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
class AttributeArg extends @attribute_arg {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Attribute extends @attribute {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_default {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from AttributeArg arg, int kind, int kind_new, Attribute attr, int index, Location location
|
||||
where
|
||||
attribute_args(arg, kind, attr, index, location) and
|
||||
if arg instanceof @attribute_arg_expr then kind_new = 0 else kind_new = kind
|
||||
select arg, kind_new, attr, index, location
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
||||
description: Support expression attribute arguments
|
||||
compatibility: partial
|
||||
attribute_arg_expr.rel: delete
|
||||
attribute_args.rel: run attribute_args.qlo
|
||||
@@ -1,33 +1,9 @@
|
||||
## 0.12.6
|
||||
|
||||
### New Features
|
||||
|
||||
* A `getInitialization` predicate was added to the `RangeBasedForStmt` class that yields the C++20-style initializer of the range-based `for` statement when it exists.
|
||||
|
||||
## 0.12.5
|
||||
|
||||
### New Features
|
||||
|
||||
* Added the `PreprocBlock.qll` library to this repository. This library offers a view of `#if`, `#elif`, `#else` and similar directives as a tree with navigable parent-child relationships.
|
||||
* Added a new `ThrowingFunction` abstract class that can be used to model an external function that may throw an exception.
|
||||
|
||||
## 0.12.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Deleted many deprecated predicates and classes with uppercase `XML`, `SSA`, `SAL`, `SQL`, etc. in their names. Use the PascalCased versions instead.
|
||||
* Deleted the deprecated `StrcatFunction` class, use `semmle.code.cpp.models.implementations.Strcat.qll` instead.
|
||||
|
||||
## 0.12.3
|
||||
## 0.12.2
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The `isUserInput`, `userInputArgument`, and `userInputReturned` predicates from `SecurityOptions` have been deprecated. Use `FlowSource` instead.
|
||||
|
||||
### New Features
|
||||
|
||||
* `UserDefineLiteral` and `DeductionGuide` classes have been added, representing C++11 user defined literals and C++17 deduction guides.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Changed the output of `Node.toString` to better reflect how many indirections a given dataflow node has.
|
||||
@@ -35,14 +11,6 @@
|
||||
* The deprecated `DefaultTaintTracking` library has been removed.
|
||||
* The `Guards` library has been replaced with the API-compatible `IRGuards` implementation, which has better precision in some cases.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Under certain circumstances a function declaration that is not also a definition could be associated with a `Function` that did not have the definition as a `FunctionDeclarationEntry`. This is now fixed when only one definition exists, and a unique `Function` will exist that has both the declaration and the definition as a `FunctionDeclarationEntry`.
|
||||
|
||||
## 0.12.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.12.1
|
||||
|
||||
### New Features
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
## 0.12.2
|
||||
|
||||
No user-facing changes.
|
||||
### Deprecated APIs
|
||||
|
||||
* The `isUserInput`, `userInputArgument`, and `userInputReturned` predicates from `SecurityOptions` have been deprecated. Use `FlowSource` instead.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Changed the output of `Node.toString` to better reflect how many indirections a given dataflow node has.
|
||||
* Added a new predicate `Node.asDefinition` on `DataFlow::Node`s for selecting the dataflow node corresponding to a particular definition.
|
||||
* The deprecated `DefaultTaintTracking` library has been removed.
|
||||
* The `Guards` library has been replaced with the API-compatible `IRGuards` implementation, which has better precision in some cases.
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
## 0.12.3
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The `isUserInput`, `userInputArgument`, and `userInputReturned` predicates from `SecurityOptions` have been deprecated. Use `FlowSource` instead.
|
||||
|
||||
### New Features
|
||||
|
||||
* `UserDefineLiteral` and `DeductionGuide` classes have been added, representing C++11 user defined literals and C++17 deduction guides.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Changed the output of `Node.toString` to better reflect how many indirections a given dataflow node has.
|
||||
* Added a new predicate `Node.asDefinition` on `DataFlow::Node`s for selecting the dataflow node corresponding to a particular definition.
|
||||
* The deprecated `DefaultTaintTracking` library has been removed.
|
||||
* The `Guards` library has been replaced with the API-compatible `IRGuards` implementation, which has better precision in some cases.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Under certain circumstances a function declaration that is not also a definition could be associated with a `Function` that did not have the definition as a `FunctionDeclarationEntry`. This is now fixed when only one definition exists, and a unique `Function` will exist that has both the declaration and the definition as a `FunctionDeclarationEntry`.
|
||||
@@ -1,6 +0,0 @@
|
||||
## 0.12.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Deleted many deprecated predicates and classes with uppercase `XML`, `SSA`, `SAL`, `SQL`, etc. in their names. Use the PascalCased versions instead.
|
||||
* Deleted the deprecated `StrcatFunction` class, use `semmle.code.cpp.models.implementations.Strcat.qll` instead.
|
||||
@@ -1,6 +0,0 @@
|
||||
## 0.12.5
|
||||
|
||||
### New Features
|
||||
|
||||
* Added the `PreprocBlock.qll` library to this repository. This library offers a view of `#if`, `#elif`, `#else` and similar directives as a tree with navigable parent-child relationships.
|
||||
* Added a new `ThrowingFunction` abstract class that can be used to model an external function that may throw an exception.
|
||||
@@ -1,5 +0,0 @@
|
||||
## 0.12.6
|
||||
|
||||
### New Features
|
||||
|
||||
* A `getInitialization` predicate was added to the `RangeBasedForStmt` class that yields the C++20-style initializer of the range-based `for` statement when it exists.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.12.6
|
||||
lastReleaseVersion: 0.12.2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.12.7-dev
|
||||
version: 0.12.3-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -380,6 +380,9 @@ class Class extends UserType {
|
||||
*/
|
||||
predicate isPod() { is_pod_class(underlyingElement(this)) }
|
||||
|
||||
/** DEPRECATED: Alias for isPod */
|
||||
deprecated predicate isPOD() { this.isPod() }
|
||||
|
||||
/**
|
||||
* Holds if this class, struct or union is a standard-layout class
|
||||
* [N4140 9(7)]. Also holds for structs in C programs.
|
||||
|
||||
@@ -7,7 +7,6 @@ import semmle.code.cpp.Location
|
||||
private import semmle.code.cpp.Enclosing
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
private import semmle.code.cpp.internal.ResolveGlobalVariable
|
||||
private import semmle.code.cpp.internal.ResolveFunction
|
||||
|
||||
/**
|
||||
* Get the `Element` that represents this `@element`.
|
||||
@@ -31,14 +30,11 @@ pragma[inline]
|
||||
@element unresolveElement(Element e) {
|
||||
not result instanceof @usertype and
|
||||
not result instanceof @variable and
|
||||
not result instanceof @function and
|
||||
result = e
|
||||
or
|
||||
e = resolveClass(result)
|
||||
or
|
||||
e = resolveGlobalVariable(result)
|
||||
or
|
||||
e = resolveFunction(result)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,6 @@ import semmle.code.cpp.exprs.Call
|
||||
import semmle.code.cpp.metrics.MetricFunction
|
||||
import semmle.code.cpp.Linkage
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
private import semmle.code.cpp.internal.ResolveFunction
|
||||
|
||||
/**
|
||||
* A C/C++ function [N4140 8.3.5]. Both member functions and non-member
|
||||
@@ -26,8 +25,6 @@ private import semmle.code.cpp.internal.ResolveFunction
|
||||
* in more detail in `Declaration.qll`.
|
||||
*/
|
||||
class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
|
||||
Function() { isFunction(underlyingElement(this)) }
|
||||
|
||||
override string getName() { functions(underlyingElement(this), result, _) }
|
||||
|
||||
/**
|
||||
@@ -885,17 +882,3 @@ class BuiltInFunction extends Function {
|
||||
}
|
||||
|
||||
private predicate suppressUnusedThis(Function f) { any() }
|
||||
|
||||
/**
|
||||
* A C++ user-defined literal [N4140 13.5.8].
|
||||
*/
|
||||
class UserDefinedLiteral extends Function {
|
||||
UserDefinedLiteral() { functions(underlyingElement(this), _, 7) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ deduction guide [N4659 17.9].
|
||||
*/
|
||||
class DeductionGuide extends Function {
|
||||
DeductionGuide() { functions(underlyingElement(this), _, 8) }
|
||||
}
|
||||
|
||||
@@ -104,6 +104,9 @@ predicate isPodClass03(Class c) {
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for isPodClass03 */
|
||||
deprecated predicate isPODClass03 = isPodClass03/1;
|
||||
|
||||
/**
|
||||
* Holds if `t` is a POD type, according to the rules specified in
|
||||
* C++03 3.9(10):
|
||||
@@ -123,3 +126,6 @@ predicate isPodType03(Type t) {
|
||||
isPodType03(ut.(SpecifiedType).getUnspecifiedType())
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for isPodType03 */
|
||||
deprecated predicate isPODType03 = isPodType03/1;
|
||||
|
||||
@@ -306,14 +306,7 @@ class ExprNode extends AstNode {
|
||||
|
||||
ExprNode() { expr = ast }
|
||||
|
||||
override AstNode getChildInternal(int childIndex) {
|
||||
result.getAst() = expr.getChild(childIndex)
|
||||
or
|
||||
exists(int destructorIndex |
|
||||
result.getAst() = expr.getImplicitDestructorCall(destructorIndex) and
|
||||
childIndex = destructorIndex + max(int index | exists(expr.getChild(index)) or index = 0) + 1
|
||||
)
|
||||
}
|
||||
override AstNode getChildInternal(int childIndex) { result.getAst() = expr.getChild(childIndex) }
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = super.getProperty(key)
|
||||
@@ -446,11 +439,6 @@ class StmtNode extends AstNode {
|
||||
result.getAst() = child.(Stmt)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(int destructorIndex |
|
||||
result.getAst() = stmt.getImplicitDestructorCall(destructorIndex) and
|
||||
childIndex = destructorIndex + max(int index | exists(stmt.getChild(index)) or index = 0) + 1
|
||||
)
|
||||
}
|
||||
|
||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
@@ -674,10 +662,6 @@ private string getChildAccessorWithoutConversions(Locatable parent, Element chil
|
||||
or
|
||||
not namedStmtChildPredicates(s, child, _) and
|
||||
exists(int n | s.getChild(n) = child and result = "getChild(" + n + ")")
|
||||
or
|
||||
exists(int n |
|
||||
s.getImplicitDestructorCall(n) = child and result = "getImplicitDestructorCall(" + n + ")"
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(Expr expr | expr = parent |
|
||||
@@ -685,11 +669,6 @@ private string getChildAccessorWithoutConversions(Locatable parent, Element chil
|
||||
or
|
||||
not namedExprChildPredicates(expr, child, _) and
|
||||
exists(int n | expr.getChild(n) = child and result = "getChild(" + n + ")")
|
||||
or
|
||||
exists(int n |
|
||||
expr.getImplicitDestructorCall(n) = child and
|
||||
result = "getImplicitDestructorCall(" + n + ")"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -735,9 +714,7 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred)
|
||||
or
|
||||
s.(ForStmt).getStmt() = e and pred = "getStmt()"
|
||||
or
|
||||
s.(RangeBasedForStmt).getInitialization() = e and pred = "getInitialization()"
|
||||
or
|
||||
s.(RangeBasedForStmt).getChild(1) = e and pred = "getChild(1)"
|
||||
s.(RangeBasedForStmt).getChild(0) = e and pred = "getChild(0)"
|
||||
or
|
||||
s.(RangeBasedForStmt).getBeginEndDeclaration() = e and pred = "getBeginEndDeclaration()"
|
||||
or
|
||||
@@ -745,7 +722,7 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred)
|
||||
or
|
||||
s.(RangeBasedForStmt).getUpdate() = e and pred = "getUpdate()"
|
||||
or
|
||||
s.(RangeBasedForStmt).getChild(5) = e and pred = "getChild(5)"
|
||||
s.(RangeBasedForStmt).getChild(4) = e and pred = "getChild(4)"
|
||||
or
|
||||
s.(RangeBasedForStmt).getStmt() = e and pred = "getStmt()"
|
||||
or
|
||||
@@ -837,11 +814,7 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
|
||||
or
|
||||
expr.(OverloadedArrayExpr).getArrayOffset() = ele and pred = "getArrayOffset()"
|
||||
or
|
||||
// OverloadedPointerDereferenceExpr::getExpr/0 also considers qualifiers, which are already handled above for all Call classes.
|
||||
not expr.(OverloadedPointerDereferenceExpr).getQualifier() =
|
||||
expr.(OverloadedPointerDereferenceExpr).getExpr() and
|
||||
expr.(OverloadedPointerDereferenceExpr).getExpr() = ele and
|
||||
pred = "getExpr()"
|
||||
expr.(OverloadedPointerDereferenceExpr).getExpr() = ele and pred = "getExpr()"
|
||||
or
|
||||
expr.(CommaExpr).getLeftOperand() = ele and pred = "getLeftOperand()"
|
||||
or
|
||||
|
||||
@@ -281,11 +281,6 @@ class AttributeArgument extends Element, @attribute_arg {
|
||||
attribute_arg_constant(underlyingElement(this), unresolveElement(result))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of this argument, if its value is an expression.
|
||||
*/
|
||||
Expr getValueExpr() { attribute_arg_expr(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
/**
|
||||
* Gets the attribute to which this is an argument.
|
||||
*/
|
||||
@@ -313,10 +308,7 @@ class AttributeArgument extends Element, @attribute_arg {
|
||||
else
|
||||
if underlyingElement(this) instanceof @attribute_arg_constant_expr
|
||||
then tail = this.getValueConstant().toString()
|
||||
else
|
||||
if underlyingElement(this) instanceof @attribute_arg_expr
|
||||
then tail = this.getValueExpr().toString()
|
||||
else tail = this.getValueText()
|
||||
else tail = this.getValueText()
|
||||
) and
|
||||
result = prefix + tail
|
||||
)
|
||||
|
||||
@@ -234,16 +234,7 @@ class VariableDeclarationEntry extends DeclarationEntry, @var_decl {
|
||||
* int f(int y) { return y; }
|
||||
* ```
|
||||
*/
|
||||
override string getName() {
|
||||
exists(string name |
|
||||
var_decls(underlyingElement(this), _, _, name, _) and
|
||||
(
|
||||
name != "" and result = name
|
||||
or
|
||||
name = "" and result = this.getVariable().(LocalVariable).getName()
|
||||
)
|
||||
)
|
||||
}
|
||||
override string getName() { var_decls(underlyingElement(this), _, _, result, _) and result != "" }
|
||||
|
||||
/**
|
||||
* Gets the type of the variable which is being declared or defined.
|
||||
|
||||
@@ -32,6 +32,9 @@ class XmlLocatable extends @xmllocatable, TXmlLocatable {
|
||||
string toString() { none() } // overridden in subclasses
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlLocatable */
|
||||
deprecated class XMLLocatable = XmlLocatable;
|
||||
|
||||
/**
|
||||
* An `XmlParent` is either an `XmlElement` or an `XmlFile`,
|
||||
* both of which can contain other elements.
|
||||
@@ -92,6 +95,9 @@ class XmlParent extends @xmlparent {
|
||||
string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlParent */
|
||||
deprecated class XMLParent = XmlParent;
|
||||
|
||||
/** An XML file. */
|
||||
class XmlFile extends XmlParent, File {
|
||||
XmlFile() { xmlEncoding(this, _) }
|
||||
@@ -113,8 +119,14 @@ class XmlFile extends XmlParent, File {
|
||||
|
||||
/** Gets a DTD associated with this XML file. */
|
||||
XmlDtd getADtd() { xmlDTDs(result, _, _, _, this) }
|
||||
|
||||
/** DEPRECATED: Alias for getADtd */
|
||||
deprecated XmlDtd getADTD() { result = this.getADtd() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlFile */
|
||||
deprecated class XMLFile = XmlFile;
|
||||
|
||||
/**
|
||||
* An XML document type definition (DTD).
|
||||
*
|
||||
@@ -151,6 +163,9 @@ class XmlDtd extends XmlLocatable, @xmldtd {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlDtd */
|
||||
deprecated class XMLDTD = XmlDtd;
|
||||
|
||||
/**
|
||||
* An XML element in an XML file.
|
||||
*
|
||||
@@ -206,6 +221,9 @@ class XmlElement extends @xmlelement, XmlParent, XmlLocatable {
|
||||
override string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlElement */
|
||||
deprecated class XMLElement = XmlElement;
|
||||
|
||||
/**
|
||||
* An attribute that occurs inside an XML element.
|
||||
*
|
||||
@@ -236,6 +254,9 @@ class XmlAttribute extends @xmlattribute, XmlLocatable {
|
||||
override string toString() { result = this.getName() + "=" + this.getValue() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlAttribute */
|
||||
deprecated class XMLAttribute = XmlAttribute;
|
||||
|
||||
/**
|
||||
* A namespace used in an XML file.
|
||||
*
|
||||
@@ -252,6 +273,9 @@ class XmlNamespace extends XmlLocatable, @xmlnamespace {
|
||||
/** Gets the URI of this namespace. */
|
||||
string getUri() { xmlNs(this, _, result, _) }
|
||||
|
||||
/** DEPRECATED: Alias for getUri */
|
||||
deprecated string getURI() { result = this.getUri() }
|
||||
|
||||
/** Holds if this namespace has no prefix. */
|
||||
predicate isDefault() { this.getPrefix() = "" }
|
||||
|
||||
@@ -262,6 +286,9 @@ class XmlNamespace extends XmlLocatable, @xmlnamespace {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlNamespace */
|
||||
deprecated class XMLNamespace = XmlNamespace;
|
||||
|
||||
/**
|
||||
* A comment in an XML file.
|
||||
*
|
||||
@@ -282,6 +309,9 @@ class XmlComment extends @xmlcomment, XmlLocatable {
|
||||
override string toString() { result = this.getText() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlComment */
|
||||
deprecated class XMLComment = XmlComment;
|
||||
|
||||
/**
|
||||
* A sequence of characters that occurs between opening and
|
||||
* closing tags of an XML element, excluding other elements.
|
||||
@@ -305,3 +335,6 @@ class XmlCharacters extends @xmlcharacters, XmlLocatable {
|
||||
/** Gets a printable representation of this XML character sequence. */
|
||||
override string toString() { result = this.getCharacters() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlCharacters */
|
||||
deprecated class XMLCharacters = XmlCharacters;
|
||||
|
||||
@@ -5,6 +5,9 @@ class NullMacro extends Macro {
|
||||
NullMacro() { this.getHead() = "NULL" }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for NullMacro */
|
||||
deprecated class NULLMacro = NullMacro;
|
||||
|
||||
/** A use of the NULL macro. */
|
||||
class NULL extends Literal {
|
||||
NULL() { exists(NullMacro nm | this = nm.getAnInvocation().getAnExpandedElement()) }
|
||||
|
||||
22
cpp/ql/lib/semmle/code/cpp/commons/Strcat.qll
Normal file
22
cpp/ql/lib/semmle/code/cpp/commons/Strcat.qll
Normal file
@@ -0,0 +1,22 @@
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `semmle.code.cpp.models.implementations.Strcat.qll` instead.
|
||||
*
|
||||
* A function that concatenates the string from its second argument
|
||||
* to the string from its first argument, for example `strcat`.
|
||||
*/
|
||||
deprecated class StrcatFunction extends Function {
|
||||
StrcatFunction() {
|
||||
this.getName() =
|
||||
[
|
||||
"strcat", // strcat(dst, src)
|
||||
"strncat", // strncat(dst, src, max_amount)
|
||||
"wcscat", // wcscat(dst, src)
|
||||
"_mbscat", // _mbscat(dst, src)
|
||||
"wcsncat", // wcsncat(dst, src, max_amount)
|
||||
"_mbsncat", // _mbsncat(dst, src, max_amount)
|
||||
"_mbsncat_l" // _mbsncat_l(dst, src, max_amount, locale)
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/**
|
||||
* A library for detecting general string concatenations.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.models.implementations.Strcat
|
||||
import semmle.code.cpp.models.interfaces.FormattingFunction
|
||||
private import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
/**
|
||||
* A call that performs a string concatenation. A string can be either a C
|
||||
* string (i.e., a value of type `char*`), or a C++ string (i.e., a value of
|
||||
* type `std::string`).
|
||||
*/
|
||||
class StringConcatenation extends Call {
|
||||
StringConcatenation() {
|
||||
// sprintf-like functions, i.e., concat through formatting
|
||||
this instanceof FormattingFunctionCall
|
||||
or
|
||||
this.getTarget() instanceof StrcatFunction
|
||||
or
|
||||
this.getTarget() instanceof StrlcatFunction
|
||||
or
|
||||
// operator+ and ostream (<<) concat
|
||||
exists(Call call, Operator op |
|
||||
call.getTarget() = op and
|
||||
op.hasQualifiedName(["std", "bsl"], ["operator+", "operator<<"]) and
|
||||
op.getType()
|
||||
.stripType()
|
||||
.(UserType)
|
||||
.hasQualifiedName(["std", "bsl"], ["basic_string", "basic_ostream"]) and
|
||||
this = call
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an operand of this concatenation (one of the string operands being
|
||||
* concatenated).
|
||||
* Will not return out param for sprintf-like functions, but will consider the format string
|
||||
* to be part of the operands.
|
||||
*/
|
||||
Expr getAnOperand() {
|
||||
// The result is an argument of 'this' (a call)
|
||||
result = this.getAnArgument() and
|
||||
// addresses odd behavior with overloaded operators
|
||||
// i.e., "call to operator+" appearing as an operand
|
||||
// occurs in cases like `string s = s1 + s2 + s3`, which is represented as
|
||||
// `string s = (s1.operator+(s2)).operator+(s3);`
|
||||
// By limiting to non-calls we get the leaf operands (the variables or raw strings)
|
||||
// also, by not enumerating allowed types (variables and strings) we avoid issues
|
||||
// with missed corner cases or extensions/changes to CodeQL in the future which might
|
||||
// invalidate that approach.
|
||||
not result instanceof Call and
|
||||
// Limit the result type to string
|
||||
(
|
||||
result.getUnderlyingType().stripType().getName() = "char"
|
||||
or
|
||||
result
|
||||
.getType()
|
||||
.getUnspecifiedType()
|
||||
.(UserType)
|
||||
.hasQualifiedName(["std", "bsl"], "basic_string")
|
||||
) and
|
||||
// when 'this' is a `FormattingFunctionCall` the result must be the format string argument
|
||||
// or one of the formatting arguments
|
||||
(
|
||||
this instanceof FormattingFunctionCall
|
||||
implies
|
||||
(
|
||||
result = this.(FormattingFunctionCall).getFormat()
|
||||
or
|
||||
exists(int n |
|
||||
result = this.getArgument(n) and
|
||||
n >= this.(FormattingFunctionCall).getTarget().getFirstFormatArgumentIndex()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data flow node representing the concatenation result.
|
||||
*/
|
||||
DataFlow::Node getResultNode() {
|
||||
if this.getTarget() instanceof StrcatFunction
|
||||
then
|
||||
result.asDefiningArgument() =
|
||||
this.getArgument(this.getTarget().(StrcatFunction).getParamDest())
|
||||
or
|
||||
// Hardcoding it is also the return
|
||||
result.asExpr() = this.(Call)
|
||||
else
|
||||
if this.getTarget() instanceof StrlcatFunction
|
||||
then (
|
||||
result.asDefiningArgument() =
|
||||
this.getArgument(this.getTarget().(StrlcatFunction).getParamDest())
|
||||
) else
|
||||
if this instanceof FormattingFunctionCall
|
||||
then result.asDefiningArgument() = this.(FormattingFunctionCall).getOutputArgument(_)
|
||||
else result.asExpr() = this.(Call)
|
||||
}
|
||||
}
|
||||
@@ -203,42 +203,30 @@ private class GuardConditionFromIR extends GuardCondition {
|
||||
* `&&` and `||`. See the detailed explanation on predicate `controls`.
|
||||
*/
|
||||
private predicate controlsBlock(BasicBlock controlled, boolean testIsTrue) {
|
||||
exists(IRBlock irb |
|
||||
exists(IRBlock irb, Instruction instr |
|
||||
ir.controls(irb, testIsTrue) and
|
||||
nonExcludedIRAndBasicBlock(irb, controlled) and
|
||||
not isUnreachedBlock(irb)
|
||||
instr = irb.getAnInstruction() and
|
||||
instr.getAst().(ControlFlowNode).getBasicBlock() = controlled and
|
||||
not isUnreachedBlock(irb) and
|
||||
not this.excludeAsControlledInstruction(instr)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate excludeAsControlledInstruction(Instruction instr) {
|
||||
// Exclude the temporaries generated by a ternary expression.
|
||||
exists(TranslatedConditionalExpr tce |
|
||||
instr = tce.getInstruction(ConditionValueFalseStoreTag())
|
||||
private predicate excludeAsControlledInstruction(Instruction instr) {
|
||||
// Exclude the temporaries generated by a ternary expression.
|
||||
exists(TranslatedConditionalExpr tce |
|
||||
instr = tce.getInstruction(ConditionValueFalseStoreTag())
|
||||
or
|
||||
instr = tce.getInstruction(ConditionValueTrueStoreTag())
|
||||
or
|
||||
instr = tce.getInstruction(ConditionValueTrueTempAddressTag())
|
||||
or
|
||||
instr = tce.getInstruction(ConditionValueFalseTempAddressTag())
|
||||
)
|
||||
or
|
||||
instr = tce.getInstruction(ConditionValueTrueStoreTag())
|
||||
or
|
||||
instr = tce.getInstruction(ConditionValueTrueTempAddressTag())
|
||||
or
|
||||
instr = tce.getInstruction(ConditionValueFalseTempAddressTag())
|
||||
)
|
||||
or
|
||||
// Exclude unreached instructions, as their AST is the whole function and not a block.
|
||||
instr instanceof UnreachedInstruction
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `irb` is the `IRBlock` corresponding to the AST basic block
|
||||
* `controlled`, and `irb` does not contain any instruction(s) that should make
|
||||
* the `irb` be ignored.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate nonExcludedIRAndBasicBlock(IRBlock irb, BasicBlock controlled) {
|
||||
exists(Instruction instr |
|
||||
instr = irb.getAnInstruction() and
|
||||
instr.getAst().(ControlFlowNode).getBasicBlock() = controlled and
|
||||
not excludeAsControlledInstruction(instr)
|
||||
)
|
||||
// Exclude unreached instructions, as their AST is the whole function and not a block.
|
||||
instr instanceof UnreachedInstruction
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -637,10 +637,8 @@ private predicate straightLineSparse(Node scope, int i, Node ni, Spec spec) {
|
||||
any(RangeBasedForStmt for |
|
||||
i = -1 and ni = for and spec.isAt()
|
||||
or
|
||||
i = 0 and ni = for.getInitialization() and spec.isAround()
|
||||
or
|
||||
exists(DeclStmt s | s.getADeclaration() = for.getRangeVariable() |
|
||||
i = 1 and ni = s and spec.isAround()
|
||||
i = 0 and ni = s and spec.isAround()
|
||||
)
|
||||
or
|
||||
exists(DeclStmt s |
|
||||
@@ -651,22 +649,22 @@ private predicate straightLineSparse(Node scope, int i, Node ni, Spec spec) {
|
||||
// DeclStmt in that case.
|
||||
exists(s.getADeclaration())
|
||||
|
|
||||
i = 2 and ni = s and spec.isAround()
|
||||
i = 1 and ni = s and spec.isAround()
|
||||
)
|
||||
or
|
||||
i = 3 and ni = for.getCondition() and spec.isBefore()
|
||||
i = 2 and ni = for.getCondition() and spec.isBefore()
|
||||
or
|
||||
i = 4 and /* BARRIER */ ni = for and spec.isBarrier()
|
||||
i = 3 and /* BARRIER */ ni = for and spec.isBarrier()
|
||||
or
|
||||
exists(DeclStmt declStmt | declStmt.getADeclaration() = for.getVariable() |
|
||||
i = 5 and ni = declStmt and spec.isAfter()
|
||||
i = 4 and ni = declStmt and spec.isAfter()
|
||||
)
|
||||
or
|
||||
i = 6 and ni = for.getStmt() and spec.isAround()
|
||||
i = 5 and ni = for.getStmt() and spec.isAround()
|
||||
or
|
||||
i = 7 and ni = for.getUpdate() and spec.isAround()
|
||||
i = 6 and ni = for.getUpdate() and spec.isAround()
|
||||
or
|
||||
i = 8 and ni = for.getCondition() and spec.isBefore()
|
||||
i = 7 and ni = for.getCondition() and spec.isBefore()
|
||||
)
|
||||
or
|
||||
scope =
|
||||
|
||||
@@ -110,8 +110,8 @@ private predicate loopConditionAlwaysUponEntry(ControlFlowNode loop, Expr condit
|
||||
* should be in this relation.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate isFunction(@element el) {
|
||||
el instanceof @function
|
||||
private predicate isFunction(Element el) {
|
||||
el instanceof Function
|
||||
or
|
||||
el.(Expr).getParent() = el
|
||||
}
|
||||
@@ -122,7 +122,7 @@ private predicate isFunction(@element el) {
|
||||
*/
|
||||
pragma[noopt]
|
||||
private predicate callHasNoTarget(@funbindexpr fc) {
|
||||
exists(@function f |
|
||||
exists(Function f |
|
||||
funbind(fc, f) and
|
||||
not isFunction(f)
|
||||
)
|
||||
|
||||
@@ -54,6 +54,18 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam
|
||||
not f.isStatic()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the set of viable implementations that can be called by `call`
|
||||
* might be improved by knowing the call context.
|
||||
*/
|
||||
predicate mayBenefitFromCallContext(DataFlowCall call, Function f) { none() }
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
Function viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { none() }
|
||||
|
||||
/** A parameter position represented by an integer. */
|
||||
class ParameterPosition extends int {
|
||||
ParameterPosition() { any(ParameterNode p).isParameterOf(_, this) }
|
||||
|
||||
@@ -244,15 +244,9 @@ class ConditionDeclExpr extends Expr, @condition_decl {
|
||||
|
||||
/**
|
||||
* Gets the compiler-generated variable access that conceptually occurs after
|
||||
* the initialization of the declared variable, if any.
|
||||
* the initialization of the declared variable.
|
||||
*/
|
||||
VariableAccess getVariableAccess() { result = this.getExpr() }
|
||||
|
||||
/**
|
||||
* Gets the expression that is evaluated after the initialization of the declared
|
||||
* variable.
|
||||
*/
|
||||
Expr getExpr() { result = this.getChild(0) }
|
||||
VariableAccess getVariableAccess() { result = this.getChild(0) }
|
||||
|
||||
/**
|
||||
* Gets the expression that initializes the declared variable. This predicate
|
||||
|
||||
@@ -58,19 +58,6 @@ class Expr extends StmtParent, @expr {
|
||||
/** Gets the parent of this expression, if any. */
|
||||
Element getParent() { exprparents(underlyingElement(this), _, unresolveElement(result)) }
|
||||
|
||||
/**
|
||||
* Gets the `n`th compiler-generated destructor call that is performed after this expression, in
|
||||
* order of destruction.
|
||||
*/
|
||||
DestructorCall getImplicitDestructorCall(int n) {
|
||||
synthetic_destructor_call(this, max(int i | synthetic_destructor_call(this, i, _)) - n, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a compiler-generated destructor call that is performed after this expression.
|
||||
*/
|
||||
DestructorCall getAnImplicitDestructorCall() { synthetic_destructor_call(this, _, result) }
|
||||
|
||||
/** Gets the location of this expression. */
|
||||
override Location getLocation() {
|
||||
result = this.getExprLocationOverride()
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
/**
|
||||
* This library offers a view of preprocessor branches (`#if`, `#ifdef`,
|
||||
* `#ifndef`, `#elif` and `#else`) as blocks of code between the opening and
|
||||
* closing directives, with navigable parent-child relationships to other
|
||||
* blocks. The main class is `PreprocessorBlock`.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* Gets the line of the `ix`th `PreprocessorBranchDirective` in file `f`.
|
||||
*/
|
||||
private int getPreprocLineFromIndex(File f, int ix) {
|
||||
result =
|
||||
rank[ix](PreprocessorBranchDirective g | g.getFile() = f | g.getLocation().getStartLine())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `ix`th `PreprocessorBranchDirective` in file `f`.
|
||||
*/
|
||||
private PreprocessorBranchDirective getPreprocFromIndex(File f, int ix) {
|
||||
result.getFile() = f and
|
||||
result.getLocation().getStartLine() = getPreprocLineFromIndex(f, ix)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of a `PreprocessorBranchDirective` in its `file`.
|
||||
*/
|
||||
private int getPreprocIndex(PreprocessorBranchDirective directive) {
|
||||
directive = getPreprocFromIndex(directive.getFile(), result)
|
||||
}
|
||||
|
||||
/**
|
||||
* A chunk of code from one preprocessor branch (`#if`, `#ifdef`,
|
||||
* `#ifndef`, `#elif` or `#else`) to the directive that closes it
|
||||
* (`#elif`, `#else` or `#endif`). The `getParent()` method
|
||||
* allows these blocks to be navigated as a tree, with the root
|
||||
* being the entire file.
|
||||
*/
|
||||
class PreprocessorBlock extends @element {
|
||||
PreprocessorBlock() {
|
||||
mkElement(this) instanceof File or
|
||||
mkElement(this) instanceof PreprocessorBranch or
|
||||
mkElement(this) instanceof PreprocessorElse
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
) {
|
||||
filepath = this.getFile().toString() and
|
||||
startline = this.getStartLine() and
|
||||
startcolumn = 0 and
|
||||
endline = this.getEndLine() and
|
||||
endcolumn = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element.
|
||||
*/
|
||||
string toString() { result = mkElement(this).toString() }
|
||||
|
||||
/**
|
||||
* Gets the file this `PreprocessorBlock` is located in.
|
||||
*/
|
||||
File getFile() { result = mkElement(this).getFile() }
|
||||
|
||||
/**
|
||||
* Gets the start line number of this `PreprocessorBlock`.
|
||||
*/
|
||||
int getStartLine() { result = mkElement(this).getLocation().getStartLine() }
|
||||
|
||||
/**
|
||||
* Gets the end line number of this `PreprocessorBlock`.
|
||||
*/
|
||||
int getEndLine() {
|
||||
result = mkElement(this).(File).getMetrics().getNumberOfLines() or
|
||||
result =
|
||||
mkElement(this).(PreprocessorBranchDirective).getNext().getLocation().getStartLine() - 1
|
||||
}
|
||||
|
||||
private PreprocessorBlock getParentInternal() {
|
||||
// find the `#ifdef` corresponding to this block and the
|
||||
// PreprocessorBranchDirective `prev` that came directly
|
||||
// before it in the source.
|
||||
exists(int ix, PreprocessorBranchDirective prev |
|
||||
ix = getPreprocIndex(mkElement(this).(PreprocessorBranchDirective).getIf()) and
|
||||
prev = getPreprocFromIndex(this.getFile(), ix - 1)
|
||||
|
|
||||
if prev instanceof PreprocessorEndif
|
||||
then
|
||||
// if we follow an #endif, we have the same parent
|
||||
// as its corresponding `#if` has.
|
||||
result = unresolveElement(prev.getIf()).(PreprocessorBlock).getParentInternal()
|
||||
else
|
||||
// otherwise we directly follow an #if / #ifdef / #ifndef /
|
||||
// #elif / #else that must be a level above and our parent
|
||||
// block.
|
||||
mkElement(result) = prev
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `PreprocessorBlock` that's directly surrounding this one.
|
||||
* Has no result if this is a file.
|
||||
*/
|
||||
PreprocessorBlock getParent() {
|
||||
not mkElement(this) instanceof File and
|
||||
(
|
||||
if exists(this.getParentInternal())
|
||||
then
|
||||
// found parent directive
|
||||
result = this.getParentInternal()
|
||||
else
|
||||
// top level directive
|
||||
mkElement(result) = this.getFile()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a `PreprocessorBlock` that's directly inside this one.
|
||||
*/
|
||||
PreprocessorBlock getAChild() { result.getParent() = this }
|
||||
|
||||
private Include getAnEnclosedInclude() {
|
||||
result.getFile() = this.getFile() and
|
||||
result.getLocation().getStartLine() > this.getStartLine() and
|
||||
result.getLocation().getStartLine() <= this.getEndLine()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an include directive that is directly in this
|
||||
* `PreprocessorBlock`.
|
||||
*/
|
||||
Include getAnInclude() {
|
||||
result = this.getAnEnclosedInclude() and
|
||||
not result = this.getAChild().getAnEnclosedInclude()
|
||||
}
|
||||
|
||||
private Macro getAnEnclosedMacro() {
|
||||
result.getFile() = this.getFile() and
|
||||
result.getLocation().getStartLine() > this.getStartLine() and
|
||||
result.getLocation().getStartLine() <= this.getEndLine()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a macro definition that is directly in this
|
||||
* `PreprocessorBlock`.
|
||||
*/
|
||||
Macro getAMacro() {
|
||||
result = this.getAnEnclosedMacro() and
|
||||
not result = this.getAChild().getAnEnclosedMacro()
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import semmle.code.cpp.Type
|
||||
/** For upgraded databases without mangled name info. */
|
||||
pragma[noinline]
|
||||
private string getTopLevelClassName(@usertype c) {
|
||||
not mangled_name(_, _, _) and
|
||||
not mangled_name(_, _) and
|
||||
isClass(c) and
|
||||
usertypes(c, result, _) and
|
||||
not namespacembrs(_, c) and // not in a namespace
|
||||
@@ -17,7 +17,7 @@ private string getTopLevelClassName(@usertype c) {
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate existsCompleteWithName(string name, @usertype d) {
|
||||
not mangled_name(_, _, _) and
|
||||
not mangled_name(_, _) and
|
||||
is_complete(d) and
|
||||
name = getTopLevelClassName(d) and
|
||||
onlyOneCompleteClassExistsWithName(name)
|
||||
@@ -26,7 +26,7 @@ private predicate existsCompleteWithName(string name, @usertype d) {
|
||||
/** For upgraded databases without mangled name info. */
|
||||
pragma[noinline]
|
||||
private predicate onlyOneCompleteClassExistsWithName(string name) {
|
||||
not mangled_name(_, _, _) and
|
||||
not mangled_name(_, _) and
|
||||
strictcount(@usertype c | is_complete(c) and getTopLevelClassName(c) = name) = 1
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ private predicate onlyOneCompleteClassExistsWithName(string name) {
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate existsIncompleteWithName(string name, @usertype c) {
|
||||
not mangled_name(_, _, _) and
|
||||
not mangled_name(_, _) and
|
||||
not is_complete(c) and
|
||||
name = getTopLevelClassName(c)
|
||||
}
|
||||
@@ -47,7 +47,7 @@ private predicate existsIncompleteWithName(string name, @usertype c) {
|
||||
* with the same name.
|
||||
*/
|
||||
private predicate oldHasCompleteTwin(@usertype c, @usertype d) {
|
||||
not mangled_name(_, _, _) and
|
||||
not mangled_name(_, _) and
|
||||
exists(string name |
|
||||
existsIncompleteWithName(name, c) and
|
||||
existsCompleteWithName(name, d)
|
||||
@@ -57,7 +57,7 @@ private predicate oldHasCompleteTwin(@usertype c, @usertype d) {
|
||||
pragma[noinline]
|
||||
private @mangledname getClassMangledName(@usertype c) {
|
||||
isClass(c) and
|
||||
mangled_name(c, result, _)
|
||||
mangled_name(c, result)
|
||||
}
|
||||
|
||||
/** Holds if `d` is a unique complete class named `name`. */
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
private predicate hasDefinition(@function f) {
|
||||
exists(@fun_decl fd | fun_decls(fd, f, _, _, _) | fun_def(fd))
|
||||
}
|
||||
|
||||
private predicate onlyOneCompleteFunctionExistsWithMangledName(@mangledname name) {
|
||||
strictcount(@function f | hasDefinition(f) and mangled_name(f, name, true)) = 1
|
||||
}
|
||||
|
||||
/** Holds if `f` is a unique function with a definition named `name`. */
|
||||
private predicate isFunctionWithMangledNameAndWithDefinition(@mangledname name, @function f) {
|
||||
hasDefinition(f) and
|
||||
mangled_name(f, name, true) and
|
||||
onlyOneCompleteFunctionExistsWithMangledName(name)
|
||||
}
|
||||
|
||||
/** Holds if `f` is a function without a definition named `name`. */
|
||||
private predicate isFunctionWithMangledNameAndWithoutDefinition(@mangledname name, @function f) {
|
||||
not hasDefinition(f) and
|
||||
mangled_name(f, name, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `incomplete` is a function without a definition, and there exists
|
||||
* a unique function `complete` with the same name that does have a definition.
|
||||
*/
|
||||
private predicate hasTwinWithDefinition(@function incomplete, @function complete) {
|
||||
not function_instantiation(incomplete, complete) and
|
||||
(
|
||||
not compgenerated(incomplete) or
|
||||
not compgenerated(complete)
|
||||
) and
|
||||
exists(@mangledname name |
|
||||
isFunctionWithMangledNameAndWithoutDefinition(name, incomplete) and
|
||||
isFunctionWithMangledNameAndWithDefinition(name, complete)
|
||||
)
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* If `f` is a function without a definition, and there exists a unique
|
||||
* function with the same name that does have a definition, then the
|
||||
* result is that unique function. Otherwise, the result is `f`.
|
||||
*/
|
||||
cached
|
||||
@function resolveFunction(@function f) {
|
||||
hasTwinWithDefinition(f, result)
|
||||
or
|
||||
not hasTwinWithDefinition(f, _) and
|
||||
result = f
|
||||
}
|
||||
|
||||
cached
|
||||
predicate isFunction(@function f) { f = resolveFunction(_) }
|
||||
}
|
||||
@@ -3,20 +3,20 @@ private predicate hasDefinition(@globalvariable g) {
|
||||
}
|
||||
|
||||
private predicate onlyOneCompleteGlobalVariableExistsWithMangledName(@mangledname name) {
|
||||
strictcount(@globalvariable g | hasDefinition(g) and mangled_name(g, name, _)) = 1
|
||||
strictcount(@globalvariable g | hasDefinition(g) and mangled_name(g, name)) = 1
|
||||
}
|
||||
|
||||
/** Holds if `g` is a unique global variable with a definition named `name`. */
|
||||
private predicate isGlobalWithMangledNameAndWithDefinition(@mangledname name, @globalvariable g) {
|
||||
hasDefinition(g) and
|
||||
mangled_name(g, name, _) and
|
||||
mangled_name(g, name) and
|
||||
onlyOneCompleteGlobalVariableExistsWithMangledName(name)
|
||||
}
|
||||
|
||||
/** Holds if `g` is a global variable without a definition named `name`. */
|
||||
private predicate isGlobalWithMangledNameAndWithoutDefinition(@mangledname name, @globalvariable g) {
|
||||
not hasDefinition(g) and
|
||||
mangled_name(g, name, _)
|
||||
mangled_name(g, name)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -24,8 +24,8 @@ private predicate isGlobalWithMangledNameAndWithoutDefinition(@mangledname name,
|
||||
* a unique global variable `complete` with the same name that does have a definition.
|
||||
*/
|
||||
private predicate hasTwinWithDefinition(@globalvariable incomplete, @globalvariable complete) {
|
||||
not variable_instantiation(incomplete, complete) and
|
||||
exists(@mangledname name |
|
||||
not variable_instantiation(incomplete, complete) and
|
||||
isGlobalWithMangledNameAndWithoutDefinition(name, incomplete) and
|
||||
isGlobalWithMangledNameAndWithDefinition(name, complete)
|
||||
)
|
||||
|
||||
@@ -249,7 +249,9 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam
|
||||
* Holds if the set of viable implementations that can be called by `call`
|
||||
* might be improved by knowing the call context.
|
||||
*/
|
||||
predicate mayBenefitFromCallContext(DataFlowCall call) { mayBenefitFromCallContext(call, _, _) }
|
||||
predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable f) {
|
||||
mayBenefitFromCallContext(call, f, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `call` is a call through a function pointer, and the pointer
|
||||
|
||||
@@ -22,8 +22,4 @@ module CppDataFlow implements InputSig {
|
||||
predicate getAdditionalFlowIntoCallNodeTerm = Private::getAdditionalFlowIntoCallNodeTerm/2;
|
||||
|
||||
predicate validParameterAliasStep = Private::validParameterAliasStep/2;
|
||||
|
||||
predicate mayBenefitFromCallContext = Private::mayBenefitFromCallContext/1;
|
||||
|
||||
predicate viableImplInCallContext = Private::viableImplInCallContext/2;
|
||||
}
|
||||
|
||||
@@ -7,9 +7,6 @@ private import SsaInternals as Ssa
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
private import codeql.util.Unit
|
||||
private import Node0ToString
|
||||
private import ModelUtil
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as IO
|
||||
private import semmle.code.cpp.models.interfaces.DataFlow as DF
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
@@ -62,41 +59,6 @@ private module Cached {
|
||||
import Cached
|
||||
private import Nodes0
|
||||
|
||||
/**
|
||||
* A module for calculating the number of stars (i.e., `*`s) needed for various
|
||||
* dataflow node `toString` predicates.
|
||||
*/
|
||||
module NodeStars {
|
||||
private int getNumberOfIndirections(Node n) {
|
||||
result = n.(RawIndirectOperand).getIndirectionIndex()
|
||||
or
|
||||
result = n.(RawIndirectInstruction).getIndirectionIndex()
|
||||
or
|
||||
result = n.(VariableNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
|
||||
or
|
||||
result = n.(FinalParameterNode).getIndirectionIndex()
|
||||
}
|
||||
|
||||
private int maxNumberOfIndirections() { result = max(getNumberOfIndirections(_)) }
|
||||
|
||||
private string repeatStars(int n) {
|
||||
n = 0 and result = ""
|
||||
or
|
||||
n = [1 .. maxNumberOfIndirections()] and
|
||||
result = "*" + repeatStars(n - 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
|
||||
* output for `n`.
|
||||
*/
|
||||
string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
|
||||
}
|
||||
|
||||
import NodeStars
|
||||
|
||||
class Node0Impl extends TIRDataFlowNode0 {
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
@@ -1181,19 +1143,6 @@ private int countNumberOfBranchesUsingParameter(SwitchInstruction switch, Parame
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate isInputOutput(
|
||||
DF::DataFlowFunction target, Node node1, Node node2, IO::FunctionInput input,
|
||||
IO::FunctionOutput output
|
||||
) {
|
||||
exists(CallInstruction call |
|
||||
node1 = callInput(call, input) and
|
||||
node2 = callOutput(call, output) and
|
||||
call.getStaticCallTarget() = target and
|
||||
target.hasDataFlow(input, output)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the data-flow step from `node1` to `node2` can be used to
|
||||
* determine where side-effects may return from a callable.
|
||||
@@ -1205,11 +1154,6 @@ private predicate isInputOutput(
|
||||
* int x = *p;
|
||||
* ```
|
||||
* does not preserve the identity of `*p`.
|
||||
*
|
||||
* Similarly, a function that copies the contents of a string into a new location
|
||||
* does not also preserve the identity. For example, `strdup(p)` does not
|
||||
* preserve the identity of `*p` (since it allocates new storage and copies
|
||||
* the string into the new storage).
|
||||
*/
|
||||
bindingset[node1, node2]
|
||||
pragma[inline_late]
|
||||
@@ -1246,16 +1190,7 @@ predicate validParameterAliasStep(Node node1, Node node2) {
|
||||
not exists(Operand operand |
|
||||
node1.asOperand() = operand and
|
||||
node2.asInstruction().(StoreInstruction).getSourceValueOperand() = operand
|
||||
) and
|
||||
(
|
||||
// Either this is not a modeled flow.
|
||||
not isInputOutput(_, node1, node2, _, _)
|
||||
or
|
||||
exists(DF::DataFlowFunction target, IO::FunctionInput input, IO::FunctionOutput output |
|
||||
// Or it is a modeled flow and there's `*input` to `*output` flow
|
||||
isInputOutput(target, node1, node2, input.getIndirectionInput(), output.getIndirectionOutput()) and
|
||||
// and in that case there should also be `input` to `output` flow
|
||||
target.hasDataFlow(input, output)
|
||||
)
|
||||
)
|
||||
// TODO: Also block flow through models that don't preserve identity such
|
||||
// as `strdup`.
|
||||
}
|
||||
|
||||
@@ -486,6 +486,47 @@ class Node extends TIRDataFlowNode {
|
||||
}
|
||||
}
|
||||
|
||||
private string toExprString(Node n) {
|
||||
not isDebugMode() and
|
||||
(
|
||||
result = n.asExpr(0).toString()
|
||||
or
|
||||
not exists(n.asExpr()) and
|
||||
result = stars(n) + n.asIndirectExpr(0, 1).toString()
|
||||
)
|
||||
}
|
||||
|
||||
private module NodeStars {
|
||||
private int getNumberOfIndirections(Node n) {
|
||||
result = n.(RawIndirectOperand).getIndirectionIndex()
|
||||
or
|
||||
result = n.(RawIndirectInstruction).getIndirectionIndex()
|
||||
or
|
||||
result = n.(VariableNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
|
||||
or
|
||||
result = n.(FinalParameterNode).getIndirectionIndex()
|
||||
}
|
||||
|
||||
private int maxNumberOfIndirections() { result = max(getNumberOfIndirections(_)) }
|
||||
|
||||
private string repeatStars(int n) {
|
||||
n = 0 and result = ""
|
||||
or
|
||||
n = [1 .. maxNumberOfIndirections()] and
|
||||
result = "*" + repeatStars(n - 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
|
||||
* output for `n`.
|
||||
*/
|
||||
string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
|
||||
}
|
||||
|
||||
private import NodeStars
|
||||
|
||||
/**
|
||||
* A class that lifts pre-SSA dataflow nodes to regular dataflow nodes.
|
||||
*/
|
||||
@@ -548,10 +589,7 @@ Type stripPointer(Type t) {
|
||||
result = t.(FunctionPointerIshType).getBaseType()
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
class PostUpdateNodeImpl extends PartialDefinitionNode, TPostUpdateNodeImpl {
|
||||
private class PostUpdateNodeImpl extends PartialDefinitionNode, TPostUpdateNodeImpl {
|
||||
int indirectionIndex;
|
||||
Operand operand;
|
||||
|
||||
@@ -709,7 +747,7 @@ class FinalGlobalValue extends Node, TFinalGlobalValue {
|
||||
override DataFlowType getType() {
|
||||
exists(int indirectionIndex |
|
||||
indirectionIndex = globalUse.getIndirectionIndex() and
|
||||
result = getTypeImpl(globalUse.getUnderlyingType(), indirectionIndex - 1)
|
||||
result = getTypeImpl(globalUse.getUnspecifiedType(), indirectionIndex - 1)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -740,7 +778,7 @@ class InitialGlobalValue extends Node, TInitialGlobalValue {
|
||||
|
||||
override DataFlowType getType() {
|
||||
exists(DataFlowType type |
|
||||
type = globalDef.getUnderlyingType() and
|
||||
type = globalDef.getUnspecifiedType() and
|
||||
if this.isGLValue()
|
||||
then result = type
|
||||
else result = getTypeImpl(type, globalDef.getIndirectionIndex() - 1)
|
||||
@@ -943,13 +981,10 @@ private Type getTypeImpl0(Type t, int indirectionIndex) {
|
||||
indirectionIndex > 0 and
|
||||
exists(Type stripped |
|
||||
stripped = stripPointer(t.stripTopLevelSpecifiers()) and
|
||||
// We need to avoid the case where `stripPointer(t) = t` (which can happen
|
||||
// on iterators that specify a `value_type` that is the iterator itself).
|
||||
// Such a type would create an infinite loop otherwise. For these cases we
|
||||
// simply don't produce a result for `getTypeImpl`.
|
||||
// To be on the safe side, we check whether the _unspecified_ type has
|
||||
// changed since this also prevents an infinite loop when `stripped` and
|
||||
// `t` only differ by const'ness or volatile'ness.
|
||||
// We need to avoid the case where `stripPointer(t) = t` (which can happen on
|
||||
// iterators that specify a `value_type` that is the iterator itself). Such a type
|
||||
// would create an infinite loop otherwise. For these cases we simply don't produce
|
||||
// a result for `getTypeImpl`.
|
||||
stripped.getUnspecifiedType() != t.getUnspecifiedType() and
|
||||
result = getTypeImpl0(stripped, indirectionIndex - 1)
|
||||
)
|
||||
@@ -999,14 +1034,12 @@ private module RawIndirectNodes {
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override predicate isGLValue() { this.getOperand().isGLValue() }
|
||||
|
||||
override DataFlowType getType() {
|
||||
exists(int sub, DataFlowType type, boolean isGLValue |
|
||||
type = getOperandType(this.getOperand(), isGLValue) and
|
||||
if isGLValue = true then sub = 1 else sub = 0
|
||||
|
|
||||
result = getTypeImpl(type.getUnderlyingType(), indirectionIndex - sub)
|
||||
result = getTypeImpl(type.getUnspecifiedType(), indirectionIndex - sub)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1043,14 +1076,12 @@ private module RawIndirectNodes {
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override predicate isGLValue() { this.getInstruction().isGLValue() }
|
||||
|
||||
override DataFlowType getType() {
|
||||
exists(int sub, DataFlowType type, boolean isGLValue |
|
||||
type = getInstructionType(this.getInstruction(), isGLValue) and
|
||||
if isGLValue = true then sub = 1 else sub = 0
|
||||
|
|
||||
result = getTypeImpl(type.getUnderlyingType(), indirectionIndex - sub)
|
||||
result = getTypeImpl(type.getUnspecifiedType(), indirectionIndex - sub)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1143,7 +1174,7 @@ class FinalParameterNode extends Node, TFinalParameterNode {
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override DataFlowType getType() { result = getTypeImpl(p.getUnderlyingType(), indirectionIndex) }
|
||||
override DataFlowType getType() { result = getTypeImpl(p.getUnspecifiedType(), indirectionIndex) }
|
||||
|
||||
final override Location getLocationImpl() {
|
||||
// Parameters can have multiple locations. When there's a unique location we use
|
||||
@@ -1401,24 +1432,11 @@ abstract private class ExprNodeBase extends Node {
|
||||
final Expr getExpr(int n) { result = this.getConvertedExpr(n).getUnconverted() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there exists a dataflow node whose `asExpr(n)` should evaluate
|
||||
* to `e`.
|
||||
*/
|
||||
private predicate exprNodeShouldBe(Expr e, int n) {
|
||||
exprNodeShouldBeInstruction(_, e, n) or
|
||||
exprNodeShouldBeOperand(_, e, n) or
|
||||
exprNodeShouldBeIndirectOutNode(_, e, n)
|
||||
}
|
||||
|
||||
private class InstructionExprNode extends ExprNodeBase, InstructionNode {
|
||||
InstructionExprNode() {
|
||||
exists(Expr e, int n |
|
||||
exprNodeShouldBeInstruction(this, e, n) and
|
||||
not exists(Expr conv |
|
||||
exprNodeShouldBe(conv, n + 1) and
|
||||
conv.getUnconverted() = e.getUnconverted()
|
||||
)
|
||||
not exprNodeShouldBeInstruction(_, e, n + 1)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1429,10 +1447,7 @@ private class OperandExprNode extends ExprNodeBase, OperandNode {
|
||||
OperandExprNode() {
|
||||
exists(Expr e, int n |
|
||||
exprNodeShouldBeOperand(this, e, n) and
|
||||
not exists(Expr conv |
|
||||
exprNodeShouldBe(conv, n + 1) and
|
||||
conv.getUnconverted() = e.getUnconverted()
|
||||
)
|
||||
not exprNodeShouldBeOperand(_, e, n + 1)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1497,17 +1512,12 @@ private module IndirectNodeToIndirectExpr<IndirectNodeToIndirectExprSig Sig> {
|
||||
indirectNodeHasIndirectExpr(node, e, n, indirectionIndex) and
|
||||
not exists(Expr conv, int adjustedIndirectionIndex |
|
||||
adjustForReference(e, indirectionIndex, conv, adjustedIndirectionIndex) and
|
||||
indirectExprNodeShouldBe(conv, n + 1, adjustedIndirectionIndex)
|
||||
indirectNodeHasIndirectExpr(_, conv, n + 1, adjustedIndirectionIndex)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate indirectExprNodeShouldBe(Expr e, int n, int indirectionIndex) {
|
||||
indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) or
|
||||
indirectExprNodeShouldBeIndirectInstruction(_, e, n, indirectionIndex)
|
||||
}
|
||||
|
||||
private module IndirectOperandIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
|
||||
class IndirectNode = IndirectOperand;
|
||||
|
||||
@@ -1796,7 +1806,7 @@ class VariableNode extends Node, TVariableNode {
|
||||
}
|
||||
|
||||
override DataFlowType getType() {
|
||||
result = getTypeImpl(v.getUnderlyingType(), indirectionIndex - 1)
|
||||
result = getTypeImpl(v.getUnspecifiedType(), indirectionIndex - 1)
|
||||
}
|
||||
|
||||
final override Location getLocationImpl() {
|
||||
|
||||
@@ -1,24 +1,9 @@
|
||||
/**
|
||||
* This file contains the class that implements the _debug_ version of
|
||||
* `toString` for `Instruction` and `Operand` dataflow nodes.
|
||||
* This file activates debugging mode for dataflow node printing.
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import codeql.util.Unit
|
||||
private import Node0ToString
|
||||
private import DataFlowUtil
|
||||
|
||||
private class DebugNode0ToString extends Node0ToString {
|
||||
DebugNode0ToString() {
|
||||
// Silence warning about `this` not being bound.
|
||||
exists(this)
|
||||
}
|
||||
|
||||
override string instructionToString(Instruction i) { result = i.getDumpString() }
|
||||
|
||||
override string operandToString(Operand op) {
|
||||
result = op.getDumpString() + " @ " + op.getUse().getResultId()
|
||||
}
|
||||
|
||||
override string toExprString(Node n) { none() }
|
||||
final override predicate isDebugMode() { any() }
|
||||
}
|
||||
|
||||
@@ -1,53 +1,75 @@
|
||||
/**
|
||||
* This file imports the class that is used to construct the strings used by
|
||||
* `Node.ToString`.
|
||||
* This file contains the abstract class that serves as the base class for
|
||||
* dataflow node printing.
|
||||
*
|
||||
* Normally, this file should just import `NormalNode0ToString` to compute the
|
||||
* efficient `toString`, but for debugging purposes one can import
|
||||
* `DebugPrinting.qll` to better correlate the dataflow nodes with their
|
||||
* underlying instructions and operands.
|
||||
* By default, a non-debug string is produced. However, a debug-friendly
|
||||
* string can be produced by importing `DebugPrinting.qll`.
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import codeql.util.Unit
|
||||
private import DataFlowUtil
|
||||
import NormalNode0ToString // Change this import to control which version should be used.
|
||||
|
||||
/** An abstract class to control the behavior of `Node.toString`. */
|
||||
abstract class Node0ToString extends Unit {
|
||||
/**
|
||||
* Gets the string that should be used by `OperandNode.toString` to print the
|
||||
* dataflow node whose underlying operand is `op.`
|
||||
*/
|
||||
abstract string operandToString(Operand op);
|
||||
/**
|
||||
* A class to control whether a debugging version of instructions and operands
|
||||
* should be printed as part of the `toString` output of dataflow nodes.
|
||||
*
|
||||
* To enable debug printing import the `DebugPrinting.ql` file. By default,
|
||||
* non-debug output will be used.
|
||||
*/
|
||||
class Node0ToString extends Unit {
|
||||
abstract predicate isDebugMode();
|
||||
|
||||
private string normalInstructionToString(Instruction i) {
|
||||
not this.isDebugMode() and
|
||||
if i.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
||||
then result = "this"
|
||||
else result = i.getAst().toString()
|
||||
}
|
||||
|
||||
private string normalOperandToString(Operand op) {
|
||||
not this.isDebugMode() and
|
||||
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
||||
then result = "this"
|
||||
else result = op.getDef().getAst().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string that should be used by `InstructionNode.toString` to print
|
||||
* the dataflow node whose underlying instruction is `instr`.
|
||||
* Gets the string that should be used by `InstructionNode.toString`
|
||||
*/
|
||||
abstract string instructionToString(Instruction i);
|
||||
string instructionToString(Instruction i) {
|
||||
if this.isDebugMode()
|
||||
then result = i.getDumpString()
|
||||
else result = this.normalInstructionToString(i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string representation of the `Expr` associated with `n`, if any.
|
||||
* Gets the string that should be used by `OperandNode.toString`.
|
||||
*/
|
||||
abstract string toExprString(Node n);
|
||||
string operandToString(Operand op) {
|
||||
if this.isDebugMode()
|
||||
then result = op.getDumpString() + " @ " + op.getUse().getResultId()
|
||||
else result = this.normalOperandToString(op)
|
||||
}
|
||||
}
|
||||
|
||||
private class NoDebugNode0ToString extends Node0ToString {
|
||||
final override predicate isDebugMode() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string that should be used by `OperandNode.toString` to print the
|
||||
* dataflow node whose underlying operand is `op.`
|
||||
* Gets the string that should be used by `OperandNode.toString`.
|
||||
*/
|
||||
string operandToString(Operand op) { result = any(Node0ToString s).operandToString(op) }
|
||||
string operandToString(Operand op) { result = any(Node0ToString nts).operandToString(op) }
|
||||
|
||||
/**
|
||||
* Gets the string that should be used by `InstructionNode.toString` to print
|
||||
* the dataflow node whose underlying instruction is `instr`.
|
||||
* Gets the string that should be used by `InstructionNode.toString`
|
||||
*/
|
||||
string instructionToString(Instruction instr) {
|
||||
result = any(Node0ToString s).instructionToString(instr)
|
||||
}
|
||||
string instructionToString(Instruction i) { result = any(Node0ToString nts).instructionToString(i) }
|
||||
|
||||
/**
|
||||
* Gets the string representation of the `Expr` associated with `n`, if any.
|
||||
* Holds if debugging mode is enabled.
|
||||
*
|
||||
* In debug mode the `toString` on dataflow nodes is more expensive to compute,
|
||||
* but gives more precise information about the different dataflow nodes.
|
||||
*/
|
||||
string toExprString(Node n) { result = any(Node0ToString s).toExprString(n) }
|
||||
predicate isDebugMode() { any(Node0ToString nts).isDebugMode() }
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* This file contains the class that implements the non-debug version of
|
||||
* `toString` for `Instruction` and `Operand` dataflow nodes.
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import codeql.util.Unit
|
||||
private import Node0ToString
|
||||
private import DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
|
||||
private class NormalNode0ToString extends Node0ToString {
|
||||
NormalNode0ToString() {
|
||||
// Silence warning about `this` not being bound.
|
||||
exists(this)
|
||||
}
|
||||
|
||||
override string instructionToString(Instruction i) {
|
||||
if i.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
||||
then result = "this"
|
||||
else result = i.getAst().toString()
|
||||
}
|
||||
|
||||
override string operandToString(Operand op) {
|
||||
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
||||
then result = "this"
|
||||
else result = op.getDef().getAst().toString()
|
||||
}
|
||||
|
||||
override string toExprString(Node n) {
|
||||
result = n.asExpr(0).toString()
|
||||
or
|
||||
not exists(n.asExpr()) and
|
||||
result = stars(n) + n.asIndirectExpr(0, 1).toString()
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import SsaInternals as Ssa
|
||||
private import PrintIRUtilities
|
||||
|
||||
@@ -34,9 +33,9 @@ private string getNodeProperty(Node node, string key) {
|
||||
key = "flow" and
|
||||
result =
|
||||
strictconcat(string flow, boolean to, int order1, int order2 |
|
||||
flow = getFromFlow(node, order1, order2) + "->" + stars(node) + "@" and to = false
|
||||
flow = getFromFlow(node, order1, order2) + "->" + starsForNode(node) + "@" and to = false
|
||||
or
|
||||
flow = stars(node) + "@->" + getToFlow(node, order1, order2) and to = true
|
||||
flow = starsForNode(node) + "@->" + getToFlow(node, order1, order2) and to = true
|
||||
|
|
||||
flow, ", " order by to, order1, order2, flow
|
||||
)
|
||||
|
||||
@@ -7,14 +7,37 @@ private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
|
||||
private string stars(int k) {
|
||||
k =
|
||||
[0 .. max([
|
||||
any(RawIndirectInstruction n).getIndirectionIndex(),
|
||||
any(RawIndirectOperand n).getIndirectionIndex()
|
||||
]
|
||||
)] and
|
||||
(if k = 0 then result = "" else result = "*" + stars(k - 1))
|
||||
}
|
||||
|
||||
string starsForNode(Node node) {
|
||||
exists(int indirectionIndex |
|
||||
node.(IndirectInstruction).hasInstructionAndIndirectionIndex(_, indirectionIndex) or
|
||||
node.(IndirectOperand).hasOperandAndIndirectionIndex(_, indirectionIndex)
|
||||
|
|
||||
result = stars(indirectionIndex)
|
||||
)
|
||||
or
|
||||
not node instanceof IndirectInstruction and
|
||||
not node instanceof IndirectOperand and
|
||||
result = ""
|
||||
}
|
||||
|
||||
private Instruction getInstruction(Node n, string stars) {
|
||||
result = [n.asInstruction(), n.(RawIndirectInstruction).getInstruction()] and
|
||||
stars = stars(n)
|
||||
stars = starsForNode(n)
|
||||
}
|
||||
|
||||
private Operand getOperand(Node n, string stars) {
|
||||
result = [n.asOperand(), n.(RawIndirectOperand).getOperand()] and
|
||||
stars = stars(n)
|
||||
stars = starsForNode(n)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -507,13 +507,13 @@ module ProductFlow {
|
||||
private predicate pathSuccPlus(TNodePair n1, TNodePair n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
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](succ.getNode().getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localPathStep2(Flow2::PathNode pred, Flow2::PathNode succ) {
|
||||
Flow2::PathGraph::edges(pred, succ, _, _) and
|
||||
Flow2::PathGraph::edges(pred, succ) and
|
||||
pragma[only_bind_out](pred.getNode().getEnclosingCallable()) =
|
||||
pragma[only_bind_out](succ.getNode().getEnclosingCallable())
|
||||
}
|
||||
@@ -530,7 +530,7 @@ module ProductFlow {
|
||||
TJump()
|
||||
|
||||
private predicate intoImpl1(Flow1::PathNode pred1, Flow1::PathNode succ1, DataFlowCall call) {
|
||||
Flow1::PathGraph::edges(pred1, succ1, _, _) and
|
||||
Flow1::PathGraph::edges(pred1, succ1) and
|
||||
pred1.getNode().(ArgumentNode).getCall() = call and
|
||||
succ1.getNode() instanceof ParameterNode
|
||||
}
|
||||
@@ -543,7 +543,7 @@ module ProductFlow {
|
||||
}
|
||||
|
||||
private predicate outImpl1(Flow1::PathNode pred1, Flow1::PathNode succ1, DataFlowCall call) {
|
||||
Flow1::PathGraph::edges(pred1, succ1, _, _) and
|
||||
Flow1::PathGraph::edges(pred1, succ1) and
|
||||
exists(ReturnKindExt returnKind |
|
||||
succ1.getNode() = returnKind.getAnOutNode(call) and
|
||||
pred1.getNode().(ReturnNodeExt).getKind() = returnKind
|
||||
@@ -558,7 +558,7 @@ module ProductFlow {
|
||||
}
|
||||
|
||||
private predicate intoImpl2(Flow2::PathNode pred2, Flow2::PathNode succ2, DataFlowCall call) {
|
||||
Flow2::PathGraph::edges(pred2, succ2, _, _) and
|
||||
Flow2::PathGraph::edges(pred2, succ2) and
|
||||
pred2.getNode().(ArgumentNode).getCall() = call and
|
||||
succ2.getNode() instanceof ParameterNode
|
||||
}
|
||||
@@ -571,7 +571,7 @@ module ProductFlow {
|
||||
}
|
||||
|
||||
private predicate outImpl2(Flow2::PathNode pred2, Flow2::PathNode succ2, DataFlowCall call) {
|
||||
Flow2::PathGraph::edges(pred2, succ2, _, _) and
|
||||
Flow2::PathGraph::edges(pred2, succ2) and
|
||||
exists(ReturnKindExt returnKind |
|
||||
succ2.getNode() = returnKind.getAnOutNode(call) and
|
||||
pred2.getNode().(ReturnNodeExt).getKind() = returnKind
|
||||
@@ -590,7 +590,7 @@ module ProductFlow {
|
||||
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
|
||||
pred1.getNode().getEnclosingCallable() = predDecl and
|
||||
succ1.getNode().getEnclosingCallable() = succDecl and
|
||||
@@ -610,7 +610,7 @@ module ProductFlow {
|
||||
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
|
||||
pred2.getNode().getEnclosingCallable() = predDecl and
|
||||
succ2.getNode().getEnclosingCallable() = succDecl and
|
||||
|
||||
@@ -16,15 +16,6 @@ private module SourceVariables {
|
||||
ind = [0 .. countIndirectionsForCppType(base.getLanguageType()) + 1]
|
||||
}
|
||||
|
||||
private int maxNumberOfIndirections() { result = max(SourceVariable sv | | sv.getIndirection()) }
|
||||
|
||||
private string repeatStars(int n) {
|
||||
n = 0 and result = ""
|
||||
or
|
||||
n = [1 .. maxNumberOfIndirections()] and
|
||||
result = "*" + repeatStars(n - 1)
|
||||
}
|
||||
|
||||
class SourceVariable extends TSourceVariable {
|
||||
SsaInternals0::SourceVariable base;
|
||||
int ind;
|
||||
@@ -41,7 +32,13 @@ private module SourceVariables {
|
||||
SsaInternals0::SourceVariable getBaseVariable() { result = base }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = repeatStars(this.getIndirection()) + base.toString() }
|
||||
string toString() {
|
||||
ind = 0 and
|
||||
result = this.getBaseVariable().toString()
|
||||
or
|
||||
ind > 0 and
|
||||
result = this.getBaseVariable().toString() + " indirection"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of loads performed on the base source variable
|
||||
@@ -142,23 +139,18 @@ private newtype TDefOrUseImpl =
|
||||
exists(SsaInternals0::Def def |
|
||||
def.getSourceVariable().getBaseVariable().(BaseIRVariable).getIRVariable().getAst() = p and
|
||||
not def.getValue().asInstruction() instanceof InitializeParameterInstruction and
|
||||
underlyingTypeIsModifiableAt(p.getUnderlyingType(), indirectionIndex)
|
||||
unspecifiedTypeIsModifiableAt(p.getUnspecifiedType(), indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isGlobalUse(
|
||||
GlobalLikeVariable v, IRFunction f, int indirection, int indirectionIndex
|
||||
) {
|
||||
// Generate a "global use" at the end of the function body if there's a
|
||||
// direct definition somewhere in the body of the function
|
||||
indirection =
|
||||
min(int cand, VariableAddressInstruction vai |
|
||||
vai.getEnclosingIRFunction() = f and
|
||||
vai.getAstVariable() = v and
|
||||
isDef(_, _, _, vai, cand, indirectionIndex)
|
||||
|
|
||||
cand
|
||||
)
|
||||
exists(VariableAddressInstruction vai |
|
||||
vai.getEnclosingIRFunction() = f and
|
||||
vai.getAstVariable() = v and
|
||||
isDef(_, _, _, vai, indirection, indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isGlobalDefImpl(
|
||||
@@ -172,13 +164,11 @@ private predicate isGlobalDefImpl(
|
||||
)
|
||||
}
|
||||
|
||||
private predicate underlyingTypeIsModifiableAt(Type underlying, int indirectionIndex) {
|
||||
indirectionIndex =
|
||||
[1 .. getIndirectionForUnspecifiedType(underlying.getUnspecifiedType())
|
||||
.getNumberOfIndirections()] and
|
||||
private predicate unspecifiedTypeIsModifiableAt(Type unspecified, int indirectionIndex) {
|
||||
indirectionIndex = [1 .. getIndirectionForUnspecifiedType(unspecified).getNumberOfIndirections()] and
|
||||
exists(CppType cppType |
|
||||
cppType.hasUnderlyingType(underlying, false) and
|
||||
isModifiableAt(cppType, indirectionIndex)
|
||||
cppType.hasUnspecifiedType(unspecified, _) and
|
||||
isModifiableAt(cppType, indirectionIndex + 1)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -454,57 +444,6 @@ class FinalParameterUse extends UseImpl, TFinalParameterUse {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A use that models a synthetic "last use" of a global variable just before a
|
||||
* function returns.
|
||||
*
|
||||
* We model global variable flow by:
|
||||
* - Inserting a last use of any global variable that's modified by a function
|
||||
* - Flowing from the last use to the `VariableNode` that represents the global
|
||||
* variable.
|
||||
* - Flowing from the `VariableNode` to an "initial def" of the global variable
|
||||
* in any function that may read the global variable.
|
||||
* - Flowing from the initial definition to any subsequent uses of the global
|
||||
* variable in the function body.
|
||||
*
|
||||
* For example, consider the following pair of functions:
|
||||
* ```cpp
|
||||
* int global;
|
||||
* int source();
|
||||
* void sink(int);
|
||||
*
|
||||
* void set_global() {
|
||||
* global = source();
|
||||
* }
|
||||
*
|
||||
* void read_global() {
|
||||
* sink(global);
|
||||
* }
|
||||
* ```
|
||||
* we insert global uses and defs so that (from the point-of-view of dataflow)
|
||||
* the above scenario looks like:
|
||||
* ```cpp
|
||||
* int global; // (1)
|
||||
* int source();
|
||||
* void sink(int);
|
||||
*
|
||||
* void set_global() {
|
||||
* global = source();
|
||||
* __global_use(global); // (2)
|
||||
* }
|
||||
*
|
||||
* void read_global() {
|
||||
* global = __global_def; // (3)
|
||||
* sink(global); // (4)
|
||||
* }
|
||||
* ```
|
||||
* and flow from `source()` to the argument of `sink` is then modeled as
|
||||
* follows:
|
||||
* 1. Flow from `source()` to `(2)` (via SSA).
|
||||
* 2. Flow from `(2)` to `(1)` (via a `jumpStep`).
|
||||
* 3. Flow from `(1)` to `(3)` (via a `jumpStep`).
|
||||
* 4. Flow from `(3)` to `(4)` (via SSA).
|
||||
*/
|
||||
class GlobalUse extends UseImpl, TGlobalUse {
|
||||
GlobalLikeVariable global;
|
||||
IRFunction f;
|
||||
@@ -547,22 +486,11 @@ class GlobalUse extends UseImpl, TGlobalUse {
|
||||
*/
|
||||
Type getUnspecifiedType() { result = global.getUnspecifiedType() }
|
||||
|
||||
/**
|
||||
* Gets the type of this use, after typedefs have been resolved.
|
||||
*/
|
||||
Type getUnderlyingType() { result = global.getUnderlyingType() }
|
||||
|
||||
override predicate isCertain() { any() }
|
||||
|
||||
override BaseSourceVariableInstruction getBase() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A definition that models a synthetic "initial definition" of a global
|
||||
* variable just after the function entry point.
|
||||
*
|
||||
* See the QLDoc for `GlobalUse` for how this is used.
|
||||
*/
|
||||
class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
|
||||
GlobalLikeVariable global;
|
||||
IRFunction f;
|
||||
@@ -595,16 +523,11 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
|
||||
int getIndirection() { result = indirectionIndex }
|
||||
|
||||
/**
|
||||
* Gets the type of this definition after specifiers have been deeply
|
||||
* stripped and typedefs have been resolved.
|
||||
* Gets the type of this use after specifiers have been deeply stripped
|
||||
* and typedefs have been resolved.
|
||||
*/
|
||||
Type getUnspecifiedType() { result = global.getUnspecifiedType() }
|
||||
|
||||
/**
|
||||
* Gets the type of this definition, after typedefs have been resolved.
|
||||
*/
|
||||
Type getUnderlyingType() { result = global.getUnderlyingType() }
|
||||
|
||||
override string toString() { result = "Def of " + this.getSourceVariable() }
|
||||
|
||||
override Location getLocation() { result = f.getLocation() }
|
||||
@@ -621,10 +544,7 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
|
||||
*/
|
||||
predicate adjacentDefRead(DefOrUse defOrUse1, UseOrPhi use) {
|
||||
exists(IRBlock bb1, int i1, SourceVariable v |
|
||||
defOrUse1
|
||||
.asDefOrUse()
|
||||
.hasIndexInBlock(pragma[only_bind_out](bb1), pragma[only_bind_out](i1),
|
||||
pragma[only_bind_out](v))
|
||||
defOrUse1.asDefOrUse().hasIndexInBlock(bb1, i1, v)
|
||||
|
|
||||
exists(IRBlock bb2, int i2, DefinitionExt def |
|
||||
adjacentDefReadExt(pragma[only_bind_into](def), pragma[only_bind_into](bb1),
|
||||
@@ -646,11 +566,7 @@ predicate adjacentDefRead(DefOrUse defOrUse1, UseOrPhi use) {
|
||||
* flows to `useOrPhi`.
|
||||
*/
|
||||
private predicate globalDefToUse(GlobalDef globalDef, UseOrPhi useOrPhi) {
|
||||
exists(IRBlock bb1, int i1, SourceVariable v |
|
||||
globalDef
|
||||
.hasIndexInBlock(pragma[only_bind_out](bb1), pragma[only_bind_out](i1),
|
||||
pragma[only_bind_out](v))
|
||||
|
|
||||
exists(IRBlock bb1, int i1, SourceVariable v | globalDef.hasIndexInBlock(bb1, i1, v) |
|
||||
exists(IRBlock bb2, int i2 |
|
||||
adjacentDefReadExt(_, pragma[only_bind_into](bb1), pragma[only_bind_into](i1),
|
||||
pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) and
|
||||
@@ -1104,11 +1020,6 @@ class GlobalDef extends TGlobalDef, SsaDefOrUse {
|
||||
*/
|
||||
DataFlowType getUnspecifiedType() { result = global.getUnspecifiedType() }
|
||||
|
||||
/**
|
||||
* Gets the type of this definition, after typedefs have been resolved.
|
||||
*/
|
||||
DataFlowType getUnderlyingType() { result = global.getUnderlyingType() }
|
||||
|
||||
/** Gets the `IRFunction` whose body is evaluated after this definition. */
|
||||
IRFunction getIRFunction() { result = global.getIRFunction() }
|
||||
|
||||
|
||||
@@ -452,7 +452,7 @@ private module IsModifiableAtImpl {
|
||||
private predicate impl(CppType cppType, int indirectionIndex) {
|
||||
exists(Type pointerType, Type base |
|
||||
isUnderlyingIndirectionType(pointerType) and
|
||||
cppType.hasUnderlyingType(pointerType, false) and
|
||||
cppType.hasUnderlyingType(pointerType, _) and
|
||||
base = getTypeImpl(pointerType, indirectionIndex)
|
||||
|
|
||||
// The value cannot be modified if it has a const specifier,
|
||||
|
||||
@@ -2125,6 +2125,13 @@ class ChiInstruction extends Instruction {
|
||||
*/
|
||||
final Instruction getPartial() { result = this.getPartialOperand().getDef() }
|
||||
|
||||
/**
|
||||
* Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand.
|
||||
*/
|
||||
final predicate getUpdatedInterval(int startBit, int endBit) {
|
||||
Construction::getIntervalUpdatedByChi(this, startBit, endBit)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `ChiPartialOperand` totally, but not exactly, overlaps with the `ChiTotalOperand`.
|
||||
* This means that the `ChiPartialOperand` will not override the entire memory associated with the
|
||||
|
||||
@@ -233,6 +233,20 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the partial operand of this `ChiInstruction` updates the bit range
|
||||
* `[startBitOffset, endBitOffset)` of the total operand.
|
||||
*/
|
||||
cached
|
||||
predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBitOffset, int endBitOffset) {
|
||||
exists(Alias::MemoryLocation location, OldInstruction oldInstruction |
|
||||
oldInstruction = getOldInstruction(chi.getPartial()) and
|
||||
location = Alias::getResultMemoryLocation(oldInstruction) and
|
||||
startBitOffset = Alias::getStartBitOffset(location) and
|
||||
endBitOffset = Alias::getEndBitOffset(location)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `operand` totally overlaps with its definition and consumes the bit range
|
||||
* `[startBitOffset, endBitOffset)`.
|
||||
@@ -1054,3 +1068,6 @@ module Ssa {
|
||||
|
||||
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for Ssa */
|
||||
deprecated module SSA = Ssa;
|
||||
|
||||
@@ -3,6 +3,13 @@ import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Rea
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
|
||||
import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSsaInstructions as SsaInstructions
|
||||
|
||||
/** DEPRECATED: Alias for SsaInstructions */
|
||||
deprecated module SSAInstructions = SsaInstructions;
|
||||
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import AliasedSSA as Alias
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand::AliasedSsaOperands as SsaOperands
|
||||
|
||||
/** DEPRECATED: Alias for SsaOperands */
|
||||
deprecated module SSAOperands = SsaOperands;
|
||||
|
||||
@@ -2,3 +2,6 @@ import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSsa
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSsa
|
||||
|
||||
/** DEPRECATED: Alias for AliasedSsa */
|
||||
deprecated module AliasedSSA = AliasedSsa;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user