mirror of
https://github.com/github/codeql.git
synced 2026-05-24 16:17:07 +02:00
Compare commits
9 Commits
rc/3.5
...
henrymerce
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e60c8470a3 | ||
|
|
ee97acefcd | ||
|
|
c553330ee3 | ||
|
|
1d507f1993 | ||
|
|
1b7088abde | ||
|
|
eec7b926b0 | ||
|
|
0a003edaa7 | ||
|
|
b7852cec7a | ||
|
|
03bb3cce73 |
@@ -4,10 +4,8 @@
|
||||
"*/ql/lib/qlpack.yml",
|
||||
"*/ql/test/qlpack.yml",
|
||||
"*/ql/examples/qlpack.yml",
|
||||
"*/ql/consistency-queries/qlpack.yml",
|
||||
"cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml",
|
||||
"javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml",
|
||||
"javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml",
|
||||
"javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml",
|
||||
"csharp/ql/campaigns/Solorigate/lib/qlpack.yml",
|
||||
"csharp/ql/campaigns/Solorigate/src/qlpack.yml",
|
||||
@@ -15,6 +13,8 @@
|
||||
"misc/legacy-support/*/qlpack.yml",
|
||||
"misc/suite-helpers/qlpack.yml",
|
||||
"ruby/extractor-pack/codeql-extractor.yml",
|
||||
"ruby/ql/consistency-queries/qlpack.yml",
|
||||
"ql/ql/consistency-queries/qlpack.yml",
|
||||
"ql/extractor-pack/codeql-extractor.yml"
|
||||
],
|
||||
"versionPolicies": {
|
||||
|
||||
13
.gitattributes
vendored
13
.gitattributes
vendored
@@ -50,15 +50,4 @@
|
||||
*.pdb -text
|
||||
|
||||
java/ql/test/stubs/**/*.java linguist-generated=true
|
||||
java/ql/test/experimental/stubs/**/*.java linguist-generated=true
|
||||
|
||||
# For some languages, upgrade script testing references really old dbscheme
|
||||
# files from legacy upgrades that have CRLF line endings. Since upgrade
|
||||
# resolution relies on object hashes, we must suppress line ending conversion
|
||||
# for those testing dbscheme files.
|
||||
*/ql/lib/upgrades/initial/*.dbscheme -text
|
||||
|
||||
# Generated test files - these are synced from the standard JavaScript libraries using
|
||||
# `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
|
||||
java/ql/test/experimental/stubs/**/*.java linguist-generated=true
|
||||
3
.github/workflows/check-change-note.yml
vendored
3
.github/workflows/check-change-note.yml
vendored
@@ -6,11 +6,8 @@ on:
|
||||
paths:
|
||||
- "*/ql/src/**/*.ql"
|
||||
- "*/ql/src/**/*.qll"
|
||||
- "*/ql/lib/**/*.ql"
|
||||
- "*/ql/lib/**/*.qll"
|
||||
- "!**/experimental/**"
|
||||
- "!ql/**"
|
||||
- ".github/workflows/check-change-note.yml"
|
||||
|
||||
jobs:
|
||||
check-change-note:
|
||||
|
||||
50
.github/workflows/check-qldoc.yml
vendored
50
.github/workflows/check-qldoc.yml
vendored
@@ -1,50 +0,0 @@
|
||||
name: "Check QLdoc coverage"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "*/ql/lib/**"
|
||||
- .github/workflows/check-qldoc.yml
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
|
||||
jobs:
|
||||
qldoc:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Install CodeQL
|
||||
run: |
|
||||
gh extension install github/gh-codeql
|
||||
gh codeql set-channel nightly
|
||||
gh codeql version
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Check QLdoc coverage
|
||||
shell: bash
|
||||
run: |
|
||||
EXIT_CODE=0
|
||||
changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -o '^[a-z]*/ql/lib' || true; } | sort -u)"
|
||||
for pack_dir in ${changed_lib_packs}; do
|
||||
lang="${pack_dir%/ql/lib}"
|
||||
gh codeql generate library-doc-coverage --output="${RUNNER_TEMP}/${lang}-current.txt" --dir="${pack_dir}"
|
||||
done
|
||||
git checkout HEAD^
|
||||
for pack_dir in ${changed_lib_packs}; do
|
||||
lang="${pack_dir%/ql/lib}"
|
||||
gh codeql generate library-doc-coverage --output="${RUNNER_TEMP}/${lang}-baseline.txt" --dir="${pack_dir}"
|
||||
awk -F, '{gsub(/"/,""); if ($4==0 && $6=="public") print "\""$3"\"" }' "${RUNNER_TEMP}/${lang}-current.txt" | sort -u > "${RUNNER_TEMP}/current-undocumented.txt"
|
||||
awk -F, '{gsub(/"/,""); if ($4==0 && $6=="public") print "\""$3"\"" }' "${RUNNER_TEMP}/${lang}-baseline.txt" | sort -u > "${RUNNER_TEMP}/baseline-undocumented.txt"
|
||||
UNDOCUMENTED="$(grep -f <(comm -13 "${RUNNER_TEMP}/baseline-undocumented.txt" "${RUNNER_TEMP}/current-undocumented.txt") "${RUNNER_TEMP}/${lang}-current.txt" || true)"
|
||||
if [ -n "$UNDOCUMENTED" ]; then
|
||||
echo "$UNDOCUMENTED" | awk -F, '{gsub(/"/,""); print "::warning file='"${pack_dir}"'/"$1",line="$2"::Missing QLdoc for "$5, $3 }'
|
||||
EXIT_CODE=1
|
||||
fi
|
||||
done
|
||||
exit "${EXIT_CODE}"
|
||||
7
.github/workflows/codeql-analysis.yml
vendored
7
.github/workflows/codeql-analysis.yml
vendored
@@ -27,11 +27,6 @@ jobs:
|
||||
pull-requests: read
|
||||
|
||||
steps:
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 6.0.101
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
@@ -56,7 +51,7 @@ jobs:
|
||||
# uses a compiled language
|
||||
|
||||
- run: |
|
||||
dotnet build csharp /p:UseSharedCompilation=false
|
||||
dotnet build csharp
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@main
|
||||
|
||||
43
.github/workflows/csv-coverage-metrics.yml
vendored
43
.github/workflows/csv-coverage-metrics.yml
vendored
@@ -1,43 +0,0 @@
|
||||
name: "Publish framework coverage as metrics"
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '5 0 * * *'
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- ".github/workflows/csv-coverage-metrics.yml"
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup CodeQL
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
- name: Create empty database
|
||||
run: |
|
||||
DATABASE="${{ runner.temp }}/java-database"
|
||||
PROJECT="${{ runner.temp }}/java-project"
|
||||
mkdir -p "$PROJECT/src/tmp/empty"
|
||||
echo "class Empty {}" >> "$PROJECT/src/tmp/empty/Empty.java"
|
||||
codeql database create "$DATABASE" --language=java --source-root="$PROJECT" --command 'javac src/tmp/empty/Empty.java'
|
||||
- name: Capture coverage information
|
||||
run: |
|
||||
DATABASE="${{ runner.temp }}/java-database"
|
||||
codeql database analyze --format=sarif-latest --output=metrics.sarif -- "$DATABASE" ./java/ql/src/Metrics/Summaries/FrameworkCoverage.ql
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: metrics.sarif
|
||||
path: metrics.sarif
|
||||
retention-days: 20
|
||||
- name: Upload SARIF file
|
||||
uses: github/codeql-action/upload-sarif@v1
|
||||
with:
|
||||
sarif_file: metrics.sarif
|
||||
76
.github/workflows/js-ml-tests.yml
vendored
76
.github/workflows/js-ml-tests.yml
vendored
@@ -1,76 +0,0 @@
|
||||
name: JS ML-powered queries tests
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/**"
|
||||
- .github/workflows/js-ml-tests.yml
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
pull_request:
|
||||
paths:
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/**"
|
||||
- .github/workflows/js-ml-tests.yml
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: javascript/ql/experimental/adaptivethreatmodeling
|
||||
|
||||
jobs:
|
||||
qlformat:
|
||||
name: Check QL formatting
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
|
||||
- name: Check QL formatting
|
||||
run: |
|
||||
find . "(" -name "*.ql" -or -name "*.qll" ")" -print0 | \
|
||||
xargs -0 codeql query format --check-only
|
||||
|
||||
qlcompile:
|
||||
name: Check QL compilation
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
|
||||
- name: Install pack dependencies
|
||||
run: |
|
||||
for pack in modelbuilding src; do
|
||||
codeql pack install --mode verify -- "${pack}"
|
||||
done
|
||||
|
||||
- name: Check QL compilation
|
||||
run: |
|
||||
codeql query compile \
|
||||
--check-only \
|
||||
--ram 5120 \
|
||||
--additional-packs "${{ github.workspace }}" \
|
||||
--threads=0 \
|
||||
-- \
|
||||
lib modelbuilding src
|
||||
|
||||
qltest:
|
||||
name: Run QL tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
|
||||
- name: Install pack dependencies
|
||||
run: codeql pack install -- test
|
||||
|
||||
- name: Run QL tests
|
||||
run: |
|
||||
codeql test run \
|
||||
--threads=0 \
|
||||
--ram 5120 \
|
||||
--additional-packs "${{ github.workspace }}" \
|
||||
-- \
|
||||
test
|
||||
103
.github/workflows/mad_modelDiff.yml
vendored
103
.github/workflows/mad_modelDiff.yml
vendored
@@ -1,103 +0,0 @@
|
||||
name: Models as Data - Diff
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
projects:
|
||||
description: "The projects to generate models for"
|
||||
required: true
|
||||
default: '["netty/netty"]'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "java/ql/src/utils/model-generator/**/*.*"
|
||||
- ".github/workflows/mad_modelDiff.yml"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
model-diff:
|
||||
name: Model Difference
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'github/codeql'
|
||||
strategy:
|
||||
matrix:
|
||||
slug: ${{fromJson(github.event.inputs.projects || '["apache/commons-codec", "apache/commons-io", "apache/commons-beanutils", "apache/commons-logging", "apache/commons-fileupload", "apache/commons-lang", "apache/commons-validator", "apache/commons-csv", "apache/dubbo"]' )}}
|
||||
steps:
|
||||
- name: Clone github/codeql from PR
|
||||
uses: actions/checkout@v2
|
||||
if: github.event.pull_request
|
||||
with:
|
||||
path: codeql-pr
|
||||
- name: Clone github/codeql from main
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: codeql-main
|
||||
ref: main
|
||||
- uses: ./codeql-main/.github/actions/fetch-codeql
|
||||
- name: Download database
|
||||
env:
|
||||
SLUG: ${{ matrix.slug }}
|
||||
run: |
|
||||
set -x
|
||||
mkdir lib-dbs
|
||||
SHORTNAME=${SLUG//[^a-zA-Z0-9_]/}
|
||||
projectId=`curl -s https://lgtm.com/api/v1.0/projects/g/${SLUG} | jq .id`
|
||||
curl -L "https://lgtm.com/api/v1.0/snapshots/$projectId/java" -o "$SHORTNAME.zip"
|
||||
unzip -q -d "${SHORTNAME}-db" "${SHORTNAME}.zip"
|
||||
mkdir "lib-dbs/$SHORTNAME/"
|
||||
mv "${SHORTNAME}-db/"$(ls -1 "${SHORTNAME}"-db)/* "lib-dbs/${SHORTNAME}/"
|
||||
- name: Generate Models (PR and main)
|
||||
run: |
|
||||
set -x
|
||||
mkdir tmp-models
|
||||
MODELS=`pwd`/tmp-models
|
||||
DATABASES=`pwd`/lib-dbs
|
||||
|
||||
analyzeDatabaseWithCheckout() {
|
||||
QL_VARIANT=$1
|
||||
DATABASE=$2
|
||||
cd codeql-$QL_VARIANT
|
||||
SHORTNAME=`basename $DATABASE`
|
||||
python java/ql/src/utils/model-generator/GenerateFlowModel.py $DATABASE $MODELS/${SHORTNAME}.qll
|
||||
mv $MODELS/${SHORTNAME}.qll $MODELS/${SHORTNAME}Generated_${QL_VARIANT}.qll
|
||||
cd ..
|
||||
}
|
||||
|
||||
for d in $DATABASES/*/ ; do
|
||||
ls -1 "$d"
|
||||
|
||||
analyzeDatabaseWithCheckout "main" $d
|
||||
if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]
|
||||
then
|
||||
analyzeDatabaseWithCheckout "pr" $d
|
||||
fi
|
||||
done
|
||||
- name: Install diff2html
|
||||
if: github.event.pull_request
|
||||
run: |
|
||||
npm install -g diff2html-cli
|
||||
- name: Generate Model Diff
|
||||
if: github.event.pull_request
|
||||
run: |
|
||||
set -x
|
||||
MODELS=`pwd`/tmp-models
|
||||
ls -1 tmp-models/
|
||||
for m in $MODELS/*_main.qll ; do
|
||||
t="${m/main/"pr"}"
|
||||
basename=`basename $m`
|
||||
name="diff_${basename/_main.qll/""}"
|
||||
(diff -w -u $m $t | diff2html -i stdin -F $MODELS/$name.html) || true
|
||||
done
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: models
|
||||
path: tmp-models/*.qll
|
||||
retention-days: 20
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: diffs
|
||||
path: tmp-models/*.html
|
||||
retention-days: 20
|
||||
62
.github/workflows/mad_regenerate-models.yml
vendored
62
.github/workflows/mad_regenerate-models.yml
vendored
@@ -1,62 +0,0 @@
|
||||
name: Regenerate framework models
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "30 2 * * *"
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- ".github/workflows/mad_regenerate-models.yml"
|
||||
|
||||
jobs:
|
||||
regenerate-models:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
# placeholder required for each axis, excluded below, replaced by the actual combinations (see include)
|
||||
slug: ["placeholder"]
|
||||
ref: ["placeholder"]
|
||||
include:
|
||||
- slug: "apache/commons-io"
|
||||
ref: "8985de8fe74f6622a419b37a6eed0dbc484dc128"
|
||||
exclude:
|
||||
- slug: "placeholder"
|
||||
ref: "placeholder"
|
||||
steps:
|
||||
- name: Clone self (github/codeql)
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup CodeQL binaries
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
- name: Clone repositories
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: repos/${{ matrix.ref }}
|
||||
ref: ${{ matrix.ref }}
|
||||
repository: ${{ matrix.slug }}
|
||||
- name: Build database
|
||||
env:
|
||||
SLUG: ${{ matrix.slug }}
|
||||
REF: ${{ matrix.ref }}
|
||||
run: |
|
||||
mkdir dbs
|
||||
cd repos/${REF}
|
||||
SHORTNAME=${SLUG//[^a-zA-Z0-9_]/}
|
||||
codeql database create --language=java ../../dbs/${SHORTNAME}
|
||||
- name: Regenerate models in-place
|
||||
env:
|
||||
SLUG: ${{ matrix.slug }}
|
||||
run: |
|
||||
SHORTNAME=${SLUG//[^a-zA-Z0-9_]/}
|
||||
java/ql/src/utils/model-generator/RegenerateModels.py "${SLUG}" dbs/${SHORTNAME}
|
||||
- name: Stage changes
|
||||
run: |
|
||||
find java -name "*.qll" -print0 | xargs -0 git add
|
||||
git status
|
||||
git diff --cached > models.patch
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: patch
|
||||
path: models.patch
|
||||
retention-days: 7
|
||||
11
.github/workflows/ql-for-ql-build.yml
vendored
11
.github/workflows/ql-for-ql-build.yml
vendored
@@ -31,13 +31,13 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ runner.temp }}/query-pack.zip
|
||||
key: queries-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}
|
||||
key: queries-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}
|
||||
- name: Build query pack
|
||||
if: steps.cache-queries.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd ql/ql/src
|
||||
"${CODEQL}" pack create
|
||||
cd .codeql/pack/codeql/ql/0.0.0
|
||||
cd .codeql/pack/codeql/ql-all/0.0.0
|
||||
zip "${PACKZIP}" -r .
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
@@ -189,11 +189,4 @@ jobs:
|
||||
uses: github/codeql-action/analyze@erik-krogh/ql
|
||||
with:
|
||||
category: "ql-for-ql-${{ matrix.folder }}"
|
||||
- name: Copy sarif file to CWD
|
||||
run: cp ../results/ql.sarif ./${{ matrix.folder }}.sarif
|
||||
- name: Sarif as artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ matrix.folder }}.sarif
|
||||
path: ${{ matrix.folder }}.sarif
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
|
||||
strategy:
|
||||
matrix:
|
||||
repo:
|
||||
repo:
|
||||
- github/codeql
|
||||
- github/codeql-go
|
||||
runs-on: ubuntu-latest
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
ql/target
|
||||
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
|
||||
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Build Extractor
|
||||
run: cd ql; env "PATH=$PATH:`dirname ${CODEQL}`" ./create-extractor-pack.sh
|
||||
env:
|
||||
|
||||
8
.github/workflows/ql-for-ql-tests.yml
vendored
8
.github/workflows/ql-for-ql-tests.yml
vendored
@@ -29,24 +29,24 @@ jobs:
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
ql/target
|
||||
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
|
||||
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Build extractor
|
||||
run: |
|
||||
cd ql;
|
||||
codeqlpath=$(dirname ${{ steps.find-codeql.outputs.codeql-path }});
|
||||
env "PATH=$PATH:$codeqlpath" ./create-extractor-pack.sh
|
||||
- name: Run QL tests
|
||||
run: |
|
||||
run: |
|
||||
"${CODEQL}" test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}/ql/extractor-pack" --consistency-queries ql/ql/consistency-queries ql/ql/test
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
- name: Check QL formatting
|
||||
run: |
|
||||
run: |
|
||||
find ql/ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 "${CODEQL}" query format --check-only
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
- name: Check QL compilation
|
||||
run: |
|
||||
run: |
|
||||
"${CODEQL}" query compile --check-only --threads=4 --warnings=error --search-path "${{ github.workspace }}/ql/extractor-pack" "ql/ql/src" "ql/ql/examples"
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
|
||||
2
.github/workflows/ruby-build.yml
vendored
2
.github/workflows/ruby-build.yml
vendored
@@ -50,7 +50,7 @@ jobs:
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
ruby/target
|
||||
key: ${{ runner.os }}-ruby-rust-cargo-${{ hashFiles('ruby/rust-toolchain.toml', 'ruby/**/Cargo.lock') }}
|
||||
key: ${{ runner.os }}-rust-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Check formatting
|
||||
run: cargo fmt --all -- --check
|
||||
- name: Build
|
||||
|
||||
55
.github/workflows/ruby-qltest.yml
vendored
55
.github/workflows/ruby-qltest.yml
vendored
@@ -24,54 +24,27 @@ defaults:
|
||||
working-directory: ruby
|
||||
|
||||
jobs:
|
||||
qlformat:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- name: Check QL formatting
|
||||
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
|
||||
qlcompile:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- name: Check QL compilation
|
||||
run: |
|
||||
codeql query compile --check-only --threads=0 --ram 5000 --warnings=error "ql/src" "ql/examples"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
qlupgrade:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- name: Check DB upgrade scripts
|
||||
run: |
|
||||
echo >empty.trap
|
||||
codeql dataset import -S ql/lib/upgrades/initial/ruby.dbscheme testdb empty.trap
|
||||
codeql dataset upgrade testdb --additional-packs ql/lib
|
||||
diff -q testdb/ruby.dbscheme ql/lib/ruby.dbscheme
|
||||
- name: Check DB downgrade scripts
|
||||
run: |
|
||||
echo >empty.trap
|
||||
rm -rf testdb; codeql dataset import -S ql/lib/ruby.dbscheme testdb empty.trap
|
||||
codeql resolve upgrades --format=lines --allow-downgrades --additional-packs downgrades \
|
||||
--dbscheme=ql/lib/ruby.dbscheme --target-dbscheme=downgrades/initial/ruby.dbscheme |
|
||||
xargs codeql execute upgrades testdb
|
||||
diff -q testdb/ruby.dbscheme downgrades/initial/ruby.dbscheme
|
||||
qltest:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
slice: ["1/2", "2/2"]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: ./ruby/actions/create-extractor-pack
|
||||
- name: Run QL tests
|
||||
run: |
|
||||
codeql test run --threads=0 --ram 5000 --slice ${{ matrix.slice }} --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test
|
||||
codeql test run --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
- name: Check QL formatting
|
||||
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
|
||||
- name: Check QL compilation
|
||||
run: |
|
||||
codeql query compile --check-only --threads=4 --warnings=error "ql/src" "ql/examples"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
- name: Check DB upgrade scripts
|
||||
run: |
|
||||
echo >empty.trap
|
||||
codeql dataset import -S ql/lib/upgrades/initial/ruby.dbscheme testdb empty.trap
|
||||
codeql dataset upgrade testdb --additional-packs ql/lib
|
||||
diff -q testdb/ruby.dbscheme ql/lib/ruby.dbscheme
|
||||
|
||||
29
.github/workflows/validate-change-notes.yml
vendored
29
.github/workflows/validate-change-notes.yml
vendored
@@ -1,29 +0,0 @@
|
||||
name: Validate change notes
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "*/ql/*/change-notes/**/*"
|
||||
- ".github/workflows/validate-change-notes.yml"
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
pull_request:
|
||||
paths:
|
||||
- "*/ql/*/change-notes/**/*"
|
||||
- ".github/workflows/validate-change-notes.yml"
|
||||
|
||||
jobs:
|
||||
check-change-note:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup CodeQL
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
|
||||
- name: Fail if there are any errors with existing change notes
|
||||
|
||||
run: |
|
||||
codeql pack release --groups cpp,csharp,java,javascript,python,ruby,-examples,-test,-experimental
|
||||
@@ -1,29 +0,0 @@
|
||||
# See https://pre-commit.com for more information
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v3.2.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: codeql-format
|
||||
name: Fix QL file formatting
|
||||
files: \.qll?$
|
||||
language: system
|
||||
entry: codeql query format --in-place
|
||||
|
||||
- id: sync-files
|
||||
name: Fix files required to be identical
|
||||
language: system
|
||||
entry: python3 config/sync-files.py --latest
|
||||
pass_filenames: false
|
||||
|
||||
- id: qhelp
|
||||
name: Check query help generation
|
||||
files: \.qhelp$
|
||||
language: system
|
||||
entry: python3 misc/scripts/check-qhelp.py
|
||||
@@ -13,9 +13,6 @@
|
||||
/python/**/experimental/**/* @github/codeql-python @xcorail
|
||||
/ruby/**/experimental/**/* @github/codeql-ruby @xcorail
|
||||
|
||||
# ML-powered queries
|
||||
/javascript/ql/experimental/adaptivethreatmodeling/ @github/codeql-ml-powered-queries-reviewers
|
||||
|
||||
# Notify members of codeql-go about PRs to the shared data-flow library files
|
||||
/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @github/codeql-java @github/codeql-go
|
||||
/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @github/codeql-java @github/codeql-go
|
||||
@@ -30,4 +27,4 @@
|
||||
/docs/query-*-style-guide.md @github/codeql-analysis-reviewers
|
||||
|
||||
# QL for QL reviewers
|
||||
/ql/ @github/codeql-ql-for-ql-reviewers
|
||||
/ql/ @erik-krogh @tausbn
|
||||
@@ -4,9 +4,6 @@ We welcome contributions to our CodeQL libraries and queries. Got an idea for a
|
||||
|
||||
There is lots of useful documentation to help you write queries, ranging from information about query file structure to tutorials for specific target languages. For more information on the documentation available, see [CodeQL queries](https://help.semmle.com/QL/learn-ql/writing-queries/writing-queries.html) on [help.semmle.com](https://help.semmle.com).
|
||||
|
||||
## Change notes
|
||||
|
||||
Any nontrivial user-visible change to a query pack or library pack should have a change note. For details on how to add a change note for your change, see [this guide](docs/change-notes.md).
|
||||
|
||||
## Submitting a new experimental query
|
||||
|
||||
@@ -42,11 +39,7 @@ If you have an idea for a query that you would like to share with other CodeQL u
|
||||
|
||||
- The queries and libraries must be autoformatted, for example using the "Format Document" command in [CodeQL for Visual Studio Code](https://help.semmle.com/codeql/codeql-for-vscode/procedures/about-codeql-for-vscode.html).
|
||||
|
||||
If you prefer, you can either:
|
||||
1. install the [pre-commit framework](https://pre-commit.com/) and install the configured hooks on this repo via `pre-commit install`, or
|
||||
2. use this [pre-commit hook](misc/scripts/pre-commit) that automatically checks whether your files are correctly formatted.
|
||||
|
||||
See the [pre-commit hook installation guide](docs/pre-commit-hook-setup.md) for instructions on the two approaches.
|
||||
If you prefer, you can use this [pre-commit hook](misc/scripts/pre-commit) that automatically checks whether your files are correctly formatted. See the [pre-commit hook installation guide](docs/pre-commit-hook-setup.md) for instructions on how to install the hook.
|
||||
|
||||
4. **Compilation**
|
||||
|
||||
@@ -67,6 +60,6 @@ After the experimental query is merged, we welcome pull requests to improve it.
|
||||
|
||||
## Using your personal data
|
||||
|
||||
If you contribute to this project, we will record your name and email address (as provided by you with your contributions) as part of the code repositories, which are public. We might also use this information to contact you in relation to your contributions, as well as in the normal course of software development. We also store records of CLA agreements signed in the past, but no longer require contributors to sign a CLA. Under GDPR legislation, we do this on the basis of our legitimate interest in creating the CodeQL product.
|
||||
If you contribute to this project, we will record your name and email address (as provided by you with your contributions) as part of the code repositories, which are public. We might also use this information to contact you in relation to your contributions, as well as in the normal course of software development. We also store records of CLA agreements signed in the past, but no longer require contributors to sign a CLA. Under GDPR legislation, we do this on the basis of our legitimate interest in creating the CodeQL product.
|
||||
|
||||
Please do get in touch (privacy@github.com) if you have any questions about this or our data protection policies.
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import cp from "child_process";
|
||||
function* walk(dir) {
|
||||
for (const file of fs.readdirSync(dir)) {
|
||||
const filePath = path.join(dir, file);
|
||||
if (fs.statSync(filePath).isDirectory()) {
|
||||
yield* walk(filePath);
|
||||
} else {
|
||||
yield filePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function* deprecatedFiles(dir) {
|
||||
for (const file of walk(dir)) {
|
||||
if (file.endsWith(".ql") || file.endsWith(".qll")) {
|
||||
const contents = fs.readFileSync(file, "utf8");
|
||||
if (/\sdeprecated\s/.test(contents)) {
|
||||
yield file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const blameRegExp =
|
||||
/^(\^?\w+)\s.+\s+(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} (?:\+|-)\d{4})\s+(\d+)\).*$/;
|
||||
|
||||
function* deprecationMessages(dir) {
|
||||
for (const file of deprecatedFiles(dir)) {
|
||||
const blame = cp.execFileSync("git", ["blame", "--", file]);
|
||||
const lines = blame.toString().split("\n");
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
if (line.includes(" deprecated ")) {
|
||||
try {
|
||||
const [_, sha, time, lineNumber] = line.match(blameRegExp);
|
||||
const date = new Date(time);
|
||||
// check if it's within the last 14 months (a year, plus 2 months for safety, in case a PR was delayed)
|
||||
if (date.getTime() >= Date.now() - 14 * 31 * 24 * 60 * 60 * 1000) {
|
||||
continue;
|
||||
}
|
||||
const message = `${file}:${lineNumber} was last updated on ${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
|
||||
yield [message, date];
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.log("----");
|
||||
console.log(line);
|
||||
console.log("----");
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
[...deprecationMessages(".")]
|
||||
.sort((a, b) => a[1].getTime() - b[1].getTime())
|
||||
.forEach((msg) => console.log(msg[0]));
|
||||
@@ -7,7 +7,6 @@
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll",
|
||||
@@ -27,8 +26,7 @@
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll"
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll"
|
||||
],
|
||||
"DataFlow Java/C++/C#/Python Common": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
|
||||
@@ -55,8 +53,7 @@
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking4/TaintTrackingImpl.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforlibraries/TaintTrackingImpl.qll"
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
|
||||
],
|
||||
"DataFlow Java/C++/C#/Python Consistency checks": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll",
|
||||
@@ -75,14 +72,6 @@
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
|
||||
],
|
||||
"Model as Data Generation Java/C# - Utils": [
|
||||
"java/ql/src/utils/model-generator/ModelGeneratorUtils.qll",
|
||||
"csharp/ql/src/utils/model-generator/ModelGeneratorUtils.qll"
|
||||
],
|
||||
"Model as Data Generation Java/C# - SummaryModels": [
|
||||
"java/ql/src/utils/model-generator/CaptureSummaryModels.qll",
|
||||
"csharp/ql/src/utils/model-generator/CaptureSummaryModels.qll"
|
||||
],
|
||||
"Sign Java/C#": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll"
|
||||
@@ -436,6 +425,7 @@
|
||||
"python/ql/src/Lexical/CommentedOutCodeMetricOverview.inc.qhelp"
|
||||
],
|
||||
"FLinesOfDuplicatedCodeCommon.inc.qhelp": [
|
||||
"cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.inc.qhelp",
|
||||
"java/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.inc.qhelp",
|
||||
"javascript/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.inc.qhelp",
|
||||
"python/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.inc.qhelp"
|
||||
@@ -474,8 +464,7 @@
|
||||
],
|
||||
"SensitiveDataHeuristics Python/JS": [
|
||||
"javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll",
|
||||
"python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll"
|
||||
"python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll"
|
||||
],
|
||||
"ReDoS Util Python/JS/Ruby": [
|
||||
"javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll",
|
||||
@@ -511,19 +500,5 @@
|
||||
"javascript/ql/lib/tutorial.qll",
|
||||
"python/ql/lib/tutorial.qll",
|
||||
"ruby/ql/lib/tutorial.qll"
|
||||
],
|
||||
"AccessPathSyntax": [
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/AccessPathSyntax.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/AccessPathSyntax.qll",
|
||||
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/AccessPathSyntax.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/AccessPathSyntax.qll"
|
||||
],
|
||||
"Hostname Regexp queries": [
|
||||
"javascript/ql/src/Security/CWE-020/HostnameRegexpShared.qll",
|
||||
"ruby/ql/src/queries/security/cwe-020/HostnameRegexpShared.qll"
|
||||
],
|
||||
"ApiGraphModels": [
|
||||
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll",
|
||||
"ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Autobuild.Cpp</AssemblyName>
|
||||
<RootNamespace>Semmle.Autobuild.Cpp</RootNamespace>
|
||||
<ApplicationIcon />
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
+ semmlecode-cpp-queries/Critical/NewArrayDeleteMismatch.ql: /Correctness/Common Errors
|
||||
+ semmlecode-cpp-queries/Critical/NewDeleteArrayMismatch.ql: /Correctness/Common Errors
|
||||
+ semmlecode-cpp-queries/Critical/NewFreeMismatch.ql: /Correctness/Common Errors
|
||||
+ semmlecode-cpp-queries/Likely Bugs/Memory Management/UsingExpiredStackAddress.ql: /Correctness/Common Errors
|
||||
# Use of Libraries
|
||||
+ semmlecode-cpp-queries/Likely Bugs/Memory Management/SuspiciousCallToMemset.ql: /Correctness/Use of Libraries
|
||||
+ semmlecode-cpp-queries/Likely Bugs/Memory Management/SuspiciousSizeof.ql: /Correctness/Use of Libraries
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
+ semmlecode-cpp-queries/Critical/NewArrayDeleteMismatch.ql: /Correctness/Common Errors
|
||||
+ semmlecode-cpp-queries/Critical/NewDeleteArrayMismatch.ql: /Correctness/Common Errors
|
||||
+ semmlecode-cpp-queries/Critical/NewFreeMismatch.ql: /Correctness/Common Errors
|
||||
+ semmlecode-cpp-queries/Likely Bugs/Memory Management/UsingExpiredStackAddress.ql: /Correctness/Common Errors
|
||||
# Exceptions
|
||||
+ semmlecode-cpp-queries/Best Practices/Exceptions/AccidentalRethrow.ql: /Correctness/Exceptions
|
||||
+ semmlecode-cpp-queries/Best Practices/Exceptions/CatchingByValue.ql: /Correctness/Exceptions
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
@name Badly bounded write (CWE-120)
|
||||
+ semmlecode-cpp-queries/Security/CWE/CWE-120/OverrunWrite.ql: /CWE/CWE-120
|
||||
@name Potentially overrunning write (CWE-120)
|
||||
+ semmlecode-cpp-queries/Security/CWE/CWE-120/VeryLikelyOverrunWrite.ql: /CWE/CWE-120
|
||||
@name Likely overrunning write
|
||||
+ semmlecode-cpp-queries/Security/CWE/CWE-120/OverrunWriteFloat.ql: /CWE/CWE-120
|
||||
@name Potentially overrunning write with float to string conversion (CWE-120)
|
||||
+ semmlecode-cpp-queries/Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.ql: /CWE/CWE-120
|
||||
@name Array offset used before range check (CWE-120)
|
||||
+ semmlecode-cpp-queries/Likely Bugs/Memory Management/UnsafeUseOfStrcat.ql: /CWE/CWE-120
|
||||
@name Potentially unsafe use of strcat (CWE-120)
|
||||
@name Potentially unsafe use of strcat (CWE-120)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
description: Remove unused legacy relations
|
||||
compatibility: backwards
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
description: Add relation for tracking variables from structured binding declarations
|
||||
compatibility: full
|
||||
is_structured_binding.rel: delete
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
description: Remove uniqueness constraint from the uuid property
|
||||
compatibility: full
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
||||
name: codeql/cpp-downgrades
|
||||
groups: cpp
|
||||
downgrades: .
|
||||
library: true
|
||||
@@ -1,6 +1,4 @@
|
||||
name: codeql/cpp-examples
|
||||
groups:
|
||||
- cpp
|
||||
- examples
|
||||
version: 0.0.2
|
||||
dependencies:
|
||||
codeql/cpp-all: "*"
|
||||
|
||||
@@ -1,56 +1,3 @@
|
||||
## 0.0.13
|
||||
|
||||
## 0.0.12
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The flow state variants of `isBarrier` and `isAdditionalFlowStep` are no longer exposed in the taint tracking library. The `isSanitizer` and `isAdditionalTaintStep` predicates should be used instead.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide.
|
||||
The old name still exists as a deprecated alias.
|
||||
|
||||
### New Features
|
||||
|
||||
* The data flow and taint tracking libraries have been extended with versions of `isBarrierIn`, `isBarrierOut`, and `isBarrierGuard`, respectively `isSanitizerIn`, `isSanitizerOut`, and `isSanitizerGuard`, that support flow states.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* `DefaultOptions::exits` now holds for C11 functions with the `_Noreturn` or `noreturn` specifier.
|
||||
* `hasImplicitCopyConstructor` and `hasImplicitCopyAssignmentOperator` now correctly handle implicitly-deleted operators in templates.
|
||||
* All deprecated predicates/classes/modules that have been deprecated for over a year have been deleted.
|
||||
|
||||
## 0.0.11
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Many queries now support structured bindings, as structured bindings are now handled in the IR translation.
|
||||
|
||||
## 0.0.10
|
||||
|
||||
### New Features
|
||||
|
||||
* Added a `isStructuredBinding` predicate to the `Variable` class which holds when the variable is declared as part of a structured binding declaration.
|
||||
|
||||
## 0.0.9
|
||||
|
||||
|
||||
## 0.0.8
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The `codeql/cpp-upgrades` CodeQL pack has been removed. All upgrades scripts have been merged into the `codeql/cpp-all` CodeQL pack.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* `FormatLiteral::getMaxConvertedLength` now uses range analysis to provide a
|
||||
more accurate length for integers formatted with `%x`
|
||||
|
||||
## 0.0.7
|
||||
|
||||
## 0.0.6
|
||||
|
||||
## 0.0.5
|
||||
|
||||
## 0.0.4
|
||||
|
||||
@@ -54,13 +54,11 @@ class Options extends string {
|
||||
*
|
||||
* By default, this holds for `exit`, `_exit`, `abort`, `__assert_fail`,
|
||||
* `longjmp`, `__builtin_unreachable` and any function with a
|
||||
* `noreturn` attribute or specifier.
|
||||
* `noreturn` attribute.
|
||||
*/
|
||||
predicate exits(Function f) {
|
||||
f.getAnAttribute().hasName("noreturn")
|
||||
or
|
||||
f.getASpecifier().hasName("noreturn")
|
||||
or
|
||||
f.hasGlobalOrStdName([
|
||||
"exit", "_exit", "abort", "__assert_fail", "longjmp", "__builtin_unreachable"
|
||||
])
|
||||
|
||||
@@ -39,7 +39,7 @@ class CustomOptions extends Options {
|
||||
*
|
||||
* By default, this holds for `exit`, `_exit`, `abort`, `__assert_fail`,
|
||||
* `longjmp`, `error`, `__builtin_unreachable` and any function with a
|
||||
* `noreturn` attribute or specifier.
|
||||
* `noreturn` attribute.
|
||||
*/
|
||||
override predicate exits(Function f) { Options.super.exits(f) }
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
## 0.0.10
|
||||
|
||||
### New Features
|
||||
|
||||
* Added a `isStructuredBinding` predicate to the `Variable` class which holds when the variable is declared as part of a structured binding declaration.
|
||||
@@ -1,5 +0,0 @@
|
||||
## 0.0.11
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Many queries now support structured bindings, as structured bindings are now handled in the IR translation.
|
||||
@@ -1,20 +0,0 @@
|
||||
## 0.0.12
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The flow state variants of `isBarrier` and `isAdditionalFlowStep` are no longer exposed in the taint tracking library. The `isSanitizer` and `isAdditionalTaintStep` predicates should be used instead.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide.
|
||||
The old name still exists as a deprecated alias.
|
||||
|
||||
### New Features
|
||||
|
||||
* The data flow and taint tracking libraries have been extended with versions of `isBarrierIn`, `isBarrierOut`, and `isBarrierGuard`, respectively `isSanitizerIn`, `isSanitizerOut`, and `isSanitizerGuard`, that support flow states.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* `DefaultOptions::exits` now holds for C11 functions with the `_Noreturn` or `noreturn` specifier.
|
||||
* `hasImplicitCopyConstructor` and `hasImplicitCopyAssignmentOperator` now correctly handle implicitly-deleted operators in templates.
|
||||
* All deprecated predicates/classes/modules that have been deprecated for over a year have been deleted.
|
||||
@@ -1 +0,0 @@
|
||||
## 0.0.13
|
||||
@@ -1 +0,0 @@
|
||||
## 0.0.6
|
||||
@@ -1 +0,0 @@
|
||||
## 0.0.7
|
||||
@@ -1,10 +0,0 @@
|
||||
## 0.0.8
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The `codeql/cpp-upgrades` CodeQL pack has been removed. All upgrades scripts have been merged into the `codeql/cpp-all` CodeQL pack.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* `FormatLiteral::getMaxConvertedLength` now uses range analysis to provide a
|
||||
more accurate length for integers formatted with `%x`
|
||||
@@ -1,2 +0,0 @@
|
||||
## 0.0.9
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.13
|
||||
lastReleaseVersion: 0.0.5
|
||||
|
||||
@@ -69,4 +69,6 @@ import semmle.code.cpp.Comments
|
||||
import semmle.code.cpp.Preprocessor
|
||||
import semmle.code.cpp.Iteration
|
||||
import semmle.code.cpp.NameQualifiers
|
||||
import semmle.code.cpp.ObjectiveC
|
||||
import semmle.code.cpp.exprs.ObjectiveC
|
||||
import DefaultOptions
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.0.14-dev
|
||||
version: 0.0.6-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -111,6 +111,24 @@ class Class extends UserType {
|
||||
result = this.getCanonicalMember(index).(TemplateVariable).getAnInstantiation()
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getCanonicalMember(int)` or `getAMember(int)` instead.
|
||||
* Gets the `index`th member of this class.
|
||||
*/
|
||||
deprecated Declaration getMember(int index) {
|
||||
member(underlyingElement(this), index, unresolveElement(result))
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: As this includes a somewhat arbitrary number of
|
||||
* template instantiations, it is unlikely to do what
|
||||
* you need.
|
||||
* Gets the number of members that this class has. This includes both
|
||||
* templates that are in this class, and instantiations of those
|
||||
* templates.
|
||||
*/
|
||||
deprecated int getNumMember() { result = count(this.getAMember()) }
|
||||
|
||||
/**
|
||||
* Gets a private member declared in this class, struct or union.
|
||||
* For template members, this may be either the template or an
|
||||
@@ -188,7 +206,26 @@ class Class extends UserType {
|
||||
* it is callable by a particular caller. For C++11, there's also a question
|
||||
* of whether to include members that are defaulted or deleted.
|
||||
*/
|
||||
deprecated predicate hasCopyConstructor() { this.getAMemberFunction() instanceof CopyConstructor }
|
||||
deprecated predicate hasCopyConstructor() {
|
||||
exists(CopyConstructor cc | cc = this.getAMemberFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this class has a copy assignment operator that is either
|
||||
* explicitly declared (though possibly `= delete`) or is auto-generated,
|
||||
* non-trivial and called from somewhere.
|
||||
*
|
||||
* DEPRECATED: There is more than one reasonable definition of what it means
|
||||
* to have a copy assignment operator, and we do not want to promote one
|
||||
* particular definition by naming it with this predicate. Having a copy
|
||||
* assignment operator could mean that such a member is declared or defined
|
||||
* in the source or that it is callable by a particular caller. For C++11,
|
||||
* there's also a question of whether to include members that are defaulted
|
||||
* or deleted.
|
||||
*/
|
||||
deprecated predicate hasCopyAssignmentOperator() {
|
||||
exists(CopyAssignmentOperator coa | coa = this.getAMemberFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
* Like accessOfBaseMember but returns multiple results if there are multiple
|
||||
@@ -251,16 +288,6 @@ class Class extends UserType {
|
||||
not this.implicitCopyConstructorDeleted() and
|
||||
forall(CopyConstructor cc | cc = this.getAMemberFunction() |
|
||||
cc.isCompilerGenerated() and not cc.isDeleted()
|
||||
) and
|
||||
(
|
||||
not this instanceof ClassTemplateInstantiation
|
||||
or
|
||||
this.(ClassTemplateInstantiation).getTemplate().hasImplicitCopyConstructor()
|
||||
) and
|
||||
(
|
||||
not this instanceof PartialClassTemplateSpecialization
|
||||
or
|
||||
this.(PartialClassTemplateSpecialization).getPrimaryTemplate().hasImplicitCopyConstructor()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -276,18 +303,6 @@ class Class extends UserType {
|
||||
not this.implicitCopyAssignmentOperatorDeleted() and
|
||||
forall(CopyAssignmentOperator ca | ca = this.getAMemberFunction() |
|
||||
ca.isCompilerGenerated() and not ca.isDeleted()
|
||||
) and
|
||||
(
|
||||
not this instanceof ClassTemplateInstantiation
|
||||
or
|
||||
this.(ClassTemplateInstantiation).getTemplate().hasImplicitCopyAssignmentOperator()
|
||||
) and
|
||||
(
|
||||
not this instanceof PartialClassTemplateSpecialization
|
||||
or
|
||||
this.(PartialClassTemplateSpecialization)
|
||||
.getPrimaryTemplate()
|
||||
.hasImplicitCopyAssignmentOperator()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -872,7 +887,7 @@ class NestedClass extends Class {
|
||||
* pure virtual function.
|
||||
*/
|
||||
class AbstractClass extends Class {
|
||||
AbstractClass() { this.getAMemberFunction() instanceof PureVirtualFunction }
|
||||
AbstractClass() { exists(PureVirtualFunction f | this.getAMemberFunction() = f) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AbstractClass" }
|
||||
}
|
||||
@@ -1057,6 +1072,31 @@ class PartialClassTemplateSpecialization extends ClassTemplateSpecialization {
|
||||
override string getAPrimaryQlClass() { result = "PartialClassTemplateSpecialization" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An "interface" is a class that only contains pure virtual functions (and contains
|
||||
* at least one such function). For example:
|
||||
* ```
|
||||
* class MyInterfaceClass {
|
||||
* public:
|
||||
* virtual void myMethod1() = 0;
|
||||
* virtual void myMethod2() = 0;
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* DEPRECATED: This class is considered to be too specific for general usage.
|
||||
*/
|
||||
deprecated class Interface extends Class {
|
||||
Interface() {
|
||||
forex(Declaration m |
|
||||
m.getDeclaringType() = this.getABaseClass*() and not compgenerated(unresolveElement(m))
|
||||
|
|
||||
m instanceof PureVirtualFunction
|
||||
)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Interface" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A class/struct derivation that is virtual. For example the derivation in
|
||||
* the following code is a `VirtualClassDerivation`:
|
||||
|
||||
@@ -55,6 +55,9 @@ class ElementBase extends @element {
|
||||
cached
|
||||
string toString() { none() }
|
||||
|
||||
/** DEPRECATED: use `getAPrimaryQlClass` instead. */
|
||||
deprecated string getCanonicalQLClass() { result = this.getAPrimaryQlClass() }
|
||||
|
||||
/**
|
||||
* Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs.
|
||||
*/
|
||||
@@ -88,6 +91,13 @@ class Element extends ElementBase {
|
||||
*/
|
||||
predicate fromSource() { this.getFile().fromSource() }
|
||||
|
||||
/**
|
||||
* Holds if this element may be from a library.
|
||||
*
|
||||
* DEPRECATED: always true.
|
||||
*/
|
||||
deprecated predicate fromLibrary() { this.getFile().fromLibrary() }
|
||||
|
||||
/** Gets the primary location of this element. */
|
||||
Location getLocation() { none() }
|
||||
|
||||
|
||||
@@ -196,11 +196,31 @@ class Folder extends Container, @folder {
|
||||
*/
|
||||
deprecated string getName() { folders(underlyingElement(this), result) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getAbsolutePath` instead.
|
||||
* Holds if this element is named `name`.
|
||||
*/
|
||||
deprecated predicate hasName(string name) { name = this.getName() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getAbsolutePath` instead.
|
||||
* Gets the full name of this folder.
|
||||
*/
|
||||
deprecated string getFullName() { result = this.getName() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getBaseName` instead.
|
||||
* Gets the last part of the folder name.
|
||||
*/
|
||||
deprecated string getShortName() { result = this.getBaseName() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getParentContainer` instead.
|
||||
* Gets the parent folder.
|
||||
*/
|
||||
deprecated Folder getParent() {
|
||||
containerparent(unresolveElement(result), underlyingElement(this))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,6 +308,13 @@ class File extends Container, @file {
|
||||
*/
|
||||
override predicate fromSource() { numlines(underlyingElement(this), _, _, _) }
|
||||
|
||||
/**
|
||||
* Holds if this file may be from a library.
|
||||
*
|
||||
* DEPRECATED: For historical reasons this is true for any file.
|
||||
*/
|
||||
deprecated override predicate fromLibrary() { any() }
|
||||
|
||||
/** Gets the metric file. */
|
||||
MetricFile getMetrics() { result = this }
|
||||
|
||||
@@ -401,3 +428,25 @@ class CppFile extends File {
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CppFile" }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C source file, as determined by file extension.
|
||||
*
|
||||
* For the related notion of whether a file is compiled as Objective C
|
||||
* code, use `File.compiledAsObjC`.
|
||||
*/
|
||||
deprecated class ObjCFile extends File {
|
||||
ObjCFile() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C++ source file, as determined by file extension.
|
||||
*
|
||||
* For the related notion of whether a file is compiled as Objective C++
|
||||
* code, use `File.compiledAsObjCpp`.
|
||||
*/
|
||||
deprecated class ObjCppFile extends File {
|
||||
ObjCppFile() { none() }
|
||||
}
|
||||
|
||||
@@ -105,6 +105,25 @@ class Location extends @location {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Location` instead.
|
||||
* A location of an element. Not used for expressions or statements, which
|
||||
* instead use LocationExpr and LocationStmt respectively.
|
||||
*/
|
||||
deprecated library class LocationDefault extends Location, @location_default { }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Location` instead.
|
||||
* A location of a statement.
|
||||
*/
|
||||
deprecated library class LocationStmt extends Location, @location_stmt { }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Location` instead.
|
||||
* A location of an expression.
|
||||
*/
|
||||
deprecated library class LocationExpr extends Location, @location_expr { }
|
||||
|
||||
/**
|
||||
* Gets the length of the longest line in file `f`.
|
||||
*/
|
||||
|
||||
@@ -30,6 +30,16 @@ class Macro extends PreprocessorDirective, @ppd_define {
|
||||
else result = "#define " + this.getHead() + " " + this.getBody()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the body of the macro starts with an unmatched closing
|
||||
* parenthesis. For example:
|
||||
*
|
||||
* #define RPAREN() )
|
||||
*
|
||||
* DEPRECATED: This predicate has a misleading name.
|
||||
*/
|
||||
deprecated predicate isFunctionLike() { this.getBody().regexpMatch("[^(]*\\).*") }
|
||||
|
||||
/**
|
||||
* Gets the name of the macro. For example, `MAX` in
|
||||
* `#define MAX(x,y) (((x)>(y))?(x):(y))`.
|
||||
@@ -251,6 +261,46 @@ class MacroInvocation extends MacroAccess {
|
||||
string getExpandedArgument(int i) { macro_argument_expanded(underlyingElement(this), i, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A top-level expression generated by a macro invocation.
|
||||
*
|
||||
* DEPRECATED: Use `MacroInvocation.getExpr()` directly to get an
|
||||
* expression generated at the top-level of a macro invocation. Use
|
||||
* `MacroInvocation.getAnAffectedElement()` to get any element generated
|
||||
* by a macro invocation.
|
||||
*/
|
||||
deprecated class MacroInvocationExpr extends Expr {
|
||||
MacroInvocationExpr() { exists(MacroInvocation i | this = i.getExpr()) }
|
||||
|
||||
/**
|
||||
* Gets the macro invocation of which this is the top-level expression.
|
||||
*/
|
||||
MacroInvocation getInvocation() { result.getExpr() = this }
|
||||
|
||||
/** Gets the name of the invoked macro. */
|
||||
string getMacroName() { result = this.getInvocation().getMacroName() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A top-level statement generated by a macro invocation.
|
||||
*
|
||||
* DEPRECATED: Use `MacroInvocation.getStmt()` directly to get a
|
||||
* statement generated at the top-level of a macro invocation. Use
|
||||
* `MacroInvocation.getAnAffectedElement()` to get any element generated
|
||||
* by a macro invocation.
|
||||
*/
|
||||
deprecated class MacroInvocationStmt extends Stmt {
|
||||
MacroInvocationStmt() { exists(MacroInvocation i | this = i.getStmt()) }
|
||||
|
||||
/**
|
||||
* Gets the macro invocation of which this is the top-level statement.
|
||||
*/
|
||||
MacroInvocation getInvocation() { result.getStmt() = this }
|
||||
|
||||
/** Gets the name of the invoked macro. */
|
||||
string getMacroName() { result = this.getInvocation().getMacroName() }
|
||||
}
|
||||
|
||||
/** Holds if `l` is the location of a macro. */
|
||||
predicate macroLocation(Location l) { macrolocationbind(_, l) }
|
||||
|
||||
|
||||
@@ -233,6 +233,40 @@ class ImplicitConversionFunction extends MemberFunction {
|
||||
Type getDestType() { none() } // overridden in subclasses
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: as of C++11 this class does not correspond perfectly with the
|
||||
* language definition of a converting constructor.
|
||||
*
|
||||
* A C++ constructor that also defines an implicit conversion. For example the
|
||||
* function `MyClass` in the following code is a `ConversionConstructor`:
|
||||
* ```
|
||||
* class MyClass {
|
||||
* public:
|
||||
* MyClass(const MyOtherClass &from) {
|
||||
* ...
|
||||
* }
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
deprecated class ConversionConstructor extends Constructor, ImplicitConversionFunction {
|
||||
ConversionConstructor() {
|
||||
strictcount(Parameter p | p = this.getAParameter() and not p.hasInitializer()) = 1 and
|
||||
not this.hasSpecifier("explicit")
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
not this instanceof CopyConstructor and
|
||||
not this instanceof MoveConstructor and
|
||||
result = "ConversionConstructor"
|
||||
}
|
||||
|
||||
/** Gets the type this `ConversionConstructor` takes as input. */
|
||||
override Type getSourceType() { result = this.getParameter(0).getType() }
|
||||
|
||||
/** Gets the type this `ConversionConstructor` is a constructor of. */
|
||||
override Type getDestType() { result = this.getDeclaringType() }
|
||||
}
|
||||
|
||||
private predicate hasCopySignature(MemberFunction f) {
|
||||
f.getParameter(0).getUnspecifiedType().(LValueReferenceType).getBaseType() = f.getDeclaringType()
|
||||
}
|
||||
|
||||
@@ -86,6 +86,13 @@ class Namespace extends NameQualifyingElement, @namespace {
|
||||
/** Holds if this namespace may be from source. */
|
||||
override predicate fromSource() { this.getADeclaration().fromSource() }
|
||||
|
||||
/**
|
||||
* Holds if this namespace is in a library.
|
||||
*
|
||||
* DEPRECATED: never holds.
|
||||
*/
|
||||
deprecated override predicate fromLibrary() { not this.fromSource() }
|
||||
|
||||
/** Gets the metric namespace. */
|
||||
MetricNamespace getMetrics() { result = this }
|
||||
|
||||
@@ -226,6 +233,11 @@ class GlobalNamespace extends Namespace {
|
||||
|
||||
override Namespace getParentNamespace() { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getName()`.
|
||||
*/
|
||||
deprecated string getFullName() { result = this.getName() }
|
||||
|
||||
override string getFriendlyName() { result = "(global namespace)" }
|
||||
}
|
||||
|
||||
|
||||
196
cpp/ql/lib/semmle/code/cpp/ObjectiveC.qll
Normal file
196
cpp/ql/lib/semmle/code/cpp/ObjectiveC.qll
Normal file
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Class
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C class.
|
||||
*/
|
||||
deprecated class ObjectiveClass extends Class {
|
||||
ObjectiveClass() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C protocol.
|
||||
*/
|
||||
deprecated class Protocol extends Class {
|
||||
Protocol() { none() }
|
||||
|
||||
/**
|
||||
* Holds if the type implements the protocol, either because the type
|
||||
* itself does, or because it is a type conforming to the protocol.
|
||||
*/
|
||||
predicate isImplementedBy(Type t) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* A type which conforms to a protocol. Use `getAProtocol` to get a
|
||||
* protocol that this type conforms to.
|
||||
*/
|
||||
deprecated class TypeConformingToProtocol extends DerivedType {
|
||||
TypeConformingToProtocol() { none() }
|
||||
|
||||
/** Gets a protocol that this type conforms to. */
|
||||
Protocol getAProtocol() { none() }
|
||||
|
||||
/** Gets the size of this type. */
|
||||
override int getSize() { none() }
|
||||
|
||||
override int getAlignment() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C `@autoreleasepool` statement, for example
|
||||
* `@autoreleasepool { int x; int y; }`.
|
||||
*/
|
||||
deprecated class AutoReleasePoolStmt extends Stmt {
|
||||
AutoReleasePoolStmt() { none() }
|
||||
|
||||
override string toString() { none() }
|
||||
|
||||
/** Gets the body statement of this `@autoreleasepool` statement. */
|
||||
Stmt getStmt() { none() }
|
||||
|
||||
override predicate mayBeImpure() { none() }
|
||||
|
||||
override predicate mayBeGloballyImpure() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C `@synchronized statement`, for example
|
||||
* `@synchronized (x) { [x complicationOperation]; }`.
|
||||
*/
|
||||
deprecated class SynchronizedStmt extends Stmt {
|
||||
SynchronizedStmt() { none() }
|
||||
|
||||
override string toString() { none() }
|
||||
|
||||
/** Gets the expression which gives the object to be locked. */
|
||||
Expr getLockedObject() { none() }
|
||||
|
||||
/** Gets the body statement of this `@synchronized` statement. */
|
||||
Stmt getStmt() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C for-in statement.
|
||||
*/
|
||||
deprecated class ForInStmt extends Loop {
|
||||
ForInStmt() { none() }
|
||||
|
||||
/**
|
||||
* Gets the condition expression of the `while` statement that the
|
||||
* `for...in` statement desugars into.
|
||||
*/
|
||||
override Expr getCondition() { none() }
|
||||
|
||||
override Expr getControllingExpr() { none() }
|
||||
|
||||
/** Gets the collection that the loop iterates over. */
|
||||
Expr getCollection() { none() }
|
||||
|
||||
/** Gets the body of the loop. */
|
||||
override Stmt getStmt() { none() }
|
||||
|
||||
override string toString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C category or class extension.
|
||||
*/
|
||||
deprecated class Category extends Class {
|
||||
Category() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C class extension.
|
||||
*/
|
||||
deprecated class ClassExtension extends Category {
|
||||
ClassExtension() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C try statement.
|
||||
*/
|
||||
deprecated class ObjcTryStmt extends TryStmt {
|
||||
ObjcTryStmt() { none() }
|
||||
|
||||
override string toString() { none() }
|
||||
|
||||
/** Gets the finally clause of this try statement, if any. */
|
||||
FinallyBlock getFinallyClause() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C `@finally` block.
|
||||
*/
|
||||
deprecated class FinallyBlock extends BlockStmt {
|
||||
FinallyBlock() { none() }
|
||||
|
||||
/** Gets the try statement corresponding to this finally block. */
|
||||
ObjcTryStmt getTryStmt() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
* An Objective C `@property`.
|
||||
*/
|
||||
deprecated class Property extends Declaration {
|
||||
Property() { none() }
|
||||
|
||||
/** Gets the name of this property. */
|
||||
override string getName() { none() }
|
||||
|
||||
/**
|
||||
* Gets nothing (provided for compatibility with Declaration).
|
||||
*
|
||||
* For the attribute list following the `@property` keyword, use
|
||||
* `getAnAttribute()`.
|
||||
*/
|
||||
override Specifier getASpecifier() { none() }
|
||||
|
||||
/**
|
||||
* Gets an attribute of this property (such as `readonly`, `nonatomic`,
|
||||
* or `getter=isEnabled`).
|
||||
*/
|
||||
Attribute getAnAttribute() { none() }
|
||||
|
||||
override Location getADeclarationLocation() { result = getLocation() }
|
||||
|
||||
override Location getDefinitionLocation() { result = getLocation() }
|
||||
|
||||
override Location getLocation() { none() }
|
||||
|
||||
/** Gets the type of this property. */
|
||||
Type getType() { none() }
|
||||
|
||||
/**
|
||||
* Gets the instance method which is called to get the value of this
|
||||
* property.
|
||||
*/
|
||||
MemberFunction getGetter() { none() }
|
||||
|
||||
/**
|
||||
* Gets the instance method which is called to set the value of this
|
||||
* property (if it is a writable property).
|
||||
*/
|
||||
MemberFunction getSetter() { none() }
|
||||
|
||||
/**
|
||||
* Gets the instance variable which stores the property value (if this
|
||||
* property was explicitly or automatically `@synthesize`d).
|
||||
*/
|
||||
MemberVariable getInstanceVariable() { none() }
|
||||
}
|
||||
@@ -95,6 +95,22 @@ class Parameter extends LocalScopeVariable, @parameter {
|
||||
else result = this.getADeclarationEntry()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this parameter in the given block (which should be
|
||||
* the body of a function with which the parameter is associated).
|
||||
*
|
||||
* DEPRECATED: this method was used in a previous implementation of
|
||||
* getName, but is no longer in use.
|
||||
*/
|
||||
deprecated string getNameInBlock(BlockStmt b) {
|
||||
exists(ParameterDeclarationEntry pde |
|
||||
pde.getFunctionDeclarationEntry().getBlock() = b and
|
||||
this.getFunction().getBlock() = b and
|
||||
pde.getVariable() = this and
|
||||
result = pde.getName()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this parameter has a name.
|
||||
*
|
||||
|
||||
@@ -8,9 +8,9 @@ private import PrintAST
|
||||
private predicate shouldPrintDeclaration(Declaration decl) {
|
||||
not decl instanceof Function
|
||||
or
|
||||
not exists(PrintAstConfiguration c)
|
||||
not exists(PrintASTConfiguration c)
|
||||
or
|
||||
exists(PrintAstConfiguration config | config.shouldPrintFunction(decl))
|
||||
exists(PrintASTConfiguration config | config.shouldPrintFunction(decl))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,7 +12,7 @@ import PrintAST
|
||||
* Temporarily tweak this class or make a copy to control which functions are
|
||||
* printed.
|
||||
*/
|
||||
class Cfg extends PrintAstConfiguration {
|
||||
class Cfg extends PrintASTConfiguration {
|
||||
/**
|
||||
* TWEAK THIS PREDICATE AS NEEDED.
|
||||
* Holds if the AST for `func` should be printed.
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
import cpp
|
||||
private import semmle.code.cpp.Print
|
||||
|
||||
private newtype TPrintAstConfiguration = MkPrintAstConfiguration()
|
||||
private newtype TPrintASTConfiguration = MkPrintASTConfiguration()
|
||||
|
||||
/**
|
||||
* The query can extend this class to control which functions are printed.
|
||||
*/
|
||||
class PrintAstConfiguration extends TPrintAstConfiguration {
|
||||
class PrintASTConfiguration extends TPrintASTConfiguration {
|
||||
/**
|
||||
* Gets a textual representation of this `PrintASTConfiguration`.
|
||||
*/
|
||||
@@ -27,11 +27,8 @@ class PrintAstConfiguration extends TPrintAstConfiguration {
|
||||
predicate shouldPrintFunction(Function func) { any() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for PrintAstConfiguration */
|
||||
deprecated class PrintASTConfiguration = PrintAstConfiguration;
|
||||
|
||||
private predicate shouldPrintFunction(Function func) {
|
||||
exists(PrintAstConfiguration config | config.shouldPrintFunction(func))
|
||||
exists(PrintASTConfiguration config | config.shouldPrintFunction(func))
|
||||
}
|
||||
|
||||
bindingset[s]
|
||||
@@ -88,8 +85,8 @@ private Function getEnclosingFunction(Locatable ast) {
|
||||
* Most nodes are just a wrapper around `Locatable`, but we do synthesize new
|
||||
* nodes for things like parameter lists and constructor init lists.
|
||||
*/
|
||||
private newtype TPrintAstNode =
|
||||
TAstNode(Locatable ast) { shouldPrintFunction(getEnclosingFunction(ast)) } or
|
||||
private newtype TPrintASTNode =
|
||||
TASTNode(Locatable ast) { shouldPrintFunction(getEnclosingFunction(ast)) } or
|
||||
TDeclarationEntryNode(DeclStmt stmt, DeclarationEntry entry) {
|
||||
// We create a unique node for each pair of (stmt, entry), to avoid having one node with
|
||||
// multiple parents due to extractor bug CPP-413.
|
||||
@@ -109,7 +106,7 @@ private newtype TPrintAstNode =
|
||||
/**
|
||||
* A node in the output tree.
|
||||
*/
|
||||
class PrintAstNode extends TPrintAstNode {
|
||||
class PrintASTNode extends TPrintASTNode {
|
||||
/**
|
||||
* Gets a textual representation of this node in the PrintAST output tree.
|
||||
*/
|
||||
@@ -119,17 +116,17 @@ class PrintAstNode extends TPrintAstNode {
|
||||
* Gets the child node at index `childIndex`. Child indices must be unique,
|
||||
* but need not be contiguous.
|
||||
*/
|
||||
abstract PrintAstNode getChildInternal(int childIndex);
|
||||
abstract PrintASTNode getChildInternal(int childIndex);
|
||||
|
||||
/**
|
||||
* Gets the child node at index `childIndex`.
|
||||
* Adds edges to fully converted expressions, that are not part of the
|
||||
* regular parent/child relation traversal.
|
||||
*/
|
||||
final PrintAstNode getChild(int childIndex) {
|
||||
final PrintASTNode getChild(int childIndex) {
|
||||
// The exact value of `childIndex` doesn't matter, as long as we preserve the correct order.
|
||||
result =
|
||||
rank[childIndex](PrintAstNode child, int nonConvertedIndex, boolean isConverted |
|
||||
rank[childIndex](PrintASTNode child, int nonConvertedIndex, boolean isConverted |
|
||||
childAndAccessorPredicate(child, _, nonConvertedIndex, isConverted)
|
||||
|
|
||||
// Unconverted children come first, then sort by original child index within each group.
|
||||
@@ -141,11 +138,11 @@ class PrintAstNode extends TPrintAstNode {
|
||||
* Gets the node for the `.getFullyConverted()` version of the child originally at index
|
||||
* `childIndex`, if that node has any conversions.
|
||||
*/
|
||||
private PrintAstNode getConvertedChild(int childIndex) {
|
||||
private PrintASTNode getConvertedChild(int childIndex) {
|
||||
exists(Expr expr |
|
||||
expr = getChildInternal(childIndex).(AstNode).getAst() and
|
||||
expr = getChildInternal(childIndex).(ASTNode).getAST() and
|
||||
expr.getFullyConverted() instanceof Conversion and
|
||||
result.(AstNode).getAst() = expr.getFullyConverted() and
|
||||
result.(ASTNode).getAST() = expr.getFullyConverted() and
|
||||
not expr instanceof Conversion
|
||||
)
|
||||
}
|
||||
@@ -169,12 +166,12 @@ class PrintAstNode extends TPrintAstNode {
|
||||
/**
|
||||
* Gets the children of this node.
|
||||
*/
|
||||
final PrintAstNode getAChild() { result = getChild(_) }
|
||||
final PrintASTNode getAChild() { result = getChild(_) }
|
||||
|
||||
/**
|
||||
* Gets the parent of this node, if any.
|
||||
*/
|
||||
final PrintAstNode getParent() { result.getAChild() = this }
|
||||
final PrintASTNode getParent() { result.getAChild() = this }
|
||||
|
||||
/**
|
||||
* Gets the location of this node in the source code.
|
||||
@@ -199,7 +196,7 @@ class PrintAstNode extends TPrintAstNode {
|
||||
* one result tuple, with `isConverted = false`.
|
||||
*/
|
||||
private predicate childAndAccessorPredicate(
|
||||
PrintAstNode child, string childPredicate, int nonConvertedIndex, boolean isConverted
|
||||
PrintASTNode child, string childPredicate, int nonConvertedIndex, boolean isConverted
|
||||
) {
|
||||
child = getChildInternal(nonConvertedIndex) and
|
||||
childPredicate = getChildAccessorPredicateInternal(nonConvertedIndex) and
|
||||
@@ -237,15 +234,12 @@ class PrintAstNode extends TPrintAstNode {
|
||||
private Function getEnclosingFunction() { result = getParent*().(FunctionNode).getFunction() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for PrintAstNode */
|
||||
deprecated class PrintASTNode = PrintAstNode;
|
||||
|
||||
/**
|
||||
* Class that restricts the elements that we compute `qlClass` for.
|
||||
*/
|
||||
private class PrintableElement extends Element {
|
||||
PrintableElement() {
|
||||
exists(TAstNode(this))
|
||||
exists(TASTNode(this))
|
||||
or
|
||||
exists(TDeclarationEntryNode(_, this))
|
||||
or
|
||||
@@ -268,7 +262,7 @@ private string qlClass(PrintableElement el) {
|
||||
/**
|
||||
* A node representing an AST node.
|
||||
*/
|
||||
abstract class BaseAstNode extends PrintAstNode {
|
||||
abstract class BaseASTNode extends PrintASTNode {
|
||||
Locatable ast;
|
||||
|
||||
override string toString() { result = qlClass(ast) + ast.toString() }
|
||||
@@ -278,34 +272,25 @@ abstract class BaseAstNode extends PrintAstNode {
|
||||
/**
|
||||
* Gets the AST represented by this node.
|
||||
*/
|
||||
final Locatable getAst() { result = ast }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Locatable getAST() { result = getAst() }
|
||||
final Locatable getAST() { result = ast }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for BaseAstNode */
|
||||
deprecated class BaseASTNode = BaseAstNode;
|
||||
|
||||
/**
|
||||
* A node representing an AST node other than a `DeclarationEntry`.
|
||||
*/
|
||||
abstract class AstNode extends BaseAstNode, TAstNode {
|
||||
AstNode() { this = TAstNode(ast) }
|
||||
abstract class ASTNode extends BaseASTNode, TASTNode {
|
||||
ASTNode() { this = TASTNode(ast) }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for AstNode */
|
||||
deprecated class ASTNode = AstNode;
|
||||
|
||||
/**
|
||||
* A node representing an `Expr`.
|
||||
*/
|
||||
class ExprNode extends AstNode {
|
||||
class ExprNode extends ASTNode {
|
||||
Expr expr;
|
||||
|
||||
ExprNode() { expr = ast }
|
||||
|
||||
override AstNode getChildInternal(int childIndex) { result.getAst() = expr.getChild(childIndex) }
|
||||
override ASTNode getChildInternal(int childIndex) { result.getAST() = expr.getChild(childIndex) }
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = super.getProperty(key)
|
||||
@@ -321,7 +306,7 @@ class ExprNode extends AstNode {
|
||||
}
|
||||
|
||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
result = getChildAccessorWithoutConversions(ast, getChildInternal(childIndex).getAst())
|
||||
result = getChildAccessorWithoutConversions(ast, getChildInternal(childIndex).getAST())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,9 +334,9 @@ class ConversionNode extends ExprNode {
|
||||
|
||||
ConversionNode() { conv = expr }
|
||||
|
||||
override AstNode getChildInternal(int childIndex) {
|
||||
override ASTNode getChildInternal(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result.getAst() = conv.getExpr() and
|
||||
result.getAST() = conv.getExpr() and
|
||||
conv.getExpr() instanceof Conversion
|
||||
}
|
||||
}
|
||||
@@ -378,27 +363,27 @@ class CastNode extends ConversionNode {
|
||||
class StmtExprNode extends ExprNode {
|
||||
override StmtExpr expr;
|
||||
|
||||
override AstNode getChildInternal(int childIndex) {
|
||||
override ASTNode getChildInternal(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result.getAst() = expr.getStmt()
|
||||
result.getAST() = expr.getStmt()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `DeclarationEntry`.
|
||||
*/
|
||||
class DeclarationEntryNode extends BaseAstNode, TDeclarationEntryNode {
|
||||
class DeclarationEntryNode extends BaseASTNode, TDeclarationEntryNode {
|
||||
override DeclarationEntry ast;
|
||||
DeclStmt declStmt;
|
||||
|
||||
DeclarationEntryNode() { this = TDeclarationEntryNode(declStmt, ast) }
|
||||
|
||||
override PrintAstNode getChildInternal(int childIndex) { none() }
|
||||
override PrintASTNode getChildInternal(int childIndex) { none() }
|
||||
|
||||
override string getChildAccessorPredicateInternal(int childIndex) { none() }
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = BaseAstNode.super.getProperty(key)
|
||||
result = BaseASTNode.super.getProperty(key)
|
||||
or
|
||||
key = "Type" and
|
||||
result = qlClass(ast.getType()) + ast.getType().toString()
|
||||
@@ -411,9 +396,9 @@ class DeclarationEntryNode extends BaseAstNode, TDeclarationEntryNode {
|
||||
class VariableDeclarationEntryNode extends DeclarationEntryNode {
|
||||
override VariableDeclarationEntry ast;
|
||||
|
||||
override AstNode getChildInternal(int childIndex) {
|
||||
override ASTNode getChildInternal(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result.getAst() = ast.getVariable().getInitializer()
|
||||
result.getAST() = ast.getVariable().getInitializer()
|
||||
}
|
||||
|
||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
@@ -425,23 +410,23 @@ class VariableDeclarationEntryNode extends DeclarationEntryNode {
|
||||
/**
|
||||
* A node representing a `Stmt`.
|
||||
*/
|
||||
class StmtNode extends AstNode {
|
||||
class StmtNode extends ASTNode {
|
||||
Stmt stmt;
|
||||
|
||||
StmtNode() { stmt = ast }
|
||||
|
||||
override BaseAstNode getChildInternal(int childIndex) {
|
||||
override BaseASTNode getChildInternal(int childIndex) {
|
||||
exists(Locatable child |
|
||||
child = stmt.getChild(childIndex) and
|
||||
(
|
||||
result.getAst() = child.(Expr) or
|
||||
result.getAst() = child.(Stmt)
|
||||
result.getAST() = child.(Expr) or
|
||||
result.getAST() = child.(Stmt)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
result = getChildAccessorWithoutConversions(ast, getChildInternal(childIndex).getAst())
|
||||
result = getChildAccessorWithoutConversions(ast, getChildInternal(childIndex).getAST())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,12 +449,12 @@ class DeclStmtNode extends StmtNode {
|
||||
/**
|
||||
* A node representing a `Parameter`.
|
||||
*/
|
||||
class ParameterNode extends AstNode {
|
||||
class ParameterNode extends ASTNode {
|
||||
Parameter param;
|
||||
|
||||
ParameterNode() { param = ast }
|
||||
|
||||
final override PrintAstNode getChildInternal(int childIndex) { none() }
|
||||
final override PrintASTNode getChildInternal(int childIndex) { none() }
|
||||
|
||||
final override string getChildAccessorPredicateInternal(int childIndex) { none() }
|
||||
|
||||
@@ -484,14 +469,14 @@ class ParameterNode extends AstNode {
|
||||
/**
|
||||
* A node representing an `Initializer`.
|
||||
*/
|
||||
class InitializerNode extends AstNode {
|
||||
class InitializerNode extends ASTNode {
|
||||
Initializer init;
|
||||
|
||||
InitializerNode() { init = ast }
|
||||
|
||||
override AstNode getChildInternal(int childIndex) {
|
||||
override ASTNode getChildInternal(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result.getAst() = init.getExpr()
|
||||
result.getAST() = init.getExpr()
|
||||
}
|
||||
|
||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
@@ -503,7 +488,7 @@ class InitializerNode extends AstNode {
|
||||
/**
|
||||
* A node representing the parameters of a `Function`.
|
||||
*/
|
||||
class ParametersNode extends PrintAstNode, TParametersNode {
|
||||
class ParametersNode extends PrintASTNode, TParametersNode {
|
||||
Function func;
|
||||
|
||||
ParametersNode() { this = TParametersNode(func) }
|
||||
@@ -512,8 +497,8 @@ class ParametersNode extends PrintAstNode, TParametersNode {
|
||||
|
||||
final override Location getLocation() { result = getRepresentativeLocation(func) }
|
||||
|
||||
override AstNode getChildInternal(int childIndex) {
|
||||
result.getAst() = func.getParameter(childIndex)
|
||||
override ASTNode getChildInternal(int childIndex) {
|
||||
result.getAST() = func.getParameter(childIndex)
|
||||
}
|
||||
|
||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
@@ -530,7 +515,7 @@ class ParametersNode extends PrintAstNode, TParametersNode {
|
||||
/**
|
||||
* A node representing the initializer list of a `Constructor`.
|
||||
*/
|
||||
class ConstructorInitializersNode extends PrintAstNode, TConstructorInitializersNode {
|
||||
class ConstructorInitializersNode extends PrintASTNode, TConstructorInitializersNode {
|
||||
Constructor ctor;
|
||||
|
||||
ConstructorInitializersNode() { this = TConstructorInitializersNode(ctor) }
|
||||
@@ -539,8 +524,8 @@ class ConstructorInitializersNode extends PrintAstNode, TConstructorInitializers
|
||||
|
||||
final override Location getLocation() { result = getRepresentativeLocation(ctor) }
|
||||
|
||||
final override AstNode getChildInternal(int childIndex) {
|
||||
result.getAst() = ctor.getInitializer(childIndex)
|
||||
final override ASTNode getChildInternal(int childIndex) {
|
||||
result.getAST() = ctor.getInitializer(childIndex)
|
||||
}
|
||||
|
||||
final override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
@@ -557,7 +542,7 @@ class ConstructorInitializersNode extends PrintAstNode, TConstructorInitializers
|
||||
/**
|
||||
* A node representing the destruction list of a `Destructor`.
|
||||
*/
|
||||
class DestructorDestructionsNode extends PrintAstNode, TDestructorDestructionsNode {
|
||||
class DestructorDestructionsNode extends PrintASTNode, TDestructorDestructionsNode {
|
||||
Destructor dtor;
|
||||
|
||||
DestructorDestructionsNode() { this = TDestructorDestructionsNode(dtor) }
|
||||
@@ -566,8 +551,8 @@ class DestructorDestructionsNode extends PrintAstNode, TDestructorDestructionsNo
|
||||
|
||||
final override Location getLocation() { result = getRepresentativeLocation(dtor) }
|
||||
|
||||
final override AstNode getChildInternal(int childIndex) {
|
||||
result.getAst() = dtor.getDestruction(childIndex)
|
||||
final override ASTNode getChildInternal(int childIndex) {
|
||||
result.getAST() = dtor.getDestruction(childIndex)
|
||||
}
|
||||
|
||||
final override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
@@ -584,14 +569,14 @@ class DestructorDestructionsNode extends PrintAstNode, TDestructorDestructionsNo
|
||||
/**
|
||||
* A node representing a `Function`.
|
||||
*/
|
||||
class FunctionNode extends AstNode {
|
||||
class FunctionNode extends ASTNode {
|
||||
Function func;
|
||||
|
||||
FunctionNode() { func = ast }
|
||||
|
||||
override string toString() { result = qlClass(func) + getIdentityString(func) }
|
||||
|
||||
override PrintAstNode getChildInternal(int childIndex) {
|
||||
override PrintASTNode getChildInternal(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result.(ParametersNode).getFunction() = func
|
||||
or
|
||||
@@ -599,7 +584,7 @@ class FunctionNode extends AstNode {
|
||||
result.(ConstructorInitializersNode).getConstructor() = func
|
||||
or
|
||||
childIndex = 2 and
|
||||
result.(AstNode).getAst() = func.getEntryPoint()
|
||||
result.(ASTNode).getAST() = func.getEntryPoint()
|
||||
or
|
||||
childIndex = 3 and
|
||||
result.(DestructorDestructionsNode).getDestructor() = func
|
||||
@@ -618,7 +603,7 @@ class FunctionNode extends AstNode {
|
||||
private int getOrder() {
|
||||
this =
|
||||
rank[result](FunctionNode node, Function function, string file, int line, int column |
|
||||
node.getAst() = function and
|
||||
node.getAST() = function and
|
||||
locationSortKeys(function, file, line, column)
|
||||
|
|
||||
node order by file, line, column, getIdentityString(function)
|
||||
@@ -871,7 +856,7 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
|
||||
}
|
||||
|
||||
/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */
|
||||
query predicate nodes(PrintAstNode node, string key, string value) {
|
||||
query predicate nodes(PrintASTNode node, string key, string value) {
|
||||
node.shouldPrint() and
|
||||
value = node.getProperty(key)
|
||||
}
|
||||
@@ -880,7 +865,7 @@ query predicate nodes(PrintAstNode node, string key, string value) {
|
||||
* Holds if `target` is a child of `source` in the AST, and property `key` of the edge has the
|
||||
* given `value`.
|
||||
*/
|
||||
query predicate edges(PrintAstNode source, PrintAstNode target, string key, string value) {
|
||||
query predicate edges(PrintASTNode source, PrintASTNode target, string key, string value) {
|
||||
exists(int childIndex |
|
||||
source.shouldPrint() and
|
||||
target.shouldPrint() and
|
||||
|
||||
@@ -38,7 +38,7 @@ class FunctionSpecifier extends Specifier {
|
||||
|
||||
/**
|
||||
* A C/C++ storage class specifier: `auto`, `register`, `static`, `extern`,
|
||||
* or `mutable`.
|
||||
* or `mutable".
|
||||
*/
|
||||
class StorageClassSpecifier extends Specifier {
|
||||
StorageClassSpecifier() { this.hasName(["auto", "register", "static", "extern", "mutable"]) }
|
||||
@@ -286,13 +286,13 @@ class AttributeArgument extends Element, @attribute_arg {
|
||||
override Location getLocation() { attribute_args(underlyingElement(this), _, _, _, result) }
|
||||
|
||||
override string toString() {
|
||||
if underlyingElement(this) instanceof @attribute_arg_empty
|
||||
if exists(@attribute_arg_empty self | self = underlyingElement(this))
|
||||
then result = "empty argument"
|
||||
else
|
||||
exists(string prefix, string tail |
|
||||
(if exists(this.getName()) then prefix = this.getName() + "=" else prefix = "") and
|
||||
(
|
||||
if underlyingElement(this) instanceof @attribute_arg_type
|
||||
if exists(@attribute_arg_type self | self = underlyingElement(this))
|
||||
then tail = this.getValueType().getName()
|
||||
else tail = this.getValueText()
|
||||
) and
|
||||
|
||||
@@ -1085,6 +1085,50 @@ class DerivedType extends Type, @derivedtype {
|
||||
override predicate involvesTemplateParameter() { this.getBaseType().involvesTemplateParameter() }
|
||||
|
||||
override Type stripType() { result = this.getBaseType().stripType() }
|
||||
|
||||
/**
|
||||
* Holds if this type has the `__autoreleasing` specifier or if it points to
|
||||
* a type with the `__autoreleasing` specifier.
|
||||
*
|
||||
* DEPRECATED: use `hasSpecifier` directly instead.
|
||||
*/
|
||||
deprecated predicate isAutoReleasing() {
|
||||
this.hasSpecifier("__autoreleasing") or
|
||||
this.(PointerType).getBaseType().hasSpecifier("__autoreleasing")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this type has the `__strong` specifier or if it points to
|
||||
* a type with the `__strong` specifier.
|
||||
*
|
||||
* DEPRECATED: use `hasSpecifier` directly instead.
|
||||
*/
|
||||
deprecated predicate isStrong() {
|
||||
this.hasSpecifier("__strong") or
|
||||
this.(PointerType).getBaseType().hasSpecifier("__strong")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this type has the `__unsafe_unretained` specifier or if it points
|
||||
* to a type with the `__unsafe_unretained` specifier.
|
||||
*
|
||||
* DEPRECATED: use `hasSpecifier` directly instead.
|
||||
*/
|
||||
deprecated predicate isUnsafeRetained() {
|
||||
this.hasSpecifier("__unsafe_unretained") or
|
||||
this.(PointerType).getBaseType().hasSpecifier("__unsafe_unretained")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this type has the `__weak` specifier or if it points to
|
||||
* a type with the `__weak` specifier.
|
||||
*
|
||||
* DEPRECATED: use `hasSpecifier` directly instead.
|
||||
*/
|
||||
deprecated predicate isWeak() {
|
||||
this.hasSpecifier("__weak") or
|
||||
this.(PointerType).getBaseType().hasSpecifier("__weak")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -106,4 +106,25 @@ class NestedTypedefType extends TypedefType {
|
||||
NestedTypedefType() { this.isMember() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NestedTypedefType" }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `.hasSpecifier("private")` instead.
|
||||
*
|
||||
* Holds if this member is private.
|
||||
*/
|
||||
deprecated predicate isPrivate() { this.hasSpecifier("private") }
|
||||
|
||||
/**
|
||||
* DEPRECATED: `.hasSpecifier("protected")` instead.
|
||||
*
|
||||
* Holds if this member is protected.
|
||||
*/
|
||||
deprecated predicate isProtected() { this.hasSpecifier("protected") }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `.hasSpecifier("public")` instead.
|
||||
*
|
||||
* Holds if this member is public.
|
||||
*/
|
||||
deprecated predicate isPublic() { this.hasSpecifier("public") }
|
||||
}
|
||||
|
||||
@@ -169,12 +169,6 @@ class Variable extends Declaration, @variable {
|
||||
variable_instantiation(underlyingElement(this), unresolveElement(v))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this variable is declated as part of a structured binding
|
||||
* declaration. For example, `x` in `auto [x, y] = ...`.
|
||||
*/
|
||||
predicate isStructuredBinding() { is_structured_binding(underlyingElement(this)) }
|
||||
|
||||
/**
|
||||
* Holds if this is a compiler-generated variable. For example, a
|
||||
* [range-based for loop](http://en.cppreference.com/w/cpp/language/range-for)
|
||||
@@ -556,6 +550,24 @@ class MemberVariable extends Variable, @membervariable {
|
||||
private Type getAType() { membervariables(underlyingElement(this), unresolveElement(result), _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ function pointer variable.
|
||||
*
|
||||
* DEPRECATED: use `Variable.getType() instanceof FunctionPointerType` instead.
|
||||
*/
|
||||
deprecated class FunctionPointerVariable extends Variable {
|
||||
FunctionPointerVariable() { this.getType() instanceof FunctionPointerType }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ function pointer member variable.
|
||||
*
|
||||
* DEPRECATED: use `MemberVariable.getType() instanceof FunctionPointerType` instead.
|
||||
*/
|
||||
deprecated class FunctionPointerMemberVariable extends MemberVariable {
|
||||
FunctionPointerMemberVariable() { this instanceof FunctionPointerVariable }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++14 variable template. For example, in the following code the variable
|
||||
* template `v` defines a family of variables:
|
||||
|
||||
@@ -4,14 +4,21 @@
|
||||
|
||||
import semmle.files.FileSystem
|
||||
|
||||
private class TXmlLocatable =
|
||||
private class TXMLLocatable =
|
||||
@xmldtd or @xmlelement or @xmlattribute or @xmlnamespace or @xmlcomment or @xmlcharacters;
|
||||
|
||||
/** An XML element that has a location. */
|
||||
class XMLLocatable extends @xmllocatable, TXmlLocatable {
|
||||
class XMLLocatable extends @xmllocatable, TXMLLocatable {
|
||||
/** Gets the source location for this element. */
|
||||
Location getLocation() { xmllocations(this, result) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getLocation()` instead.
|
||||
*
|
||||
* Gets the source location for this element.
|
||||
*/
|
||||
deprecated Location getALocation() { result = this.getLocation() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
@@ -76,6 +83,21 @@ class XMLParent extends @xmlparent {
|
||||
/** Gets the number of places in the body of this XML parent where text occurs. */
|
||||
int getNumberOfCharacterSets() { result = count(int pos | xmlChars(_, _, this, pos, _, _)) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Internal.
|
||||
*
|
||||
* Append the character sequences of this XML parent from left to right, separated by a space,
|
||||
* up to a specified (zero-based) index.
|
||||
*/
|
||||
deprecated string charsSetUpTo(int n) {
|
||||
n = 0 and xmlChars(_, result, this, 0, _, _)
|
||||
or
|
||||
n > 0 and
|
||||
exists(string chars | xmlChars(_, chars, this, n, _, _) |
|
||||
result = this.charsSetUpTo(n - 1) + " " + chars
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result of appending all the character sequences of this XML parent from
|
||||
* left to right, separated by a space.
|
||||
@@ -211,7 +233,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||
XMLAttribute getAttribute(string name) { result.getElement() = this and result.getName() = name }
|
||||
|
||||
/** Holds if this XML element has an attribute with the specified `name`. */
|
||||
predicate hasAttribute(string name) { exists(this.getAttribute(name)) }
|
||||
predicate hasAttribute(string name) { exists(XMLAttribute a | a = this.getAttribute(name)) }
|
||||
|
||||
/** Gets the value of the attribute with the specified `name`, if any. */
|
||||
string getAttributeValue(string name) { result = this.getAttribute(name).getValue() }
|
||||
|
||||
@@ -2,6 +2,20 @@ import cpp
|
||||
import semmle.code.cpp.models.interfaces.Allocation
|
||||
import semmle.code.cpp.models.interfaces.Deallocation
|
||||
|
||||
/**
|
||||
* A library routine that allocates memory.
|
||||
*
|
||||
* DEPRECATED: Use the `AllocationFunction` class instead of this predicate.
|
||||
*/
|
||||
deprecated predicate allocationFunction(Function f) { f instanceof AllocationFunction }
|
||||
|
||||
/**
|
||||
* A call to a library routine that allocates memory.
|
||||
*
|
||||
* DEPRECATED: Use `AllocationExpr` instead (this also includes `new` expressions).
|
||||
*/
|
||||
deprecated predicate allocationCall(FunctionCall fc) { fc instanceof AllocationExpr }
|
||||
|
||||
/**
|
||||
* A library routine that frees memory.
|
||||
*/
|
||||
@@ -19,6 +33,13 @@ predicate freeCall(FunctionCall fc, Expr arg) { arg = fc.(DeallocationExpr).getF
|
||||
*/
|
||||
predicate isMemoryManagementExpr(Expr e) { isAllocationExpr(e) or e instanceof DeallocationExpr }
|
||||
|
||||
/**
|
||||
* Is e an allocation from stdlib.h (`malloc`, `realloc` etc)?
|
||||
*
|
||||
* DEPRECATED: Use `AllocationExpr` instead (this also includes `new` expressions).
|
||||
*/
|
||||
deprecated predicate isStdLibAllocationExpr(Expr e) { allocationCall(e) }
|
||||
|
||||
/**
|
||||
* Is e some kind of allocation (`new`, `alloc`, `realloc` etc)?
|
||||
*/
|
||||
@@ -27,3 +48,19 @@ predicate isAllocationExpr(Expr e) {
|
||||
or
|
||||
e = any(NewOrNewArrayExpr new | not exists(new.getPlacementPointer()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Is e some kind of allocation (`new`, `alloc`, `realloc` etc) with a fixed size?
|
||||
*
|
||||
* DEPRECATED: Use `AllocationExpr.getSizeBytes()` instead.
|
||||
*/
|
||||
deprecated predicate isFixedSizeAllocationExpr(Expr allocExpr, int size) {
|
||||
size = allocExpr.(AllocationExpr).getSizeBytes()
|
||||
}
|
||||
|
||||
/**
|
||||
* Is e some kind of deallocation (`delete`, `free`, `realloc` etc)?
|
||||
*
|
||||
* DEPRECATED: Use `DeallocationExpr` instead.
|
||||
*/
|
||||
deprecated predicate isDeallocationExpr(Expr e) { e instanceof DeallocationExpr }
|
||||
|
||||
@@ -101,21 +101,6 @@ predicate functionArgumentMustBeNullTerminated(Function f, int i) {
|
||||
f instanceof StrcatFunction and i = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `arg` is a string format argument to a formatting function call
|
||||
* `ffc`.
|
||||
*/
|
||||
predicate formatArgumentMustBeNullTerminated(FormattingFunctionCall ffc, Expr arg) {
|
||||
// String argument to a formatting function (such as `printf`)
|
||||
exists(int n, FormatLiteral fl |
|
||||
ffc.getConversionArgument(n) = arg and
|
||||
fl = ffc.getFormat() and
|
||||
fl.getConversionType(n) instanceof PointerType and // `%s`, `%ws` etc
|
||||
not fl.getConversionType(n) instanceof VoidPointerType and // exclude: `%p`
|
||||
not fl.hasPrecision(n) // exclude: `%.*s`
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `va` is a variable access where the contents must be null terminated.
|
||||
*/
|
||||
@@ -128,7 +113,13 @@ predicate variableMustBeNullTerminated(VariableAccess va) {
|
||||
)
|
||||
or
|
||||
// String argument to a formatting function (such as `printf`)
|
||||
formatArgumentMustBeNullTerminated(fc, va)
|
||||
exists(int n, FormatLiteral fl |
|
||||
fc.(FormattingFunctionCall).getConversionArgument(n) = va and
|
||||
fl = fc.(FormattingFunctionCall).getFormat() and
|
||||
fl.getConversionType(n) instanceof PointerType and // `%s`, `%ws` etc
|
||||
not fl.getConversionType(n) instanceof VoidPointerType and // exclude: `%p`
|
||||
not fl.hasPrecision(n) // exclude: `%.*s`
|
||||
)
|
||||
or
|
||||
// Call to a wrapper function that requires null termination
|
||||
// (not itself adding a null terminator)
|
||||
|
||||
@@ -10,22 +10,10 @@ private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||
|
||||
private newtype TBufferWriteEstimationReason =
|
||||
TUnspecifiedEstimateReason() or
|
||||
TNoSpecifiedEstimateReason() or
|
||||
TTypeBoundsAnalysis() or
|
||||
TWidenedValueFlowAnalysis() or
|
||||
TValueFlowAnalysis()
|
||||
|
||||
private predicate gradeToReason(int grade, TBufferWriteEstimationReason reason) {
|
||||
// when combining reasons, lower grade takes precedence
|
||||
grade = 0 and reason = TUnspecifiedEstimateReason()
|
||||
or
|
||||
grade = 1 and reason = TTypeBoundsAnalysis()
|
||||
or
|
||||
grade = 2 and reason = TWidenedValueFlowAnalysis()
|
||||
or
|
||||
grade = 3 and reason = TValueFlowAnalysis()
|
||||
}
|
||||
|
||||
/**
|
||||
* A reason for a specific buffer write size estimate.
|
||||
*/
|
||||
@@ -44,13 +32,7 @@ abstract class BufferWriteEstimationReason extends TBufferWriteEstimationReason
|
||||
* Combine estimate reasons. Used to give a reason for the size of a format string
|
||||
* conversion given reasons coming from its individual specifiers.
|
||||
*/
|
||||
BufferWriteEstimationReason combineWith(BufferWriteEstimationReason other) {
|
||||
exists(int grade, int otherGrade |
|
||||
gradeToReason(grade, this) and gradeToReason(otherGrade, other)
|
||||
|
|
||||
if otherGrade < grade then result = other else result = this
|
||||
)
|
||||
}
|
||||
abstract BufferWriteEstimationReason combineWith(BufferWriteEstimationReason other);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,10 +40,16 @@ abstract class BufferWriteEstimationReason extends TBufferWriteEstimationReason
|
||||
* classes derived from BufferWrite and overriding `getMaxData/0` still work with the
|
||||
* queries as intended.
|
||||
*/
|
||||
class UnspecifiedEstimateReason extends BufferWriteEstimationReason, TUnspecifiedEstimateReason {
|
||||
override string toString() { result = "UnspecifiedEstimateReason" }
|
||||
class NoSpecifiedEstimateReason extends BufferWriteEstimationReason, TNoSpecifiedEstimateReason {
|
||||
override string toString() { result = "NoSpecifiedEstimateReason" }
|
||||
|
||||
override string getDescription() { result = "no reason specified" }
|
||||
|
||||
override BufferWriteEstimationReason combineWith(BufferWriteEstimationReason other) {
|
||||
// this reason should not be used in format specifiers, so it should not be combined
|
||||
// with other reasons
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,24 +60,9 @@ class TypeBoundsAnalysis extends BufferWriteEstimationReason, TTypeBoundsAnalysi
|
||||
override string toString() { result = "TypeBoundsAnalysis" }
|
||||
|
||||
override string getDescription() { result = "based on type bounds" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The estimation comes from non trivial bounds found via actual flow analysis,
|
||||
* but a widening aproximation might have been used for variables in loops.
|
||||
* For example
|
||||
* ```
|
||||
* for (int i = 0; i < 10; ++i) {
|
||||
* int j = i + i;
|
||||
* //... <- estimation done here based on j
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class WidenedValueFlowAnalysis extends BufferWriteEstimationReason, TWidenedValueFlowAnalysis {
|
||||
override string toString() { result = "WidenedValueFlowAnalysis" }
|
||||
|
||||
override string getDescription() {
|
||||
result = "based on flow analysis of value bounds with a widening approximation"
|
||||
override BufferWriteEstimationReason combineWith(BufferWriteEstimationReason other) {
|
||||
other != TNoSpecifiedEstimateReason() and result = TTypeBoundsAnalysis()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +80,10 @@ class ValueFlowAnalysis extends BufferWriteEstimationReason, TValueFlowAnalysis
|
||||
override string toString() { result = "ValueFlowAnalysis" }
|
||||
|
||||
override string getDescription() { result = "based on flow analysis of value bounds" }
|
||||
|
||||
override BufferWriteEstimationReason combineWith(BufferWriteEstimationReason other) {
|
||||
other != TNoSpecifiedEstimateReason() and result = other
|
||||
}
|
||||
}
|
||||
|
||||
class PrintfFormatAttribute extends FormatAttribute {
|
||||
@@ -207,6 +184,26 @@ predicate variadicFormatter(Function f, string type, int formatParamIndex, int o
|
||||
callsVariadicFormatter(f, type, formatParamIndex, outputParamIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* A standard function such as `vprintf` that has a format parameter
|
||||
* and a variable argument list of type `va_arg`.
|
||||
*
|
||||
* DEPRECATED: Use the four argument version instead.
|
||||
*/
|
||||
deprecated predicate primitiveVariadicFormatter(TopLevelFunction f, int formatParamIndex) {
|
||||
primitiveVariadicFormatter(f, _, formatParamIndex, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` is a function such as `vprintf` that has a format parameter
|
||||
* (at `formatParamIndex`) and a variable argument list of type `va_arg`.
|
||||
*
|
||||
* DEPRECATED: Use the four argument version instead.
|
||||
*/
|
||||
deprecated predicate variadicFormatter(Function f, int formatParamIndex) {
|
||||
variadicFormatter(f, _, formatParamIndex, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* A function not in the standard library which takes a `printf`-like formatting
|
||||
* string and a variable number of arguments.
|
||||
@@ -362,38 +359,6 @@ private int lengthInBase10(float f) {
|
||||
result = f.log10().floor() + 1
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate isPointerTypeWithBase(Type base, PointerType pt) { base = pt.getBaseType() }
|
||||
|
||||
bindingset[expr]
|
||||
private BufferWriteEstimationReason getEstimationReasonForIntegralExpression(Expr expr) {
|
||||
// we consider the range analysis non trivial if it
|
||||
// * constrained non-trivially both sides of a signed value, or
|
||||
// * constrained non-trivially the positive side of an unsigned value
|
||||
// expr should already be given as getFullyConverted
|
||||
if
|
||||
upperBound(expr) < exprMaxVal(expr) and
|
||||
(exprMinVal(expr) >= 0 or lowerBound(expr) > exprMinVal(expr))
|
||||
then
|
||||
// next we check whether the estimate may have been widened
|
||||
if upperBoundMayBeWidened(expr)
|
||||
then result = TWidenedValueFlowAnalysis()
|
||||
else result = TValueFlowAnalysis()
|
||||
else result = TTypeBoundsAnalysis()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of hex digits required to represent the integer represented by `f`.
|
||||
*
|
||||
* `f` is assumed to be nonnegative.
|
||||
*/
|
||||
bindingset[f]
|
||||
private int lengthInBase16(float f) {
|
||||
f = 0 and result = 1
|
||||
or
|
||||
result = (f.log2() / 4.0).floor() + 1
|
||||
}
|
||||
|
||||
/**
|
||||
* A class to represent format strings that occur as arguments to invocations of formatting functions.
|
||||
*/
|
||||
@@ -408,6 +373,13 @@ class FormatLiteral extends Literal {
|
||||
*/
|
||||
FormattingFunctionCall getUse() { result.getFormat() = this }
|
||||
|
||||
/**
|
||||
* Holds if the default meaning of `%s` is a `wchar_t *`, rather than
|
||||
* a `char *` (either way, `%S` will have the opposite meaning).
|
||||
* DEPRECATED: Use getDefaultCharType() instead.
|
||||
*/
|
||||
deprecated predicate isWideCharDefault() { this.getUse().getTarget().isWideCharDefault() }
|
||||
|
||||
/**
|
||||
* Gets the default character type expected for `%s` by this format literal. Typically
|
||||
* `char` or `wchar_t`.
|
||||
@@ -938,19 +910,19 @@ class FormatLiteral extends Literal {
|
||||
(
|
||||
conv = ["s", "S"] and
|
||||
len = "h" and
|
||||
isPointerTypeWithBase(any(PlainCharType plainCharType), result)
|
||||
result.(PointerType).getBaseType() instanceof PlainCharType
|
||||
or
|
||||
conv = ["s", "S"] and
|
||||
len = ["l", "w"] and
|
||||
isPointerTypeWithBase(this.getWideCharType(), result)
|
||||
result.(PointerType).getBaseType() = this.getWideCharType()
|
||||
or
|
||||
conv = "s" and
|
||||
(len != "l" and len != "w" and len != "h") and
|
||||
isPointerTypeWithBase(this.getDefaultCharType(), result)
|
||||
result.(PointerType).getBaseType() = this.getDefaultCharType()
|
||||
or
|
||||
conv = "S" and
|
||||
(len != "l" and len != "w" and len != "h") and
|
||||
isPointerTypeWithBase(this.getNonDefaultCharType(), result)
|
||||
result.(PointerType).getBaseType() = this.getNonDefaultCharType()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1095,7 +1067,7 @@ class FormatLiteral extends Literal {
|
||||
* conversion specifier of this format string; has no result if this cannot
|
||||
* be determined.
|
||||
*/
|
||||
int getMaxConvertedLength(int n) { result = max(this.getMaxConvertedLength(n, _)) }
|
||||
int getMaxConvertedLength(int n) { result = max(getMaxConvertedLength(n, _)) }
|
||||
|
||||
/**
|
||||
* Gets the maximum length of the string that can be produced by the nth
|
||||
@@ -1185,10 +1157,12 @@ class FormatLiteral extends Literal {
|
||||
1 + lengthInBase10(2.pow(this.getIntegralDisplayType(n).getSize() * 8 - 1)) and
|
||||
// The second case uses range analysis to deduce a length that's shorter than the length
|
||||
// of the number -2^31.
|
||||
exists(Expr arg, float lower, float upper |
|
||||
exists(Expr arg, float lower, float upper, float typeLower, float typeUpper |
|
||||
arg = this.getUse().getConversionArgument(n) and
|
||||
lower = lowerBound(arg.getFullyConverted()) and
|
||||
upper = upperBound(arg.getFullyConverted())
|
||||
upper = upperBound(arg.getFullyConverted()) and
|
||||
typeLower = exprMinVal(arg.getFullyConverted()) and
|
||||
typeUpper = exprMaxVal(arg.getFullyConverted())
|
||||
|
|
||||
valueBasedBound =
|
||||
max(int cand |
|
||||
@@ -1205,9 +1179,11 @@ class FormatLiteral extends Literal {
|
||||
else cand = lengthInBase10(upper)
|
||||
)
|
||||
) and
|
||||
// we don't want to call this on `arg.getFullyConverted()` as we want
|
||||
// to detect non-trivial range analysis without taking into account up-casting
|
||||
reason = getEstimationReasonForIntegralExpression(arg)
|
||||
(
|
||||
if lower > typeLower or upper < typeUpper
|
||||
then reason = TValueFlowAnalysis()
|
||||
else reason = TTypeBoundsAnalysis()
|
||||
)
|
||||
) and
|
||||
len = valueBasedBound.minimum(typeBasedBound)
|
||||
)
|
||||
@@ -1219,40 +1195,6 @@ class FormatLiteral extends Literal {
|
||||
typeBasedBound = lengthInBase10(2.pow(this.getIntegralDisplayType(n).getSize() * 8) - 1) and
|
||||
// The second case uses range analysis to deduce a length that's shorter than
|
||||
// the length of the number 2^31 - 1.
|
||||
exists(Expr arg, float lower, float upper |
|
||||
arg = this.getUse().getConversionArgument(n) and
|
||||
lower = lowerBound(arg.getFullyConverted()) and
|
||||
upper = upperBound(arg.getFullyConverted())
|
||||
|
|
||||
valueBasedBound =
|
||||
lengthInBase10(max(float cand |
|
||||
// If lower can be negative we use `(unsigned)-1` as the candidate value.
|
||||
lower < 0 and
|
||||
cand = 2.pow(any(IntType t | t.isUnsigned()).getSize() * 8)
|
||||
or
|
||||
cand = upper
|
||||
)) and
|
||||
// we don't want to call this on `arg.getFullyConverted()` as we want
|
||||
// to detect non-trivial range analysis without taking into account up-casting
|
||||
reason = getEstimationReasonForIntegralExpression(arg)
|
||||
) and
|
||||
len = valueBasedBound.minimum(typeBasedBound)
|
||||
)
|
||||
or
|
||||
this.getConversionChar(n).toLowerCase() = "x" and
|
||||
// e.g. "12345678"
|
||||
exists(int baseLen, int typeBasedBound, int valueBasedBound |
|
||||
typeBasedBound =
|
||||
min(int digits |
|
||||
digits = 2 * this.getIntegralDisplayType(n).getSize()
|
||||
or
|
||||
exists(IntegralType t |
|
||||
t = this.getUse().getConversionArgument(n).getType().getUnderlyingType()
|
||||
|
|
||||
t.isUnsigned() and
|
||||
digits = 2 * t.getSize()
|
||||
)
|
||||
) and
|
||||
exists(Expr arg, float lower, float upper, float typeLower, float typeUpper |
|
||||
arg = this.getUse().getConversionArgument(n) and
|
||||
lower = lowerBound(arg.getFullyConverted()) and
|
||||
@@ -1261,7 +1203,7 @@ class FormatLiteral extends Literal {
|
||||
typeUpper = exprMaxVal(arg.getFullyConverted())
|
||||
|
|
||||
valueBasedBound =
|
||||
lengthInBase16(max(float cand |
|
||||
lengthInBase10(max(float cand |
|
||||
// If lower can be negative we use `(unsigned)-1` as the candidate value.
|
||||
lower < 0 and
|
||||
cand = 2.pow(any(IntType t | t.isUnsigned()).getSize() * 8)
|
||||
@@ -1274,10 +1216,29 @@ class FormatLiteral extends Literal {
|
||||
else reason = TTypeBoundsAnalysis()
|
||||
)
|
||||
) and
|
||||
baseLen = valueBasedBound.minimum(typeBasedBound) and
|
||||
if this.hasAlternateFlag(n) then len = 2 + baseLen else len = baseLen // "0x"
|
||||
len = valueBasedBound.minimum(typeBasedBound)
|
||||
)
|
||||
or
|
||||
this.getConversionChar(n).toLowerCase() = "x" and
|
||||
// e.g. "12345678"
|
||||
exists(int sizeBytes, int baseLen |
|
||||
sizeBytes =
|
||||
min(int bytes |
|
||||
bytes = this.getIntegralDisplayType(n).getSize()
|
||||
or
|
||||
exists(IntegralType t |
|
||||
t = this.getUse().getConversionArgument(n).getType().getUnderlyingType()
|
||||
|
|
||||
t.isUnsigned() and bytes = t.getSize()
|
||||
)
|
||||
) and
|
||||
baseLen = sizeBytes * 2 and
|
||||
(
|
||||
if this.hasAlternateFlag(n) then len = 2 + baseLen else len = baseLen // "0x"
|
||||
)
|
||||
) and
|
||||
reason = TTypeBoundsAnalysis()
|
||||
or
|
||||
this.getConversionChar(n).toLowerCase() = "p" and
|
||||
exists(PointerType ptrType, int baseLen |
|
||||
ptrType = this.getFullyConverted().getType() and
|
||||
@@ -1326,7 +1287,7 @@ class FormatLiteral extends Literal {
|
||||
* determining whether a buffer overflow is caused by long float to string
|
||||
* conversions.
|
||||
*/
|
||||
int getMaxConvertedLengthLimited(int n) { result = max(this.getMaxConvertedLengthLimited(n, _)) }
|
||||
int getMaxConvertedLengthLimited(int n) { result = max(getMaxConvertedLengthLimited(n, _)) }
|
||||
|
||||
/**
|
||||
* Gets the maximum length of the string that can be produced by the nth
|
||||
|
||||
@@ -11,10 +11,10 @@ import cpp
|
||||
*/
|
||||
bindingset[input]
|
||||
int parseOctal(string input) {
|
||||
input.regexpMatch("0[0-7]+") and
|
||||
input.charAt(0) = "0" and
|
||||
result =
|
||||
strictsum(int ix |
|
||||
ix in [1 .. input.length()]
|
||||
ix in [0 .. input.length()]
|
||||
|
|
||||
8.pow(input.length() - (ix + 1)) * input.charAt(ix).toInt()
|
||||
)
|
||||
|
||||
@@ -223,6 +223,20 @@ class BasicBlock extends ControlFlowNodeBase {
|
||||
*/
|
||||
predicate inLoop() { this.getASuccessor+() = this }
|
||||
|
||||
/**
|
||||
* DEPRECATED since version 1.11: this predicate does not match the standard
|
||||
* definition of _loop header_.
|
||||
*
|
||||
* Holds if this basic block is in a loop of the control-flow graph and
|
||||
* additionally has an incoming edge that is not part of any loop containing
|
||||
* this basic block. A typical example would be the basic block that computes
|
||||
* `x > 0` in an outermost loop `while (x > 0) { ... }`.
|
||||
*/
|
||||
deprecated predicate isLoopHeader() {
|
||||
this.inLoop() and
|
||||
exists(BasicBlock pred | pred = this.getAPredecessor() and not pred = this.getASuccessor+())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if control flow may reach this basic block from a function entry
|
||||
* point or any handler of a reachable `try` statement.
|
||||
|
||||
@@ -65,7 +65,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase {
|
||||
* taken when this expression is true.
|
||||
*/
|
||||
ControlFlowNode getATrueSuccessor() {
|
||||
qlCfgTrueSuccessor(this, result) and
|
||||
qlCFGTrueSuccessor(this, result) and
|
||||
result = this.getASuccessor()
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase {
|
||||
* taken when this expression is false.
|
||||
*/
|
||||
ControlFlowNode getAFalseSuccessor() {
|
||||
qlCfgFalseSuccessor(this, result) and
|
||||
qlCFGFalseSuccessor(this, result) and
|
||||
result = this.getASuccessor()
|
||||
}
|
||||
|
||||
@@ -94,6 +94,24 @@ import ControlFlowGraphPublic
|
||||
*/
|
||||
class ControlFlowNodeBase extends ElementBase, @cfgnode { }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ControlFlowNode.getATrueSuccessor()` instead.
|
||||
* Holds when `n2` is a control-flow node such that the control-flow
|
||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is true.
|
||||
*/
|
||||
deprecated predicate truecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) {
|
||||
qlCFGTrueSuccessor(n1, n2)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ControlFlowNode.getAFalseSuccessor()` instead.
|
||||
* Holds when `n2` is a control-flow node such that the control-flow
|
||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is false.
|
||||
*/
|
||||
deprecated predicate falsecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) {
|
||||
qlCFGFalseSuccessor(n1, n2)
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract class that can be extended to add additional edges to the
|
||||
* control-flow graph. Instances of this class correspond to the source nodes
|
||||
@@ -121,7 +139,7 @@ abstract class AdditionalControlFlowEdge extends ControlFlowNodeBase {
|
||||
* `AdditionalControlFlowEdge`. Use this relation instead of `qlCFGSuccessor`.
|
||||
*/
|
||||
predicate successors_extended(ControlFlowNodeBase source, ControlFlowNodeBase target) {
|
||||
qlCfgSuccessor(source, target)
|
||||
qlCFGSuccessor(source, target)
|
||||
or
|
||||
source.(AdditionalControlFlowEdge).getAnEdgeTarget() = target
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ class GuardCondition extends Expr {
|
||||
exists(IRGuardCondition ir | this = ir.getUnconvertedResultExpression())
|
||||
or
|
||||
// no binary operators in the IR
|
||||
this.(BinaryLogicalOperation).getAnOperand() instanceof GuardCondition
|
||||
exists(GuardCondition gc | this.(BinaryLogicalOperation).getAnOperand() = gc)
|
||||
or
|
||||
// the IR short-circuits if(!x)
|
||||
// don't produce a guard condition for `y = !x` and other non-short-circuited cases
|
||||
not exists(Instruction inst | this.getFullyConverted() = inst.getAst()) and
|
||||
exists(IRGuardCondition ir | this.(NotExpr).getOperand() = ir.getAst())
|
||||
not exists(Instruction inst | this.getFullyConverted() = inst.getAST()) and
|
||||
exists(IRGuardCondition ir | this.(NotExpr).getOperand() = ir.getAST())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,7 +98,7 @@ class GuardCondition extends Expr {
|
||||
*/
|
||||
private class GuardConditionFromBinaryLogicalOperator extends GuardCondition {
|
||||
GuardConditionFromBinaryLogicalOperator() {
|
||||
this.(BinaryLogicalOperation).getAnOperand() instanceof GuardCondition
|
||||
exists(GuardCondition gc | this.(BinaryLogicalOperation).getAnOperand() = gc)
|
||||
}
|
||||
|
||||
override predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
||||
@@ -146,8 +146,8 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardCondition {
|
||||
*/
|
||||
private class GuardConditionFromShortCircuitNot extends GuardCondition, NotExpr {
|
||||
GuardConditionFromShortCircuitNot() {
|
||||
not exists(Instruction inst | this.getFullyConverted() = inst.getAst()) and
|
||||
exists(IRGuardCondition ir | this.getOperand() = ir.getAst())
|
||||
not exists(Instruction inst | this.getFullyConverted() = inst.getAST()) and
|
||||
exists(IRGuardCondition ir | this.getOperand() = ir.getAST())
|
||||
}
|
||||
|
||||
override predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
||||
@@ -241,7 +241,7 @@ private class GuardConditionFromIR extends GuardCondition {
|
||||
private predicate controlsBlock(BasicBlock controlled, boolean testIsTrue) {
|
||||
exists(IRBlock irb |
|
||||
forex(IRGuardCondition inst | inst = ir | inst.controls(irb, testIsTrue)) and
|
||||
irb.getAnInstruction().getAst().(ControlFlowNode).getBasicBlock() = controlled and
|
||||
irb.getAnInstruction().getAST().(ControlFlowNode).getBasicBlock() = controlled and
|
||||
not isUnreachedBlock(irb)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,393 @@
|
||||
/**
|
||||
* DEPRECATED: Use `StackVariableReachability` instead.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `StackVariableReachability` instead.
|
||||
*
|
||||
* A reachability analysis for control-flow nodes involving stack variables.
|
||||
* This defines sources, sinks, and any other configurable aspect of the
|
||||
* analysis. Multiple analyses can coexist. To create an analysis, extend this
|
||||
* class with a subclass whose characteristic predicate is a unique singleton
|
||||
* string. For example, write
|
||||
*
|
||||
* ```
|
||||
* class MyAnalysisConfiguration extends LocalScopeVariableReachability {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Override `isBarrier`.
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Then, to query whether there is flow between some source and sink, call the
|
||||
* `reaches` predicate on an instance of `MyAnalysisConfiguration`.
|
||||
*/
|
||||
abstract deprecated class LocalScopeVariableReachability extends string {
|
||||
bindingset[this]
|
||||
LocalScopeVariableReachability() { length() >= 0 }
|
||||
|
||||
/** Holds if `node` is a source for the reachability analysis using variable `v`. */
|
||||
abstract predicate isSource(ControlFlowNode node, LocalScopeVariable v);
|
||||
|
||||
/** Holds if `sink` is a (potential) sink for the reachability analysis using variable `v`. */
|
||||
abstract predicate isSink(ControlFlowNode node, LocalScopeVariable v);
|
||||
|
||||
/** Holds if `node` is a barrier for the reachability analysis using variable `v`. */
|
||||
abstract predicate isBarrier(ControlFlowNode node, LocalScopeVariable v);
|
||||
|
||||
/**
|
||||
* Holds if the source node `source` can reach the sink `sink` without crossing
|
||||
* a barrier. This is (almost) equivalent to the following QL predicate but
|
||||
* uses basic blocks internally for better performance:
|
||||
*
|
||||
* ```
|
||||
* predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
* reachesImpl(source, v, sink)
|
||||
* and
|
||||
* isSink(sink, v)
|
||||
* }
|
||||
*
|
||||
* predicate reachesImpl(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
* sink = source.getASuccessor() and isSource(source, v)
|
||||
* or
|
||||
* exists(ControlFlowNode mid | reachesImpl(source, v, mid) |
|
||||
* not isBarrier(mid, v)
|
||||
* and
|
||||
* sink = mid.getASuccessor()
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* In addition to using a better performing implementation, this analysis
|
||||
* accounts for loops where the condition is provably true upon entry.
|
||||
*/
|
||||
predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
/*
|
||||
* Implementation detail: the predicates in this class are a generalization of
|
||||
* those in DefinitionsAndUses.qll, and should be kept in sync.
|
||||
*
|
||||
* Unfortunately, caching of abstract predicates does not work well, so the
|
||||
* predicates in DefinitionsAndUses.qll cannot use this library.
|
||||
*/
|
||||
|
||||
exists(BasicBlock bb, int i |
|
||||
this.isSource(source, v) and
|
||||
bb.getNode(i) = source and
|
||||
not bb.isUnreachable()
|
||||
|
|
||||
exists(int j |
|
||||
j > i and
|
||||
sink = bb.getNode(j) and
|
||||
this.isSink(sink, v) and
|
||||
not exists(int k | this.isBarrier(bb.getNode(k), v) | k in [i + 1 .. j - 1])
|
||||
)
|
||||
or
|
||||
not exists(int k | this.isBarrier(bb.getNode(k), v) | k > i) and
|
||||
this.bbSuccessorEntryReaches(bb, v, sink, _)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate bbSuccessorEntryReaches(
|
||||
BasicBlock bb, SemanticStackVariable v, ControlFlowNode node,
|
||||
boolean skipsFirstLoopAlwaysTrueUponEntry
|
||||
) {
|
||||
exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
|
||||
bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
|
||||
succSkipsFirstLoopAlwaysTrueUponEntry)
|
||||
|
|
||||
this.bbEntryReachesLocally(succ, v, node) and
|
||||
succSkipsFirstLoopAlwaysTrueUponEntry = false
|
||||
or
|
||||
not this.isBarrier(succ.getNode(_), v) and
|
||||
this.bbSuccessorEntryReaches(succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate bbEntryReachesLocally(
|
||||
BasicBlock bb, SemanticStackVariable v, ControlFlowNode node
|
||||
) {
|
||||
exists(int n |
|
||||
node = bb.getNode(n) and
|
||||
this.isSink(node, v)
|
||||
|
|
||||
not exists(this.firstBarrierIndexIn(bb, v))
|
||||
or
|
||||
n <= this.firstBarrierIndexIn(bb, v)
|
||||
)
|
||||
}
|
||||
|
||||
private int firstBarrierIndexIn(BasicBlock bb, SemanticStackVariable v) {
|
||||
result = min(int m | this.isBarrier(bb.getNode(m), v))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bb` contains the entry point `loop` for a loop at position `i`.
|
||||
* The condition of that loop is provably true upon entry but not provably
|
||||
* true in general (if it were, the false-successor had already been removed
|
||||
* from the CFG).
|
||||
*
|
||||
* Examples:
|
||||
* ```
|
||||
* for (int i = 0; i < 2; i++) { } // always true upon entry
|
||||
* for (int i = 0; true; i++) { } // always true
|
||||
* ```
|
||||
*/
|
||||
private predicate bbLoopEntryConditionAlwaysTrueAt(BasicBlock bb, int i, ControlFlowNode loop) {
|
||||
exists(Expr condition |
|
||||
loopConditionAlwaysTrueUponEntry(loop, condition) and
|
||||
not conditionAlwaysTrue(condition) and
|
||||
bb.getNode(i) = loop
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic block `pred` contains all or part of the condition belonging to a loop,
|
||||
* and there is an edge from `pred` to `succ` that concludes the condition.
|
||||
* If the edge corrseponds with the loop condition being found to be `true`, then
|
||||
* `skipsLoop` is `false`. Otherwise the edge corresponds with the loop condition
|
||||
* being found to be `false` and `skipsLoop` is `true`. Non-concluding edges
|
||||
* within a complex loop condition are not matched by this predicate.
|
||||
*/
|
||||
private predicate bbLoopConditionAlwaysTrueUponEntrySuccessor(
|
||||
BasicBlock pred, BasicBlock succ, boolean skipsLoop
|
||||
) {
|
||||
exists(Expr cond |
|
||||
loopConditionAlwaysTrueUponEntry(_, cond) and
|
||||
cond.getAChild*() = pred.getEnd() and
|
||||
succ = pred.getASuccessor() and
|
||||
not cond.getAChild*() = succ.getStart() and
|
||||
(
|
||||
succ = pred.getAFalseSuccessor() and
|
||||
skipsLoop = true
|
||||
or
|
||||
succ = pred.getATrueSuccessor() and
|
||||
skipsLoop = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Loop invariant for `bbSuccessorEntryReaches`:
|
||||
*
|
||||
* - `succ` is a successor of `pred`.
|
||||
* - `predSkipsFirstLoopAlwaysTrueUponEntry`: whether the path from
|
||||
* `pred` (via `succ`) skips the first loop where the condition is
|
||||
* provably true upon entry.
|
||||
* - `succSkipsFirstLoopAlwaysTrueUponEntry`: whether the path from
|
||||
* `succ` skips the first loop where the condition is provably true
|
||||
* upon entry.
|
||||
* - If `pred` contains the entry point of a loop where the condition
|
||||
* is provably true upon entry, then `succ` is not allowed to skip
|
||||
* that loop (`succSkipsFirstLoopAlwaysTrueUponEntry = false`).
|
||||
*/
|
||||
predicate bbSuccessorEntryReachesLoopInvariant(
|
||||
BasicBlock pred, BasicBlock succ, boolean predSkipsFirstLoopAlwaysTrueUponEntry,
|
||||
boolean succSkipsFirstLoopAlwaysTrueUponEntry
|
||||
) {
|
||||
succ = pred.getASuccessor() and
|
||||
(succSkipsFirstLoopAlwaysTrueUponEntry = true or succSkipsFirstLoopAlwaysTrueUponEntry = false) and
|
||||
(
|
||||
// The edge from `pred` to `succ` is from a loop condition provably
|
||||
// true upon entry, so the value of `predSkipsFirstLoopAlwaysTrueUponEntry`
|
||||
// is determined by whether the true edge or the false edge is chosen,
|
||||
// regardless of the value of `succSkipsFirstLoopAlwaysTrueUponEntry`.
|
||||
bbLoopConditionAlwaysTrueUponEntrySuccessor(pred, succ, predSkipsFirstLoopAlwaysTrueUponEntry)
|
||||
or
|
||||
// The edge from `pred` to `succ` is _not_ from a loop condition provably
|
||||
// true upon entry, so the values of `predSkipsFirstLoopAlwaysTrueUponEntry`
|
||||
// and `succSkipsFirstLoopAlwaysTrueUponEntry` must be the same.
|
||||
not bbLoopConditionAlwaysTrueUponEntrySuccessor(pred, succ, _) and
|
||||
succSkipsFirstLoopAlwaysTrueUponEntry = predSkipsFirstLoopAlwaysTrueUponEntry and
|
||||
// Moreover, if `pred` contains the entry point of a loop where the
|
||||
// condition is provably true upon entry, then `succ` is not allowed
|
||||
// to skip that loop, and hence `succSkipsFirstLoopAlwaysTrueUponEntry = false`.
|
||||
(
|
||||
bbLoopEntryConditionAlwaysTrueAt(pred, _, _)
|
||||
implies
|
||||
succSkipsFirstLoopAlwaysTrueUponEntry = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `StackVariableReachabilityWithReassignment` instead.
|
||||
*
|
||||
* Reachability analysis for control-flow nodes involving stack variables.
|
||||
* Unlike `LocalScopeVariableReachability`, this analysis takes variable
|
||||
* reassignments into account.
|
||||
*
|
||||
* This class is used like `LocalScopeVariableReachability`, except that
|
||||
* subclasses should override `isSourceActual` and `isSinkActual` instead of
|
||||
* `isSource` and `isSink`, and that there is a `reachesTo` predicate in
|
||||
* addition to `reaches`.
|
||||
*/
|
||||
abstract deprecated class LocalScopeVariableReachabilityWithReassignment extends LocalScopeVariableReachability {
|
||||
bindingset[this]
|
||||
LocalScopeVariableReachabilityWithReassignment() { length() >= 0 }
|
||||
|
||||
/** Override this predicate rather than `isSource` (`isSource` is used internally). */
|
||||
abstract predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v);
|
||||
|
||||
/** Override this predicate rather than `isSink` (`isSink` is used internally). */
|
||||
abstract predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v);
|
||||
|
||||
/**
|
||||
* Holds if the source node `source` can reach the sink `sink` without crossing
|
||||
* a barrier, taking reassignments into account. This is (almost) equivalent
|
||||
* to the following QL predicate, but uses basic blocks internally for better
|
||||
* performance:
|
||||
*
|
||||
* ```
|
||||
* predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
* reachesImpl(source, v, sink)
|
||||
* and
|
||||
* isSinkActual(sink, v)
|
||||
* }
|
||||
*
|
||||
* predicate reachesImpl(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
* isSourceActual(source, v)
|
||||
* and
|
||||
* (
|
||||
* sink = source.getASuccessor()
|
||||
* or
|
||||
* exists(ControlFlowNode mid, SemanticStackVariable v0 | reachesImpl(source, v0, mid) |
|
||||
* // ordinary successor
|
||||
* not isBarrier(mid, v) and
|
||||
* sink = mid.getASuccessor() and
|
||||
* v = v0
|
||||
* or
|
||||
* // reassigned from v0 to v
|
||||
* exprDefinition(v, mid, v0.getAnAccess()) and
|
||||
* sink = mid.getASuccessor()
|
||||
* )
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* In addition to using a better performing implementation, this analysis
|
||||
* accounts for loops where the condition is provably true upon entry.
|
||||
*/
|
||||
override predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
this.reachesTo(source, v, sink, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* As `reaches`, but also specifies the last variable it was reassigned to (`v0`).
|
||||
*/
|
||||
predicate reachesTo(
|
||||
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink, SemanticStackVariable v0
|
||||
) {
|
||||
exists(ControlFlowNode def |
|
||||
this.actualSourceReaches(source, v, def, v0) and
|
||||
LocalScopeVariableReachability.super.reaches(def, v0, sink) and
|
||||
this.isSinkActual(sink, v0)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate actualSourceReaches(
|
||||
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0
|
||||
) {
|
||||
this.isSourceActual(source, v) and def = source and v0 = v
|
||||
or
|
||||
exists(ControlFlowNode source1, SemanticStackVariable v1 |
|
||||
this.actualSourceReaches(source, v, source1, v1)
|
||||
|
|
||||
this.reassignment(source1, v1, def, v0)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate reassignment(
|
||||
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0
|
||||
) {
|
||||
LocalScopeVariableReachability.super.reaches(source, v, def) and
|
||||
exprDefinition(v0, def, v.getAnAccess())
|
||||
}
|
||||
|
||||
final override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
|
||||
this.isSourceActual(node, v)
|
||||
or
|
||||
// Reassignment generates a new (non-actual) source
|
||||
this.reassignment(_, _, node, v)
|
||||
}
|
||||
|
||||
final override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
|
||||
this.isSinkActual(node, v)
|
||||
or
|
||||
// Reassignment generates a new (non-actual) sink
|
||||
exprDefinition(_, node, v.getAnAccess())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `StackVariableReachabilityExt` instead.
|
||||
*
|
||||
* Same as `LocalScopeVariableReachability`, but `isBarrier` works on control-flow
|
||||
* edges rather than nodes and is therefore parameterized by the original
|
||||
* source node as well. Otherwise, this class is used like
|
||||
* `LocalScopeVariableReachability`.
|
||||
*/
|
||||
abstract deprecated class LocalScopeVariableReachabilityExt extends string {
|
||||
bindingset[this]
|
||||
LocalScopeVariableReachabilityExt() { length() >= 0 }
|
||||
|
||||
/** `node` is a source for the reachability analysis using variable `v`. */
|
||||
abstract predicate isSource(ControlFlowNode node, LocalScopeVariable v);
|
||||
|
||||
/** `sink` is a (potential) sink for the reachability analysis using variable `v`. */
|
||||
abstract predicate isSink(ControlFlowNode node, LocalScopeVariable v);
|
||||
|
||||
/** `node` is a barrier for the reachability analysis using variable `v` and starting from `source`. */
|
||||
abstract predicate isBarrier(
|
||||
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v
|
||||
);
|
||||
|
||||
/** See `LocalScopeVariableReachability.reaches`. */
|
||||
predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
exists(BasicBlock bb, int i |
|
||||
this.isSource(source, v) and
|
||||
bb.getNode(i) = source and
|
||||
not bb.isUnreachable()
|
||||
|
|
||||
exists(int j |
|
||||
j > i and
|
||||
sink = bb.getNode(j) and
|
||||
this.isSink(sink, v) and
|
||||
not exists(int k | this.isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) |
|
||||
k in [i .. j - 1]
|
||||
)
|
||||
)
|
||||
or
|
||||
not exists(int k | this.isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) | k >= i) and
|
||||
this.bbSuccessorEntryReaches(source, bb, v, sink, _)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate bbSuccessorEntryReaches(
|
||||
ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node,
|
||||
boolean skipsFirstLoopAlwaysTrueUponEntry
|
||||
) {
|
||||
exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
|
||||
bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
|
||||
succSkipsFirstLoopAlwaysTrueUponEntry) and
|
||||
not this.isBarrier(source, bb.getEnd(), succ.getStart(), v)
|
||||
|
|
||||
this.bbEntryReachesLocally(source, succ, v, node) and
|
||||
succSkipsFirstLoopAlwaysTrueUponEntry = false
|
||||
or
|
||||
not exists(int k | this.isBarrier(source, succ.getNode(k), succ.getNode(k + 1), v)) and
|
||||
this.bbSuccessorEntryReaches(source, succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate bbEntryReachesLocally(
|
||||
ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node
|
||||
) {
|
||||
this.isSource(source, v) and
|
||||
exists(int n | node = bb.getNode(n) and this.isSink(node, v) |
|
||||
not exists(int m | m < n | this.isBarrier(source, bb.getNode(m), bb.getNode(m + 1), v))
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -156,6 +156,15 @@ class AnalysedExpr extends Expr {
|
||||
this.isValidCheck(v) and result = this.getATrueSuccessor()
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getNonNullSuccessor` instead, which does the same.
|
||||
*/
|
||||
deprecated ControlFlowNode getValidSuccessor(LocalScopeVariable v) {
|
||||
this.isValidCheck(v) and result = this.getATrueSuccessor()
|
||||
or
|
||||
this.isNullCheck(v) and result = this.getAFalseSuccessor()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this is a `VariableAccess` of `v` nested inside a condition.
|
||||
*/
|
||||
|
||||
@@ -10,13 +10,10 @@ import SSAUtils
|
||||
* The SSA logic comes in two versions: the standard SSA and range-analysis RangeSSA.
|
||||
* This class provides the standard SSA logic.
|
||||
*/
|
||||
library class StandardSsa extends SsaHelper {
|
||||
StandardSsa() { this = 0 }
|
||||
library class StandardSSA extends SSAHelper {
|
||||
StandardSSA() { this = 0 }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for StandardSsa */
|
||||
deprecated class StandardSSA = StandardSsa;
|
||||
|
||||
/**
|
||||
* A definition of one or more SSA variables, including phi node definitions.
|
||||
* An _SSA variable_, as defined in the literature, is effectively the pair of
|
||||
@@ -30,22 +27,22 @@ deprecated class StandardSSA = StandardSsa;
|
||||
* statically seen to be unreachable.
|
||||
*/
|
||||
class SsaDefinition extends ControlFlowNodeBase {
|
||||
SsaDefinition() { exists(StandardSsa x | x.ssa_defn(_, this, _, _)) }
|
||||
SsaDefinition() { exists(StandardSSA x | x.ssa_defn(_, this, _, _)) }
|
||||
|
||||
/**
|
||||
* Gets a variable corresponding to an SSA StackVariable defined by
|
||||
* this definition.
|
||||
*/
|
||||
StackVariable getAVariable() { exists(StandardSsa x | x.ssa_defn(result, this, _, _)) }
|
||||
StackVariable getAVariable() { exists(StandardSSA x | x.ssa_defn(result, this, _, _)) }
|
||||
|
||||
/**
|
||||
* Gets a string representation of the SSA variable represented by the pair
|
||||
* `(this, v)`.
|
||||
*/
|
||||
string toString(StackVariable v) { exists(StandardSsa x | result = x.toString(this, v)) }
|
||||
string toString(StackVariable v) { exists(StandardSSA x | result = x.toString(this, v)) }
|
||||
|
||||
/** Gets a use of the SSA variable represented by the pair `(this, v)`. */
|
||||
VariableAccess getAUse(StackVariable v) { exists(StandardSsa x | result = x.getAUse(this, v)) }
|
||||
VariableAccess getAUse(StackVariable v) { exists(StandardSSA x | result = x.getAUse(this, v)) }
|
||||
|
||||
/**
|
||||
* Gets the control-flow node for this definition. This will usually be the
|
||||
@@ -65,7 +62,7 @@ class SsaDefinition extends ControlFlowNodeBase {
|
||||
BasicBlock getBasicBlock() { result.contains(this.getDefinition()) }
|
||||
|
||||
/** Holds if this definition is a phi node for variable `v`. */
|
||||
predicate isPhiNode(StackVariable v) { exists(StandardSsa x | x.phi_node(v, this)) }
|
||||
predicate isPhiNode(StackVariable v) { exists(StandardSSA x | x.phi_node(v, this)) }
|
||||
|
||||
/** Gets the location of this definition. */
|
||||
Location getLocation() { result = this.(ControlFlowNode).getLocation() }
|
||||
@@ -127,7 +124,7 @@ class SsaDefinition extends ControlFlowNodeBase {
|
||||
|
||||
/** Holds if `(this, v)` reaches the end of basic block `b`. */
|
||||
predicate reachesEndOfBB(StackVariable v, BasicBlock b) {
|
||||
exists(StandardSsa x | x.ssaDefinitionReachesEndOfBB(v, this, b))
|
||||
exists(StandardSSA x | x.ssaDefinitionReachesEndOfBB(v, this, b))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,4 +147,15 @@ class SsaDefinition extends ControlFlowNodeBase {
|
||||
Expr getAnUltimateDefiningValue(StackVariable v) {
|
||||
result = this.getAnUltimateSsaDefinition(v).getDefiningValue(v)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: this is the old name for `getAnUltimateDefiningValue`. The
|
||||
* name was confusing as it seemed analogous to `getDefinition` rather than
|
||||
* `getDefiningValue`. The SSA libraries for other languages use the name
|
||||
* `getAnUltimateSsaDefinition` to refer to a predicate named
|
||||
* `getAnUltimateSsaDefinition` in this class.
|
||||
*/
|
||||
deprecated Expr getAnUltimateDefinition(StackVariable v) {
|
||||
result = this.getAnUltimateDefiningValue(v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,10 +114,10 @@ private predicate live_at_exit_of_bb(StackVariable v, BasicBlock b) {
|
||||
|
||||
/** Common SSA logic for standard SSA and range-analysis SSA. */
|
||||
cached
|
||||
library class SsaHelper extends int {
|
||||
library class SSAHelper extends int {
|
||||
/* 0 = StandardSSA, 1 = RangeSSA */
|
||||
cached
|
||||
SsaHelper() { this in [0 .. 1] }
|
||||
SSAHelper() { this in [0 .. 1] }
|
||||
|
||||
/**
|
||||
* Override to insert a custom phi node for variable `v` at the start of
|
||||
@@ -311,6 +311,3 @@ library class SsaHelper extends int {
|
||||
ssa_use(v, result, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SsaHelper */
|
||||
deprecated class SSAHelper = SsaHelper;
|
||||
|
||||
@@ -80,11 +80,7 @@ abstract class StackVariableReachability extends string {
|
||||
j > i and
|
||||
sink = bb.getNode(j) and
|
||||
this.isSink(sink, v) and
|
||||
not exists(int k, ControlFlowNode node |
|
||||
node = bb.getNode(k) and this.isBarrier(pragma[only_bind_into](node), v)
|
||||
|
|
||||
k in [i + 1 .. j - 1]
|
||||
)
|
||||
not exists(int k | this.isBarrier(bb.getNode(k), v) | k in [i + 1 .. j - 1])
|
||||
)
|
||||
or
|
||||
not exists(int k | this.isBarrier(bb.getNode(k), v) | k > i) and
|
||||
|
||||
@@ -447,6 +447,26 @@ private predicate skipInitializer(Initializer init) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` is an expression in a static initializer that must be evaluated
|
||||
* at run time. This predicate computes "is non-const" instead of "is const" in
|
||||
* order to avoid recursion through forall.
|
||||
*/
|
||||
private predicate runtimeExprInStaticInitializer(Expr e) {
|
||||
inStaticInitializer(e) and
|
||||
if e instanceof AggregateLiteral
|
||||
then runtimeExprInStaticInitializer(e.getAChild())
|
||||
else not e.getFullyConverted().isConstant()
|
||||
}
|
||||
|
||||
/** Holds if `e` is part of the initializer of a local static variable. */
|
||||
private predicate inStaticInitializer(Expr e) {
|
||||
exists(LocalVariable local |
|
||||
local.isStatic() and
|
||||
e.getParent+() = local.getInitializer()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `i`th child of `n` in control-flow order, where the `i`-indexes are
|
||||
* contiguous, and the first index is 0.
|
||||
@@ -1359,7 +1379,7 @@ private module Cached {
|
||||
* true-successors and false-successors.
|
||||
*/
|
||||
cached
|
||||
predicate qlCfgSuccessor(Node n1, Node n2) {
|
||||
predicate qlCFGSuccessor(Node n1, Node n2) {
|
||||
exists(Node memberNode, Pos memberPos |
|
||||
subEdgeIncludingDestructors(any(Pos at | at.isAt()), n1, memberNode, memberPos) and
|
||||
normalGroupMember(memberNode, memberPos, n2)
|
||||
@@ -1368,32 +1388,23 @@ private module Cached {
|
||||
conditionalSuccessor(n1, _, n2)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for qlCfgSuccessor */
|
||||
deprecated predicate qlCFGSuccessor = qlCfgSuccessor/2;
|
||||
|
||||
/**
|
||||
* Holds if `n2` is a control-flow node such that the control-flow
|
||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is true.
|
||||
*/
|
||||
cached
|
||||
predicate qlCfgTrueSuccessor(Node n1, Node n2) {
|
||||
predicate qlCFGTrueSuccessor(Node n1, Node n2) {
|
||||
conditionalSuccessor(n1, true, n2) and
|
||||
not conditionalSuccessor(n1, false, n2)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for qlCfgTrueSuccessor */
|
||||
deprecated predicate qlCFGTrueSuccessor = qlCfgTrueSuccessor/2;
|
||||
|
||||
/**
|
||||
* Holds if `n2` is a control-flow node such that the control-flow
|
||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is false.
|
||||
*/
|
||||
cached
|
||||
predicate qlCfgFalseSuccessor(Node n1, Node n2) {
|
||||
predicate qlCFGFalseSuccessor(Node n1, Node n2) {
|
||||
conditionalSuccessor(n1, false, n2) and
|
||||
not conditionalSuccessor(n1, true, n2)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for qlCfgFalseSuccessor */
|
||||
deprecated predicate qlCFGFalseSuccessor = qlCfgFalseSuccessor/2;
|
||||
}
|
||||
|
||||
@@ -188,8 +188,8 @@ private predicate nonAnalyzableFunction(Function f) {
|
||||
*/
|
||||
private predicate impossibleFalseEdge(Expr condition, Node succ) {
|
||||
conditionAlwaysTrue(condition) and
|
||||
qlCfgFalseSuccessor(condition, succ) and
|
||||
not qlCfgTrueSuccessor(condition, succ)
|
||||
qlCFGFalseSuccessor(condition, succ) and
|
||||
not qlCFGTrueSuccessor(condition, succ)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,8 +197,8 @@ private predicate impossibleFalseEdge(Expr condition, Node succ) {
|
||||
*/
|
||||
private predicate impossibleTrueEdge(Expr condition, Node succ) {
|
||||
conditionAlwaysFalse(condition) and
|
||||
qlCfgTrueSuccessor(condition, succ) and
|
||||
not qlCfgFalseSuccessor(condition, succ)
|
||||
qlCFGTrueSuccessor(condition, succ) and
|
||||
not qlCFGFalseSuccessor(condition, succ)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -960,9 +960,9 @@ library class ConditionEvaluator extends ExprEvaluator {
|
||||
ConditionEvaluator() { this = 0 }
|
||||
|
||||
override predicate interesting(Expr e) {
|
||||
qlCfgFalseSuccessor(e, _)
|
||||
qlCFGFalseSuccessor(e, _)
|
||||
or
|
||||
qlCfgTrueSuccessor(e, _)
|
||||
qlCFGTrueSuccessor(e, _)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,4 +20,10 @@ import semmle.code.cpp.dataflow.DataFlow2
|
||||
|
||||
module TaintTracking {
|
||||
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||
private import semmle.code.cpp.dataflow.TaintTracking2
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use TaintTracking2::Configuration instead.
|
||||
*/
|
||||
deprecated class Configuration2 = TaintTracking2::Configuration;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,17 +3,6 @@ private import DataFlowImplSpecific::Public
|
||||
import Cached
|
||||
|
||||
module DataFlowImplCommonPublic {
|
||||
/** A state value to track during data flow. */
|
||||
class FlowState = string;
|
||||
|
||||
/**
|
||||
* The default state, which is used when the state is unspecified for a source
|
||||
* or a sink.
|
||||
*/
|
||||
class FlowStateEmpty extends FlowState {
|
||||
FlowStateEmpty() { this = "" }
|
||||
}
|
||||
|
||||
private newtype TFlowFeature =
|
||||
TFeatureHasSourceCallContext() or
|
||||
TFeatureHasSinkCallContext() or
|
||||
@@ -1290,7 +1279,7 @@ class DataFlowCallOption extends TDataFlowCallOption {
|
||||
}
|
||||
}
|
||||
|
||||
/** A `Content` tagged with the type of a containing object. */
|
||||
/** Content tagged with the type of a containing object. */
|
||||
class TypedContent extends MkTypedContent {
|
||||
private Content c;
|
||||
private DataFlowType t;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -48,7 +48,7 @@ private class Argument extends Expr {
|
||||
*/
|
||||
class ArgumentNode extends Node {
|
||||
ArgumentNode() {
|
||||
this.asExpr() instanceof Argument or
|
||||
exists(Argument arg | this.asExpr() = arg) or
|
||||
this = getInstanceArgument(_)
|
||||
}
|
||||
|
||||
|
||||
@@ -592,14 +592,12 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
* Holds if data flows from `source` to `sink` in zero or more local
|
||||
* (intra-procedural) steps.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `e1` to `e2` in zero or more
|
||||
* local (intra-procedural) steps.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)) }
|
||||
|
||||
/**
|
||||
|
||||
@@ -113,6 +113,10 @@ private module PartialDefinitions {
|
||||
abstract class PartialDefinition extends Expr {
|
||||
ControlFlowNode node;
|
||||
|
||||
abstract deprecated predicate partiallyDefines(Variable v);
|
||||
|
||||
abstract deprecated predicate partiallyDefinesThis(ThisExpr e);
|
||||
|
||||
/**
|
||||
* Gets the subBasicBlock where this `PartialDefinition` is defined.
|
||||
*/
|
||||
@@ -185,6 +189,10 @@ private module PartialDefinitions {
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate partiallyDefines(Variable v) { v = collection }
|
||||
|
||||
deprecated override predicate partiallyDefinesThis(ThisExpr e) { none() }
|
||||
|
||||
override predicate definesExpressions(Expr inner, Expr outer) {
|
||||
inner = innerDefinedExpr and
|
||||
outer = this
|
||||
@@ -209,6 +217,12 @@ private module PartialDefinitions {
|
||||
|
||||
VariablePartialDefinition() { innerDefinedExpr = getInnerDefinedExpr(this, node) }
|
||||
|
||||
deprecated override predicate partiallyDefines(Variable v) {
|
||||
innerDefinedExpr = v.getAnAccess()
|
||||
}
|
||||
|
||||
deprecated override predicate partiallyDefinesThis(ThisExpr e) { innerDefinedExpr = e }
|
||||
|
||||
/**
|
||||
* Holds if this partial definition may modify `inner` (or what it points
|
||||
* to) through `outer`. These expressions will never be `Conversion`s.
|
||||
@@ -339,9 +353,9 @@ module FlowVar_internal {
|
||||
// indirection.
|
||||
result = def.getAUse(v)
|
||||
or
|
||||
exists(SsaDefinition descendantDef |
|
||||
this.getASuccessorSsaVar+() = TSsaVar(descendantDef, _) and
|
||||
result = descendantDef.getAUse(v)
|
||||
exists(SsaDefinition descendentDef |
|
||||
this.getASuccessorSsaVar+() = TSsaVar(descendentDef, _) and
|
||||
result = descendentDef.getAUse(v)
|
||||
)
|
||||
)
|
||||
or
|
||||
@@ -421,7 +435,7 @@ module FlowVar_internal {
|
||||
parameterIsNonConstReference(p) and
|
||||
p = v and
|
||||
// This definition reaches the exit node of the function CFG
|
||||
getAReachedBlockVarSBB(this).getEnd() = p.getFunction()
|
||||
getAReachedBlockVarSBB(this).getANode() = p.getFunction()
|
||||
}
|
||||
|
||||
override predicate definedByInitialValue(StackVariable lsv) {
|
||||
|
||||
@@ -47,12 +47,6 @@ predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::Content c) { n
|
||||
*/
|
||||
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `guard` should be a sanitizer guard in all global taint flow configurations
|
||||
* but not in local taint.
|
||||
*/
|
||||
predicate defaultTaintSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
|
||||
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
|
||||
@@ -124,14 +118,12 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
|
||||
* Holds if taint may propagate from `source` to `sink` in zero or more local
|
||||
* (intra-procedural) steps.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) }
|
||||
|
||||
/**
|
||||
* Holds if taint can flow from `e1` to `e2` in zero or more
|
||||
* local (intra-procedural) steps.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate localExprTaint(Expr e1, Expr e2) {
|
||||
localTaint(DataFlow::exprNode(e1), DataFlow::exprNode(e2))
|
||||
}
|
||||
|
||||
@@ -61,32 +61,15 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
abstract override predicate isSource(DataFlow::Node source);
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant taint source with the given initial
|
||||
* `state`.
|
||||
* Holds if `sink` is a relevant taint sink.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSink(DataFlow::Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink accepting `state`.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
||||
abstract override predicate isSink(DataFlow::Node sink);
|
||||
|
||||
/** Holds if the node `node` is a taint sanitizer. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
@@ -96,29 +79,9 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the node `node` is a taint sanitizer when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isSanitizer(node, state)
|
||||
}
|
||||
|
||||
/** Holds if taint propagation into `node` is prohibited. */
|
||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if taint propagation into `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isSanitizerIn(node, state)
|
||||
}
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
@@ -126,31 +89,11 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||
|
||||
/**
|
||||
* Holds if taint propagation out of `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isSanitizerOut(node, state)
|
||||
}
|
||||
|
||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||
* when the flow state is `state`.
|
||||
*/
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||
this.isSanitizerGuard(guard, state)
|
||||
this.isSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,25 +107,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
defaultAdditionalTaintStep(node1, node2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
* must be taken into account in the analysis. This step is only applicable
|
||||
* in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
final override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
|
||||
@@ -61,32 +61,15 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
abstract override predicate isSource(DataFlow::Node source);
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant taint source with the given initial
|
||||
* `state`.
|
||||
* Holds if `sink` is a relevant taint sink.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSink(DataFlow::Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink accepting `state`.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
||||
abstract override predicate isSink(DataFlow::Node sink);
|
||||
|
||||
/** Holds if the node `node` is a taint sanitizer. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
@@ -96,29 +79,9 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the node `node` is a taint sanitizer when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isSanitizer(node, state)
|
||||
}
|
||||
|
||||
/** Holds if taint propagation into `node` is prohibited. */
|
||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if taint propagation into `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isSanitizerIn(node, state)
|
||||
}
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
@@ -126,31 +89,11 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||
|
||||
/**
|
||||
* Holds if taint propagation out of `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isSanitizerOut(node, state)
|
||||
}
|
||||
|
||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||
* when the flow state is `state`.
|
||||
*/
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||
this.isSanitizerGuard(guard, state)
|
||||
this.isSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,25 +107,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
defaultAdditionalTaintStep(node1, node2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
* must be taken into account in the analysis. This step is only applicable
|
||||
* in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
final override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
|
||||
@@ -84,8 +84,8 @@ class VariableAccess extends Access, @varaccess {
|
||||
exists(Assignment a | a.getLValue() = this) or
|
||||
exists(CrementOperation c | c.getOperand() = this) or
|
||||
exists(AddressOfExpr addof | addof.getOperand() = this) or
|
||||
this.getConversion() instanceof ReferenceToExpr or
|
||||
this.getConversion() instanceof ArrayToPointerConversion
|
||||
exists(ReferenceToExpr rte | this.getConversion() = rte) or
|
||||
exists(ArrayToPointerConversion atpc | this.getConversion() = atpc)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,8 +104,8 @@ class VariableAccess extends Access, @varaccess {
|
||||
predicate isRValue() {
|
||||
not exists(AssignExpr ae | ae.getLValue() = this) and
|
||||
not exists(AddressOfExpr addof | addof.getOperand() = this) and
|
||||
not this.getConversion() instanceof ReferenceToExpr and
|
||||
not this.getConversion() instanceof ArrayToPointerConversion
|
||||
not exists(ReferenceToExpr rte | this.getConversion() = rte) and
|
||||
not exists(ArrayToPointerConversion atpc | this.getConversion() = atpc)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,7 +218,9 @@ class PointerFieldAccess extends FieldAccess {
|
||||
class DotFieldAccess extends FieldAccess {
|
||||
override string getAPrimaryQlClass() { result = "DotFieldAccess" }
|
||||
|
||||
DotFieldAccess() { this.getQualifier().getFullyConverted().getUnspecifiedType() instanceof Class }
|
||||
DotFieldAccess() {
|
||||
exists(Class c | c = this.getQualifier().getFullyConverted().getUnspecifiedType())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -226,6 +226,13 @@ class AssignPointerSubExpr extends AssignOperation, @assignpsubexpr {
|
||||
* ```
|
||||
*/
|
||||
class ConditionDeclExpr extends Expr, @condition_decl {
|
||||
/**
|
||||
* DEPRECATED: Use `getVariableAccess()` or `getInitializingExpr()` instead.
|
||||
*
|
||||
* Gets the access using the condition for this declaration.
|
||||
*/
|
||||
deprecated Expr getExpr() { result = this.getChild(0) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConditionDeclExpr" }
|
||||
|
||||
/**
|
||||
|
||||
@@ -118,6 +118,11 @@ class BuiltInNoOp extends BuiltInOperation, @noopexpr {
|
||||
override string getAPrimaryQlClass() { result = "BuiltInNoOp" }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `BuiltInOperationBuiltInOffsetOf` instead.
|
||||
*/
|
||||
deprecated class BuiltInOperationOffsetOf = BuiltInOperationBuiltInOffsetOf;
|
||||
|
||||
/**
|
||||
* A C/C++ `__builtin_offsetof` built-in operation (used by some implementations
|
||||
* of `offsetof`). The operation retains its semantics even in the presence
|
||||
@@ -460,6 +465,11 @@ class BuiltInOperationIsUnion extends BuiltInOperation, @isunionexpr {
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsUnion" }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `BuiltInOperationBuiltInTypesCompatibleP` instead.
|
||||
*/
|
||||
deprecated class BuiltInOperationBuiltInTypes = BuiltInOperationBuiltInTypesCompatibleP;
|
||||
|
||||
/**
|
||||
* A C++ `__builtin_types_compatible_p` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
|
||||
@@ -35,7 +35,7 @@ class Call extends Expr, NameQualifiableElement, TCall {
|
||||
*
|
||||
* For example, `ptr->f()` has a qualifier, whereas plain `f()` does not.
|
||||
*/
|
||||
predicate hasQualifier() { exists(this.getChild(-1)) }
|
||||
predicate hasQualifier() { exists(Expr e | this.getChild(-1) = e) }
|
||||
|
||||
/**
|
||||
* Gets the expression to the left of the function name or function pointer variable name.
|
||||
|
||||
@@ -666,6 +666,13 @@ class TypeidOperator extends Expr, @type_id {
|
||||
*/
|
||||
Type getResultType() { typeid_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getResultType()` instead.
|
||||
*
|
||||
* Gets the type that is returned by this typeid expression.
|
||||
*/
|
||||
deprecated Type getSpecifiedType() { result = this.getResultType() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TypeidOperator" }
|
||||
|
||||
/**
|
||||
@@ -717,13 +724,20 @@ class SizeofOperator extends Expr, @runtime_sizeof {
|
||||
* ```
|
||||
*/
|
||||
class SizeofExprOperator extends SizeofOperator {
|
||||
SizeofExprOperator() { exists(this.getChild(0)) }
|
||||
SizeofExprOperator() { exists(Expr e | this.getChild(0) = e) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SizeofExprOperator" }
|
||||
|
||||
/** Gets the contained expression. */
|
||||
Expr getExprOperand() { result = this.getChild(0) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getExprOperand()` instead
|
||||
*
|
||||
* Gets the contained expression.
|
||||
*/
|
||||
deprecated Expr getExpr() { result = this.getExprOperand() }
|
||||
|
||||
override string toString() { result = "sizeof(<expr>)" }
|
||||
|
||||
override predicate mayBeImpure() { this.getExprOperand().mayBeImpure() }
|
||||
@@ -745,6 +759,13 @@ class SizeofTypeOperator extends SizeofOperator {
|
||||
/** Gets the contained type. */
|
||||
Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getTypeOperand()` instead
|
||||
*
|
||||
* Gets the contained type.
|
||||
*/
|
||||
deprecated Type getSpecifiedType() { result = this.getTypeOperand() }
|
||||
|
||||
override string toString() { result = "sizeof(" + this.getTypeOperand().getName() + ")" }
|
||||
|
||||
override predicate mayBeImpure() { none() }
|
||||
@@ -766,13 +787,18 @@ class AlignofOperator extends Expr, @runtime_alignof {
|
||||
* ```
|
||||
*/
|
||||
class AlignofExprOperator extends AlignofOperator {
|
||||
AlignofExprOperator() { exists(this.getChild(0)) }
|
||||
AlignofExprOperator() { exists(Expr e | this.getChild(0) = e) }
|
||||
|
||||
/**
|
||||
* Gets the contained expression.
|
||||
*/
|
||||
Expr getExprOperand() { result = this.getChild(0) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getExprOperand()` instead.
|
||||
*/
|
||||
deprecated Expr getExpr() { result = this.getExprOperand() }
|
||||
|
||||
override string toString() { result = "alignof(<expr>)" }
|
||||
}
|
||||
|
||||
@@ -788,6 +814,11 @@ class AlignofTypeOperator extends AlignofOperator {
|
||||
/** Gets the contained type. */
|
||||
Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getTypeOperand()` instead.
|
||||
*/
|
||||
deprecated Type getSpecifiedType() { result = this.getTypeOperand() }
|
||||
|
||||
override string toString() { result = "alignof(" + this.getTypeOperand().getName() + ")" }
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user