mirror of
https://github.com/github/codeql.git
synced 2026-05-27 09:31:30 +02:00
Compare commits
16 Commits
criemen/ba
...
mbg/go/imp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12bc9f84bd | ||
|
|
f64e617da2 | ||
|
|
97b95337b6 | ||
|
|
a8d87ea4ea | ||
|
|
dfa23197c7 | ||
|
|
8a9fd8c619 | ||
|
|
42ee9afc69 | ||
|
|
c6809c46f5 | ||
|
|
0174a16d5a | ||
|
|
69bf334a33 | ||
|
|
01597ec23b | ||
|
|
c9d1aa6354 | ||
|
|
4666ed9957 | ||
|
|
4e701a12db | ||
|
|
628064118f | ||
|
|
648b28c1d2 |
10
.bazelrc
10
.bazelrc
@@ -10,19 +10,15 @@ common --override_module=semmle_code=%workspace%/misc/bazel/semmle_code_stub
|
||||
|
||||
build --repo_env=CC=clang --repo_env=CXX=clang++
|
||||
|
||||
# we use transitions that break builds of `...`, so for `test` to work with that we need the following
|
||||
test --build_tests_only
|
||||
build:linux --cxxopt=-std=c++20
|
||||
build:macos --cxxopt=-std=c++20 --cpu=darwin_x86_64
|
||||
build:windows --cxxopt=/std:c++20 --cxxopt=/Zc:preprocessor
|
||||
|
||||
# this requires developer mode, but is required to have pack installer functioning
|
||||
startup --windows_enable_symlinks
|
||||
common --enable_runfiles
|
||||
|
||||
# with the above, we can avoid building python zips which is the default on windows as that's expensive
|
||||
build --nobuild_python_zip
|
||||
|
||||
common --registry=file:///%workspace%/misc/bazel/registry
|
||||
common --registry=https://bcr.bazel.build
|
||||
|
||||
common --@rules_dotnet//dotnet/settings:strict_deps=false
|
||||
|
||||
try-import %workspace%/local.bazelrc
|
||||
|
||||
@@ -2,9 +2,3 @@
|
||||
|
||||
common --registry=file:///%workspace%/ql/misc/bazel/registry
|
||||
common --registry=https://bcr.bazel.build
|
||||
|
||||
# See bazelbuild/rules_dotnet#413: strict_deps in C# also appliy to 3rd-party deps, and when we pull
|
||||
# in (for example) the xunit package, there's no code in this at all, it just depends transitively on
|
||||
# its implementation packages without providing any code itself.
|
||||
# We either can depend on internal implementation details, or turn of strict deps.
|
||||
common --@rules_dotnet//dotnet/settings:strict_deps=false
|
||||
|
||||
@@ -1 +1 @@
|
||||
7.1.2
|
||||
7.1.0
|
||||
|
||||
34
.gitattributes
vendored
34
.gitattributes
vendored
@@ -50,40 +50,26 @@
|
||||
*.dll -text
|
||||
*.pdb -text
|
||||
|
||||
/java/ql/test/stubs/**/*.java linguist-generated=true
|
||||
/java/ql/test/experimental/stubs/**/*.java linguist-generated=true
|
||||
/java/kotlin-extractor/deps/*.jar filter=lfs diff=lfs merge=lfs -text
|
||||
java/ql/test/stubs/**/*.java linguist-generated=true
|
||||
java/ql/test/experimental/stubs/**/*.java linguist-generated=true
|
||||
|
||||
# Force git not to modify line endings for go or html files under the go/ql directory
|
||||
/go/ql/**/*.go -text
|
||||
/go/ql/**/*.html -text
|
||||
go/ql/**/*.go -text
|
||||
go/ql/**/*.html -text
|
||||
# Force git not to modify line endings for go dbschemes
|
||||
/go/*.dbscheme -text
|
||||
go/*.dbscheme -text
|
||||
# Preserve unusual line ending from codeql-go merge
|
||||
/go/extractor/opencsv/CSVReader.java -text
|
||||
go/extractor/opencsv/CSVReader.java -text
|
||||
|
||||
# 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
|
||||
*/ql/lib/upgrades/initial/*.dbscheme -text
|
||||
|
||||
# Auto-generated modeling for Python
|
||||
/python/ql/lib/semmle/python/frameworks/data/internal/subclass-capture/*.yml linguist-generated=true
|
||||
python/ql/lib/semmle/python/frameworks/data/internal/subclass-capture/*.yml linguist-generated=true
|
||||
|
||||
# auto-generated bazel lock file
|
||||
/ruby/extractor/cargo-bazel-lock.json linguist-generated=true
|
||||
/ruby/extractor/cargo-bazel-lock.json -merge
|
||||
|
||||
# auto-generated files for the C# build
|
||||
/csharp/paket.lock linguist-generated=true
|
||||
# needs eol=crlf, as `paket` touches this file and saves it as crlf
|
||||
/csharp/.paket/Paket.Restore.targets linguist-generated=true eol=crlf
|
||||
/csharp/paket.main.bzl linguist-generated=true
|
||||
/csharp/paket.main_extension.bzl linguist-generated=true
|
||||
|
||||
# ripunzip tool
|
||||
/misc/ripunzip/ripunzip-* filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
# swift prebuilt resources
|
||||
/swift/third_party/resource-dir/*.zip filter=lfs diff=lfs merge=lfs -text
|
||||
ruby/extractor/cargo-bazel-lock.json linguist-generated=true
|
||||
ruby/extractor/cargo-bazel-lock.json -merge
|
||||
|
||||
74
.github/workflows/build-ripunzip.yml
vendored
74
.github/workflows/build-ripunzip.yml
vendored
@@ -1,74 +0,0 @@
|
||||
name: Build runzip
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ripunzip-version:
|
||||
description: "what reference to checktout from google/runzip"
|
||||
required: false
|
||||
default: v1.2.1
|
||||
openssl-version:
|
||||
description: "what reference to checkout from openssl/openssl for Linux"
|
||||
required: false
|
||||
default: openssl-3.3.0
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-20.04, macos-12, windows-2019]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: google/ripunzip
|
||||
ref: ${{ inputs.ripunzip-version }}
|
||||
# we need to avoid ripunzip dynamically linking into libssl
|
||||
# see https://github.com/sfackler/rust-openssl/issues/183
|
||||
- if: runner.os == 'Linux'
|
||||
name: checkout openssl
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: openssl/openssl
|
||||
path: openssl
|
||||
ref: ${{ inputs.openssl-version }}
|
||||
- if: runner.os == 'Linux'
|
||||
name: build and install openssl with fPIC
|
||||
shell: bash
|
||||
working-directory: openssl
|
||||
run: |
|
||||
./config -fPIC --prefix=$HOME/.local --openssldir=$HOME/.local/ssl
|
||||
make -j $(nproc)
|
||||
make install_sw -j $(nproc)
|
||||
- if: runner.os == 'Linux'
|
||||
name: build (linux)
|
||||
shell: bash
|
||||
run: |
|
||||
env OPENSSL_LIB_DIR=$HOME/.local/lib64 OPENSSL_INCLUDE_DIR=$HOME/.local/include OPENSSL_STATIC=yes cargo build --release
|
||||
mv target/release/ripunzip ripunzip-linux
|
||||
- if: runner.os == 'Windows'
|
||||
name: build (windows)
|
||||
shell: bash
|
||||
run: |
|
||||
cargo build --release
|
||||
mv target/release/ripunzip ripunzip-windows
|
||||
- name: build (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
shell: bash
|
||||
run: |
|
||||
rustup target install x86_64-apple-darwin
|
||||
rustup target install aarch64-apple-darwin
|
||||
cargo build --target x86_64-apple-darwin --release
|
||||
cargo build --target aarch64-apple-darwin --release
|
||||
lipo -create -output ripunzip-macos \
|
||||
-arch x86_64 target/x86_64-apple-darwin/release/ripunzip \
|
||||
-arch arm64 target/aarch64-apple-darwin/release/ripunzip
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ripunzip-${{ runner.os }}
|
||||
path: ripunzip-*
|
||||
- name: Check built binary
|
||||
shell: bash
|
||||
run: |
|
||||
./ripunzip-* --version
|
||||
4
.github/workflows/codeql-analysis.yml
vendored
4
.github/workflows/codeql-analysis.yml
vendored
@@ -56,9 +56,7 @@ jobs:
|
||||
# uses a compiled language
|
||||
|
||||
- run: |
|
||||
cd csharp
|
||||
dotnet tool restore
|
||||
dotnet build .
|
||||
dotnet build csharp
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@main
|
||||
|
||||
7
.github/workflows/csharp-qltest.yml
vendored
7
.github/workflows/csharp-qltest.yml
vendored
@@ -65,7 +65,7 @@ jobs:
|
||||
key: csharp-qltest-${{ matrix.slice }}
|
||||
- name: Run QL tests
|
||||
run: |
|
||||
codeql test run --threads=0 --ram 50000 --slice ${{ matrix.slice }} --search-path "${{ github.workspace }}" --check-databases --check-undefined-labels --check-repeated-labels --check-redefined-labels --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
codeql test run --threads=0 --ram 50000 --slice ${{ matrix.slice }} --search-path extractor-pack --check-databases --check-undefined-labels --check-repeated-labels --check-redefined-labels --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
unit-tests:
|
||||
@@ -81,11 +81,10 @@ jobs:
|
||||
dotnet-version: 8.0.101
|
||||
- name: Extractor unit tests
|
||||
run: |
|
||||
dotnet tool restore
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.1 extractor/Semmle.Util.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.1 extractor/Semmle.Extraction.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.1 autobuilder/Semmle.Autobuild.CSharp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.1 autobuilder/Semmle.Autobuild.Cpp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.1 "${{ github.workspace }}/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests"
|
||||
shell: bash
|
||||
stubgentest:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -101,6 +100,6 @@ jobs:
|
||||
# Update existing stubs in the repo with the freshly generated ones
|
||||
mv "$STUBS_PATH/output/stubs/_frameworks" ql/test/resources/stubs/
|
||||
git status
|
||||
codeql test run --threads=0 --search-path "${{ github.workspace }}" --check-databases --check-undefined-labels --check-repeated-labels --check-redefined-labels --consistency-queries ql/consistency-queries -- ql/test/library-tests/dataflow/flowsources/aspremote
|
||||
codeql test run --threads=0 --search-path extractor-pack --check-databases --check-undefined-labels --check-repeated-labels --check-redefined-labels --consistency-queries ql/consistency-queries -- ql/test/library-tests/dataflow/flowsources/aspremote
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
68
.github/workflows/go-tests-other-os.yml
vendored
68
.github/workflows/go-tests-other-os.yml
vendored
@@ -7,9 +7,8 @@ on:
|
||||
- .github/workflows/go-tests-other-os.yml
|
||||
- .github/actions/**
|
||||
- codeql-workspace.yml
|
||||
- MODULE.bazel
|
||||
- .bazelrc
|
||||
- misc/bazel/**
|
||||
env:
|
||||
GO_VERSION: '~1.22.0'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -19,17 +18,72 @@ jobs:
|
||||
name: Test MacOS
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
id: go
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Run tests
|
||||
uses: ./go/actions/test
|
||||
|
||||
- name: Set up CodeQL CLI
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
|
||||
- name: Enable problem matchers in repository
|
||||
shell: bash
|
||||
run: 'find .github/problem-matchers -name \*.json -exec echo "::add-matcher::{}" \;'
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd go
|
||||
make
|
||||
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: go-qltest
|
||||
- name: Test
|
||||
run: |
|
||||
cd go
|
||||
make test cache="${{ steps.query-cache.outputs.cache-dir }}"
|
||||
|
||||
test-win:
|
||||
if: github.repository_owner == 'github'
|
||||
name: Test Windows
|
||||
runs-on: windows-latest-xl
|
||||
steps:
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
id: go
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Run tests
|
||||
uses: ./go/actions/test
|
||||
|
||||
- name: Set up CodeQL CLI
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
|
||||
- name: Enable problem matchers in repository
|
||||
shell: bash
|
||||
run: 'find .github/problem-matchers -name \*.json -exec echo "::add-matcher::{}" \;'
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd go
|
||||
make
|
||||
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: go-qltest
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
cd go
|
||||
make test cache="${{ steps.query-cache.outputs.cache-dir }}"
|
||||
|
||||
54
.github/workflows/go-tests.yml
vendored
54
.github/workflows/go-tests.yml
vendored
@@ -15,9 +15,9 @@ on:
|
||||
- .github/workflows/go-tests.yml
|
||||
- .github/actions/**
|
||||
- codeql-workspace.yml
|
||||
- MODULE.bazel
|
||||
- .bazelrc
|
||||
- misc/bazel/**
|
||||
|
||||
env:
|
||||
GO_VERSION: '~1.22.0'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -28,9 +28,51 @@ jobs:
|
||||
name: Test Linux (Ubuntu)
|
||||
runs-on: ubuntu-latest-xl
|
||||
steps:
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
id: go
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Run tests
|
||||
uses: ./go/actions/test
|
||||
|
||||
- name: Set up CodeQL CLI
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
|
||||
- name: Enable problem matchers in repository
|
||||
shell: bash
|
||||
run: 'find .github/problem-matchers -name \*.json -exec echo "::add-matcher::{}" \;'
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd go
|
||||
make
|
||||
|
||||
- name: Check that all Go code is autoformatted
|
||||
run: |
|
||||
cd go
|
||||
make check-formatting
|
||||
|
||||
- name: Compile qhelp files to markdown
|
||||
run: |
|
||||
cd go
|
||||
env QHELP_OUT_DIR=qhelp-out make qhelp-to-markdown
|
||||
|
||||
- name: Upload qhelp markdown
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
run-code-checks: true
|
||||
name: qhelp-markdown
|
||||
path: go/qhelp-out/**/*.md
|
||||
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: go-qltest
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
cd go
|
||||
make test cache="${{ steps.query-cache.outputs.cache-dir }}"
|
||||
|
||||
28
.github/workflows/kotlin-build.yml
vendored
28
.github/workflows/kotlin-build.yml
vendored
@@ -1,28 +0,0 @@
|
||||
name: "Kotlin Build"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "java/kotlin-extractor/**"
|
||||
- "misc/bazel/**"
|
||||
- "misc/codegen/**"
|
||||
- "*.bazel*"
|
||||
- .github/workflows/kotlin-build.yml
|
||||
branches:
|
||||
- main
|
||||
- rc/*
|
||||
- codeql-cli-*
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: |
|
||||
bazel query //java/kotlin-extractor/...
|
||||
# only build the default version as a quick check that we can build from `codeql`
|
||||
# the full official build will be checked by QLucie
|
||||
bazel build //java/kotlin-extractor
|
||||
10
.github/workflows/ql-for-ql-build.yml
vendored
10
.github/workflows/ql-for-ql-build.yml
vendored
@@ -49,20 +49,20 @@ jobs:
|
||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
|
||||
- name: Release build
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
run: cd ql; ./scripts/create-extractor-pack.sh
|
||||
run: cd ql; ./scripts/create-extractor-pack.sh
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
with:
|
||||
key: run-ql-for-ql
|
||||
- name: Make database and analyze
|
||||
run: |
|
||||
./ql/target/release/buramu | tee deprecated.blame # Add a blame file for the extractor to parse.
|
||||
${CODEQL} database create -l=ql ${DB} --search-path "${{ github.workspace }}"
|
||||
${CODEQL} database create -l=ql --search-path ql/extractor-pack ${DB}
|
||||
${CODEQL} database analyze -j0 --format=sarif-latest --output=ql-for-ql.sarif ${DB} ql/ql/src/codeql-suites/ql-code-scanning.qls --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
env:
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
DB: ${{ runner.temp }}/DB
|
||||
LGTM_INDEX_FILTERS: |
|
||||
|
||||
@@ -53,8 +53,8 @@ jobs:
|
||||
- name: Create database
|
||||
run: |
|
||||
"${CODEQL}" database create \
|
||||
--search-path "${{ github.workspace }}"
|
||||
--threads 4 \
|
||||
--search-path "ql/extractor-pack" \
|
||||
--threads 4 \
|
||||
--language ql --source-root "${{ github.workspace }}/repo" \
|
||||
"${{ runner.temp }}/database"
|
||||
env:
|
||||
|
||||
13
.github/workflows/ql-for-ql-tests.yml
vendored
13
.github/workflows/ql-for-ql-tests.yml
vendored
@@ -49,15 +49,15 @@ jobs:
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
with:
|
||||
key: ql-for-ql-tests
|
||||
- name: Run QL tests
|
||||
run: |
|
||||
"${CODEQL}" test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}" --consistency-queries ql/ql/consistency-queries --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" ql/ql/test
|
||||
"${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 --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" ql/ql/test
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
|
||||
other-os:
|
||||
other-os:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest]
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install GNU tar
|
||||
- name: Install GNU tar
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew install gnu-tar
|
||||
@@ -100,7 +100,7 @@ jobs:
|
||||
- name: Run a single QL tests - Unix
|
||||
if: runner.os != 'Windows'
|
||||
run: |
|
||||
"${CODEQL}" test run --check-databases --search-path "${{ github.workspace }}" ql/ql/test/queries/style/DeadCode/DeadCode.qlref
|
||||
"${CODEQL}" test run --check-databases --search-path "${{ github.workspace }}/ql/extractor-pack" ql/ql/test/queries/style/DeadCode/DeadCode.qlref
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
- name: Run a single QL tests - Windows
|
||||
@@ -108,4 +108,5 @@ jobs:
|
||||
shell: pwsh
|
||||
run: |
|
||||
$Env:PATH += ";$(dirname ${{ steps.find-codeql.outputs.codeql-path }})"
|
||||
codeql test run --check-databases --search-path "${{ github.workspace }}" ql/ql/test/queries/style/DeadCode/DeadCode.qlref
|
||||
codeql test run --check-databases --search-path "${{ github.workspace }}/ql/extractor-pack" ql/ql/test/queries/style/DeadCode/DeadCode.qlref
|
||||
|
||||
2
.github/workflows/ruby-dataset-measure.yml
vendored
2
.github/workflows/ruby-dataset-measure.yml
vendored
@@ -44,7 +44,7 @@ jobs:
|
||||
- name: Create database
|
||||
run: |
|
||||
codeql database create \
|
||||
--search-path "${{ github.workspace }}" \
|
||||
--search-path "${{ github.workspace }}/ruby/extractor-pack" \
|
||||
--threads 4 \
|
||||
--language ruby --source-root "${{ github.workspace }}/repo" \
|
||||
"${{ runner.temp }}/database"
|
||||
|
||||
4
.github/workflows/ruby-qltest.yml
vendored
4
.github/workflows/ruby-qltest.yml
vendored
@@ -64,10 +64,10 @@ jobs:
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
with:
|
||||
key: ruby-qltest
|
||||
- name: Run QL tests
|
||||
run: |
|
||||
codeql test run --threads=0 --ram 50000 --search-path "${{ github.workspace }}" --check-databases --check-undefined-labels --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
codeql test run --threads=0 --ram 50000 --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-undefined-labels --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
15
.github/workflows/swift.yml
vendored
15
.github/workflows/swift.yml
vendored
@@ -68,6 +68,21 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./swift/actions/run-ql-tests
|
||||
integration-tests-linux:
|
||||
if: github.repository_owner == 'github'
|
||||
needs: build-and-test-linux
|
||||
runs-on: ubuntu-latest-xl
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./swift/actions/run-integration-tests
|
||||
integration-tests-macos:
|
||||
if: ${{ github.repository_owner == 'github' && github.event_name == 'pull_request' }}
|
||||
needs: build-and-test-macos
|
||||
runs-on: macos-12-xl
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./swift/actions/run-integration-tests
|
||||
clang-format:
|
||||
if : ${{ github.event_name == 'pull_request' }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
23
.github/workflows/zipmerge-test.yml
vendored
23
.github/workflows/zipmerge-test.yml
vendored
@@ -1,23 +0,0 @@
|
||||
name: "Test zipmerge code"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "misc/bazel/internal/zipmerge/**"
|
||||
- "MODULE.bazel"
|
||||
- ".bazelrc*"
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: |
|
||||
bazel test //misc/bazel/internal/zipmerge:test --test_output=all
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -62,6 +62,3 @@ node_modules/
|
||||
|
||||
# Temporary folders for working with generated models
|
||||
.model-temp
|
||||
|
||||
# bazel-built in-tree extractor packs
|
||||
/*/extractor-pack
|
||||
|
||||
@@ -2,6 +2,4 @@
|
||||
# codeql is publicly forked by many users, and we don't want any LFS file polluting their working
|
||||
# copies. We therefore exclude everything by default.
|
||||
# For files required by bazel builds, use rules in `misc/bazel/lfs.bzl` to download them on demand.
|
||||
# we go for `fetchinclude` to something not exsiting rather than `fetchexclude = *` because the
|
||||
# former is easier to override (with `git -c` or a local git config) to fetch something specific
|
||||
fetchinclude = /nothing
|
||||
|
||||
@@ -29,13 +29,12 @@ repos:
|
||||
entry: bazel run //misc/bazel:buildifier
|
||||
pass_filenames: false
|
||||
|
||||
# DISABLED: can be enabled by copying this config and installing `pre-commit` with `--config` on the copy
|
||||
# - id: go-gen
|
||||
# name: Check checked in generated files in go
|
||||
# files: ^go/.*
|
||||
# language: system
|
||||
# entry: bazel run //go:gen
|
||||
# pass_filenames: false
|
||||
- id: go-gen
|
||||
name: Check checked in generated files in go
|
||||
files: ^go/.*
|
||||
language: system
|
||||
entry: bazel run //go:gen
|
||||
pass_filenames: false
|
||||
|
||||
- id: codeql-format
|
||||
name: Fix QL file formatting
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
exports_files(["LICENSE"])
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/cpp/ @github/codeql-c-analysis
|
||||
/cpp/autobuilder/ @github/codeql-c-extractor
|
||||
/csharp/ @github/codeql-csharp
|
||||
/csharp/autobuilder/Semmle.Autobuild.Cpp @github/codeql-c-extractor
|
||||
/csharp/autobuilder/Semmle.Autobuild.Cpp.Tests @github/codeql-c-extractor
|
||||
/go/ @github/codeql-go
|
||||
/java/ @github/codeql-java
|
||||
/javascript/ @github/codeql-javascript
|
||||
|
||||
@@ -4,8 +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://codeql.github.com/docs/writing-codeql-queries/codeql-queries) on [codeql.github.com](https://codeql.github.com).
|
||||
|
||||
Note that the CodeQL for Visual Studio Code documentation has been migrated to https://docs.github.com/en/code-security/codeql-for-vs-code/, but you can still contribute to it via a different repository. For more information, see [Contributing to GitHub Docs documentation](https://docs.github.com/en/contributing)."
|
||||
|
||||
## 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).
|
||||
@@ -45,7 +43,7 @@ If you have an idea for a query that you would like to share with other CodeQL u
|
||||
|
||||
3. **Formatting**
|
||||
|
||||
- The queries and libraries must be autoformatted, for example using the "Format Document" command in [CodeQL for Visual Studio Code](https://docs.github.com/en/code-security/codeql-for-vs-code/).
|
||||
- The queries and libraries must be autoformatted, for example using the "Format Document" command in [CodeQL for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/about-codeql-for-visual-studio-code).
|
||||
|
||||
If you prefer, you can either:
|
||||
1. install the [pre-commit framework](https://pre-commit.com/) and install the configured hooks on this repo via `pre-commit install`, or
|
||||
|
||||
87
MODULE.bazel
87
MODULE.bazel
@@ -22,22 +22,10 @@ bazel_dep(name = "bazel_skylib", version = "1.5.0")
|
||||
bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl")
|
||||
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||
bazel_dep(name = "fmt", version = "10.0.0")
|
||||
bazel_dep(name = "rules_kotlin", version = "1.9.4-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.36.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.15.1")
|
||||
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
|
||||
|
||||
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
|
||||
|
||||
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
|
||||
dotnet.toolchain(dotnet_version = "8.0.101")
|
||||
use_repo(dotnet, "dotnet_toolchains")
|
||||
|
||||
register_toolchains("@dotnet_toolchains//:all")
|
||||
|
||||
csharp_main_extension = use_extension("//csharp:paket.main_extension.bzl", "main_extension")
|
||||
use_repo(csharp_main_extension, "paket.main")
|
||||
|
||||
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
|
||||
pip.parse(
|
||||
hub_name = "codegen_deps",
|
||||
@@ -66,84 +54,9 @@ node.toolchain(
|
||||
)
|
||||
use_repo(node, "nodejs", "nodejs_toolchains")
|
||||
|
||||
kotlin_extractor_deps = use_extension("//java/kotlin-extractor:deps.bzl", "kotlin_extractor_deps")
|
||||
|
||||
# following list can be kept in sync by running `bazel mod tidy` in `codeql`
|
||||
use_repo(
|
||||
kotlin_extractor_deps,
|
||||
"codeql_kotlin_defaults",
|
||||
"codeql_kotlin_embeddable",
|
||||
"kotlin-compiler-1.5.0",
|
||||
"kotlin-compiler-1.5.10",
|
||||
"kotlin-compiler-1.5.20",
|
||||
"kotlin-compiler-1.5.30",
|
||||
"kotlin-compiler-1.6.0",
|
||||
"kotlin-compiler-1.6.20",
|
||||
"kotlin-compiler-1.7.0",
|
||||
"kotlin-compiler-1.7.20",
|
||||
"kotlin-compiler-1.8.0",
|
||||
"kotlin-compiler-1.9.0-Beta",
|
||||
"kotlin-compiler-1.9.20-Beta",
|
||||
"kotlin-compiler-2.0.0-RC1",
|
||||
"kotlin-compiler-embeddable-1.5.0",
|
||||
"kotlin-compiler-embeddable-1.5.10",
|
||||
"kotlin-compiler-embeddable-1.5.20",
|
||||
"kotlin-compiler-embeddable-1.5.30",
|
||||
"kotlin-compiler-embeddable-1.6.0",
|
||||
"kotlin-compiler-embeddable-1.6.20",
|
||||
"kotlin-compiler-embeddable-1.7.0",
|
||||
"kotlin-compiler-embeddable-1.7.20",
|
||||
"kotlin-compiler-embeddable-1.8.0",
|
||||
"kotlin-compiler-embeddable-1.9.0-Beta",
|
||||
"kotlin-compiler-embeddable-1.9.20-Beta",
|
||||
"kotlin-compiler-embeddable-2.0.0-RC1",
|
||||
"kotlin-stdlib-1.5.0",
|
||||
"kotlin-stdlib-1.5.10",
|
||||
"kotlin-stdlib-1.5.20",
|
||||
"kotlin-stdlib-1.5.30",
|
||||
"kotlin-stdlib-1.6.0",
|
||||
"kotlin-stdlib-1.6.20",
|
||||
"kotlin-stdlib-1.7.0",
|
||||
"kotlin-stdlib-1.7.20",
|
||||
"kotlin-stdlib-1.8.0",
|
||||
"kotlin-stdlib-1.9.0-Beta",
|
||||
"kotlin-stdlib-1.9.20-Beta",
|
||||
"kotlin-stdlib-2.0.0-RC1",
|
||||
)
|
||||
|
||||
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
|
||||
go_sdk.download(version = "1.22.2")
|
||||
|
||||
lfs_files = use_repo_rule("//misc/bazel:lfs.bzl", "lfs_files")
|
||||
|
||||
lfs_files(
|
||||
name = "ripunzip-linux",
|
||||
srcs = ["//misc/ripunzip:ripunzip-linux"],
|
||||
executable = True,
|
||||
)
|
||||
|
||||
lfs_files(
|
||||
name = "ripunzip-windows",
|
||||
srcs = ["//misc/ripunzip:ripunzip-windows.exe"],
|
||||
executable = True,
|
||||
)
|
||||
|
||||
lfs_files(
|
||||
name = "ripunzip-macos",
|
||||
srcs = ["//misc/ripunzip:ripunzip-macos"],
|
||||
executable = True,
|
||||
)
|
||||
|
||||
lfs_files(
|
||||
name = "swift-resource-dir-linux",
|
||||
srcs = ["//swift/third_party/resource-dir:resource-dir-linux.zip"],
|
||||
)
|
||||
|
||||
lfs_files(
|
||||
name = "swift-resource-dir-macos",
|
||||
srcs = ["//swift/third_party/resource-dir:resource-dir-macos.zip"],
|
||||
)
|
||||
|
||||
register_toolchains(
|
||||
"@nodejs_toolchains//:all",
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ This open source repository contains the standard CodeQL libraries and queries t
|
||||
|
||||
## How do I learn CodeQL and run queries?
|
||||
|
||||
There is extensive documentation about the [CodeQL language](https://codeql.github.com/docs/), writing CodeQL using the [CodeQL extension for Visual Studio Code](https://docs.github.com/en/code-security/codeql-for-vs-code/) and using the [CodeQL CLI](https://docs.github.com/en/code-security/codeql-cli).
|
||||
There is [extensive documentation](https://codeql.github.com/docs/) on getting started with writing CodeQL using the [CodeQL extension for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/) and the [CodeQL CLI](https://codeql.github.com/docs/codeql-cli/).
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -6,16 +6,19 @@ provide:
|
||||
- "*/ql/consistency-queries/qlpack.yml"
|
||||
- "*/ql/automodel/src/qlpack.yml"
|
||||
- "*/ql/automodel/test/qlpack.yml"
|
||||
- "*/extractor-pack/codeql-extractor.yml"
|
||||
- "python/extractor/qlpack.yml"
|
||||
- "shared/**/qlpack.yml"
|
||||
- "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml"
|
||||
- "go/ql/config/legacy-support/qlpack.yml"
|
||||
- "go/build/codeql-extractor-go/codeql-extractor.yml"
|
||||
- "csharp/ql/campaigns/Solorigate/lib/qlpack.yml"
|
||||
- "csharp/ql/campaigns/Solorigate/src/qlpack.yml"
|
||||
- "csharp/ql/campaigns/Solorigate/test/qlpack.yml"
|
||||
- "misc/legacy-support/*/qlpack.yml"
|
||||
- "misc/suite-helpers/qlpack.yml"
|
||||
- "ruby/extractor-pack/codeql-extractor.yml"
|
||||
- "swift/extractor-pack/codeql-extractor.yml"
|
||||
- "ql/extractor-pack/codeql-extractor.yml"
|
||||
- ".github/codeql/extensions/**/codeql-pack.yml"
|
||||
|
||||
versionPolicies:
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
"/*- Yaml dbscheme -*/",
|
||||
"/*- Blame dbscheme -*/",
|
||||
"/*- JSON dbscheme -*/",
|
||||
"/*- Python dbscheme -*/",
|
||||
"/*- Empty location -*/"
|
||||
"/*- Python dbscheme -*/"
|
||||
]
|
||||
}
|
||||
@@ -364,9 +364,5 @@
|
||||
"Python model summaries test extension": [
|
||||
"python/ql/test/library-tests/dataflow/model-summaries/InlineTaintTest.ext.yml",
|
||||
"python/ql/test/library-tests/dataflow/model-summaries/NormalDataflowTest.ext.yml"
|
||||
],
|
||||
"shared tree-sitter extractor cargo.toml": [
|
||||
"shared/tree-sitter-extractor/Cargo.toml",
|
||||
"ruby/extractor/codeql-extractor-fake-crate/Cargo.toml"
|
||||
]
|
||||
}
|
||||
|
||||
13
cpp/autobuilder/.gitignore
vendored
Normal file
13
cpp/autobuilder/.gitignore
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
obj/
|
||||
TestResults/
|
||||
*.manifest
|
||||
*.pdb
|
||||
*.suo
|
||||
*.mdb
|
||||
*.vsmdi
|
||||
csharp.log
|
||||
**/bin/Debug
|
||||
**/bin/Release
|
||||
*.tlog
|
||||
.vs
|
||||
*.user
|
||||
@@ -1 +0,0 @@
|
||||
The Windows autobuilder that used to live in this directory moved to `csharp/autobuilder/Semmle.Autobuild.Cpp`.
|
||||
@@ -200,9 +200,9 @@ namespace Semmle.Autobuild.Cpp.Tests
|
||||
|
||||
internal class TestDiagnosticWriter : IDiagnosticsWriter
|
||||
{
|
||||
public IList<Semmle.Util.DiagnosticMessage> Diagnostics { get; } = new List<Semmle.Util.DiagnosticMessage>();
|
||||
public IList<DiagnosticMessage> Diagnostics { get; } = new List<DiagnosticMessage>();
|
||||
|
||||
public void AddEntry(Semmle.Util.DiagnosticMessage message) => this.Diagnostics.Add(message);
|
||||
public void AddEntry(DiagnosticMessage message) => this.Diagnostics.Add(message);
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Autobuild.Cpp\Semmle.Autobuild.Cpp.csproj" />
|
||||
<ProjectReference Include="..\..\..\csharp\autobuilder\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Semmle.Autobuild.Cpp")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("GitHub")]
|
||||
[assembly: AssemblyProduct("CodeQL autobuilder for C++")]
|
||||
[assembly: AssemblyCopyright("Copyright © GitHub 2020")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Autobuild.Cpp</AssemblyName>
|
||||
<RootNamespace>Semmle.Autobuild.Cpp</RootNamespace>
|
||||
<ApplicationIcon />
|
||||
<OutputType>Exe</OutputType>
|
||||
<StartupObject />
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="17.8.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\csharp\extractor\Semmle.Util\Semmle.Util.csproj" />
|
||||
<ProjectReference Include="..\..\..\csharp\autobuilder\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,4 +1,4 @@
|
||||
description: Revert support for repeated initializers, which are allowed in C with designated initializers.
|
||||
compatibility: full
|
||||
aggregate_field_init.rel: reorder aggregate_field_init.rel (@aggregateliteral aggregate, @expr initializer, @membervariable field, int position) aggregate initializer field
|
||||
aggregate_array_init.rel: reorder aggregate_array_init.rel (@aggregateliteral aggregate, @expr initializer, int element_index, int position) aggregate initializer element_index
|
||||
aggregate_field_init.rel: reorder aggregate_field_init.rel (int aggregate, int initializer, int field, int position) aggregate initializer field
|
||||
aggregate_array_init.rel: reorder aggregate_array_init.rel (int aggregate, int initializer, int element_index, int position) aggregate initializer element_index
|
||||
|
||||
@@ -6,7 +6,7 @@ pkg_files(
|
||||
["**"],
|
||||
exclude = ["BUILD.bazel"],
|
||||
),
|
||||
prefix = "downgrades",
|
||||
prefix = "cpp/downgrades",
|
||||
strip_prefix = strip_prefix.from_pkg(),
|
||||
visibility = ["//cpp:__pkg__"],
|
||||
)
|
||||
|
||||
@@ -5,9 +5,11 @@ package(default_visibility = ["//cpp:__pkg__"])
|
||||
pkg_files(
|
||||
name = "dbscheme",
|
||||
srcs = ["semmlecode.cpp.dbscheme"],
|
||||
prefix = "cpp",
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = "dbscheme-stats",
|
||||
srcs = ["semmlecode.cpp.dbscheme.stats"],
|
||||
prefix = "cpp",
|
||||
)
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
## 1.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
|
||||
|
||||
## 0.13.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.13.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* A partial model for the `Boost.Asio` network library has been added. This includes sources, sinks and summaries for certain functions in `Boost.Asio`, such as `read_until` and `write`.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Data models can now be added with data extensions. In this way source, sink and summary models can be added in extension `.model.yml` files, rather than by writing classes in QL code. New models should be added in the `lib/ext` folder.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.13.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,5 +0,0 @@
|
||||
## 1.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.0
|
||||
lastReleaseVersion: 0.13.0
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
extensions:
|
||||
# partial model of the Boost::Asio network library
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sourceModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
|
||||
- ["boost::asio", "", False, "read", "", "", "Argument[*1]", "remote", "manual"]
|
||||
- ["boost::asio", "", False, "read_at", "", "", "Argument[*2]", "remote", "manual"]
|
||||
- ["boost::asio", "", False, "read_until", "", "", "Argument[*1]", "remote", "manual"]
|
||||
- ["boost::asio", "", False, "async_read", "", "", "Argument[*1]", "remote", "manual"]
|
||||
- ["boost::asio", "", False, "async_read_at", "", "", "Argument[*2]", "remote", "manual"]
|
||||
- ["boost::asio", "", False, "async_read_until", "", "", "Argument[*1]", "remote", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sinkModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, kind, provenance
|
||||
- ["boost::asio", "", False, "write", "", "", "Argument[*1]", "remote-sink", "manual"]
|
||||
- ["boost::asio", "", False, "write_at", "", "", "Argument[*2]", "remote-sink", "manual"]
|
||||
- ["boost::asio", "", False, "async_write", "", "", "Argument[*1]", "remote-sink", "manual"]
|
||||
- ["boost::asio", "", False, "async_write_at", "", "", "Argument[*2]", "remote-sink", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
|
||||
- ["boost::asio", "", False, "buffer", "", "", "Argument[*0]", "ReturnValue", "taint", "manual"]
|
||||
@@ -1,15 +0,0 @@
|
||||
extensions:
|
||||
# Make sure that the extensible model predicates have at least one definition
|
||||
# to avoid errors about undefined extensionals.
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sourceModel
|
||||
data: []
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sinkModel
|
||||
data: []
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
data: []
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 1.0.1-dev
|
||||
version: 0.13.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
@@ -14,6 +14,4 @@ dependencies:
|
||||
codeql/tutorial: ${workspace}
|
||||
codeql/util: ${workspace}
|
||||
codeql/xml: ${workspace}
|
||||
dataExtensions:
|
||||
- ext/*.model.yml
|
||||
warnOnImplicitThis: true
|
||||
|
||||
@@ -410,10 +410,6 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
|
||||
or
|
||||
orphaned_variables(underlyingElement(this), unresolveElement(result))
|
||||
}
|
||||
|
||||
override predicate isStatic() {
|
||||
super.isStatic() or orphaned_variables(underlyingElement(this), _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -565,7 +565,7 @@ class IRGuardCondition extends Instruction {
|
||||
/** Holds if (determined by this guard) `op == k` evaluates to `areEqual` if this expression evaluates to `value`. */
|
||||
cached
|
||||
predicate comparesEq(Operand op, int k, boolean areEqual, AbstractValue value) {
|
||||
unary_compares_eq(this, op, k, areEqual, false, value)
|
||||
compares_eq(this, op, k, areEqual, value)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -586,7 +586,7 @@ class IRGuardCondition extends Instruction {
|
||||
cached
|
||||
predicate ensuresEq(Operand op, int k, IRBlock block, boolean areEqual) {
|
||||
exists(AbstractValue value |
|
||||
unary_compares_eq(this, op, k, areEqual, false, value) and this.valueControls(block, value)
|
||||
compares_eq(this, op, k, areEqual, value) and this.valueControls(block, value)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -611,7 +611,7 @@ class IRGuardCondition extends Instruction {
|
||||
cached
|
||||
predicate ensuresEqEdge(Operand op, int k, IRBlock pred, IRBlock succ, boolean areEqual) {
|
||||
exists(AbstractValue value |
|
||||
unary_compares_eq(this, op, k, areEqual, false, value) and
|
||||
compares_eq(this, op, k, areEqual, value) and
|
||||
this.valueControlsEdge(pred, succ, value)
|
||||
)
|
||||
}
|
||||
@@ -737,66 +737,26 @@ private predicate compares_eq(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `op == k` is `areEqual` given that `test` is equal to `value`.
|
||||
*
|
||||
* Many internal predicates in this file have a `inNonZeroCase` column.
|
||||
* Ideally, the `k` column would be a type such as `Option<int>::Option`, to
|
||||
* represent whether we have a concrete value `k` such that `op == k`, or whether
|
||||
* we only know that `op != 0`.
|
||||
* However, cannot instantiate `Option` with an infinite type. Thus the boolean
|
||||
* `inNonZeroCase` is used to distinquish the `Some` (where we have a concrete
|
||||
* value `k`) and `None` cases (where we only know that `op != 0`).
|
||||
*
|
||||
* Thus, if `inNonZeroCase = true` then `op != 0` and the value of `k` is
|
||||
* meaningless.
|
||||
*
|
||||
* To see why `inNonZeroCase` is needed consider the following C program:
|
||||
* ```c
|
||||
* char* p = ...;
|
||||
* if(p) {
|
||||
* use(p);
|
||||
* }
|
||||
* ```
|
||||
* in C++ there would be an int-to-bool conversion on `p`. However, since C
|
||||
* does not have booleans there is no conversion. We want to be able to
|
||||
* conclude that `p` is non-zero in the true branch, so we need to give `k`
|
||||
* some value. However, simply setting `k = 1` would make the rest of the
|
||||
* analysis think that `k == 1` holds inside the branch. So we distinquish
|
||||
* between the above case and
|
||||
* ```c
|
||||
* if(p == 1) {
|
||||
* use(p)
|
||||
* }
|
||||
* ```
|
||||
* by setting `inNonZeroCase` to `true` in the former case, but not in the
|
||||
* latter.
|
||||
*/
|
||||
private predicate unary_compares_eq(
|
||||
Instruction test, Operand op, int k, boolean areEqual, boolean inNonZeroCase, AbstractValue value
|
||||
/** Holds if `op == k` is `areEqual` given that `test` is equal to `value`. */
|
||||
private predicate compares_eq(
|
||||
Instruction test, Operand op, int k, boolean areEqual, AbstractValue value
|
||||
) {
|
||||
/* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */
|
||||
exists(AbstractValue v | unary_simple_comparison_eq(test, op, k, inNonZeroCase, v) |
|
||||
exists(AbstractValue v | simple_comparison_eq(test, op, k, v) |
|
||||
areEqual = true and value = v
|
||||
or
|
||||
areEqual = false and value = v.getDualValue()
|
||||
)
|
||||
or
|
||||
unary_complex_eq(test, op, k, areEqual, inNonZeroCase, value)
|
||||
complex_eq(test, op, k, areEqual, value)
|
||||
or
|
||||
/* (x is true => (op == k)) => (!x is false => (op == k)) */
|
||||
exists(AbstractValue dual, boolean inNonZeroCase0 |
|
||||
value = dual.getDualValue() and
|
||||
unary_compares_eq(test.(LogicalNotInstruction).getUnary(), op, k, inNonZeroCase0, areEqual, dual)
|
||||
|
|
||||
k = 0 and inNonZeroCase = inNonZeroCase0
|
||||
or
|
||||
k != 0 and inNonZeroCase = true
|
||||
exists(AbstractValue dual | value = dual.getDualValue() |
|
||||
compares_eq(test.(LogicalNotInstruction).getUnary(), op, k, areEqual, dual)
|
||||
)
|
||||
or
|
||||
// ((test is `areEqual` => op == const + k2) and const == `k1`) =>
|
||||
// test is `areEqual` => op == k1 + k2
|
||||
inNonZeroCase = false and
|
||||
exists(int k1, int k2, ConstantInstruction const |
|
||||
compares_eq(test, op, const.getAUse(), k2, areEqual, value) and
|
||||
int_value(const) = k1 and
|
||||
@@ -821,53 +781,35 @@ private predicate simple_comparison_eq(
|
||||
value.(BooleanValue).getValue() = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `test` is an instruction that is part of test that eventually is
|
||||
* used in a conditional branch.
|
||||
*/
|
||||
private predicate relevantUnaryComparison(Instruction test) {
|
||||
not test instanceof CompareInstruction and
|
||||
exists(IRType type, ConditionalBranchInstruction branch |
|
||||
type instanceof IRAddressType or type instanceof IRIntegerType
|
||||
|
|
||||
type = test.getResultIRType() and
|
||||
branch.getCondition() = test
|
||||
)
|
||||
or
|
||||
exists(LogicalNotInstruction logicalNot |
|
||||
relevantUnaryComparison(logicalNot) and
|
||||
test = logicalNot.getUnary()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Rearrange various simple comparisons into `op == k` form.
|
||||
*/
|
||||
private predicate unary_simple_comparison_eq(
|
||||
Instruction test, Operand op, int k, boolean inNonZeroCase, AbstractValue value
|
||||
) {
|
||||
/** Rearrange various simple comparisons into `op == k` form. */
|
||||
private predicate simple_comparison_eq(Instruction test, Operand op, int k, AbstractValue value) {
|
||||
exists(SwitchInstruction switch, CaseEdge case |
|
||||
test = switch.getExpression() and
|
||||
op.getDef() = test and
|
||||
case = value.(MatchValue).getCase() and
|
||||
exists(switch.getSuccessor(case)) and
|
||||
case.getValue().toInt() = k and
|
||||
inNonZeroCase = false
|
||||
case.getValue().toInt() = k
|
||||
)
|
||||
or
|
||||
// There's no implicit CompareInstruction in files compiled as C since C
|
||||
// doesn't have implicit boolean conversions. So instead we check whether
|
||||
// there's a branch on a value of pointer or integer type.
|
||||
relevantUnaryComparison(test) and
|
||||
op.getDef() = test and
|
||||
(
|
||||
k = 1 and
|
||||
value.(BooleanValue).getValue() = true and
|
||||
inNonZeroCase = true
|
||||
or
|
||||
exists(ConditionalBranchInstruction branch, IRType type |
|
||||
not test instanceof CompareInstruction and
|
||||
type = test.getResultIRType() and
|
||||
(type instanceof IRAddressType or type instanceof IRIntegerType) and
|
||||
test = branch.getCondition() and
|
||||
op.getDef() = test
|
||||
|
|
||||
// We'd like to also include a case such as:
|
||||
// ```
|
||||
// k = 1 and
|
||||
// value.(BooleanValue).getValue() = true
|
||||
// ```
|
||||
// but all we know is that the value is non-zero in the true branch.
|
||||
// So we can only conclude something in the false branch.
|
||||
k = 0 and
|
||||
value.(BooleanValue).getValue() = false and
|
||||
inNonZeroCase = false
|
||||
value.(BooleanValue).getValue() = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -879,12 +821,12 @@ private predicate complex_eq(
|
||||
add_eq(cmp, left, right, k, areEqual, value)
|
||||
}
|
||||
|
||||
private predicate unary_complex_eq(
|
||||
Instruction test, Operand op, int k, boolean areEqual, boolean inNonZeroCase, AbstractValue value
|
||||
private predicate complex_eq(
|
||||
Instruction test, Operand op, int k, boolean areEqual, AbstractValue value
|
||||
) {
|
||||
unary_sub_eq(test, op, k, areEqual, inNonZeroCase, value)
|
||||
sub_eq(test, op, k, areEqual, value)
|
||||
or
|
||||
unary_add_eq(test, op, k, areEqual, inNonZeroCase, value)
|
||||
add_eq(test, op, k, areEqual, value)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1148,20 +1090,16 @@ private predicate sub_eq(
|
||||
}
|
||||
|
||||
// op - x == c => op == (c+x)
|
||||
private predicate unary_sub_eq(
|
||||
Instruction test, Operand op, int k, boolean areEqual, boolean inNonZeroCase, AbstractValue value
|
||||
) {
|
||||
inNonZeroCase = false and
|
||||
private predicate sub_eq(Instruction test, Operand op, int k, boolean areEqual, AbstractValue value) {
|
||||
exists(SubInstruction sub, int c, int x |
|
||||
unary_compares_eq(test, sub.getAUse(), c, areEqual, inNonZeroCase, value) and
|
||||
compares_eq(test, sub.getAUse(), c, areEqual, value) and
|
||||
op = sub.getLeftOperand() and
|
||||
x = int_value(sub.getRight()) and
|
||||
k = c + x
|
||||
)
|
||||
or
|
||||
inNonZeroCase = false and
|
||||
exists(PointerSubInstruction sub, int c, int x |
|
||||
unary_compares_eq(test, sub.getAUse(), c, areEqual, inNonZeroCase, value) and
|
||||
compares_eq(test, sub.getAUse(), c, areEqual, value) and
|
||||
op = sub.getLeftOperand() and
|
||||
x = int_value(sub.getRight()) and
|
||||
k = c + x
|
||||
@@ -1215,13 +1153,11 @@ private predicate add_eq(
|
||||
}
|
||||
|
||||
// left + x == right + c => left == right + (c-x)
|
||||
private predicate unary_add_eq(
|
||||
Instruction test, Operand left, int k, boolean areEqual, boolean inNonZeroCase,
|
||||
AbstractValue value
|
||||
private predicate add_eq(
|
||||
Instruction test, Operand left, int k, boolean areEqual, AbstractValue value
|
||||
) {
|
||||
inNonZeroCase = false and
|
||||
exists(AddInstruction lhs, int c, int x |
|
||||
unary_compares_eq(test, lhs.getAUse(), c, areEqual, inNonZeroCase, value) and
|
||||
compares_eq(test, lhs.getAUse(), c, areEqual, value) and
|
||||
(
|
||||
left = lhs.getLeftOperand() and x = int_value(lhs.getRight())
|
||||
or
|
||||
@@ -1230,9 +1166,8 @@ private predicate unary_add_eq(
|
||||
k = c - x
|
||||
)
|
||||
or
|
||||
inNonZeroCase = false and
|
||||
exists(PointerAddInstruction lhs, int c, int x |
|
||||
unary_compares_eq(test, lhs.getAUse(), c, areEqual, inNonZeroCase, value) and
|
||||
compares_eq(test, lhs.getAUse(), c, areEqual, value) and
|
||||
(
|
||||
left = lhs.getLeftOperand() and x = int_value(lhs.getRight())
|
||||
or
|
||||
|
||||
@@ -78,7 +78,6 @@ private import internal.FlowSummaryImpl
|
||||
private import internal.FlowSummaryImpl::Public
|
||||
private import internal.FlowSummaryImpl::Private
|
||||
private import internal.FlowSummaryImpl::Private::External
|
||||
private import internal.ExternalFlowExtensions as Extensions
|
||||
private import codeql.mad.ModelValidation as SharedModelVal
|
||||
private import codeql.util.Unit
|
||||
|
||||
@@ -139,9 +138,6 @@ predicate sourceModel(
|
||||
row.splitAt(";", 7) = kind
|
||||
) and
|
||||
provenance = "manual"
|
||||
or
|
||||
Extensions::sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance,
|
||||
_)
|
||||
}
|
||||
|
||||
/** Holds if a sink model exists for the given parameters. */
|
||||
@@ -162,8 +158,6 @@ predicate sinkModel(
|
||||
row.splitAt(";", 7) = kind
|
||||
) and
|
||||
provenance = "manual"
|
||||
or
|
||||
Extensions::sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance, _)
|
||||
}
|
||||
|
||||
/** Holds if a summary model exists for the given parameters. */
|
||||
@@ -185,9 +179,6 @@ predicate summaryModel(
|
||||
row.splitAt(";", 8) = kind
|
||||
) and
|
||||
provenance = "manual"
|
||||
or
|
||||
Extensions::summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind,
|
||||
provenance, _)
|
||||
}
|
||||
|
||||
private predicate relevantNamespace(string namespace) {
|
||||
@@ -212,10 +203,8 @@ private predicate canonicalNamespaceLink(string namespace, string subns) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if MaD framework coverage of `namespace` is `n` api endpoints of the
|
||||
* kind `(kind, part)`, and `namespaces` is the number of subnamespaces of
|
||||
* `namespace` which have MaD framework coverage (including `namespace`
|
||||
* itself).
|
||||
* Holds if CSV framework coverage of `namespace` is `n` api endpoints of the
|
||||
* kind `(kind, part)`.
|
||||
*/
|
||||
predicate modelCoverage(string namespace, int namespaces, string kind, string part, int n) {
|
||||
namespaces = strictcount(string subns | canonicalNamespaceLink(namespace, subns)) and
|
||||
@@ -332,10 +321,10 @@ module CsvValidation {
|
||||
or
|
||||
summaryModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "summary"
|
||||
|
|
||||
not namespace.regexpMatch("[a-zA-Z0-9_\\.:]*") and
|
||||
not namespace.regexpMatch("[a-zA-Z0-9_\\.]+") and
|
||||
result = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
|
||||
or
|
||||
not type.regexpMatch("[a-zA-Z0-9_<>,\\+]*") and
|
||||
not type.regexpMatch("[a-zA-Z0-9_<>,\\+]+") and
|
||||
result = "Dubious type \"" + type + "\" in " + pred + " model."
|
||||
or
|
||||
not name.regexpMatch("[a-zA-Z0-9_<>,]*") and
|
||||
|
||||
@@ -9,7 +9,7 @@ private import DataFlowUtil
|
||||
/**
|
||||
* Gets a function that might be called by `call`.
|
||||
*/
|
||||
DataFlowCallable viableCallable(DataFlowCall call) {
|
||||
Function viableCallable(DataFlowCall call) {
|
||||
result = call.(Call).getTarget()
|
||||
or
|
||||
// If the target of the call does not have a body in the snapshot, it might
|
||||
|
||||
@@ -242,17 +242,7 @@ class CastNode extends Node {
|
||||
CastNode() { none() } // stub implementation
|
||||
}
|
||||
|
||||
class DataFlowCallable extends Function {
|
||||
/** Gets a best-effort total ordering. */
|
||||
int totalorder() {
|
||||
this =
|
||||
rank[result](DataFlowCallable c, string file, int startline, int startcolumn |
|
||||
c.getLocation().hasLocationInfo(file, startline, startcolumn, _, _)
|
||||
|
|
||||
c order by file, startline, startcolumn
|
||||
)
|
||||
}
|
||||
}
|
||||
class DataFlowCallable = Function;
|
||||
|
||||
class DataFlowExpr = Expr;
|
||||
|
||||
@@ -271,28 +261,10 @@ class DataFlowCall extends Expr instanceof Call {
|
||||
ExprNode getNode() { result.getExpr() = this }
|
||||
|
||||
/** Gets the enclosing callable of this call. */
|
||||
DataFlowCallable getEnclosingCallable() { result = this.getEnclosingFunction() }
|
||||
|
||||
/** Gets a best-effort total ordering. */
|
||||
int totalorder() {
|
||||
this =
|
||||
rank[result](DataFlowCall c, int startline, int startcolumn |
|
||||
c.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
||||
|
|
||||
c order by startline, startcolumn
|
||||
)
|
||||
}
|
||||
Function getEnclosingCallable() { result = this.getEnclosingFunction() }
|
||||
}
|
||||
|
||||
class NodeRegion instanceof Unit {
|
||||
string toString() { result = "NodeRegion" }
|
||||
|
||||
predicate contains(Node n) { none() }
|
||||
|
||||
int totalOrder() { result = 1 }
|
||||
}
|
||||
|
||||
predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call) { none() } // stub implementation
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation
|
||||
|
||||
/**
|
||||
* Holds if access paths with `c` at their head always should be tracked at high
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* This module provides extensible predicates for defining MaD models.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Holds if an external source model exists for the given parameters.
|
||||
*/
|
||||
extensible predicate sourceModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string output, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if an external sink model exists for the given parameters.
|
||||
*/
|
||||
extensible predicate sinkModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if an external summary model exists for the given parameters.
|
||||
*/
|
||||
extensible predicate summaryModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string output, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||
);
|
||||
@@ -1062,16 +1062,6 @@ class DataFlowCallable extends TDataFlowCallable {
|
||||
result = this.asSummarizedCallable() or // SummarizedCallable = Function (in CPP)
|
||||
result = this.asSourceCallable()
|
||||
}
|
||||
|
||||
/** Gets a best-effort total ordering. */
|
||||
int totalorder() {
|
||||
this =
|
||||
rank[result](DataFlowCallable c, string file, int startline, int startcolumn |
|
||||
c.getLocation().hasLocationInfo(file, startline, startcolumn, _, _)
|
||||
|
|
||||
c order by file, startline, startcolumn
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1169,16 +1159,6 @@ class DataFlowCall extends TDataFlowCall {
|
||||
* Gets the location of this call.
|
||||
*/
|
||||
Location getLocation() { none() }
|
||||
|
||||
/** Gets a best-effort total ordering. */
|
||||
int totalorder() {
|
||||
this =
|
||||
rank[result](DataFlowCall c, int startline, int startcolumn |
|
||||
c.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
||||
|
|
||||
c order by startline, startcolumn
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1267,53 +1247,43 @@ module IsUnreachableInCall {
|
||||
any(G::IRGuardCondition guard).ensuresLt(left, right, k, block, areEqual)
|
||||
}
|
||||
|
||||
class NodeRegion instanceof IRBlock {
|
||||
string toString() { result = "NodeRegion" }
|
||||
|
||||
predicate contains(Node n) { this = n.getBasicBlock() }
|
||||
|
||||
int totalOrder() {
|
||||
this =
|
||||
rank[result](IRBlock b, int startline, int startcolumn |
|
||||
b.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
||||
|
|
||||
b order by startline, startcolumn
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate isUnreachableInCall(NodeRegion block, DataFlowCall call) {
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) {
|
||||
exists(
|
||||
InstructionDirectParameterNode paramNode, ConstantIntegralTypeArgumentNode arg,
|
||||
IntegerConstantInstruction constant, int k, Operand left, Operand right, int argval
|
||||
IntegerConstantInstruction constant, int k, Operand left, Operand right, IRBlock block
|
||||
|
|
||||
// arg flows into `paramNode`
|
||||
DataFlowImplCommon::viableParamArg(call, pragma[only_bind_into](paramNode),
|
||||
pragma[only_bind_into](arg)) and
|
||||
DataFlowImplCommon::viableParamArg(call, paramNode, arg) and
|
||||
left = constant.getAUse() and
|
||||
right = valueNumber(paramNode.getInstruction()).getAUse() and
|
||||
argval = arg.getValue()
|
||||
block = n.getBasicBlock()
|
||||
|
|
||||
// and there's a guard condition which ensures that the result of `left == right + k` is `areEqual`
|
||||
exists(boolean areEqual | ensuresEq(left, right, k, block, areEqual) |
|
||||
exists(boolean areEqual |
|
||||
ensuresEq(pragma[only_bind_into](left), pragma[only_bind_into](right),
|
||||
pragma[only_bind_into](k), pragma[only_bind_into](block), areEqual)
|
||||
|
|
||||
// this block ensures that left = right + k, but it holds that `left != right + k`
|
||||
areEqual = true and
|
||||
constant.getValue().toInt() != argval + k
|
||||
constant.getValue().toInt() != arg.getValue() + k
|
||||
or
|
||||
// this block ensures that or `left != right + k`, but it holds that `left = right + k`
|
||||
areEqual = false and
|
||||
constant.getValue().toInt() = argval + k
|
||||
constant.getValue().toInt() = arg.getValue() + k
|
||||
)
|
||||
or
|
||||
// or there's a guard condition which ensures that the result of `left < right + k` is `isLessThan`
|
||||
exists(boolean isLessThan | ensuresLt(left, right, k, block, isLessThan) |
|
||||
exists(boolean isLessThan |
|
||||
ensuresLt(pragma[only_bind_into](left), pragma[only_bind_into](right),
|
||||
pragma[only_bind_into](k), pragma[only_bind_into](block), isLessThan)
|
||||
|
|
||||
isLessThan = true and
|
||||
// this block ensures that `left < right + k`, but it holds that `left >= right + k`
|
||||
constant.getValue().toInt() >= argval + k
|
||||
constant.getValue().toInt() >= arg.getValue() + k
|
||||
or
|
||||
// this block ensures that `left >= right + k`, but it holds that `left < right + k`
|
||||
isLessThan = false and
|
||||
constant.getValue().toInt() < argval + k
|
||||
constant.getValue().toInt() < arg.getValue() + k
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1336,8 +1306,6 @@ predicate nodeIsHidden(Node n) {
|
||||
n instanceof FinalGlobalValue
|
||||
or
|
||||
n instanceof InitialGlobalValue
|
||||
or
|
||||
n instanceof SsaPhiInputNode
|
||||
}
|
||||
|
||||
predicate neverSkipInPathGraph(Node n) {
|
||||
@@ -1636,8 +1604,6 @@ private Instruction getAnInstruction(Node n) {
|
||||
or
|
||||
result = n.(SsaPhiNode).getPhiNode().getBasicBlock().getFirstInstruction()
|
||||
or
|
||||
result = n.(SsaPhiInputNode).getBasicBlock().getFirstInstruction()
|
||||
or
|
||||
n.(IndirectInstruction).hasInstructionAndIndirectionIndex(result, _)
|
||||
or
|
||||
not n instanceof IndirectInstruction and
|
||||
@@ -1767,7 +1733,7 @@ module IteratorFlow {
|
||||
crementCall = def.getValue().asInstruction().(StoreInstruction).getSourceValue() and
|
||||
sv = def.getSourceVariable() and
|
||||
bb.getInstruction(i) = crementCall and
|
||||
Ssa::ssaDefReachesReadExt(sv, result.asDef(), bb, i)
|
||||
Ssa::ssaDefReachesRead(sv, result.asDef(), bb, i)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1801,7 +1767,7 @@ module IteratorFlow {
|
||||
isIteratorWrite(writeToDeref, address) and
|
||||
operandForFullyConvertedCall(address, starCall) and
|
||||
bbStar.getInstruction(iStar) = starCall and
|
||||
Ssa::ssaDefReachesReadExt(_, def.asDef(), bbStar, iStar) and
|
||||
Ssa::ssaDefReachesRead(_, def.asDef(), bbStar, iStar) and
|
||||
ultimate = getAnUltimateDefinition*(def) and
|
||||
beginStore = ultimate.getValue().asInstruction() and
|
||||
operandForFullyConvertedCall(beginStore.getSourceValueOperand(), beginCall)
|
||||
|
||||
@@ -45,7 +45,6 @@ private newtype TIRDataFlowNode =
|
||||
or
|
||||
Ssa::isModifiableByCall(operand, indirectionIndex)
|
||||
} or
|
||||
TSsaPhiInputNode(Ssa::PhiNode phi, IRBlock input) { phi.hasInputFromBlock(_, _, _, _, input) } or
|
||||
TSsaPhiNode(Ssa::PhiNode phi) or
|
||||
TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
|
||||
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
|
||||
@@ -115,13 +114,6 @@ predicate conversionFlow(
|
||||
instrTo.(CheckedConvertOrNullInstruction).getUnaryOperand() = opFrom
|
||||
or
|
||||
instrTo.(InheritanceConversionInstruction).getUnaryOperand() = opFrom
|
||||
or
|
||||
exists(BuiltInInstruction builtIn |
|
||||
builtIn = instrTo and
|
||||
// __builtin_bit_cast
|
||||
builtIn.getBuiltInOperation() instanceof BuiltInBitCast and
|
||||
opFrom = builtIn.getAnOperand()
|
||||
)
|
||||
)
|
||||
or
|
||||
additional = true and
|
||||
@@ -166,12 +158,6 @@ class Node extends TIRDataFlowNode {
|
||||
/** Gets the operands corresponding to this node, if any. */
|
||||
Operand asOperand() { result = this.(OperandNode).getOperand() }
|
||||
|
||||
/**
|
||||
* Gets the operand that is indirectly tracked by this node behind `index`
|
||||
* number of indirections.
|
||||
*/
|
||||
Operand asIndirectOperand(int index) { hasOperandAndIndex(this, result, index) }
|
||||
|
||||
/**
|
||||
* Holds if this node is at index `i` in basic block `block`.
|
||||
*
|
||||
@@ -184,9 +170,6 @@ class Node extends TIRDataFlowNode {
|
||||
or
|
||||
this.(SsaPhiNode).getPhiNode().getBasicBlock() = block and i = -1
|
||||
or
|
||||
this.(SsaPhiInputNode).getBlock() = block and
|
||||
i = block.getInstructionCount()
|
||||
or
|
||||
this.(RawIndirectOperand).getOperand().getUse() = block.getInstruction(i)
|
||||
or
|
||||
this.(RawIndirectInstruction).getInstruction() = block.getInstruction(i)
|
||||
@@ -639,7 +622,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
||||
|
||||
final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() }
|
||||
|
||||
override string toStringImpl() { result = phi.toString() }
|
||||
override string toStringImpl() { result = "Phi" }
|
||||
|
||||
/**
|
||||
* Gets a node that is used as input to this phi node.
|
||||
@@ -648,7 +631,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
||||
*/
|
||||
cached
|
||||
final Node getAnInput(boolean fromBackEdge) {
|
||||
result.(SsaPhiInputNode).getPhiNode() = phi and
|
||||
localFlowStep(result, this) and
|
||||
exists(IRBlock bPhi, IRBlock bResult |
|
||||
bPhi = phi.getBasicBlock() and bResult = result.getBasicBlock()
|
||||
|
|
||||
@@ -671,58 +654,6 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
||||
predicate isPhiRead() { phi.isPhiRead() }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* A node that is used as an input to a phi node.
|
||||
*
|
||||
* This class exists to allow more powerful barrier guards. Consider this
|
||||
* example:
|
||||
*
|
||||
* ```cpp
|
||||
* int x = source();
|
||||
* if(!safe(x)) {
|
||||
* x = clear();
|
||||
* }
|
||||
* // phi node for x here
|
||||
* sink(x);
|
||||
* ```
|
||||
*
|
||||
* At the phi node for `x` it is neither the case that `x` is dominated by
|
||||
* `safe(x)`, or is the case that the phi is dominated by a clearing of `x`.
|
||||
*
|
||||
* By inserting a "phi input" node as the last entry in the basic block that
|
||||
* defines the inputs to the phi we can conclude that each of those inputs are
|
||||
* safe to pass to `sink`.
|
||||
*/
|
||||
class SsaPhiInputNode extends Node, TSsaPhiInputNode {
|
||||
Ssa::PhiNode phi;
|
||||
IRBlock block;
|
||||
|
||||
SsaPhiInputNode() { this = TSsaPhiInputNode(phi, block) }
|
||||
|
||||
/** Gets the phi node associated with this node. */
|
||||
Ssa::PhiNode getPhiNode() { result = phi }
|
||||
|
||||
/** Gets the basic block in which this input originates. */
|
||||
IRBlock getBlock() { result = block }
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
|
||||
|
||||
override DataFlowType getType() { result = this.getSourceVariable().getType() }
|
||||
|
||||
override predicate isGLValue() { phi.getSourceVariable().isGLValue() }
|
||||
|
||||
final override Location getLocationImpl() { result = block.getLastInstruction().getLocation() }
|
||||
|
||||
override string toStringImpl() { result = "Phi input" }
|
||||
|
||||
/** Gets the source variable underlying this phi node. */
|
||||
Ssa::SourceVariable getSourceVariable() { result = phi.getSourceVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: do not use.
|
||||
*
|
||||
@@ -2245,9 +2176,6 @@ private module Cached {
|
||||
// Def-use/Use-use flow
|
||||
Ssa::ssaFlow(nodeFrom, nodeTo)
|
||||
or
|
||||
// Phi input -> Phi
|
||||
nodeFrom.(SsaPhiInputNode).getPhiNode() = nodeTo.(SsaPhiNode).getPhiNode()
|
||||
or
|
||||
IteratorFlow::localFlowStep(nodeFrom, nodeTo)
|
||||
or
|
||||
// Operand -> Instruction flow
|
||||
@@ -2686,22 +2614,6 @@ class ContentSet instanceof Content {
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate guardControlsPhiInput(
|
||||
IRGuardCondition g, boolean branch, Ssa::Definition def, IRBlock input, Ssa::PhiNode phi
|
||||
) {
|
||||
phi.hasInputFromBlock(def, _, _, _, input) and
|
||||
(
|
||||
g.controls(input, branch)
|
||||
or
|
||||
exists(EdgeKind kind |
|
||||
g.getBlock() = input and
|
||||
kind = getConditionalEdge(branch) and
|
||||
input.getSuccessor(kind) = phi.getBasicBlock()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
|
||||
*
|
||||
@@ -2750,21 +2662,13 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
*
|
||||
* NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead.
|
||||
*/
|
||||
Node getABarrierNode() {
|
||||
ExprNode getABarrierNode() {
|
||||
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
|
||||
e = value.getAnInstruction().getConvertedResultExpression() and
|
||||
result.asConvertedExpr() = e and
|
||||
result.getConvertedExpr() = e and
|
||||
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
|
||||
g.controls(result.getBasicBlock(), edge)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
|
||||
|
|
||||
guardChecks(g, def.getARead().asOperand().getDef().getConvertedResultExpression(), branch) and
|
||||
guardControlsPhiInput(g, branch, def, input, phi) and
|
||||
result = TSsaPhiInputNode(phi, input)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2800,7 +2704,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
*
|
||||
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
|
||||
*/
|
||||
Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
|
||||
IndirectExprNode getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
|
||||
|
||||
/**
|
||||
* Gets an indirect expression node with indirection index `indirectionIndex` that is
|
||||
@@ -2836,23 +2740,13 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
*
|
||||
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
|
||||
*/
|
||||
Node getAnIndirectBarrierNode(int indirectionIndex) {
|
||||
IndirectExprNode getAnIndirectBarrierNode(int indirectionIndex) {
|
||||
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
|
||||
e = value.getAnInstruction().getConvertedResultExpression() and
|
||||
result.asIndirectConvertedExpr(indirectionIndex) = e and
|
||||
result.getConvertedExpr(indirectionIndex) = e and
|
||||
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
|
||||
g.controls(result.getBasicBlock(), edge)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
|
||||
|
|
||||
guardChecks(g,
|
||||
def.getARead().asIndirectOperand(indirectionIndex).getDef().getConvertedResultExpression(),
|
||||
branch) and
|
||||
guardControlsPhiInput(g, branch, def, input, phi) and
|
||||
result = TSsaPhiInputNode(phi, input)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2861,14 +2755,6 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
*/
|
||||
signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction instr, boolean branch);
|
||||
|
||||
private EdgeKind getConditionalEdge(boolean branch) {
|
||||
branch = true and
|
||||
result instanceof TrueEdge
|
||||
or
|
||||
branch = false and
|
||||
result instanceof FalseEdge
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a set of barrier nodes for a guard that validates an instruction.
|
||||
*
|
||||
@@ -2877,20 +2763,12 @@ private EdgeKind getConditionalEdge(boolean branch) {
|
||||
*/
|
||||
module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> {
|
||||
/** Gets a node that is safely guarded by the given guard check. */
|
||||
Node getABarrierNode() {
|
||||
ExprNode getABarrierNode() {
|
||||
exists(IRGuardCondition g, ValueNumber value, boolean edge, Operand use |
|
||||
instructionGuardChecks(g, value.getAnInstruction(), edge) and
|
||||
use = value.getAnInstruction().getAUse() and
|
||||
result.asOperand() = use and
|
||||
g.controls(result.getBasicBlock(), edge)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
|
||||
|
|
||||
instructionGuardChecks(g, def.getARead().asOperand().getDef(), branch) and
|
||||
guardControlsPhiInput(g, branch, def, input, phi) and
|
||||
result = TSsaPhiInputNode(phi, input)
|
||||
g.controls(use.getDef().getBlock(), edge)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,7 +546,7 @@ module ProductFlow {
|
||||
Flow1::PathGraph::edges(pred1, succ1, _, _) and
|
||||
exists(ReturnKindExt returnKind |
|
||||
succ1.getNode() = returnKind.getAnOutNode(call) and
|
||||
paramReturnNode(_, pred1.asParameterReturnNode(), _, returnKind)
|
||||
pred1.getNode().(ReturnNodeExt).getKind() = returnKind
|
||||
)
|
||||
}
|
||||
|
||||
@@ -574,7 +574,7 @@ module ProductFlow {
|
||||
Flow2::PathGraph::edges(pred2, succ2, _, _) and
|
||||
exists(ReturnKindExt returnKind |
|
||||
succ2.getNode() = returnKind.getAnOutNode(call) and
|
||||
paramReturnNode(_, pred2.asParameterReturnNode(), _, returnKind)
|
||||
pred2.getNode().(ReturnNodeExt).getKind() = returnKind
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -105,8 +105,8 @@ predicate hasRawIndirectInstruction(Instruction instr, int indirectionIndex) {
|
||||
cached
|
||||
private newtype TDefImpl =
|
||||
TDefAddressImpl(BaseIRVariable v) or
|
||||
TDirectDefImpl(Operand address, int indirectionIndex) {
|
||||
isDef(_, _, address, _, _, indirectionIndex)
|
||||
TDirectDefImpl(BaseSourceVariableInstruction base, Operand address, int indirectionIndex) {
|
||||
isDef(_, _, address, base, _, indirectionIndex)
|
||||
} or
|
||||
TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
||||
// Represents the initial "definition" of a global variable when entering
|
||||
@@ -116,8 +116,8 @@ private newtype TDefImpl =
|
||||
|
||||
cached
|
||||
private newtype TUseImpl =
|
||||
TDirectUseImpl(Operand operand, int indirectionIndex) {
|
||||
isUse(_, operand, _, _, indirectionIndex) and
|
||||
TDirectUseImpl(BaseSourceVariableInstruction base, Operand operand, int indirectionIndex) {
|
||||
isUse(_, operand, base, _, indirectionIndex) and
|
||||
not isDef(true, _, operand, _, _, _)
|
||||
} or
|
||||
TGlobalUse(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
||||
@@ -211,11 +211,19 @@ abstract class DefImpl extends TDefImpl {
|
||||
*/
|
||||
abstract int getIndirection();
|
||||
|
||||
/**
|
||||
* Gets the instruction that computes the base of this definition or use.
|
||||
* This is always a `VariableAddressInstruction` or an `CallInstruction`.
|
||||
*/
|
||||
abstract BaseSourceVariableInstruction getBase();
|
||||
|
||||
/**
|
||||
* Gets the base source variable (i.e., the variable without
|
||||
* any indirection) of this definition or use.
|
||||
*/
|
||||
abstract BaseSourceVariable getBaseSourceVariable();
|
||||
final BaseSourceVariable getBaseSourceVariable() {
|
||||
this.getBase().getBaseSourceVariable() = result
|
||||
}
|
||||
|
||||
/** Gets the variable that is defined or used. */
|
||||
SourceVariable getSourceVariable() {
|
||||
@@ -275,11 +283,19 @@ abstract class UseImpl extends TUseImpl {
|
||||
/** Gets the indirection index of this use. */
|
||||
final int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
/**
|
||||
* Gets the instruction that computes the base of this definition or use.
|
||||
* This is always a `VariableAddressInstruction` or an `CallInstruction`.
|
||||
*/
|
||||
abstract BaseSourceVariableInstruction getBase();
|
||||
|
||||
/**
|
||||
* Gets the base source variable (i.e., the variable without
|
||||
* any indirection) of this definition or use.
|
||||
*/
|
||||
abstract BaseSourceVariable getBaseSourceVariable();
|
||||
final BaseSourceVariable getBaseSourceVariable() {
|
||||
this.getBase().getBaseSourceVariable() = result
|
||||
}
|
||||
|
||||
/** Gets the variable that is defined or used. */
|
||||
SourceVariable getSourceVariable() {
|
||||
@@ -361,13 +377,14 @@ private class DefAddressImpl extends DefImpl, TDefAddressImpl {
|
||||
result.getIndirection() = 0
|
||||
}
|
||||
|
||||
final override BaseSourceVariable getBaseSourceVariable() { result = v }
|
||||
final override BaseSourceVariableInstruction getBase() { none() }
|
||||
}
|
||||
|
||||
private class DirectDef extends DefImpl, TDirectDefImpl {
|
||||
Operand address;
|
||||
BaseSourceVariableInstruction base;
|
||||
|
||||
DirectDef() { this = TDirectDefImpl(address, indirectionIndex) }
|
||||
DirectDef() { this = TDirectDefImpl(base, address, indirectionIndex) }
|
||||
|
||||
override Cpp::Location getLocation() { result = this.getAddressOperand().getUse().getLocation() }
|
||||
|
||||
@@ -379,36 +396,30 @@ private class DirectDef extends DefImpl, TDirectDefImpl {
|
||||
|
||||
override Operand getAddressOperand() { result = address }
|
||||
|
||||
private BaseSourceVariableInstruction getBase() {
|
||||
isDef(_, _, address, result, _, indirectionIndex)
|
||||
}
|
||||
override BaseSourceVariableInstruction getBase() { result = base }
|
||||
|
||||
override BaseSourceVariable getBaseSourceVariable() {
|
||||
result = this.getBase().getBaseSourceVariable()
|
||||
}
|
||||
override int getIndirection() { isDef(_, _, address, base, result, indirectionIndex) }
|
||||
|
||||
override int getIndirection() { isDef(_, _, address, _, result, indirectionIndex) }
|
||||
override Node0Impl getValue() { isDef(_, result, address, base, _, _) }
|
||||
|
||||
override Node0Impl getValue() { isDef(_, result, address, _, _, _) }
|
||||
|
||||
override predicate isCertain() { isDef(true, _, address, _, _, indirectionIndex) }
|
||||
override predicate isCertain() { isDef(true, _, address, base, _, indirectionIndex) }
|
||||
}
|
||||
|
||||
private class DirectUseImpl extends UseImpl, TDirectUseImpl {
|
||||
Operand operand;
|
||||
BaseSourceVariableInstruction base;
|
||||
|
||||
DirectUseImpl() { this = TDirectUseImpl(operand, indirectionIndex) }
|
||||
DirectUseImpl() { this = TDirectUseImpl(base, operand, indirectionIndex) }
|
||||
|
||||
override string toString() { result = "Use of " + this.getSourceVariable() }
|
||||
|
||||
final override predicate hasIndexInBlock(IRBlock block, int index) {
|
||||
// See the comment in `ssa0`'s `OperandBasedUse` for an explanation of this
|
||||
// predicate's implementation.
|
||||
if this.getBase().getAst() = any(Cpp::PostfixCrementOperation c).getOperand()
|
||||
if base.getAst() = any(Cpp::PostfixCrementOperation c).getOperand()
|
||||
then
|
||||
exists(Operand op, int indirection, Instruction base |
|
||||
exists(Operand op, int indirection |
|
||||
indirection = this.getIndirection() and
|
||||
base = this.getBase() and
|
||||
op =
|
||||
min(Operand cand, int i |
|
||||
isUse(_, cand, base, indirection, indirectionIndex) and
|
||||
@@ -421,19 +432,15 @@ private class DirectUseImpl extends UseImpl, TDirectUseImpl {
|
||||
else operand.getUse() = block.getInstruction(index)
|
||||
}
|
||||
|
||||
private BaseSourceVariableInstruction getBase() { isUse(_, operand, result, _, indirectionIndex) }
|
||||
|
||||
override BaseSourceVariable getBaseSourceVariable() {
|
||||
result = this.getBase().getBaseSourceVariable()
|
||||
}
|
||||
final override BaseSourceVariableInstruction getBase() { result = base }
|
||||
|
||||
final Operand getOperand() { result = operand }
|
||||
|
||||
final override Cpp::Location getLocation() { result = operand.getLocation() }
|
||||
|
||||
override int getIndirection() { isUse(_, operand, _, result, indirectionIndex) }
|
||||
override int getIndirection() { isUse(_, operand, base, result, indirectionIndex) }
|
||||
|
||||
override predicate isCertain() { isUse(true, operand, _, _, indirectionIndex) }
|
||||
override predicate isCertain() { isUse(true, operand, base, _, indirectionIndex) }
|
||||
|
||||
override Node getNode() { nodeHasOperand(result, operand, indirectionIndex) }
|
||||
}
|
||||
@@ -492,7 +499,13 @@ class FinalParameterUse extends UseImpl, TFinalParameterUse {
|
||||
result instanceof UnknownDefaultLocation
|
||||
}
|
||||
|
||||
override BaseIRVariable getBaseSourceVariable() { result.getIRVariable().getAst() = p }
|
||||
override BaseSourceVariableInstruction getBase() {
|
||||
exists(InitializeParameterInstruction init |
|
||||
init.getParameter() = p and
|
||||
// This is always a `VariableAddressInstruction`
|
||||
result = init.getAnOperand().getDef()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -578,8 +591,8 @@ class GlobalUse extends UseImpl, TGlobalUse {
|
||||
)
|
||||
}
|
||||
|
||||
override BaseSourceVariable getBaseSourceVariable() {
|
||||
baseSourceVariableIsGlobal(result, global, f)
|
||||
override SourceVariable getSourceVariable() {
|
||||
sourceVariableIsGlobal(result, global, f, this.getIndirection())
|
||||
}
|
||||
|
||||
final override Cpp::Location getLocation() { result = f.getLocation() }
|
||||
@@ -596,6 +609,8 @@ class GlobalUse extends UseImpl, TGlobalUse {
|
||||
Type getUnderlyingType() { result = global.getUnderlyingType() }
|
||||
|
||||
override predicate isCertain() { any() }
|
||||
|
||||
override BaseSourceVariableInstruction getBase() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -625,8 +640,8 @@ class GlobalDefImpl extends DefImpl, TGlobalDefImpl {
|
||||
}
|
||||
|
||||
/** Gets the global variable associated with this definition. */
|
||||
override BaseSourceVariable getBaseSourceVariable() {
|
||||
baseSourceVariableIsGlobal(result, global, f)
|
||||
override SourceVariable getSourceVariable() {
|
||||
sourceVariableIsGlobal(result, global, f, this.getIndirection())
|
||||
}
|
||||
|
||||
override int getIndirection() { result = indirectionIndex }
|
||||
@@ -649,6 +664,8 @@ class GlobalDefImpl extends DefImpl, TGlobalDefImpl {
|
||||
override string toString() { result = "Def of " + this.getSourceVariable() }
|
||||
|
||||
override Location getLocation() { result = f.getLocation() }
|
||||
|
||||
override BaseSourceVariableInstruction getBase() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -657,9 +674,19 @@ class GlobalDefImpl extends DefImpl, TGlobalDefImpl {
|
||||
*/
|
||||
predicate adjacentDefRead(IRBlock bb1, int i1, SourceVariable sv, IRBlock bb2, int i2) {
|
||||
adjacentDefReadExt(_, sv, bb1, i1, bb2, i2)
|
||||
or
|
||||
exists(PhiNode phi |
|
||||
lastRefRedefExt(_, sv, bb1, i1, phi) and
|
||||
phi.definesAt(sv, bb2, i2, _)
|
||||
)
|
||||
}
|
||||
|
||||
predicate useToNode(IRBlock bb, int i, SourceVariable sv, Node nodeTo) {
|
||||
exists(Phi phi |
|
||||
phi.asPhi().definesAt(sv, bb, i, _) and
|
||||
nodeTo = phi.getNode()
|
||||
)
|
||||
or
|
||||
exists(UseImpl use |
|
||||
use.hasIndexInBlock(bb, i, sv) and
|
||||
nodeTo = use.getNode()
|
||||
@@ -713,26 +740,46 @@ predicate nodeToDefOrUse(Node node, SourceVariable sv, IRBlock bb, int i, boolea
|
||||
*/
|
||||
private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
|
||||
not exists(SourceVariable sv, IRBlock bb2, int i2 |
|
||||
useToNode(bb2, i2, sv, nTo) and
|
||||
nodeToDefOrUse(nTo, sv, bb2, i2, _) and
|
||||
adjacentDefRead(bb2, i2, sv, _, _)
|
||||
) and
|
||||
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
|
||||
hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and
|
||||
hasOperandAndIndex(nTo, op2, pragma[only_bind_into](indirectionIndex)) and
|
||||
instr = op2.getDef() and
|
||||
conversionFlow(op1, instr, _, _)
|
||||
(
|
||||
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
|
||||
hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and
|
||||
hasOperandAndIndex(nTo, op2, pragma[only_bind_into](indirectionIndex)) and
|
||||
instr = op2.getDef() and
|
||||
conversionFlow(op1, instr, _, _)
|
||||
)
|
||||
or
|
||||
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
|
||||
hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and
|
||||
hasOperandAndIndex(nTo, op2, indirectionIndex - 1) and
|
||||
instr = op2.getDef() and
|
||||
isDereference(instr, op1, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is a phi input node that should receive flow from the
|
||||
* definition to (or use of) `sv` at `(bb1, i1)`.
|
||||
* The reason for this predicate is a bit annoying:
|
||||
* We cannot mark a `PointerArithmeticInstruction` that computes an offset based on some SSA
|
||||
* variable `x` as a use of `x` since this creates taint-flow in the following example:
|
||||
* ```c
|
||||
* int x = array[source]
|
||||
* sink(*array)
|
||||
* ```
|
||||
* This is because `source` would flow from the operand of `PointerArithmeticInstruction` to the
|
||||
* result of the instruction, and into the `IndirectOperand` that represents the value of `*array`.
|
||||
* Then, via use-use flow, flow will arrive at `*array` in `sink(*array)`.
|
||||
*
|
||||
* So this predicate recurses back along conversions and `PointerArithmeticInstruction`s to find the
|
||||
* first use that has provides use-use flow, and uses that target as the target of the `nodeFrom`.
|
||||
*/
|
||||
private predicate phiToNode(SsaPhiInputNode node, SourceVariable sv, IRBlock bb1, int i1) {
|
||||
exists(PhiNode phi, IRBlock input |
|
||||
phi.hasInputFromBlock(_, sv, bb1, i1, input) and
|
||||
node.getPhiNode() = phi and
|
||||
node.getBlock() = input
|
||||
private predicate adjustForPointerArith(PostUpdateNode pun, SourceVariable sv, IRBlock bb2, int i2) {
|
||||
exists(IRBlock bb1, int i1, Node adjusted |
|
||||
indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
|
||||
nodeToDefOrUse(adjusted, sv, bb1, i1, _) and
|
||||
adjacentDefRead(bb1, i1, sv, bb2, i2)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -747,14 +794,10 @@ private predicate phiToNode(SsaPhiInputNode node, SourceVariable sv, IRBlock bb1
|
||||
private predicate ssaFlowImpl(
|
||||
IRBlock bb1, int i1, SourceVariable sv, Node nodeFrom, Node nodeTo, boolean uncertain
|
||||
) {
|
||||
nodeToDefOrUse(nodeFrom, sv, bb1, i1, uncertain) and
|
||||
(
|
||||
exists(IRBlock bb2, int i2 |
|
||||
adjacentDefRead(bb1, i1, sv, bb2, i2) and
|
||||
useToNode(bb2, i2, sv, nodeTo)
|
||||
)
|
||||
or
|
||||
phiToNode(nodeTo, sv, bb1, i1)
|
||||
exists(IRBlock bb2, int i2 |
|
||||
nodeToDefOrUse(nodeFrom, sv, bb1, i1, uncertain) and
|
||||
adjacentDefRead(bb1, i1, sv, bb2, i2) and
|
||||
useToNode(bb2, i2, sv, nodeTo)
|
||||
) and
|
||||
nodeFrom != nodeTo
|
||||
}
|
||||
@@ -763,7 +806,7 @@ private predicate ssaFlowImpl(
|
||||
private Node getAPriorDefinition(DefinitionExt next) {
|
||||
exists(IRBlock bb, int i, SourceVariable sv |
|
||||
lastRefRedefExt(_, pragma[only_bind_into](sv), pragma[only_bind_into](bb),
|
||||
pragma[only_bind_into](i), _, next) and
|
||||
pragma[only_bind_into](i), next) and
|
||||
nodeToDefOrUse(result, sv, bb, i, _)
|
||||
)
|
||||
}
|
||||
@@ -870,31 +913,9 @@ private predicate isArgumentOfCallable(DataFlowCall call, Node n) {
|
||||
* Holds if there is use-use flow from `pun`'s pre-update node to `n`.
|
||||
*/
|
||||
private predicate postUpdateNodeToFirstUse(PostUpdateNode pun, Node n) {
|
||||
// We cannot mark a `PointerArithmeticInstruction` that computes an offset
|
||||
// based on some SSA
|
||||
// variable `x` as a use of `x` since this creates taint-flow in the
|
||||
// following example:
|
||||
// ```c
|
||||
// int x = array[source]
|
||||
// sink(*array)
|
||||
// ```
|
||||
// This is because `source` would flow from the operand of `PointerArithmetic`
|
||||
// instruction to the result of the instruction, and into the `IndirectOperand`
|
||||
// that represents the value of `*array`. Then, via use-use flow, flow will
|
||||
// arrive at `*array` in `sink(*array)`.
|
||||
// So this predicate recurses back along conversions and `PointerArithmetic`
|
||||
// instructions to find the first use that has provides use-use flow, and
|
||||
// uses that target as the target of the `nodeFrom`.
|
||||
exists(Node adjusted, IRBlock bb1, int i1, SourceVariable sv |
|
||||
indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
|
||||
useToNode(bb1, i1, sv, adjusted)
|
||||
|
|
||||
exists(IRBlock bb2, int i2 |
|
||||
adjacentDefRead(bb1, i1, sv, bb2, i2) and
|
||||
useToNode(bb2, i2, sv, n)
|
||||
)
|
||||
or
|
||||
phiToNode(n, sv, bb1, i1)
|
||||
exists(SourceVariable sv, IRBlock bb2, int i2 |
|
||||
adjustForPointerArith(pun, sv, bb2, i2) and
|
||||
useToNode(bb2, i2, sv, n)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -949,23 +970,19 @@ predicate postUpdateFlow(PostUpdateNode pun, Node nodeTo) {
|
||||
|
||||
/** Holds if `nodeTo` receives flow from the phi node `nodeFrom`. */
|
||||
predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) {
|
||||
exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1 |
|
||||
exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, IRBlock bb2, int i2 |
|
||||
phi = nodeFrom.getPhiNode() and
|
||||
phi.definesAt(sv, bb1, i1, _)
|
||||
|
|
||||
exists(IRBlock bb2, int i2 |
|
||||
adjacentDefRead(bb1, i1, sv, bb2, i2) and
|
||||
useToNode(bb2, i2, sv, nodeTo)
|
||||
)
|
||||
or
|
||||
phiToNode(nodeTo, sv, bb1, i1)
|
||||
phi.definesAt(sv, bb1, i1, _) and
|
||||
adjacentDefRead(bb1, i1, sv, bb2, i2) and
|
||||
useToNode(bb2, i2, sv, nodeTo)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate baseSourceVariableIsGlobal(
|
||||
BaseIRVariable base, GlobalLikeVariable global, IRFunction func
|
||||
private predicate sourceVariableIsGlobal(
|
||||
SourceVariable sv, GlobalLikeVariable global, IRFunction func, int indirectionIndex
|
||||
) {
|
||||
exists(IRVariable irVar |
|
||||
exists(IRVariable irVar, BaseIRVariable base |
|
||||
sourceVariableHasBaseAndIndex(sv, base, indirectionIndex) and
|
||||
irVar = base.getIRVariable() and
|
||||
irVar.getEnclosingIRFunction() = func and
|
||||
global = irVar.getAst() and
|
||||
@@ -1032,26 +1049,22 @@ module SsaCached {
|
||||
* Holds if the node at index `i` in `bb` is a last reference to SSA definition
|
||||
* `def`. The reference is last because it can reach another write `next`,
|
||||
* without passing through another read or write.
|
||||
*
|
||||
* The path from node `i` in `bb` to `next` goes via basic block `input`,
|
||||
* which is either a predecessor of the basic block of `next`, or `input` =
|
||||
* `bb` in case `next` occurs in basic block `bb`.
|
||||
*/
|
||||
cached
|
||||
predicate lastRefRedefExt(
|
||||
DefinitionExt def, SourceVariable sv, IRBlock bb, int i, IRBlock input, DefinitionExt next
|
||||
DefinitionExt def, SourceVariable sv, IRBlock bb, int i, DefinitionExt next
|
||||
) {
|
||||
SsaImpl::lastRefRedefExt(def, sv, bb, i, input, next)
|
||||
SsaImpl::lastRefRedefExt(def, sv, bb, i, next)
|
||||
}
|
||||
|
||||
cached
|
||||
Definition phiHasInputFromBlockExt(PhiNode phi, IRBlock bb) {
|
||||
SsaImpl::phiHasInputFromBlockExt(phi, result, bb)
|
||||
Definition phiHasInputFromBlock(PhiNode phi, IRBlock bb) {
|
||||
SsaImpl::phiHasInputFromBlock(phi, result, bb)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate ssaDefReachesReadExt(SourceVariable v, DefinitionExt def, IRBlock bb, int i) {
|
||||
SsaImpl::ssaDefReachesReadExt(v, def, bb, i)
|
||||
predicate ssaDefReachesRead(SourceVariable v, Definition def, IRBlock bb, int i) {
|
||||
SsaImpl::ssaDefReachesRead(v, def, bb, i)
|
||||
}
|
||||
|
||||
predicate variableRead = SsaInput::variableRead/4;
|
||||
@@ -1203,11 +1216,11 @@ class Phi extends TPhi, SsaDef {
|
||||
|
||||
final override Location getLocation() { result = phi.getBasicBlock().getLocation() }
|
||||
|
||||
override string toString() { result = phi.toString() }
|
||||
override string toString() { result = "Phi" }
|
||||
|
||||
SsaPhiInputNode getNode(IRBlock block) { result.getPhiNode() = phi and result.getBlock() = block }
|
||||
SsaPhiNode getNode() { result.getPhiNode() = phi }
|
||||
|
||||
predicate hasInputFromBlock(Definition inp, IRBlock bb) { inp = phiHasInputFromBlockExt(phi, bb) }
|
||||
predicate hasInputFromBlock(Definition inp, IRBlock bb) { inp = phiHasInputFromBlock(phi, bb) }
|
||||
|
||||
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
|
||||
}
|
||||
@@ -1233,21 +1246,13 @@ class PhiNode extends SsaImpl::DefinitionExt {
|
||||
*/
|
||||
predicate isPhiRead() { this instanceof SsaImpl::PhiReadNode }
|
||||
|
||||
/**
|
||||
* Holds if the node at index `i` in `bb` is a last reference to SSA
|
||||
* definition `def` of `sv`. The reference is last because it can reach
|
||||
* this phi node, without passing through another read or write.
|
||||
*
|
||||
* The path from node `i` in `bb` to this phi node goes via basic block
|
||||
* `input`, which is either a predecessor of the basic block of this phi
|
||||
* node, or `input` = `bb` in case this phi node occurs in basic block `bb`.
|
||||
*/
|
||||
predicate hasInputFromBlock(DefinitionExt def, SourceVariable sv, IRBlock bb, int i, IRBlock input) {
|
||||
SsaCached::lastRefRedefExt(def, sv, bb, i, input, this)
|
||||
/** Holds if `inp` is an input to this phi node along the edge originating in `bb`. */
|
||||
predicate hasInputFromBlock(Definition inp, IRBlock bb) {
|
||||
inp = SsaCached::phiHasInputFromBlock(this, bb)
|
||||
}
|
||||
|
||||
/** Gets a definition that is an input to this phi node. */
|
||||
final Definition getAnInput() { this.hasInputFromBlock(result, _, _, _, _) }
|
||||
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
|
||||
}
|
||||
|
||||
/** An static single assignment (SSA) definition. */
|
||||
@@ -1262,15 +1267,6 @@ class DefinitionExt extends SsaImpl::DefinitionExt {
|
||||
result = this.getAPhiInputOrPriorDefinition*() and
|
||||
not result instanceof PhiNode
|
||||
}
|
||||
|
||||
/** Gets a node that represents a read of this SSA definition. */
|
||||
Node getARead() {
|
||||
exists(SourceVariable sv, IRBlock bb, int i | SsaCached::ssaDefReachesReadExt(sv, this, bb, i) |
|
||||
useToNode(bb, i, sv, result)
|
||||
or
|
||||
phiToNode(result, sv, bb, i)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class Definition = SsaImpl::Definition;
|
||||
|
||||
@@ -830,12 +830,6 @@ newtype TTranslatedElement =
|
||||
not ignoreExpr(dc)
|
||||
)
|
||||
} or
|
||||
// The set of destructors to invoke after a handler for a `try` statement. These
|
||||
// need to be special cased because the destructors need to run following an
|
||||
// `ExceptionEdge`, but not following a `GotoEdge` edge.
|
||||
TTranslatedDestructorsAfterHandler(Handler handler) {
|
||||
exists(handler.getAnImplicitDestructorCall())
|
||||
} or
|
||||
// A precise side effect of an argument to a `Call`
|
||||
TTranslatedArgumentExprSideEffect(Call call, Expr expr, int n, SideEffectOpcode opcode) {
|
||||
not ignoreExpr(expr) and
|
||||
|
||||
@@ -1844,6 +1844,9 @@ class TranslatedAssignExpr extends TranslatedNonConstantExpr {
|
||||
child = this.getRightOperand() and
|
||||
result = this.getLeftOperand().getFirstInstruction(kind)
|
||||
or
|
||||
child = this.getRightOperand() and
|
||||
result = this.getLeftOperand().getFirstInstruction(kind)
|
||||
or
|
||||
kind instanceof GotoEdge and
|
||||
child = this.getLeftOperand() and
|
||||
result = this.getInstruction(AssignmentStoreTag())
|
||||
@@ -3208,20 +3211,9 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
|
||||
|
||||
final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) }
|
||||
|
||||
/**
|
||||
* Gets the rnk'th (0-indexed) child for which a `TranslatedElement` exists.
|
||||
*
|
||||
* We use this predicate to filter out `TypeName` expressions that sometimes
|
||||
* occur in builtin operations since the IR doesn't have an instruction to
|
||||
* represent a reference to a type.
|
||||
*/
|
||||
private TranslatedElement getRankedChild(int rnk) {
|
||||
result = rank[rnk + 1](int id, TranslatedElement te | te = this.getChild(id) | te order by id)
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
if exists(this.getRankedChild(0))
|
||||
then result = this.getRankedChild(0).getFirstInstruction(kind)
|
||||
if exists(this.getChild(0))
|
||||
then result = this.getChild(0).getFirstInstruction(kind)
|
||||
else (
|
||||
kind instanceof GotoEdge and result = this.getInstruction(OnlyInstructionTag())
|
||||
)
|
||||
@@ -3241,11 +3233,11 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
|
||||
}
|
||||
|
||||
final override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
|
||||
exists(int id | child = this.getRankedChild(id) |
|
||||
result = this.getRankedChild(id + 1).getFirstInstruction(kind)
|
||||
exists(int id | child = this.getChild(id) |
|
||||
result = this.getChild(id + 1).getFirstInstruction(kind)
|
||||
or
|
||||
kind instanceof GotoEdge and
|
||||
not exists(this.getRankedChild(id + 1)) and
|
||||
not exists(this.getChild(id + 1)) and
|
||||
result = this.getInstruction(OnlyInstructionTag())
|
||||
)
|
||||
}
|
||||
@@ -3260,7 +3252,7 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
|
||||
tag = OnlyInstructionTag() and
|
||||
exists(int index |
|
||||
operandTag = positionalArgumentOperand(index) and
|
||||
result = this.getRankedChild(index).(TranslatedExpr).getResult()
|
||||
result = this.getChild(index).(TranslatedExpr).getResult()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -777,72 +777,6 @@ abstract class TranslatedHandler extends TranslatedStmt {
|
||||
TranslatedStmt getBlock() { result = getTranslatedStmt(stmt.getBlock()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of the destructor calls of the parent `TranslatedCatchByTypeHandler`.
|
||||
*
|
||||
* This object does not itself generate the destructor calls. Instead, its
|
||||
* children provide the actual calls.
|
||||
*/
|
||||
class TranslatedDestructorsAfterHandler extends TranslatedElement,
|
||||
TTranslatedDestructorsAfterHandler
|
||||
{
|
||||
Handler handler;
|
||||
|
||||
TranslatedDestructorsAfterHandler() { this = TTranslatedDestructorsAfterHandler(handler) }
|
||||
|
||||
override string toString() { result = "Destructor calls after handler: " + handler }
|
||||
|
||||
private TranslatedCall getTranslatedImplicitDestructorCall(int id) {
|
||||
result.getExpr() = handler.getImplicitDestructorCall(id)
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
result = this.getChild(0).getFirstInstruction(kind)
|
||||
}
|
||||
|
||||
override Handler getAst() { result = handler }
|
||||
|
||||
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
result = this.getTranslatedImplicitDestructorCall(id)
|
||||
}
|
||||
|
||||
override predicate handlesDestructorsExplicitly() { any() }
|
||||
|
||||
override Declaration getFunction() { result = handler.getEnclosingFunction() }
|
||||
|
||||
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
|
||||
exists(int id | child = this.getChild(id) |
|
||||
// Transition to the next child, if any.
|
||||
result = this.getChild(id + 1).getFirstInstruction(kind)
|
||||
or
|
||||
// And otherwise go to the next handler, if any.
|
||||
not exists(this.getChild(id + 1)) and
|
||||
result =
|
||||
getTranslatedStmt(handler)
|
||||
.getParent()
|
||||
.(TranslatedTryStmt)
|
||||
.getNextHandler(getTranslatedStmt(handler), kind)
|
||||
)
|
||||
}
|
||||
|
||||
override TranslatedElement getLastChild() {
|
||||
result =
|
||||
this.getTranslatedImplicitDestructorCall(max(int id |
|
||||
exists(handler.getImplicitDestructorCall(id))
|
||||
))
|
||||
}
|
||||
|
||||
override Instruction getALastInstructionInternal() {
|
||||
result = this.getLastChild().getALastInstruction()
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of a C++ `catch` block that catches an exception with a
|
||||
* specific type (e.g. `catch (const std::exception&)`).
|
||||
@@ -856,14 +790,10 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler {
|
||||
resultType = getVoidType()
|
||||
}
|
||||
|
||||
override predicate handlesDestructorsExplicitly() { any() }
|
||||
|
||||
override TranslatedElement getChildInternal(int id) {
|
||||
result = super.getChildInternal(id)
|
||||
or
|
||||
id = 0 and result = this.getParameter()
|
||||
or
|
||||
id = 1 and result = this.getDestructors()
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
|
||||
@@ -880,9 +810,7 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler {
|
||||
result = this.getParameter().getFirstInstruction(kind)
|
||||
or
|
||||
kind instanceof ExceptionEdge and
|
||||
if exists(this.getDestructors())
|
||||
then result = this.getDestructors().getFirstInstruction(any(GotoEdge edge))
|
||||
else result = this.getParent().(TranslatedTryStmt).getNextHandler(this, any(GotoEdge edge))
|
||||
result = this.getParent().(TranslatedTryStmt).getNextHandler(this, any(GotoEdge edge))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -894,8 +822,6 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler {
|
||||
private TranslatedParameter getParameter() {
|
||||
result = getTranslatedParameter(stmt.getParameter())
|
||||
}
|
||||
|
||||
private TranslatedDestructorsAfterHandler getDestructors() { result.getAst() = stmt }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -916,7 +842,9 @@ class TranslatedCatchAnyHandler extends TranslatedHandler {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TranslatedIfLikeStmt extends TranslatedStmt, ConditionContext {
|
||||
class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
|
||||
override IfStmt stmt;
|
||||
|
||||
override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
if this.hasInitialization()
|
||||
then result = this.getInitialization().getFirstInstruction(kind)
|
||||
@@ -929,8 +857,6 @@ abstract class TranslatedIfLikeStmt extends TranslatedStmt, ConditionContext {
|
||||
|
||||
override TranslatedElement getLastChild() { result = this.getElse() or result = this.getThen() }
|
||||
|
||||
override predicate handlesDestructorsExplicitly() { any() }
|
||||
|
||||
override TranslatedElement getChildInternal(int id) {
|
||||
id = 0 and result = this.getInitialization()
|
||||
or
|
||||
@@ -941,21 +867,25 @@ abstract class TranslatedIfLikeStmt extends TranslatedStmt, ConditionContext {
|
||||
id = 3 and result = this.getElse()
|
||||
}
|
||||
|
||||
abstract predicate hasInitialization();
|
||||
private predicate hasInitialization() { exists(stmt.getInitialization()) }
|
||||
|
||||
abstract TranslatedStmt getInitialization();
|
||||
private TranslatedStmt getInitialization() {
|
||||
result = getTranslatedStmt(stmt.getInitialization())
|
||||
}
|
||||
|
||||
abstract TranslatedCondition getCondition();
|
||||
private TranslatedCondition getCondition() {
|
||||
result = getTranslatedCondition(stmt.getCondition().getFullyConverted())
|
||||
}
|
||||
|
||||
private Instruction getFirstConditionInstruction(EdgeKind kind) {
|
||||
result = this.getCondition().getFirstInstruction(kind)
|
||||
}
|
||||
|
||||
abstract TranslatedStmt getThen();
|
||||
private TranslatedStmt getThen() { result = getTranslatedStmt(stmt.getThen()) }
|
||||
|
||||
abstract TranslatedStmt getElse();
|
||||
private TranslatedStmt getElse() { result = getTranslatedStmt(stmt.getElse()) }
|
||||
|
||||
abstract predicate hasElse();
|
||||
private predicate hasElse() { exists(stmt.getElse()) }
|
||||
|
||||
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
@@ -968,11 +898,7 @@ abstract class TranslatedIfLikeStmt extends TranslatedStmt, ConditionContext {
|
||||
child = this.getCondition() and
|
||||
if this.hasElse()
|
||||
then result = this.getElse().getFirstInstruction(kind)
|
||||
else (
|
||||
if this.hasAnImplicitDestructorCall()
|
||||
then result = this.getChild(this.getFirstDestructorCallIndex()).getFirstInstruction(kind)
|
||||
else result = this.getParent().getChildSuccessor(this, kind)
|
||||
)
|
||||
else result = this.getParent().getChildSuccessor(this, kind)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
|
||||
@@ -980,24 +906,7 @@ abstract class TranslatedIfLikeStmt extends TranslatedStmt, ConditionContext {
|
||||
result = this.getFirstConditionInstruction(kind)
|
||||
or
|
||||
(child = this.getThen() or child = this.getElse()) and
|
||||
(
|
||||
if this.hasAnImplicitDestructorCall()
|
||||
then result = this.getChild(this.getFirstDestructorCallIndex()).getFirstInstruction(kind)
|
||||
else result = this.getParent().getChildSuccessor(this, kind)
|
||||
)
|
||||
or
|
||||
exists(int destructorId |
|
||||
destructorId >= this.getFirstDestructorCallIndex() and
|
||||
child = this.getChild(destructorId) and
|
||||
result = this.getChild(destructorId + 1).getFirstInstruction(kind)
|
||||
)
|
||||
or
|
||||
exists(int lastDestructorIndex |
|
||||
lastDestructorIndex =
|
||||
max(int n | exists(this.getChild(n)) and n >= this.getFirstDestructorCallIndex()) and
|
||||
child = this.getChild(lastDestructorIndex) and
|
||||
result = this.getParent().getChildSuccessor(this, kind)
|
||||
)
|
||||
result = this.getParent().getChildSuccessor(this, kind)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
@@ -1005,44 +914,76 @@ abstract class TranslatedIfLikeStmt extends TranslatedStmt, ConditionContext {
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedIfStmt extends TranslatedIfLikeStmt {
|
||||
override IfStmt stmt;
|
||||
|
||||
override predicate hasInitialization() { exists(stmt.getInitialization()) }
|
||||
|
||||
override TranslatedStmt getInitialization() {
|
||||
result = getTranslatedStmt(stmt.getInitialization())
|
||||
}
|
||||
|
||||
override TranslatedCondition getCondition() {
|
||||
result = getTranslatedCondition(stmt.getCondition().getFullyConverted())
|
||||
}
|
||||
|
||||
override TranslatedStmt getThen() { result = getTranslatedStmt(stmt.getThen()) }
|
||||
|
||||
override TranslatedStmt getElse() { result = getTranslatedStmt(stmt.getElse()) }
|
||||
|
||||
override predicate hasElse() { exists(stmt.getElse()) }
|
||||
}
|
||||
|
||||
class TranslatedConstExprIfStmt extends TranslatedIfLikeStmt {
|
||||
class TranslatedConstExprIfStmt extends TranslatedStmt, ConditionContext {
|
||||
override ConstexprIfStmt stmt;
|
||||
|
||||
override predicate hasInitialization() { exists(stmt.getInitialization()) }
|
||||
override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
if this.hasInitialization()
|
||||
then result = this.getInitialization().getFirstInstruction(kind)
|
||||
else result = this.getFirstConditionInstruction(kind)
|
||||
}
|
||||
|
||||
override TranslatedStmt getInitialization() {
|
||||
override TranslatedElement getChildInternal(int id) {
|
||||
id = 0 and result = this.getInitialization()
|
||||
or
|
||||
id = 1 and result = this.getCondition()
|
||||
or
|
||||
id = 2 and result = this.getThen()
|
||||
or
|
||||
id = 3 and result = this.getElse()
|
||||
}
|
||||
|
||||
private predicate hasInitialization() { exists(stmt.getInitialization()) }
|
||||
|
||||
private TranslatedStmt getInitialization() {
|
||||
result = getTranslatedStmt(stmt.getInitialization())
|
||||
}
|
||||
|
||||
override TranslatedCondition getCondition() {
|
||||
private TranslatedCondition getCondition() {
|
||||
result = getTranslatedCondition(stmt.getCondition().getFullyConverted())
|
||||
}
|
||||
|
||||
override TranslatedStmt getThen() { result = getTranslatedStmt(stmt.getThen()) }
|
||||
private Instruction getFirstConditionInstruction(EdgeKind kind) {
|
||||
result = this.getCondition().getFirstInstruction(kind)
|
||||
}
|
||||
|
||||
override TranslatedStmt getElse() { result = getTranslatedStmt(stmt.getElse()) }
|
||||
private TranslatedStmt getThen() { result = getTranslatedStmt(stmt.getThen()) }
|
||||
|
||||
override predicate hasElse() { exists(stmt.getElse()) }
|
||||
private TranslatedStmt getElse() { result = getTranslatedStmt(stmt.getElse()) }
|
||||
|
||||
private predicate hasElse() { exists(stmt.getElse()) }
|
||||
|
||||
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child, EdgeKind kind) {
|
||||
child = this.getCondition() and
|
||||
result = this.getThen().getFirstInstruction(kind)
|
||||
}
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child, EdgeKind kind) {
|
||||
child = this.getCondition() and
|
||||
if this.hasElse()
|
||||
then result = this.getElse().getFirstInstruction(kind)
|
||||
else result = this.getParent().getChildSuccessor(this, kind)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
|
||||
child = this.getInitialization() and
|
||||
result = this.getFirstConditionInstruction(kind)
|
||||
or
|
||||
(child = this.getThen() or child = this.getElse()) and
|
||||
result = this.getParent().getChildSuccessor(this, kind)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
override Instruction getALastInstructionInternal() {
|
||||
result = this.getThen().getALastInstruction()
|
||||
or
|
||||
result = this.getElse().getALastInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TranslatedLoop extends TranslatedStmt, ConditionContext {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
description: Removed unused column from the `folders` and `files` relations
|
||||
compatibility: full
|
||||
files.rel: reorder files.rel (@file id, string name, string simple, string ext, int fromSource) id name
|
||||
folders.rel: reorder folders.rel (@folder id, string name, string simple) id name
|
||||
files.rel: reorder files.rel (int id, string name, string simple, string ext, int fromSource) id name
|
||||
folders.rel: reorder folders.rel (int id, string name, string simple) id name
|
||||
@@ -1,20 +1,3 @@
|
||||
## 1.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The "Use of unique pointer after lifetime ends" query (`cpp/use-of-unique-pointer-after-lifetime-ends`) no longer reports an alert when the pointer is converted to a boolean
|
||||
* The "Variable not initialized before use" query (`cpp/not-initialised`) no longer reports an alert on static variables.
|
||||
|
||||
## 0.9.12
|
||||
|
||||
### New Queries
|
||||
|
||||
* Added a new query, `cpp/iterator-to-expired-container`, to detect the creation of iterators owned by a temporary objects that are about to be destroyed.
|
||||
|
||||
## 0.9.11
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -14,32 +14,13 @@ the program, or security vulnerabilities, by allowing an attacker to overwrite a
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>
|
||||
Ensure that all execution paths deallocate the allocated memory at most once. In complex cases it may
|
||||
help to reassign a pointer to a null value after deallocating it. This will prevent double-free vulnerabilities
|
||||
since most deallocation functions will perform a null-pointer check before attempting to deallocate memory.
|
||||
Ensure that all execution paths deallocate the allocated memory at most once. If possible, reassign
|
||||
the pointer to a null value after deallocating it. This will prevent double-free vulnerabilities since
|
||||
most deallocation functions will perform a null-pointer check before attempting to deallocate the memory.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>
|
||||
In the following example, <code>buff</code> is allocated and then freed twice:
|
||||
</p>
|
||||
<sample src="DoubleFreeBad.cpp" />
|
||||
<p>
|
||||
Reviewing the code above, the issue can be fixed by simply deleting the additional call to
|
||||
<code>free(buff)</code>.
|
||||
</p>
|
||||
<sample src="DoubleFreeGood.cpp" />
|
||||
<p>
|
||||
In the next example, <code>task</code> may be deleted twice, if an exception occurs inside the <code>try</code>
|
||||
block after the first <code>delete</code>:
|
||||
</p>
|
||||
<sample src="DoubleFreeBad2.cpp" />
|
||||
<p>
|
||||
The problem can be solved by assigning a null value to the pointer after the first <code>delete</code>, as
|
||||
calling <code>delete</code> a second time on the null pointer is harmless.
|
||||
</p>
|
||||
<sample src="DoubleFreeGood2.cpp" />
|
||||
<example><sample src="DoubleFree.cpp" />
|
||||
</example>
|
||||
<references>
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
void g() {
|
||||
MyTask *task = nullptr;
|
||||
|
||||
try
|
||||
{
|
||||
task = new MyTask;
|
||||
|
||||
...
|
||||
|
||||
delete task;
|
||||
|
||||
...
|
||||
} catch (...) {
|
||||
delete task; // BAD: potential double-free
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
int* f() {
|
||||
int *buff = malloc(SIZE*sizeof(int));
|
||||
do_stuff(buff);
|
||||
free(buff); // GOOD: buff is only freed once.
|
||||
int *new_buffer = malloc(SIZE*sizeof(int));
|
||||
return new_buffer;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
void g() {
|
||||
MyTask *task = nullptr;
|
||||
|
||||
try
|
||||
{
|
||||
task = new MyTask;
|
||||
|
||||
...
|
||||
|
||||
delete task;
|
||||
task = nullptr;
|
||||
|
||||
...
|
||||
} catch (...) {
|
||||
delete task; // GOOD: harmless if task is NULL
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,6 @@ predicate undefinedLocalUse(VariableAccess va) {
|
||||
// it is hard to tell when a struct or array has been initialized, so we
|
||||
// ignore them
|
||||
not isAggregateType(lv.getUnderlyingType()) and
|
||||
not lv.isStatic() and // static variables are initialized to zero or null by default
|
||||
not lv.getType().hasName("va_list") and
|
||||
va = lv.getAnAccess() and
|
||||
noDefPath(lv, va) and
|
||||
@@ -71,8 +70,7 @@ predicate uninitialisedGlobal(GlobalVariable gv) {
|
||||
va = gv.getAnAccess() and
|
||||
va.isRValue() and
|
||||
not gv.hasInitializer() and
|
||||
not gv.hasSpecifier("extern") and
|
||||
not gv.isStatic() // static variables are initialized to zero or null by default
|
||||
not gv.hasSpecifier("extern")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ in the previous example, one solution is to make the log message a trailing argu
|
||||
<p>An alternative solution is to allow <code>log_with_timestamp</code> to accept format arguments:</p>
|
||||
<sample src="NonConstantFormat-2-good.c" />
|
||||
<p>In this formulation, the non-constant format string to <code>printf</code> has been replaced with
|
||||
a non-constant format string to <code>vprintf</code>. The analysis will no longer consider the body of
|
||||
a non-constant format string to <code>vprintf</code>. Semmle will no longer consider the body of
|
||||
<code>log_with_timestamp</code> to be a problem, and will instead check that every call to
|
||||
<code>log_with_timestamp</code> passes a constant format string.</p>
|
||||
|
||||
|
||||
@@ -37,19 +37,6 @@ class AllocaCall extends FunctionCall {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression associated with a dataflow node.
|
||||
*/
|
||||
private Expr getExpr(DataFlow::Node node) {
|
||||
result = node.asInstruction().getAst()
|
||||
or
|
||||
result = node.asOperand().getUse().getAst()
|
||||
or
|
||||
result = node.(DataFlow::RawIndirectInstruction).getInstruction().getAst()
|
||||
or
|
||||
result = node.(DataFlow::RawIndirectOperand).getOperand().getUse().getAst()
|
||||
}
|
||||
|
||||
/**
|
||||
* A loop that contains an `alloca` call.
|
||||
*/
|
||||
@@ -198,6 +185,19 @@ class LoopWithAlloca extends Stmt {
|
||||
not this.conditionReachesWithoutUpdate(var, this.(Loop).getCondition())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression associated with a dataflow node.
|
||||
*/
|
||||
private Expr getExpr(DataFlow::Node node) {
|
||||
result = node.asInstruction().getAst()
|
||||
or
|
||||
result = node.asOperand().getUse().getAst()
|
||||
or
|
||||
result = node.(DataFlow::RawIndirectInstruction).getInstruction().getAst()
|
||||
or
|
||||
result = node.(DataFlow::RawIndirectOperand).getOperand().getUse().getAst()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a definition that may be the most recent definition of the
|
||||
* controlling variable `var` before this loop.
|
||||
@@ -209,9 +209,8 @@ class LoopWithAlloca extends Stmt {
|
||||
DataFlow::localFlow(result, DataFlow::exprNode(va)) and
|
||||
// Phi nodes will be preceded by nodes that represent actual definitions
|
||||
not result instanceof DataFlow::SsaPhiNode and
|
||||
not result instanceof DataFlow::SsaPhiInputNode and
|
||||
// A source is outside the loop if it's not inside the loop
|
||||
not exists(Expr e | e = getExpr(result) | this = getAnEnclosingLoopOfExpr(e))
|
||||
not exists(Expr e | e = this.getExpr(result) | this = getAnEnclosingLoopOfExpr(e))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -222,9 +221,9 @@ class LoopWithAlloca extends Stmt {
|
||||
private int getAControllingVarInitialValue(Variable var, DataFlow::Node source) {
|
||||
source = this.getAPrecedingDef(var) and
|
||||
(
|
||||
result = getExpr(source).getValue().toInt()
|
||||
result = this.getExpr(source).getValue().toInt()
|
||||
or
|
||||
result = getExpr(source).(Assignment).getRValue().getValue().toInt()
|
||||
result = this.getExpr(source).(Assignment).getRValue().getValue().toInt()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ class SnprintfSizeExpr extends BufferAccess, FunctionCall {
|
||||
}
|
||||
|
||||
class MemcmpSizeExpr extends BufferAccess, FunctionCall {
|
||||
MemcmpSizeExpr() { this.getTarget().hasName("memcmp") }
|
||||
MemcmpSizeExpr() { this.getTarget().hasName("Memcmp") }
|
||||
|
||||
override Expr getPointer() {
|
||||
result = this.getArgument(0) or
|
||||
|
||||
22
cpp/ql/src/Security/CWE/CWE-022/TaintedPath.c
Normal file
22
cpp/ql/src/Security/CWE/CWE-022/TaintedPath.c
Normal file
@@ -0,0 +1,22 @@
|
||||
int main(int argc, char** argv) {
|
||||
char *userAndFile = argv[2];
|
||||
|
||||
{
|
||||
char fileBuffer[FILENAME_MAX] = "/home/";
|
||||
char *fileName = fileBuffer;
|
||||
size_t len = strlen(fileName);
|
||||
strncat(fileName+len, userAndFile, FILENAME_MAX-len-1);
|
||||
// BAD: a string from the user is used in a filename
|
||||
fopen(fileName, "wb+");
|
||||
}
|
||||
|
||||
{
|
||||
char fileBuffer[FILENAME_MAX] = "/home/";
|
||||
char *fileName = fileBuffer;
|
||||
size_t len = strlen(fileName);
|
||||
// GOOD: use a fixed file
|
||||
char* fixed = "jim/file.txt";
|
||||
strncat(fileName+len, fixed, FILENAME_MAX-len-1);
|
||||
fopen(fileName, "wb+");
|
||||
}
|
||||
}
|
||||
@@ -3,57 +3,36 @@
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Accessing paths controlled by users can allow an attacker to access unexpected resources. This
|
||||
<p>Accessing paths controlled by users can allow an attacker to access unexpected resources. This
|
||||
can result in sensitive information being revealed or deleted, or an attacker being able to influence
|
||||
behavior by modifying unexpected files.</p>
|
||||
|
||||
<p>Paths that are naively constructed from data controlled by a user may be absolute paths, or may contain
|
||||
unexpected special characters such as "..". Such a path could point anywhere on the file system.</p>
|
||||
<p>Paths that are naively constructed from data controlled by a user may contain unexpected special characters,
|
||||
such as "..". Such a path may potentially point to any directory on the filesystem.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Validate user input before using it to construct a file path.</p>
|
||||
<p>Validate user input before using it to construct a filepath. Ideally, follow these rules:</p>
|
||||
|
||||
<p>Common validation methods include checking that the normalized path is relative and does not contain
|
||||
any ".." components, or checking that the path is contained within a safe folder. The method you should use depends
|
||||
on how the path is used in the application, and whether the path should be a single path component.
|
||||
</p>
|
||||
|
||||
<p>If the path should be a single path component (such as a file name), you can check for the existence
|
||||
of any path separators ("/" or "\"), or ".." sequences in the input, and reject the input if any are found.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that removing "../" sequences is <i>not</i> sufficient, since the input could still contain a path separator
|
||||
followed by "..". For example, the input ".../...//" would still result in the string "../" if only "../" sequences
|
||||
are removed.
|
||||
</p>
|
||||
|
||||
<p>Finally, the simplest (but most restrictive) option is to use an allow list of safe patterns and make sure that
|
||||
the user input matches one of these patterns.</p>
|
||||
<ul>
|
||||
<li>Do not allow more than a single "." character.</li>
|
||||
<li>Do not allow directory separators such as "/" or "\" (depending on the filesystem).</li>
|
||||
<li>Do not rely on simply replacing problematic sequences such as "../". For example, after applying this filter to
|
||||
".../...//" the resulting string would still be "../".</li>
|
||||
<li>Ideally use a whitelist of known good patterns.</li>
|
||||
</ul>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>In this example, a file name is read from a user and then used to access a file.
|
||||
However, a malicious user could enter a file name anywhere on the file system,
|
||||
such as "/etc/passwd" or "../../../etc/passwd".</p>
|
||||
<p>In this example, a username and file are read from the arguments to main and then used to access a file in the
|
||||
user's home directory. However, a malicious user could enter a filename which contains special
|
||||
characters. For example, the string "../../etc/passwd" will result in the code reading the file located at
|
||||
"/home/[user]/../../etc/passwd", which is the system's password file. This could potentially allow them to
|
||||
access all the system's passwords.</p>
|
||||
|
||||
<sample src="examples/TaintedPath.c" />
|
||||
|
||||
<p>
|
||||
If the input should only be a file name, you can check that it doesn't contain any path separators or ".." sequences.
|
||||
</p>
|
||||
|
||||
<sample src="examples/TaintedPathNormalize.c" />
|
||||
|
||||
<p>
|
||||
If the input should be within a specific directory, you can check that the resolved path
|
||||
is still contained within that directory.
|
||||
</p>
|
||||
|
||||
<sample src="examples/TaintedPathFolder.c" />
|
||||
<sample src="TaintedPath.c" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
@@ -62,7 +41,6 @@ is still contained within that directory.
|
||||
OWASP:
|
||||
<a href="https://owasp.org/www-community/attacks/Path_Traversal">Path Traversal</a>.
|
||||
</li>
|
||||
<li>Linux man pages: <a href="https://man7.org/linux/man-pages/man3/realpath.3.html">realpath(3)</a>.</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
int main(int argc, char** argv) {
|
||||
char *userAndFile = argv[2];
|
||||
|
||||
{
|
||||
char fileBuffer[PATH_MAX];
|
||||
snprintf(fileBuffer, sizeof(fileBuffer), "/home/%s", userAndFile);
|
||||
// BAD: a string from the user is used in a filename
|
||||
fopen(fileBuffer, "wb+");
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
char *userAndFile = argv[2];
|
||||
const char *baseDir = "/home/user/public/";
|
||||
char fullPath[PATH_MAX];
|
||||
|
||||
// Attempt to concatenate the base directory and the user-supplied path
|
||||
snprintf(fullPath, sizeof(fullPath), "%s%s", baseDir, userAndFile);
|
||||
|
||||
// Resolve the absolute path, normalizing any ".." or "."
|
||||
char *resolvedPath = realpath(fullPath, NULL);
|
||||
if (resolvedPath == NULL) {
|
||||
perror("Error resolving path");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check if the resolved path starts with the base directory
|
||||
if (strncmp(baseDir, resolvedPath, strlen(baseDir)) != 0) {
|
||||
free(resolvedPath);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// GOOD: Path is within the intended directory
|
||||
FILE *file = fopen(resolvedPath, "wb+");
|
||||
free(resolvedPath);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
char *fileName = argv[2];
|
||||
// Check for invalid sequences in the user input
|
||||
if (strstr(fileName , "..") || strchr(fileName , '/') || strchr(fileName , '\\')) {
|
||||
printf("Invalid filename.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char fileBuffer[PATH_MAX];
|
||||
snprintf(fileBuffer, sizeof(fileBuffer), "/home/user/files/%s", fileName);
|
||||
// GOOD: We know that the filename is safe and stays within the public folder
|
||||
FILE *file = fopen(fileBuffer, "wb+");
|
||||
}
|
||||
@@ -12,8 +12,8 @@ the required buffer size, but do not allocate space for the zero terminator.
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>
|
||||
The highlighted code segment creates a buffer without ensuring it's large enough to accommodate the copied data.
|
||||
This leaves the code susceptible to a buffer overflow attack, which could lead to anything from program crashes to malicious code execution.
|
||||
The expression highlighted by this rule creates a buffer that is of insufficient size to contain
|
||||
the data being copied. This makes the code vulnerable to buffer overflow which can result in anything from a segmentation fault to a security vulnerability (particularly if the array is on stack-allocated memory).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -30,8 +30,6 @@ where
|
||||
outlivesFullExpr(c) and
|
||||
not c.isFromUninstantiatedTemplate(_) and
|
||||
isUniquePointerDerefFunction(c.getTarget()) and
|
||||
// Exclude cases where the pointer is implicitly converted to a non-pointer type
|
||||
not c.getActualType() instanceof IntegralType and
|
||||
isTemporary(c.getQualifier().getFullyConverted())
|
||||
select c,
|
||||
"The underlying unique pointer object is destroyed after the call to '" + c.getTarget() +
|
||||
|
||||
@@ -17,6 +17,5 @@ import cpp
|
||||
from FunctionCall call, Function target
|
||||
where
|
||||
call.getTarget() = target and
|
||||
target.hasGlobalOrStdName("gets") and
|
||||
target.getNumberOfParameters() = 1
|
||||
target.hasGlobalOrStdName("gets")
|
||||
select call, "'gets' does not guard against buffer overflow."
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/dangerous-function-overflow` no longer produces a false positive alert when the `gets` function does not have exactly one parameter.
|
||||
@@ -1,5 +1,4 @@
|
||||
## 0.9.12
|
||||
|
||||
### New Queries
|
||||
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* Added a new query, `cpp/iterator-to-expired-container`, to detect the creation of iterators owned by a temporary objects that are about to be destroyed.
|
||||
@@ -1,10 +0,0 @@
|
||||
## 1.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The "Use of unique pointer after lifetime ends" query (`cpp/use-of-unique-pointer-after-lifetime-ends`) no longer reports an alert when the pointer is converted to a boolean
|
||||
* The "Variable not initialized before use" query (`cpp/not-initialised`) no longer reports an alert on static variables.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.0
|
||||
lastReleaseVersion: 0.9.11
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
char * create (int arg) {
|
||||
if (arg > 42) {
|
||||
// this function may return NULL
|
||||
return NULL;
|
||||
}
|
||||
char * r = malloc(arg);
|
||||
snprintf(r, arg -1, "Hello");
|
||||
return r;
|
||||
}
|
||||
|
||||
void process(char *str) {
|
||||
// str is dereferenced
|
||||
if (str[0] == 'H') {
|
||||
printf("Hello H\n");
|
||||
}
|
||||
}
|
||||
|
||||
void test(int arg) {
|
||||
// first function returns a pointer that may be NULL
|
||||
char *str = create(arg);
|
||||
// str is not checked for nullness before being passed to process function
|
||||
process(str);
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>This rule finds a dereference of a function parameter, whose value comes from another function call that may return NULL, without checks in the meantime.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>A check should be added between the return of the function which may return NULL, and its use by the function dereferencing ths pointer.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<sample src="DerefNullResult.cpp" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
<a href="https://www.owasp.org/index.php/Null_Dereference">
|
||||
Null Dereference
|
||||
</a>
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
* @name Null dereference from a function result
|
||||
* @description A function parameter is dereferenced,
|
||||
* while it comes from a function that may return NULL,
|
||||
* and is not checked for nullness by the caller.
|
||||
* @kind problem
|
||||
* @id cpp/deref-null-result
|
||||
* @problem.severity recommendation
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-476
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
from Function nuller, Parameter pd, FunctionCall fc, Variable v
|
||||
where
|
||||
mayReturnNull(nuller) and
|
||||
functionDereferences(pd.getFunction(), pd.getIndex()) and
|
||||
// there is a function call which will deref parameter pd
|
||||
fc.getTarget() = pd.getFunction() and
|
||||
// the parameter pd comes from a variable v
|
||||
DataFlow::localFlow(DataFlow::exprNode(v.getAnAccess()),
|
||||
DataFlow::exprNode(fc.getArgument(pd.getIndex()))) and
|
||||
// this variable v was assigned by a call to the nuller function
|
||||
unique( | | v.getAnAssignedValue()) = nuller.getACallToThisFunction() and
|
||||
// this variable v is not accessed for an operation (check for NULLness)
|
||||
not exists(VariableAccess vc |
|
||||
vc.getTarget() = v and
|
||||
(vc.getParent() instanceof Operation or vc.getParent() instanceof IfStmt)
|
||||
)
|
||||
select fc, "This function call may deref $@ when it can be NULL from $@", v, v.getName(), nuller,
|
||||
nuller.getName()
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 1.0.1-dev
|
||||
version: 0.9.12-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -1,55 +1,55 @@
|
||||
edges
|
||||
| test.cpp:34:10:34:12 | buf | test.cpp:34:5:34:24 | access to array | provenance | Config |
|
||||
| test.cpp:35:10:35:12 | buf | test.cpp:35:5:35:22 | access to array | provenance | Config |
|
||||
| test.cpp:36:10:36:12 | buf | test.cpp:36:5:36:24 | access to array | provenance | Config |
|
||||
| test.cpp:39:14:39:16 | buf | test.cpp:39:9:39:19 | access to array | provenance | Config |
|
||||
| test.cpp:43:14:43:16 | buf | test.cpp:43:9:43:19 | access to array | provenance | Config |
|
||||
| test.cpp:48:10:48:12 | buf | test.cpp:48:5:48:24 | access to array | provenance | Config |
|
||||
| test.cpp:49:10:49:12 | buf | test.cpp:49:5:49:22 | access to array | provenance | Config |
|
||||
| test.cpp:50:10:50:12 | buf | test.cpp:50:5:50:24 | access to array | provenance | Config |
|
||||
| test.cpp:53:14:53:16 | buf | test.cpp:53:9:53:19 | access to array | provenance | Config |
|
||||
| test.cpp:57:14:57:16 | buf | test.cpp:57:9:57:19 | access to array | provenance | Config |
|
||||
| test.cpp:61:14:61:16 | buf | test.cpp:61:9:61:19 | access to array | provenance | Config |
|
||||
| test.cpp:70:33:70:33 | p | test.cpp:71:5:71:17 | access to array | provenance | Config |
|
||||
| test.cpp:70:33:70:33 | p | test.cpp:72:5:72:15 | access to array | provenance | Config |
|
||||
| test.cpp:34:10:34:12 | buf | test.cpp:34:5:34:24 | access to array | provenance | |
|
||||
| test.cpp:35:10:35:12 | buf | test.cpp:35:5:35:22 | access to array | provenance | |
|
||||
| test.cpp:36:10:36:12 | buf | test.cpp:36:5:36:24 | access to array | provenance | |
|
||||
| test.cpp:39:14:39:16 | buf | test.cpp:39:9:39:19 | access to array | provenance | |
|
||||
| test.cpp:43:14:43:16 | buf | test.cpp:43:9:43:19 | access to array | provenance | |
|
||||
| test.cpp:48:10:48:12 | buf | test.cpp:48:5:48:24 | access to array | provenance | |
|
||||
| test.cpp:49:10:49:12 | buf | test.cpp:49:5:49:22 | access to array | provenance | |
|
||||
| test.cpp:50:10:50:12 | buf | test.cpp:50:5:50:24 | access to array | provenance | |
|
||||
| test.cpp:53:14:53:16 | buf | test.cpp:53:9:53:19 | access to array | provenance | |
|
||||
| test.cpp:57:14:57:16 | buf | test.cpp:57:9:57:19 | access to array | provenance | |
|
||||
| test.cpp:61:14:61:16 | buf | test.cpp:61:9:61:19 | access to array | provenance | |
|
||||
| test.cpp:70:33:70:33 | p | test.cpp:71:5:71:17 | access to array | provenance | |
|
||||
| test.cpp:70:33:70:33 | p | test.cpp:72:5:72:15 | access to array | provenance | |
|
||||
| test.cpp:76:26:76:46 | & ... | test.cpp:66:32:66:32 | p | provenance | |
|
||||
| test.cpp:76:32:76:34 | buf | test.cpp:76:26:76:46 | & ... | provenance | Config |
|
||||
| test.cpp:76:32:76:34 | buf | test.cpp:76:26:76:46 | & ... | provenance | |
|
||||
| test.cpp:77:26:77:44 | & ... | test.cpp:66:32:66:32 | p | provenance | |
|
||||
| test.cpp:77:32:77:34 | buf | test.cpp:77:26:77:44 | & ... | provenance | Config |
|
||||
| test.cpp:77:32:77:34 | buf | test.cpp:77:26:77:44 | & ... | provenance | |
|
||||
| test.cpp:79:27:79:34 | buf | test.cpp:70:33:70:33 | p | provenance | |
|
||||
| test.cpp:79:32:79:34 | buf | test.cpp:79:27:79:34 | buf | provenance | |
|
||||
| test.cpp:85:21:85:36 | buf | test.cpp:87:5:87:31 | access to array | provenance | Config |
|
||||
| test.cpp:85:21:85:36 | buf | test.cpp:88:5:88:27 | access to array | provenance | Config |
|
||||
| test.cpp:85:21:85:36 | buf | test.cpp:87:5:87:31 | access to array | provenance | |
|
||||
| test.cpp:85:21:85:36 | buf | test.cpp:88:5:88:27 | access to array | provenance | |
|
||||
| test.cpp:85:34:85:36 | buf | test.cpp:85:21:85:36 | buf | provenance | |
|
||||
| test.cpp:96:13:96:15 | arr | test.cpp:96:13:96:18 | access to array | provenance | Config |
|
||||
| test.cpp:111:17:111:19 | arr | test.cpp:111:17:111:22 | access to array | provenance | Config |
|
||||
| test.cpp:111:17:111:19 | arr | test.cpp:115:35:115:40 | access to array | provenance | Config |
|
||||
| test.cpp:111:17:111:19 | arr | test.cpp:119:17:119:22 | access to array | provenance | Config |
|
||||
| test.cpp:115:35:115:37 | arr | test.cpp:111:17:111:22 | access to array | provenance | Config |
|
||||
| test.cpp:115:35:115:37 | arr | test.cpp:115:35:115:40 | access to array | provenance | Config |
|
||||
| test.cpp:115:35:115:37 | arr | test.cpp:119:17:119:22 | access to array | provenance | Config |
|
||||
| test.cpp:119:17:119:19 | arr | test.cpp:111:17:111:22 | access to array | provenance | Config |
|
||||
| test.cpp:119:17:119:19 | arr | test.cpp:115:35:115:40 | access to array | provenance | Config |
|
||||
| test.cpp:119:17:119:19 | arr | test.cpp:119:17:119:22 | access to array | provenance | Config |
|
||||
| test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array | provenance | Config |
|
||||
| test.cpp:134:25:134:27 | arr | test.cpp:136:9:136:16 | ... += ... | provenance | Config |
|
||||
| test.cpp:96:13:96:15 | arr | test.cpp:96:13:96:18 | access to array | provenance | |
|
||||
| test.cpp:111:17:111:19 | arr | test.cpp:111:17:111:22 | access to array | provenance | |
|
||||
| test.cpp:111:17:111:19 | arr | test.cpp:115:35:115:40 | access to array | provenance | |
|
||||
| test.cpp:111:17:111:19 | arr | test.cpp:119:17:119:22 | access to array | provenance | |
|
||||
| test.cpp:115:35:115:37 | arr | test.cpp:111:17:111:22 | access to array | provenance | |
|
||||
| test.cpp:115:35:115:37 | arr | test.cpp:115:35:115:40 | access to array | provenance | |
|
||||
| test.cpp:115:35:115:37 | arr | test.cpp:119:17:119:22 | access to array | provenance | |
|
||||
| test.cpp:119:17:119:19 | arr | test.cpp:111:17:111:22 | access to array | provenance | |
|
||||
| test.cpp:119:17:119:19 | arr | test.cpp:115:35:115:40 | access to array | provenance | |
|
||||
| test.cpp:119:17:119:19 | arr | test.cpp:119:17:119:22 | access to array | provenance | |
|
||||
| test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array | provenance | |
|
||||
| test.cpp:134:25:134:27 | arr | test.cpp:136:9:136:16 | ... += ... | provenance | |
|
||||
| test.cpp:136:9:136:16 | ... += ... | test.cpp:136:9:136:16 | ... += ... | provenance | |
|
||||
| test.cpp:136:9:136:16 | ... += ... | test.cpp:138:13:138:15 | arr | provenance | |
|
||||
| test.cpp:143:18:143:21 | asdf | test.cpp:134:25:134:27 | arr | provenance | |
|
||||
| test.cpp:143:18:143:21 | asdf | test.cpp:143:18:143:21 | asdf | provenance | |
|
||||
| test.cpp:146:26:146:26 | *p | test.cpp:147:4:147:9 | -- ... | provenance | |
|
||||
| test.cpp:156:12:156:14 | buf | test.cpp:156:12:156:18 | ... + ... | provenance | Config |
|
||||
| test.cpp:156:12:156:14 | buf | test.cpp:156:12:156:18 | ... + ... | provenance | |
|
||||
| test.cpp:156:12:156:18 | ... + ... | test.cpp:156:12:156:18 | ... + ... | provenance | |
|
||||
| test.cpp:156:12:156:18 | ... + ... | test.cpp:158:17:158:18 | *& ... | provenance | |
|
||||
| test.cpp:158:17:158:18 | *& ... | test.cpp:146:26:146:26 | *p | provenance | |
|
||||
| test.cpp:218:16:218:28 | buffer | test.cpp:220:5:220:11 | access to array | provenance | Config |
|
||||
| test.cpp:218:16:218:28 | buffer | test.cpp:221:5:221:11 | access to array | provenance | Config |
|
||||
| test.cpp:218:16:218:28 | buffer | test.cpp:220:5:220:11 | access to array | provenance | |
|
||||
| test.cpp:218:16:218:28 | buffer | test.cpp:221:5:221:11 | access to array | provenance | |
|
||||
| test.cpp:218:23:218:28 | buffer | test.cpp:218:16:218:28 | buffer | provenance | |
|
||||
| test.cpp:229:17:229:29 | array | test.cpp:231:5:231:10 | access to array | provenance | Config |
|
||||
| test.cpp:229:17:229:29 | array | test.cpp:232:5:232:10 | access to array | provenance | Config |
|
||||
| test.cpp:229:17:229:29 | array | test.cpp:231:5:231:10 | access to array | provenance | |
|
||||
| test.cpp:229:17:229:29 | array | test.cpp:232:5:232:10 | access to array | provenance | |
|
||||
| test.cpp:229:25:229:29 | array | test.cpp:229:17:229:29 | array | provenance | |
|
||||
| test.cpp:245:30:245:30 | p | test.cpp:261:27:261:30 | access to array | provenance | Config |
|
||||
| test.cpp:245:30:245:30 | p | test.cpp:261:27:261:30 | access to array | provenance | Config |
|
||||
| test.cpp:245:30:245:30 | p | test.cpp:261:27:261:30 | access to array | provenance | |
|
||||
| test.cpp:245:30:245:30 | p | test.cpp:261:27:261:30 | access to array | provenance | |
|
||||
| test.cpp:274:14:274:20 | buffer3 | test.cpp:245:30:245:30 | p | provenance | |
|
||||
| test.cpp:274:14:274:20 | buffer3 | test.cpp:274:14:274:20 | buffer3 | provenance | |
|
||||
| test.cpp:277:35:277:35 | p | test.cpp:278:14:278:14 | p | provenance | |
|
||||
@@ -60,20 +60,21 @@ edges
|
||||
| test.cpp:286:19:286:25 | buffer2 | test.cpp:286:19:286:25 | buffer2 | provenance | |
|
||||
| test.cpp:289:19:289:25 | buffer3 | test.cpp:277:35:277:35 | p | provenance | |
|
||||
| test.cpp:289:19:289:25 | buffer3 | test.cpp:289:19:289:25 | buffer3 | provenance | |
|
||||
| test.cpp:292:25:292:27 | arr | test.cpp:299:16:299:21 | access to array | provenance | Config |
|
||||
| test.cpp:292:25:292:27 | arr | test.cpp:299:16:299:21 | access to array | provenance | |
|
||||
| test.cpp:292:25:292:27 | arr | test.cpp:299:16:299:21 | access to array | provenance | |
|
||||
| test.cpp:306:20:306:23 | arr1 | test.cpp:292:25:292:27 | arr | provenance | |
|
||||
| test.cpp:306:20:306:23 | arr1 | test.cpp:306:20:306:23 | arr1 | provenance | |
|
||||
| test.cpp:309:20:309:23 | arr2 | test.cpp:292:25:292:27 | arr | provenance | |
|
||||
| test.cpp:309:20:309:23 | arr2 | test.cpp:309:20:309:23 | arr2 | provenance | |
|
||||
| test.cpp:319:13:319:27 | ... = ... | test.cpp:325:24:325:26 | end | provenance | |
|
||||
| test.cpp:319:19:319:22 | temp | test.cpp:319:19:319:27 | ... + ... | provenance | Config |
|
||||
| test.cpp:319:19:319:22 | temp | test.cpp:324:23:324:32 | ... + ... | provenance | Config |
|
||||
| test.cpp:319:19:319:22 | temp | test.cpp:319:19:319:27 | ... + ... | provenance | |
|
||||
| test.cpp:319:19:319:22 | temp | test.cpp:324:23:324:32 | ... + ... | provenance | |
|
||||
| test.cpp:319:19:319:27 | ... + ... | test.cpp:319:13:319:27 | ... = ... | provenance | |
|
||||
| test.cpp:322:13:322:27 | ... = ... | test.cpp:325:24:325:26 | end | provenance | |
|
||||
| test.cpp:322:19:322:22 | temp | test.cpp:322:19:322:27 | ... + ... | provenance | Config |
|
||||
| test.cpp:322:19:322:22 | temp | test.cpp:324:23:324:32 | ... + ... | provenance | Config |
|
||||
| test.cpp:322:19:322:22 | temp | test.cpp:322:19:322:27 | ... + ... | provenance | |
|
||||
| test.cpp:322:19:322:22 | temp | test.cpp:324:23:324:32 | ... + ... | provenance | |
|
||||
| test.cpp:322:19:322:27 | ... + ... | test.cpp:322:13:322:27 | ... = ... | provenance | |
|
||||
| test.cpp:324:23:324:26 | temp | test.cpp:324:23:324:32 | ... + ... | provenance | Config |
|
||||
| test.cpp:324:23:324:26 | temp | test.cpp:324:23:324:32 | ... + ... | provenance | |
|
||||
| test.cpp:324:23:324:32 | ... + ... | test.cpp:324:23:324:32 | ... + ... | provenance | |
|
||||
| test.cpp:324:23:324:32 | ... + ... | test.cpp:325:15:325:19 | temp2 | provenance | |
|
||||
nodes
|
||||
@@ -158,6 +159,7 @@ nodes
|
||||
| test.cpp:289:19:289:25 | buffer3 | semmle.label | buffer3 |
|
||||
| test.cpp:289:19:289:25 | buffer3 | semmle.label | buffer3 |
|
||||
| test.cpp:292:25:292:27 | arr | semmle.label | arr |
|
||||
| test.cpp:292:25:292:27 | arr | semmle.label | arr |
|
||||
| test.cpp:299:16:299:21 | access to array | semmle.label | access to array |
|
||||
| test.cpp:306:20:306:23 | arr1 | semmle.label | arr1 |
|
||||
| test.cpp:306:20:306:23 | arr1 | semmle.label | arr1 |
|
||||
|
||||
@@ -160,9 +160,6 @@ astGuardsCompare
|
||||
| 137 | 0 == 0 when 0 is false |
|
||||
| 146 | ! ... != 0 when ! ... is true |
|
||||
| 146 | ! ... == 0 when ! ... is false |
|
||||
| 146 | x != 0 when ! ... is false |
|
||||
| 146 | x != 0 when x is true |
|
||||
| 146 | x == 0 when x is false |
|
||||
| 152 | x != 0 when ... && ... is true |
|
||||
| 152 | x != 0 when x is true |
|
||||
| 152 | x == 0 when x is false |
|
||||
@@ -521,7 +518,6 @@ astGuardsEnsure_const
|
||||
| test.c:131:7:131:7 | b | test.c:131:7:131:7 | b | != | 0 | 131 | 132 |
|
||||
| test.c:137:7:137:7 | 0 | test.c:137:7:137:7 | 0 | == | 0 | 142 | 136 |
|
||||
| test.c:146:7:146:8 | ! ... | test.c:146:7:146:8 | ! ... | != | 0 | 146 | 147 |
|
||||
| test.c:146:8:146:8 | x | test.c:146:8:146:8 | x | == | 0 | 146 | 147 |
|
||||
| test.c:152:10:152:10 | x | test.c:152:10:152:10 | x | != | 0 | 151 | 152 |
|
||||
| test.c:152:10:152:10 | x | test.c:152:10:152:10 | x | != | 0 | 152 | 152 |
|
||||
| test.c:152:10:152:15 | ... && ... | test.c:152:10:152:10 | x | != | 0 | 151 | 152 |
|
||||
@@ -693,9 +689,6 @@ irGuardsCompare
|
||||
| 137 | 0 == 0 when Constant: 0 is false |
|
||||
| 146 | ! ... != 0 when LogicalNot: ! ... is true |
|
||||
| 146 | ! ... == 0 when LogicalNot: ! ... is false |
|
||||
| 146 | x != 0 when Load: x is true |
|
||||
| 146 | x != 0 when LogicalNot: ! ... is false |
|
||||
| 146 | x == 0 when Load: x is false |
|
||||
| 152 | x != 0 when Load: x is true |
|
||||
| 152 | x == 0 when Load: x is false |
|
||||
| 152 | y != 0 when Load: y is true |
|
||||
@@ -1070,7 +1063,6 @@ irGuardsEnsure_const
|
||||
| test.c:131:7:131:7 | Load: b | test.c:131:7:131:7 | Load: b | != | 0 | 132 | 132 |
|
||||
| test.c:137:7:137:7 | Constant: 0 | test.c:137:7:137:7 | Constant: 0 | == | 0 | 142 | 142 |
|
||||
| test.c:146:7:146:8 | LogicalNot: ! ... | test.c:146:7:146:8 | LogicalNot: ! ... | != | 0 | 147 | 147 |
|
||||
| test.c:146:8:146:8 | Load: x | test.c:146:8:146:8 | Load: x | == | 0 | 147 | 147 |
|
||||
| test.c:152:10:152:10 | Load: x | test.c:152:10:152:10 | Load: x | != | 0 | 152 | 152 |
|
||||
| test.c:152:15:152:15 | Load: y | test.c:152:15:152:15 | Load: y | != | 0 | 152 | 152 |
|
||||
| test.c:175:13:175:32 | CompareEQ: ... == ... | test.c:175:13:175:15 | Call: call to foo | != | 0 | 175 | 175 |
|
||||
|
||||
@@ -161,20 +161,11 @@
|
||||
| 137 | 0 == 0 when 0 is false |
|
||||
| 146 | ! ... != 0 when ! ... is true |
|
||||
| 146 | ! ... == 0 when ! ... is false |
|
||||
| 146 | x != 0 when ! ... is false |
|
||||
| 146 | x != 0 when x is true |
|
||||
| 146 | x == 0 when x is false |
|
||||
| 152 | p != 0 when p is true |
|
||||
| 152 | p == 0 when p is false |
|
||||
| 158 | ! ... != 0 when ! ... is true |
|
||||
| 158 | ! ... == 0 when ! ... is false |
|
||||
| 158 | p != 0 when ! ... is false |
|
||||
| 158 | p != 0 when p is true |
|
||||
| 158 | p == 0 when p is false |
|
||||
| 164 | s != 0 when s is true |
|
||||
| 164 | s == 0 when s is false |
|
||||
| 170 | ! ... != 0 when ! ... is true |
|
||||
| 170 | ! ... == 0 when ! ... is false |
|
||||
| 170 | s != 0 when ! ... is false |
|
||||
| 170 | s != 0 when s is true |
|
||||
| 170 | s == 0 when s is false |
|
||||
|
||||
@@ -245,13 +245,10 @@ unary
|
||||
| test.c:131:7:131:7 | b | test.c:131:7:131:7 | b | != | 0 | 131 | 132 |
|
||||
| test.c:137:7:137:7 | 0 | test.c:137:7:137:7 | 0 | == | 0 | 142 | 136 |
|
||||
| test.c:146:7:146:8 | ! ... | test.c:146:7:146:8 | ! ... | != | 0 | 146 | 147 |
|
||||
| test.c:146:8:146:8 | x | test.c:146:8:146:8 | x | == | 0 | 146 | 147 |
|
||||
| test.c:152:8:152:8 | p | test.c:152:8:152:8 | p | != | 0 | 152 | 154 |
|
||||
| test.c:158:8:158:9 | ! ... | test.c:158:8:158:9 | ! ... | != | 0 | 158 | 160 |
|
||||
| test.c:158:9:158:9 | p | test.c:158:9:158:9 | p | == | 0 | 158 | 160 |
|
||||
| test.c:164:8:164:8 | s | test.c:164:8:164:8 | s | != | 0 | 164 | 166 |
|
||||
| test.c:170:8:170:9 | ! ... | test.c:170:8:170:9 | ! ... | != | 0 | 170 | 172 |
|
||||
| test.c:170:9:170:9 | s | test.c:170:9:170:9 | s | == | 0 | 170 | 172 |
|
||||
| test.cpp:18:8:18:10 | call to get | test.cpp:18:8:18:10 | call to get | != | 0 | 19 | 19 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
|
||||
|
||||
@@ -75,54 +75,4 @@ void bg_indirect_expr() {
|
||||
if (guarded(buf)) {
|
||||
sink(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void test_guard_and_reassign() {
|
||||
int x = source();
|
||||
|
||||
if(!guarded(x)) {
|
||||
x = 0;
|
||||
}
|
||||
sink(x); // $ SPURIOUS: ast,ir
|
||||
}
|
||||
|
||||
void test_phi_read_guard(bool b) {
|
||||
int x = source();
|
||||
|
||||
if(b) {
|
||||
if(!guarded(x))
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if(!guarded(x))
|
||||
return;
|
||||
}
|
||||
|
||||
sink(x); // $ SPURIOUS: ast,ir
|
||||
}
|
||||
|
||||
bool unsafe(int);
|
||||
|
||||
void test_guard_and_reassign_2() {
|
||||
int x = source();
|
||||
|
||||
if(unsafe(x)) {
|
||||
x = 0;
|
||||
}
|
||||
sink(x); // $ SPURIOUS: ast
|
||||
}
|
||||
|
||||
void test_phi_read_guard_2(bool b) {
|
||||
int x = source();
|
||||
|
||||
if(b) {
|
||||
if(unsafe(x))
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if(unsafe(x))
|
||||
return;
|
||||
}
|
||||
|
||||
sink(x); // $ SPURIOUS: ast
|
||||
}
|
||||
@@ -11,10 +11,6 @@ module AstTest {
|
||||
g.(FunctionCall).getTarget().getName() = "guarded" and
|
||||
checked = g.(FunctionCall).getArgument(0) and
|
||||
isTrue = true
|
||||
or
|
||||
g.(FunctionCall).getTarget().getName() = "unsafe" and
|
||||
checked = g.(FunctionCall).getArgument(0) and
|
||||
isTrue = false
|
||||
}
|
||||
|
||||
/** Common data flow configuration to be used by tests. */
|
||||
@@ -109,13 +105,9 @@ module IRTest {
|
||||
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean isTrue) {
|
||||
exists(Call call |
|
||||
call = g.getUnconvertedResultExpression() and
|
||||
checked = call.getArgument(0)
|
||||
|
|
||||
call.getTarget().hasName("guarded") and
|
||||
checked = call.getArgument(0) and
|
||||
isTrue = true
|
||||
or
|
||||
call.getTarget().hasName("unsafe") and
|
||||
isTrue = false
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -52,9 +52,3 @@ void following_pointers( // $ ast-def=sourceStruct1_ptr ir-def=*cleanArray1 ir-d
|
||||
sink(stackArray); // $ ast,ir
|
||||
indirect_sink(stackArray); // $ ast ir=50:25 ir=50:35 ir=51:19
|
||||
}
|
||||
|
||||
void test_bitcast() {
|
||||
unsigned long x = source();
|
||||
double d = __builtin_bit_cast(double, x);
|
||||
sink(d); // $ ir MISSING: ast
|
||||
}
|
||||
@@ -69,61 +69,45 @@
|
||||
| test.cpp:8:8:8:9 | t1 | test.cpp:9:8:9:9 | t1 |
|
||||
| test.cpp:9:8:9:9 | t1 | test.cpp:11:7:11:8 | t1 |
|
||||
| test.cpp:9:8:9:9 | t1 | test.cpp:11:7:11:8 | t1 |
|
||||
| test.cpp:10:8:10:9 | t2 | test.cpp:11:7:11:8 | Phi input |
|
||||
| test.cpp:10:8:10:9 | t2 | test.cpp:11:7:11:8 | Phi input |
|
||||
| test.cpp:10:8:10:9 | t2 | test.cpp:13:10:13:11 | t2 |
|
||||
| test.cpp:11:7:11:8 | Phi input | test.cpp:15:3:15:6 | SSA phi read(t2) |
|
||||
| test.cpp:11:7:11:8 | Phi input | test.cpp:15:3:15:6 | SSA phi(*t2) |
|
||||
| test.cpp:10:8:10:9 | t2 | test.cpp:15:3:15:6 | Phi |
|
||||
| test.cpp:10:8:10:9 | t2 | test.cpp:15:3:15:6 | Phi |
|
||||
| test.cpp:11:7:11:8 | t1 | test.cpp:21:8:21:9 | t1 |
|
||||
| test.cpp:12:5:12:10 | ... = ... | test.cpp:13:10:13:11 | t2 |
|
||||
| test.cpp:12:10:12:10 | 0 | test.cpp:12:5:12:10 | ... = ... |
|
||||
| test.cpp:13:5:13:8 | Phi input | test.cpp:15:3:15:6 | SSA phi read(t2) |
|
||||
| test.cpp:13:5:13:8 | Phi input | test.cpp:15:3:15:6 | SSA phi(*t2) |
|
||||
| test.cpp:13:10:13:11 | t2 | test.cpp:13:5:13:8 | Phi input |
|
||||
| test.cpp:13:10:13:11 | t2 | test.cpp:13:5:13:8 | Phi input |
|
||||
| test.cpp:15:3:15:6 | SSA phi read(t2) | test.cpp:15:8:15:9 | t2 |
|
||||
| test.cpp:15:3:15:6 | SSA phi(*t2) | test.cpp:15:8:15:9 | t2 |
|
||||
| test.cpp:15:8:15:9 | t2 | test.cpp:23:15:23:16 | Phi input |
|
||||
| test.cpp:15:8:15:9 | t2 | test.cpp:23:15:23:16 | Phi input |
|
||||
| test.cpp:13:10:13:11 | t2 | test.cpp:15:3:15:6 | Phi |
|
||||
| test.cpp:13:10:13:11 | t2 | test.cpp:15:3:15:6 | Phi |
|
||||
| test.cpp:15:3:15:6 | Phi | test.cpp:15:8:15:9 | t2 |
|
||||
| test.cpp:15:3:15:6 | Phi | test.cpp:15:8:15:9 | t2 |
|
||||
| test.cpp:15:8:15:9 | t2 | test.cpp:23:19:23:19 | Phi |
|
||||
| test.cpp:15:8:15:9 | t2 | test.cpp:23:19:23:19 | Phi |
|
||||
| test.cpp:17:3:17:8 | ... = ... | test.cpp:21:8:21:9 | t1 |
|
||||
| test.cpp:17:8:17:8 | 0 | test.cpp:17:3:17:8 | ... = ... |
|
||||
| test.cpp:21:8:21:9 | t1 | test.cpp:23:15:23:16 | Phi input |
|
||||
| test.cpp:21:8:21:9 | t1 | test.cpp:23:15:23:16 | Phi input |
|
||||
| test.cpp:21:8:21:9 | t1 | test.cpp:23:19:23:19 | Phi |
|
||||
| test.cpp:21:8:21:9 | t1 | test.cpp:23:19:23:19 | Phi |
|
||||
| test.cpp:23:15:23:16 | 0 | test.cpp:23:15:23:16 | 0 |
|
||||
| test.cpp:23:15:23:16 | 0 | test.cpp:23:15:23:16 | Phi input |
|
||||
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi read(*t2) |
|
||||
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi read(i) |
|
||||
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi read(t1) |
|
||||
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi read(t2) |
|
||||
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi(*i) |
|
||||
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi(*t1) |
|
||||
| test.cpp:23:19:23:19 | SSA phi read(*t2) | test.cpp:24:10:24:11 | t2 |
|
||||
| test.cpp:23:19:23:19 | SSA phi read(i) | test.cpp:23:19:23:19 | i |
|
||||
| test.cpp:23:19:23:19 | SSA phi read(t1) | test.cpp:23:23:23:24 | t1 |
|
||||
| test.cpp:23:19:23:19 | SSA phi read(t2) | test.cpp:24:10:24:11 | t2 |
|
||||
| test.cpp:23:19:23:19 | SSA phi(*i) | test.cpp:23:19:23:19 | i |
|
||||
| test.cpp:23:19:23:19 | SSA phi(*t1) | test.cpp:23:23:23:24 | t1 |
|
||||
| test.cpp:23:15:23:16 | 0 | test.cpp:23:19:23:19 | Phi |
|
||||
| test.cpp:23:19:23:19 | Phi | test.cpp:23:19:23:19 | i |
|
||||
| test.cpp:23:19:23:19 | Phi | test.cpp:23:19:23:19 | i |
|
||||
| test.cpp:23:19:23:19 | Phi | test.cpp:23:23:23:24 | t1 |
|
||||
| test.cpp:23:19:23:19 | Phi | test.cpp:23:23:23:24 | t1 |
|
||||
| test.cpp:23:19:23:19 | Phi | test.cpp:24:10:24:11 | t2 |
|
||||
| test.cpp:23:19:23:19 | Phi | test.cpp:24:10:24:11 | t2 |
|
||||
| test.cpp:23:19:23:19 | i | test.cpp:23:27:23:27 | i |
|
||||
| test.cpp:23:19:23:19 | i | test.cpp:23:27:23:27 | i |
|
||||
| test.cpp:23:23:23:24 | t1 | test.cpp:23:27:23:29 | Phi input |
|
||||
| test.cpp:23:23:23:24 | t1 | test.cpp:23:19:23:19 | Phi |
|
||||
| test.cpp:23:23:23:24 | t1 | test.cpp:26:8:26:9 | t1 |
|
||||
| test.cpp:23:23:23:24 | t1 | test.cpp:26:8:26:9 | t1 |
|
||||
| test.cpp:23:27:23:27 | *i | test.cpp:23:27:23:27 | *i |
|
||||
| test.cpp:23:27:23:27 | *i | test.cpp:23:27:23:27 | i |
|
||||
| test.cpp:23:27:23:27 | i | test.cpp:23:19:23:19 | Phi |
|
||||
| test.cpp:23:27:23:27 | i | test.cpp:23:27:23:27 | i |
|
||||
| test.cpp:23:27:23:27 | i | test.cpp:23:27:23:27 | i |
|
||||
| test.cpp:23:27:23:27 | i | test.cpp:23:27:23:29 | Phi input |
|
||||
| test.cpp:23:27:23:29 | ... ++ | test.cpp:23:19:23:19 | Phi |
|
||||
| test.cpp:23:27:23:29 | ... ++ | test.cpp:23:27:23:29 | ... ++ |
|
||||
| test.cpp:23:27:23:29 | ... ++ | test.cpp:23:27:23:29 | Phi input |
|
||||
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi read(*t2) |
|
||||
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi read(i) |
|
||||
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi read(t1) |
|
||||
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi read(t2) |
|
||||
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi(*i) |
|
||||
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi(*t1) |
|
||||
| test.cpp:24:5:24:11 | ... = ... | test.cpp:23:27:23:29 | Phi input |
|
||||
| test.cpp:24:10:24:11 | t2 | test.cpp:23:27:23:29 | Phi input |
|
||||
| test.cpp:24:10:24:11 | t2 | test.cpp:23:27:23:29 | Phi input |
|
||||
| test.cpp:24:5:24:11 | ... = ... | test.cpp:23:19:23:19 | Phi |
|
||||
| test.cpp:24:10:24:11 | t2 | test.cpp:23:19:23:19 | Phi |
|
||||
| test.cpp:24:10:24:11 | t2 | test.cpp:23:19:23:19 | Phi |
|
||||
| test.cpp:24:10:24:11 | t2 | test.cpp:24:5:24:11 | ... = ... |
|
||||
| test.cpp:382:48:382:54 | source1 | test.cpp:384:16:384:23 | *& ... |
|
||||
| test.cpp:383:12:383:13 | 0 | test.cpp:383:12:383:13 | 0 |
|
||||
|
||||
@@ -12,10 +12,6 @@ astFlow
|
||||
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:62:14:62:14 | x |
|
||||
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:64:14:64:14 | x |
|
||||
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:66:14:66:14 | x |
|
||||
| BarrierGuard.cpp:81:11:81:16 | call to source | BarrierGuard.cpp:86:8:86:8 | x |
|
||||
| BarrierGuard.cpp:90:11:90:16 | call to source | BarrierGuard.cpp:101:8:101:8 | x |
|
||||
| BarrierGuard.cpp:107:11:107:16 | call to source | BarrierGuard.cpp:112:8:112:8 | x |
|
||||
| BarrierGuard.cpp:116:11:116:16 | call to source | BarrierGuard.cpp:127:8:127:8 | x |
|
||||
| acrossLinkTargets.cpp:19:27:19:32 | call to source | acrossLinkTargets.cpp:12:8:12:8 | x |
|
||||
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:18:8:18:19 | sourceArray1 |
|
||||
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:22:8:22:20 | & ... |
|
||||
@@ -145,8 +141,6 @@ irFlow
|
||||
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:55:13:55:13 | x |
|
||||
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:64:14:64:14 | x |
|
||||
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:66:14:66:14 | x |
|
||||
| BarrierGuard.cpp:81:11:81:16 | call to source | BarrierGuard.cpp:86:8:86:8 | x |
|
||||
| BarrierGuard.cpp:90:11:90:16 | call to source | BarrierGuard.cpp:101:8:101:8 | x |
|
||||
| acrossLinkTargets.cpp:19:27:19:32 | call to source | acrossLinkTargets.cpp:12:8:12:8 | x |
|
||||
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:18:8:18:19 | sourceArray1 |
|
||||
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:23:17:23:29 | *& ... |
|
||||
@@ -159,7 +153,6 @@ irFlow
|
||||
| clang.cpp:50:25:50:30 | call to source | clang.cpp:53:17:53:26 | *stackArray |
|
||||
| clang.cpp:50:35:50:40 | call to source | clang.cpp:53:17:53:26 | *stackArray |
|
||||
| clang.cpp:51:19:51:24 | call to source | clang.cpp:53:17:53:26 | *stackArray |
|
||||
| clang.cpp:57:21:57:28 | call to source | clang.cpp:59:8:59:8 | d |
|
||||
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:35:16:35:25 | call to notSource1 |
|
||||
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:43:15:43:24 | call to notSource1 |
|
||||
| dispatch.cpp:10:37:10:42 | call to source | dispatch.cpp:36:16:36:25 | call to notSource2 |
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
|
||||
// --- stub library headers ---
|
||||
|
||||
namespace std {
|
||||
typedef unsigned long size_t;
|
||||
#define SIZE_MAX 0xFFFFFFFF
|
||||
|
||||
template <class T> class allocator {
|
||||
};
|
||||
|
||||
template<class charT> struct char_traits {
|
||||
};
|
||||
|
||||
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
|
||||
class basic_string {
|
||||
public:
|
||||
basic_string(const charT* s, const Allocator& a = Allocator());
|
||||
};
|
||||
|
||||
typedef basic_string<char> string;
|
||||
};
|
||||
|
||||
namespace boost {
|
||||
namespace system {
|
||||
class error_code {
|
||||
public:
|
||||
operator bool() const;
|
||||
};
|
||||
};
|
||||
|
||||
namespace asio {
|
||||
template<typename Protocol/*, typename Executor*/>
|
||||
class basic_stream_socket /*: public basic_socket<Protocol, Executor>*/ {
|
||||
};
|
||||
|
||||
namespace ip {
|
||||
class tcp {
|
||||
public:
|
||||
typedef basic_stream_socket<tcp> socket;
|
||||
};
|
||||
};
|
||||
|
||||
template<typename Allocator = std::allocator<char>> class basic_streambuf {
|
||||
public:
|
||||
basic_streambuf(
|
||||
std::size_t maximum_size = SIZE_MAX,
|
||||
const Allocator &allocator = Allocator());
|
||||
};
|
||||
|
||||
typedef basic_streambuf<> streambuf;
|
||||
|
||||
class mutable_buffer {
|
||||
};
|
||||
|
||||
template<typename Elem, typename Traits, typename Allocator>
|
||||
mutable_buffer buffer(std::basic_string<Elem, Traits, Allocator> & data);
|
||||
|
||||
template<typename SyncReadStream, typename Allocator> std::size_t read_until(
|
||||
SyncReadStream &s,
|
||||
asio::basic_streambuf<Allocator> &b,
|
||||
char delim,
|
||||
boost::system::error_code &ec);
|
||||
|
||||
template<typename SyncWriteStream, typename ConstBufferSequence> std::size_t write(
|
||||
SyncWriteStream &s,
|
||||
const ConstBufferSequence &buffers,
|
||||
boost::system::error_code &ec,
|
||||
int constraint = 0); // simplified
|
||||
};
|
||||
};
|
||||
|
||||
// --- test code ---
|
||||
|
||||
char *source();
|
||||
void sink(char *);
|
||||
void sink(std::string);
|
||||
void sink(boost::asio::streambuf);
|
||||
void sink(boost::asio::mutable_buffer);
|
||||
|
||||
char *getenv(const char *name);
|
||||
int send(int, const void*, int, int);
|
||||
|
||||
void test(boost::asio::ip::tcp::socket &socket) {
|
||||
boost::asio::streambuf recv_buffer;
|
||||
boost::system::error_code error;
|
||||
|
||||
boost::asio::read_until(socket, recv_buffer, '\0', error);
|
||||
if (error) {
|
||||
// ...
|
||||
}
|
||||
sink(recv_buffer); // $ ir
|
||||
|
||||
boost::asio::write(socket, recv_buffer, error); // $ ir
|
||||
|
||||
// ---
|
||||
|
||||
std::string send_str = std::string(source());
|
||||
sink(send_str); // $ ir
|
||||
|
||||
boost::asio::mutable_buffer send_buffer = boost::asio::buffer(send_str);
|
||||
sink(send_buffer); // $ ir
|
||||
|
||||
boost::asio::write(socket, send_buffer, error); // $ ir
|
||||
if (error) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
testFailures
|
||||
failures
|
||||
@@ -1,16 +0,0 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sourceModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
|
||||
- ["", "", False, "ymlSource", "", "", "ReturnValue", "local", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sinkModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, kind, provenance
|
||||
- ["", "", False, "ymlSink", "", "", "Argument[0]", "test-sink", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
|
||||
- ["", "", False, "ymlStep", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user