mirror of
https://github.com/github/codeql.git
synced 2026-05-26 09:01:22 +02:00
Compare commits
4 Commits
tausbn/pyt
...
copilot/ad
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52a6f5d626 | ||
|
|
36dc27c3e7 | ||
|
|
a00e31c572 | ||
|
|
27fcd97ed1 |
@@ -1 +1 @@
|
||||
8.4.2
|
||||
8.1.1
|
||||
|
||||
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -82,6 +82,9 @@
|
||||
/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,8 +40,3 @@ updates:
|
||||
- dependency-name: "*"
|
||||
reviewers:
|
||||
- "github/codeql-go"
|
||||
|
||||
- package-ecosystem: bazel
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
|
||||
74
.github/workflows/build-ripunzip.yml
vendored
Normal file
74
.github/workflows/build-ripunzip.yml
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
name: Build runzip
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ripunzip-version:
|
||||
description: "what reference to checktout from google/runzip"
|
||||
required: false
|
||||
default: v2.0.2
|
||||
openssl-version:
|
||||
description: "what reference to checkout from openssl/openssl for Linux"
|
||||
required: false
|
||||
default: openssl-3.5.0
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-22.04, macos-13, windows-2022]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
repository: google/ripunzip
|
||||
ref: ${{ inputs.ripunzip-version }}
|
||||
# we need to avoid ripunzip dynamically linking into libssl
|
||||
# see https://github.com/sfackler/rust-openssl/issues/183
|
||||
- if: runner.os == 'Linux'
|
||||
name: checkout openssl
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: openssl/openssl
|
||||
path: openssl
|
||||
ref: ${{ inputs.openssl-version }}
|
||||
- if: runner.os == 'Linux'
|
||||
name: build and install openssl with fPIC
|
||||
shell: bash
|
||||
working-directory: openssl
|
||||
run: |
|
||||
./config -fPIC --prefix=$HOME/.local --openssldir=$HOME/.local/ssl
|
||||
make -j $(nproc)
|
||||
make install_sw -j $(nproc)
|
||||
- if: runner.os == 'Linux'
|
||||
name: build (linux)
|
||||
shell: bash
|
||||
run: |
|
||||
env OPENSSL_LIB_DIR=$HOME/.local/lib64 OPENSSL_INCLUDE_DIR=$HOME/.local/include OPENSSL_STATIC=yes cargo build --release
|
||||
mv target/release/ripunzip ripunzip-linux
|
||||
- if: runner.os == 'Windows'
|
||||
name: build (windows)
|
||||
shell: bash
|
||||
run: |
|
||||
cargo build --release
|
||||
mv target/release/ripunzip ripunzip-windows
|
||||
- name: build (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
shell: bash
|
||||
run: |
|
||||
rustup target install x86_64-apple-darwin
|
||||
rustup target install aarch64-apple-darwin
|
||||
cargo build --target x86_64-apple-darwin --release
|
||||
cargo build --target aarch64-apple-darwin --release
|
||||
lipo -create -output ripunzip-macos \
|
||||
-arch x86_64 target/x86_64-apple-darwin/release/ripunzip \
|
||||
-arch arm64 target/aarch64-apple-darwin/release/ripunzip
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ripunzip-${{ runner.os }}
|
||||
path: ripunzip-*
|
||||
- name: Check built binary
|
||||
shell: bash
|
||||
run: |
|
||||
./ripunzip-* --version
|
||||
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: 10.0.100
|
||||
dotnet-version: 9.0.300
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
|
||||
42
.github/workflows/compile-queries.yml
vendored
42
.github/workflows/compile-queries.yml
vendored
@@ -17,41 +17,9 @@ permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
detect-changes:
|
||||
if: github.repository_owner == 'github'
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
languages: ${{ steps.detect.outputs.languages }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Detect changed languages
|
||||
id: detect
|
||||
run: |
|
||||
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
||||
# For PRs, detect which languages have changes
|
||||
changed_files=$(gh pr view ${{ github.event.pull_request.number }} --json files --jq '.files.[].path')
|
||||
languages=()
|
||||
for lang in actions cpp csharp go java javascript python ql ruby rust swift; do
|
||||
if echo "$changed_files" | grep -qE "^($lang/|shared/)" ; then
|
||||
languages+=("$lang")
|
||||
fi
|
||||
done
|
||||
echo "languages=$(jq -c -n '$ARGS.positional' --args "${languages[@]}")" >> $GITHUB_OUTPUT
|
||||
else
|
||||
# For pushes to main/rc branches, run all languages
|
||||
echo 'languages=["actions","cpp","csharp","go","java","javascript","python","ql","ruby","rust","swift"]' >> $GITHUB_OUTPUT
|
||||
fi
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
|
||||
compile-queries:
|
||||
needs: detect-changes
|
||||
if: github.repository_owner == 'github' && needs.detect-changes.outputs.languages != '[]'
|
||||
if: github.repository_owner == 'github'
|
||||
runs-on: ubuntu-latest-xl
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: ${{ fromJson(needs.detect-changes.outputs.languages) }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
@@ -63,16 +31,16 @@ jobs:
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: ${{ matrix.language }}-queries
|
||||
key: all-queries
|
||||
- name: check formatting
|
||||
run: find shared ${{ matrix.language }}/ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 -n 3000 -P 10 codeql query format -q --check-only
|
||||
run: find shared */ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 -n 3000 -P 10 codeql query format -q --check-only
|
||||
- name: compile queries - check-only
|
||||
# run with --check-only if running in a PR (github.sha != main)
|
||||
if : ${{ github.event_name == 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -q -j0 ${{ matrix.language }}/ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
|
||||
- name: compile queries - full
|
||||
# do full compile if running on main - this populates the cache
|
||||
if : ${{ github.event_name != 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -q -j0 ${{ matrix.language }}/ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
|
||||
|
||||
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: 10.0.100
|
||||
dotnet-version: 9.0.300
|
||||
- name: Extractor unit tests
|
||||
run: |
|
||||
dotnet tool restore
|
||||
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
|
||||
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
|
||||
shell: bash
|
||||
stubgentest:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
16
CODEOWNERS
16
CODEOWNERS
@@ -5,29 +5,19 @@
|
||||
/actions/ @github/codeql-dynamic
|
||||
/cpp/ @github/codeql-c-analysis
|
||||
/csharp/ @github/codeql-csharp
|
||||
/csharp/autobuilder/Semmle.Autobuild.Cpp @github/codeql-c-extractor @github/code-scanning-language-coverage
|
||||
/csharp/autobuilder/Semmle.Autobuild.Cpp.Tests @github/codeql-c-extractor @github/code-scanning-language-coverage
|
||||
/csharp/autobuilder/Semmle.Autobuild.Cpp @github/codeql-c-extractor
|
||||
/csharp/autobuilder/Semmle.Autobuild.Cpp.Tests @github/codeql-c-extractor
|
||||
/go/ @github/codeql-go
|
||||
/go/codeql-tools/ @github/codeql-go @github/code-scanning-language-coverage
|
||||
/go/downgrades/ @github/codeql-go @github/code-scanning-language-coverage
|
||||
/go/extractor/ @github/codeql-go @github/code-scanning-language-coverage
|
||||
/go/extractor-smoke-test/ @github/codeql-go @github/code-scanning-language-coverage
|
||||
/go/ql/test/extractor-tests/ @github/codeql-go @github/code-scanning-language-coverage
|
||||
/java/ @github/codeql-java
|
||||
/javascript/ @github/codeql-javascript
|
||||
/javascript/extractor/ @github/codeql-javascript @github/code-scanning-language-coverage
|
||||
/python/ @github/codeql-python
|
||||
/python/extractor/ @github/codeql-python @github/code-scanning-language-coverage
|
||||
/ql/ @github/codeql-ql-for-ql-reviewers
|
||||
/ruby/ @github/codeql-ruby
|
||||
/ruby/extractor/ @github/codeql-ruby @github/code-scanning-language-coverage
|
||||
/rust/ @github/codeql-rust
|
||||
/rust/extractor/ @github/codeql-rust @github/code-scanning-language-coverage
|
||||
/shared/ @github/codeql-shared-libraries-reviewers
|
||||
/swift/ @github/codeql-swift
|
||||
/swift/extractor/ @github/codeql-swift @github/code-scanning-language-coverage
|
||||
/misc/codegen/ @github/codeql-swift
|
||||
/java/kotlin-extractor/ @github/codeql-kotlin @github/code-scanning-language-coverage
|
||||
/java/kotlin-extractor/ @github/codeql-kotlin
|
||||
/java/ql/test-kotlin1/ @github/codeql-kotlin
|
||||
/java/ql/test-kotlin2/ @github/codeql-kotlin
|
||||
|
||||
|
||||
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 = "12.1.0-codeql.1")
|
||||
bazel_dep(name = "fmt", version = "10.0.0")
|
||||
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.21.5-codeql.1")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.19.2-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 = "10.0.100")
|
||||
dotnet.toolchain(dotnet_version = "9.0.300")
|
||||
use_repo(dotnet, "dotnet_toolchains")
|
||||
|
||||
register_toolchains("@dotnet_toolchains//:all")
|
||||
@@ -269,16 +269,24 @@ 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")
|
||||
|
||||
ripunzip_archive = use_repo_rule("//misc/ripunzip:ripunzip.bzl", "ripunzip_archive")
|
||||
lfs_archive = use_repo_rule("//misc/bazel:lfs.bzl", "lfs_archive")
|
||||
|
||||
# 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",
|
||||
lfs_archive(
|
||||
name = "ripunzip-linux",
|
||||
src = "//misc/ripunzip:ripunzip-Linux.zip",
|
||||
build_file = "//misc/ripunzip:BUILD.ripunzip.bazel",
|
||||
)
|
||||
|
||||
lfs_archive(
|
||||
name = "ripunzip-windows",
|
||||
src = "//misc/ripunzip:ripunzip-Windows.zip",
|
||||
build_file = "//misc/ripunzip:BUILD.ripunzip.bazel",
|
||||
)
|
||||
|
||||
lfs_archive(
|
||||
name = "ripunzip-macos",
|
||||
src = "//misc/ripunzip:ripunzip-macOS.zip",
|
||||
build_file = "//misc/ripunzip:BUILD.ripunzip.bazel",
|
||||
)
|
||||
|
||||
register_toolchains(
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
lockVersion: 1.0.0
|
||||
dependencies: {}
|
||||
compiled: false
|
||||
@@ -1,7 +0,0 @@
|
||||
name: codeql/actions-examples
|
||||
groups:
|
||||
- actions
|
||||
- examples
|
||||
dependencies:
|
||||
codeql/actions-all: ${workspace}
|
||||
warnOnImplicitThis: true
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* @name Uses step with pinned SHA
|
||||
* @description Finds 'uses' steps where the version is a pinned SHA.
|
||||
* @id actions/examples/uses-pinned-sha
|
||||
* @tags example
|
||||
*/
|
||||
|
||||
import actions
|
||||
|
||||
from UsesStep uses
|
||||
where uses.getVersion().regexpMatch("^[A-Fa-f0-9]{40}$")
|
||||
select uses, "This 'uses' step has a pinned SHA version."
|
||||
@@ -1,33 +1,3 @@
|
||||
## 0.4.26
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* 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`.
|
||||
|
||||
## 0.4.25
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 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.4.19
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.20
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.21
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.22
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.23
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.24
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.25
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,5 +0,0 @@
|
||||
## 0.4.26
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* 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`.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.26
|
||||
lastReleaseVersion: 0.4.19
|
||||
|
||||
@@ -19,7 +19,12 @@ 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
|
||||
not isGithubScriptUsingToJson(sink.asExpr())
|
||||
// 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(), _))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,38 +91,3 @@ 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.27-dev
|
||||
version: 0.4.20-dev
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,31 +1,3 @@
|
||||
## 0.6.18
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.17
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 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.
|
||||
|
||||
## 0.6.11
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -20,7 +20,10 @@ import CodeInjectionFlow::PathGraph
|
||||
import codeql.actions.security.ControlChecks
|
||||
|
||||
from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink, Event event
|
||||
where criticalSeverityCodeInjection(source, sink, event)
|
||||
where
|
||||
CodeInjectionFlow::flowPath(source, sink) and
|
||||
event = getRelevantCriticalEventForSink(sink.getNode()) and
|
||||
source.getNode().(RemoteFlowSource).getEventName() = event.getName()
|
||||
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,7 +19,15 @@ import codeql.actions.security.CodeInjectionQuery
|
||||
import CodeInjectionFlow::PathGraph
|
||||
|
||||
from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink
|
||||
where mediumSeverityCodeInjection(source, 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(), _))
|
||||
)
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential code injection in $@, which may be controlled by an external user.", sink,
|
||||
sink.getNode().asExpr().(Expression).getRawExpression()
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
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.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.12
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.13
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.14
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.15
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.16
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.17
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.18
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.18
|
||||
lastReleaseVersion: 0.6.11
|
||||
|
||||
@@ -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.19-dev
|
||||
version: 0.6.12-dev
|
||||
library: false
|
||||
warnOnImplicitThis: true
|
||||
groups: [actions, queries]
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
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,16 +435,6 @@ 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,16 +435,6 @@ 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 |
|
||||
@@ -729,16 +719,6 @@ 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 }} |
|
||||
@@ -749,10 +729,6 @@ 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,13 +276,5 @@
|
||||
"Python model summaries test extension": [
|
||||
"python/ql/test/library-tests/dataflow/model-summaries/InlineTaintTest.ext.yml",
|
||||
"python/ql/test/library-tests/dataflow/model-summaries/NormalDataflowTest.ext.yml"
|
||||
],
|
||||
"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"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
class Expr extends @expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_default {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
predicate isExprWithNewBuiltin(Expr expr) {
|
||||
exists(int kind | exprs(expr, kind, _) | 394 <= kind and kind <= 396)
|
||||
}
|
||||
|
||||
from Expr expr, int kind, int kind_new, Location location
|
||||
where
|
||||
exprs(expr, kind, location) and
|
||||
if isExprWithNewBuiltin(expr) then kind_new = 1 else kind_new = kind
|
||||
select expr, kind_new, location
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
||||
description: Add new builtin operations and this parameter access table
|
||||
compatibility: partial
|
||||
exprs.rel: run exprs.qlo
|
||||
param_ref_to_this.rel: delete
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
description: Support expanded compilation argument lists
|
||||
compatibility: full
|
||||
compilation_expanded_args.rel: delete
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
description: Fix decltype qualifier issue
|
||||
compatibility: full
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
description: Sections for databaseMetadata and overlayChangedFiles
|
||||
compatibility: full
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
||||
description: Add databaseMetadata and overlayChangedFiles relations
|
||||
compatibility: full
|
||||
databaseMetadata.rel: delete
|
||||
overlayChangedFiles.rel: delete
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
description: Remove _Decimal{32,64,128} types
|
||||
compatibility: full
|
||||
@@ -1,59 +1,3 @@
|
||||
## 7.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The `_Decimal32`, `_Decimal64`, and `_Decimal128` types are no longer exposed as builtin types. Support for these gcc-specific types was incomplete, and are generally not used in C/C++ codebases.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The `OverloadedArrayExpr::getArrayOffset/0` predicate has been deprecated. Use `OverloadedArrayExpr::getArrayOffset/1` and `OverloadedArrayExpr::getAnArrayOffset` instead.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added subclasses of `BuiltInOperations` for the `__is_bitwise_cloneable`, `__is_invocable`, and `__is_nothrow_invocable` builtin operations.
|
||||
* Added a `isThisAccess` predicate to `ParamAccessForType` that holds when the access is to the implicit object parameter.
|
||||
* Predicates `getArrayOffset/1` and `getAnArrayOffset` have been added to the `OverloadedArrayExpr` class to support C++23 multidimensional subscript operators.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Some constants will now be represented by their unfolded expression trees. The `isConstant` predicate of `Expr` will no longer yield a result for those constants.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed a bug in the `DataFlow::BarrierGuard<...>::getABarrierNode` predicate which caused the predicate to return `DataFlow::Node`s with incorrect indirections. If you use `getABarrierNode` to implement barriers in a dataflow/taint-tracking query it may result in more query results. You can use `DataFlow::BarrierGuard<...>::getAnIndirectBarrierNode` to remove those query results.
|
||||
|
||||
## 6.1.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 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.
|
||||
|
||||
## 6.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Improve performance of the range analysis in cases where it would otherwise take an exorbitant amount of time.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 6.0.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,9 +0,0 @@
|
||||
## 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.
|
||||
@@ -1,5 +0,0 @@
|
||||
## 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`.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 6.1.2
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 6.1.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 6.1.4
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,23 +0,0 @@
|
||||
## 7.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The `_Decimal32`, `_Decimal64`, and `_Decimal128` types are no longer exposed as builtin types. Support for these gcc-specific types was incomplete, and are generally not used in C/C++ codebases.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The `OverloadedArrayExpr::getArrayOffset/0` predicate has been deprecated. Use `OverloadedArrayExpr::getArrayOffset/1` and `OverloadedArrayExpr::getAnArrayOffset` instead.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added subclasses of `BuiltInOperations` for the `__is_bitwise_cloneable`, `__is_invocable`, and `__is_nothrow_invocable` builtin operations.
|
||||
* Added a `isThisAccess` predicate to `ParamAccessForType` that holds when the access is to the implicit object parameter.
|
||||
* Predicates `getArrayOffset/1` and `getAnArrayOffset` have been added to the `OverloadedArrayExpr` class to support C++23 multidimensional subscript operators.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Some constants will now be represented by their unfolded expression trees. The `isConstant` predicate of `Expr` will no longer yield a result for those constants.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed a bug in the `DataFlow::BarrierGuard<...>::getABarrierNode` predicate which caused the predicate to return `DataFlow::Node`s with incorrect indirections. If you use `getABarrierNode` to implement barriers in a dataflow/taint-tracking query it may result in more query results. You can use `DataFlow::BarrierGuard<...>::getAnIndirectBarrierNode` to remove those query results.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 7.0.0
|
||||
lastReleaseVersion: 6.0.0
|
||||
|
||||
@@ -74,4 +74,3 @@ import semmle.code.cpp.Preprocessor
|
||||
import semmle.code.cpp.Iteration
|
||||
import semmle.code.cpp.NameQualifiers
|
||||
import DefaultOptions
|
||||
private import semmle.code.cpp.internal.Overlay
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
|
||||
- ["", "", False, "tolower", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "tolower", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||
- ["", "", False, "toupper", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "toupper", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||
@@ -9,14 +9,6 @@ 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,7 +0,0 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
|
||||
- ["", "", False, "iconv", "", "", "Argument[**1]", "Argument[**3]", "value", "manual"]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 7.0.1-dev
|
||||
version: 6.0.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
@@ -21,4 +21,3 @@ dataExtensions:
|
||||
- ext/deallocation/*.model.yml
|
||||
- ext/allocation/*.model.yml
|
||||
warnOnImplicitThis: true
|
||||
compileForOverlayEval: true
|
||||
|
||||
@@ -94,25 +94,6 @@ 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,14 +171,12 @@ 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), _, _) }
|
||||
|
||||
/**
|
||||
|
||||
@@ -144,14 +144,14 @@ class NameQualifiableElement extends Element, @namequalifiableelement {
|
||||
class NameQualifyingElement extends Element, @namequalifyingelement {
|
||||
/**
|
||||
* Gets a name qualifier for which this is the qualifying namespace or
|
||||
* user-defined type, or decltype. For example: class `X` is the
|
||||
* user-defined type. For example: class `X` is the
|
||||
* `NameQualifyingElement` and `X::` is the `NameQualifier`.
|
||||
*/
|
||||
NameQualifier getANameQualifier() {
|
||||
namequalifiers(unresolveElement(result), _, underlyingElement(this), _)
|
||||
}
|
||||
|
||||
/** Gets the name of this namespace, user-defined type, or decltype. */
|
||||
/** Gets the name of this namespace or user-defined type. */
|
||||
string getName() { none() }
|
||||
}
|
||||
|
||||
|
||||
@@ -1050,10 +1050,10 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
|
||||
expr.(Call).getQualifier() = ele and
|
||||
pred = "getQualifier()"
|
||||
or
|
||||
// OverloadedArrayExpr::getArrayBase/0 and OverloadedArrayExpr::getArrayOffset/1 also consider arguments, and are already handled below.
|
||||
// OverloadedArrayExpr::getArrayBase/0 and OverloadedArrayExpr::getArrayOffset/0 also consider arguments, and are already handled below.
|
||||
exists(int n, Expr arg | expr.(Call).getArgument(n) = arg |
|
||||
not expr.(OverloadedArrayExpr).getArrayBase() = arg and
|
||||
not expr.(OverloadedArrayExpr).getAnArrayOffset() = arg and
|
||||
not expr.(OverloadedArrayExpr).getArrayOffset() = arg and
|
||||
arg = ele and
|
||||
pred = "getArgument(" + n.toString() + ")"
|
||||
)
|
||||
@@ -1062,10 +1062,7 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
|
||||
or
|
||||
expr.(OverloadedArrayExpr).getArrayBase() = ele and pred = "getArrayBase()"
|
||||
or
|
||||
exists(int n |
|
||||
expr.(OverloadedArrayExpr).getArrayOffset(n) = ele and
|
||||
pred = "getArrayOffset(" + n.toString() + ")"
|
||||
)
|
||||
expr.(OverloadedArrayExpr).getArrayOffset() = ele and pred = "getArrayOffset()"
|
||||
or
|
||||
// OverloadedPointerDereferenceExpr::getExpr/0 also considers qualifiers, and is already handled above for all Call classes.
|
||||
not expr.(OverloadedPointerDereferenceExpr).getQualifier() =
|
||||
|
||||
@@ -802,6 +802,15 @@ private predicate floatingPointTypeMapping(
|
||||
// _Complex __float128
|
||||
kind = 39 and base = 2 and domain = TComplexDomain() and realKind = 38 and extended = false
|
||||
or
|
||||
// _Decimal32
|
||||
kind = 40 and base = 10 and domain = TRealDomain() and realKind = 40 and extended = false
|
||||
or
|
||||
// _Decimal64
|
||||
kind = 41 and base = 10 and domain = TRealDomain() and realKind = 41 and extended = false
|
||||
or
|
||||
// _Decimal128
|
||||
kind = 42 and base = 10 and domain = TRealDomain() and realKind = 42 and extended = false
|
||||
or
|
||||
// _Float32
|
||||
kind = 45 and base = 2 and domain = TRealDomain() and realKind = 45 and extended = false
|
||||
or
|
||||
@@ -862,8 +871,9 @@ private predicate floatingPointTypeMapping(
|
||||
|
||||
/**
|
||||
* The C/C++ floating point types. See 4.5. This includes `float`, `double` and `long double`, the
|
||||
* fixed-size floating-point types like `_Float32`, and the extended-precision floating-point types
|
||||
* like `_Float64x`. It also includes the complex and imaginary versions of all of these types.
|
||||
* fixed-size floating-point types like `_Float32`, the extended-precision floating-point types like
|
||||
* `_Float64x`, and the decimal floating-point types like `_Decimal32`. It also includes the complex
|
||||
* and imaginary versions of all of these types.
|
||||
*/
|
||||
class FloatingPointType extends ArithmeticType {
|
||||
final int base;
|
||||
@@ -981,6 +991,42 @@ class Float128Type extends RealNumberType, BinaryFloatingPointType {
|
||||
override string getAPrimaryQlClass() { result = "Float128Type" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The GNU C `_Decimal32` primitive type. This is not standard C/C++.
|
||||
* ```
|
||||
* _Decimal32 d32;
|
||||
* ```
|
||||
*/
|
||||
class Decimal32Type extends RealNumberType, DecimalFloatingPointType {
|
||||
Decimal32Type() { builtintypes(underlyingElement(this), _, 40, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Decimal32Type" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The GNU C `_Decimal64` primitive type. This is not standard C/C++.
|
||||
* ```
|
||||
* _Decimal64 d64;
|
||||
* ```
|
||||
*/
|
||||
class Decimal64Type extends RealNumberType, DecimalFloatingPointType {
|
||||
Decimal64Type() { builtintypes(underlyingElement(this), _, 41, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Decimal64Type" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The GNU C `_Decimal128` primitive type. This is not standard C/C++.
|
||||
* ```
|
||||
* _Decimal128 d128;
|
||||
* ```
|
||||
*/
|
||||
class Decimal128Type extends RealNumberType, DecimalFloatingPointType {
|
||||
Decimal128Type() { builtintypes(underlyingElement(this), _, 42, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Decimal128Type" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The C/C++ `void` type. See 4.7.
|
||||
* ```
|
||||
@@ -1100,7 +1146,7 @@ class DerivedType extends Type, @derivedtype {
|
||||
* decltype(a) b;
|
||||
* ```
|
||||
*/
|
||||
class Decltype extends Type, NameQualifyingElement {
|
||||
class Decltype extends Type {
|
||||
Decltype() { decltypes(underlyingElement(this), _, 0, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Decltype" }
|
||||
@@ -1141,7 +1187,7 @@ class Decltype extends Type, NameQualifyingElement {
|
||||
|
||||
override string toString() { result = "decltype(...)" }
|
||||
|
||||
override string getName() { result = "decltype(...)" }
|
||||
override string getName() { none() }
|
||||
|
||||
override int getSize() { result = this.getBaseType().getSize() }
|
||||
|
||||
@@ -1201,7 +1247,7 @@ class TypeofType extends Type {
|
||||
|
||||
override string toString() { result = "typeof(...)" }
|
||||
|
||||
override string getName() { result = "typeof(...)" }
|
||||
override string getName() { none() }
|
||||
|
||||
override int getSize() { result = this.getBaseType().getSize() }
|
||||
|
||||
@@ -1265,6 +1311,8 @@ class TypeofTypeType extends TypeofType {
|
||||
Type getType() { type_operators(underlyingElement(this), unresolveElement(result), _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TypeofTypeType" }
|
||||
|
||||
override string toString() { result = "typeof(...)" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1346,7 +1394,7 @@ class IntrinsicTransformedType extends Type {
|
||||
|
||||
override Type resolveTypedefs() { result = this.getBaseType().resolveTypedefs() }
|
||||
|
||||
override string getName() { result = this.getIntrinsicName() + "(...)" }
|
||||
override string getName() { none() }
|
||||
|
||||
override int getSize() { result = this.getBaseType().getSize() }
|
||||
|
||||
|
||||
@@ -703,7 +703,6 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardConditionImpl
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
override predicate comparesLt(
|
||||
Cpp::Expr left, Cpp::Expr right, int k, boolean isLessThan, boolean testIsTrue
|
||||
) {
|
||||
@@ -714,7 +713,6 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardConditionImpl
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
override predicate comparesLt(Cpp::Expr e, int k, boolean isLessThan, GuardValue value) {
|
||||
exists(GuardValue partValue, GuardCondition part |
|
||||
this.(Cpp::BinaryLogicalOperation)
|
||||
@@ -740,7 +738,6 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardConditionImpl
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
override predicate comparesEq(
|
||||
Cpp::Expr left, Cpp::Expr right, int k, boolean areEqual, boolean testIsTrue
|
||||
) {
|
||||
@@ -760,7 +757,6 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardConditionImpl
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
override predicate comparesEq(Cpp::Expr e, int k, boolean areEqual, GuardValue value) {
|
||||
exists(GuardValue partValue, GuardCondition part |
|
||||
this.(Cpp::BinaryLogicalOperation)
|
||||
|
||||
@@ -15,17 +15,16 @@
|
||||
* reading.
|
||||
* 1. The `namespace` column selects a namespace.
|
||||
* 2. The `type` column selects a type within that namespace. This column can
|
||||
* introduce template type names that can be mentioned in the `signature` column.
|
||||
* introduce template names that can be mentioned in the `signature` column.
|
||||
* For example, `vector<T,Allocator>` introduces the template names `T` and
|
||||
* `Allocator`. Non-type template parameters cannot be specified.
|
||||
* `Allocator`.
|
||||
* 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 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.
|
||||
* 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`.
|
||||
* 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
|
||||
@@ -101,10 +100,9 @@ private import internal.FlowSummaryImpl
|
||||
private import internal.FlowSummaryImpl::Public
|
||||
private import internal.FlowSummaryImpl::Private
|
||||
private import internal.FlowSummaryImpl::Private::External
|
||||
private import internal.ExternalFlowExtensions::Extensions as Extensions
|
||||
private import internal.ExternalFlowExtensions 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.
|
||||
@@ -145,81 +143,134 @@ 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) }
|
||||
|
||||
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 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 MaD = SharedMaD::ModelsAsData<Extensions, MadInput>;
|
||||
/** 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()
|
||||
)
|
||||
}
|
||||
|
||||
import MaD
|
||||
/**
|
||||
* 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
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `input` is `input0`, but with all occurrences of `@` replaced
|
||||
@@ -242,13 +293,69 @@ predicate summaryModel(
|
||||
string input, string output, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string input0, string output0 |
|
||||
MaD::summaryModel(namespace, type, subtypes, name, signature, ext, input0, output0, kind,
|
||||
summaryModel0(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() {
|
||||
@@ -526,28 +633,6 @@ 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).
|
||||
@@ -555,51 +640,27 @@ private Locatable getSupportedFunctionTemplateArgument(Function templateFunction
|
||||
private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remaining) {
|
||||
exists(Function templateFunction |
|
||||
templateFunction = getFullyTemplatedFunction(f) and
|
||||
remaining = getNumberOfSupportedFunctionTemplateArguments(templateFunction) and
|
||||
remaining = templateFunction.getNumberOfTemplateArguments() 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 = getSupportedFunctionTemplateArgument(templateFunction, remaining)
|
||||
|
|
||||
tp = templateFunction.getTemplateArgument(remaining) and
|
||||
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).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
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 = getNumberOfSupportedClassTemplateArguments(template) and
|
||||
remaining = template.getNumberOfTemplateArguments() and
|
||||
result = getTypeNameWithoutFunctionTemplates(f, n, 0)
|
||||
)
|
||||
or
|
||||
@@ -611,8 +672,7 @@ 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 = getSupportedClassTemplateArgument(template, remaining)
|
||||
|
|
||||
tp = template.getTemplateArgument(remaining) and
|
||||
result = mid.replaceAll(tp.getName(), "class:" + remaining.toString())
|
||||
)
|
||||
}
|
||||
@@ -667,7 +727,6 @@ private string getSignatureWithoutClassTemplateNames(
|
||||
* - The `remaining` number of template arguments in `partiallyNormalizedSignature`
|
||||
* with their index in `nameArgs`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private string getSignatureWithoutFunctionTemplateNames(
|
||||
string partiallyNormalizedSignature, string typeArgs, string nameArgs, int remaining
|
||||
) {
|
||||
@@ -711,7 +770,6 @@ private string getSignatureWithoutFunctionTemplateNames(
|
||||
* ```
|
||||
* In this case, `normalizedSignature` will be `"(const func:0 &,int,class:1,class:0 *)"`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate elementSpecWithArguments(
|
||||
string signature, string type, string name, string normalizedSignature, string typeArgs,
|
||||
string nameArgs
|
||||
@@ -731,35 +789,6 @@ private string getSignatureParameterName(string signature, string type, string n
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a `Function` identified by the `(namespace, type, name)` components.
|
||||
*
|
||||
* If `subtypes` is `true` then the result may be an override of the function
|
||||
* identified by the components.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private Function getFunction(string namespace, string type, boolean subtypes, string name) {
|
||||
elementSpec(namespace, type, subtypes, name, _, _) and
|
||||
(
|
||||
funcHasQualifiedName(result, namespace, name) and
|
||||
subtypes = false and
|
||||
type = ""
|
||||
or
|
||||
exists(Class namedClass, Class classWithMethod |
|
||||
hasClassAndName(classWithMethod, result, name) and
|
||||
classHasQualifiedName(namedClass, namespace, type)
|
||||
|
|
||||
// member declared in the named type or a subtype of it
|
||||
subtypes = true and
|
||||
classWithMethod = namedClass.getADerivedClass*()
|
||||
or
|
||||
// member declared directly in the named type
|
||||
subtypes = false and
|
||||
classWithMethod = namedClass
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the suffix containing the entries in `signature` starting at entry
|
||||
* `i` matches the suffix containing the parameters of `func` starting at entry `i`.
|
||||
@@ -783,17 +812,13 @@ private Function getFunction(string namespace, string type, boolean subtypes, st
|
||||
* is `func:n` then the signature name is compared with the `n`'th name
|
||||
* in `name`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate signatureMatches(
|
||||
Function func, string namespace, string signature, string type, string name, int i
|
||||
) {
|
||||
func = getFunction(namespace, type, _, name) and
|
||||
private predicate signatureMatches(Function func, string signature, string type, string name, int i) {
|
||||
exists(string s |
|
||||
s = getSignatureParameterName(signature, type, name, i) and
|
||||
s = getParameterTypeName(func, i)
|
||||
) and
|
||||
if exists(getParameterTypeName(func, i + 1))
|
||||
then signatureMatches(func, namespace, signature, type, name, i + 1)
|
||||
then signatureMatches(func, signature, type, name, i + 1)
|
||||
else i = count(signature.indexOf(","))
|
||||
}
|
||||
|
||||
@@ -808,7 +833,7 @@ module ExternalFlowDebug {
|
||||
*
|
||||
* Exposed for testing purposes.
|
||||
*/
|
||||
predicate signatureMatches_debug = signatureMatches/6;
|
||||
predicate signatureMatches_debug = signatureMatches/5;
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
@@ -858,7 +883,6 @@ private predicate parseParens(string s, string betweenParens) { s = "(" + betwee
|
||||
* - `signatureWithoutParens` equals `signature`, but with the surrounding
|
||||
* parentheses removed.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate elementSpecWithArguments0(
|
||||
string signature, string type, string name, string signatureWithoutParens, string typeArgs,
|
||||
string nameArgs
|
||||
@@ -885,7 +909,7 @@ private predicate elementSpecMatchesSignature(
|
||||
) {
|
||||
elementSpec(namespace, pragma[only_bind_into](type), subtypes, pragma[only_bind_into](name),
|
||||
pragma[only_bind_into](signature), _) and
|
||||
signatureMatches(func, namespace, signature, type, name, 0)
|
||||
signatureMatches(func, signature, type, name, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -929,7 +953,7 @@ private predicate funcHasQualifiedName(Function func, string namespace, string n
|
||||
* Holds if `namedClass` is in namespace `namespace` and has
|
||||
* name `type` (excluding any template parameters).
|
||||
*/
|
||||
bindingset[type]
|
||||
bindingset[type, namespace]
|
||||
pragma[inline_late]
|
||||
private predicate classHasQualifiedName(Class namedClass, string namespace, string type) {
|
||||
exists(string typeWithoutArgs |
|
||||
@@ -945,14 +969,17 @@ private predicate classHasQualifiedName(Class namedClass, string namespace, stri
|
||||
* are also returned.
|
||||
* 3. The element has name `name`
|
||||
* 4. If `signature` is non-empty, then the element has a list of parameter types described by `signature`.
|
||||
*
|
||||
* NOTE: `namespace` is currently not used (since we don't properly extract modules yet).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private Element interpretElement0(
|
||||
string namespace, string type, boolean subtypes, string name, string signature
|
||||
) {
|
||||
result = getFunction(namespace, type, subtypes, name) and
|
||||
(
|
||||
// Non-member functions
|
||||
funcHasQualifiedName(result, namespace, name) and
|
||||
subtypes = false and
|
||||
type = "" and
|
||||
(
|
||||
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
|
||||
@@ -962,36 +989,52 @@ private Element interpretElement0(
|
||||
)
|
||||
or
|
||||
// Member functions
|
||||
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
|
||||
exists(Class namedClass, Class classWithMethod |
|
||||
hasClassAndName(classWithMethod, result, name) and
|
||||
classHasQualifiedName(namedClass, namespace, type)
|
||||
|
|
||||
(
|
||||
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
|
||||
or
|
||||
signature = "" and
|
||||
elementSpec(namespace, type, subtypes, name, "", _)
|
||||
) and
|
||||
(
|
||||
// member declared in the named type or a subtype of it
|
||||
subtypes = true and
|
||||
classWithMethod = namedClass.getADerivedClass*()
|
||||
or
|
||||
// member declared directly in the named type
|
||||
subtypes = false and
|
||||
classWithMethod = namedClass
|
||||
)
|
||||
)
|
||||
or
|
||||
elementSpec(namespace, type, subtypes, name, signature, _) and
|
||||
// Member variables
|
||||
signature = "" and
|
||||
elementSpec(namespace, type, subtypes, name, signature, _)
|
||||
)
|
||||
or
|
||||
// Member variables
|
||||
elementSpec(namespace, type, subtypes, name, signature, _) and
|
||||
signature = "" and
|
||||
exists(Class namedClass, Class classWithMember, MemberVariable member |
|
||||
member.getName() = name and
|
||||
member = classWithMember.getAMember() and
|
||||
namedClass.hasQualifiedName(namespace, type) and
|
||||
result = member
|
||||
|
|
||||
// field declared in the named type or a subtype of it (or an extension of any)
|
||||
subtypes = true and
|
||||
classWithMember = namedClass.getADerivedClass*()
|
||||
exists(Class namedClass, Class classWithMember, MemberVariable member |
|
||||
member.getName() = name and
|
||||
member = classWithMember.getAMember() and
|
||||
namedClass.hasQualifiedName(namespace, type) and
|
||||
result = member
|
||||
|
|
||||
// field declared in the named type or a subtype of it (or an extension of any)
|
||||
subtypes = true and
|
||||
classWithMember = namedClass.getADerivedClass*()
|
||||
or
|
||||
// field declared directly in the named type (or an extension of it)
|
||||
subtypes = false and
|
||||
classWithMember = namedClass
|
||||
)
|
||||
or
|
||||
// field declared directly in the named type (or an extension of it)
|
||||
// Global or namespace variables
|
||||
elementSpec(namespace, type, subtypes, name, signature, _) and
|
||||
signature = "" and
|
||||
type = "" and
|
||||
subtypes = false and
|
||||
classWithMember = namedClass
|
||||
result = any(GlobalOrNamespaceVariable v | v.hasQualifiedName(namespace, name))
|
||||
)
|
||||
or
|
||||
// Global or namespace variables
|
||||
elementSpec(namespace, type, subtypes, name, signature, _) and
|
||||
signature = "" and
|
||||
type = "" and
|
||||
subtypes = false and
|
||||
result = any(GlobalOrNamespaceVariable v | v.hasQualifiedName(namespace, name))
|
||||
}
|
||||
|
||||
cached
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
* 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.
|
||||
*/
|
||||
@@ -20,22 +18,6 @@ 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.
|
||||
*/
|
||||
@@ -43,16 +25,3 @@ 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,19 +148,6 @@ 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)
|
||||
|
||||
@@ -394,11 +394,6 @@ class FunctionAccess extends Access, @routineexpr {
|
||||
*/
|
||||
class ParamAccessForType extends Expr, @param_ref {
|
||||
override string toString() { result = "param access" }
|
||||
|
||||
/**
|
||||
* Holds if the accessed parameter is implicit object parameter of the function.
|
||||
*/
|
||||
predicate isThisAccess() { param_ref_to_this(underlyingElement(this)) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1941,61 +1941,3 @@ class BuiltInOperationIsTriviallyRelocatable extends BuiltInOperation, @istrivia
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyRelocatable" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_bitwise_cloneable` built-in operation.
|
||||
*
|
||||
* Returns `true` if an object of type `_Tp` is bitwise cloneable.
|
||||
*
|
||||
* ```
|
||||
* template<typename _Tp>
|
||||
* struct is_bitwise_cloneable
|
||||
* : public integral_constant<bool, __is_bitwise_cloneable(_Tp)>
|
||||
* {};
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsBitwiseCloneable extends BuiltInOperation, @isbitwisecloneable {
|
||||
override string toString() { result = "__is_bitwise_cloneable" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsBitwiseCloneable" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_invocable` built-in operation (used by some implementations
|
||||
* of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if a function of type `_FTpn` can be invoked with arguments of
|
||||
* type `_Tps`.
|
||||
*
|
||||
* ```
|
||||
* template<typename _FTpn, typename... _Tps>
|
||||
* struct is_invocable
|
||||
* : public integral_constant<bool, __is_invocable(_FTpn, _Tps...)>
|
||||
* {};
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsInvocable extends BuiltInOperation, @isinvocable {
|
||||
override string toString() { result = "__is_invocable" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsInvocable" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_nothrow_invocable` built-in operation (used by some implementations
|
||||
* of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if a function of non-throwing type `_FTpn` can be invoked
|
||||
* with arguments of type `_Tps`.
|
||||
*
|
||||
* ```
|
||||
* template<typename _FTpn, typename... _Tps>
|
||||
* struct is_nothrow_invocable
|
||||
* : public integral_constant<bool, __is_nothrow_invocable(_FTpn, _Tps...)>
|
||||
* {};
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsNothrowInvocable extends BuiltInOperation, @isnothrowinvocable {
|
||||
override string toString() { result = "__is_nothrow_invocable" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowInvocable" }
|
||||
}
|
||||
|
||||
@@ -387,23 +387,10 @@ class OverloadedArrayExpr extends FunctionCall {
|
||||
|
||||
/**
|
||||
* Gets the expression giving the index.
|
||||
*
|
||||
* DEPRECATED: Use getArrayOffset/1 instead.
|
||||
*/
|
||||
deprecated Expr getArrayOffset() { result = this.getArrayOffset(0) }
|
||||
|
||||
/**
|
||||
* Gets the expression giving the nth index.
|
||||
*/
|
||||
Expr getArrayOffset(int n) {
|
||||
n >= 0 and
|
||||
if exists(this.getQualifier()) then result = this.getChild(n) else result = this.getChild(n + 1)
|
||||
Expr getArrayOffset() {
|
||||
if exists(this.getQualifier()) then result = this.getChild(0) else result = this.getChild(1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression giving an index.
|
||||
*/
|
||||
Expr getAnArrayOffset() { result = this.getArrayOffset(_) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -750,16 +750,6 @@ 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
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -776,8 +766,6 @@ 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() }
|
||||
@@ -796,7 +784,8 @@ class SizeofTypeOperator extends SizeofOperator {
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SizeofTypeOperator" }
|
||||
|
||||
override Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
/** Gets the contained type. */
|
||||
Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
override string toString() { result = "sizeof(" + this.getTypeOperand().getName() + ")" }
|
||||
|
||||
@@ -853,16 +842,6 @@ 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() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -876,8 +855,6 @@ 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() }
|
||||
@@ -893,7 +870,8 @@ class DatasizeofTypeOperator extends DatasizeofOperator {
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DatasizeofTypeOperator" }
|
||||
|
||||
override Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
/** Gets the contained type. */
|
||||
Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
override string toString() { result = "__datasizeof(" + this.getTypeOperand().getName() + ")" }
|
||||
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/**
|
||||
* 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))
|
||||
)
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
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,10 +861,6 @@ 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
|
||||
@@ -877,17 +873,23 @@ private int getIndirectionIndexLate(Content c) { result = c.getIndirectionIndex(
|
||||
predicate storeStepImpl(Node node1, Content c, Node node2, boolean certain) {
|
||||
exists(
|
||||
PostFieldUpdateNode postFieldUpdate, int indirectionIndex1, int numberOfLoads,
|
||||
StoreInstruction store, FieldContent fc
|
||||
StoreInstruction store
|
||||
|
|
||||
postFieldUpdate = node2 and
|
||||
fc = c and
|
||||
nodeHasInstruction(node1, pragma[only_bind_into](store),
|
||||
pragma[only_bind_into](indirectionIndex1)) and
|
||||
nodeHasInstruction(node1, store, pragma[only_bind_into](indirectionIndex1)) and
|
||||
postFieldUpdate.getIndirectionIndex() = 1 and
|
||||
numberOfLoadsFromOperand(postFieldUpdate.getFieldAddress(),
|
||||
store.getDestinationAddressOperand(), numberOfLoads, certain) and
|
||||
fc.getAField() = postFieldUpdate.getUpdatedField() and
|
||||
getIndirectionIndexLate(fc) = 1 + indirectionIndex1 + numberOfLoads
|
||||
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
|
||||
)
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
@@ -963,17 +965,22 @@ 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, FieldContent fc
|
||||
|
|
||||
fc = c and
|
||||
exists(FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2 |
|
||||
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, _) and
|
||||
fc.getAField() = fa1.getField() and
|
||||
getIndirectionIndexLate(fc) = indirectionIndex2 + numberOfLoads
|
||||
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
|
||||
)
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
@@ -1567,7 +1574,7 @@ pragma[inline]
|
||||
ContentApprox getContentApprox(Content c) {
|
||||
exists(string prefix, Field f |
|
||||
prefix = result.(FieldApproxContent).getPrefix() and
|
||||
f = c.(NonUnionFieldContent).getField() and
|
||||
f = c.(FieldContent).getField() and
|
||||
fieldHasApproxName(f, prefix)
|
||||
)
|
||||
or
|
||||
|
||||
@@ -156,7 +156,7 @@ class Node extends TIRDataFlowNode {
|
||||
* If `isGLValue()` holds, then the type of this node
|
||||
* should be thought of as "pointer to `getType()`".
|
||||
*/
|
||||
Type getType() { none() } // overridden in subclasses
|
||||
DataFlowType getType() { none() } // overridden in subclasses
|
||||
|
||||
/** Gets the instruction corresponding to this node, if any. */
|
||||
Instruction asInstruction() { result = this.(InstructionNode).getInstruction() }
|
||||
@@ -541,7 +541,7 @@ class Node extends TIRDataFlowNode {
|
||||
/**
|
||||
* Gets an upper bound on the type of this node.
|
||||
*/
|
||||
Type getTypeBound() { result = this.getType() }
|
||||
DataFlowType getTypeBound() { result = this.getType() }
|
||||
|
||||
/** Gets the location of this element. */
|
||||
cached
|
||||
@@ -585,7 +585,7 @@ private class Node0 extends Node, TNode0 {
|
||||
|
||||
override string toStringImpl() { result = node.toString() }
|
||||
|
||||
override Type getType() { result = node.getType() }
|
||||
override DataFlowType getType() { result = node.getType() }
|
||||
|
||||
override predicate isGLValue() { node.isGLValue() }
|
||||
}
|
||||
@@ -704,7 +704,7 @@ class SsaSynthNode extends Node, TSsaSynthNode {
|
||||
|
||||
override Declaration getFunction() { result = node.getBasicBlock().getEnclosingFunction() }
|
||||
|
||||
override Type getType() { result = node.getSourceVariable().getType() }
|
||||
override DataFlowType getType() { result = node.getSourceVariable().getType() }
|
||||
|
||||
override predicate isGLValue() { node.getSourceVariable().isGLValue() }
|
||||
|
||||
@@ -732,7 +732,7 @@ class SsaIteratorNode extends Node, TSsaIteratorNode {
|
||||
|
||||
override Declaration getFunction() { result = node.getFunction() }
|
||||
|
||||
override Type getType() { result = node.getType() }
|
||||
override DataFlowType getType() { result = node.getType() }
|
||||
|
||||
final override Location getLocationImpl() { result = node.getLocation() }
|
||||
|
||||
@@ -792,7 +792,7 @@ class FinalGlobalValue extends Node, TFinalGlobalValue {
|
||||
|
||||
override Declaration getFunction() { result = globalUse.getIRFunction().getFunction() }
|
||||
|
||||
override Type getType() {
|
||||
override DataFlowType getType() {
|
||||
exists(int indirectionIndex |
|
||||
indirectionIndex = globalUse.getIndirectionIndex() and
|
||||
result = getTypeImpl(globalUse.getUnderlyingType(), indirectionIndex)
|
||||
@@ -826,7 +826,7 @@ class InitialGlobalValue extends Node, TInitialGlobalValue {
|
||||
|
||||
final override predicate isGLValue() { globalDef.getIndirectionIndex() = 0 }
|
||||
|
||||
override Type getType() { result = globalDef.getUnderlyingType() }
|
||||
override DataFlowType getType() { result = globalDef.getUnderlyingType() }
|
||||
|
||||
final override Location getLocationImpl() { result = globalDef.getLocation() }
|
||||
|
||||
@@ -853,7 +853,7 @@ class BodyLessParameterNodeImpl extends Node, TBodyLessParameterNodeImpl {
|
||||
/** Gets the indirection index of this node. */
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
override Type getType() {
|
||||
override DataFlowType getType() {
|
||||
result = getTypeImpl(p.getUnderlyingType(), this.getIndirectionIndex())
|
||||
}
|
||||
|
||||
@@ -1117,8 +1117,8 @@ private module RawIndirectNodes {
|
||||
|
||||
override predicate isGLValue() { this.getOperand().isGLValue() }
|
||||
|
||||
override Type getType() {
|
||||
exists(int sub, Type type, boolean isGLValue |
|
||||
override DataFlowType getType() {
|
||||
exists(int sub, DataFlowType type, boolean isGLValue |
|
||||
type = getOperandType(this.getOperand(), isGLValue) and
|
||||
if isGLValue = true then sub = 1 else sub = 0
|
||||
|
|
||||
@@ -1163,8 +1163,8 @@ private module RawIndirectNodes {
|
||||
|
||||
override predicate isGLValue() { this.getInstruction().isGLValue() }
|
||||
|
||||
override Type getType() {
|
||||
exists(int sub, Type type, boolean isGLValue |
|
||||
override DataFlowType getType() {
|
||||
exists(int sub, DataFlowType type, boolean isGLValue |
|
||||
type = getInstructionType(this.getInstruction(), isGLValue) and
|
||||
if isGLValue = true then sub = 1 else sub = 0
|
||||
|
|
||||
@@ -1263,7 +1263,7 @@ class FinalParameterNode extends Node, TFinalParameterNode {
|
||||
result.asSourceCallable() = this.getFunction()
|
||||
}
|
||||
|
||||
override Type getType() { result = getTypeImpl(p.getUnderlyingType(), indirectionIndex) }
|
||||
override DataFlowType getType() { result = getTypeImpl(p.getUnderlyingType(), indirectionIndex) }
|
||||
|
||||
final override Location getLocationImpl() {
|
||||
// Parameters can have multiple locations. When there's a unique location we use
|
||||
@@ -1539,7 +1539,7 @@ abstract class PostUpdateNode extends Node {
|
||||
*/
|
||||
abstract Node getPreUpdateNode();
|
||||
|
||||
final override Type getType() { result = this.getPreUpdateNode().getType() }
|
||||
final override DataFlowType getType() { result = this.getPreUpdateNode().getType() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1632,7 +1632,9 @@ class VariableNode extends Node, TGlobalLikeVariableNode {
|
||||
result.asSourceCallable() = v
|
||||
}
|
||||
|
||||
override Type getType() { result = getTypeImpl(v.getUnderlyingType(), indirectionIndex - 1) }
|
||||
override DataFlowType getType() {
|
||||
result = getTypeImpl(v.getUnderlyingType(), indirectionIndex - 1)
|
||||
}
|
||||
|
||||
final override Location getLocationImpl() {
|
||||
// Certain variables (such as parameters) can have multiple locations.
|
||||
@@ -2076,151 +2078,38 @@ 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(CanonicalField f) { result = max(f.getAType().getSize()) }
|
||||
private int getFieldSize(Field f) { result = f.getType().getSize() }
|
||||
|
||||
/**
|
||||
* Gets a field in the union `u` whose size
|
||||
* is `bytes` number of bytes.
|
||||
*/
|
||||
private CanonicalField getAFieldWithSize(CanonicalUnion u, int bytes) {
|
||||
result = u.getACanonicalField() and
|
||||
private Field getAFieldWithSize(Union u, int bytes) {
|
||||
result = u.getAField() and
|
||||
bytes = getFieldSize(result)
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TContent =
|
||||
TNonUnionContent(CanonicalField f, int indirectionIndex) {
|
||||
// the indirection index for field content starts at 1 (because `TNonUnionContent` is thought of as
|
||||
TFieldContent(Field f, int indirectionIndex) {
|
||||
// the indirection index for field content starts at 1 (because `TFieldContent` is thought of as
|
||||
// the address of the field, `FieldAddress` in the IR).
|
||||
indirectionIndex = [1 .. max(SsaImpl::getMaxIndirectionsForType(f.getAnUnspecifiedType()))] and
|
||||
indirectionIndex = [1 .. SsaImpl::getMaxIndirectionsForType(f.getUnspecifiedType())] and
|
||||
// Reads and writes of union fields are tracked using `UnionContent`.
|
||||
not f.getDeclaringType() instanceof Union
|
||||
} or
|
||||
TUnionContent(CanonicalUnion u, int bytes, int indirectionIndex) {
|
||||
exists(CanonicalField f |
|
||||
f = u.getACanonicalField() and
|
||||
TUnionContent(Union u, int bytes, int indirectionIndex) {
|
||||
exists(Field f |
|
||||
f = u.getAField() 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)
|
||||
.getAnUnspecifiedType())
|
||||
.getUnspecifiedType())
|
||||
)]
|
||||
)
|
||||
} or
|
||||
@@ -2235,14 +2124,14 @@ private newtype TContent =
|
||||
*/
|
||||
class Content extends TContent {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() } // overridden in subclasses
|
||||
abstract string toString();
|
||||
|
||||
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`. */
|
||||
int getIndirectionIndex() { none() } // overridden in subclasses
|
||||
abstract int getIndirectionIndex();
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
@@ -2253,7 +2142,7 @@ class Content extends TContent {
|
||||
* For example, a write to a field `f` implies that any content of
|
||||
* the form `*f` is also cleared.
|
||||
*/
|
||||
predicate impliesClearOf(Content c) { none() } // overridden in subclasses
|
||||
abstract predicate impliesClearOf(Content c);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2273,62 +2162,37 @@ private module ContentStars {
|
||||
|
||||
private import ContentStars
|
||||
|
||||
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 {
|
||||
/** 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;
|
||||
class FieldContent extends Content, TFieldContent {
|
||||
private Field f;
|
||||
private int indirectionIndex;
|
||||
|
||||
NonUnionFieldContent() { this = TNonUnionContent(f, indirectionIndex) }
|
||||
FieldContent() { this = TFieldContent(f, indirectionIndex) }
|
||||
|
||||
override string toString() { result = contentStars(this) + f.toString() }
|
||||
|
||||
final override Field getField() { result = f.getAField() }
|
||||
|
||||
override Field getAField() { result = this.getField() }
|
||||
Field getField() { result = f }
|
||||
|
||||
/** Gets the indirection index of this `FieldContent`. */
|
||||
override int getIndirectionIndex() { result = indirectionIndex }
|
||||
pragma[inline]
|
||||
override int getIndirectionIndex() {
|
||||
pragma[only_bind_into](result) = pragma[only_bind_out](indirectionIndex)
|
||||
}
|
||||
|
||||
override predicate impliesClearOf(Content c) {
|
||||
exists(int i |
|
||||
c = TNonUnionContent(f, i) and
|
||||
exists(FieldContent fc |
|
||||
fc = c and
|
||||
fc.getField() = f and
|
||||
// If `this` is `f` then `c` is cleared if it's of the
|
||||
// form `*f`, `**f`, etc.
|
||||
i >= indirectionIndex
|
||||
fc.getIndirectionIndex() >= indirectionIndex
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A reference through an instance field of a union. */
|
||||
class UnionContent extends FieldContent, TUnionContent {
|
||||
private CanonicalUnion u;
|
||||
class UnionContent extends Content, TUnionContent {
|
||||
private Union u;
|
||||
private int indirectionIndex;
|
||||
private int bytes;
|
||||
|
||||
@@ -2336,31 +2200,27 @@ class UnionContent extends FieldContent, 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. */
|
||||
override Field getAField() {
|
||||
exists(CanonicalField cf |
|
||||
cf = u.getACanonicalField() and
|
||||
result = cf.getAField() and
|
||||
getFieldSize(cf) = bytes
|
||||
)
|
||||
}
|
||||
Field getAField() { result = u.getAField() and getFieldSize(result) = bytes }
|
||||
|
||||
/** Gets the underlying union of this `UnionContent`. */
|
||||
Union getUnion() { result = u.getAUnion() }
|
||||
Union getUnion() { result = u }
|
||||
|
||||
/** Gets the indirection index of this `UnionContent`. */
|
||||
override int getIndirectionIndex() { result = indirectionIndex }
|
||||
pragma[inline]
|
||||
override int getIndirectionIndex() {
|
||||
pragma[only_bind_into](result) = pragma[only_bind_out](indirectionIndex)
|
||||
}
|
||||
|
||||
override predicate impliesClearOf(Content c) {
|
||||
exists(int i |
|
||||
c = TUnionContent(u, _, i) and
|
||||
exists(UnionContent uc |
|
||||
uc = c and
|
||||
uc.getUnion() = u 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).
|
||||
i >= indirectionIndex
|
||||
uc.getIndirectionIndex() >= indirectionIndex
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2374,7 +2234,10 @@ class ElementContent extends Content, TElementContent {
|
||||
|
||||
ElementContent() { this = TElementContent(indirectionIndex) }
|
||||
|
||||
override int getIndirectionIndex() { result = indirectionIndex }
|
||||
pragma[inline]
|
||||
override int getIndirectionIndex() {
|
||||
pragma[only_bind_into](result) = pragma[only_bind_out](indirectionIndex)
|
||||
}
|
||||
|
||||
override predicate impliesClearOf(Content c) { none() }
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ private module SourceVariables {
|
||||
* the type of this source variable should be thought of as "pointer
|
||||
* to `getType()`".
|
||||
*/
|
||||
Type getType() {
|
||||
DataFlowType getType() {
|
||||
if this.isGLValue()
|
||||
then result = base.getType()
|
||||
else result = getTypeImpl(base.getType(), ind - 1)
|
||||
@@ -1051,12 +1051,12 @@ module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
|
||||
}
|
||||
|
||||
private predicate guardChecksInstr(
|
||||
IRGuards::Guards_v1::Guard g, IRGuards::GuardsInput::Expr instr, IRGuards::GuardValue gv,
|
||||
IRGuards::Guards_v1::Guard g, IRGuards::GuardsInput::Expr instr, boolean branch,
|
||||
int indirectionIndex
|
||||
) {
|
||||
exists(Node node |
|
||||
nodeHasInstruction(node, instr, indirectionIndex) and
|
||||
guardChecksNode(g, node, gv.asBooleanValue(), indirectionIndex)
|
||||
guardChecksNode(g, node, branch, indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1064,15 +1064,8 @@ module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
|
||||
DataFlowIntegrationInput::Guard g, SsaImpl::Definition def, IRGuards::GuardValue val,
|
||||
int indirectionIndex
|
||||
) {
|
||||
exists(Instruction e |
|
||||
IRGuards::Guards_v1::ParameterizedValidationWrapper<int, guardChecksInstr/4>::guardChecks(g,
|
||||
e, val, indirectionIndex)
|
||||
|
|
||||
indirectionIndex = 0 and
|
||||
def.(Definition).getAUse().getDef() = e
|
||||
or
|
||||
def.(Definition).getAnIndirectUse(indirectionIndex).getDef() = e
|
||||
)
|
||||
IRGuards::Guards_v1::ValidationWrapperWithState<int, guardChecksInstr/4>::guardChecksDef(g, def,
|
||||
val, indirectionIndex)
|
||||
}
|
||||
|
||||
Node getABarrierNode(int indirectionIndex) {
|
||||
|
||||
@@ -688,9 +688,15 @@ private module Cached {
|
||||
conversionFlow(mid, instr, false, _)
|
||||
)
|
||||
or
|
||||
exists(Operand address |
|
||||
isDereference(operand.getDef(), address, _) and
|
||||
isUseImpl(address, base, ind - 1)
|
||||
exists(int ind0 |
|
||||
exists(Operand address |
|
||||
isDereference(operand.getDef(), address, _) and
|
||||
isUseImpl(address, base, ind0)
|
||||
)
|
||||
or
|
||||
isUseImpl(operand.getDef().(InitializeParameterInstruction).getAnOperand(), base, ind0)
|
||||
|
|
||||
ind0 = ind - 1
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -2679,7 +2679,7 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr, St
|
||||
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getTranslatedFunction(getEnclosingFunction(expr)).getLoadThisInstruction()
|
||||
result = getTranslatedFunction(getEnclosingFunction(expr)).getInitializeThisInstruction()
|
||||
}
|
||||
|
||||
final override Field getInstructionField(InstructionTag tag) {
|
||||
|
||||
@@ -306,11 +306,11 @@ class TranslatedFunction extends TranslatedRootElement, TTranslatedFunction {
|
||||
final predicate hasReturnValue() { hasReturnValue(func) }
|
||||
|
||||
/**
|
||||
* Gets the first load of `this` for this function. Holds only if the function
|
||||
* is an instance member function, constructor, or destructor.
|
||||
* Gets the single `InitializeThis` instruction for this function. Holds only
|
||||
* if the function is an instance member function, constructor, or destructor.
|
||||
*/
|
||||
final Instruction getLoadThisInstruction() {
|
||||
result = getTranslatedThisParameter(func).getInstruction(InitializerIndirectAddressTag())
|
||||
final Instruction getInitializeThisInstruction() {
|
||||
result = getTranslatedThisParameter(func).getInstruction(InitializerStoreTag())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -639,7 +639,7 @@ class TranslatedConstructorInitList extends TranslatedElement, InitializationCon
|
||||
}
|
||||
|
||||
override Instruction getTargetAddress() {
|
||||
result = getTranslatedFunction(func).getLoadThisInstruction()
|
||||
result = getTranslatedFunction(func).getInitializeThisInstruction()
|
||||
}
|
||||
|
||||
override Type getTargetType() { result = getTranslatedFunction(func).getThisType() }
|
||||
|
||||
@@ -950,7 +950,7 @@ abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStru
|
||||
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getTranslatedFunction(this.getFunction()).getLoadThisInstruction()
|
||||
result = getTranslatedFunction(this.getFunction()).getInitializeThisInstruction()
|
||||
}
|
||||
|
||||
final override predicate getInstructionInheritance(
|
||||
@@ -1000,7 +1000,7 @@ class TranslatedConstructorDelegationInit extends TranslatedConstructorCallFromC
|
||||
}
|
||||
|
||||
final override Instruction getReceiver() {
|
||||
result = getTranslatedFunction(this.getFunction()).getLoadThisInstruction()
|
||||
result = getTranslatedFunction(this.getFunction()).getInitializeThisInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.NonThrowing
|
||||
|
||||
/**
|
||||
* The standard functions `memcpy`, `memmove` and `bcopy`; and variants such as
|
||||
* `__builtin___memcpy_chk` and `__builtin___memmove_chk`.
|
||||
* The standard functions `memcpy`, `memmove` and `bcopy`; and the gcc variant
|
||||
* `__builtin___memcpy_chk`.
|
||||
*/
|
||||
private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction,
|
||||
AliasFunction, NonCppThrowingFunction
|
||||
@@ -27,9 +27,7 @@ private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffect
|
||||
// bcopy(src, dest, num)
|
||||
// mempcpy(dest, src, num)
|
||||
// memccpy(dest, src, c, n)
|
||||
this.hasGlobalName([
|
||||
"bcopy", mempcpy(), "memccpy", "__builtin___memcpy_chk", "__builtin___memmove_chk"
|
||||
])
|
||||
this.hasGlobalName(["bcopy", mempcpy(), "memccpy", "__builtin___memcpy_chk"])
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,8 +19,7 @@ private class MemsetFunctionModel extends ArrayFunction, DataFlowFunction, Alias
|
||||
this.hasGlobalOrStdName("wmemset")
|
||||
or
|
||||
this.hasGlobalName([
|
||||
bzero(), "__builtin_memset", "__builtin_memset_chk", "__builtin___memset_chk",
|
||||
"RtlZeroMemory", "RtlSecureZeroMemory"
|
||||
bzero(), "__builtin_memset", "__builtin_memset_chk", "RtlZeroMemory", "RtlSecureZeroMemory"
|
||||
])
|
||||
}
|
||||
|
||||
@@ -33,7 +32,7 @@ private class MemsetFunctionModel extends ArrayFunction, DataFlowFunction, Alias
|
||||
or
|
||||
this.hasGlobalOrStdName("wmemset")
|
||||
or
|
||||
this.hasGlobalName(["__builtin_memset", "__builtin_memset_chk", "__builtin___memset_chk"])
|
||||
this.hasGlobalName(["__builtin_memset", "__builtin_memset_chk"])
|
||||
) and
|
||||
result = 1
|
||||
}
|
||||
|
||||
@@ -30,9 +30,7 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
|
||||
"_mbsncat", // _mbsncat(dst, src, max_amount)
|
||||
"_mbsncat_l", // _mbsncat_l(dst, src, max_amount, locale)
|
||||
"_mbsnbcat", // _mbsnbcat(dest, src, count)
|
||||
"_mbsnbcat_l", // _mbsnbcat_l(dest, src, count, locale)
|
||||
"__builtin___strcat_chk", // __builtin___strcat_chk (dest, src, magic)
|
||||
"__builtin___strncat_chk" // __builtin___strncat_chk (dest, src, max_amount, magic)
|
||||
"_mbsnbcat_l" // _mbsnbcat_l(dest, src, count, locale)
|
||||
])
|
||||
}
|
||||
|
||||
@@ -58,7 +56,7 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
(
|
||||
this.getName() = ["strncat", "wcsncat", "_mbsncat", "_mbsncat_l", "__builtin___strncat_chk"] and
|
||||
this.getName() = ["strncat", "wcsncat", "_mbsncat", "_mbsncat_l"] and
|
||||
input.isParameter(2)
|
||||
or
|
||||
this.getName() = ["_mbsncat_l", "_mbsnbcat_l"] and
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user