Compare commits

..

1 Commits

Author SHA1 Message Date
Asger F
0751ef5c72 JS: Use HTTP responses as taint sources 2024-06-13 09:33:06 +02:00
1203 changed files with 16360 additions and 29586 deletions

View File

@@ -10,16 +10,15 @@ common --override_module=semmle_code=%workspace%/misc/bazel/semmle_code_stub
build --repo_env=CC=clang --repo_env=CXX=clang++ 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 build:linux --cxxopt=-std=c++20
test --build_tests_only # we currently cannot built the swift extractor for ARM
build:macos --cxxopt=-std=c++20 --copt=-arch --copt=x86_64 --linkopt=-arch --linkopt=x86_64
build:windows --cxxopt=/std:c++20 --cxxopt=/Zc:preprocessor
# this requires developer mode, but is required to have pack installer functioning # this requires developer mode, but is required to have pack installer functioning
startup --windows_enable_symlinks startup --windows_enable_symlinks
common --enable_runfiles 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=file:///%workspace%/misc/bazel/registry
common --registry=https://bcr.bazel.build common --registry=https://bcr.bazel.build

37
.gitattributes vendored
View File

@@ -50,40 +50,33 @@
*.dll -text *.dll -text
*.pdb -text *.pdb -text
/java/ql/test/stubs/**/*.java linguist-generated=true java/ql/test/stubs/**/*.java linguist-generated=true
/java/ql/test/experimental/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
# Force git not to modify line endings for go or html files under the go/ql directory # Force git not to modify line endings for go or html files under the go/ql directory
/go/ql/**/*.go -text go/ql/**/*.go -text
/go/ql/**/*.html -text go/ql/**/*.html -text
# Force git not to modify line endings for go dbschemes # Force git not to modify line endings for go dbschemes
/go/*.dbscheme -text go/*.dbscheme -text
# Preserve unusual line ending from codeql-go merge # 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 # For some languages, upgrade script testing references really old dbscheme
# files from legacy upgrades that have CRLF line endings. Since upgrade # files from legacy upgrades that have CRLF line endings. Since upgrade
# resolution relies on object hashes, we must suppress line ending conversion # resolution relies on object hashes, we must suppress line ending conversion
# for those testing dbscheme files. # for those testing dbscheme files.
/*/ql/lib/upgrades/initial/*.dbscheme -text */ql/lib/upgrades/initial/*.dbscheme -text
# Auto-generated modeling for Python # 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 # auto-generated bazel lock file
/ruby/extractor/cargo-bazel-lock.json linguist-generated=true ruby/extractor/cargo-bazel-lock.json linguist-generated=true
/ruby/extractor/cargo-bazel-lock.json -merge ruby/extractor/cargo-bazel-lock.json -merge
# auto-generated files for the C# build # auto-generated files for the C# build
/csharp/paket.lock linguist-generated=true csharp/paket.lock linguist-generated=true
# needs eol=crlf, as `paket` touches this file and saves it as crlf # needs eol=crlf, as `paket` touches this file and saves it als crlf
/csharp/.paket/Paket.Restore.targets linguist-generated=true eol=crlf csharp/.paket/Paket.Restore.targets linguist-generated=true eol=crlf
/csharp/paket.main.bzl linguist-generated=true csharp/paket.main.bzl linguist-generated=true
/csharp/paket.main_extension.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

View File

@@ -65,7 +65,7 @@ jobs:
key: csharp-qltest-${{ matrix.slice }} key: csharp-qltest-${{ matrix.slice }}
- name: Run QL tests - name: Run QL tests
run: | 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: env:
GITHUB_TOKEN: ${{ github.token }} GITHUB_TOKEN: ${{ github.token }}
unit-tests: unit-tests:
@@ -101,6 +101,6 @@ jobs:
# Update existing stubs in the repo with the freshly generated ones # Update existing stubs in the repo with the freshly generated ones
mv "$STUBS_PATH/output/stubs/_frameworks" ql/test/resources/stubs/ mv "$STUBS_PATH/output/stubs/_frameworks" ql/test/resources/stubs/
git status 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: env:
GITHUB_TOKEN: ${{ github.token }} GITHUB_TOKEN: ${{ github.token }}

View File

@@ -7,9 +7,6 @@ on:
- .github/workflows/go-tests-other-os.yml - .github/workflows/go-tests-other-os.yml
- .github/actions/** - .github/actions/**
- codeql-workspace.yml - codeql-workspace.yml
- MODULE.bazel
- .bazelrc
- misc/bazel/**
permissions: permissions:
contents: read contents: read

View File

@@ -15,9 +15,6 @@ on:
- .github/workflows/go-tests.yml - .github/workflows/go-tests.yml
- .github/actions/** - .github/actions/**
- codeql-workspace.yml - codeql-workspace.yml
- MODULE.bazel
- .bazelrc
- misc/bazel/**
permissions: permissions:
contents: read contents: read

View File

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

View File

@@ -49,20 +49,20 @@ jobs:
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }} key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
- name: Release build - name: Release build
if: steps.cache-extractor.outputs.cache-hit != 'true' 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: env:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
- name: Cache compilation cache - name: Cache compilation cache
id: query-cache id: query-cache
uses: ./.github/actions/cache-query-compilation uses: ./.github/actions/cache-query-compilation
with: with:
key: run-ql-for-ql key: run-ql-for-ql
- name: Make database and analyze - name: Make database and analyze
run: | run: |
./ql/target/release/buramu | tee deprecated.blame # Add a blame file for the extractor to parse. ./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 }}" ${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 }} CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
DB: ${{ runner.temp }}/DB DB: ${{ runner.temp }}/DB
LGTM_INDEX_FILTERS: | LGTM_INDEX_FILTERS: |

View File

@@ -53,8 +53,8 @@ jobs:
- name: Create database - name: Create database
run: | run: |
"${CODEQL}" database create \ "${CODEQL}" database create \
--search-path "${{ github.workspace }}" --search-path "ql/extractor-pack" \
--threads 4 \ --threads 4 \
--language ql --source-root "${{ github.workspace }}/repo" \ --language ql --source-root "${{ github.workspace }}/repo" \
"${{ runner.temp }}/database" "${{ runner.temp }}/database"
env: env:

View File

@@ -49,15 +49,15 @@ jobs:
- name: Cache compilation cache - name: Cache compilation cache
id: query-cache id: query-cache
uses: ./.github/actions/cache-query-compilation uses: ./.github/actions/cache-query-compilation
with: with:
key: ql-for-ql-tests key: ql-for-ql-tests
- name: Run QL tests - name: Run QL tests
run: | run: |
"${CODEQL}" test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}" --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: env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }} CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
other-os: other-os:
strategy: strategy:
matrix: matrix:
os: [macos-latest, windows-latest] os: [macos-latest, windows-latest]
@@ -65,7 +65,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install GNU tar - name: Install GNU tar
if: runner.os == 'macOS' if: runner.os == 'macOS'
run: | run: |
brew install gnu-tar brew install gnu-tar
@@ -100,7 +100,7 @@ jobs:
- name: Run a single QL tests - Unix - name: Run a single QL tests - Unix
if: runner.os != 'Windows' if: runner.os != 'Windows'
run: | 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: env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }} CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
- name: Run a single QL tests - Windows - name: Run a single QL tests - Windows
@@ -108,4 +108,5 @@ jobs:
shell: pwsh shell: pwsh
run: | run: |
$Env:PATH += ";$(dirname ${{ steps.find-codeql.outputs.codeql-path }})" $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

View File

@@ -44,7 +44,7 @@ jobs:
- name: Create database - name: Create database
run: | run: |
codeql database create \ codeql database create \
--search-path "${{ github.workspace }}" \ --search-path "${{ github.workspace }}/ruby/extractor-pack" \
--threads 4 \ --threads 4 \
--language ruby --source-root "${{ github.workspace }}/repo" \ --language ruby --source-root "${{ github.workspace }}/repo" \
"${{ runner.temp }}/database" "${{ runner.temp }}/database"

View File

@@ -64,10 +64,10 @@ jobs:
- name: Cache compilation cache - name: Cache compilation cache
id: query-cache id: query-cache
uses: ./.github/actions/cache-query-compilation uses: ./.github/actions/cache-query-compilation
with: with:
key: ruby-qltest key: ruby-qltest
- name: Run QL tests - name: Run QL tests
run: | 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: env:
GITHUB_TOKEN: ${{ github.token }} GITHUB_TOKEN: ${{ github.token }}

View File

@@ -68,6 +68,21 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: ./swift/actions/run-ql-tests - 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: clang-format:
if : ${{ github.event_name == 'pull_request' }} if : ${{ github.event_name == 'pull_request' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

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

@@ -62,6 +62,3 @@ node_modules/
# Temporary folders for working with generated models # Temporary folders for working with generated models
.model-temp .model-temp
# bazel-built in-tree extractor packs
/*/extractor-pack

View File

@@ -2,6 +2,4 @@
# codeql is publicly forked by many users, and we don't want any LFS file polluting their working # 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. # 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. # 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 fetchinclude = /nothing

View File

@@ -22,10 +22,8 @@ bazel_dep(name = "bazel_skylib", version = "1.5.0")
bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl") 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 = "nlohmann_json", version = "3.11.3", repo_name = "json")
bazel_dep(name = "fmt", version = "10.0.0") 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 = "gazelle", version = "0.36.0")
bazel_dep(name = "rules_dotnet", version = "0.15.1") 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) bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
@@ -66,84 +64,9 @@ node.toolchain(
) )
use_repo(node, "nodejs", "nodejs_toolchains") 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 = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
go_sdk.download(version = "1.22.2") 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( register_toolchains(
"@nodejs_toolchains//:all", "@nodejs_toolchains//:all",
) )

View File

@@ -6,16 +6,19 @@ provide:
- "*/ql/consistency-queries/qlpack.yml" - "*/ql/consistency-queries/qlpack.yml"
- "*/ql/automodel/src/qlpack.yml" - "*/ql/automodel/src/qlpack.yml"
- "*/ql/automodel/test/qlpack.yml" - "*/ql/automodel/test/qlpack.yml"
- "*/extractor-pack/codeql-extractor.yml"
- "python/extractor/qlpack.yml" - "python/extractor/qlpack.yml"
- "shared/**/qlpack.yml" - "shared/**/qlpack.yml"
- "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml" - "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml"
- "go/ql/config/legacy-support/qlpack.yml" - "go/ql/config/legacy-support/qlpack.yml"
- "go/build/codeql-extractor-go/codeql-extractor.yml"
- "csharp/ql/campaigns/Solorigate/lib/qlpack.yml" - "csharp/ql/campaigns/Solorigate/lib/qlpack.yml"
- "csharp/ql/campaigns/Solorigate/src/qlpack.yml" - "csharp/ql/campaigns/Solorigate/src/qlpack.yml"
- "csharp/ql/campaigns/Solorigate/test/qlpack.yml" - "csharp/ql/campaigns/Solorigate/test/qlpack.yml"
- "misc/legacy-support/*/qlpack.yml" - "misc/legacy-support/*/qlpack.yml"
- "misc/suite-helpers/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" - ".github/codeql/extensions/**/codeql-pack.yml"
versionPolicies: versionPolicies:

View File

@@ -28,7 +28,6 @@
"/*- Yaml dbscheme -*/", "/*- Yaml dbscheme -*/",
"/*- Blame dbscheme -*/", "/*- Blame dbscheme -*/",
"/*- JSON dbscheme -*/", "/*- JSON dbscheme -*/",
"/*- Python dbscheme -*/", "/*- Python dbscheme -*/"
"/*- Empty location -*/"
] ]
} }

View File

@@ -6,7 +6,7 @@ pkg_files(
["**"], ["**"],
exclude = ["BUILD.bazel"], exclude = ["BUILD.bazel"],
), ),
prefix = "downgrades", prefix = "cpp/downgrades",
strip_prefix = strip_prefix.from_pkg(), strip_prefix = strip_prefix.from_pkg(),
visibility = ["//cpp:__pkg__"], visibility = ["//cpp:__pkg__"],
) )

View File

@@ -5,9 +5,11 @@ package(default_visibility = ["//cpp:__pkg__"])
pkg_files( pkg_files(
name = "dbscheme", name = "dbscheme",
srcs = ["semmlecode.cpp.dbscheme"], srcs = ["semmlecode.cpp.dbscheme"],
prefix = "cpp",
) )
pkg_files( pkg_files(
name = "dbscheme-stats", name = "dbscheme-stats",
srcs = ["semmlecode.cpp.dbscheme.stats"], srcs = ["semmlecode.cpp.dbscheme.stats"],
prefix = "cpp",
) )

View File

@@ -1,23 +1,3 @@
## 1.1.1
No user-facing changes.
## 1.1.0
### New Features
* 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.
### Minor Analysis Improvements
* 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.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 ## 0.13.1
No user-facing changes. No user-facing changes.

View File

@@ -1,5 +1,4 @@
## 1.0.0 ---
category: breaking
### 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. * CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.

View File

@@ -1,9 +0,0 @@
## 1.1.0
### New Features
* 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.
### Minor Analysis Improvements
* 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`.

View File

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

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 1.1.1 lastReleaseVersion: 0.13.1

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all name: codeql/cpp-all
version: 1.1.1 version: 1.0.0-dev
groups: cpp groups: cpp
dbscheme: semmlecode.cpp.dbscheme dbscheme: semmlecode.cpp.dbscheme
extractor: cpp extractor: cpp
@@ -14,6 +14,4 @@ dependencies:
codeql/tutorial: ${workspace} codeql/tutorial: ${workspace}
codeql/util: ${workspace} codeql/util: ${workspace}
codeql/xml: ${workspace} codeql/xml: ${workspace}
dataExtensions:
- ext/*.model.yml
warnOnImplicitThis: true warnOnImplicitThis: true

View File

@@ -410,10 +410,6 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
or or
orphaned_variables(underlyingElement(this), unresolveElement(result)) orphaned_variables(underlyingElement(this), unresolveElement(result))
} }
override predicate isStatic() {
super.isStatic() or orphaned_variables(underlyingElement(this), _)
}
} }
/** /**

View File

@@ -375,33 +375,6 @@ cached
class IRGuardCondition extends Instruction { class IRGuardCondition extends Instruction {
Instruction branch; Instruction branch;
/*
* An `IRGuardCondition` supports reasoning about four different kinds of
* relations:
* 1. A unary equality relation of the form `e == k`
* 2. A binary equality relation of the form `e1 == e2 + k`
* 3. A unary inequality relation of the form `e < k`
* 4. A binary inequality relation of the form `e1 < e2 + k`
*
* where `k` is a constant.
*
* Furthermore, the unary relations (i.e., case 1 and case 3) are also
* inferred from `switch` statement guards: equality relations are inferred
* from the unique `case` statement, if any, and inequality relations are
* inferred from the [case range](https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html)
* gcc extension.
*
* The implementation of all four follows the same structure: Each relation
* has a cached user-facing predicate that. For example,
* `GuardCondition::comparesEq` calls `compares_eq`. This predicate has
* several cases that recursively decompose the relation to bring it to a
* canonical form (i.e., a relation of the form `e1 == e2 + k`). The base
* case for this relation (i.e., `simple_comparison_eq`) handles
* `CompareEQInstruction`s and `CompareNEInstruction`, and recursive
* predicates (e.g., `complex_eq`) rewrites larger expressions such as
* `e1 + k1 == e2 + k2` into canonical the form `e1 == e2 + (k2 - k1)`.
*/
cached cached
IRGuardCondition() { branch = getBranchForCondition(this) } IRGuardCondition() { branch = getBranchForCondition(this) }
@@ -803,9 +776,7 @@ private predicate unary_compares_eq(
Instruction test, Operand op, int k, boolean areEqual, boolean inNonZeroCase, AbstractValue value Instruction test, Operand op, int k, boolean areEqual, boolean inNonZeroCase, AbstractValue value
) { ) {
/* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */ /* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */
exists(AbstractValue v | exists(AbstractValue v | unary_simple_comparison_eq(test, op, k, inNonZeroCase, v) |
unary_simple_comparison_eq(test, k, inNonZeroCase, v) and op.getDef() = test
|
areEqual = true and value = v areEqual = true and value = v
or or
areEqual = false and value = v.getDualValue() areEqual = false and value = v.getDualValue()
@@ -850,55 +821,45 @@ private predicate simple_comparison_eq(
value.(BooleanValue).getValue() = false 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. * Rearrange various simple comparisons into `op == k` form.
*/ */
private predicate unary_simple_comparison_eq( private predicate unary_simple_comparison_eq(
Instruction test, int k, boolean inNonZeroCase, AbstractValue value Instruction test, Operand op, int k, boolean inNonZeroCase, AbstractValue value
) { ) {
exists(SwitchInstruction switch, CaseEdge case | exists(SwitchInstruction switch, CaseEdge case |
test = switch.getExpression() and test = switch.getExpression() and
op.getDef() = test and
case = value.(MatchValue).getCase() and case = value.(MatchValue).getCase() and
exists(switch.getSuccessor(case)) and exists(switch.getSuccessor(case)) and
case.getValue().toInt() = k and case.getValue().toInt() = k and
inNonZeroCase = false inNonZeroCase = false
) )
or or
// Any instruction with an integral type could potentially be part of a // There's no implicit CompareInstruction in files compiled as C since C
// check for nullness when used in a guard. So we include all integral // doesn't have implicit boolean conversions. So instead we check whether
// typed instructions here. However, since some of these instructions are // there's a branch on a value of pointer or integer type.
// already included as guards in other cases, we exclude those here. relevantUnaryComparison(test) and
// These are instructions that compute a binary equality or inequality op.getDef() = test and
// relation. For example, the following:
// ```cpp
// if(a == b + 42) { ... }
// ```
// generates the following IR:
// ```
// r1(glval<int>) = VariableAddress[a] :
// r2(int) = Load[a] : &:r1, m1
// r3(glval<int>) = VariableAddress[b] :
// r4(int) = Load[b] : &:r3, m2
// r5(int) = Constant[42] :
// r6(int) = Add : r4, r5
// r7(bool) = CompareEQ : r2, r6
// v1(void) = ConditionalBranch : r7
// ```
// and since `r7` is an integral typed instruction this predicate could
// include a case for when `r7` evaluates to true (in which case we would
// infer that `r6` was non-zero, and a case for when `r7` evaluates to false
// (in which case we would infer that `r6` was zero).
// However, since `a == b + 42` is already supported when reasoning about
// binary equalities we exclude those cases here.
not test.isGLValue() and
not simple_comparison_eq(test, _, _, _, _) and
not simple_comparison_lt(test, _, _, _) and
not test = any(SwitchInstruction switch).getExpression() and
(
test.getResultIRType() instanceof IRAddressType or
test.getResultIRType() instanceof IRIntegerType or
test.getResultIRType() instanceof IRBooleanType
) and
( (
k = 1 and k = 1 and
value.(BooleanValue).getValue() = true and value.(BooleanValue).getValue() = true and
@@ -952,8 +913,7 @@ private predicate compares_lt(
/** Holds if `op < k` evaluates to `isLt` given that `test` evaluates to `value`. */ /** Holds if `op < k` evaluates to `isLt` given that `test` evaluates to `value`. */
private predicate compares_lt(Instruction test, Operand op, int k, boolean isLt, AbstractValue value) { private predicate compares_lt(Instruction test, Operand op, int k, boolean isLt, AbstractValue value) {
unary_simple_comparison_lt(test, k, isLt, value) and simple_comparison_lt(test, op, k, isLt, value)
op.getDef() = test
or or
complex_lt(test, op, k, isLt, value) complex_lt(test, op, k, isLt, value)
or or
@@ -1000,11 +960,12 @@ private predicate simple_comparison_lt(CompareInstruction cmp, Operand left, Ope
} }
/** Rearrange various simple comparisons into `op < k` form. */ /** Rearrange various simple comparisons into `op < k` form. */
private predicate unary_simple_comparison_lt( private predicate simple_comparison_lt(
Instruction test, int k, boolean isLt, AbstractValue value Instruction test, Operand op, int k, boolean isLt, AbstractValue value
) { ) {
exists(SwitchInstruction switch, CaseEdge case | exists(SwitchInstruction switch, CaseEdge case |
test = switch.getExpression() and test = switch.getExpression() and
op.getDef() = test and
case = value.(MatchValue).getCase() and case = value.(MatchValue).getCase() and
exists(switch.getSuccessor(case)) and exists(switch.getSuccessor(case)) and
case.getMaxValue() > case.getMinValue() case.getMaxValue() > case.getMinValue()

View File

@@ -78,7 +78,6 @@ private import internal.FlowSummaryImpl
private import internal.FlowSummaryImpl::Public private import internal.FlowSummaryImpl::Public
private import internal.FlowSummaryImpl::Private private import internal.FlowSummaryImpl::Private
private import internal.FlowSummaryImpl::Private::External private import internal.FlowSummaryImpl::Private::External
private import internal.ExternalFlowExtensions as Extensions
private import codeql.mad.ModelValidation as SharedModelVal private import codeql.mad.ModelValidation as SharedModelVal
private import codeql.util.Unit private import codeql.util.Unit
@@ -139,9 +138,6 @@ predicate sourceModel(
row.splitAt(";", 7) = kind row.splitAt(";", 7) = kind
) and ) and
provenance = "manual" provenance = "manual"
or
Extensions::sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance,
_)
} }
/** Holds if a sink model exists for the given parameters. */ /** Holds if a sink model exists for the given parameters. */
@@ -162,8 +158,6 @@ predicate sinkModel(
row.splitAt(";", 7) = kind row.splitAt(";", 7) = kind
) and ) and
provenance = "manual" provenance = "manual"
or
Extensions::sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance, _)
} }
/** Holds if a summary model exists for the given parameters. */ /** Holds if a summary model exists for the given parameters. */
@@ -185,9 +179,6 @@ predicate summaryModel(
row.splitAt(";", 8) = kind row.splitAt(";", 8) = kind
) and ) and
provenance = "manual" provenance = "manual"
or
Extensions::summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind,
provenance, _)
} }
private predicate relevantNamespace(string namespace) { 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 * Holds if CSV framework coverage of `namespace` is `n` api endpoints of the
* kind `(kind, part)`, and `namespaces` is the number of subnamespaces of * kind `(kind, part)`.
* `namespace` which have MaD framework coverage (including `namespace`
* itself).
*/ */
predicate modelCoverage(string namespace, int namespaces, string kind, string part, int n) { predicate modelCoverage(string namespace, int namespaces, string kind, string part, int n) {
namespaces = strictcount(string subns | canonicalNamespaceLink(namespace, subns)) and namespaces = strictcount(string subns | canonicalNamespaceLink(namespace, subns)) and
@@ -332,10 +321,10 @@ module CsvValidation {
or or
summaryModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "summary" 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." result = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
or or
not type.regexpMatch("[a-zA-Z0-9_<>,\\+]*") and not type.regexpMatch("[a-zA-Z0-9_<>,\\+]+") and
result = "Dubious type \"" + type + "\" in " + pred + " model." result = "Dubious type \"" + type + "\" in " + pred + " model."
or or
not name.regexpMatch("[a-zA-Z0-9_<>,]*") and not name.regexpMatch("[a-zA-Z0-9_<>,]*") and

View File

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

View File

@@ -1336,8 +1336,6 @@ predicate nodeIsHidden(Node n) {
n instanceof FinalGlobalValue n instanceof FinalGlobalValue
or or
n instanceof InitialGlobalValue n instanceof InitialGlobalValue
or
n instanceof SsaPhiInputNode
} }
predicate neverSkipInPathGraph(Node n) { predicate neverSkipInPathGraph(Node n) {
@@ -1636,8 +1634,6 @@ private Instruction getAnInstruction(Node n) {
or or
result = n.(SsaPhiNode).getPhiNode().getBasicBlock().getFirstInstruction() result = n.(SsaPhiNode).getPhiNode().getBasicBlock().getFirstInstruction()
or or
result = n.(SsaPhiInputNode).getBasicBlock().getFirstInstruction()
or
n.(IndirectInstruction).hasInstructionAndIndirectionIndex(result, _) n.(IndirectInstruction).hasInstructionAndIndirectionIndex(result, _)
or or
not n instanceof IndirectInstruction and not n instanceof IndirectInstruction and
@@ -1767,7 +1763,7 @@ module IteratorFlow {
crementCall = def.getValue().asInstruction().(StoreInstruction).getSourceValue() and crementCall = def.getValue().asInstruction().(StoreInstruction).getSourceValue() and
sv = def.getSourceVariable() and sv = def.getSourceVariable() and
bb.getInstruction(i) = crementCall and bb.getInstruction(i) = crementCall and
Ssa::ssaDefReachesReadExt(sv, result.asDef(), bb, i) Ssa::ssaDefReachesRead(sv, result.asDef(), bb, i)
) )
} }
@@ -1801,7 +1797,7 @@ module IteratorFlow {
isIteratorWrite(writeToDeref, address) and isIteratorWrite(writeToDeref, address) and
operandForFullyConvertedCall(address, starCall) and operandForFullyConvertedCall(address, starCall) and
bbStar.getInstruction(iStar) = 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 ultimate = getAnUltimateDefinition*(def) and
beginStore = ultimate.getValue().asInstruction() and beginStore = ultimate.getValue().asInstruction() and
operandForFullyConvertedCall(beginStore.getSourceValueOperand(), beginCall) operandForFullyConvertedCall(beginStore.getSourceValueOperand(), beginCall)

View File

@@ -17,7 +17,6 @@ private import SsaInternals as Ssa
private import DataFlowImplCommon as DataFlowImplCommon private import DataFlowImplCommon as DataFlowImplCommon
private import codeql.util.Unit private import codeql.util.Unit
private import Node0ToString private import Node0ToString
import ExprNodes
/** /**
* The IR dataflow graph consists of the following nodes: * The IR dataflow graph consists of the following nodes:
@@ -46,7 +45,6 @@ private newtype TIRDataFlowNode =
or or
Ssa::isModifiableByCall(operand, indirectionIndex) Ssa::isModifiableByCall(operand, indirectionIndex)
} or } or
TSsaPhiInputNode(Ssa::PhiNode phi, IRBlock input) { phi.hasInputFromBlock(_, _, _, _, input) } or
TSsaPhiNode(Ssa::PhiNode phi) or TSsaPhiNode(Ssa::PhiNode phi) or
TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) { TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
@@ -116,13 +114,6 @@ predicate conversionFlow(
instrTo.(CheckedConvertOrNullInstruction).getUnaryOperand() = opFrom instrTo.(CheckedConvertOrNullInstruction).getUnaryOperand() = opFrom
or or
instrTo.(InheritanceConversionInstruction).getUnaryOperand() = opFrom instrTo.(InheritanceConversionInstruction).getUnaryOperand() = opFrom
or
exists(BuiltInInstruction builtIn |
builtIn = instrTo and
// __builtin_bit_cast
builtIn.getBuiltInOperation() instanceof BuiltInBitCast and
opFrom = builtIn.getAnOperand()
)
) )
or or
additional = true and additional = true and
@@ -167,12 +158,6 @@ class Node extends TIRDataFlowNode {
/** Gets the operands corresponding to this node, if any. */ /** Gets the operands corresponding to this node, if any. */
Operand asOperand() { result = this.(OperandNode).getOperand() } 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`. * Holds if this node is at index `i` in basic block `block`.
* *
@@ -185,9 +170,6 @@ class Node extends TIRDataFlowNode {
or or
this.(SsaPhiNode).getPhiNode().getBasicBlock() = block and i = -1 this.(SsaPhiNode).getPhiNode().getBasicBlock() = block and i = -1
or or
this.(SsaPhiInputNode).getBlock() = block and
i = block.getInstructionCount()
or
this.(RawIndirectOperand).getOperand().getUse() = block.getInstruction(i) this.(RawIndirectOperand).getOperand().getUse() = block.getInstruction(i)
or or
this.(RawIndirectInstruction).getInstruction() = block.getInstruction(i) this.(RawIndirectInstruction).getInstruction() = block.getInstruction(i)
@@ -640,7 +622,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() } 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. * Gets a node that is used as input to this phi node.
@@ -649,7 +631,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
*/ */
cached cached
final Node getAnInput(boolean fromBackEdge) { final Node getAnInput(boolean fromBackEdge) {
result.(SsaPhiInputNode).getPhiNode() = phi and localFlowStep(result, this) and
exists(IRBlock bPhi, IRBlock bResult | exists(IRBlock bPhi, IRBlock bResult |
bPhi = phi.getBasicBlock() and bResult = result.getBasicBlock() bPhi = phi.getBasicBlock() and bResult = result.getBasicBlock()
| |
@@ -672,58 +654,6 @@ class SsaPhiNode extends Node, TSsaPhiNode {
predicate isPhiRead() { phi.isPhiRead() } 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. * INTERNAL: do not use.
* *
@@ -1297,6 +1227,466 @@ class UninitializedNode extends Node {
LocalVariable getLocalVariable() { result = v } LocalVariable getLocalVariable() { result = v }
} }
private module GetConvertedResultExpression {
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
private Operand getAnInitializeDynamicAllocationInstructionAddress() {
result = any(InitializeDynamicAllocationInstruction init).getAllocationAddressOperand()
}
/**
* Gets the expression that should be returned as the result expression from `instr`.
*
* Note that this predicate may return multiple results in cases where a conversion belongs to a
* different AST element than its operand.
*/
Expr getConvertedResultExpression(Instruction instr, int n) {
// Only fully converted instructions have a result for `asConvertedExpr`
not conversionFlow(unique(Operand op |
// The address operand of a `InitializeDynamicAllocationInstruction` is
// special: we need to handle it during dataflow (since it's
// effectively a store to an indirection), but it doesn't appear in
// source syntax, so dataflow node <-> expression conversion shouldn't
// care about it.
op = getAUse(instr) and not op = getAnInitializeDynamicAllocationInstructionAddress()
|
op
), _, false, false) and
result = getConvertedResultExpressionImpl(instr) and
n = 0
or
// If the conversion also has a result then we return multiple results
exists(Operand operand | conversionFlow(operand, instr, false, false) |
n = 1 and
result = getConvertedResultExpressionImpl(operand.getDef())
or
result = getConvertedResultExpression(operand.getDef(), n - 1)
)
}
private Expr getConvertedResultExpressionImpl0(Instruction instr) {
// IR construction inserts an additional cast to a `size_t` on the extent
// of a `new[]` expression. The resulting `ConvertInstruction` doesn't have
// a result for `getConvertedResultExpression`. We remap this here so that
// this `ConvertInstruction` maps to the result of the expression that
// represents the extent.
exists(TranslatedNonConstantAllocationSize tas |
result = tas.getExtent().getExpr() and
instr = tas.getInstruction(AllocationExtentConvertTag())
)
or
// There's no instruction that returns `ParenthesisExpr`, but some queries
// expect this
exists(TranslatedTransparentConversion ttc |
result = ttc.getExpr().(ParenthesisExpr) and
instr = ttc.getResult()
)
or
// Certain expressions generate `CopyValueInstruction`s only when they
// are needed. Examples of this include crement operations and compound
// assignment operations. For example:
// ```cpp
// int x = ...
// int y = x++;
// ```
// this generate IR like:
// ```
// r1(glval<int>) = VariableAddress[x] :
// r2(int) = Constant[0] :
// m3(int) = Store[x] : &:r1, r2
// r4(glval<int>) = VariableAddress[y] :
// r5(glval<int>) = VariableAddress[x] :
// r6(int) = Load[x] : &:r5, m3
// r7(int) = Constant[1] :
// r8(int) = Add : r6, r7
// m9(int) = Store[x] : &:r5, r8
// r11(int) = CopyValue : r6
// m12(int) = Store[y] : &:r4, r11
// ```
// When the `CopyValueInstruction` is not generated there is no instruction
// whose `getConvertedResultExpression` maps back to the expression. When
// such an instruction doesn't exist it means that the old value is not
// needed, and in that case the only value that will propagate forward in
// the program is the value that's been updated. So in those cases we just
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
exists(TranslatedCoreExpr tco |
tco.getInstruction(_) = instr and
tco.producesExprResult() and
result = asDefinitionImpl0(instr)
)
}
private Expr getConvertedResultExpressionImpl(Instruction instr) {
result = getConvertedResultExpressionImpl0(instr)
or
not exists(getConvertedResultExpressionImpl0(instr)) and
result = instr.getConvertedResultExpression()
}
/**
* Gets the result for `node.asDefinition()` (when `node` is the instruction
* node that wraps `store`) in the cases where `store.getAst()` should not be
* used to define the result of `node.asDefinition()`.
*/
private Expr asDefinitionImpl0(StoreInstruction store) {
// For an expression such as `i += 2` we pretend that the generated
// `StoreInstruction` contains the result of the expression even though
// this isn't totally aligned with the C/C++ standard.
exists(TranslatedAssignOperation tao |
store = tao.getInstruction(AssignmentStoreTag()) and
result = tao.getExpr()
)
or
// Similarly for `i++` and `++i` we pretend that the generated
// `StoreInstruction` is contains the result of the expression even though
// this isn't totally aligned with the C/C++ standard.
exists(TranslatedCrementOperation tco |
store = tco.getInstruction(CrementStoreTag()) and
result = tco.getExpr()
)
}
/**
* Holds if the expression returned by `store.getAst()` should not be
* returned as the result of `node.asDefinition()` when `node` is the
* instruction node that wraps `store`.
*/
private predicate excludeAsDefinitionResult(StoreInstruction store) {
// Exclude the store to the temporary generated by a ternary expression.
exists(TranslatedConditionalExpr tce |
store = tce.getInstruction(ConditionValueFalseStoreTag())
or
store = tce.getInstruction(ConditionValueTrueStoreTag())
)
}
/**
* Gets the expression that represents the result of `StoreInstruction` for
* dataflow purposes.
*
* For example, consider the following example
* ```cpp
* int x = 42; // 1
* x = 34; // 2
* ++x; // 3
* x++; // 4
* x += 1; // 5
* int y = x += 2; // 6
* ```
* For (1) the result is `42`.
* For (2) the result is `x = 34`.
* For (3) the result is `++x`.
* For (4) the result is `x++`.
* For (5) the result is `x += 1`.
* For (6) there are two results:
* - For the `StoreInstruction` generated by `x += 2` the result
* is `x += 2`
* - For the `StoreInstruction` generated by `int y = ...` the result
* is also `x += 2`
*/
Expr asDefinitionImpl(StoreInstruction store) {
not exists(asDefinitionImpl0(store)) and
not excludeAsDefinitionResult(store) and
result = store.getAst().(Expr).getUnconverted()
or
result = asDefinitionImpl0(store)
}
}
private import GetConvertedResultExpression
/** Holds if `node` is an `OperandNode` that should map `node.asExpr()` to `e`. */
predicate exprNodeShouldBeOperand(OperandNode node, Expr e, int n) {
not exprNodeShouldBeIndirectOperand(_, e, n) and
exists(Instruction def |
unique( | | getAUse(def)) = node.getOperand() and
e = getConvertedResultExpression(def, n)
)
}
/** Holds if `node` should be an `IndirectOperand` that maps `node.asIndirectExpr()` to `e`. */
private predicate indirectExprNodeShouldBeIndirectOperand(
IndirectOperand node, Expr e, int n, int indirectionIndex
) {
exists(Instruction def |
node.hasOperandAndIndirectionIndex(unique( | | getAUse(def)), indirectionIndex) and
e = getConvertedResultExpression(def, n)
)
}
/** Holds if `node` should be an `IndirectOperand` that maps `node.asExpr()` to `e`. */
private predicate exprNodeShouldBeIndirectOperand(IndirectOperand node, Expr e, int n) {
exists(ArgumentOperand operand |
// When an argument (qualifier or positional) is a prvalue and the
// parameter (qualifier or positional) is a (const) reference, IR
// construction introduces a temporary `IRVariable`. The `VariableAddress`
// instruction has the argument as its `getConvertedResultExpression`
// result. However, the instruction actually represents the _address_ of
// the argument. So to fix this mismatch, we have the indirection of the
// `VariableAddressInstruction` map to the expression.
node.hasOperandAndIndirectionIndex(operand, 1) and
e = getConvertedResultExpression(operand.getDef(), n) and
operand.getDef().(VariableAddressInstruction).getIRVariable() instanceof IRTempVariable
)
}
private predicate exprNodeShouldBeIndirectOutNode(IndirectArgumentOutNode node, Expr e, int n) {
exists(CallInstruction call |
call.getStaticCallTarget() instanceof Constructor and
e = getConvertedResultExpression(call, n) and
call.getThisArgumentOperand() = node.getAddressOperand()
)
}
/** Holds if `node` should be an instruction node that maps `node.asExpr()` to `e`. */
predicate exprNodeShouldBeInstruction(Node node, Expr e, int n) {
not exprNodeShouldBeOperand(_, e, n) and
not exprNodeShouldBeIndirectOutNode(_, e, n) and
not exprNodeShouldBeIndirectOperand(_, e, n) and
e = getConvertedResultExpression(node.asInstruction(), n)
}
/** Holds if `node` should be an `IndirectInstruction` that maps `node.asIndirectExpr()` to `e`. */
predicate indirectExprNodeShouldBeIndirectInstruction(
IndirectInstruction node, Expr e, int n, int indirectionIndex
) {
not indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) and
exists(Instruction instr |
node.hasInstructionAndIndirectionIndex(instr, indirectionIndex) and
e = getConvertedResultExpression(instr, n)
)
}
abstract private class ExprNodeBase extends Node {
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
abstract Expr getConvertedExpr(int n);
/** Gets the non-conversion expression corresponding to this node, if any. */
final Expr getExpr(int n) { result = this.getConvertedExpr(n).getUnconverted() }
}
/**
* Holds if there exists a dataflow node whose `asExpr(n)` should evaluate
* to `e`.
*/
private predicate exprNodeShouldBe(Expr e, int n) {
exprNodeShouldBeInstruction(_, e, n) or
exprNodeShouldBeOperand(_, e, n) or
exprNodeShouldBeIndirectOutNode(_, e, n) or
exprNodeShouldBeIndirectOperand(_, e, n)
}
private class InstructionExprNode extends ExprNodeBase, InstructionNode {
InstructionExprNode() {
exists(Expr e, int n |
exprNodeShouldBeInstruction(this, e, n) and
not exists(Expr conv |
exprNodeShouldBe(conv, n + 1) and
conv.getUnconverted() = e.getUnconverted()
)
)
}
final override Expr getConvertedExpr(int n) { exprNodeShouldBeInstruction(this, result, n) }
}
private class OperandExprNode extends ExprNodeBase, OperandNode {
OperandExprNode() {
exists(Expr e, int n |
exprNodeShouldBeOperand(this, e, n) and
not exists(Expr conv |
exprNodeShouldBe(conv, n + 1) and
conv.getUnconverted() = e.getUnconverted()
)
)
}
final override Expr getConvertedExpr(int n) { exprNodeShouldBeOperand(this, result, n) }
}
abstract private class IndirectExprNodeBase extends Node {
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
abstract Expr getConvertedExpr(int n, int indirectionIndex);
/** Gets the non-conversion expression corresponding to this node, if any. */
final Expr getExpr(int n, int indirectionIndex) {
result = this.getConvertedExpr(n, indirectionIndex).getUnconverted()
}
}
/** A signature for converting an indirect node to an expression. */
private signature module IndirectNodeToIndirectExprSig {
/** The indirect node class to be converted to an expression */
class IndirectNode;
/**
* Holds if the indirect expression at indirection index `indirectionIndex`
* of `node` is `e`. The integer `n` specifies how many conversions has been
* applied to `node`.
*/
predicate indirectNodeHasIndirectExpr(IndirectNode node, Expr e, int n, int indirectionIndex);
}
/**
* A module that implements the logic for deciding whether an indirect node
* should be an `IndirectExprNode`.
*/
private module IndirectNodeToIndirectExpr<IndirectNodeToIndirectExprSig Sig> {
import Sig
/**
* This predicate shifts the indirection index by one when `conv` is a
* `ReferenceDereferenceExpr`.
*
* This is necessary because `ReferenceDereferenceExpr` is a conversion
* in the AST, but appears as a `LoadInstruction` in the IR.
*/
bindingset[e, indirectionIndex]
private predicate adjustForReference(
Expr e, int indirectionIndex, Expr conv, int adjustedIndirectionIndex
) {
conv.(ReferenceDereferenceExpr).getExpr() = e and
adjustedIndirectionIndex = indirectionIndex - 1
or
not conv instanceof ReferenceDereferenceExpr and
conv = e and
adjustedIndirectionIndex = indirectionIndex
}
/** Holds if `node` should be an `IndirectExprNode`. */
predicate charpred(IndirectNode node) {
exists(Expr e, int n, int indirectionIndex |
indirectNodeHasIndirectExpr(node, e, n, indirectionIndex) and
not exists(Expr conv, int adjustedIndirectionIndex |
adjustForReference(e, indirectionIndex, conv, adjustedIndirectionIndex) and
indirectExprNodeShouldBe(conv, n + 1, adjustedIndirectionIndex)
)
)
}
}
private predicate indirectExprNodeShouldBe(Expr e, int n, int indirectionIndex) {
indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) or
indirectExprNodeShouldBeIndirectInstruction(_, e, n, indirectionIndex)
}
private module IndirectOperandIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
class IndirectNode = IndirectOperand;
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectOperand/4;
}
module IndirectOperandToIndirectExpr =
IndirectNodeToIndirectExpr<IndirectOperandIndirectExprNodeImpl>;
private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
{
IndirectOperandIndirectExprNode() { IndirectOperandToIndirectExpr::charpred(this) }
final override Expr getConvertedExpr(int n, int index) {
IndirectOperandToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
}
}
private module IndirectInstructionIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
class IndirectNode = IndirectInstruction;
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectInstruction/4;
}
module IndirectInstructionToIndirectExpr =
IndirectNodeToIndirectExpr<IndirectInstructionIndirectExprNodeImpl>;
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction
{
IndirectInstructionIndirectExprNode() { IndirectInstructionToIndirectExpr::charpred(this) }
final override Expr getConvertedExpr(int n, int index) {
IndirectInstructionToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
}
}
private class IndirectArgumentOutExprNode extends ExprNodeBase, IndirectArgumentOutNode {
IndirectArgumentOutExprNode() { exprNodeShouldBeIndirectOutNode(this, _, _) }
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOutNode(this, result, n) }
}
private class IndirectOperandExprNode extends ExprNodeBase instanceof IndirectOperand {
IndirectOperandExprNode() { exprNodeShouldBeIndirectOperand(this, _, _) }
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOperand(this, result, n) }
}
/**
* An expression, viewed as a node in a data flow graph.
*/
class ExprNode extends Node instanceof ExprNodeBase {
/**
* INTERNAL: Do not use.
*/
Expr getExpr(int n) { result = super.getExpr(n) }
/**
* Gets the non-conversion expression corresponding to this node, if any. If
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
* expression.
*/
final Expr getExpr() { result = this.getExpr(_) }
/**
* INTERNAL: Do not use.
*/
Expr getConvertedExpr(int n) { result = super.getConvertedExpr(n) }
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
final Expr getConvertedExpr() { result = this.getConvertedExpr(_) }
}
/**
* An indirect expression, viewed as a node in a data flow graph.
*/
class IndirectExprNode extends Node instanceof IndirectExprNodeBase {
/**
* Gets the non-conversion expression corresponding to this node, if any. If
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
* expression.
*/
final Expr getExpr(int indirectionIndex) { result = this.getExpr(_, indirectionIndex) }
/**
* INTERNAL: Do not use.
*/
Expr getExpr(int n, int indirectionIndex) { result = super.getExpr(n, indirectionIndex) }
/**
* INTERNAL: Do not use.
*/
Expr getConvertedExpr(int n, int indirectionIndex) {
result = super.getConvertedExpr(n, indirectionIndex)
}
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
Expr getConvertedExpr(int indirectionIndex) {
result = this.getConvertedExpr(_, indirectionIndex)
}
}
abstract private class AbstractParameterNode extends Node { abstract private class AbstractParameterNode extends Node {
/** /**
* Holds if this node is the parameter of `f` at the specified position. The * Holds if this node is the parameter of `f` at the specified position. The
@@ -1786,9 +2176,6 @@ private module Cached {
// Def-use/Use-use flow // Def-use/Use-use flow
Ssa::ssaFlow(nodeFrom, nodeTo) Ssa::ssaFlow(nodeFrom, nodeTo)
or or
// Phi input -> Phi
nodeFrom.(SsaPhiInputNode).getPhiNode() = nodeTo.(SsaPhiNode).getPhiNode()
or
IteratorFlow::localFlowStep(nodeFrom, nodeTo) IteratorFlow::localFlowStep(nodeFrom, nodeTo)
or or
// Operand -> Instruction flow // Operand -> Instruction flow
@@ -2227,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`. * Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
* *
@@ -2291,21 +2662,13 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
* *
* NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead. * NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead.
*/ */
Node getABarrierNode() { ExprNode getABarrierNode() {
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge | exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
e = value.getAnInstruction().getConvertedResultExpression() and e = value.getAnInstruction().getConvertedResultExpression() and
result.asConvertedExpr() = e and result.getConvertedExpr() = e and
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
g.controls(result.getBasicBlock(), edge) 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)
)
} }
/** /**
@@ -2341,7 +2704,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
* *
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead. * 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 * Gets an indirect expression node with indirection index `indirectionIndex` that is
@@ -2377,23 +2740,13 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
* *
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead. * 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 | exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
e = value.getAnInstruction().getConvertedResultExpression() and e = value.getAnInstruction().getConvertedResultExpression() and
result.asIndirectConvertedExpr(indirectionIndex) = e and result.getConvertedExpr(indirectionIndex) = e and
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
g.controls(result.getBasicBlock(), edge) 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)
)
} }
} }
@@ -2402,14 +2755,6 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
*/ */
signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction instr, boolean branch); 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. * Provides a set of barrier nodes for a guard that validates an instruction.
* *
@@ -2418,20 +2763,12 @@ private EdgeKind getConditionalEdge(boolean branch) {
*/ */
module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> { module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> {
/** Gets a node that is safely guarded by the given guard check. */ /** 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 | exists(IRGuardCondition g, ValueNumber value, boolean edge, Operand use |
instructionGuardChecks(g, value.getAnInstruction(), edge) and instructionGuardChecks(g, value.getAnInstruction(), edge) and
use = value.getAnInstruction().getAUse() and use = value.getAnInstruction().getAUse() and
result.asOperand() = use and result.asOperand() = use and
g.controls(result.getBasicBlock(), edge) g.controls(use.getDef().getBlock(), 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)
) )
} }
} }

View File

@@ -1,479 +0,0 @@
/**
* Provides the classes `ExprNode` and `IndirectExprNode` for converting between `Expr` and `Node`.
*/
private import cpp
private import semmle.code.cpp.ir.IR
private import DataFlowUtil
private import DataFlowPrivate
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
cached
private module Cached {
private Operand getAnInitializeDynamicAllocationInstructionAddress() {
result = any(InitializeDynamicAllocationInstruction init).getAllocationAddressOperand()
}
/**
* Gets the expression that should be returned as the result expression from `instr`.
*
* Note that this predicate may return multiple results in cases where a conversion belongs to a
* different AST element than its operand.
*/
private Expr getConvertedResultExpression(Instruction instr, int n) {
// Only fully converted instructions have a result for `asConvertedExpr`
not conversionFlow(unique(Operand op |
// The address operand of a `InitializeDynamicAllocationInstruction` is
// special: we need to handle it during dataflow (since it's
// effectively a store to an indirection), but it doesn't appear in
// source syntax, so dataflow node <-> expression conversion shouldn't
// care about it.
op = getAUse(instr) and not op = getAnInitializeDynamicAllocationInstructionAddress()
|
op
), _, false, false) and
result = getConvertedResultExpressionImpl(instr) and
n = 0
or
// If the conversion also has a result then we return multiple results
exists(Operand operand | conversionFlow(operand, instr, false, false) |
n = 1 and
result = getConvertedResultExpressionImpl(operand.getDef())
or
result = getConvertedResultExpression(operand.getDef(), n - 1)
)
}
private Expr getConvertedResultExpressionImpl0(Instruction instr) {
// IR construction inserts an additional cast to a `size_t` on the extent
// of a `new[]` expression. The resulting `ConvertInstruction` doesn't have
// a result for `getConvertedResultExpression`. We remap this here so that
// this `ConvertInstruction` maps to the result of the expression that
// represents the extent.
exists(TranslatedNonConstantAllocationSize tas |
result = tas.getExtent().getExpr() and
instr = tas.getInstruction(AllocationExtentConvertTag())
)
or
// There's no instruction that returns `ParenthesisExpr`, but some queries
// expect this
exists(TranslatedTransparentConversion ttc |
result = ttc.getExpr().(ParenthesisExpr) and
instr = ttc.getResult()
)
or
// Certain expressions generate `CopyValueInstruction`s only when they
// are needed. Examples of this include crement operations and compound
// assignment operations. For example:
// ```cpp
// int x = ...
// int y = x++;
// ```
// this generate IR like:
// ```
// r1(glval<int>) = VariableAddress[x] :
// r2(int) = Constant[0] :
// m3(int) = Store[x] : &:r1, r2
// r4(glval<int>) = VariableAddress[y] :
// r5(glval<int>) = VariableAddress[x] :
// r6(int) = Load[x] : &:r5, m3
// r7(int) = Constant[1] :
// r8(int) = Add : r6, r7
// m9(int) = Store[x] : &:r5, r8
// r11(int) = CopyValue : r6
// m12(int) = Store[y] : &:r4, r11
// ```
// When the `CopyValueInstruction` is not generated there is no instruction
// whose `getConvertedResultExpression` maps back to the expression. When
// such an instruction doesn't exist it means that the old value is not
// needed, and in that case the only value that will propagate forward in
// the program is the value that's been updated. So in those cases we just
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
exists(TranslatedCoreExpr tco |
tco.getInstruction(_) = instr and
tco.producesExprResult() and
result = asDefinitionImpl0(instr)
)
}
private Expr getConvertedResultExpressionImpl(Instruction instr) {
result = getConvertedResultExpressionImpl0(instr)
or
not exists(getConvertedResultExpressionImpl0(instr)) and
result = instr.getConvertedResultExpression()
}
/**
* Gets the result for `node.asDefinition()` (when `node` is the instruction
* node that wraps `store`) in the cases where `store.getAst()` should not be
* used to define the result of `node.asDefinition()`.
*/
private Expr asDefinitionImpl0(StoreInstruction store) {
// For an expression such as `i += 2` we pretend that the generated
// `StoreInstruction` contains the result of the expression even though
// this isn't totally aligned with the C/C++ standard.
exists(TranslatedAssignOperation tao |
store = tao.getInstruction(AssignmentStoreTag()) and
result = tao.getExpr()
)
or
// Similarly for `i++` and `++i` we pretend that the generated
// `StoreInstruction` is contains the result of the expression even though
// this isn't totally aligned with the C/C++ standard.
exists(TranslatedCrementOperation tco |
store = tco.getInstruction(CrementStoreTag()) and
result = tco.getExpr()
)
}
/**
* Holds if the expression returned by `store.getAst()` should not be
* returned as the result of `node.asDefinition()` when `node` is the
* instruction node that wraps `store`.
*/
private predicate excludeAsDefinitionResult(StoreInstruction store) {
// Exclude the store to the temporary generated by a ternary expression.
exists(TranslatedConditionalExpr tce |
store = tce.getInstruction(ConditionValueFalseStoreTag())
or
store = tce.getInstruction(ConditionValueTrueStoreTag())
)
}
/**
* Gets the expression that represents the result of `StoreInstruction` for
* dataflow purposes.
*
* For example, consider the following example
* ```cpp
* int x = 42; // 1
* x = 34; // 2
* ++x; // 3
* x++; // 4
* x += 1; // 5
* int y = x += 2; // 6
* ```
* For (1) the result is `42`.
* For (2) the result is `x = 34`.
* For (3) the result is `++x`.
* For (4) the result is `x++`.
* For (5) the result is `x += 1`.
* For (6) there are two results:
* - For the `StoreInstruction` generated by `x += 2` the result
* is `x += 2`
* - For the `StoreInstruction` generated by `int y = ...` the result
* is also `x += 2`
*/
cached
Expr asDefinitionImpl(StoreInstruction store) {
not exists(asDefinitionImpl0(store)) and
not excludeAsDefinitionResult(store) and
result = store.getAst().(Expr).getUnconverted()
or
result = asDefinitionImpl0(store)
}
/** Holds if `node` is an `OperandNode` that should map `node.asExpr()` to `e`. */
private predicate exprNodeShouldBeOperand(OperandNode node, Expr e, int n) {
not exprNodeShouldBeIndirectOperand(_, e, n) and
exists(Instruction def |
unique( | | getAUse(def)) = node.getOperand() and
e = getConvertedResultExpression(def, n)
)
}
/** Holds if `node` should be an `IndirectOperand` that maps `node.asIndirectExpr()` to `e`. */
private predicate indirectExprNodeShouldBeIndirectOperand(
IndirectOperand node, Expr e, int n, int indirectionIndex
) {
exists(Instruction def |
node.hasOperandAndIndirectionIndex(unique( | | getAUse(def)), indirectionIndex) and
e = getConvertedResultExpression(def, n)
)
}
/** Holds if `node` should be an `IndirectOperand` that maps `node.asExpr()` to `e`. */
private predicate exprNodeShouldBeIndirectOperand(IndirectOperand node, Expr e, int n) {
exists(ArgumentOperand operand |
// When an argument (qualifier or positional) is a prvalue and the
// parameter (qualifier or positional) is a (const) reference, IR
// construction introduces a temporary `IRVariable`. The `VariableAddress`
// instruction has the argument as its `getConvertedResultExpression`
// result. However, the instruction actually represents the _address_ of
// the argument. So to fix this mismatch, we have the indirection of the
// `VariableAddressInstruction` map to the expression.
node.hasOperandAndIndirectionIndex(operand, 1) and
e = getConvertedResultExpression(operand.getDef(), n) and
operand.getDef().(VariableAddressInstruction).getIRVariable() instanceof IRTempVariable
)
}
private predicate exprNodeShouldBeIndirectOutNode(IndirectArgumentOutNode node, Expr e, int n) {
exists(CallInstruction call |
call.getStaticCallTarget() instanceof Constructor and
e = getConvertedResultExpression(call, n) and
call.getThisArgumentOperand() = node.getAddressOperand()
)
}
/** Holds if `node` should be an instruction node that maps `node.asExpr()` to `e`. */
private predicate exprNodeShouldBeInstruction(Node node, Expr e, int n) {
not exprNodeShouldBeOperand(_, e, n) and
not exprNodeShouldBeIndirectOutNode(_, e, n) and
not exprNodeShouldBeIndirectOperand(_, e, n) and
e = getConvertedResultExpression(node.asInstruction(), n)
}
/** Holds if `node` should be an `IndirectInstruction` that maps `node.asIndirectExpr()` to `e`. */
private predicate indirectExprNodeShouldBeIndirectInstruction(
IndirectInstruction node, Expr e, int n, int indirectionIndex
) {
not indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) and
exists(Instruction instr |
node.hasInstructionAndIndirectionIndex(instr, indirectionIndex) and
e = getConvertedResultExpression(instr, n)
)
}
abstract private class ExprNodeBase extends Node {
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
abstract Expr getConvertedExpr(int n);
/** Gets the non-conversion expression corresponding to this node, if any. */
final Expr getExpr(int n) { result = this.getConvertedExpr(n).getUnconverted() }
}
/**
* Holds if there exists a dataflow node whose `asExpr(n)` should evaluate
* to `e`.
*/
private predicate exprNodeShouldBe(Expr e, int n) {
exprNodeShouldBeInstruction(_, e, n) or
exprNodeShouldBeOperand(_, e, n) or
exprNodeShouldBeIndirectOutNode(_, e, n) or
exprNodeShouldBeIndirectOperand(_, e, n)
}
private class InstructionExprNode extends ExprNodeBase, InstructionNode {
InstructionExprNode() {
exists(Expr e, int n |
exprNodeShouldBeInstruction(this, e, n) and
not exists(Expr conv |
exprNodeShouldBe(conv, n + 1) and
conv.getUnconverted() = e.getUnconverted()
)
)
}
final override Expr getConvertedExpr(int n) { exprNodeShouldBeInstruction(this, result, n) }
}
private class OperandExprNode extends ExprNodeBase, OperandNode {
OperandExprNode() {
exists(Expr e, int n |
exprNodeShouldBeOperand(this, e, n) and
not exists(Expr conv |
exprNodeShouldBe(conv, n + 1) and
conv.getUnconverted() = e.getUnconverted()
)
)
}
final override Expr getConvertedExpr(int n) { exprNodeShouldBeOperand(this, result, n) }
}
abstract private class IndirectExprNodeBase extends Node {
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
abstract Expr getConvertedExpr(int n, int indirectionIndex);
/** Gets the non-conversion expression corresponding to this node, if any. */
final Expr getExpr(int n, int indirectionIndex) {
result = this.getConvertedExpr(n, indirectionIndex).getUnconverted()
}
}
/** A signature for converting an indirect node to an expression. */
private signature module IndirectNodeToIndirectExprSig {
/** The indirect node class to be converted to an expression */
class IndirectNode;
/**
* Holds if the indirect expression at indirection index `indirectionIndex`
* of `node` is `e`. The integer `n` specifies how many conversions has been
* applied to `node`.
*/
predicate indirectNodeHasIndirectExpr(IndirectNode node, Expr e, int n, int indirectionIndex);
}
/**
* A module that implements the logic for deciding whether an indirect node
* should be an `IndirectExprNode`.
*/
private module IndirectNodeToIndirectExpr<IndirectNodeToIndirectExprSig Sig> {
import Sig
/**
* This predicate shifts the indirection index by one when `conv` is a
* `ReferenceDereferenceExpr`.
*
* This is necessary because `ReferenceDereferenceExpr` is a conversion
* in the AST, but appears as a `LoadInstruction` in the IR.
*/
bindingset[e, indirectionIndex]
private predicate adjustForReference(
Expr e, int indirectionIndex, Expr conv, int adjustedIndirectionIndex
) {
conv.(ReferenceDereferenceExpr).getExpr() = e and
adjustedIndirectionIndex = indirectionIndex - 1
or
not conv instanceof ReferenceDereferenceExpr and
conv = e and
adjustedIndirectionIndex = indirectionIndex
}
/** Holds if `node` should be an `IndirectExprNode`. */
predicate charpred(IndirectNode node) {
exists(Expr e, int n, int indirectionIndex |
indirectNodeHasIndirectExpr(node, e, n, indirectionIndex) and
not exists(Expr conv, int adjustedIndirectionIndex |
adjustForReference(e, indirectionIndex, conv, adjustedIndirectionIndex) and
indirectExprNodeShouldBe(conv, n + 1, adjustedIndirectionIndex)
)
)
}
}
private predicate indirectExprNodeShouldBe(Expr e, int n, int indirectionIndex) {
indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) or
indirectExprNodeShouldBeIndirectInstruction(_, e, n, indirectionIndex)
}
private module IndirectOperandIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
class IndirectNode = IndirectOperand;
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectOperand/4;
}
module IndirectOperandToIndirectExpr =
IndirectNodeToIndirectExpr<IndirectOperandIndirectExprNodeImpl>;
private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
{
IndirectOperandIndirectExprNode() { IndirectOperandToIndirectExpr::charpred(this) }
final override Expr getConvertedExpr(int n, int index) {
IndirectOperandToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
}
}
private module IndirectInstructionIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
class IndirectNode = IndirectInstruction;
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectInstruction/4;
}
module IndirectInstructionToIndirectExpr =
IndirectNodeToIndirectExpr<IndirectInstructionIndirectExprNodeImpl>;
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction
{
IndirectInstructionIndirectExprNode() { IndirectInstructionToIndirectExpr::charpred(this) }
final override Expr getConvertedExpr(int n, int index) {
IndirectInstructionToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
}
}
private class IndirectArgumentOutExprNode extends ExprNodeBase, IndirectArgumentOutNode {
IndirectArgumentOutExprNode() { exprNodeShouldBeIndirectOutNode(this, _, _) }
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOutNode(this, result, n) }
}
private class IndirectOperandExprNode extends ExprNodeBase instanceof IndirectOperand {
IndirectOperandExprNode() { exprNodeShouldBeIndirectOperand(this, _, _) }
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOperand(this, result, n) }
}
/**
* An expression, viewed as a node in a data flow graph.
*/
cached
class ExprNode extends Node instanceof ExprNodeBase {
/**
* INTERNAL: Do not use.
*/
cached
Expr getExpr(int n) { result = super.getExpr(n) }
/**
* Gets the non-conversion expression corresponding to this node, if any. If
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
* expression.
*/
cached
final Expr getExpr() { result = this.getExpr(_) }
/**
* INTERNAL: Do not use.
*/
cached
Expr getConvertedExpr(int n) { result = super.getConvertedExpr(n) }
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
cached
final Expr getConvertedExpr() { result = this.getConvertedExpr(_) }
}
/**
* An indirect expression, viewed as a node in a data flow graph.
*/
cached
class IndirectExprNode extends Node instanceof IndirectExprNodeBase {
/**
* Gets the non-conversion expression corresponding to this node, if any. If
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
* expression.
*/
cached
final Expr getExpr(int indirectionIndex) { result = this.getExpr(_, indirectionIndex) }
/**
* INTERNAL: Do not use.
*/
cached
Expr getExpr(int n, int indirectionIndex) { result = super.getExpr(n, indirectionIndex) }
/**
* INTERNAL: Do not use.
*/
cached
Expr getConvertedExpr(int n, int indirectionIndex) {
result = super.getConvertedExpr(n, indirectionIndex)
}
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
cached
Expr getConvertedExpr(int indirectionIndex) {
result = this.getConvertedExpr(_, indirectionIndex)
}
}
}
import Cached

View File

@@ -657,9 +657,19 @@ class GlobalDefImpl extends DefImpl, TGlobalDefImpl {
*/ */
predicate adjacentDefRead(IRBlock bb1, int i1, SourceVariable sv, IRBlock bb2, int i2) { predicate adjacentDefRead(IRBlock bb1, int i1, SourceVariable sv, IRBlock bb2, int i2) {
adjacentDefReadExt(_, sv, bb1, i1, bb2, 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) { 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 | exists(UseImpl use |
use.hasIndexInBlock(bb, i, sv) and use.hasIndexInBlock(bb, i, sv) and
nodeTo = use.getNode() nodeTo = use.getNode()
@@ -713,26 +723,46 @@ predicate nodeToDefOrUse(Node node, SourceVariable sv, IRBlock bb, int i, boolea
*/ */
private predicate indirectConversionFlowStep(Node nFrom, Node nTo) { private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
not exists(SourceVariable sv, IRBlock bb2, int i2 | not exists(SourceVariable sv, IRBlock bb2, int i2 |
useToNode(bb2, i2, sv, nTo) and nodeToDefOrUse(nTo, sv, bb2, i2, _) and
adjacentDefRead(bb2, i2, sv, _, _) adjacentDefRead(bb2, i2, sv, _, _)
) and ) and
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr | (
hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
hasOperandAndIndex(nTo, op2, pragma[only_bind_into](indirectionIndex)) and hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and
instr = op2.getDef() and hasOperandAndIndex(nTo, op2, pragma[only_bind_into](indirectionIndex)) and
conversionFlow(op1, instr, _, _) 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 * The reason for this predicate is a bit annoying:
* definition to (or use of) `sv` at `(bb1, i1)`. * 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) { private predicate adjustForPointerArith(PostUpdateNode pun, SourceVariable sv, IRBlock bb2, int i2) {
exists(PhiNode phi, IRBlock input | exists(IRBlock bb1, int i1, Node adjusted |
phi.hasInputFromBlock(_, sv, bb1, i1, input) and indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
node.getPhiNode() = phi and nodeToDefOrUse(adjusted, sv, bb1, i1, _) and
node.getBlock() = input adjacentDefRead(bb1, i1, sv, bb2, i2)
) )
} }
@@ -747,14 +777,10 @@ private predicate phiToNode(SsaPhiInputNode node, SourceVariable sv, IRBlock bb1
private predicate ssaFlowImpl( private predicate ssaFlowImpl(
IRBlock bb1, int i1, SourceVariable sv, Node nodeFrom, Node nodeTo, boolean uncertain IRBlock bb1, int i1, SourceVariable sv, Node nodeFrom, Node nodeTo, boolean uncertain
) { ) {
nodeToDefOrUse(nodeFrom, sv, bb1, i1, uncertain) and exists(IRBlock bb2, int i2 |
( nodeToDefOrUse(nodeFrom, sv, bb1, i1, uncertain) and
exists(IRBlock bb2, int i2 | adjacentDefRead(bb1, i1, sv, bb2, i2) and
adjacentDefRead(bb1, i1, sv, bb2, i2) and useToNode(bb2, i2, sv, nodeTo)
useToNode(bb2, i2, sv, nodeTo)
)
or
phiToNode(nodeTo, sv, bb1, i1)
) and ) and
nodeFrom != nodeTo nodeFrom != nodeTo
} }
@@ -763,7 +789,7 @@ private predicate ssaFlowImpl(
private Node getAPriorDefinition(DefinitionExt next) { private Node getAPriorDefinition(DefinitionExt next) {
exists(IRBlock bb, int i, SourceVariable sv | exists(IRBlock bb, int i, SourceVariable sv |
lastRefRedefExt(_, pragma[only_bind_into](sv), pragma[only_bind_into](bb), 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, _) nodeToDefOrUse(result, sv, bb, i, _)
) )
} }
@@ -870,31 +896,9 @@ private predicate isArgumentOfCallable(DataFlowCall call, Node n) {
* Holds if there is use-use flow from `pun`'s pre-update node to `n`. * Holds if there is use-use flow from `pun`'s pre-update node to `n`.
*/ */
private predicate postUpdateNodeToFirstUse(PostUpdateNode pun, Node n) { private predicate postUpdateNodeToFirstUse(PostUpdateNode pun, Node n) {
// We cannot mark a `PointerArithmeticInstruction` that computes an offset exists(SourceVariable sv, IRBlock bb2, int i2 |
// based on some SSA adjustForPointerArith(pun, sv, bb2, i2) and
// variable `x` as a use of `x` since this creates taint-flow in the useToNode(bb2, i2, sv, n)
// 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)
) )
} }
@@ -949,16 +953,11 @@ predicate postUpdateFlow(PostUpdateNode pun, Node nodeTo) {
/** Holds if `nodeTo` receives flow from the phi node `nodeFrom`. */ /** Holds if `nodeTo` receives flow from the phi node `nodeFrom`. */
predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) { 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 = nodeFrom.getPhiNode() and
phi.definesAt(sv, bb1, i1, _) phi.definesAt(sv, bb1, i1, _) and
| adjacentDefRead(bb1, i1, sv, bb2, i2) and
exists(IRBlock bb2, int i2 | useToNode(bb2, i2, sv, nodeTo)
adjacentDefRead(bb1, i1, sv, bb2, i2) and
useToNode(bb2, i2, sv, nodeTo)
)
or
phiToNode(nodeTo, sv, bb1, i1)
) )
} }
@@ -1032,26 +1031,22 @@ module SsaCached {
* Holds if the node at index `i` in `bb` is a last reference to SSA definition * 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`, * `def`. The reference is last because it can reach another write `next`,
* without passing through another read or write. * 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 cached
predicate lastRefRedefExt( 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 cached
Definition phiHasInputFromBlockExt(PhiNode phi, IRBlock bb) { Definition phiHasInputFromBlock(PhiNode phi, IRBlock bb) {
SsaImpl::phiHasInputFromBlockExt(phi, result, bb) SsaImpl::phiHasInputFromBlock(phi, result, bb)
} }
cached cached
predicate ssaDefReachesReadExt(SourceVariable v, DefinitionExt def, IRBlock bb, int i) { predicate ssaDefReachesRead(SourceVariable v, Definition def, IRBlock bb, int i) {
SsaImpl::ssaDefReachesReadExt(v, def, bb, i) SsaImpl::ssaDefReachesRead(v, def, bb, i)
} }
predicate variableRead = SsaInput::variableRead/4; predicate variableRead = SsaInput::variableRead/4;
@@ -1203,11 +1198,11 @@ class Phi extends TPhi, SsaDef {
final override Location getLocation() { result = phi.getBasicBlock().getLocation() } 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, _) } final Definition getAnInput() { this.hasInputFromBlock(result, _) }
} }
@@ -1233,21 +1228,13 @@ class PhiNode extends SsaImpl::DefinitionExt {
*/ */
predicate isPhiRead() { this instanceof SsaImpl::PhiReadNode } predicate isPhiRead() { this instanceof SsaImpl::PhiReadNode }
/** /** Holds if `inp` is an input to this phi node along the edge originating in `bb`. */
* Holds if the node at index `i` in `bb` is a last reference to SSA predicate hasInputFromBlock(Definition inp, IRBlock bb) {
* definition `def` of `sv`. The reference is last because it can reach inp = SsaCached::phiHasInputFromBlock(this, bb)
* 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)
} }
/** Gets a definition that is an input to this phi node. */ /** 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. */ /** An static single assignment (SSA) definition. */
@@ -1262,15 +1249,6 @@ class DefinitionExt extends SsaImpl::DefinitionExt {
result = this.getAPhiInputOrPriorDefinition*() and result = this.getAPhiInputOrPriorDefinition*() and
not result instanceof PhiNode 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; class Definition = SsaImpl::Definition;

View File

@@ -3208,20 +3208,9 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } 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) { final override Instruction getFirstInstruction(EdgeKind kind) {
if exists(this.getRankedChild(0)) if exists(this.getChild(0))
then result = this.getRankedChild(0).getFirstInstruction(kind) then result = this.getChild(0).getFirstInstruction(kind)
else ( else (
kind instanceof GotoEdge and result = this.getInstruction(OnlyInstructionTag()) kind instanceof GotoEdge and result = this.getInstruction(OnlyInstructionTag())
) )
@@ -3241,11 +3230,11 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
} }
final override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { final override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
exists(int id | child = this.getRankedChild(id) | exists(int id | child = this.getChild(id) |
result = this.getRankedChild(id + 1).getFirstInstruction(kind) result = this.getChild(id + 1).getFirstInstruction(kind)
or or
kind instanceof GotoEdge and kind instanceof GotoEdge and
not exists(this.getRankedChild(id + 1)) and not exists(this.getChild(id + 1)) and
result = this.getInstruction(OnlyInstructionTag()) result = this.getInstruction(OnlyInstructionTag())
) )
} }
@@ -3260,7 +3249,7 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
exists(int index | exists(int index |
operandTag = positionalArgumentOperand(index) and operandTag = positionalArgumentOperand(index) and
result = this.getRankedChild(index).(TranslatedExpr).getResult() result = this.getChild(index).(TranslatedExpr).getResult()
) )
} }

View File

@@ -1,24 +1,3 @@
## 1.0.2
No user-facing changes.
## 1.0.1
### Minor Analysis Improvements
* The `cpp/dangerous-function-overflow` no longer produces a false positive alert when the `gets` function does not have exactly one parameter.
## 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 ## 0.9.12
### New Queries ### New Queries

View File

@@ -209,7 +209,6 @@ class LoopWithAlloca extends Stmt {
DataFlow::localFlow(result, DataFlow::exprNode(va)) and DataFlow::localFlow(result, DataFlow::exprNode(va)) and
// Phi nodes will be preceded by nodes that represent actual definitions // Phi nodes will be preceded by nodes that represent actual definitions
not result instanceof DataFlow::SsaPhiNode and 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 // 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 = getExpr(result) | this = getAnEnclosingLoopOfExpr(e))
) )

View File

@@ -12,8 +12,8 @@ the required buffer size, but do not allocate space for the zero terminator.
</overview> </overview>
<recommendation> <recommendation>
<p> <p>
The highlighted code segment creates a buffer without ensuring it's large enough to accommodate the copied data. The expression highlighted by this rule creates a buffer that is of insufficient size to contain
This leaves the code susceptible to a buffer overflow attack, which could lead to anything from program crashes to malicious code execution. 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>
<p> <p>

View File

@@ -17,6 +17,5 @@ import cpp
from FunctionCall call, Function target from FunctionCall call, Function target
where where
call.getTarget() = target and call.getTarget() = target and
target.hasGlobalOrStdName("gets") and target.hasGlobalOrStdName("gets")
target.getNumberOfParameters() = 1
select call, "'gets' does not guard against buffer overflow." select call, "'gets' does not guard against buffer overflow."

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The "Variable not initialized before use" query (`cpp/not-initialised`) no longer reports an alert on static variables.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* 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

View File

@@ -1,5 +1,4 @@
## 1.0.0 ---
category: breaking
### 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. * CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.

View File

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

View File

@@ -1,5 +0,0 @@
## 1.0.1
### Minor Analysis Improvements
* The `cpp/dangerous-function-overflow` no longer produces a false positive alert when the `gets` function does not have exactly one parameter.

View File

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

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 1.0.2 lastReleaseVersion: 0.9.12

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries name: codeql/cpp-queries
version: 1.0.2 version: 1.0.0-dev
groups: groups:
- cpp - cpp
- queries - queries

View File

@@ -74,8 +74,6 @@ astGuardsCompare
| 34 | j >= 10+0 when ... < ... is false | | 34 | j >= 10+0 when ... < ... is false |
| 42 | 10 < j+1 when ... < ... is false | | 42 | 10 < j+1 when ... < ... is false |
| 42 | 10 >= j+1 when ... < ... is true | | 42 | 10 >= j+1 when ... < ... is true |
| 42 | call to getABool != 0 when call to getABool is true |
| 42 | call to getABool == 0 when call to getABool is false |
| 42 | j < 10+0 when ... < ... is true | | 42 | j < 10+0 when ... < ... is true |
| 42 | j >= 10+0 when ... < ... is false | | 42 | j >= 10+0 when ... < ... is false |
| 44 | 0 < z+0 when ... > ... is true | | 44 | 0 < z+0 when ... > ... is true |
@@ -539,8 +537,6 @@ astGuardsEnsure_const
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 | | test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
| 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 | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 31 | 32 | | test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 31 | 32 |
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | != | 0 | 43 | 45 |
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | == | 0 | 53 | 53 |
irGuards irGuards
| test.c:7:9:7:13 | CompareGT: ... > ... | | test.c:7:9:7:13 | CompareGT: ... > ... |
| test.c:17:8:17:12 | CompareLT: ... < ... | | test.c:17:8:17:12 | CompareLT: ... < ... |
@@ -617,8 +613,6 @@ irGuardsCompare
| 34 | j >= 10+0 when CompareLT: ... < ... is false | | 34 | j >= 10+0 when CompareLT: ... < ... is false |
| 42 | 10 < j+1 when CompareLT: ... < ... is false | | 42 | 10 < j+1 when CompareLT: ... < ... is false |
| 42 | 10 >= j+1 when CompareLT: ... < ... is true | | 42 | 10 >= j+1 when CompareLT: ... < ... is true |
| 42 | call to getABool != 0 when Call: call to getABool is true |
| 42 | call to getABool == 0 when Call: call to getABool is false |
| 42 | j < 10 when CompareLT: ... < ... is true | | 42 | j < 10 when CompareLT: ... < ... is true |
| 42 | j < 10+0 when CompareLT: ... < ... is true | | 42 | j < 10+0 when CompareLT: ... < ... is true |
| 42 | j >= 10 when CompareLT: ... < ... is false | | 42 | j >= 10 when CompareLT: ... < ... is false |
@@ -1087,5 +1081,3 @@ irGuardsEnsure_const
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | != | -1 | 34 | 34 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | != | -1 | 34 | 34 |
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 30 | 30 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 30 | 30 |
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 32 | 32 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 32 | 32 |
| test.cpp:42:13:42:20 | Call: call to getABool | test.cpp:42:13:42:20 | Call: call to getABool | != | 0 | 44 | 44 |
| test.cpp:42:13:42:20 | Call: call to getABool | test.cpp:42:13:42:20 | Call: call to getABool | == | 0 | 53 | 53 |

View File

@@ -42,6 +42,3 @@
| test.cpp:99:6:99:6 | f | | test.cpp:99:6:99:6 | f |
| test.cpp:105:6:105:14 | ... != ... | | test.cpp:105:6:105:14 | ... != ... |
| test.cpp:111:6:111:14 | ... != ... | | test.cpp:111:6:111:14 | ... != ... |
| test.cpp:122:9:122:9 | b |
| test.cpp:125:13:125:20 | ! ... |
| test.cpp:125:14:125:17 | call to safe |

View File

@@ -44,8 +44,6 @@
| 34 | j >= 10+0 when ... < ... is false | | 34 | j >= 10+0 when ... < ... is false |
| 42 | 10 < j+1 when ... < ... is false | | 42 | 10 < j+1 when ... < ... is false |
| 42 | 10 >= j+1 when ... < ... is true | | 42 | 10 >= j+1 when ... < ... is true |
| 42 | call to getABool != 0 when call to getABool is true |
| 42 | call to getABool == 0 when call to getABool is false |
| 42 | j < 10 when ... < ... is true | | 42 | j < 10 when ... < ... is true |
| 42 | j < 10+0 when ... < ... is true | | 42 | j < 10+0 when ... < ... is true |
| 42 | j >= 10 when ... < ... is false | | 42 | j >= 10 when ... < ... is false |
@@ -151,13 +149,6 @@
| 111 | 0.0 == i+0 when ... != ... is false | | 111 | 0.0 == i+0 when ... != ... is false |
| 111 | i != 0.0+0 when ... != ... is true | | 111 | i != 0.0+0 when ... != ... is true |
| 111 | i == 0.0+0 when ... != ... is false | | 111 | i == 0.0+0 when ... != ... is false |
| 122 | b != 0 when b is true |
| 122 | b == 0 when b is false |
| 125 | ! ... != 0 when ! ... is true |
| 125 | ! ... == 0 when ! ... is false |
| 125 | call to safe != 0 when ! ... is false |
| 125 | call to safe != 0 when call to safe is true |
| 125 | call to safe == 0 when call to safe is false |
| 126 | 1 != 0 when 1 is true | | 126 | 1 != 0 when 1 is true |
| 126 | 1 != 0 when ... && ... is true | | 126 | 1 != 0 when ... && ... is true |
| 126 | 1 == 0 when 1 is false | | 126 | 1 == 0 when 1 is false |

View File

@@ -100,7 +100,3 @@
| test.cpp:99:6:99:6 | f | true | 99 | 100 | | test.cpp:99:6:99:6 | f | true | 99 | 100 |
| test.cpp:105:6:105:14 | ... != ... | true | 105 | 106 | | test.cpp:105:6:105:14 | ... != ... | true | 105 | 106 |
| test.cpp:111:6:111:14 | ... != ... | true | 111 | 112 | | test.cpp:111:6:111:14 | ... != ... | true | 111 | 112 |
| test.cpp:122:9:122:9 | b | true | 123 | 125 |
| test.cpp:122:9:122:9 | b | true | 125 | 125 |
| test.cpp:125:13:125:20 | ! ... | true | 125 | 125 |
| test.cpp:125:14:125:17 | call to safe | false | 125 | 125 |

View File

@@ -257,8 +257,6 @@ unary
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 | | test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
| 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 | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 31 | 32 | | test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 31 | 32 |
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | != | 0 | 43 | 45 |
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | == | 0 | 53 | 53 |
| test.cpp:61:10:61:10 | i | test.cpp:61:10:61:10 | i | == | 0 | 62 | 64 | | test.cpp:61:10:61:10 | i | test.cpp:61:10:61:10 | i | == | 0 | 62 | 64 |
| test.cpp:61:10:61:10 | i | test.cpp:61:10:61:10 | i | == | 1 | 65 | 66 | | test.cpp:61:10:61:10 | i | test.cpp:61:10:61:10 | i | == | 1 | 65 | 66 |
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | < | 11 | 75 | 77 | | test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | < | 11 | 75 | 77 |
@@ -266,7 +264,3 @@ unary
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 0 | 75 | 77 | | test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 0 | 75 | 77 |
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 11 | 78 | 79 | | test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 11 | 78 | 79 |
| test.cpp:93:6:93:6 | c | test.cpp:93:6:93:6 | c | != | 0 | 93 | 94 | | test.cpp:93:6:93:6 | c | test.cpp:93:6:93:6 | c | != | 0 | 93 | 94 |
| test.cpp:122:9:122:9 | b | test.cpp:122:9:122:9 | b | != | 0 | 123 | 125 |
| test.cpp:122:9:122:9 | b | test.cpp:122:9:122:9 | b | != | 0 | 125 | 125 |
| test.cpp:125:13:125:20 | ! ... | test.cpp:125:13:125:20 | ! ... | != | 0 | 125 | 125 |
| test.cpp:125:14:125:17 | call to safe | test.cpp:125:14:125:17 | call to safe | == | 0 | 125 | 125 |

View File

@@ -112,17 +112,3 @@ void int_float_comparison(int i) {
use(i); use(i);
} }
} }
int source();
bool safe(int);
void test(bool b)
{
int x;
if (b)
{
x = source();
if (!safe(x)) return;
}
use(x);
}

View File

@@ -75,54 +75,4 @@ void bg_indirect_expr() {
if (guarded(buf)) { if (guarded(buf)) {
sink(buf); sink(buf);
} }
}
void test_guard_and_reassign() {
int x = source();
if(!guarded(x)) {
x = 0;
}
sink(x); // $ SPURIOUS: ast
}
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
}
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
} }

View File

@@ -7,17 +7,10 @@ module AstTest {
* S in `if (guarded(x)) S`. * S in `if (guarded(x)) S`.
*/ */
// This is tested in `BarrierGuard.cpp`. // This is tested in `BarrierGuard.cpp`.
predicate testBarrierGuard(GuardCondition g, Expr checked, boolean branch) { predicate testBarrierGuard(GuardCondition g, Expr checked, boolean isTrue) {
exists(Call call, boolean b | g.(FunctionCall).getTarget().getName() = "guarded" and
checked = call.getArgument(0) and checked = g.(FunctionCall).getArgument(0) and
g.comparesEq(call, 0, b, any(BooleanValue bv | bv.getValue() = branch)) isTrue = true
|
call.getTarget().hasName("guarded") and
b = false
or
call.getTarget().hasName("unsafe") and
b = true
)
} }
/** Common data flow configuration to be used by tests. */ /** Common data flow configuration to be used by tests. */
@@ -109,16 +102,12 @@ module IRTest {
* S in `if (guarded(x)) S`. * S in `if (guarded(x)) S`.
*/ */
// This is tested in `BarrierGuard.cpp`. // This is tested in `BarrierGuard.cpp`.
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean branch) { predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean isTrue) {
exists(CallInstruction call, boolean b | exists(Call call |
checked = call.getArgument(0).getUnconvertedResultExpression() and call = g.getUnconvertedResultExpression() and
g.comparesEq(call.getAUse(), 0, b, any(BooleanValue bv | bv.getValue() = branch)) call.getTarget().hasName("guarded") and
| checked = call.getArgument(0) and
call.getStaticCallTarget().hasName("guarded") and isTrue = true
b = false
or
call.getStaticCallTarget().hasName("unsafe") and
b = true
) )
} }

View File

@@ -52,9 +52,3 @@ void following_pointers( // $ ast-def=sourceStruct1_ptr ir-def=*cleanArray1 ir-d
sink(stackArray); // $ ast,ir sink(stackArray); // $ ast,ir
indirect_sink(stackArray); // $ ast ir=50:25 ir=50:35 ir=51:19 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
}

View File

@@ -69,61 +69,45 @@
| test.cpp:8:8:8:9 | t1 | test.cpp:9:8:9:9 | t1 | | 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: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: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:10:8:10:9 | t2 | test.cpp:15:3:15:6 | Phi |
| 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:11:7:11:8 | t1 | test.cpp:21:8:21:9 | t1 | | 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: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: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:10:13:11 | t2 | test.cpp:15:3:15:6 | Phi |
| 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:15:3:15:6 | Phi |
| test.cpp:13:10:13:11 | t2 | test.cpp:13:5:13:8 | Phi input | | test.cpp:15:3:15:6 | Phi | test.cpp:15:8:15:9 | t2 |
| test.cpp:13:10:13:11 | t2 | test.cpp:13:5:13:8 | Phi input | | test.cpp:15:3:15:6 | Phi | test.cpp:15:8:15:9 | t2 |
| test.cpp:15:3:15:6 | SSA phi read(t2) | test.cpp:15:8:15:9 | t2 | | test.cpp:15:8:15:9 | t2 | test.cpp:23:19:23:19 | Phi |
| 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:19:23:19 | Phi |
| 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:17:3:17:8 | ... = ... | test.cpp:21:8:21:9 | t1 | | 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: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:19:23:19 | Phi |
| 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: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 | 0 |
| test.cpp:23:15:23:16 | 0 | test.cpp:23:15:23:16 | Phi input | | test.cpp:23:15:23:16 | 0 | test.cpp:23:19:23:19 | Phi |
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi read(*t2) | | test.cpp:23:19:23:19 | Phi | test.cpp:23:19:23:19 | i |
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi read(i) | | test.cpp:23:19:23:19 | Phi | test.cpp:23:19:23:19 | i |
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi read(t1) | | test.cpp:23:19:23:19 | Phi | test.cpp:23:23:23:24 | t1 |
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi read(t2) | | test.cpp:23:19:23:19 | Phi | test.cpp:23:23:23:24 | t1 |
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi(*i) | | test.cpp:23:19:23:19 | Phi | test.cpp:24:10:24:11 | t2 |
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi(*t1) | | test.cpp:23:19:23:19 | Phi | test.cpp:24:10:24:11 | t2 |
| 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: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: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: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: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: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 | ... ++ |
| test.cpp:23:27:23:29 | ... ++ | test.cpp:23:27:23:29 | Phi input | | test.cpp:24:5:24:11 | ... = ... | test.cpp:23:19:23:19 | Phi |
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi read(*t2) | | test.cpp:24:10:24:11 | t2 | test.cpp:23:19:23:19 | Phi |
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi read(i) | | test.cpp:24:10:24:11 | t2 | test.cpp:23:19:23:19 | Phi |
| 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:10:24:11 | t2 | test.cpp:24:5:24:11 | ... = ... | | 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: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 | | test.cpp:383:12:383:13 | 0 | test.cpp:383:12:383:13 | 0 |

View File

@@ -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: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:64:14:64:14 | x |
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:66:14:66: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 | | 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:18:8:18:19 | sourceArray1 |
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:22:8:22:20 | & ... | | clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:22:8:22:20 | & ... |
@@ -157,7 +153,6 @@ irFlow
| clang.cpp:50:25:50:30 | call to source | clang.cpp:53:17:53:26 | *stackArray | | 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: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: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: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: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 | | dispatch.cpp:10:37:10:42 | call to source | dispatch.cpp:36:16:36:25 | call to notSource2 |

View File

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

View File

@@ -1,2 +0,0 @@
testFailures
failures

View File

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

View File

@@ -1,34 +0,0 @@
import TestUtilities.dataflow.FlowTestCommon
import cpp
import semmle.code.cpp.security.FlowSources
module IRTest {
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.TaintTracking
/** Common data flow configuration to be used by tests. */
module TestAllocationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
// external flow source node
sourceNode(source, _)
or
// test source function
source.asExpr().(FunctionCall).getTarget().getName() = "source"
}
predicate isSink(DataFlow::Node sink) {
// external flow sink node
sinkNode(sink, _)
or
// test sink function
exists(FunctionCall call |
call.getTarget().getName() = "sink" and
sink.asExpr() = call.getAnArgument()
)
}
}
module IRFlow = TaintTracking::Global<TestAllocationConfig>;
}
import MakeTest<IRFlowTest<IRTest::IRFlow>>

View File

@@ -1,5 +0,0 @@
| asio_streams.cpp:93:29:93:39 | *recv_buffer | remote-sink |
| asio_streams.cpp:103:29:103:39 | *send_buffer | remote-sink |
| test.cpp:9:10:9:10 | 0 | test-sink |
| test.cpp:11:10:11:10 | x | test-sink |
| test.cpp:15:10:15:10 | y | test-sink |

View File

@@ -1,6 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: sinkModel
data: # namespace, type, subtypes, name, signature, ext, input, kind, provenance
- ["", "", False, "ymlSink", "", "", "Argument[0]", "test-sink", "manual"]

View File

@@ -1,7 +0,0 @@
import cpp
import semmle.code.cpp.ir.dataflow.DataFlow
import semmle.code.cpp.dataflow.ExternalFlow
from DataFlow::Node node, string kind
where sinkNode(node, kind)
select node, kind

View File

@@ -1,2 +0,0 @@
| asio_streams.cpp:87:34:87:44 | read_until output argument | remote |
| test.cpp:7:10:7:18 | call to ymlSource | local |

View File

@@ -1,6 +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"]

View File

@@ -1,7 +0,0 @@
import cpp
import semmle.code.cpp.ir.dataflow.DataFlow
import semmle.code.cpp.dataflow.ExternalFlow
from DataFlow::Node node, string kind
where sourceNode(node, kind)
select node, kind

View File

@@ -1,2 +0,0 @@
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer |
| test.cpp:13:18:13:18 | x | test.cpp:13:10:13:16 | call to ymlStep |

View File

@@ -1,6 +0,0 @@
extensions:
- 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"]

View File

@@ -1,8 +0,0 @@
import cpp
import semmle.code.cpp.ir.dataflow.DataFlow
import semmle.code.cpp.dataflow.ExternalFlow
import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
from DataFlow::Node node1, DataFlow::Node node2
where FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(node1, node2, _)
select node1, node2

View File

@@ -1,16 +0,0 @@
int ymlSource();
void ymlSink(int value);
int ymlStep(int value);
void test() {
int x = ymlSource();
ymlSink(0);
ymlSink(x); // $ ir
int y = ymlStep(x);
ymlSink(y); // $ ir
}

View File

@@ -1,2 +0,0 @@
import cpp
import semmle.code.cpp.dataflow.ExternalFlow::CsvValidation

View File

@@ -184,7 +184,6 @@ postWithInFlow
| simple.cpp:65:7:65:7 | i [post update] | PostUpdateNode should not be the target of local flow. | | simple.cpp:65:7:65:7 | i [post update] | PostUpdateNode should not be the target of local flow. |
| simple.cpp:83:12:83:13 | f1 [post update] | PostUpdateNode should not be the target of local flow. | | simple.cpp:83:12:83:13 | f1 [post update] | PostUpdateNode should not be the target of local flow. |
| simple.cpp:92:7:92:7 | i [post update] | PostUpdateNode should not be the target of local flow. | | simple.cpp:92:7:92:7 | i [post update] | PostUpdateNode should not be the target of local flow. |
| simple.cpp:118:7:118:7 | i [post update] | PostUpdateNode should not be the target of local flow. |
| struct_init.c:24:11:24:12 | ab [inner post update] | PostUpdateNode should not be the target of local flow. | | struct_init.c:24:11:24:12 | ab [inner post update] | PostUpdateNode should not be the target of local flow. |
| struct_init.c:36:17:36:24 | nestedAB [inner post update] | PostUpdateNode should not be the target of local flow. | | struct_init.c:36:17:36:24 | nestedAB [inner post update] | PostUpdateNode should not be the target of local flow. |
viableImplInCallContextTooLarge viableImplInCallContextTooLarge

View File

@@ -842,10 +842,6 @@ edges
| simple.cpp:108:17:108:26 | call to user_input | simple.cpp:108:17:108:26 | call to user_input | provenance | | | simple.cpp:108:17:108:26 | call to user_input | simple.cpp:108:17:108:26 | call to user_input | provenance | |
| simple.cpp:108:17:108:26 | call to user_input | simple.cpp:109:43:109:43 | x | provenance | | | simple.cpp:108:17:108:26 | call to user_input | simple.cpp:109:43:109:43 | x | provenance | |
| simple.cpp:109:43:109:43 | x | simple.cpp:103:24:103:24 | x | provenance | | | simple.cpp:109:43:109:43 | x | simple.cpp:103:24:103:24 | x | provenance | |
| simple.cpp:118:5:118:5 | *a [post update] [i] | simple.cpp:120:8:120:8 | *a [i] | provenance | |
| simple.cpp:118:5:118:22 | ... = ... | simple.cpp:118:5:118:5 | *a [post update] [i] | provenance | |
| simple.cpp:118:11:118:20 | call to user_input | simple.cpp:118:5:118:22 | ... = ... | provenance | |
| simple.cpp:120:8:120:8 | *a [i] | simple.cpp:120:10:120:10 | i | provenance | |
| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:14:24:14:25 | *ab [a] | provenance | | | struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:14:24:14:25 | *ab [a] | provenance | |
| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:8:15:9 | *ab [a] | provenance | | | struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:8:15:9 | *ab [a] | provenance | |
| struct_init.c:15:8:15:9 | *ab [a] | struct_init.c:15:12:15:12 | a | provenance | | | struct_init.c:15:8:15:9 | *ab [a] | struct_init.c:15:12:15:12 | a | provenance | |
@@ -1751,11 +1747,6 @@ nodes
| simple.cpp:108:17:108:26 | call to user_input | semmle.label | call to user_input | | simple.cpp:108:17:108:26 | call to user_input | semmle.label | call to user_input |
| simple.cpp:108:17:108:26 | call to user_input | semmle.label | call to user_input | | simple.cpp:108:17:108:26 | call to user_input | semmle.label | call to user_input |
| simple.cpp:109:43:109:43 | x | semmle.label | x | | simple.cpp:109:43:109:43 | x | semmle.label | x |
| simple.cpp:118:5:118:5 | *a [post update] [i] | semmle.label | *a [post update] [i] |
| simple.cpp:118:5:118:22 | ... = ... | semmle.label | ... = ... |
| simple.cpp:118:11:118:20 | call to user_input | semmle.label | call to user_input |
| simple.cpp:120:8:120:8 | *a [i] | semmle.label | *a [i] |
| simple.cpp:120:10:120:10 | i | semmle.label | i |
| struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] | | struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] |
| struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] | | struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] |
| struct_init.c:15:8:15:9 | *ab [a] | semmle.label | *ab [a] | | struct_init.c:15:8:15:9 | *ab [a] | semmle.label | *ab [a] |
@@ -1966,7 +1957,6 @@ subpaths
| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input |
| simple.cpp:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input | | simple.cpp:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input |
| simple.cpp:104:14:104:14 | x | simple.cpp:108:17:108:26 | call to user_input | simple.cpp:104:14:104:14 | x | x flows from $@ | simple.cpp:108:17:108:26 | call to user_input | call to user_input | | simple.cpp:104:14:104:14 | x | simple.cpp:108:17:108:26 | call to user_input | simple.cpp:104:14:104:14 | x | x flows from $@ | simple.cpp:108:17:108:26 | call to user_input | call to user_input |
| simple.cpp:120:10:120:10 | i | simple.cpp:118:11:118:20 | call to user_input | simple.cpp:120:10:120:10 | i | i flows from $@ | simple.cpp:118:11:118:20 | call to user_input | call to user_input |
| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input |
| struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input |

View File

@@ -289,5 +289,3 @@ WARNING: Module DataFlow has been deprecated and may be removed in future (parti
| simple.cpp:83:12:83:13 | f1 | AST only | | simple.cpp:83:12:83:13 | f1 | AST only |
| simple.cpp:92:7:92:7 | i | AST only | | simple.cpp:92:7:92:7 | i | AST only |
| simple.cpp:94:10:94:11 | a2 | IR only | | simple.cpp:94:10:94:11 | a2 | IR only |
| simple.cpp:118:7:118:7 | i | AST only |
| simple.cpp:120:8:120:8 | a | IR only |

View File

@@ -649,8 +649,6 @@
| simple.cpp:84:14:84:20 | this | | simple.cpp:84:14:84:20 | this |
| simple.cpp:92:5:92:5 | a | | simple.cpp:92:5:92:5 | a |
| simple.cpp:94:10:94:11 | a2 | | simple.cpp:94:10:94:11 | a2 |
| simple.cpp:118:5:118:5 | a |
| simple.cpp:120:8:120:8 | a |
| struct_init.c:15:8:15:9 | ab | | struct_init.c:15:8:15:9 | ab |
| struct_init.c:15:12:15:12 | a | | struct_init.c:15:12:15:12 | a |
| struct_init.c:16:8:16:9 | ab | | struct_init.c:16:8:16:9 | ab |

View File

@@ -579,8 +579,6 @@ WARNING: Module DataFlow has been deprecated and may be removed in future (parti
| simple.cpp:84:14:84:20 | this | | simple.cpp:84:14:84:20 | this |
| simple.cpp:92:5:92:5 | a | | simple.cpp:92:5:92:5 | a |
| simple.cpp:92:7:92:7 | i | | simple.cpp:92:7:92:7 | i |
| simple.cpp:118:5:118:5 | a |
| simple.cpp:118:7:118:7 | i |
| struct_init.c:15:8:15:9 | ab | | struct_init.c:15:8:15:9 | ab |
| struct_init.c:15:12:15:12 | a | | struct_init.c:15:12:15:12 | a |
| struct_init.c:16:8:16:9 | ab | | struct_init.c:16:8:16:9 | ab |

View File

@@ -731,10 +731,6 @@ edges
| simple.cpp:92:5:92:22 | ... = ... | simple.cpp:92:5:92:5 | a [post update] [i] | provenance | | | simple.cpp:92:5:92:22 | ... = ... | simple.cpp:92:5:92:5 | a [post update] [i] | provenance | |
| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | ... = ... | provenance | | | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | ... = ... | provenance | |
| simple.cpp:94:10:94:11 | a2 [i] | simple.cpp:94:13:94:13 | i | provenance | | | simple.cpp:94:10:94:11 | a2 [i] | simple.cpp:94:13:94:13 | i | provenance | |
| simple.cpp:118:5:118:5 | a [post update] [i] | simple.cpp:120:8:120:8 | a [i] | provenance | |
| simple.cpp:118:5:118:22 | ... = ... | simple.cpp:118:5:118:5 | a [post update] [i] | provenance | |
| simple.cpp:118:11:118:20 | call to user_input | simple.cpp:118:5:118:22 | ... = ... | provenance | |
| simple.cpp:120:8:120:8 | a [i] | simple.cpp:120:10:120:10 | i | provenance | |
| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:14:24:14:25 | ab [a] | provenance | | | struct_init.c:14:24:14:25 | ab [a] | struct_init.c:14:24:14:25 | ab [a] | provenance | |
| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | provenance | | | struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | provenance | |
| struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | provenance | | | struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | provenance | |
@@ -1542,11 +1538,6 @@ nodes
| simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input | | simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input |
| simple.cpp:94:10:94:11 | a2 [i] | semmle.label | a2 [i] | | simple.cpp:94:10:94:11 | a2 [i] | semmle.label | a2 [i] |
| simple.cpp:94:13:94:13 | i | semmle.label | i | | simple.cpp:94:13:94:13 | i | semmle.label | i |
| simple.cpp:118:5:118:5 | a [post update] [i] | semmle.label | a [post update] [i] |
| simple.cpp:118:5:118:22 | ... = ... | semmle.label | ... = ... |
| simple.cpp:118:11:118:20 | call to user_input | semmle.label | call to user_input |
| simple.cpp:120:8:120:8 | a [i] | semmle.label | a [i] |
| simple.cpp:120:10:120:10 | i | semmle.label | i |
| struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] | | struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] |
| struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] | | struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] |
| struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] |
@@ -1760,7 +1751,6 @@ subpaths
| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input |
| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input |
| simple.cpp:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input | | simple.cpp:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input |
| simple.cpp:120:10:120:10 | i | simple.cpp:118:11:118:20 | call to user_input | simple.cpp:120:10:120:10 | i | i flows from $@ | simple.cpp:118:11:118:20 | call to user_input | call to user_input |
| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input |
| struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input |

View File

@@ -111,13 +111,4 @@ namespace TestAdditionalCallTargets {
} }
void post_update_to_phi_input(bool b)
{
A a;
if(b) {
a.i = user_input();
}
sink(a.i); // $ ast,ir
}
} // namespace Simple } // namespace Simple

View File

@@ -1,89 +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 ---
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); // $ remote_source
if (error) {
// ...
}
std::string send_str = std::string("message");
boost::asio::mutable_buffer send_buffer = boost::asio::buffer(send_str);
boost::asio::write(socket, send_buffer, error); // $ remote_sink
if (error) {
// ...
}
}

View File

@@ -22734,25 +22734,6 @@ ir.cpp:
# 2552| Type = [Class] ClassWithDestructor # 2552| Type = [Class] ClassWithDestructor
# 2552| ValueCategory = xvalue # 2552| ValueCategory = xvalue
# 2553| getStmt(1): [ReturnStmt] return ... # 2553| getStmt(1): [ReturnStmt] return ...
# 2555| [TopLevelFunction] void builtin_bitcast(unsigned long)
# 2555| <params>:
# 2555| getParameter(0): [Parameter] ul
# 2555| Type = [LongType] unsigned long
# 2555| getEntryPoint(): [BlockStmt] { ... }
# 2556| getStmt(0): [DeclStmt] declaration
# 2556| getDeclarationEntry(0): [VariableDeclarationEntry] definition of d
# 2556| Type = [DoubleType] double
# 2556| getVariable().getInitializer(): [Initializer] initializer for d
# 2556| getExpr(): [BuiltInBitCast] __builtin_bit_cast
# 2556| Type = [DoubleType] double
# 2556| ValueCategory = prvalue
# 2556| getChild(0): [TypeName] double
# 2556| Type = [DoubleType] double
# 2556| ValueCategory = prvalue
# 2556| getChild(1): [VariableAccess] ul
# 2556| Type = [LongType] unsigned long
# 2556| ValueCategory = prvalue(load)
# 2557| getStmt(1): [ReturnStmt] return ...
perf-regression.cpp: perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&) # 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| <params>: # 4| <params>:

View File

@@ -13430,32 +13430,6 @@ ir.cpp:
# 1898| v1898_6(void) = AliasedUse : m1898_3 # 1898| v1898_6(void) = AliasedUse : m1898_3
# 1898| v1898_7(void) = ExitFunction : # 1898| v1898_7(void) = ExitFunction :
# 1899| const char[17] __PRETTY_FUNCTION__
# 1899| Block 0
# 1899| v1899_1(void) = EnterFunction :
# 1899| m1899_2(unknown) = AliasedDefinition :
# 1899| r1899_3(glval<char[17]>) = VariableAddress[__PRETTY_FUNCTION__] :
# 1899| r1899_4(glval<char[17]>) = StringConstant[__PRETTY_FUNCTION__] :
# 1899| r1899_5(char[17]) = Load[?] : &:r1899_4, ~m?
# 1899| m1899_6(char[17]) = Store[__PRETTY_FUNCTION__] : &:r1899_3, r1899_5
# 1899| m1899_7(unknown) = Chi : total:m1899_2, partial:m1899_6
# 1899| v1899_8(void) = ReturnVoid :
# 1899| v1899_9(void) = AliasedUse : ~m1899_7
# 1899| v1899_10(void) = ExitFunction :
# 1900| const char[10] __func__
# 1900| Block 0
# 1900| v1900_1(void) = EnterFunction :
# 1900| m1900_2(unknown) = AliasedDefinition :
# 1900| r1900_3(glval<char[10]>) = VariableAddress[__func__] :
# 1900| r1900_4(glval<char[10]>) = StringConstant[__func__] :
# 1900| r1900_5(char[10]) = Load[?] : &:r1900_4, ~m?
# 1900| m1900_6(char[10]) = Store[__func__] : &:r1900_3, r1900_5
# 1900| m1900_7(unknown) = Chi : total:m1900_2, partial:m1900_6
# 1900| v1900_8(void) = ReturnVoid :
# 1900| v1900_9(void) = AliasedUse : ~m1900_7
# 1900| v1900_10(void) = ExitFunction :
# 1911| void* missing_declaration_entries::Bar1<int>::missing_type_decl_entry(missing_declaration_entries::Bar1<int>::pointer) # 1911| void* missing_declaration_entries::Bar1<int>::missing_type_decl_entry(missing_declaration_entries::Bar1<int>::pointer)
# 1911| Block 0 # 1911| Block 0
# 1911| v1911_1(void) = EnterFunction : # 1911| v1911_1(void) = EnterFunction :
@@ -18377,24 +18351,6 @@ ir.cpp:
# 2550| Block 2 # 2550| Block 2
# 2550| v2550_10(void) = Unreached : # 2550| v2550_10(void) = Unreached :
# 2555| void builtin_bitcast(unsigned long)
# 2555| Block 0
# 2555| v2555_1(void) = EnterFunction :
# 2555| m2555_2(unknown) = AliasedDefinition :
# 2555| m2555_3(unknown) = InitializeNonLocal :
# 2555| m2555_4(unknown) = Chi : total:m2555_2, partial:m2555_3
# 2555| r2555_5(glval<unsigned long>) = VariableAddress[ul] :
# 2555| m2555_6(unsigned long) = InitializeParameter[ul] : &:r2555_5
# 2556| r2556_1(glval<double>) = VariableAddress[d] :
# 2556| r2556_2(glval<unsigned long>) = VariableAddress[ul] :
# 2556| r2556_3(unsigned long) = Load[ul] : &:r2556_2, m2555_6
# 2556| r2556_4(double) = BuiltIn[__builtin_bit_cast] : 0:r2556_3
# 2556| m2556_5(double) = Store[d] : &:r2556_1, r2556_4
# 2557| v2557_1(void) = NoOp :
# 2555| v2555_7(void) = ReturnVoid :
# 2555| v2555_8(void) = AliasedUse : m2555_3
# 2555| v2555_9(void) = ExitFunction :
perf-regression.cpp: perf-regression.cpp:
# 6| void Big::Big() # 6| void Big::Big()
# 6| Block 0 # 6| Block 0

View File

@@ -2552,8 +2552,4 @@ void constexpr_inconsistency(bool b) {
; ;
} }
void builtin_bitcast(unsigned long ul) {
double d = __builtin_bit_cast(double, ul);
}
// semmle-extractor-options: -std=c++20 --clang // semmle-extractor-options: -std=c++20 --clang

View File

@@ -12384,30 +12384,6 @@ ir.cpp:
# 1898| v1898_5(void) = AliasedUse : ~m? # 1898| v1898_5(void) = AliasedUse : ~m?
# 1898| v1898_6(void) = ExitFunction : # 1898| v1898_6(void) = ExitFunction :
# 1899| const char[17] __PRETTY_FUNCTION__
# 1899| Block 0
# 1899| v1899_1(void) = EnterFunction :
# 1899| mu1899_2(unknown) = AliasedDefinition :
# 1899| r1899_3(glval<char[17]>) = VariableAddress[__PRETTY_FUNCTION__] :
# 1899| r1899_4(glval<char[17]>) = StringConstant[__PRETTY_FUNCTION__] :
# 1899| r1899_5(char[17]) = Load[?] : &:r1899_4, ~m?
# 1899| mu1899_6(char[17]) = Store[__PRETTY_FUNCTION__] : &:r1899_3, r1899_5
# 1899| v1899_7(void) = ReturnVoid :
# 1899| v1899_8(void) = AliasedUse : ~m?
# 1899| v1899_9(void) = ExitFunction :
# 1900| const char[10] __func__
# 1900| Block 0
# 1900| v1900_1(void) = EnterFunction :
# 1900| mu1900_2(unknown) = AliasedDefinition :
# 1900| r1900_3(glval<char[10]>) = VariableAddress[__func__] :
# 1900| r1900_4(glval<char[10]>) = StringConstant[__func__] :
# 1900| r1900_5(char[10]) = Load[?] : &:r1900_4, ~m?
# 1900| mu1900_6(char[10]) = Store[__func__] : &:r1900_3, r1900_5
# 1900| v1900_7(void) = ReturnVoid :
# 1900| v1900_8(void) = AliasedUse : ~m?
# 1900| v1900_9(void) = ExitFunction :
# 1911| void* missing_declaration_entries::Bar1<int>::missing_type_decl_entry(missing_declaration_entries::Bar1<int>::pointer) # 1911| void* missing_declaration_entries::Bar1<int>::missing_type_decl_entry(missing_declaration_entries::Bar1<int>::pointer)
# 1911| Block 0 # 1911| Block 0
# 1911| v1911_1(void) = EnterFunction : # 1911| v1911_1(void) = EnterFunction :
@@ -16717,23 +16693,6 @@ ir.cpp:
# 2550| v2550_7(void) = AliasedUse : ~m? # 2550| v2550_7(void) = AliasedUse : ~m?
# 2550| v2550_8(void) = ExitFunction : # 2550| v2550_8(void) = ExitFunction :
# 2555| void builtin_bitcast(unsigned long)
# 2555| Block 0
# 2555| v2555_1(void) = EnterFunction :
# 2555| mu2555_2(unknown) = AliasedDefinition :
# 2555| mu2555_3(unknown) = InitializeNonLocal :
# 2555| r2555_4(glval<unsigned long>) = VariableAddress[ul] :
# 2555| mu2555_5(unsigned long) = InitializeParameter[ul] : &:r2555_4
# 2556| r2556_1(glval<double>) = VariableAddress[d] :
# 2556| r2556_2(glval<unsigned long>) = VariableAddress[ul] :
# 2556| r2556_3(unsigned long) = Load[ul] : &:r2556_2, ~m?
# 2556| r2556_4(double) = BuiltIn[__builtin_bit_cast] : 0:r2556_3
# 2556| mu2556_5(double) = Store[d] : &:r2556_1, r2556_4
# 2557| v2557_1(void) = NoOp :
# 2555| v2555_6(void) = ReturnVoid :
# 2555| v2555_7(void) = AliasedUse : ~m?
# 2555| v2555_8(void) = ExitFunction :
perf-regression.cpp: perf-regression.cpp:
# 6| void Big::Big() # 6| void Big::Big()
# 6| Block 0 # 6| Block 0

View File

@@ -1 +0,0 @@
semmle-extractor-options: -D__x86_64=1

View File

@@ -39,4 +39,3 @@
| variables.cpp:51:9:51:12 | town | file://:0:0:0:0 | char * | Field | | | | variables.cpp:51:9:51:12 | town | file://:0:0:0:0 | char * | Field | | |
| variables.cpp:52:16:52:22 | country | file://:0:0:0:0 | char * | MemberVariable, StaticStorageDurationVariable | | static | | variables.cpp:52:16:52:22 | country | file://:0:0:0:0 | char * | MemberVariable, StaticStorageDurationVariable | | static |
| variables.cpp:56:14:56:29 | externInFunction | file://:0:0:0:0 | int | GlobalLikeVariable, GlobalVariable, StaticStorageDurationVariable | | | | variables.cpp:56:14:56:29 | externInFunction | file://:0:0:0:0 | int | GlobalLikeVariable, GlobalVariable, StaticStorageDurationVariable | | |
| variables.cpp:60:10:60:17 | __func__ | file://:0:0:0:0 | const char[9] | GlobalLikeVariable, StaticInitializedStaticLocalVariable | | static |

View File

@@ -55,7 +55,3 @@ struct address {
void hasExtern() { void hasExtern() {
extern int externInFunction; extern int externInFunction;
} }
const char* isStatic() {
return __func__;
}

View File

@@ -36,7 +36,7 @@ char *gets(char *s);
void testGets() { void testGets() {
char buf1[1024]; char buf1[1024];
char *buf2 = malloc(1024); char buf2 = malloc(1024);
char *s; char *s;
gets(buf1); // BAD: use of gets gets(buf1); // BAD: use of gets

View File

@@ -1,7 +0,0 @@
char *gets();
void testOtherGets() {
char *s;
s = gets(); // GOOD: this is not the gets from stdio.h
}

1
csharp/.gitignore vendored
View File

@@ -14,4 +14,5 @@ csharp.log
.vscode/launch.json .vscode/launch.json
extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
extractor-pack
paket-files/ paket-files/

View File

@@ -1,5 +1,6 @@
load("@rules_pkg//pkg:mappings.bzl", "pkg_filegroup", "pkg_files") load("@rules_pkg//pkg:mappings.bzl", "pkg_filegroup", "pkg_files")
load("//misc/bazel:pkg.bzl", "codeql_pack", "codeql_pkg_files_overlay") load("@semmle_code//:dist.bzl", "dist")
load("//misc/bazel:pkg.bzl", "codeql_pkg_files_overlay")
package(default_visibility = ["//visibility:public"]) package(default_visibility = ["//visibility:public"])
@@ -58,16 +59,22 @@ codeql_pkg_files_overlay(
], ],
) )
codeql_pack( dist(
name = "csharp", name = "extractor-arch",
srcs = [":extractor-arch-overlay"],
)
dist(
name = "extractor-generic",
srcs = [ srcs = [
":dbscheme-group", ":dbscheme-group",
":extra-files", ":extra-files",
":extractor-arch-overlay",
":extractor-asp", ":extractor-asp",
"//csharp/downgrades", "//csharp/downgrades",
"//csharp/tools", "//csharp/tools",
], ],
prefix = "csharp",
visibility = ["//visibility:public"],
) )
test_suite( test_suite(

View File

@@ -7,11 +7,10 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Company>GitHub</Company> <Company>GitHub</Company>
<Product>CodeQL</Product>
<Copyright>Copyright © $([System.DateTime]::Now.Year) $(Company)</Copyright> <Copyright>Copyright © $([System.DateTime]::Now.Year) $(Company)</Copyright>
<Version>1.0.0.0</Version> <Version>1.0.0.0</Version>
<AssemblyVersion>$(Version)</AssemblyVersion> <AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>$(Version)</FileVersion> <FileVersion>1.0.0.0</FileVersion>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@@ -7,6 +7,7 @@ codeql_xunit_test(
name = "Semmle.Autobuild.CSharp.Tests", name = "Semmle.Autobuild.CSharp.Tests",
srcs = glob([ srcs = glob([
"*.cs", "*.cs",
"Properties/*.cs",
]), ]),
deps = [ deps = [
"//csharp/autobuilder/Semmle.Autobuild.CSharp:bin/Semmle.Autobuild.CSharp", "//csharp/autobuilder/Semmle.Autobuild.CSharp:bin/Semmle.Autobuild.CSharp",

View File

@@ -7,6 +7,7 @@ codeql_csharp_binary(
name = "Semmle.Autobuild.CSharp", name = "Semmle.Autobuild.CSharp",
srcs = glob([ srcs = glob([
"*.cs", "*.cs",
"Properties/*.cs",
]), ]),
visibility = ["//csharp:__subpackages__"], visibility = ["//csharp:__subpackages__"],
deps = [ deps = [

View File

@@ -12,7 +12,7 @@ namespace Semmle.Autobuild.CSharp
public class CSharpAutobuildOptions : AutobuildOptionsShared public class CSharpAutobuildOptions : AutobuildOptionsShared
{ {
private const string buildModeEnvironmentVariable = "CODEQL_EXTRACTOR_CSHARP_BUILD_MODE"; private const string buildModeEnvironmentVariable = "CODEQL_EXTRACTOR_CSHARP_BUILD_MODE";
internal const string ExtractorOptionBuildless = "CODEQL_EXTRACTOR_CSHARP_OPTION_BUILDLESS"; private const string extractorOptionPrefix = "CODEQL_EXTRACTOR_CSHARP_OPTION_";
public bool Buildless { get; } public bool Buildless { get; }
@@ -26,7 +26,7 @@ namespace Semmle.Autobuild.CSharp
public CSharpAutobuildOptions(IBuildActions actions) : base(actions) public CSharpAutobuildOptions(IBuildActions actions) : base(actions)
{ {
Buildless = Buildless =
actions.GetEnvironmentVariable(ExtractorOptionBuildless).AsBool("buildless", false) || actions.GetEnvironmentVariable(extractorOptionPrefix + "BUILDLESS").AsBool("buildless", false) ||
actions.GetEnvironmentVariable(buildModeEnvironmentVariable)?.ToLower() == "none"; actions.GetEnvironmentVariable(buildModeEnvironmentVariable)?.ToLower() == "none";
@@ -51,7 +51,7 @@ namespace Semmle.Autobuild.CSharp
case CSharpBuildStrategy.Buildless: case CSharpBuildStrategy.Buildless:
// No need to check that the extractor has been executed in buildless mode // No need to check that the extractor has been executed in buildless mode
attempt = BuildScript.Bind( attempt = BuildScript.Bind(
AddBuildlessWronglyConfiguredWarning() & AddBuildlessStartedDiagnostic() & new StandaloneBuildRule().Analyse(this, false), AddBuildlessStartedDiagnostic() & new StandaloneBuildRule().Analyse(this, false),
AddBuildlessEndedDiagnostic); AddBuildlessEndedDiagnostic);
break; break;
case CSharpBuildStrategy.Auto: case CSharpBuildStrategy.Auto:
@@ -81,27 +81,6 @@ namespace Semmle.Autobuild.CSharp
return 1; return 1;
}); });
private BuildScript AddBuildlessWronglyConfiguredWarning()
{
return BuildScript.Create(actions =>
{
if (actions.GetEnvironmentVariable(CSharpAutobuildOptions.ExtractorOptionBuildless) is null)
{
return 0;
}
AddDiagnostic(new DiagnosticMessage(
Options.Language,
"buildless/use-build-mode",
"C# was extracted with the deprecated 'buildless' option, use build-mode instead",
visibility: new DiagnosticMessage.TspVisibility(statusPage: true, cliSummaryTable: true, telemetry: true),
markdownMessage: "C# was extracted with the deprecated 'buildless' option, use build-mode instead.",
severity: DiagnosticMessage.TspSeverity.Warning
));
return 0;
});
}
private BuildScript AddBuildlessStartedDiagnostic() private BuildScript AddBuildlessStartedDiagnostic()
{ {
return BuildScript.Create(actions => return BuildScript.Create(actions =>

View File

@@ -7,6 +7,7 @@ codeql_xunit_test(
name = "Semmle.Autobuild.Cpp.Tests", name = "Semmle.Autobuild.Cpp.Tests",
srcs = glob([ srcs = glob([
"*.cs", "*.cs",
"Properties/*.cs",
]), ]),
deps = [ deps = [
"//csharp/autobuilder/Semmle.Autobuild.Cpp:bin/Semmle.Autobuild.Cpp", "//csharp/autobuilder/Semmle.Autobuild.Cpp:bin/Semmle.Autobuild.Cpp",

Some files were not shown because too many files have changed in this diff Show More