mirror of
https://github.com/github/codeql.git
synced 2026-02-11 20:51:06 +01:00
Merge branch 'main' into java-mad-test
This commit is contained in:
@@ -1 +1 @@
|
||||
8.1.1
|
||||
8.4.2
|
||||
|
||||
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -82,9 +82,6 @@
|
||||
/csharp/paket.main.bzl linguist-generated=true
|
||||
/csharp/paket.main_extension.bzl linguist-generated=true
|
||||
|
||||
# ripunzip tool
|
||||
/misc/ripunzip/ripunzip-* filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
# swift prebuilt resources
|
||||
/swift/third_party/resources/*.zip filter=lfs diff=lfs merge=lfs -text
|
||||
/swift/third_party/resources/*.tar.zst filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
5
.github/dependabot.yml
vendored
5
.github/dependabot.yml
vendored
@@ -40,3 +40,8 @@ updates:
|
||||
- dependency-name: "*"
|
||||
reviewers:
|
||||
- "github/codeql-go"
|
||||
|
||||
- package-ecosystem: bazel
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
|
||||
166
.github/workflows/build-ripunzip.yml
vendored
166
.github/workflows/build-ripunzip.yml
vendored
@@ -1,166 +0,0 @@
|
||||
name: Build ripunzip
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ripunzip-version:
|
||||
description: What reference to checkout from google/ripunzip. Latest by default
|
||||
required: false
|
||||
openssl-version:
|
||||
description: What reference to checkout from openssl/openssl for Linux. Latest by default
|
||||
required: false
|
||||
open-pr:
|
||||
description: Open a pull request updating the ripunzip versions committed to lfs
|
||||
required: false
|
||||
default: true # will be false on PRs
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/build-ripunzip.yml
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
versions:
|
||||
runs-on: ubuntu-slim
|
||||
outputs:
|
||||
ripunzip-version: ${{ inputs.ripunzip-version || steps.fetch-ripunzip-version.outputs.version }}
|
||||
openssl-version: ${{ inputs.openssl-version || steps.fetch-openssl-version.outputs.version }}
|
||||
steps:
|
||||
- name: Fetch latest ripunzip version
|
||||
id: fetch-ripunzip-version
|
||||
if: "!inputs.ripunzip-version"
|
||||
run: &fetch-version
|
||||
echo "version=$(gh release view --repo $REPO --json tagName --jq .tagName)" | tee -a $GITHUB_OUTPUT
|
||||
env:
|
||||
REPO: "google/ripunzip"
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Fetch latest openssl version
|
||||
id: fetch-openssl-version
|
||||
if: "!inputs.openssl-version"
|
||||
run: *fetch-version
|
||||
env:
|
||||
REPO: "openssl/openssl"
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
build:
|
||||
needs: versions
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-24.04, macos-15, windows-2025]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
repository: google/ripunzip
|
||||
ref: ${{ needs.versions.outputs.ripunzip-version }}
|
||||
# we need to avoid ripunzip dynamically linking into libssl
|
||||
# see https://github.com/sfackler/rust-openssl/issues/183
|
||||
- if: runner.os == 'Linux'
|
||||
name: checkout openssl
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: openssl/openssl
|
||||
path: openssl
|
||||
ref: ${{ needs.versions.outputs.openssl-version }}
|
||||
- if: runner.os == 'Linux'
|
||||
name: build and install openssl with fPIC
|
||||
shell: bash
|
||||
working-directory: openssl
|
||||
run: |
|
||||
./config -fPIC --prefix=$HOME/.local --openssldir=$HOME/.local/ssl
|
||||
make -j $(nproc)
|
||||
make install_sw -j $(nproc)
|
||||
- if: runner.os == 'Linux'
|
||||
name: build (linux)
|
||||
shell: bash
|
||||
run: |
|
||||
env OPENSSL_LIB_DIR=$HOME/.local/lib64 OPENSSL_INCLUDE_DIR=$HOME/.local/include OPENSSL_STATIC=yes cargo build --release
|
||||
mv target/release/ripunzip ripunzip-linux
|
||||
- if: runner.os == 'Windows'
|
||||
name: build (windows)
|
||||
shell: bash
|
||||
run: |
|
||||
cargo build --release
|
||||
mv target/release/ripunzip ripunzip-windows
|
||||
- name: build (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
shell: bash
|
||||
run: |
|
||||
rustup target install x86_64-apple-darwin
|
||||
rustup target install aarch64-apple-darwin
|
||||
cargo build --target x86_64-apple-darwin --release
|
||||
cargo build --target aarch64-apple-darwin --release
|
||||
lipo -create -output ripunzip-macos \
|
||||
-arch x86_64 target/x86_64-apple-darwin/release/ripunzip \
|
||||
-arch arm64 target/aarch64-apple-darwin/release/ripunzip
|
||||
- name: Archive
|
||||
shell: bash
|
||||
run: |
|
||||
tar acf ripunzip-$RUNNER_OS.tar.zst ripunzip-$(echo $RUNNER_OS | tr '[:upper:]' '[:lower:]')
|
||||
- name: Upload built binary
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ripunzip-${{ runner.os }}
|
||||
path: ripunzip-${{ runner.os }}.tar.zst
|
||||
retention-days: 5
|
||||
compression: 0
|
||||
- name: Check built binary
|
||||
shell: bash
|
||||
run: |
|
||||
rm -f ripunzip-*.tar.zst
|
||||
./ripunzip-* --version
|
||||
publish:
|
||||
needs: [versions, build]
|
||||
if: inputs.open-pr == 'true'
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
# workaround for git-lfs not being installed yet on ubuntu-slim runners
|
||||
- name: Ensure git-lfs is installed
|
||||
shell: bash
|
||||
run: |
|
||||
if which git-lfs &>/dev/null; then
|
||||
echo "git-lfs is already installed"
|
||||
exit 0
|
||||
fi
|
||||
cd $TMP
|
||||
gh release download --repo git-lfs/git-lfs --pattern "git-lfs-linux-amd64-*.tar.gz" --clobber
|
||||
tar xzf git-lfs-linux-amd64-*.tar.gz
|
||||
rm git-lfs-linux-amd64-*.tar.gz
|
||||
cd git-lfs-*
|
||||
pwd | tee -a $GITHUB_PATH
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.github
|
||||
misc/ripunzip
|
||||
lfs: true
|
||||
- name: Download built binaries
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
merge-multiple: true
|
||||
path: misc/ripunzip
|
||||
- name: Open PR
|
||||
shell: bash
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git switch -c update-ripunzip
|
||||
git add misc/ripunzip
|
||||
git commit -m "Update ripunzip binaries to version $VERSION"
|
||||
git push --set-upstream origin update-ripunzip --force
|
||||
TITLE="Update ripunzip binaries to version $VERSION"
|
||||
gh pr create \
|
||||
--draft \
|
||||
--title "$TITLE" \
|
||||
--body "Automated update of ripunzip binaries." \
|
||||
--assignee "$ACTOR" ||
|
||||
(gh pr edit --title "$TITLE" --add-assignee "$ACTOR" && gh pr ready --undo)
|
||||
env:
|
||||
ACTOR: ${{ github.actor }}
|
||||
VERSION: ${{ needs.versions.outputs.ripunzip-version }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.300
|
||||
dotnet-version: 10.0.100
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
|
||||
10
.github/workflows/csharp-qltest.yml
vendored
10
.github/workflows/csharp-qltest.yml
vendored
@@ -43,14 +43,14 @@ jobs:
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.300
|
||||
dotnet-version: 10.0.100
|
||||
- name: Extractor unit tests
|
||||
run: |
|
||||
dotnet tool restore
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.5 extractor/Semmle.Util.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.5 extractor/Semmle.Extraction.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.5 autobuilder/Semmle.Autobuild.CSharp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.5 autobuilder/Semmle.Autobuild.Cpp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=10.0.0 extractor/Semmle.Util.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=10.0.0 extractor/Semmle.Extraction.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=10.0.0 autobuilder/Semmle.Autobuild.CSharp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=10.0.0 autobuilder/Semmle.Autobuild.Cpp.Tests
|
||||
shell: bash
|
||||
stubgentest:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
32
MODULE.bazel
32
MODULE.bazel
@@ -23,10 +23,10 @@ bazel_dep(name = "rules_shell", version = "0.5.0")
|
||||
bazel_dep(name = "bazel_skylib", version = "1.8.1")
|
||||
bazel_dep(name = "abseil-cpp", version = "20240116.1", repo_name = "absl")
|
||||
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||
bazel_dep(name = "fmt", version = "10.0.0")
|
||||
bazel_dep(name = "fmt", version = "12.1.0-codeql.1")
|
||||
bazel_dep(name = "rules_kotlin", version = "2.1.3-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.40.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.19.2-codeql.1")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.21.5-codeql.1")
|
||||
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
|
||||
bazel_dep(name = "rules_rust", version = "0.66.0")
|
||||
bazel_dep(name = "zstd", version = "1.5.5.bcr.1")
|
||||
@@ -172,7 +172,7 @@ http_archive(
|
||||
)
|
||||
|
||||
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
|
||||
dotnet.toolchain(dotnet_version = "9.0.300")
|
||||
dotnet.toolchain(dotnet_version = "10.0.100")
|
||||
use_repo(dotnet, "dotnet_toolchains")
|
||||
|
||||
register_toolchains("@dotnet_toolchains//:all")
|
||||
@@ -269,24 +269,16 @@ go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
|
||||
go_deps.from_file(go_mod = "//go/extractor:go.mod")
|
||||
use_repo(go_deps, "org_golang_x_mod", "org_golang_x_tools")
|
||||
|
||||
lfs_archive = use_repo_rule("//misc/bazel:lfs.bzl", "lfs_archive")
|
||||
ripunzip_archive = use_repo_rule("//misc/ripunzip:ripunzip.bzl", "ripunzip_archive")
|
||||
|
||||
lfs_archive(
|
||||
name = "ripunzip-linux",
|
||||
src = "//misc/ripunzip:ripunzip-Linux.tar.zst",
|
||||
build_file = "//misc/ripunzip:BUILD.ripunzip.bazel",
|
||||
)
|
||||
|
||||
lfs_archive(
|
||||
name = "ripunzip-windows",
|
||||
src = "//misc/ripunzip:ripunzip-Windows.tar.zst",
|
||||
build_file = "//misc/ripunzip:BUILD.ripunzip.bazel",
|
||||
)
|
||||
|
||||
lfs_archive(
|
||||
name = "ripunzip-macos",
|
||||
src = "//misc/ripunzip:ripunzip-macOS.tar.zst",
|
||||
build_file = "//misc/ripunzip:BUILD.ripunzip.bazel",
|
||||
# go to https://github.com/GoogleChrome/ripunzip/releases to find latest version and corresponding sha256s
|
||||
ripunzip_archive(
|
||||
name = "ripunzip",
|
||||
sha256_linux = "71482d7a7e4ea9176d5596161c49250c34b136b157c45f632b1111323fbfc0de",
|
||||
sha256_macos_arm = "604194ab13f0aba3972995d995f11002b8fc285c8170401fcd46655065df20c9",
|
||||
sha256_macos_intel = "65367b94fd579d93d46f2d2595cc4c9a60cfcf497e3c824f9d1a7b80fa8bd38a",
|
||||
sha256_windows = "ac3874075def2b9e5074a3b5945005ab082cc6e689e1de658da8965bc23e643e",
|
||||
version = "2.0.4",
|
||||
)
|
||||
|
||||
register_toolchains(
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
## 0.4.24
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.23
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.22
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.21
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.20
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
* The query `actions/code-injection/medium` has been updated to include results which were incorrectly excluded while filtering out results that are reported by `actions/code-injection/critical`.
|
||||
3
actions/ql/lib/change-notes/released/0.4.21.md
Normal file
3
actions/ql/lib/change-notes/released/0.4.21.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.21
|
||||
|
||||
No user-facing changes.
|
||||
3
actions/ql/lib/change-notes/released/0.4.22.md
Normal file
3
actions/ql/lib/change-notes/released/0.4.22.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.22
|
||||
|
||||
No user-facing changes.
|
||||
3
actions/ql/lib/change-notes/released/0.4.23.md
Normal file
3
actions/ql/lib/change-notes/released/0.4.23.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.23
|
||||
|
||||
No user-facing changes.
|
||||
3
actions/ql/lib/change-notes/released/0.4.24.md
Normal file
3
actions/ql/lib/change-notes/released/0.4.24.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.24
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.20
|
||||
lastReleaseVersion: 0.4.24
|
||||
|
||||
@@ -19,12 +19,7 @@ class CodeInjectionSink extends DataFlow::Node {
|
||||
Event getRelevantCriticalEventForSink(DataFlow::Node sink) {
|
||||
inPrivilegedContext(sink.asExpr(), result) and
|
||||
not exists(ControlCheck check | check.protects(sink.asExpr(), result, "code-injection")) and
|
||||
// exclude cases where the sink is a JS script and the expression uses toJson
|
||||
not exists(UsesStep script |
|
||||
script.getCallee() = "actions/github-script" and
|
||||
script.getArgumentExpr("script") = sink.asExpr() and
|
||||
exists(getAToJsonReferenceExpression(sink.asExpr().(Expression).getExpression(), _))
|
||||
)
|
||||
not isGithubScriptUsingToJson(sink.asExpr())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,3 +86,38 @@ private module CodeInjectionConfig implements DataFlow::ConfigSig {
|
||||
|
||||
/** Tracks flow of unsafe user input that is used to construct and evaluate a code script. */
|
||||
module CodeInjectionFlow = TaintTracking::Global<CodeInjectionConfig>;
|
||||
|
||||
/**
|
||||
* Holds if there is a code injection flow from `source` to `sink` with
|
||||
* critical severity, linked by `event`.
|
||||
*/
|
||||
predicate criticalSeverityCodeInjection(
|
||||
CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink, Event event
|
||||
) {
|
||||
CodeInjectionFlow::flowPath(source, sink) and
|
||||
event = getRelevantCriticalEventForSink(sink.getNode()) and
|
||||
source.getNode().(RemoteFlowSource).getEventName() = event.getName()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a code injection flow from `source` to `sink` with medium severity.
|
||||
*/
|
||||
predicate mediumSeverityCodeInjection(
|
||||
CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink
|
||||
) {
|
||||
CodeInjectionFlow::flowPath(source, sink) and
|
||||
not criticalSeverityCodeInjection(source, sink, _) and
|
||||
not isGithubScriptUsingToJson(sink.getNode().asExpr())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `expr` is the `script` input to `actions/github-script` and it uses
|
||||
* `toJson`.
|
||||
*/
|
||||
predicate isGithubScriptUsingToJson(Expression expr) {
|
||||
exists(UsesStep script |
|
||||
script.getCallee() = "actions/github-script" and
|
||||
script.getArgumentExpr("script") = expr and
|
||||
exists(getAToJsonReferenceExpression(expr.getExpression(), _))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-all
|
||||
version: 0.4.21-dev
|
||||
version: 0.4.25-dev
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
## 0.6.16
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.15
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.14
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.13
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.12
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -20,10 +20,7 @@ import CodeInjectionFlow::PathGraph
|
||||
import codeql.actions.security.ControlChecks
|
||||
|
||||
from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink, Event event
|
||||
where
|
||||
CodeInjectionFlow::flowPath(source, sink) and
|
||||
event = getRelevantCriticalEventForSink(sink.getNode()) and
|
||||
source.getNode().(RemoteFlowSource).getEventName() = event.getName()
|
||||
where criticalSeverityCodeInjection(source, sink, event)
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential code injection in $@, which may be controlled by an external user ($@).", sink,
|
||||
sink.getNode().asExpr().(Expression).getRawExpression(), event, event.getName()
|
||||
|
||||
@@ -19,15 +19,7 @@ import codeql.actions.security.CodeInjectionQuery
|
||||
import CodeInjectionFlow::PathGraph
|
||||
|
||||
from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink
|
||||
where
|
||||
CodeInjectionFlow::flowPath(source, sink) and
|
||||
inNonPrivilegedContext(sink.getNode().asExpr()) and
|
||||
// exclude cases where the sink is a JS script and the expression uses toJson
|
||||
not exists(UsesStep script |
|
||||
script.getCallee() = "actions/github-script" and
|
||||
script.getArgumentExpr("script") = sink.getNode().asExpr() and
|
||||
exists(getAToJsonReferenceExpression(sink.getNode().asExpr().(Expression).getExpression(), _))
|
||||
)
|
||||
where mediumSeverityCodeInjection(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential code injection in $@, which may be controlled by an external user.", sink,
|
||||
sink.getNode().asExpr().(Expression).getRawExpression()
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
If a GitHub Actions job or workflow has no explicit permissions set, then the repository permissions are used. Repositories created under organizations inherit the organization permissions. The organizations or repositories created before February 2023 have the default permissions set to read-write. Often these permissions do not adhere to the principle of least privilege and can be reduced to read-only, leaving the `write` permission only to a specific types as `issues: write` or `pull-requests: write`.
|
||||
|
||||
Note that this query cannot check whether the organization or repository token settings are set to read-only. However, even if they are, it is recommended to define explicit permissions (`contents: read` and `packages: read` are equivalent to the read-only default) so that (a) the actual needs of the workflow are documented, and (b) the permissions will remain restricted if the default is subsequently changed, or the workflow is copied to a different repository or organization.
|
||||
|
||||
## Recommendation
|
||||
|
||||
Add the `permissions` key to the job or the root of workflow (in this case it is applied to all jobs in the workflow that do not have their own `permissions` key) and assign the least privileges required to complete the task.
|
||||
|
||||
3
actions/ql/src/change-notes/released/0.6.13.md
Normal file
3
actions/ql/src/change-notes/released/0.6.13.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.6.13
|
||||
|
||||
No user-facing changes.
|
||||
3
actions/ql/src/change-notes/released/0.6.14.md
Normal file
3
actions/ql/src/change-notes/released/0.6.14.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.6.14
|
||||
|
||||
No user-facing changes.
|
||||
3
actions/ql/src/change-notes/released/0.6.15.md
Normal file
3
actions/ql/src/change-notes/released/0.6.15.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.6.15
|
||||
|
||||
No user-facing changes.
|
||||
3
actions/ql/src/change-notes/released/0.6.16.md
Normal file
3
actions/ql/src/change-notes/released/0.6.16.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.6.16
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.12
|
||||
lastReleaseVersion: 0.6.16
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @name Artifact Poisoning (Path Traversal).
|
||||
* @name Artifact Poisoning (Path Traversal)
|
||||
* @description An attacker may be able to poison the workflow's artifacts and influence on consequent steps.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-queries
|
||||
version: 0.6.13-dev
|
||||
version: 0.6.17-dev
|
||||
library: false
|
||||
warnOnImplicitThis: true
|
||||
groups: [actions, queries]
|
||||
|
||||
18
actions/ql/test/query-tests/Security/CWE-094/.github/workflows/push_and_workflow_dispatch.yml
vendored
Normal file
18
actions/ql/test/query-tests/Security/CWE-094/.github/workflows/push_and_workflow_dispatch.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
echo-chamber:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo '${{ github.event.commits[11].message }}'
|
||||
- run: echo '${{ github.event.commits[11].author.email }}'
|
||||
- run: echo '${{ github.event.commits[11].author.name }}'
|
||||
- run: echo '${{ github.event.head_commit.message }}'
|
||||
- run: echo '${{ github.event.head_commit.author.email }}'
|
||||
- run: echo '${{ github.event.head_commit.author.name }}'
|
||||
- run: echo '${{ github.event.head_commit.committer.email }}'
|
||||
- run: echo '${{ github.event.head_commit.committer.name }}'
|
||||
- run: echo '${{ github.event.commits[11].committer.email }}'
|
||||
- run: echo '${{ github.event.commits[11].committer.name }}'
|
||||
@@ -435,6 +435,16 @@ nodes
|
||||
| .github/workflows/push.yml:14:19:14:64 | github.event.head_commit.committer.name | semmle.label | github.event.head_commit.committer.name |
|
||||
| .github/workflows/push.yml:15:19:15:65 | github.event.commits[11].committer.email | semmle.label | github.event.commits[11].committer.email |
|
||||
| .github/workflows/push.yml:16:19:16:64 | github.event.commits[11].committer.name | semmle.label | github.event.commits[11].committer.name |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:9:19:9:57 | github.event.commits[11].message | semmle.label | github.event.commits[11].message |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:10:19:10:62 | github.event.commits[11].author.email | semmle.label | github.event.commits[11].author.email |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:11:19:11:61 | github.event.commits[11].author.name | semmle.label | github.event.commits[11].author.name |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:12:19:12:57 | github.event.head_commit.message | semmle.label | github.event.head_commit.message |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:13:19:13:62 | github.event.head_commit.author.email | semmle.label | github.event.head_commit.author.email |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:14:19:14:61 | github.event.head_commit.author.name | semmle.label | github.event.head_commit.author.name |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:15:19:15:65 | github.event.head_commit.committer.email | semmle.label | github.event.head_commit.committer.email |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:16:19:16:64 | github.event.head_commit.committer.name | semmle.label | github.event.head_commit.committer.name |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:17:19:17:65 | github.event.commits[11].committer.email | semmle.label | github.event.commits[11].committer.email |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:18:19:18:64 | github.event.commits[11].committer.name | semmle.label | github.event.commits[11].committer.name |
|
||||
| .github/workflows/reusable-workflow-1.yml:6:7:6:11 | input taint | semmle.label | input taint |
|
||||
| .github/workflows/reusable-workflow-1.yml:36:21:36:39 | inputs.taint | semmle.label | inputs.taint |
|
||||
| .github/workflows/reusable-workflow-1.yml:44:19:44:56 | github.event.pull_request.title | semmle.label | github.event.pull_request.title |
|
||||
|
||||
@@ -435,6 +435,16 @@ nodes
|
||||
| .github/workflows/push.yml:14:19:14:64 | github.event.head_commit.committer.name | semmle.label | github.event.head_commit.committer.name |
|
||||
| .github/workflows/push.yml:15:19:15:65 | github.event.commits[11].committer.email | semmle.label | github.event.commits[11].committer.email |
|
||||
| .github/workflows/push.yml:16:19:16:64 | github.event.commits[11].committer.name | semmle.label | github.event.commits[11].committer.name |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:9:19:9:57 | github.event.commits[11].message | semmle.label | github.event.commits[11].message |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:10:19:10:62 | github.event.commits[11].author.email | semmle.label | github.event.commits[11].author.email |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:11:19:11:61 | github.event.commits[11].author.name | semmle.label | github.event.commits[11].author.name |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:12:19:12:57 | github.event.head_commit.message | semmle.label | github.event.head_commit.message |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:13:19:13:62 | github.event.head_commit.author.email | semmle.label | github.event.head_commit.author.email |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:14:19:14:61 | github.event.head_commit.author.name | semmle.label | github.event.head_commit.author.name |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:15:19:15:65 | github.event.head_commit.committer.email | semmle.label | github.event.head_commit.committer.email |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:16:19:16:64 | github.event.head_commit.committer.name | semmle.label | github.event.head_commit.committer.name |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:17:19:17:65 | github.event.commits[11].committer.email | semmle.label | github.event.commits[11].committer.email |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:18:19:18:64 | github.event.commits[11].committer.name | semmle.label | github.event.commits[11].committer.name |
|
||||
| .github/workflows/reusable-workflow-1.yml:6:7:6:11 | input taint | semmle.label | input taint |
|
||||
| .github/workflows/reusable-workflow-1.yml:36:21:36:39 | inputs.taint | semmle.label | inputs.taint |
|
||||
| .github/workflows/reusable-workflow-1.yml:44:19:44:56 | github.event.pull_request.title | semmle.label | github.event.pull_request.title |
|
||||
@@ -719,6 +729,16 @@ subpaths
|
||||
| .github/workflows/push.yml:14:19:14:64 | github.event.head_commit.committer.name | .github/workflows/push.yml:14:19:14:64 | github.event.head_commit.committer.name | .github/workflows/push.yml:14:19:14:64 | github.event.head_commit.committer.name | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push.yml:14:19:14:64 | github.event.head_commit.committer.name | ${{ github.event.head_commit.committer.name }} |
|
||||
| .github/workflows/push.yml:15:19:15:65 | github.event.commits[11].committer.email | .github/workflows/push.yml:15:19:15:65 | github.event.commits[11].committer.email | .github/workflows/push.yml:15:19:15:65 | github.event.commits[11].committer.email | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push.yml:15:19:15:65 | github.event.commits[11].committer.email | ${{ github.event.commits[11].committer.email }} |
|
||||
| .github/workflows/push.yml:16:19:16:64 | github.event.commits[11].committer.name | .github/workflows/push.yml:16:19:16:64 | github.event.commits[11].committer.name | .github/workflows/push.yml:16:19:16:64 | github.event.commits[11].committer.name | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push.yml:16:19:16:64 | github.event.commits[11].committer.name | ${{ github.event.commits[11].committer.name }} |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:9:19:9:57 | github.event.commits[11].message | .github/workflows/push_and_workflow_dispatch.yml:9:19:9:57 | github.event.commits[11].message | .github/workflows/push_and_workflow_dispatch.yml:9:19:9:57 | github.event.commits[11].message | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push_and_workflow_dispatch.yml:9:19:9:57 | github.event.commits[11].message | ${{ github.event.commits[11].message }} |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:10:19:10:62 | github.event.commits[11].author.email | .github/workflows/push_and_workflow_dispatch.yml:10:19:10:62 | github.event.commits[11].author.email | .github/workflows/push_and_workflow_dispatch.yml:10:19:10:62 | github.event.commits[11].author.email | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push_and_workflow_dispatch.yml:10:19:10:62 | github.event.commits[11].author.email | ${{ github.event.commits[11].author.email }} |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:11:19:11:61 | github.event.commits[11].author.name | .github/workflows/push_and_workflow_dispatch.yml:11:19:11:61 | github.event.commits[11].author.name | .github/workflows/push_and_workflow_dispatch.yml:11:19:11:61 | github.event.commits[11].author.name | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push_and_workflow_dispatch.yml:11:19:11:61 | github.event.commits[11].author.name | ${{ github.event.commits[11].author.name }} |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:12:19:12:57 | github.event.head_commit.message | .github/workflows/push_and_workflow_dispatch.yml:12:19:12:57 | github.event.head_commit.message | .github/workflows/push_and_workflow_dispatch.yml:12:19:12:57 | github.event.head_commit.message | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push_and_workflow_dispatch.yml:12:19:12:57 | github.event.head_commit.message | ${{ github.event.head_commit.message }} |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:13:19:13:62 | github.event.head_commit.author.email | .github/workflows/push_and_workflow_dispatch.yml:13:19:13:62 | github.event.head_commit.author.email | .github/workflows/push_and_workflow_dispatch.yml:13:19:13:62 | github.event.head_commit.author.email | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push_and_workflow_dispatch.yml:13:19:13:62 | github.event.head_commit.author.email | ${{ github.event.head_commit.author.email }} |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:14:19:14:61 | github.event.head_commit.author.name | .github/workflows/push_and_workflow_dispatch.yml:14:19:14:61 | github.event.head_commit.author.name | .github/workflows/push_and_workflow_dispatch.yml:14:19:14:61 | github.event.head_commit.author.name | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push_and_workflow_dispatch.yml:14:19:14:61 | github.event.head_commit.author.name | ${{ github.event.head_commit.author.name }} |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:15:19:15:65 | github.event.head_commit.committer.email | .github/workflows/push_and_workflow_dispatch.yml:15:19:15:65 | github.event.head_commit.committer.email | .github/workflows/push_and_workflow_dispatch.yml:15:19:15:65 | github.event.head_commit.committer.email | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push_and_workflow_dispatch.yml:15:19:15:65 | github.event.head_commit.committer.email | ${{ github.event.head_commit.committer.email }} |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:16:19:16:64 | github.event.head_commit.committer.name | .github/workflows/push_and_workflow_dispatch.yml:16:19:16:64 | github.event.head_commit.committer.name | .github/workflows/push_and_workflow_dispatch.yml:16:19:16:64 | github.event.head_commit.committer.name | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push_and_workflow_dispatch.yml:16:19:16:64 | github.event.head_commit.committer.name | ${{ github.event.head_commit.committer.name }} |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:17:19:17:65 | github.event.commits[11].committer.email | .github/workflows/push_and_workflow_dispatch.yml:17:19:17:65 | github.event.commits[11].committer.email | .github/workflows/push_and_workflow_dispatch.yml:17:19:17:65 | github.event.commits[11].committer.email | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push_and_workflow_dispatch.yml:17:19:17:65 | github.event.commits[11].committer.email | ${{ github.event.commits[11].committer.email }} |
|
||||
| .github/workflows/push_and_workflow_dispatch.yml:18:19:18:64 | github.event.commits[11].committer.name | .github/workflows/push_and_workflow_dispatch.yml:18:19:18:64 | github.event.commits[11].committer.name | .github/workflows/push_and_workflow_dispatch.yml:18:19:18:64 | github.event.commits[11].committer.name | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push_and_workflow_dispatch.yml:18:19:18:64 | github.event.commits[11].committer.name | ${{ github.event.commits[11].committer.name }} |
|
||||
| .github/workflows/reusable-workflow-1.yml:36:21:36:39 | inputs.taint | .github/workflows/reusable-workflow-caller-1.yml:11:15:11:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-1.yml:36:21:36:39 | inputs.taint | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/reusable-workflow-1.yml:36:21:36:39 | inputs.taint | ${{ inputs.taint }} |
|
||||
| .github/workflows/reusable-workflow-1.yml:53:26:53:39 | env.log | .github/workflows/reusable-workflow-1.yml:44:19:44:56 | github.event.pull_request.title | .github/workflows/reusable-workflow-1.yml:53:26:53:39 | env.log | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/reusable-workflow-1.yml:53:26:53:39 | env.log | ${{ env.log }} |
|
||||
| .github/workflows/reusable-workflow-1.yml:66:34:66:52 | env.prev_log | .github/workflows/reusable-workflow-1.yml:45:24:45:61 | github.event.changes.title.from | .github/workflows/reusable-workflow-1.yml:66:34:66:52 | env.prev_log | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/reusable-workflow-1.yml:66:34:66:52 | env.prev_log | ${{ env.prev_log }} |
|
||||
@@ -729,6 +749,10 @@ subpaths
|
||||
| .github/workflows/test10.yml:333:34:333:77 | github.event.workflow_run.head_branch | .github/workflows/test10.yml:333:34:333:77 | github.event.workflow_run.head_branch | .github/workflows/test10.yml:333:34:333:77 | github.event.workflow_run.head_branch | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test10.yml:333:34:333:77 | github.event.workflow_run.head_branch | ${{ github.event.workflow_run.head_branch }} |
|
||||
| .github/workflows/test10.yml:423:34:423:77 | github.event.workflow_run.head_branch | .github/workflows/test10.yml:423:34:423:77 | github.event.workflow_run.head_branch | .github/workflows/test10.yml:423:34:423:77 | github.event.workflow_run.head_branch | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test10.yml:423:34:423:77 | github.event.workflow_run.head_branch | ${{ github.event.workflow_run.head_branch }} |
|
||||
| .github/workflows/test10.yml:518:34:518:77 | github.event.workflow_run.head_branch | .github/workflows/test10.yml:518:34:518:77 | github.event.workflow_run.head_branch | .github/workflows/test10.yml:518:34:518:77 | github.event.workflow_run.head_branch | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test10.yml:518:34:518:77 | github.event.workflow_run.head_branch | ${{ github.event.workflow_run.head_branch }} |
|
||||
| .github/workflows/test20.yml:15:54:15:94 | github.event.pull_request.head.ref | .github/workflows/test20.yml:15:54:15:94 | github.event.pull_request.head.ref | .github/workflows/test20.yml:15:54:15:94 | github.event.pull_request.head.ref | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test20.yml:15:54:15:94 | github.event.pull_request.head.ref | ${{ github.event.pull_request.head.ref }} |
|
||||
| .github/workflows/test21.yml:22:35:22:73 | github.event.head_commit.message | .github/workflows/test21.yml:22:35:22:73 | github.event.head_commit.message | .github/workflows/test21.yml:22:35:22:73 | github.event.head_commit.message | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test21.yml:22:35:22:73 | github.event.head_commit.message | ${{ github.event.head_commit.message }} |
|
||||
| .github/workflows/test21.yml:23:36:23:74 | github.event.head_commit.message | .github/workflows/test21.yml:23:36:23:74 | github.event.head_commit.message | .github/workflows/test21.yml:23:36:23:74 | github.event.head_commit.message | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test21.yml:23:36:23:74 | github.event.head_commit.message | ${{ github.event.head_commit.message }} |
|
||||
| .github/workflows/test21.yml:24:50:24:88 | github.event.head_commit.message | .github/workflows/test21.yml:24:50:24:88 | github.event.head_commit.message | .github/workflows/test21.yml:24:50:24:88 | github.event.head_commit.message | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test21.yml:24:50:24:88 | github.event.head_commit.message | ${{ github.event.head_commit.message }} |
|
||||
| .github/workflows/workflow_run_branches1.yml:13:20:13:63 | github.event.workflow_run.head_branch | .github/workflows/workflow_run_branches1.yml:13:20:13:63 | github.event.workflow_run.head_branch | .github/workflows/workflow_run_branches1.yml:13:20:13:63 | github.event.workflow_run.head_branch | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/workflow_run_branches1.yml:13:20:13:63 | github.event.workflow_run.head_branch | ${{ github.event.workflow_run.head_branch }} |
|
||||
| .github/workflows/workflow_run_branches2.yml:13:20:13:63 | github.event.workflow_run.head_branch | .github/workflows/workflow_run_branches2.yml:13:20:13:63 | github.event.workflow_run.head_branch | .github/workflows/workflow_run_branches2.yml:13:20:13:63 | github.event.workflow_run.head_branch | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/workflow_run_branches2.yml:13:20:13:63 | github.event.workflow_run.head_branch | ${{ github.event.workflow_run.head_branch }} |
|
||||
| .github/workflows/workflow_run_branches4.yml:13:20:13:63 | github.event.workflow_run.head_branch | .github/workflows/workflow_run_branches4.yml:13:20:13:63 | github.event.workflow_run.head_branch | .github/workflows/workflow_run_branches4.yml:13:20:13:63 | github.event.workflow_run.head_branch | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/workflow_run_branches4.yml:13:20:13:63 | github.event.workflow_run.head_branch | ${{ github.event.workflow_run.head_branch }} |
|
||||
|
||||
@@ -276,5 +276,13 @@
|
||||
"Python model summaries test extension": [
|
||||
"python/ql/test/library-tests/dataflow/model-summaries/InlineTaintTest.ext.yml",
|
||||
"python/ql/test/library-tests/dataflow/model-summaries/NormalDataflowTest.ext.yml"
|
||||
],
|
||||
"XML discard predicates": [
|
||||
"javascript/ql/lib/semmle/javascript/internal/OverlayXml.qll",
|
||||
"java/ql/lib/semmle/code/java/internal/OverlayXml.qll",
|
||||
"go/ql/lib/semmle/go/internal/OverlayXml.qll",
|
||||
"python/ql/lib/semmle/python/internal/OverlayXml.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/internal/OverlayXml.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/internal/OverlayXml.qll"
|
||||
]
|
||||
}
|
||||
|
||||
2450
cpp/downgrades/1a6854060d5d3ada16c580a29f8c5ce21f3367f8/old.dbscheme
Normal file
2450
cpp/downgrades/1a6854060d5d3ada16c580a29f8c5ce21f3367f8/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Support expanded compilation argument lists
|
||||
compatibility: full
|
||||
compilation_expanded_args.rel: delete
|
||||
2469
cpp/downgrades/a42ce5fc943254097f85471b94ae2247e819104a/old.dbscheme
Normal file
2469
cpp/downgrades/a42ce5fc943254097f85471b94ae2247e819104a/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
description: Add databaseMetadata and overlayChangedFiles relations
|
||||
compatibility: full
|
||||
databaseMetadata.rel: delete
|
||||
overlayChangedFiles.rel: delete
|
||||
@@ -1,3 +1,27 @@
|
||||
## 6.1.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 6.1.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 6.1.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The class `DataFlow::FieldContent` now covers both `union` and `struct`/`class` types. A new predicate `FieldContent.getAField` has been added to access the union members associated with the `FieldContent`. The old `FieldContent` has been renamed to `NonUnionFieldContent`.
|
||||
|
||||
## 6.1.0
|
||||
|
||||
### New Features
|
||||
|
||||
* New predicates `getAnExpandedArgument` and `getExpandedArgument` were added to the `Compilation` class, yielding compilation arguments after expansion of response files.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Improve performance of the range analysis in cases where it would otherwise take an exorbitant amount of time.
|
||||
|
||||
## 6.0.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -259,8 +283,8 @@ No user-facing changes.
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* Deleted many deprecated taint-tracking configurations based on `TaintTracking::Configuration`.
|
||||
* Deleted many deprecated dataflow configurations based on `DataFlow::Configuration`.
|
||||
* Deleted many deprecated taint-tracking configurations based on `TaintTracking::Configuration`.
|
||||
* Deleted many deprecated dataflow configurations based on `DataFlow::Configuration`.
|
||||
* Deleted the deprecated `hasQualifiedName` and `isDefined` predicates from the `Declaration` class, use `hasGlobalName` and `hasDefinition` respectively instead.
|
||||
* Deleted the `getFullSignature` predicate from the `Function` class, use `getIdentityString(Declaration)` from `semmle.code.cpp.Print` instead.
|
||||
* Deleted the deprecated `freeCall` predicate from `Alloc.qll`. Use `DeallocationExpr` instead.
|
||||
@@ -294,7 +318,7 @@ No user-facing changes.
|
||||
* A `getTemplateClass` predicate was added to the `DeductionGuide` class to get the class template for which the deduction guide is a guide.
|
||||
* An `isExplicit` predicate was added to the `Function` class that determines whether the function was declared as explicit.
|
||||
* A `getExplicitExpr` predicate was added to the `Function` class that yields the constant boolean expression (if any) that conditionally determines whether the function is explicit.
|
||||
* A `isDestroyingDeleteDeallocation` predicate was added to the `NewOrNewArrayExpr` and `DeleteOrDeleteArrayExpr` classes to indicate whether the deallocation function is a destroying delete.
|
||||
* A `isDestroyingDeleteDeallocation` predicate was added to the `NewOrNewArrayExpr` and `DeleteOrDeleteArrayExpr` classes to indicate whether the deallocation function is a destroying delete.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -372,9 +396,9 @@ No user-facing changes.
|
||||
### New Features
|
||||
|
||||
* Added a `TaintInheritingContent` class that can be extended to model taint flowing from a qualifier to a field.
|
||||
* Added a predicate `GuardCondition.comparesEq/4` to query whether an expression is compared to a constant.
|
||||
* Added a predicate `GuardCondition.comparesEq/4` to query whether an expression is compared to a constant.
|
||||
* Added a predicate `GuardCondition.ensuresEq/4` to query whether a basic block is guarded by an expression being equal to a constant.
|
||||
* Added a predicate `GuardCondition.comparesLt/4` to query whether an expression is compared to a constant.
|
||||
* Added a predicate `GuardCondition.comparesLt/4` to query whether an expression is compared to a constant.
|
||||
* Added a predicate `GuardCondition.ensuresLt/4` to query whether a basic block is guarded by an expression being less than a constant.
|
||||
* Added a predicate `GuardCondition.valueControls` to query whether a basic block is guarded by a particular `case` of a `switch` statement.
|
||||
|
||||
@@ -490,7 +514,7 @@ No user-facing changes.
|
||||
* Functions that do not return due to calling functions that don't return (e.g. `exit`) are now detected as
|
||||
non-returning in the IR and dataflow.
|
||||
* Treat functions that reach the end of the function as returning in the IR.
|
||||
They used to be treated as unreachable but it is allowed in C.
|
||||
They used to be treated as unreachable but it is allowed in C.
|
||||
* The `DataFlow::asDefiningArgument` predicate now takes its argument from the range starting at `1` instead of `2`. Queries that depend on the single-parameter version of `DataFlow::asDefiningArgument` should have their arguments updated accordingly.
|
||||
|
||||
## 0.9.3
|
||||
@@ -539,7 +563,7 @@ No user-facing changes.
|
||||
|
||||
### New Features
|
||||
|
||||
* The `DataFlow::StateConfigSig` signature module has gained default implementations for `isBarrier/2` and `isAdditionalFlowStep/4`.
|
||||
* The `DataFlow::StateConfigSig` signature module has gained default implementations for `isBarrier/2` and `isAdditionalFlowStep/4`.
|
||||
Hence it is no longer needed to provide `none()` implementations of these predicates if they are not needed.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
@@ -733,7 +757,7 @@ No user-facing changes.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
|
||||
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
|
||||
The old name still exists as a deprecated alias.
|
||||
|
||||
### New Features
|
||||
@@ -750,7 +774,7 @@ No user-facing changes.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
|
||||
* Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
|
||||
The old name still exists as a deprecated alias.
|
||||
|
||||
### New Features
|
||||
@@ -849,7 +873,7 @@ No user-facing changes.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide.
|
||||
* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide.
|
||||
The old name still exists as a deprecated alias.
|
||||
|
||||
### New Features
|
||||
|
||||
9
cpp/ql/lib/change-notes/released/6.1.0.md
Normal file
9
cpp/ql/lib/change-notes/released/6.1.0.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## 6.1.0
|
||||
|
||||
### New Features
|
||||
|
||||
* New predicates `getAnExpandedArgument` and `getExpandedArgument` were added to the `Compilation` class, yielding compilation arguments after expansion of response files.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Improve performance of the range analysis in cases where it would otherwise take an exorbitant amount of time.
|
||||
5
cpp/ql/lib/change-notes/released/6.1.1.md
Normal file
5
cpp/ql/lib/change-notes/released/6.1.1.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 6.1.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The class `DataFlow::FieldContent` now covers both `union` and `struct`/`class` types. A new predicate `FieldContent.getAField` has been added to access the union members associated with the `FieldContent`. The old `FieldContent` has been renamed to `NonUnionFieldContent`.
|
||||
3
cpp/ql/lib/change-notes/released/6.1.2.md
Normal file
3
cpp/ql/lib/change-notes/released/6.1.2.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 6.1.2
|
||||
|
||||
No user-facing changes.
|
||||
3
cpp/ql/lib/change-notes/released/6.1.3.md
Normal file
3
cpp/ql/lib/change-notes/released/6.1.3.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 6.1.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 6.0.1
|
||||
lastReleaseVersion: 6.1.3
|
||||
|
||||
@@ -74,3 +74,4 @@ import semmle.code.cpp.Preprocessor
|
||||
import semmle.code.cpp.Iteration
|
||||
import semmle.code.cpp.NameQualifiers
|
||||
import DefaultOptions
|
||||
private import semmle.code.cpp.internal.Overlay
|
||||
|
||||
@@ -9,6 +9,14 @@ extensions:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sinkModel
|
||||
data: []
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: barrierModel
|
||||
data: []
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: barrierGuardModel
|
||||
data: []
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 6.0.2-dev
|
||||
version: 6.1.4-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
@@ -21,3 +21,4 @@ dataExtensions:
|
||||
- ext/deallocation/*.model.yml
|
||||
- ext/allocation/*.model.yml
|
||||
warnOnImplicitThis: true
|
||||
compileForOverlayEval: true
|
||||
|
||||
@@ -94,6 +94,25 @@ class Compilation extends @compilation {
|
||||
*/
|
||||
string getArgument(int i) { compilation_args(this, i, result) }
|
||||
|
||||
/**
|
||||
* Gets an expanded argument passed to the extractor on this invocation.
|
||||
*/
|
||||
string getAnExpandedArgument() { result = this.getExpandedArgument(_) }
|
||||
|
||||
/**
|
||||
* Gets the `i`th expanded argument passed to the extractor on this
|
||||
* invocation.
|
||||
*
|
||||
* This is similar to `getArgument`, but for a `@someFile` argument, it
|
||||
* includes the arguments from that file, rather than just taking the
|
||||
* argument literally.
|
||||
*/
|
||||
string getExpandedArgument(int i) {
|
||||
if exists(string arg | compilation_expanded_args(this, _, arg))
|
||||
then compilation_expanded_args(this, i, result)
|
||||
else result = this.getArgument(i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total amount of CPU time spent processing all the files in the
|
||||
* front-end and extractor.
|
||||
|
||||
@@ -171,12 +171,14 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
|
||||
* Gets the nth parameter of this function. There is no result for the
|
||||
* implicit `this` parameter, and there is no `...` varargs pseudo-parameter.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
Parameter getParameter(int n) { params(unresolveElement(result), underlyingElement(this), n, _) }
|
||||
|
||||
/**
|
||||
* Gets a parameter of this function. There is no result for the implicit
|
||||
* `this` parameter, and there is no `...` varargs pseudo-parameter.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
Parameter getAParameter() { params(unresolveElement(result), underlyingElement(this), _, _) }
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,16 +15,17 @@
|
||||
* reading.
|
||||
* 1. The `namespace` column selects a namespace.
|
||||
* 2. The `type` column selects a type within that namespace. This column can
|
||||
* introduce template names that can be mentioned in the `signature` column.
|
||||
* introduce template type names that can be mentioned in the `signature` column.
|
||||
* For example, `vector<T,Allocator>` introduces the template names `T` and
|
||||
* `Allocator`.
|
||||
* `Allocator`. Non-type template parameters cannot be specified.
|
||||
* 3. The `subtypes` is a boolean that indicates whether to jump to an
|
||||
* arbitrary subtype of that type. Set this to `false` if leaving the `type`
|
||||
* blank (for example, a free function).
|
||||
* 4. The `name` column optionally selects a specific named member of the type.
|
||||
* Like the `type` column, this column can introduce template names that can
|
||||
* be mentioned in the `signature` column. For example, `insert<InputIt>`
|
||||
* introduces the template name `InputIt`.
|
||||
* Like the `type` column, this column can introduce template type names
|
||||
* that can be mentioned in the `signature` column. For example,
|
||||
* `insert<InputIt>` introduces the template name `InputIt`. Non-type
|
||||
* template parameters cannot be specified.
|
||||
* 5. The `signature` column optionally restricts the named member. If
|
||||
* `signature` is blank then no such filtering is done. The format of the
|
||||
* signature is a comma-separated list of types enclosed in parentheses. The
|
||||
@@ -100,9 +101,10 @@ private import internal.FlowSummaryImpl
|
||||
private import internal.FlowSummaryImpl::Public
|
||||
private import internal.FlowSummaryImpl::Private
|
||||
private import internal.FlowSummaryImpl::Private::External
|
||||
private import internal.ExternalFlowExtensions as Extensions
|
||||
private import internal.ExternalFlowExtensions::Extensions as Extensions
|
||||
private import codeql.mad.ModelValidation as SharedModelVal
|
||||
private import codeql.util.Unit
|
||||
private import codeql.mad.static.ModelsAsData as SharedMaD
|
||||
|
||||
/**
|
||||
* A unit class for adding additional source model rows.
|
||||
@@ -143,134 +145,81 @@ predicate sinkModel(string row) { any(SinkModelCsv s).row(row) }
|
||||
/** Holds if `row` is a summary model. */
|
||||
predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
|
||||
|
||||
/** Holds if a source model exists for the given parameters. */
|
||||
predicate sourceModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string output, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string row |
|
||||
sourceModel(row) and
|
||||
row.splitAt(";", 0) = namespace and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = subtypes.toString() and
|
||||
subtypes = [true, false] and
|
||||
row.splitAt(";", 3) = name and
|
||||
row.splitAt(";", 4) = signature and
|
||||
row.splitAt(";", 5) = ext and
|
||||
row.splitAt(";", 6) = output and
|
||||
row.splitAt(";", 7) = kind
|
||||
) and
|
||||
provenance = "manual" and
|
||||
model = ""
|
||||
or
|
||||
exists(QlBuiltins::ExtensionId madId |
|
||||
Extensions::sourceModel(namespace, type, subtypes, name, signature, ext, output, kind,
|
||||
provenance, madId) and
|
||||
model = "MaD:" + madId.toString()
|
||||
)
|
||||
private module MadInput implements SharedMaD::InputSig {
|
||||
/** Holds if a source model exists for the given parameters. */
|
||||
predicate additionalSourceModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string output, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string row |
|
||||
sourceModel(row) and
|
||||
row.splitAt(";", 0) = namespace and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = subtypes.toString() and
|
||||
subtypes = [true, false] and
|
||||
row.splitAt(";", 3) = name and
|
||||
row.splitAt(";", 4) = signature and
|
||||
row.splitAt(";", 5) = ext and
|
||||
row.splitAt(";", 6) = output and
|
||||
row.splitAt(";", 7) = kind
|
||||
) and
|
||||
provenance = "manual" and
|
||||
model = ""
|
||||
}
|
||||
|
||||
/** Holds if a sink model exists for the given parameters. */
|
||||
predicate additionalSinkModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string row |
|
||||
sinkModel(row) and
|
||||
row.splitAt(";", 0) = namespace and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = subtypes.toString() and
|
||||
subtypes = [true, false] and
|
||||
row.splitAt(";", 3) = name and
|
||||
row.splitAt(";", 4) = signature and
|
||||
row.splitAt(";", 5) = ext and
|
||||
row.splitAt(";", 6) = input and
|
||||
row.splitAt(";", 7) = kind
|
||||
) and
|
||||
provenance = "manual" and
|
||||
model = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a summary model exists for the given parameters.
|
||||
*
|
||||
* This predicate does not expand `@` to `*`s.
|
||||
*/
|
||||
predicate additionalSummaryModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string output, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string row |
|
||||
summaryModel(row) and
|
||||
row.splitAt(";", 0) = namespace and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = subtypes.toString() and
|
||||
subtypes = [true, false] and
|
||||
row.splitAt(";", 3) = name and
|
||||
row.splitAt(";", 4) = signature and
|
||||
row.splitAt(";", 5) = ext and
|
||||
row.splitAt(";", 6) = input and
|
||||
row.splitAt(";", 7) = output and
|
||||
row.splitAt(";", 8) = kind
|
||||
) and
|
||||
provenance = "manual" and
|
||||
model = ""
|
||||
}
|
||||
|
||||
string namespaceSegmentSeparator() { result = "::" }
|
||||
}
|
||||
|
||||
/** Holds if a sink model exists for the given parameters. */
|
||||
predicate sinkModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string row |
|
||||
sinkModel(row) and
|
||||
row.splitAt(";", 0) = namespace and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = subtypes.toString() and
|
||||
subtypes = [true, false] and
|
||||
row.splitAt(";", 3) = name and
|
||||
row.splitAt(";", 4) = signature and
|
||||
row.splitAt(";", 5) = ext and
|
||||
row.splitAt(";", 6) = input and
|
||||
row.splitAt(";", 7) = kind
|
||||
) and
|
||||
provenance = "manual" and
|
||||
model = ""
|
||||
or
|
||||
exists(QlBuiltins::ExtensionId madId |
|
||||
Extensions::sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance,
|
||||
madId) and
|
||||
model = "MaD:" + madId.toString()
|
||||
)
|
||||
}
|
||||
private module MaD = SharedMaD::ModelsAsData<Extensions, MadInput>;
|
||||
|
||||
/**
|
||||
* Holds if a summary model exists for the given parameters.
|
||||
*
|
||||
* This predicate does not expand `@` to `*`s.
|
||||
*/
|
||||
private predicate summaryModel0(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string output, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string row |
|
||||
summaryModel(row) and
|
||||
row.splitAt(";", 0) = namespace and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = subtypes.toString() and
|
||||
subtypes = [true, false] and
|
||||
row.splitAt(";", 3) = name and
|
||||
row.splitAt(";", 4) = signature and
|
||||
row.splitAt(";", 5) = ext and
|
||||
row.splitAt(";", 6) = input and
|
||||
row.splitAt(";", 7) = output and
|
||||
row.splitAt(";", 8) = kind
|
||||
) and
|
||||
provenance = "manual" and
|
||||
model = ""
|
||||
or
|
||||
exists(QlBuiltins::ExtensionId madId |
|
||||
Extensions::summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind,
|
||||
provenance, madId) and
|
||||
model = "MaD:" + madId.toString()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given extension tuple `madId` should pretty-print as `model`.
|
||||
*
|
||||
* This predicate should only be used in tests.
|
||||
*/
|
||||
predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string output, string kind, string provenance
|
||||
|
|
||||
Extensions::sourceModel(namespace, type, subtypes, name, signature, ext, output, kind,
|
||||
provenance, madId)
|
||||
|
|
||||
model =
|
||||
"Source: " + namespace + "; " + type + "; " + subtypes + "; " + name + "; " + signature + "; "
|
||||
+ ext + "; " + output + "; " + kind + "; " + provenance
|
||||
)
|
||||
or
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string kind, string provenance
|
||||
|
|
||||
Extensions::sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance,
|
||||
madId)
|
||||
|
|
||||
model =
|
||||
"Sink: " + namespace + "; " + type + "; " + subtypes + "; " + name + "; " + signature + "; " +
|
||||
ext + "; " + input + "; " + kind + "; " + provenance
|
||||
)
|
||||
or
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string output, string kind, string provenance
|
||||
|
|
||||
Extensions::summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind,
|
||||
provenance, madId)
|
||||
|
|
||||
model =
|
||||
"Summary: " + namespace + "; " + type + "; " + subtypes + "; " + name + "; " + signature +
|
||||
"; " + ext + "; " + input + "; " + output + "; " + kind + "; " + provenance
|
||||
)
|
||||
}
|
||||
import MaD
|
||||
|
||||
/**
|
||||
* Holds if `input` is `input0`, but with all occurrences of `@` replaced
|
||||
@@ -293,69 +242,13 @@ predicate summaryModel(
|
||||
string input, string output, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string input0, string output0 |
|
||||
summaryModel0(namespace, type, subtypes, name, signature, ext, input0, output0, kind,
|
||||
MaD::summaryModel(namespace, type, subtypes, name, signature, ext, input0, output0, kind,
|
||||
provenance, model) and
|
||||
expandInputAndOutput(input0, input, output0, output,
|
||||
[0 .. Private::getMaxElementContentIndirectionIndex() - 1])
|
||||
)
|
||||
}
|
||||
|
||||
private predicate relevantNamespace(string namespace) {
|
||||
sourceModel(namespace, _, _, _, _, _, _, _, _, _) or
|
||||
sinkModel(namespace, _, _, _, _, _, _, _, _, _) or
|
||||
summaryModel(namespace, _, _, _, _, _, _, _, _, _, _)
|
||||
}
|
||||
|
||||
private predicate namespaceLink(string shortns, string longns) {
|
||||
relevantNamespace(shortns) and
|
||||
relevantNamespace(longns) and
|
||||
longns.prefix(longns.indexOf("::")) = shortns
|
||||
}
|
||||
|
||||
private predicate canonicalNamespace(string namespace) {
|
||||
relevantNamespace(namespace) and not namespaceLink(_, namespace)
|
||||
}
|
||||
|
||||
private predicate canonicalNamespaceLink(string namespace, string subns) {
|
||||
canonicalNamespace(namespace) and
|
||||
(subns = namespace or namespaceLink(namespace, subns))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if MaD framework coverage of `namespace` is `n` api endpoints of the
|
||||
* kind `(kind, part)`, and `namespaces` is the number of subnamespaces of
|
||||
* `namespace` which have MaD framework coverage (including `namespace`
|
||||
* itself).
|
||||
*/
|
||||
predicate modelCoverage(string namespace, int namespaces, string kind, string part, int n) {
|
||||
namespaces = strictcount(string subns | canonicalNamespaceLink(namespace, subns)) and
|
||||
(
|
||||
part = "source" and
|
||||
n =
|
||||
strictcount(string subns, string type, boolean subtypes, string name, string signature,
|
||||
string ext, string output, string provenance, string model |
|
||||
canonicalNamespaceLink(namespace, subns) and
|
||||
sourceModel(subns, type, subtypes, name, signature, ext, output, kind, provenance, model)
|
||||
)
|
||||
or
|
||||
part = "sink" and
|
||||
n =
|
||||
strictcount(string subns, string type, boolean subtypes, string name, string signature,
|
||||
string ext, string input, string provenance, string model |
|
||||
canonicalNamespaceLink(namespace, subns) and
|
||||
sinkModel(subns, type, subtypes, name, signature, ext, input, kind, provenance, model)
|
||||
)
|
||||
or
|
||||
part = "summary" and
|
||||
n =
|
||||
strictcount(string subns, string type, boolean subtypes, string name, string signature,
|
||||
string ext, string input, string output, string provenance |
|
||||
canonicalNamespaceLink(namespace, subns) and
|
||||
summaryModel(subns, type, subtypes, name, signature, ext, input, output, kind, provenance, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Provides a query predicate to check the CSV data for validation errors. */
|
||||
module CsvValidation {
|
||||
private string getInvalidModelInput() {
|
||||
@@ -633,6 +526,28 @@ string getParameterTypeWithoutTemplateArguments(Function f, int n, boolean canon
|
||||
canonical = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the largest index of a template parameter of `templateFunction` that
|
||||
* is a type template parameter.
|
||||
*/
|
||||
private int getLastTypeTemplateFunctionParameterIndex(Function templateFunction) {
|
||||
result =
|
||||
max(int index | templateFunction.getTemplateArgument(index) instanceof TypeTemplateParameter)
|
||||
}
|
||||
|
||||
/** Gets the number of supported template parameters for `templateFunction`. */
|
||||
private int getNumberOfSupportedFunctionTemplateArguments(Function templateFunction) {
|
||||
result = count(int i | exists(getSupportedFunctionTemplateArgument(templateFunction, i)) | i)
|
||||
}
|
||||
|
||||
/** Gets the `i`'th supported template parameter for `templateFunction`. */
|
||||
private Locatable getSupportedFunctionTemplateArgument(Function templateFunction, int i) {
|
||||
result = templateFunction.getTemplateArgument(i) and
|
||||
// We don't yet support non-type template parameters in the middle of a
|
||||
// template parameter list
|
||||
i <= getLastTypeTemplateFunctionParameterIndex(templateFunction)
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the `n`'th parameter of `f` by replacing template names
|
||||
* with `func:N` (where `N` is the index of the template).
|
||||
@@ -640,18 +555,41 @@ string getParameterTypeWithoutTemplateArguments(Function f, int n, boolean canon
|
||||
private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remaining) {
|
||||
exists(Function templateFunction |
|
||||
templateFunction = getFullyTemplatedFunction(f) and
|
||||
remaining = templateFunction.getNumberOfTemplateArguments() and
|
||||
remaining = getNumberOfSupportedFunctionTemplateArguments(templateFunction) and
|
||||
result = getParameterTypeWithoutTemplateArguments(templateFunction, n, _)
|
||||
)
|
||||
or
|
||||
exists(string mid, TypeTemplateParameter tp, Function templateFunction |
|
||||
mid = getTypeNameWithoutFunctionTemplates(f, n, remaining + 1) and
|
||||
templateFunction = getFullyTemplatedFunction(f) and
|
||||
tp = templateFunction.getTemplateArgument(remaining) and
|
||||
tp = getSupportedFunctionTemplateArgument(templateFunction, remaining)
|
||||
|
|
||||
result = mid.replaceAll(tp.getName(), "func:" + remaining.toString())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the largest index of a template parameter of `templateClass` that
|
||||
* is a type template parameter.
|
||||
*/
|
||||
private int getLastTypeTemplateClassParameterIndex(Class templateClass) {
|
||||
result =
|
||||
max(int index | templateClass.getTemplateArgument(index) instanceof TypeTemplateParameter)
|
||||
}
|
||||
|
||||
/** Gets the `i`'th supported template parameter for `templateClass`. */
|
||||
private Locatable getSupportedClassTemplateArgument(Class templateClass, int i) {
|
||||
result = templateClass.getTemplateArgument(i) and
|
||||
// We don't yet support non-type template parameters in the middle of a
|
||||
// template parameter list
|
||||
i <= getLastTypeTemplateClassParameterIndex(templateClass)
|
||||
}
|
||||
|
||||
/** Gets the number of supported template parameters for `templateClass`. */
|
||||
private int getNumberOfSupportedClassTemplateArguments(Class templateClass) {
|
||||
result = count(int i | exists(getSupportedClassTemplateArgument(templateClass, i)) | i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the `n`'th parameter of `f` by replacing template names
|
||||
* with `class:N` (where `N` is the index of the template).
|
||||
@@ -661,7 +599,7 @@ private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining
|
||||
// If there is a declaring type then we start by expanding the function templates
|
||||
exists(Class template |
|
||||
isClassConstructedFrom(f.getDeclaringType(), template) and
|
||||
remaining = template.getNumberOfTemplateArguments() and
|
||||
remaining = getNumberOfSupportedClassTemplateArguments(template) and
|
||||
result = getTypeNameWithoutFunctionTemplates(f, n, 0)
|
||||
)
|
||||
or
|
||||
@@ -673,7 +611,8 @@ private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining
|
||||
exists(string mid, TypeTemplateParameter tp, Class template |
|
||||
mid = getTypeNameWithoutClassTemplates(f, n, remaining + 1) and
|
||||
isClassConstructedFrom(f.getDeclaringType(), template) and
|
||||
tp = template.getTemplateArgument(remaining) and
|
||||
tp = getSupportedClassTemplateArgument(template, remaining)
|
||||
|
|
||||
result = mid.replaceAll(tp.getName(), "class:" + remaining.toString())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* This module provides extensible predicates for defining MaD models.
|
||||
*/
|
||||
|
||||
private import codeql.mad.static.ModelsAsData as SharedMaD
|
||||
|
||||
/**
|
||||
* Holds if an external source model exists for the given parameters.
|
||||
*/
|
||||
@@ -18,6 +20,22 @@ extensible predicate sinkModel(
|
||||
string input, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if a barrier model exists for the given parameters.
|
||||
*/
|
||||
extensible predicate barrierModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string output, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if a barrier guard model exists for the given parameters.
|
||||
*/
|
||||
extensible predicate barrierGuardModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string acceptingvalue, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if an external summary model exists for the given parameters.
|
||||
*/
|
||||
@@ -25,3 +43,16 @@ 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
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if a neutral model exists for the given parameters.
|
||||
*/
|
||||
extensible predicate neutralModel(
|
||||
string namespace, string type, string name, string signature, string kind, string provenance
|
||||
);
|
||||
|
||||
module Extensions implements SharedMaD::ExtensionsSig {
|
||||
import ExternalFlowExtensions
|
||||
|
||||
predicate namespaceGrouping(string group, string namespace) { none() }
|
||||
}
|
||||
|
||||
@@ -148,6 +148,19 @@ module SourceSinkInterpretationInput implements
|
||||
)
|
||||
}
|
||||
|
||||
predicate barrierElement(
|
||||
Element n, string output, string kind, Public::Provenance provenance, string model
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
predicate barrierGuardElement(
|
||||
Element n, string input, Public::AcceptingValue acceptingvalue, string kind,
|
||||
Public::Provenance provenance, string model
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
private newtype TInterpretNode =
|
||||
TElement_(Element n) or
|
||||
TNode_(Node n)
|
||||
|
||||
@@ -750,6 +750,16 @@ class SizeofPackTypeOperator extends SizeofPackOperator {
|
||||
*/
|
||||
class SizeofOperator extends Expr, @runtime_sizeof {
|
||||
override int getPrecedence() { result = 16 }
|
||||
|
||||
/**
|
||||
* Gets the contained type of this `sizeof`. For example,
|
||||
* the result is `int` in both cases below:
|
||||
* ```
|
||||
* sizeof(int);
|
||||
* sizeof(42);
|
||||
* ```
|
||||
*/
|
||||
Type getTypeOperand() { none() } // overridden in subclasses
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -766,6 +776,8 @@ class SizeofExprOperator extends SizeofOperator {
|
||||
/** Gets the contained expression. */
|
||||
Expr getExprOperand() { result = this.getChild(0) }
|
||||
|
||||
override Type getTypeOperand() { result = this.getExprOperand().getType() }
|
||||
|
||||
override string toString() { result = "sizeof(<expr>)" }
|
||||
|
||||
override predicate mayBeImpure() { this.getExprOperand().mayBeImpure() }
|
||||
@@ -784,8 +796,7 @@ class SizeofTypeOperator extends SizeofOperator {
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SizeofTypeOperator" }
|
||||
|
||||
/** Gets the contained type. */
|
||||
Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
override Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
override string toString() { result = "sizeof(" + this.getTypeOperand().getName() + ")" }
|
||||
|
||||
@@ -842,6 +853,16 @@ class AlignofTypeOperator extends AlignofOperator {
|
||||
*/
|
||||
class DatasizeofOperator extends Expr, @datasizeof {
|
||||
override int getPrecedence() { result = 16 }
|
||||
|
||||
/**
|
||||
* Gets the contained type of this `__datasizeof`. For example,
|
||||
* the result is `int` in both cases below:
|
||||
* ```
|
||||
* __datasizeof(int);
|
||||
* __datasizeof(42);
|
||||
* ```
|
||||
*/
|
||||
Type getTypeOperand() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -855,6 +876,8 @@ class DatasizeofExprOperator extends DatasizeofOperator {
|
||||
/** Gets the contained expression. */
|
||||
Expr getExprOperand() { result = this.getChild(0) }
|
||||
|
||||
override Type getTypeOperand() { result = this.getExprOperand().getType() }
|
||||
|
||||
override string toString() { result = "__datasizeof(<expr>)" }
|
||||
|
||||
override predicate mayBeImpure() { this.getExprOperand().mayBeImpure() }
|
||||
@@ -870,8 +893,7 @@ class DatasizeofTypeOperator extends DatasizeofOperator {
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DatasizeofTypeOperator" }
|
||||
|
||||
/** Gets the contained type. */
|
||||
Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
override Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
override string toString() { result = "__datasizeof(" + this.getTypeOperand().getName() + ")" }
|
||||
|
||||
|
||||
80
cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll
Normal file
80
cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Defines entity discard predicates for C++ overlay analysis.
|
||||
*/
|
||||
|
||||
private import OverlayXml
|
||||
|
||||
/**
|
||||
* Holds always for the overlay variant and never for the base variant.
|
||||
* This local predicate is used to define local predicates that behave
|
||||
* differently for the base and overlay variant.
|
||||
*/
|
||||
overlay[local]
|
||||
predicate isOverlay() { databaseMetadata("isOverlay", "true") }
|
||||
|
||||
overlay[local]
|
||||
private string getLocationFilePath(@location_default loc) {
|
||||
exists(@file file | locations_default(loc, file, _, _, _, _) | files(file, result))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file path for an element with a single location.
|
||||
*/
|
||||
overlay[local]
|
||||
private string getSingleLocationFilePath(@element e) {
|
||||
exists(@location_default loc |
|
||||
var_decls(e, _, _, _, loc)
|
||||
or
|
||||
fun_decls(e, _, _, _, loc)
|
||||
or
|
||||
type_decls(e, _, loc)
|
||||
or
|
||||
namespace_decls(e, _, loc, _)
|
||||
or
|
||||
macroinvocations(e, _, loc, _)
|
||||
or
|
||||
preprocdirects(e, _, loc)
|
||||
|
|
||||
result = getLocationFilePath(loc)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file path for an element with potentially multiple locations.
|
||||
*/
|
||||
overlay[local]
|
||||
private string getMultiLocationFilePath(@element e) {
|
||||
exists(@location_default loc |
|
||||
exists(@var_decl vd | var_decls(vd, e, _, _, loc))
|
||||
or
|
||||
exists(@fun_decl fd | fun_decls(fd, e, _, _, loc))
|
||||
or
|
||||
exists(@type_decl td | type_decls(td, e, loc))
|
||||
or
|
||||
exists(@namespace_decl nd | namespace_decls(nd, e, loc, _))
|
||||
|
|
||||
result = getLocationFilePath(loc)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A local helper predicate that holds in the base variant and never in the
|
||||
* overlay variant.
|
||||
*/
|
||||
overlay[local]
|
||||
private predicate holdsInBase() { not isOverlay() }
|
||||
|
||||
/**
|
||||
* Discards an element from the base variant if:
|
||||
* - It has a single location in a changed file, or
|
||||
* - All of its locations are in changed files.
|
||||
*/
|
||||
overlay[discard_entity]
|
||||
private predicate discardElement(@element e) {
|
||||
holdsInBase() and
|
||||
(
|
||||
overlayChangedFiles(getSingleLocationFilePath(e))
|
||||
or
|
||||
forex(string path | path = getMultiLocationFilePath(e) | overlayChangedFiles(path))
|
||||
)
|
||||
}
|
||||
46
cpp/ql/lib/semmle/code/cpp/internal/OverlayXml.qll
Normal file
46
cpp/ql/lib/semmle/code/cpp/internal/OverlayXml.qll
Normal file
@@ -0,0 +1,46 @@
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
/**
|
||||
* A local predicate that always holds for the overlay variant and never holds for the base variant.
|
||||
* This is used to define local predicates that behave differently for the base and overlay variant.
|
||||
*/
|
||||
private predicate isOverlay() { databaseMetadata("isOverlay", "true") }
|
||||
|
||||
private string getXmlFile(@xmllocatable locatable) {
|
||||
exists(@location_default location, @file file | xmllocations(locatable, location) |
|
||||
locations_default(location, file, _, _, _, _) and
|
||||
files(file, result)
|
||||
)
|
||||
}
|
||||
|
||||
private string getXmlFileInBase(@xmllocatable locatable) {
|
||||
not isOverlay() and
|
||||
result = getXmlFile(locatable)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given `file` was extracted as part of the overlay and was extracted by the HTML/XML
|
||||
* extractor.
|
||||
*/
|
||||
private predicate overlayXmlExtracted(string file) {
|
||||
isOverlay() and
|
||||
exists(@xmllocatable locatable |
|
||||
not files(locatable, _) and not xmlNs(locatable, _, _, _) and file = getXmlFile(locatable)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given XML `locatable` should be discarded, because it is part of the overlay base
|
||||
* and is in a file that was also extracted as part of the overlay database.
|
||||
*/
|
||||
overlay[discard_entity]
|
||||
private predicate discardXmlLocatable(@xmllocatable locatable) {
|
||||
exists(string file | file = getXmlFileInBase(locatable) |
|
||||
overlayChangedFiles(file)
|
||||
or
|
||||
// The HTML/XML extractor is currently not incremental and may extract more files than those
|
||||
// included in overlayChangedFiles.
|
||||
overlayXmlExtracted(file)
|
||||
)
|
||||
}
|
||||
@@ -861,6 +861,10 @@ predicate jumpStep(Node n1, Node n2) {
|
||||
n2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
bindingset[c]
|
||||
pragma[inline_late]
|
||||
private int getIndirectionIndexLate(Content c) { result = c.getIndirectionIndex() }
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
@@ -873,23 +877,17 @@ predicate jumpStep(Node n1, Node n2) {
|
||||
predicate storeStepImpl(Node node1, Content c, Node node2, boolean certain) {
|
||||
exists(
|
||||
PostFieldUpdateNode postFieldUpdate, int indirectionIndex1, int numberOfLoads,
|
||||
StoreInstruction store
|
||||
StoreInstruction store, FieldContent fc
|
||||
|
|
||||
postFieldUpdate = node2 and
|
||||
nodeHasInstruction(node1, store, pragma[only_bind_into](indirectionIndex1)) and
|
||||
fc = c and
|
||||
nodeHasInstruction(node1, pragma[only_bind_into](store),
|
||||
pragma[only_bind_into](indirectionIndex1)) and
|
||||
postFieldUpdate.getIndirectionIndex() = 1 and
|
||||
numberOfLoadsFromOperand(postFieldUpdate.getFieldAddress(),
|
||||
store.getDestinationAddressOperand(), numberOfLoads, certain)
|
||||
|
|
||||
exists(FieldContent fc | fc = c |
|
||||
fc.getField() = postFieldUpdate.getUpdatedField() and
|
||||
fc.getIndirectionIndex() = 1 + indirectionIndex1 + numberOfLoads
|
||||
)
|
||||
or
|
||||
exists(UnionContent uc | uc = c |
|
||||
uc.getAField() = postFieldUpdate.getUpdatedField() and
|
||||
uc.getIndirectionIndex() = 1 + indirectionIndex1 + numberOfLoads
|
||||
)
|
||||
store.getDestinationAddressOperand(), numberOfLoads, certain) and
|
||||
fc.getAField() = postFieldUpdate.getUpdatedField() and
|
||||
getIndirectionIndexLate(fc) = 1 + indirectionIndex1 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
@@ -965,22 +963,17 @@ predicate nodeHasInstruction(Node node, Instruction instr, int indirectionIndex)
|
||||
* `node2`.
|
||||
*/
|
||||
predicate readStep(Node node1, ContentSet c, Node node2) {
|
||||
exists(FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2 |
|
||||
exists(
|
||||
FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2, FieldContent fc
|
||||
|
|
||||
fc = c and
|
||||
nodeHasOperand(node2, operand, indirectionIndex2) and
|
||||
// The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct
|
||||
// in `storeStep`.
|
||||
nodeHasOperand(node1, fa1.getObjectAddressOperand(), 1) and
|
||||
numberOfLoadsFromOperand(fa1, operand, numberOfLoads, _)
|
||||
|
|
||||
exists(FieldContent fc | fc = c |
|
||||
fc.getField() = fa1.getField() and
|
||||
fc.getIndirectionIndex() = indirectionIndex2 + numberOfLoads
|
||||
)
|
||||
or
|
||||
exists(UnionContent uc | uc = c |
|
||||
uc.getAField() = fa1.getField() and
|
||||
uc.getIndirectionIndex() = indirectionIndex2 + numberOfLoads
|
||||
)
|
||||
numberOfLoadsFromOperand(fa1, operand, numberOfLoads, _) and
|
||||
fc.getAField() = fa1.getField() and
|
||||
getIndirectionIndexLate(fc) = indirectionIndex2 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
@@ -1574,7 +1567,7 @@ pragma[inline]
|
||||
ContentApprox getContentApprox(Content c) {
|
||||
exists(string prefix, Field f |
|
||||
prefix = result.(FieldApproxContent).getPrefix() and
|
||||
f = c.(FieldContent).getField() and
|
||||
f = c.(NonUnionFieldContent).getField() and
|
||||
fieldHasApproxName(f, prefix)
|
||||
)
|
||||
or
|
||||
|
||||
@@ -2078,38 +2078,151 @@ predicate localExprFlow(Expr e1, Expr e2) {
|
||||
localExprFlowPlus(e1, e2)
|
||||
}
|
||||
|
||||
/**
|
||||
* A canonical representation of a field.
|
||||
*
|
||||
* For performance reasons we want a unique `Content` that represents
|
||||
* a given field across any template instantiation of a class.
|
||||
*
|
||||
* This is possible in _almost_ all cases, but there are cases where it is
|
||||
* not possible to map between a field in the uninstantiated template to a
|
||||
* field in the instantiated template. This happens in the case of local class
|
||||
* definitions (because the local class is not the template that constructs
|
||||
* the instantiation - it is the enclosing function). So this abstract class
|
||||
* has two implementations: a non-local case (where we can represent a
|
||||
* canonical field as the field declaration from an uninstantiated class
|
||||
* template or a non-templated class), and a local case (where we simply use
|
||||
* the field from the instantiated class).
|
||||
*/
|
||||
abstract private class CanonicalField extends Field {
|
||||
/** Gets a field represented by this canonical field. */
|
||||
abstract Field getAField();
|
||||
|
||||
/**
|
||||
* Gets a class that declares a field represented by this canonical field.
|
||||
*/
|
||||
abstract Class getADeclaringType();
|
||||
|
||||
/**
|
||||
* Gets a type that this canonical field may have. Note that this may
|
||||
* not be a unique type. For example, consider this case:
|
||||
* ```
|
||||
* template<typename T>
|
||||
* struct S { T x; };
|
||||
*
|
||||
* S<int> s1;
|
||||
* S<char> s2;
|
||||
* ```
|
||||
* In this case the canonical field corresponding to `S::x` has two types:
|
||||
* `int` and `char`.
|
||||
*/
|
||||
Type getAType() { result = this.getAField().getType() }
|
||||
|
||||
Type getAnUnspecifiedType() { result = this.getAType().getUnspecifiedType() }
|
||||
}
|
||||
|
||||
private class NonLocalCanonicalField extends CanonicalField {
|
||||
Class declaringType;
|
||||
|
||||
NonLocalCanonicalField() {
|
||||
declaringType = this.getDeclaringType() and
|
||||
not declaringType.isFromTemplateInstantiation(_) and
|
||||
not declaringType.isLocal() // handled in LocalCanonicalField
|
||||
}
|
||||
|
||||
override Field getAField() {
|
||||
exists(Class c | result.getDeclaringType() = c |
|
||||
// Either the declaring class of the field is a template instantiation
|
||||
// that has been constructed from this canonical declaration
|
||||
c.isConstructedFrom(declaringType) and
|
||||
pragma[only_bind_out](result.getName()) = pragma[only_bind_out](this.getName())
|
||||
or
|
||||
// or this canonical declaration is not a template.
|
||||
not c.isConstructedFrom(_) and
|
||||
result = this
|
||||
)
|
||||
}
|
||||
|
||||
override Class getADeclaringType() {
|
||||
result = this.getDeclaringType()
|
||||
or
|
||||
result.isConstructedFrom(this.getDeclaringType())
|
||||
}
|
||||
}
|
||||
|
||||
private class LocalCanonicalField extends CanonicalField {
|
||||
Class declaringType;
|
||||
|
||||
LocalCanonicalField() {
|
||||
declaringType = this.getDeclaringType() and
|
||||
declaringType.isLocal()
|
||||
}
|
||||
|
||||
override Field getAField() { result = this }
|
||||
|
||||
override Class getADeclaringType() { result = declaringType }
|
||||
}
|
||||
|
||||
/**
|
||||
* A canonical representation of a `Union`. See `CanonicalField` for the explanation for
|
||||
* why we need a canonical representation.
|
||||
*/
|
||||
abstract private class CanonicalUnion extends Union {
|
||||
/** Gets a union represented by this canonical union. */
|
||||
abstract Union getAUnion();
|
||||
|
||||
/** Gets a canonical field of this canonical union. */
|
||||
CanonicalField getACanonicalField() { result.getDeclaringType() = this }
|
||||
}
|
||||
|
||||
private class NonLocalCanonicalUnion extends CanonicalUnion {
|
||||
NonLocalCanonicalUnion() { not this.isFromTemplateInstantiation(_) and not this.isLocal() }
|
||||
|
||||
override Union getAUnion() {
|
||||
result = this
|
||||
or
|
||||
result.isConstructedFrom(this)
|
||||
}
|
||||
}
|
||||
|
||||
private class LocalCanonicalUnion extends CanonicalUnion {
|
||||
LocalCanonicalUnion() { this.isLocal() }
|
||||
|
||||
override Union getAUnion() { result = this }
|
||||
}
|
||||
|
||||
bindingset[f]
|
||||
pragma[inline_late]
|
||||
private int getFieldSize(Field f) { result = f.getType().getSize() }
|
||||
private int getFieldSize(CanonicalField f) { result = max(f.getAType().getSize()) }
|
||||
|
||||
/**
|
||||
* Gets a field in the union `u` whose size
|
||||
* is `bytes` number of bytes.
|
||||
*/
|
||||
private Field getAFieldWithSize(Union u, int bytes) {
|
||||
result = u.getAField() and
|
||||
private CanonicalField getAFieldWithSize(CanonicalUnion u, int bytes) {
|
||||
result = u.getACanonicalField() and
|
||||
bytes = getFieldSize(result)
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TContent =
|
||||
TFieldContent(Field f, int indirectionIndex) {
|
||||
// the indirection index for field content starts at 1 (because `TFieldContent` is thought of as
|
||||
TNonUnionContent(CanonicalField f, int indirectionIndex) {
|
||||
// the indirection index for field content starts at 1 (because `TNonUnionContent` is thought of as
|
||||
// the address of the field, `FieldAddress` in the IR).
|
||||
indirectionIndex = [1 .. SsaImpl::getMaxIndirectionsForType(f.getUnspecifiedType())] and
|
||||
indirectionIndex = [1 .. max(SsaImpl::getMaxIndirectionsForType(f.getAnUnspecifiedType()))] and
|
||||
// Reads and writes of union fields are tracked using `UnionContent`.
|
||||
not f.getDeclaringType() instanceof Union
|
||||
} or
|
||||
TUnionContent(Union u, int bytes, int indirectionIndex) {
|
||||
exists(Field f |
|
||||
f = u.getAField() and
|
||||
TUnionContent(CanonicalUnion u, int bytes, int indirectionIndex) {
|
||||
exists(CanonicalField f |
|
||||
f = u.getACanonicalField() and
|
||||
bytes = getFieldSize(f) and
|
||||
// We key `UnionContent` by the union instead of its fields since a write to one
|
||||
// field can be read by any read of the union's fields. Again, the indirection index
|
||||
// is 1-based (because 0 is considered the address).
|
||||
indirectionIndex =
|
||||
[1 .. max(SsaImpl::getMaxIndirectionsForType(getAFieldWithSize(u, bytes)
|
||||
.getUnspecifiedType())
|
||||
.getAnUnspecifiedType())
|
||||
)]
|
||||
)
|
||||
} or
|
||||
@@ -2124,14 +2237,14 @@ private newtype TContent =
|
||||
*/
|
||||
class Content extends TContent {
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
string toString() { none() } // overridden in subclasses
|
||||
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0
|
||||
}
|
||||
|
||||
/** Gets the indirection index of this `Content`. */
|
||||
abstract int getIndirectionIndex();
|
||||
int getIndirectionIndex() { none() } // overridden in subclasses
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
@@ -2142,7 +2255,7 @@ class Content extends TContent {
|
||||
* For example, a write to a field `f` implies that any content of
|
||||
* the form `*f` is also cleared.
|
||||
*/
|
||||
abstract predicate impliesClearOf(Content c);
|
||||
predicate impliesClearOf(Content c) { none() } // overridden in subclasses
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2162,37 +2275,62 @@ private module ContentStars {
|
||||
|
||||
private import ContentStars
|
||||
|
||||
/** A reference through a non-union instance field. */
|
||||
private class TFieldContent = TNonUnionContent or TUnionContent;
|
||||
|
||||
/**
|
||||
* A `Content` that references a `Field`. This may be a field of a `struct`,
|
||||
* `class`, or `union`. In the case of a `union` there may be multiple fields
|
||||
* associated with the same `Content`.
|
||||
*/
|
||||
class FieldContent extends Content, TFieldContent {
|
||||
private Field f;
|
||||
/** Gets a `Field` of this `Content`. */
|
||||
Field getAField() { none() }
|
||||
|
||||
/**
|
||||
* Gets the field associated with this `Content`, if a unique one exists.
|
||||
*
|
||||
* For fields from template instantiations this predicate may still return
|
||||
* more than one field, but all the fields will be constructed from the same
|
||||
* template.
|
||||
*/
|
||||
Field getField() { none() } // overridden in subclasses
|
||||
|
||||
override int getIndirectionIndex() { none() } // overridden in subclasses
|
||||
|
||||
override string toString() { none() } // overridden in subclasses
|
||||
|
||||
override predicate impliesClearOf(Content c) { none() } // overridden in subclasses
|
||||
}
|
||||
|
||||
/** A reference through a non-union instance field. */
|
||||
class NonUnionFieldContent extends FieldContent, TNonUnionContent {
|
||||
private CanonicalField f;
|
||||
private int indirectionIndex;
|
||||
|
||||
FieldContent() { this = TFieldContent(f, indirectionIndex) }
|
||||
NonUnionFieldContent() { this = TNonUnionContent(f, indirectionIndex) }
|
||||
|
||||
override string toString() { result = contentStars(this) + f.toString() }
|
||||
|
||||
Field getField() { result = f }
|
||||
final override Field getField() { result = f.getAField() }
|
||||
|
||||
override Field getAField() { result = this.getField() }
|
||||
|
||||
/** Gets the indirection index of this `FieldContent`. */
|
||||
pragma[inline]
|
||||
override int getIndirectionIndex() {
|
||||
pragma[only_bind_into](result) = pragma[only_bind_out](indirectionIndex)
|
||||
}
|
||||
override int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
override predicate impliesClearOf(Content c) {
|
||||
exists(FieldContent fc |
|
||||
fc = c and
|
||||
fc.getField() = f and
|
||||
exists(int i |
|
||||
c = TNonUnionContent(f, i) and
|
||||
// If `this` is `f` then `c` is cleared if it's of the
|
||||
// form `*f`, `**f`, etc.
|
||||
fc.getIndirectionIndex() >= indirectionIndex
|
||||
i >= indirectionIndex
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A reference through an instance field of a union. */
|
||||
class UnionContent extends Content, TUnionContent {
|
||||
private Union u;
|
||||
class UnionContent extends FieldContent, TUnionContent {
|
||||
private CanonicalUnion u;
|
||||
private int indirectionIndex;
|
||||
private int bytes;
|
||||
|
||||
@@ -2200,27 +2338,31 @@ class UnionContent extends Content, TUnionContent {
|
||||
|
||||
override string toString() { result = contentStars(this) + u.toString() }
|
||||
|
||||
final override Field getField() { result = unique( | | u.getACanonicalField()).getAField() }
|
||||
|
||||
/** Gets a field of the underlying union of this `UnionContent`, if any. */
|
||||
Field getAField() { result = u.getAField() and getFieldSize(result) = bytes }
|
||||
|
||||
/** Gets the underlying union of this `UnionContent`. */
|
||||
Union getUnion() { result = u }
|
||||
|
||||
/** Gets the indirection index of this `UnionContent`. */
|
||||
pragma[inline]
|
||||
override int getIndirectionIndex() {
|
||||
pragma[only_bind_into](result) = pragma[only_bind_out](indirectionIndex)
|
||||
override Field getAField() {
|
||||
exists(CanonicalField cf |
|
||||
cf = u.getACanonicalField() and
|
||||
result = cf.getAField() and
|
||||
getFieldSize(cf) = bytes
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the underlying union of this `UnionContent`. */
|
||||
Union getUnion() { result = u.getAUnion() }
|
||||
|
||||
/** Gets the indirection index of this `UnionContent`. */
|
||||
override int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
override predicate impliesClearOf(Content c) {
|
||||
exists(UnionContent uc |
|
||||
uc = c and
|
||||
uc.getUnion() = u and
|
||||
exists(int i |
|
||||
c = TUnionContent(u, _, i) and
|
||||
// If `this` is `u` then `c` is cleared if it's of the
|
||||
// form `*u`, `**u`, etc. (and we ignore `bytes` because
|
||||
// we know the entire union is overwritten because it's a
|
||||
// union).
|
||||
uc.getIndirectionIndex() >= indirectionIndex
|
||||
i >= indirectionIndex
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2234,10 +2376,7 @@ class ElementContent extends Content, TElementContent {
|
||||
|
||||
ElementContent() { this = TElementContent(indirectionIndex) }
|
||||
|
||||
pragma[inline]
|
||||
override int getIndirectionIndex() {
|
||||
pragma[only_bind_into](result) = pragma[only_bind_out](indirectionIndex)
|
||||
}
|
||||
override int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
override predicate impliesClearOf(Content c) { none() }
|
||||
|
||||
|
||||
@@ -1051,12 +1051,12 @@ module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
|
||||
}
|
||||
|
||||
private predicate guardChecksInstr(
|
||||
IRGuards::Guards_v1::Guard g, IRGuards::GuardsInput::Expr instr, boolean branch,
|
||||
IRGuards::Guards_v1::Guard g, IRGuards::GuardsInput::Expr instr, IRGuards::GuardValue gv,
|
||||
int indirectionIndex
|
||||
) {
|
||||
exists(Node node |
|
||||
nodeHasInstruction(node, instr, indirectionIndex) and
|
||||
guardChecksNode(g, node, branch, indirectionIndex)
|
||||
guardChecksNode(g, node, gv.asBooleanValue(), indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1064,8 +1064,8 @@ module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
|
||||
DataFlowIntegrationInput::Guard g, SsaImpl::Definition def, IRGuards::GuardValue val,
|
||||
int indirectionIndex
|
||||
) {
|
||||
IRGuards::Guards_v1::ValidationWrapperWithState<int, guardChecksInstr/4>::guardChecksDef(g, def,
|
||||
val, indirectionIndex)
|
||||
IRGuards::Guards_v1::ParameterizedValidationWrapper<int, guardChecksInstr/4>::guardChecksDef(g,
|
||||
def, val, indirectionIndex)
|
||||
}
|
||||
|
||||
Node getABarrierNode(int indirectionIndex) {
|
||||
|
||||
@@ -93,6 +93,18 @@ private float wideningUpperBounds(ArithmeticType t) {
|
||||
result = 1.0 / 0.0 // +Inf
|
||||
}
|
||||
|
||||
/** Gets the widened lower bound for a given type and lower bound. */
|
||||
bindingset[type, lb]
|
||||
float widenLowerBound(Type type, float lb) {
|
||||
result = max(float widenLB | widenLB = wideningLowerBounds(type) and widenLB <= lb | widenLB)
|
||||
}
|
||||
|
||||
/** Gets the widened upper bound for a given type and upper bound. */
|
||||
bindingset[type, ub]
|
||||
float widenUpperBound(Type type, float ub) {
|
||||
result = min(float widenUB | widenUB = wideningUpperBounds(type) and widenUB >= ub | widenUB)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the expression `e`, if it is a constant.
|
||||
* This predicate also handles the case of constant variables initialized in different
|
||||
@@ -504,6 +516,336 @@ private predicate isRecursiveExpr(Expr e) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides predicates that estimate the number of bounds that the range
|
||||
* analysis might produce.
|
||||
*/
|
||||
private module BoundsEstimate {
|
||||
/**
|
||||
* Gets the limit beyond which we enable widening. That is, if the estimated
|
||||
* number of bounds exceeds this limit, we enable widening such that the limit
|
||||
* will not be reached.
|
||||
*/
|
||||
float getBoundsLimit() {
|
||||
// This limit is arbitrary, but low enough that it prevents timeouts on
|
||||
// specific observed customer databases (and the in the tests).
|
||||
result = 2.0.pow(40)
|
||||
}
|
||||
|
||||
/** Gets the maximum number of bounds possible for `t` when widening is used. */
|
||||
private int getNrOfWideningBounds(ArithmeticType t) {
|
||||
result = strictcount(wideningLowerBounds(t)).maximum(strictcount(wideningUpperBounds(t)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `boundFromGuard(guard, v, _, branch)` holds, but without
|
||||
* relying on range analysis (which would cause non-monotonic recursion
|
||||
* elsewhere).
|
||||
*/
|
||||
private predicate hasBoundFromGuard(Expr guard, VariableAccess v, boolean branch) {
|
||||
exists(Expr lhs | linearAccess(lhs, v, _, _) |
|
||||
relOpWithSwapAndNegate(guard, lhs, _, _, _, branch)
|
||||
or
|
||||
eqOpWithSwapAndNegate(guard, lhs, _, true, branch)
|
||||
or
|
||||
eqZeroWithNegate(guard, lhs, true, branch)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `def` is a guard phi node for `v` with a bound from a guard. */
|
||||
predicate isGuardPhiWithBound(RangeSsaDefinition def, StackVariable v, VariableAccess access) {
|
||||
exists(Expr guard, boolean branch |
|
||||
def.isGuardPhi(v, access, guard, branch) and
|
||||
hasBoundFromGuard(guard, access, branch)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of bounds for `def` when `def` is a guard phi node for the
|
||||
* variable `v`.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
private float nrOfBoundsPhiGuard(RangeSsaDefinition def, StackVariable v) {
|
||||
// If we have
|
||||
//
|
||||
// if (x < c) { e1 }
|
||||
// e2
|
||||
//
|
||||
// then `e2` is both a guard phi node (guarded by `x < c`) and a normal
|
||||
// phi node (control is merged after the `if` statement).
|
||||
//
|
||||
// Assume `x` has `n` bounds. Then `n` bounds are propagated to the guard
|
||||
// phi node `{ e1 }` and, since `{ e1 }` is input to `e2` as a normal phi
|
||||
// node, `n` bounds are propagated to `e2`. If we also propagate the `n`
|
||||
// bounds to `e2` as a guard phi node, then we square the number of
|
||||
// bounds.
|
||||
//
|
||||
// However in practice `x < c` is going to cut down the number of bounds:
|
||||
// The tracked bounds can't flow to both branches as that would require
|
||||
// them to simultaneously be greater and smaller than `c`. To approximate
|
||||
// this better, the contribution from a guard phi node that is also a
|
||||
// normal phi node is 1.
|
||||
exists(def.getAPhiInput(v)) and
|
||||
isGuardPhiWithBound(def, v, _) and
|
||||
result = 1
|
||||
or
|
||||
not exists(def.getAPhiInput(v)) and
|
||||
// If there's different `access`es, then they refer to the same variable
|
||||
// with the same lower bounds. Hence adding these guards make no sense (the
|
||||
// implementation will take the union, but they'll be removed by
|
||||
// deduplication). Hence we use `max` as an approximation.
|
||||
result =
|
||||
max(VariableAccess access | isGuardPhiWithBound(def, v, access) | nrOfBoundsExpr(access))
|
||||
or
|
||||
def.isPhiNode(v) and
|
||||
not isGuardPhiWithBound(def, v, _) and
|
||||
result = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of bounds for `def` when `def` is a normal phi node for the
|
||||
* variable `v`.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
private float nrOfBoundsPhiNormal(RangeSsaDefinition def, StackVariable v) {
|
||||
result =
|
||||
strictsum(RangeSsaDefinition inputDef |
|
||||
inputDef = def.getAPhiInput(v)
|
||||
|
|
||||
nrOfBoundsDef(inputDef, v)
|
||||
)
|
||||
or
|
||||
def.isPhiNode(v) and
|
||||
not exists(def.getAPhiInput(v)) and
|
||||
result = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of bounds for `def` when `def` is an NE phi node for the
|
||||
* variable `v`.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
float nrOfBoundsNEPhi(RangeSsaDefinition def, StackVariable v) {
|
||||
// If there's different `access`es, then they refer to the same variable
|
||||
// with the same lower bounds. Hence adding these guards make no sense (the
|
||||
// implementation will take the union, but they'll be removed by
|
||||
// deduplication). Hence we use `max` as an approximation.
|
||||
result = max(VariableAccess access | isNEPhi(v, def, access, _) | nrOfBoundsExpr(access))
|
||||
or
|
||||
def.isPhiNode(v) and
|
||||
not isNEPhi(v, def, _, _) and
|
||||
result = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of bounds for `def` when `def` is an unsupported guard phi
|
||||
* node for the variable `v`.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
private float nrOfBoundsUnsupportedGuardPhi(RangeSsaDefinition def, StackVariable v) {
|
||||
// If there's different `access`es, then they refer to the same variable
|
||||
// with the same lower bounds. Hence adding these guards make no sense (the
|
||||
// implementation will take the union, but they'll be removed by
|
||||
// deduplication). Hence we use `max` as an approximation.
|
||||
result =
|
||||
max(VariableAccess access | isUnsupportedGuardPhi(v, def, access) | nrOfBoundsExpr(access))
|
||||
or
|
||||
def.isPhiNode(v) and
|
||||
not isUnsupportedGuardPhi(v, def, _) and
|
||||
result = 0
|
||||
}
|
||||
|
||||
private float nrOfBoundsPhi(RangeSsaDefinition def, StackVariable v) {
|
||||
// The cases for phi nodes are not mutually exclusive. For instance a phi
|
||||
// node can be both a guard phi node and a normal phi node. To handle this
|
||||
// we sum the contributions from the different cases.
|
||||
result =
|
||||
nrOfBoundsPhiGuard(def, v) + nrOfBoundsPhiNormal(def, v) + nrOfBoundsNEPhi(def, v) +
|
||||
nrOfBoundsUnsupportedGuardPhi(def, v)
|
||||
}
|
||||
|
||||
/** Gets the estimated number of bounds for `def` and `v`. */
|
||||
float nrOfBoundsDef(RangeSsaDefinition def, StackVariable v) {
|
||||
// Recursive definitions are already widened, so we simply estimate them as
|
||||
// having the number of widening bounds available. This is crucial as it
|
||||
// ensures that we don't follow recursive cycles when calculating the
|
||||
// estimate. Had that not been the case the estimate itself would be at risk
|
||||
// of causing performance issues and being non-functional.
|
||||
if isRecursiveDef(def, v)
|
||||
then result = getNrOfWideningBounds(getVariableRangeType(v))
|
||||
else (
|
||||
// Definitions with a defining value
|
||||
exists(Expr defExpr | assignmentDef(def, v, defExpr) and result = nrOfBoundsExpr(defExpr))
|
||||
or
|
||||
// Assignment operations with a defining value
|
||||
exists(AssignOperation assignOp |
|
||||
def = assignOp and
|
||||
assignOp.getLValue() = v.getAnAccess() and
|
||||
result = nrOfBoundsExpr(assignOp)
|
||||
)
|
||||
or
|
||||
// Phi nodes
|
||||
result = nrOfBoundsPhi(def, v)
|
||||
or
|
||||
unanalyzableDefBounds(def, v, _, _) and result = 1
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a naive estimate of the number of bounds for `e`.
|
||||
*
|
||||
* The estimate is like an abstract interpretation of the range analysis,
|
||||
* where the abstract value is the number of bounds. For instance,
|
||||
* `nrOfBoundsExpr(12) = 1` and `nrOfBoundsExpr(x + y) = nrOfBoundsExpr(x) *
|
||||
* nrOfBoundsExpr(y)`.
|
||||
*
|
||||
* The estimated number of bounds will usually be greater than the actual
|
||||
* number of bounds, as the estimate can not detect cases where bounds are cut
|
||||
* down when tracked precisely. For instance, in
|
||||
* ```c
|
||||
* int x = 1;
|
||||
* if (cond) { x = 1; }
|
||||
* int y = x + x;
|
||||
* ```
|
||||
* the actual number of bounds for `y` is 1. However, the estimate will be 4
|
||||
* as the conditional assignment to `x` gives two bounds for `x` on the last
|
||||
* line and the addition gives 2 * 2 bounds. There are two sources of inaccuracies:
|
||||
*
|
||||
* 1. Without tracking the lower bounds we can't see that `x` is assigned a
|
||||
* value that is equal to its lower bound.
|
||||
* 2. Had the conditional assignment been `x = 2` then the estimate of two
|
||||
* bounds for `x` would have been correct. However, the estimate of 4 for `y`
|
||||
* would still be incorrect. Summing the actual bounds `{1,2}` with itself
|
||||
* gives `{2,3,4}` which is only three bounds. Again, we can't realise this
|
||||
* without tracking the bounds.
|
||||
*
|
||||
* Since these inaccuracies compound the estimated number of bounds can often
|
||||
* be _much_ greater than the actual number of bounds. Do note though that the
|
||||
* estimate is not _guaranteed_ to be an upper bound. In some cases the
|
||||
* approximations might underestimate the number of bounds.
|
||||
*
|
||||
* This predicate is functional. This is crucial as:
|
||||
*
|
||||
* - It ensures that the computing the estimate itself is fast.
|
||||
* - Our use of monotonic aggregates assumes functionality.
|
||||
*
|
||||
* Any non-functional case should be considered a bug.
|
||||
*/
|
||||
float nrOfBoundsExpr(Expr e) {
|
||||
// Similarly to what we do for definitions, we do not attempt to measure the
|
||||
// number of bounds for recursive expressions.
|
||||
if isRecursiveExpr(e)
|
||||
then result = getNrOfWideningBounds(e.getUnspecifiedType())
|
||||
else
|
||||
if analyzableExpr(e)
|
||||
then
|
||||
// The cases here are an abstraction of and mirrors the cases inside
|
||||
// `getLowerBoundsImpl`/`getUpperBoundsImpl`.
|
||||
result = 1 and exists(getValue(e).toFloat())
|
||||
or
|
||||
exists(Expr operand | result = nrOfBoundsExpr(operand) |
|
||||
effectivelyMultipliesByPositive(e, operand, _)
|
||||
or
|
||||
effectivelyMultipliesByNegative(e, operand, _)
|
||||
)
|
||||
or
|
||||
exists(ConditionalExpr condExpr |
|
||||
e = condExpr and
|
||||
result = nrOfBoundsExpr(condExpr.getThen()) * nrOfBoundsExpr(condExpr.getElse())
|
||||
)
|
||||
or
|
||||
exists(BinaryOperation binop |
|
||||
e = binop and
|
||||
result = nrOfBoundsExpr(binop.getLeftOperand()) * nrOfBoundsExpr(binop.getRightOperand())
|
||||
|
|
||||
e instanceof MaxExpr or
|
||||
e instanceof MinExpr or
|
||||
e instanceof AddExpr or
|
||||
e instanceof SubExpr or
|
||||
e instanceof UnsignedMulExpr or
|
||||
e instanceof UnsignedBitwiseAndExpr
|
||||
)
|
||||
or
|
||||
exists(AssignExpr assign | e = assign and result = nrOfBoundsExpr(assign.getRValue()))
|
||||
or
|
||||
exists(AssignArithmeticOperation assignOp |
|
||||
e = assignOp and
|
||||
result = nrOfBoundsExpr(assignOp.getLValue()) * nrOfBoundsExpr(assignOp.getRValue())
|
||||
|
|
||||
e instanceof AssignAddExpr or
|
||||
e instanceof AssignSubExpr or
|
||||
e instanceof UnsignedAssignMulExpr
|
||||
)
|
||||
or
|
||||
// Handles `AssignMulByPositiveConstantExpr` and `AssignMulByNegativeConstantExpr`
|
||||
exists(AssignMulByConstantExpr mulExpr |
|
||||
e = mulExpr and
|
||||
result = nrOfBoundsExpr(mulExpr.getLValue())
|
||||
)
|
||||
or
|
||||
// Handles the prefix and postfix increment and decrement operators.
|
||||
exists(CrementOperation crementOp |
|
||||
e = crementOp and result = nrOfBoundsExpr(crementOp.getOperand())
|
||||
)
|
||||
or
|
||||
exists(RemExpr remExpr | e = remExpr | result = nrOfBoundsExpr(remExpr.getRightOperand()))
|
||||
or
|
||||
exists(Conversion convExpr |
|
||||
e = convExpr and
|
||||
if convExpr.getUnspecifiedType() instanceof BoolType
|
||||
then result = 1
|
||||
else result = nrOfBoundsExpr(convExpr.getExpr())
|
||||
)
|
||||
or
|
||||
exists(RangeSsaDefinition def, StackVariable v |
|
||||
e = def.getAUse(v) and
|
||||
result = nrOfBoundsDef(def, v) and
|
||||
// Avoid returning two numbers when `e` is a use with a constant value.
|
||||
not exists(getValue(e).toFloat())
|
||||
)
|
||||
or
|
||||
exists(RShiftExpr rsExpr |
|
||||
e = rsExpr and
|
||||
exists(getValue(rsExpr.getRightOperand().getFullyConverted()).toInt()) and
|
||||
result = nrOfBoundsExpr(rsExpr.getLeftOperand())
|
||||
)
|
||||
else (
|
||||
exists(exprMinVal(e)) and result = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is a variable for which widening should be used, as otherwise a
|
||||
* very large number of bounds might be generated during the range analysis for
|
||||
* `v`.
|
||||
*/
|
||||
private predicate varHasTooManyBounds(StackVariable v) {
|
||||
exists(RangeSsaDefinition def |
|
||||
def.getAVariable() = v and
|
||||
BoundsEstimate::nrOfBoundsDef(def, v) > BoundsEstimate::getBoundsLimit()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` is an expression for which widening should be used, as otherwise
|
||||
* a very large number of bounds might be generated during the range analysis
|
||||
* for `e`.
|
||||
*/
|
||||
private predicate exprHasTooManyBounds(Expr e) {
|
||||
BoundsEstimate::nrOfBoundsExpr(e) > BoundsEstimate::getBoundsLimit()
|
||||
or
|
||||
// A subexpressions of an expression with too many bounds may itself not have
|
||||
// to many bounds. For instance, `x + y` can have too many bounds without `x`
|
||||
// having as well. But in these cases, still want to consider `e` as having
|
||||
// too many bounds since:
|
||||
// - The overall result is widened anyway, so widening `e` as well is unlikely
|
||||
// to cause further precision loss.
|
||||
// - The number of bounds could be very large but still below the arbitrary
|
||||
// limit. Hence widening `e` can improve performance.
|
||||
exists(Expr pe | exprHasTooManyBounds(pe) and e.getParent() = pe)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `binop` is a binary operation that's likely to be assigned a
|
||||
* quadratic (or more) number of candidate bounds during the analysis. This can
|
||||
@@ -654,13 +996,8 @@ private float getTruncatedLowerBounds(Expr expr) {
|
||||
if exprMinVal(expr) <= newLB and newLB <= exprMaxVal(expr)
|
||||
then
|
||||
// Apply widening where we might get a combinatorial explosion.
|
||||
if isRecursiveBinary(expr)
|
||||
then
|
||||
result =
|
||||
max(float widenLB |
|
||||
widenLB = wideningLowerBounds(expr.getUnspecifiedType()) and
|
||||
not widenLB > newLB
|
||||
)
|
||||
if isRecursiveBinary(expr) or exprHasTooManyBounds(expr)
|
||||
then result = widenLowerBound(expr.getUnspecifiedType(), newLB)
|
||||
else result = newLB
|
||||
else result = exprMinVal(expr)
|
||||
) and
|
||||
@@ -713,13 +1050,8 @@ private float getTruncatedUpperBounds(Expr expr) {
|
||||
if exprMinVal(expr) <= newUB and newUB <= exprMaxVal(expr)
|
||||
then
|
||||
// Apply widening where we might get a combinatorial explosion.
|
||||
if isRecursiveBinary(expr)
|
||||
then
|
||||
result =
|
||||
min(float widenUB |
|
||||
widenUB = wideningUpperBounds(expr.getUnspecifiedType()) and
|
||||
not widenUB < newUB
|
||||
)
|
||||
if isRecursiveBinary(expr) or exprHasTooManyBounds(expr)
|
||||
then result = widenUpperBound(expr.getUnspecifiedType(), newUB)
|
||||
else result = newUB
|
||||
else result = exprMaxVal(expr)
|
||||
)
|
||||
@@ -1796,18 +2128,12 @@ module SimpleRangeAnalysisInternal {
|
||||
|
|
||||
// Widening: check whether the new lower bound is from a source which
|
||||
// depends recursively on the current definition.
|
||||
if isRecursiveDef(def, v)
|
||||
if isRecursiveDef(def, v) or varHasTooManyBounds(v)
|
||||
then
|
||||
// The new lower bound is from a recursive source, so we round
|
||||
// down to one of a limited set of values to prevent the
|
||||
// recursion from exploding.
|
||||
result =
|
||||
max(float widenLB |
|
||||
widenLB = wideningLowerBounds(getVariableRangeType(v)) and
|
||||
not widenLB > truncatedLB
|
||||
|
|
||||
widenLB
|
||||
)
|
||||
result = widenLowerBound(getVariableRangeType(v), truncatedLB)
|
||||
else result = truncatedLB
|
||||
)
|
||||
or
|
||||
@@ -1826,18 +2152,12 @@ module SimpleRangeAnalysisInternal {
|
||||
|
|
||||
// Widening: check whether the new upper bound is from a source which
|
||||
// depends recursively on the current definition.
|
||||
if isRecursiveDef(def, v)
|
||||
if isRecursiveDef(def, v) or varHasTooManyBounds(v)
|
||||
then
|
||||
// The new upper bound is from a recursive source, so we round
|
||||
// up to one of a fixed set of values to prevent the recursion
|
||||
// from exploding.
|
||||
result =
|
||||
min(float widenUB |
|
||||
widenUB = wideningUpperBounds(getVariableRangeType(v)) and
|
||||
not widenUB < truncatedUB
|
||||
|
|
||||
widenUB
|
||||
)
|
||||
result = widenUpperBound(getVariableRangeType(v), truncatedUB)
|
||||
else result = truncatedUB
|
||||
)
|
||||
or
|
||||
@@ -1845,4 +2165,60 @@ module SimpleRangeAnalysisInternal {
|
||||
// bound is `typeUpperBound`.
|
||||
defMightOverflowNegatively(def, v) and result = varMaxVal(v)
|
||||
}
|
||||
|
||||
/** Gets the estimate of the number of bounds for `e`. */
|
||||
float estimateNrOfBounds(Expr e) { result = BoundsEstimate::nrOfBoundsExpr(e) }
|
||||
}
|
||||
|
||||
/** Provides predicates for debugging the simple range analysis library. */
|
||||
private module Debug {
|
||||
Locatable getRelevantLocatable() {
|
||||
exists(string filepath, int startline |
|
||||
result.getLocation().hasLocationInfo(filepath, startline, _, _, _) and
|
||||
filepath.matches("%/test.c") and
|
||||
startline = [621 .. 639]
|
||||
)
|
||||
}
|
||||
|
||||
float debugGetLowerBoundsImpl(Expr e) {
|
||||
e = getRelevantLocatable() and
|
||||
result = getLowerBoundsImpl(e)
|
||||
}
|
||||
|
||||
float debugGetUpperBoundsImpl(Expr e) {
|
||||
e = getRelevantLocatable() and
|
||||
result = getUpperBoundsImpl(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of lower bounds for a given expression. This predicate is
|
||||
* useful for identifying performance issues in the range analysis.
|
||||
*/
|
||||
predicate countGetLowerBoundsImpl(Expr e, int n) {
|
||||
e = getRelevantLocatable() and
|
||||
n = strictcount(float lb | lb = getLowerBoundsImpl(e) | lb)
|
||||
}
|
||||
|
||||
float debugNrOfBounds(Expr e) {
|
||||
e = getRelevantLocatable() and
|
||||
result = BoundsEstimate::nrOfBoundsExpr(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds any expressions for which `nrOfBounds` is not functional. The result
|
||||
* should be empty, so this predicate is useful to debug non-functional cases.
|
||||
*/
|
||||
int nonFunctionalNrOfBounds(Expr e) {
|
||||
strictcount(BoundsEstimate::nrOfBoundsExpr(e)) > 1 and
|
||||
result = BoundsEstimate::nrOfBoundsExpr(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` is an expression that has a lower bound, but where
|
||||
* `nrOfBounds` does not compute an estimate.
|
||||
*/
|
||||
predicate missingNrOfBounds(Expr e, float n) {
|
||||
n = lowerBound(e) and
|
||||
not exists(BoundsEstimate::nrOfBoundsExpr(e))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
/*- Compilations -*/
|
||||
|
||||
/**
|
||||
@@ -47,6 +48,19 @@ compilation_args(
|
||||
string arg : string ref
|
||||
);
|
||||
|
||||
/**
|
||||
* The expanded arguments that were passed to the extractor for a
|
||||
* compiler invocation. This is similar to `compilation_args`, but
|
||||
* for a `@someFile` argument, it includes the arguments from that
|
||||
* file, rather than just taking the argument literally.
|
||||
*/
|
||||
#keyset[id, num]
|
||||
compilation_expanded_args(
|
||||
int id : @compilation ref,
|
||||
int num : int ref,
|
||||
string arg : string ref
|
||||
);
|
||||
|
||||
/**
|
||||
* Optionally, record the build mode for each compilation.
|
||||
*/
|
||||
@@ -2365,6 +2379,24 @@ link_parent(
|
||||
int link_target : @link_target ref
|
||||
);
|
||||
|
||||
/**
|
||||
* The CLI will automatically emit applicable tuples for this table,
|
||||
* such as `databaseMetadata("isOverlay", "true")` when building an
|
||||
* overlay database.
|
||||
*/
|
||||
databaseMetadata(
|
||||
string metadataKey: string ref,
|
||||
string value: string ref
|
||||
);
|
||||
|
||||
/**
|
||||
* The CLI will automatically emit tuples for each new/modified/deleted file
|
||||
* when building an overlay database.
|
||||
*/
|
||||
overlayChangedFiles(
|
||||
string path: string ref
|
||||
);
|
||||
|
||||
/*- XML Files -*/
|
||||
|
||||
xmlEncoding(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Add databaseMetadata and overlayChangedFiles relations
|
||||
compatibility: full
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Support expanded compilation argument lists
|
||||
compatibility: backwards
|
||||
@@ -1,3 +1,19 @@
|
||||
## 1.5.7
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.5.6
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.5.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.5.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.5.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -10,7 +10,7 @@ import ExternalAPIsSpecific
|
||||
|
||||
/** A node representing untrusted data being passed to an external API. */
|
||||
class UntrustedExternalApiDataNode extends ExternalApiDataNode {
|
||||
UntrustedExternalApiDataNode() { UntrustedDataToExternalApiFlow::flow(_, this) }
|
||||
UntrustedExternalApiDataNode() { UntrustedDataToExternalApiFlow::flowTo(this) }
|
||||
|
||||
/** Gets a source of untrusted data which is passed to this external API data node. */
|
||||
DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::flow(result, this) }
|
||||
|
||||
@@ -10,7 +10,7 @@ import ExternalAPIsSpecific
|
||||
|
||||
/** A node representing untrusted data being passed to an external API. */
|
||||
class UntrustedExternalApiDataNode extends ExternalApiDataNode {
|
||||
UntrustedExternalApiDataNode() { UntrustedDataToExternalApiFlow::flow(_, this) }
|
||||
UntrustedExternalApiDataNode() { UntrustedDataToExternalApiFlow::flowTo(this) }
|
||||
|
||||
/** Gets a source of untrusted data which is passed to this external API data node. */
|
||||
DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::flow(result, this) }
|
||||
|
||||
@@ -263,7 +263,7 @@ module FromSensitiveFlow = TaintTracking::Global<FromSensitiveConfig>;
|
||||
* A taint flow configuration for flow from a sensitive expression to an encryption operation.
|
||||
*/
|
||||
module ToEncryptionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { FromSensitiveFlow::flow(source, _) }
|
||||
predicate isSource(DataFlow::Node source) { FromSensitiveFlow::flowFrom(source) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isSinkEncrypt(sink, _) }
|
||||
|
||||
@@ -311,7 +311,7 @@ where
|
||||
FromSensitiveFlow::flowPath(source, sink) and
|
||||
isSinkSendRecv(sink.getNode(), networkSendRecv) and
|
||||
// no flow from sensitive -> evidence of encryption
|
||||
not ToEncryptionFlow::flow(source.getNode(), _) and
|
||||
not ToEncryptionFlow::flowFrom(source.getNode()) and
|
||||
not FromEncryptionFlow::flowTo(sink.getNode()) and
|
||||
// construct result
|
||||
if networkSendRecv instanceof NetworkSend
|
||||
|
||||
3
cpp/ql/src/change-notes/released/1.5.4.md
Normal file
3
cpp/ql/src/change-notes/released/1.5.4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.5.4
|
||||
|
||||
No user-facing changes.
|
||||
3
cpp/ql/src/change-notes/released/1.5.5.md
Normal file
3
cpp/ql/src/change-notes/released/1.5.5.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.5.5
|
||||
|
||||
No user-facing changes.
|
||||
3
cpp/ql/src/change-notes/released/1.5.6.md
Normal file
3
cpp/ql/src/change-notes/released/1.5.6.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.5.6
|
||||
|
||||
No user-facing changes.
|
||||
3
cpp/ql/src/change-notes/released/1.5.7.md
Normal file
3
cpp/ql/src/change-notes/released/1.5.7.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.5.7
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.5.3
|
||||
lastReleaseVersion: 1.5.7
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @name Dangerous use convert function.
|
||||
* @name Dangerous use convert function
|
||||
* @description Using convert function with an invalid length argument can result in an out-of-bounds access error or unexpected result.
|
||||
* @kind problem
|
||||
* @id cpp/dangerous-use-convert-function
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @name Dangerous use of transformation after operation.
|
||||
* @name Dangerous use of transformation after operation
|
||||
* @description By using the transformation after the operation, you are doing a pointless and dangerous action.
|
||||
* @kind problem
|
||||
* @id cpp/dangerous-use-of-transformation-after-operation
|
||||
|
||||
@@ -129,7 +129,7 @@ module PointerArithmeticToDerefFlow = DataFlow::Global<PointerArithmeticToDerefC
|
||||
|
||||
predicate pointerArithOverflow(PointerArithmeticInstruction pai, int delta) {
|
||||
pointerArithOverflow0(pai, delta) and
|
||||
PointerArithmeticToDerefFlow::flow(DataFlow::instructionNode(pai), _)
|
||||
PointerArithmeticToDerefFlow::flowFrom(DataFlow::instructionNode(pai))
|
||||
}
|
||||
|
||||
bindingset[v]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @name Writing to a file without setting permissions.
|
||||
* @name Writing to a file without setting permissions
|
||||
* @description Lack of restriction on file access rights can be unsafe.
|
||||
* @kind problem
|
||||
* @id cpp/work-with-file-without-permissions-rights
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @name Find work with changing working directories, with security errors.
|
||||
* @name Find work with changing working directories, with security errors
|
||||
* @description Not validating the return value or pinning the directory can be unsafe.
|
||||
* @kind problem
|
||||
* @id cpp/work-with-changing-working-directories
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @name Find the wrong use of the umask function.
|
||||
* @name Find the wrong use of the umask function
|
||||
* @description Incorrectly evaluated argument to the umask function may have security implications.
|
||||
* @kind problem
|
||||
* @id cpp/wrong-use-of-the-umask
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @name Insecure generation of filenames.
|
||||
* @name Insecure generation of filenames
|
||||
* @description Using a predictable filename when creating a temporary file can lead to an attacker-controlled input.
|
||||
* @kind problem
|
||||
* @id cpp/insecure-generation-of-filename
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @name Dangerous use of exception blocks.
|
||||
* @name Dangerous use of exception blocks
|
||||
* @description When clearing the data in the catch block, you must be sure that the memory was allocated before the exception.
|
||||
* @kind problem
|
||||
* @id cpp/dangerous-use-of-exception-blocks
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @name Dangerous use SSL_shutdown.
|
||||
* @name Dangerous use SSL_shutdown
|
||||
* @description Incorrect closing of the connection leads to the creation of different states for the server and client, which can be exploited by an attacker.
|
||||
* @kind problem
|
||||
* @id cpp/dangerous-use-of-ssl-shutdown
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 1.5.4-dev
|
||||
version: 1.5.8-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @name Capture content based summary models.
|
||||
* @name Capture content based summary models
|
||||
* @description Finds applicable content based summary models to be used by other queries.
|
||||
* @kind diagnostic
|
||||
* @id cpp/utils/modelgenerator/contentbased-summary-models
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @name Capture neutral models.
|
||||
* @name Capture neutral models
|
||||
* @description Finds neutral models to be used by other queries.
|
||||
* @kind diagnostic
|
||||
* @id cpp/utils/modelgenerator/neutral-models
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @name Capture sink models.
|
||||
* @name Capture sink models
|
||||
* @description Finds public methods that act as sinks as they flow into a known sink.
|
||||
* @kind diagnostic
|
||||
* @id cpp/utils/modelgenerator/sink-models
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @name Capture source models.
|
||||
* @name Capture source models
|
||||
* @description Finds APIs that act as sources as they expose already known sources.
|
||||
* @kind diagnostic
|
||||
* @id cpp/utils/modelgenerator/source-models
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @name Capture summary models.
|
||||
* @name Capture summary models
|
||||
* @description Finds applicable summary models to be used by other queries.
|
||||
* @kind diagnostic
|
||||
* @id cpp/utils/modelgenerator/summary-models
|
||||
|
||||
@@ -190,7 +190,7 @@ module ModelGeneratorCommonInput implements ModelGeneratorCommonInputSig<Cpp::Lo
|
||||
predicate isRelevantType(Type t) { any() }
|
||||
|
||||
Type getUnderlyingContentType(DataFlow::ContentSet c) {
|
||||
result = c.(DataFlow::FieldContent).getField().getUnspecifiedType() or
|
||||
result = c.(DataFlow::NonUnionFieldContent).getField().getUnspecifiedType() or
|
||||
result = c.(DataFlow::UnionContent).getUnion().getUnspecifiedType()
|
||||
}
|
||||
|
||||
@@ -340,12 +340,7 @@ private module SummaryModelGeneratorInput implements SummaryModelGeneratorInputS
|
||||
)
|
||||
}
|
||||
|
||||
predicate isField(DataFlow::ContentSet cs) {
|
||||
exists(DataFlow::Content c | cs.isSingleton(c) |
|
||||
c instanceof DataFlow::FieldContent or
|
||||
c instanceof DataFlow::UnionContent
|
||||
)
|
||||
}
|
||||
predicate isField(DataFlow::ContentSet cs) { cs.isSingleton(any(DataFlow::FieldContent fc)) }
|
||||
|
||||
predicate isCallback(DataFlow::ContentSet c) { none() }
|
||||
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
| clang421.c:1:12:1:19 | clang421 | 0 |
|
||||
| clang450.c:1:12:1:19 | clang450 | 1 |
|
||||
| gcc421.c:1:12:1:17 | gcc421 | 0 |
|
||||
| gcc450.c:1:12:1:17 | gcc450 | 1 |
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
static int gcc421 = __has_feature(attribute_deprecated_with_message);
|
||||
// semmle-extractor-options: --gnu_version 40201
|
||||
@@ -1,2 +0,0 @@
|
||||
static int gcc450 = __has_feature(attribute_deprecated_with_message);
|
||||
// semmle-extractor-options: --gnu_version 40500
|
||||
@@ -30,13 +30,14 @@ models
|
||||
| 29 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
|
||||
| 30 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
|
||||
| 31 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual |
|
||||
| 32 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual |
|
||||
| 33 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated |
|
||||
| 34 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual |
|
||||
| 35 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual |
|
||||
| 36 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual |
|
||||
| 32 | Summary: ; ; false; callWithNonTypeTemplate<T>; (const T &); ; Argument[*0]; ReturnValue; value; manual |
|
||||
| 33 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual |
|
||||
| 34 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated |
|
||||
| 35 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual |
|
||||
| 36 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual |
|
||||
| 37 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual |
|
||||
edges
|
||||
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:36 |
|
||||
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:37 |
|
||||
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:17 |
|
||||
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:17 Sink:MaD:2 |
|
||||
| asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction |
|
||||
@@ -45,10 +46,10 @@ edges
|
||||
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | |
|
||||
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:2 |
|
||||
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | provenance | |
|
||||
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:36 |
|
||||
| test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | provenance | MaD:34 |
|
||||
| test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | provenance | MaD:33 |
|
||||
| test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | provenance | MaD:35 |
|
||||
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:37 |
|
||||
| test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | provenance | MaD:35 |
|
||||
| test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | provenance | MaD:34 |
|
||||
| test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | provenance | MaD:36 |
|
||||
| test.cpp:7:47:7:52 | value2 | test.cpp:7:64:7:69 | value2 | provenance | |
|
||||
| test.cpp:7:64:7:69 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | provenance | |
|
||||
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:16 |
|
||||
@@ -60,15 +61,15 @@ edges
|
||||
| test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | |
|
||||
| test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:1 |
|
||||
| test.cpp:17:24:17:24 | x | test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | provenance | |
|
||||
| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:34 |
|
||||
| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:35 |
|
||||
| test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | |
|
||||
| test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:1 |
|
||||
| test.cpp:21:27:21:27 | x | test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | provenance | |
|
||||
| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:33 |
|
||||
| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:34 |
|
||||
| test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | |
|
||||
| test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:1 |
|
||||
| test.cpp:25:35:25:35 | x | test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | provenance | |
|
||||
| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:35 |
|
||||
| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:36 |
|
||||
| test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | |
|
||||
| test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:1 |
|
||||
| test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | provenance | |
|
||||
@@ -76,7 +77,7 @@ edges
|
||||
| test.cpp:46:30:46:32 | *arg [x] | test.cpp:47:12:47:19 | *arg [x] | provenance | |
|
||||
| test.cpp:47:12:47:19 | *arg [x] | test.cpp:48:13:48:13 | *s [x] | provenance | |
|
||||
| test.cpp:48:13:48:13 | *s [x] | test.cpp:48:16:48:16 | x | provenance | Sink:MaD:1 |
|
||||
| test.cpp:52:5:52:18 | [summary param] *3 in pthread_create [x] | test.cpp:52:5:52:18 | [summary] to write: Argument[2].Parameter[*0] in pthread_create [x] | provenance | MaD:32 |
|
||||
| test.cpp:52:5:52:18 | [summary param] *3 in pthread_create [x] | test.cpp:52:5:52:18 | [summary] to write: Argument[2].Parameter[*0] in pthread_create [x] | provenance | MaD:33 |
|
||||
| test.cpp:52:5:52:18 | [summary] to write: Argument[2].Parameter[*0] in pthread_create [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | |
|
||||
| test.cpp:56:2:56:2 | *s [post update] [x] | test.cpp:59:55:59:64 | *& ... [x] | provenance | |
|
||||
| test.cpp:56:2:56:18 | ... = ... | test.cpp:56:2:56:2 | *s [post update] [x] | provenance | |
|
||||
@@ -103,6 +104,13 @@ edges
|
||||
| test.cpp:101:26:101:26 | x | test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | provenance | |
|
||||
| test.cpp:103:63:103:63 | x | test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | provenance | |
|
||||
| test.cpp:104:62:104:62 | x | test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | provenance | |
|
||||
| test.cpp:111:3:111:25 | [summary param] *0 in callWithNonTypeTemplate | test.cpp:111:3:111:25 | [summary] to write: ReturnValue in callWithNonTypeTemplate | provenance | MaD:32 |
|
||||
| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:16 |
|
||||
| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:118:44:118:44 | *x | provenance | |
|
||||
| test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | |
|
||||
| test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:119:10:119:11 | y2 | provenance | Sink:MaD:1 |
|
||||
| test.cpp:118:44:118:44 | *x | test.cpp:111:3:111:25 | [summary param] *0 in callWithNonTypeTemplate | provenance | |
|
||||
| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:32 |
|
||||
| windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | windows.cpp:17:8:17:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | provenance | MaD:18 |
|
||||
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:3 |
|
||||
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:24:8:24:11 | * ... | provenance | |
|
||||
@@ -314,6 +322,14 @@ nodes
|
||||
| test.cpp:101:26:101:26 | x | semmle.label | x |
|
||||
| test.cpp:103:63:103:63 | x | semmle.label | x |
|
||||
| test.cpp:104:62:104:62 | x | semmle.label | x |
|
||||
| test.cpp:111:3:111:25 | [summary param] *0 in callWithNonTypeTemplate | semmle.label | [summary param] *0 in callWithNonTypeTemplate |
|
||||
| test.cpp:111:3:111:25 | [summary] to write: ReturnValue in callWithNonTypeTemplate | semmle.label | [summary] to write: ReturnValue in callWithNonTypeTemplate |
|
||||
| test.cpp:114:10:114:18 | call to ymlSource | semmle.label | call to ymlSource |
|
||||
| test.cpp:114:10:114:18 | call to ymlSource | semmle.label | call to ymlSource |
|
||||
| test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | semmle.label | call to callWithNonTypeTemplate |
|
||||
| test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | semmle.label | call to callWithNonTypeTemplate |
|
||||
| test.cpp:118:44:118:44 | *x | semmle.label | *x |
|
||||
| test.cpp:119:10:119:11 | y2 | semmle.label | y2 |
|
||||
| windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | semmle.label | [summary param] *0 in CommandLineToArgvA |
|
||||
| windows.cpp:17:8:17:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | semmle.label | [summary] to write: ReturnValue[**] in CommandLineToArgvA |
|
||||
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | semmle.label | *call to GetCommandLineA |
|
||||
@@ -472,6 +488,7 @@ subpaths
|
||||
| test.cpp:21:27:21:27 | x | test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated |
|
||||
| test.cpp:25:35:25:35 | x | test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body |
|
||||
| test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body |
|
||||
| test.cpp:118:44:118:44 | *x | test.cpp:111:3:111:25 | [summary param] *0 in callWithNonTypeTemplate | test.cpp:111:3:111:25 | [summary] to write: ReturnValue in callWithNonTypeTemplate | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate |
|
||||
| windows.cpp:27:36:27:38 | *cmd | windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | windows.cpp:17:8:17:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA |
|
||||
| windows.cpp:537:40:537:41 | *& ... | windows.cpp:473:17:473:37 | [summary param] *1 in RtlCopyVolatileMemory | windows.cpp:473:17:473:37 | [summary param] *0 in RtlCopyVolatileMemory [Return] | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument |
|
||||
| windows.cpp:542:38:542:39 | *& ... | windows.cpp:479:17:479:35 | [summary param] *1 in RtlCopyDeviceMemory | windows.cpp:479:17:479:35 | [summary param] *0 in RtlCopyDeviceMemory [Return] | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument |
|
||||
|
||||
@@ -17,4 +17,5 @@ extensions:
|
||||
- ["", "", False, "ymlStepGenerated", "", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
|
||||
- ["", "", False, "ymlStepManual_with_body", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||
- ["", "", False, "ymlStepGenerated_with_body", "", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
|
||||
- ["", "", False, "callWithArgument", "", "", "Argument[1]", "Argument[0].Parameter[0]", "value", "manual"]
|
||||
- ["", "", False, "callWithArgument", "", "", "Argument[1]", "Argument[0].Parameter[0]", "value", "manual"]
|
||||
- ["", "", False, "callWithNonTypeTemplate<T>", "(const T &)", "", "Argument[*0]", "ReturnValue", "value", "manual"]
|
||||
@@ -13,3 +13,5 @@
|
||||
| test.cpp:75:11:75:11 | y | test-sink |
|
||||
| test.cpp:83:11:83:11 | y | test-sink |
|
||||
| test.cpp:89:11:89:11 | y | test-sink |
|
||||
| test.cpp:116:10:116:11 | y1 | test-sink |
|
||||
| test.cpp:119:10:119:11 | y2 | test-sink |
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
| test.cpp:10:10:10:18 | call to ymlSource | local |
|
||||
| test.cpp:56:8:56:16 | call to ymlSource | local |
|
||||
| test.cpp:94:10:94:18 | call to ymlSource | local |
|
||||
| test.cpp:114:10:114:18 | call to ymlSource | local |
|
||||
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | local |
|
||||
| windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | local |
|
||||
| windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | local |
|
||||
|
||||
@@ -102,4 +102,19 @@ void test_callWithArgument() {
|
||||
}
|
||||
callWithArgument(StructWithOperatorCall_has_constructor_2(), x);
|
||||
callWithArgument(StructWithOperatorCall_no_constructor_2(), x);
|
||||
}
|
||||
}
|
||||
|
||||
template<int N, typename T>
|
||||
T callWithNonTypeTemplate(const T&);
|
||||
|
||||
template<typename T, int N>
|
||||
T callWithNonTypeTemplate(const T&);
|
||||
|
||||
void test_callWithNonTypeTemplate() {
|
||||
int x = ymlSource();
|
||||
int y1 = callWithNonTypeTemplate<10, int>(x);
|
||||
ymlSink(y1); // $ MISSING: ir
|
||||
|
||||
int y2 = callWithNonTypeTemplate<int, 10>(x);
|
||||
ymlSink(y2); // $ ir
|
||||
}
|
||||
|
||||
@@ -142,6 +142,7 @@ postWithInFlow
|
||||
| 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. |
|
||||
| simple.cpp:124:5:124:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| simple.cpp:167:9:167:9 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
viableImplInCallContextTooLarge
|
||||
uniqueParameterNodeAtPosition
|
||||
uniqueParameterNodePosition
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user