Compare commits

..

1 Commits

Author SHA1 Message Date
Ian Lynagh
4fc95ac322 GitHub: Add workflow_dispatch trigger to compile-queries.yml
This change adds a workflow_dispatch trigger to the
compile-queries.yml GitHub Actions workflow, allowing
manual triggering of the query compilation test.
2026-01-06 18:43:19 +00:00
1584 changed files with 149426 additions and 289094 deletions

View File

@@ -1,6 +1,7 @@
name: "Compile all queries using the latest stable CodeQL CLI" name: "Compile all queries using the latest stable CodeQL CLI"
on: on:
workflow_dispatch:
push: push:
branches: # makes sure the cache gets populated - running on the branches people tend to merge into. branches: # makes sure the cache gets populated - running on the branches people tend to merge into.
- main - main
@@ -17,41 +18,9 @@ permissions:
contents: read contents: read
jobs: 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: compile-queries:
needs: detect-changes if: github.repository_owner == 'github'
if: github.repository_owner == 'github' && needs.detect-changes.outputs.languages != '[]'
runs-on: ubuntu-latest-xl runs-on: ubuntu-latest-xl
strategy:
fail-fast: false
matrix:
language: ${{ fromJson(needs.detect-changes.outputs.languages) }}
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
@@ -63,16 +32,16 @@ jobs:
id: query-cache id: query-cache
uses: ./.github/actions/cache-query-compilation uses: ./.github/actions/cache-query-compilation
with: with:
key: ${{ matrix.language }}-queries key: all-queries
- name: check formatting - 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 - name: compile queries - check-only
# run with --check-only if running in a PR (github.sha != main) # run with --check-only if running in a PR (github.sha != main)
if : ${{ github.event_name == 'pull_request' }} if : ${{ github.event_name == 'pull_request' }}
shell: bash 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 - name: compile queries - full
# do full compile if running on main - this populates the cache # do full compile if running on main - this populates the cache
if : ${{ github.event_name != 'pull_request' }} if : ${{ github.event_name != 'pull_request' }}
shell: bash 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

View File

@@ -27,7 +27,6 @@ jobs:
uses: github/codeql-action/init@main uses: github/codeql-action/init@main
with: with:
languages: javascript # does not matter languages: javascript # does not matter
tools: nightly
- uses: ./.github/actions/os-version - uses: ./.github/actions/os-version
id: os_version id: os_version
### Build the extractor ### ### Build the extractor ###

View File

@@ -30,7 +30,6 @@ jobs:
uses: github/codeql-action/init@main uses: github/codeql-action/init@main
with: with:
languages: javascript # does not matter languages: javascript # does not matter
tools: nightly
- uses: ./.github/actions/os-version - uses: ./.github/actions/os-version
id: os_version id: os_version
- uses: actions/cache@v3 - uses: actions/cache@v3
@@ -76,7 +75,6 @@ jobs:
uses: github/codeql-action/init@main uses: github/codeql-action/init@main
with: with:
languages: javascript # does not matter languages: javascript # does not matter
tools: nightly
- uses: ./.github/actions/os-version - uses: ./.github/actions/os-version
id: os_version id: os_version
- uses: actions/cache@v3 - uses: actions/cache@v3

View File

@@ -24,7 +24,7 @@ bazel_dep(name = "bazel_skylib", version = "1.8.1")
bazel_dep(name = "abseil-cpp", version = "20240116.1", repo_name = "absl") 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 = "nlohmann_json", version = "3.11.3", repo_name = "json")
bazel_dep(name = "fmt", version = "12.1.0-codeql.1") bazel_dep(name = "fmt", version = "12.1.0-codeql.1")
bazel_dep(name = "rules_kotlin", version = "2.2.0-codeql.1") bazel_dep(name = "rules_kotlin", version = "2.1.3-codeql.1")
bazel_dep(name = "gazelle", version = "0.40.0") bazel_dep(name = "gazelle", version = "0.40.0")
bazel_dep(name = "rules_dotnet", version = "0.21.5-codeql.1") bazel_dep(name = "rules_dotnet", version = "0.21.5-codeql.1")
bazel_dep(name = "googletest", version = "1.14.0.bcr.1") bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
@@ -221,6 +221,10 @@ use_repo(
kotlin_extractor_deps, kotlin_extractor_deps,
"codeql_kotlin_defaults", "codeql_kotlin_defaults",
"codeql_kotlin_embeddable", "codeql_kotlin_embeddable",
"kotlin-compiler-1.6.0",
"kotlin-compiler-1.6.20",
"kotlin-compiler-1.7.0",
"kotlin-compiler-1.7.20",
"kotlin-compiler-1.8.0", "kotlin-compiler-1.8.0",
"kotlin-compiler-1.9.0-Beta", "kotlin-compiler-1.9.0-Beta",
"kotlin-compiler-1.9.20-Beta", "kotlin-compiler-1.9.20-Beta",
@@ -230,7 +234,10 @@ use_repo(
"kotlin-compiler-2.1.20-Beta1", "kotlin-compiler-2.1.20-Beta1",
"kotlin-compiler-2.2.0-Beta1", "kotlin-compiler-2.2.0-Beta1",
"kotlin-compiler-2.2.20-Beta2", "kotlin-compiler-2.2.20-Beta2",
"kotlin-compiler-2.3.0", "kotlin-compiler-embeddable-1.6.0",
"kotlin-compiler-embeddable-1.6.20",
"kotlin-compiler-embeddable-1.7.0",
"kotlin-compiler-embeddable-1.7.20",
"kotlin-compiler-embeddable-1.8.0", "kotlin-compiler-embeddable-1.8.0",
"kotlin-compiler-embeddable-1.9.0-Beta", "kotlin-compiler-embeddable-1.9.0-Beta",
"kotlin-compiler-embeddable-1.9.20-Beta", "kotlin-compiler-embeddable-1.9.20-Beta",
@@ -240,7 +247,10 @@ use_repo(
"kotlin-compiler-embeddable-2.1.20-Beta1", "kotlin-compiler-embeddable-2.1.20-Beta1",
"kotlin-compiler-embeddable-2.2.0-Beta1", "kotlin-compiler-embeddable-2.2.0-Beta1",
"kotlin-compiler-embeddable-2.2.20-Beta2", "kotlin-compiler-embeddable-2.2.20-Beta2",
"kotlin-compiler-embeddable-2.3.0", "kotlin-stdlib-1.6.0",
"kotlin-stdlib-1.6.20",
"kotlin-stdlib-1.7.0",
"kotlin-stdlib-1.7.20",
"kotlin-stdlib-1.8.0", "kotlin-stdlib-1.8.0",
"kotlin-stdlib-1.9.0-Beta", "kotlin-stdlib-1.9.0-Beta",
"kotlin-stdlib-1.9.20-Beta", "kotlin-stdlib-1.9.20-Beta",
@@ -250,15 +260,14 @@ use_repo(
"kotlin-stdlib-2.1.20-Beta1", "kotlin-stdlib-2.1.20-Beta1",
"kotlin-stdlib-2.2.0-Beta1", "kotlin-stdlib-2.2.0-Beta1",
"kotlin-stdlib-2.2.20-Beta2", "kotlin-stdlib-2.2.20-Beta2",
"kotlin-stdlib-2.3.0",
) )
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
go_sdk.download(version = "1.26.0") go_sdk.download(version = "1.25.0")
go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
go_deps.from_file(go_mod = "//go/extractor:go.mod") go_deps.from_file(go_mod = "//go/extractor:go.mod")
use_repo(go_deps, "com_github_stretchr_testify", "org_golang_x_mod", "org_golang_x_tools") use_repo(go_deps, "org_golang_x_mod", "org_golang_x_tools")
ripunzip_archive = use_repo_rule("//misc/ripunzip:ripunzip.bzl", "ripunzip_archive") ripunzip_archive = use_repo_rule("//misc/ripunzip:ripunzip.bzl", "ripunzip_archive")

View File

@@ -1,4 +0,0 @@
---
lockVersion: 1.0.0
dependencies: {}
compiled: false

View File

@@ -1,7 +0,0 @@
name: codeql/actions-examples
groups:
- actions
- examples
dependencies:
codeql/actions-all: ${workspace}
warnOnImplicitThis: true

View File

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

View File

@@ -1,23 +1,3 @@
## 0.4.28
No user-facing changes.
## 0.4.27
### Bug Fixes
* Fixed a crash when analysing a `${{ ... }}` expression over around 300 characters in length.
## 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 ## 0.4.24
No user-facing changes. No user-facing changes.

View File

@@ -1,5 +1,4 @@
## 0.4.26 ---
category: majorAnalysis
### 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`. * 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`.

View File

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

View File

@@ -1,5 +0,0 @@
## 0.4.27
### Bug Fixes
* Fixed a crash when analysing a `${{ ... }}` expression over around 300 characters in length.

View File

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

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 0.4.28 lastReleaseVersion: 0.4.24

View File

@@ -27,8 +27,8 @@ string getADelimitedExpression(YamlString s, int offset) {
// not just the last (greedy match) or first (reluctant match). // not just the last (greedy match) or first (reluctant match).
result = result =
s.getValue() s.getValue()
.regexpFind("\\$\\{\\{(?:[^}]|}(?!}))*+\\}\\}", _, offset) .regexpFind("\\$\\{\\{(?:[^}]|}(?!}))*\\}\\}", _, offset)
.regexpCapture("(\\$\\{\\{(?:[^}]|}(?!}))*+\\}\\})", 1) .regexpCapture("(\\$\\{\\{(?:[^}]|}(?!}))*\\}\\})", 1)
.trim() .trim()
} }

View File

@@ -1,5 +1,5 @@
name: codeql/actions-all name: codeql/actions-all
version: 0.4.28 version: 0.4.25-dev
library: true library: true
warnOnImplicitThis: true warnOnImplicitThis: true
dependencies: dependencies:

View File

@@ -1,19 +1,3 @@
## 0.6.20
No user-facing changes.
## 0.6.19
No user-facing changes.
## 0.6.18
No user-facing changes.
## 0.6.17
No user-facing changes.
## 0.6.16 ## 0.6.16
No user-facing changes. No user-facing changes.

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 0.6.20 lastReleaseVersion: 0.6.16

View File

@@ -1,5 +1,5 @@
name: codeql/actions-queries name: codeql/actions-queries
version: 0.6.20 version: 0.6.17-dev
library: false library: false
warnOnImplicitThis: true warnOnImplicitThis: true
groups: [actions, queries] groups: [actions, queries]

View File

@@ -1,5 +0,0 @@
import codeql.actions.ast.internal.Ast
int getAnExpressionLength() { result = any(ExpressionImpl e).toString().length() }
select max(getAnExpressionLength())

View File

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

View File

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

View File

@@ -1,5 +0,0 @@
description: Add trap_filename, source_file_uses_trap and in_trap relations
compatibility: full
trap_filename.rel: delete
source_file_uses_trap.rel: delete
in_trap.rel: delete

View File

@@ -1,2 +0,0 @@
description: Sections for databaseMetadata and overlayChangedFiles
compatibility: full

View File

@@ -1,13 +0,0 @@
class PreprocessorDirective extends @preprocdirect {
string toString() { none() }
}
class Location extends @location_default {
string toString() { none() }
}
from PreprocessorDirective ppd, int kind, int kind_new, Location l
where
preprocdirects(ppd, kind, l) and
if kind = 17 then kind_new = /* ppd_warning */ 18 else kind_new = kind
select ppd, kind_new, l

View File

@@ -1,4 +0,0 @@
description: Support embed preprocessor directive
compatibility: partial
embeds.rel: delete
preprocdirects.rel: run preprocdirects.qlo

View File

@@ -1,2 +0,0 @@
description: Remove _Decimal{32,64,128} types
compatibility: full

View File

@@ -1,55 +1,3 @@
## 7.1.1
### Minor Analysis Improvements
* Added remote flow source models for the `winhttp.h` windows header and the Azure SDK core library for C/C++.
## 7.1.0
### New Features
* Added a subclass `Embed` of `PreprocessorDirective` for C23 and C++26 `#embed` preprocessor directives.
* Added modules `DataFlow::ParameterizedBarrierGuard` and `DataFlow::ParameterizedInstructionBarrierGuard`. These modules provide the same features as `DataFlow::BarrierGuard` and `DataFlow::InstructionBarrierGuard`, but allow for an additional parameter to support properly using them in dataflow configurations that uses flow states.
### Minor Analysis Improvements
* The `Buffer.qll` library will no longer report incorrect buffer sizes on certain malformed databases. As a result, the queries `cpp/static-buffer-overflow`, `cpp/overflow-buffer`, `cpp/badly-bounded-write`, `cpp/overrunning-write`, `cpp/overrunning-write-with-float`, and `cpp/very-likely-overrunning-write` will report fewer false positives on such databases.
* Added `taint` summary models and `sql-injection` barrier models for the MySQL `mysql_real_escape_string` and `mysql_real_escape_string_quote` escaping functions.
* The predicate `SummarizedCallable.propagatesFlow` has been extended with the columns `Provenance p` and `boolean isExact`, and as a consequence the predicates `SummarizedCallable.hasProvenance` and `SummarizedCallable.hasExactModel` have been removed.
### Bug Fixes
* Fixed a bug in the `GuardCondition` library which sometimes prevented binary logical operators from being recognized as guard conditions. As a result, queries using `GuardCondition` may see improved results.
* Fixed a bug which caused `Node.asDefinition()` to not have a result for certain assignments.
## 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 ## 6.1.3
No user-facing changes. No user-facing changes.

View File

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

View File

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

View File

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

View File

@@ -1,17 +0,0 @@
## 7.1.0
### New Features
* Added a subclass `Embed` of `PreprocessorDirective` for C23 and C++26 `#embed` preprocessor directives.
* Added modules `DataFlow::ParameterizedBarrierGuard` and `DataFlow::ParameterizedInstructionBarrierGuard`. These modules provide the same features as `DataFlow::BarrierGuard` and `DataFlow::InstructionBarrierGuard`, but allow for an additional parameter to support properly using them in dataflow configurations that uses flow states.
### Minor Analysis Improvements
* The `Buffer.qll` library will no longer report incorrect buffer sizes on certain malformed databases. As a result, the queries `cpp/static-buffer-overflow`, `cpp/overflow-buffer`, `cpp/badly-bounded-write`, `cpp/overrunning-write`, `cpp/overrunning-write-with-float`, and `cpp/very-likely-overrunning-write` will report fewer false positives on such databases.
* Added `taint` summary models and `sql-injection` barrier models for the MySQL `mysql_real_escape_string` and `mysql_real_escape_string_quote` escaping functions.
* The predicate `SummarizedCallable.propagatesFlow` has been extended with the columns `Provenance p` and `boolean isExact`, and as a consequence the predicates `SummarizedCallable.hasProvenance` and `SummarizedCallable.hasExactModel` have been removed.
### Bug Fixes
* Fixed a bug in the `GuardCondition` library which sometimes prevented binary logical operators from being recognized as guard conditions. As a result, queries using `GuardCondition` may see improved results.
* Fixed a bug which caused `Node.asDefinition()` to not have a result for certain assignments.

View File

@@ -1,5 +0,0 @@
## 7.1.1
### Minor Analysis Improvements
* Added remote flow source models for the `winhttp.h` windows header and the Azure SDK core library for C/C++.

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 7.1.1 lastReleaseVersion: 6.1.3

View File

@@ -1,14 +0,0 @@
# partial model of the MySQL api
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
- ["", "", False, "mysql_real_escape_string", "", "", "Argument[*2]", "Argument[*1]", "taint", "manual"]
- ["", "", False, "mysql_real_escape_string_quote", "", "", "Argument[*2]", "Argument[*1]", "taint", "manual"]
- addsTo:
pack: codeql/cpp-all
extensible: barrierModel
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
- ["", "", False, "mysql_real_escape_string", "", "", "Argument[*1]", "sql-injection", "manual"]
- ["", "", False, "mysql_real_escape_string_quote", "", "", "Argument[*1]", "sql-injection", "manual"]

View File

@@ -24,13 +24,6 @@ extensions:
- ["", "", False, "MapViewOfFileNuma2", "", "", "ReturnValue[*]", "local", "manual"] - ["", "", False, "MapViewOfFileNuma2", "", "", "ReturnValue[*]", "local", "manual"]
# ntifs.h # ntifs.h
- ["", "", False, "NtReadFile", "", "", "Argument[*5]", "local", "manual"] - ["", "", False, "NtReadFile", "", "", "Argument[*5]", "local", "manual"]
# winhttp.h
- ["", "", False, "WinHttpReadData", "", "", "Argument[*1]", "remote", "manual"]
- ["", "", False, "WinHttpReadDataEx", "", "", "Argument[*1]", "remote", "manual"]
- ["", "", False, "WinHttpQueryHeaders", "", "", "Argument[*3]", "remote", "manual"]
- ["", "", False, "WinHttpQueryHeadersEx", "", "", "Argument[*5]", "remote", "manual"]
- ["", "", False, "WinHttpQueryHeadersEx", "", "", "Argument[*6]", "remote", "manual"]
- ["", "", False, "WinHttpQueryHeadersEx", "", "", "Argument[**8]", "remote", "manual"]
- addsTo: - addsTo:
pack: codeql/cpp-all pack: codeql/cpp-all
extensible: summaryModel extensible: summaryModel
@@ -54,5 +47,3 @@ extensions:
- ["", "", False, "RtlMoveVolatileMemory", "", "", "Argument[*@1]", "Argument[*@0]", "value", "manual"] - ["", "", False, "RtlMoveVolatileMemory", "", "", "Argument[*@1]", "Argument[*@0]", "value", "manual"]
# winternl.h # winternl.h
- ["", "", False, "RtlInitUnicodeString", "", "", "Argument[*1]", "Argument[*0].Field[*Buffer]", "value", "manual"] - ["", "", False, "RtlInitUnicodeString", "", "", "Argument[*1]", "Argument[*0].Field[*Buffer]", "value", "manual"]
# winhttp.h
- ["", "", False, "WinHttpCrackUrl", "", "", "Argument[*0]", "Argument[*3]", "taint", "manual"]

View File

@@ -1,41 +0,0 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: sourceModel
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
- ["Azure::Core::Http", "RawResponse", True, "GetHeaders", "", "", "ReturnValue[*]", "remote", "manual"]
- ["Azure::Core::Http", "RawResponse", True, "GetBody", "", "", "ReturnValue[*]", "remote", "manual"]
- ["Azure::Core::Http", "RawResponse", True, "ExtractBodyStream", "", "", "ReturnValue[*]", "remote", "manual"]
- ["Azure::Core::Http", "Request", True, "GetHeaders", "", "", "ReturnValue", "remote", "manual"]
- ["Azure::Core::Http", "Request", True, "GetHeader", "", "", "ReturnValue", "remote", "manual"]
- ["Azure::Core::Http", "Request", True, "GetBodyStream", "", "", "ReturnValue[*]", "remote", "manual"]
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
- ["Azure::Core", "Url", True, "Url", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
- ["Azure::Core", "Url", True, "SetScheme", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
- ["Azure::Core", "Url", True, "SetHost", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
- ["Azure::Core", "Url", True, "SetPort", "", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
- ["Azure::Core", "Url", True, "SetPath", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
- ["Azure::Core", "Url", True, "SetQueryParameters", "", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
- ["Azure::Core", "Url", True, "AppendPath", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
- ["Azure::Core", "Url", True, "AppendQueryParameter", "", "", "Argument[*1]", "Argument[-1]", "taint", "manual"]
- ["Azure::Core", "Url", True, "GetHost", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
- ["Azure::Core", "Url", True, "GetPath", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
- ["Azure::Core", "Url", True, "GetPort", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
- ["Azure::Core", "Url", True, "GetQueryParameters", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
- ["Azure::Core", "Url", True, "GetScheme", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
- ["Azure::Core", "Url", True, "GetRelativeUrl", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
- ["Azure::Core", "Url", True, "GetAbsoluteUrl", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
- ["Azure::Core", "Url", True, "Decode", "", "", "Argument[*0]", "ReturnValue", "taint", "manual"]
- ["Azure::Core", "Url", True, "Encode", "", "", "Argument[*0]", "ReturnValue", "taint", "manual"]
- ["Azure::Core::IO", "BodyStream", True, "Read", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
- ["Azure::Core::IO", "BodyStream", True, "ReadToCount", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
- ["Azure::Core::IO", "BodyStream", True, "ReadToEnd", "", "", "Argument[-1]", "ReturnValue.Element", "taint", "manual"]
- ["Azure", "Nullable", True, "Nullable", "", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
- ["Azure", "Nullable", True, "operator=", "", "", "Argument[*0]", "Argument[-1]", "value", "manual"]
- ["Azure", "Nullable", True, "Value", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
- ["Azure", "Nullable", True, "operator->", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
- ["Azure", "Nullable", True, "operator*", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all name: codeql/cpp-all
version: 7.1.1 version: 6.1.4-dev
groups: cpp groups: cpp
dbscheme: semmlecode.cpp.dbscheme dbscheme: semmlecode.cpp.dbscheme
extractor: cpp extractor: cpp

View File

@@ -192,15 +192,6 @@ class Element extends ElementBase {
*/ */
predicate isAffectedByMacro() { affectedByMacro(this) } predicate isAffectedByMacro() { affectedByMacro(this) }
/**
* INTERNAL: Do not use.
*
* Holds if this element is affected by the expansion of `mi`.
*/
predicate isAffectedByMacro(MacroInvocation mi) {
affectedbymacroexpansion(underlyingElement(this), unresolveElement(mi))
}
private Element getEnclosingElementPref() { private Element getEnclosingElementPref() {
enclosingfunction(underlyingElement(this), unresolveElement(result)) or enclosingfunction(underlyingElement(this), unresolveElement(result)) or
result.(Function) = stmtEnclosingElement(this) or result.(Function) = stmtEnclosingElement(this) or

View File

@@ -239,9 +239,6 @@ class MacroInvocation extends MacroAccess {
macro_argument_unexpanded(underlyingElement(this), i, result) macro_argument_unexpanded(underlyingElement(this), i, result)
} }
/** Gets the number of arguments for this macro invocation. */
int getNumberOfArguments() { result = count(int i | exists(this.getUnexpandedArgument(i)) | i) }
/** /**
* Gets the `i`th _expanded_ argument of this macro invocation, where the * Gets the `i`th _expanded_ argument of this macro invocation, where the
* first argument has `i = 0`. The result has been expanded for macros _and_ * first argument has `i = 0`. The result has been expanded for macros _and_

View File

@@ -328,27 +328,3 @@ class PreprocessorPragma extends PreprocessorDirective, @ppd_pragma {
class PreprocessorLine extends PreprocessorDirective, @ppd_line { class PreprocessorLine extends PreprocessorDirective, @ppd_line {
override string toString() { result = "#line " + this.getHead() } override string toString() { result = "#line " + this.getHead() }
} }
/**
* A C23 or C++26 `#embed` preprocessor directive. For example, the following code
* contains one `Embed` directive:
* ```cpp
* char arr[] = {
* #embed "bin"
* };
* ```
*/
class Embed extends PreprocessorDirective, @ppd_embed {
override string toString() { result = "#embed " + this.getIncludeText() }
/**
* Gets the token which occurs after `#embed`, for example `"filename"`
* or `<filename>`.
*/
string getIncludeText() { result = this.getHead() }
/**
* Gets the file directly embedded by this `#embed`.
*/
File getEmbeddedFile() { embeds(underlyingElement(this), unresolveElement(result)) }
}

View File

@@ -1050,10 +1050,10 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
expr.(Call).getQualifier() = ele and expr.(Call).getQualifier() = ele and
pred = "getQualifier()" pred = "getQualifier()"
or 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 | exists(int n, Expr arg | expr.(Call).getArgument(n) = arg |
not expr.(OverloadedArrayExpr).getArrayBase() = arg and not expr.(OverloadedArrayExpr).getArrayBase() = arg and
not expr.(OverloadedArrayExpr).getAnArrayOffset() = arg and not expr.(OverloadedArrayExpr).getArrayOffset() = arg and
arg = ele and arg = ele and
pred = "getArgument(" + n.toString() + ")" pred = "getArgument(" + n.toString() + ")"
) )
@@ -1062,10 +1062,7 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
or or
expr.(OverloadedArrayExpr).getArrayBase() = ele and pred = "getArrayBase()" expr.(OverloadedArrayExpr).getArrayBase() = ele and pred = "getArrayBase()"
or or
exists(int n | expr.(OverloadedArrayExpr).getArrayOffset() = ele and pred = "getArrayOffset()"
expr.(OverloadedArrayExpr).getArrayOffset(n) = ele and
pred = "getArrayOffset(" + n.toString() + ")"
)
or or
// OverloadedPointerDereferenceExpr::getExpr/0 also considers qualifiers, and is already handled above for all Call classes. // OverloadedPointerDereferenceExpr::getExpr/0 also considers qualifiers, and is already handled above for all Call classes.
not expr.(OverloadedPointerDereferenceExpr).getQualifier() = not expr.(OverloadedPointerDereferenceExpr).getQualifier() =

View File

@@ -802,6 +802,15 @@ private predicate floatingPointTypeMapping(
// _Complex __float128 // _Complex __float128
kind = 39 and base = 2 and domain = TComplexDomain() and realKind = 38 and extended = false kind = 39 and base = 2 and domain = TComplexDomain() and realKind = 38 and extended = false
or 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 // _Float32
kind = 45 and base = 2 and domain = TRealDomain() and realKind = 45 and extended = false kind = 45 and base = 2 and domain = TRealDomain() and realKind = 45 and extended = false
or 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 * 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 * fixed-size floating-point types like `_Float32`, the extended-precision floating-point types like
* like `_Float64x`. It also includes the complex and imaginary versions of all of these types. * `_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 { class FloatingPointType extends ArithmeticType {
final int base; final int base;
@@ -981,6 +991,42 @@ class Float128Type extends RealNumberType, BinaryFloatingPointType {
override string getAPrimaryQlClass() { result = "Float128Type" } 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. * The C/C++ `void` type. See 4.7.
* ``` * ```

View File

@@ -62,13 +62,11 @@ private Class getRootType(FieldAccess fa) {
* unspecified type of `v` is a `ReferenceType`. * unspecified type of `v` is a `ReferenceType`.
*/ */
private int getVariableSize(Variable v) { private int getVariableSize(Variable v) {
result = exists(Type t |
unique(Type t | t = v.getUnspecifiedType() and
t = v.getUnspecifiedType() and not t instanceof ReferenceType and
not t instanceof ReferenceType result = t.getSize()
| )
t.getSize()
)
} }
/** /**
@@ -81,32 +79,30 @@ private int getSize(VariableAccess va) {
not v instanceof Field and not v instanceof Field and
result = getVariableSize(v) result = getVariableSize(v)
or or
result = exists(Class c, int trueSize |
unique(Class c, int trueSize | // Otherwise, we find the "outermost" object and compute the size
// Otherwise, we find the "outermost" object and compute the size // as the difference between the size of the type of the "outermost
// as the difference between the size of the type of the "outermost // object" and the offset of the field relative to that type.
// object" and the offset of the field relative to that type. // For example, consider the following structs:
// For example, consider the following structs: // ```
// ``` // struct S {
// struct S { // uint32_t x;
// uint32_t x; // uint32_t y;
// uint32_t y; // };
// }; // struct S2 {
// struct S2 { // S s;
// S s; // uint32_t z;
// uint32_t z; // };
// }; // ```
// ``` // Given an object `S2 s2` the size of the buffer `&s2.s.y`
// Given an object `S2 s2` the size of the buffer `&s2.s.y` // is the size of the base object type (i.e., `S2`) minutes the offset
// is the size of the base object type (i.e., `S2`) minus the offset // of `y` relative to the type `S2` (i.e., `4`). So the size of the
// of `y` relative to the type `S2` (i.e., `4`). So the size of the // buffer is `12 - 4 = 8`.
// buffer is `12 - 4 = 8`. c = getRootType(va) and
c = getRootType(va) and // we calculate the size based on the last field, to avoid including any padding after it
// we calculate the size based on the last field, to avoid including any padding after it trueSize = max(Field f | | f.getOffsetInClass(c) + getVariableSize(f)) and
trueSize = max(Field f | | f.getOffsetInClass(c) + getVariableSize(f)) result = trueSize - v.(Field).getOffsetInClass(c)
| )
trueSize - v.(Field).getOffsetInClass(c)
)
) )
} }
@@ -120,8 +116,12 @@ private int isSource(Expr bufferExpr, Element why) {
exists(Variable bufferVar | bufferVar = bufferExpr.(VariableAccess).getTarget() | exists(Variable bufferVar | bufferVar = bufferExpr.(VariableAccess).getTarget() |
// buffer is a fixed size array // buffer is a fixed size array
exists(bufferVar.getUnspecifiedType().(ArrayType).getSize()) and exists(bufferVar.getUnspecifiedType().(ArrayType).getSize()) and
// more generous than .getSize() itself, when the array is a class field or similar. result =
result = getSize(bufferExpr) and unique(int size | // more generous than .getSize() itself, when the array is a class field or similar.
size = getSize(bufferExpr)
|
size
) and
why = bufferVar and why = bufferVar and
not memberMayBeVarSize(_, bufferVar) and not memberMayBeVarSize(_, bufferVar) and
not exists(BuiltInOperationBuiltInOffsetOf offsetof | offsetof.getAChild*() = bufferExpr) and not exists(BuiltInOperationBuiltInOffsetOf offsetof | offsetof.getAChild*() = bufferExpr) and

View File

@@ -8,8 +8,7 @@ import semmle.code.cpp.ir.IR
private import codeql.util.Void private import codeql.util.Void
private import codeql.controlflow.Guards as SharedGuards private import codeql.controlflow.Guards as SharedGuards
private import semmle.code.cpp.ir.ValueNumbering private import semmle.code.cpp.ir.ValueNumbering
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr as TE private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedFunction as TF
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
private class BasicBlock = IRCfg::BasicBlock; private class BasicBlock = IRCfg::BasicBlock;
@@ -684,26 +683,24 @@ final class GuardCondition = GuardConditionImpl;
*/ */
private class GuardConditionFromBinaryLogicalOperator extends GuardConditionImpl instanceof Cpp::BinaryLogicalOperation private class GuardConditionFromBinaryLogicalOperator extends GuardConditionImpl instanceof Cpp::BinaryLogicalOperation
{ {
GuardConditionImpl l;
GuardConditionImpl r;
GuardConditionFromBinaryLogicalOperator() {
super.getLeftOperand() = l and
super.getRightOperand() = r
}
override predicate valueControls(Cpp::BasicBlock controlled, GuardValue v) { override predicate valueControls(Cpp::BasicBlock controlled, GuardValue v) {
// `l || r` does not control `r` even though `l` does. exists(Cpp::BinaryLogicalOperation binop, GuardCondition lhs, GuardCondition rhs |
not r.(Cpp::Expr).getBasicBlock() = controlled and this = binop and
l.valueControls(controlled, v) lhs = binop.getLeftOperand() and
or rhs = binop.getRightOperand() and
r.valueControls(controlled, v) lhs.valueControls(controlled, v) and
rhs.valueControls(controlled, v)
)
} }
override predicate valueControlsEdge(Cpp::BasicBlock pred, Cpp::BasicBlock succ, GuardValue v) { override predicate valueControlsEdge(Cpp::BasicBlock pred, Cpp::BasicBlock succ, GuardValue v) {
l.valueControlsEdge(pred, succ, v) exists(Cpp::BinaryLogicalOperation binop, GuardCondition lhs, GuardCondition rhs |
or this = binop and
r.valueControlsEdge(pred, succ, v) lhs = binop.getLeftOperand() and
rhs = binop.getRightOperand() and
lhs.valueControlsEdge(pred, succ, v) and
rhs.valueControlsEdge(pred, succ, v)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1029,7 +1026,7 @@ private class GuardConditionFromIR extends GuardConditionImpl {
private predicate excludeAsControlledInstruction(Instruction instr) { private predicate excludeAsControlledInstruction(Instruction instr) {
// Exclude the temporaries generated by a ternary expression. // Exclude the temporaries generated by a ternary expression.
exists(TE::TranslatedConditionalExpr tce | exists(TranslatedConditionalExpr tce |
instr = tce.getInstruction(ConditionValueFalseStoreTag()) instr = tce.getInstruction(ConditionValueFalseStoreTag())
or or
instr = tce.getInstruction(ConditionValueTrueStoreTag()) instr = tce.getInstruction(ConditionValueTrueStoreTag())
@@ -1041,14 +1038,6 @@ private predicate excludeAsControlledInstruction(Instruction instr) {
or or
// Exclude unreached instructions, as their AST is the whole function and not a block. // Exclude unreached instructions, as their AST is the whole function and not a block.
instr instanceof UnreachedInstruction instr instanceof UnreachedInstruction
or
// Exclude instructions generated by a translated function as they map to the function itself
// and the function is considered the last basic block of a function body.
any(TF::TranslatedFunction tf).getInstruction(_) = instr
or
// `ChiInstruction`s generated by instructions in the above case don't come from `getInstruction` (since they are generated by AliasedSSA)
// so we need to special case them.
excludeAsControlledInstruction(instr.(ChiInstruction).getPartial())
} }
/** /**

View File

@@ -95,7 +95,6 @@
import cpp import cpp
private import new.DataFlow private import new.DataFlow
private import semmle.code.cpp.controlflow.IRGuards
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as Private private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as Private
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import internal.FlowSummaryImpl private import internal.FlowSummaryImpl
@@ -368,8 +367,6 @@ private predicate elementSpec(
) { ) {
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or
sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or
barrierModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or
barrierGuardModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _) or
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _) summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _)
} }
@@ -1031,84 +1028,6 @@ private module Cached {
isSinkNode(n, kind, model) and n.asNode() = node isSinkNode(n, kind, model) and n.asNode() = node
) )
} }
private newtype TKindModelPair =
TMkPair(string kind, string model) { isBarrierGuardNode(_, _, kind, model) }
private GuardValue convertAcceptingValue(Public::AcceptingValue av) {
av.isTrue() and result.asBooleanValue() = true
or
av.isFalse() and result.asBooleanValue() = false
or
// NOTE: The below cases don't contribute anything currently since the
// callers immediately use `.asBooleanValue()` to convert the `GuardValue`
// to a boolean. Once we're willing to accept the breaking change of
// converting the barrier guard API to use `GuardValue`s instead `Boolean`s
// we can remove this restriction.
av.isNoException() and result.getDualValue().isThrowsException()
or
av.isZero() and result.asIntValue() = 0
or
av.isNotZero() and result.getDualValue().asIntValue() = 0
or
av.isNull() and result.isNullValue()
or
av.isNotNull() and result.isNonNullValue()
}
private predicate barrierGuardChecks(IRGuardCondition g, Expr e, boolean gv, TKindModelPair kmp) {
exists(
SourceSinkInterpretationInput::InterpretNode n, Public::AcceptingValue acceptingvalue,
string kind, string model
|
isBarrierGuardNode(n, acceptingvalue, kind, model) and
n.asNode().asExpr() = e and
kmp = TMkPair(kind, model) and
gv = convertAcceptingValue(acceptingvalue).asBooleanValue() and
n.asNode().(Private::ArgumentNode).getCall().asCallInstruction() = g
)
}
private newtype TKindModelPairIntPair =
MkKindModelPairIntPair(TKindModelPair pair, int indirectionIndex) {
indirectionIndex > 0 and
Private::nodeHasInstruction(_, _, indirectionIndex) and
exists(pair)
}
private predicate indirectBarrierGuardChecks(
IRGuardCondition g, Expr e, boolean gv, TKindModelPairIntPair kmp
) {
exists(
SourceSinkInterpretationInput::InterpretNode interpretNode,
Public::AcceptingValue acceptingvalue, string kind, string model, int indirectionIndex,
Private::ArgumentNode arg
|
isBarrierGuardNode(interpretNode, acceptingvalue, kind, model) and
arg = interpretNode.asNode() and
arg.asIndirectExpr(indirectionIndex) = e and
kmp = MkKindModelPairIntPair(TMkPair(kind, model), indirectionIndex) and
gv = convertAcceptingValue(acceptingvalue).asBooleanValue() and
arg.getCall().asCallInstruction() = g
)
}
/**
* Holds if `node` is specified as a barrier with the given kind in a MaD flow
* model.
*/
cached
predicate barrierNode(DataFlow::Node node, string kind, string model) {
exists(SourceSinkInterpretationInput::InterpretNode n |
isBarrierNode(n, kind, model) and n.asNode() = node
)
or
DataFlow::ParameterizedBarrierGuard<TKindModelPair, barrierGuardChecks/4>::getABarrierNode(TMkPair(kind,
model)) = node
or
DataFlow::ParameterizedBarrierGuard<TKindModelPairIntPair, indirectBarrierGuardChecks/4>::getAnIndirectBarrierNode(MkKindModelPairIntPair(TMkPair(kind,
model), _)) = node
}
} }
import Cached import Cached
@@ -1125,12 +1044,6 @@ predicate sourceNode(DataFlow::Node node, string kind) { sourceNode(node, kind,
*/ */
predicate sinkNode(DataFlow::Node node, string kind) { sinkNode(node, kind, _) } predicate sinkNode(DataFlow::Node node, string kind) { sinkNode(node, kind, _) }
/**
* Holds if `node` is specified as a barrier with the given kind in a MaD flow
* model.
*/
predicate barrierNode(DataFlow::Node node, string kind) { barrierNode(node, kind, _) }
private predicate interpretSummary( private predicate interpretSummary(
Function f, string input, string output, string kind, string provenance, string model Function f, string input, string output, string kind, string provenance, string model
) { ) {
@@ -1145,22 +1058,40 @@ private predicate interpretSummary(
// adapter class for converting Mad summaries to `SummarizedCallable`s // adapter class for converting Mad summaries to `SummarizedCallable`s
private class SummarizedCallableAdapter extends SummarizedCallable { private class SummarizedCallableAdapter extends SummarizedCallable {
string input_; SummarizedCallableAdapter() { interpretSummary(this, _, _, _, _, _) }
string output_;
string kind;
Provenance p_;
string model_;
SummarizedCallableAdapter() { interpretSummary(this, input_, output_, kind, p_, model_) } private predicate relevantSummaryElementManual(
string input, string output, string kind, string model
) {
exists(Provenance provenance |
interpretSummary(this, input, output, kind, provenance, model) and
provenance.isManual()
)
}
private predicate relevantSummaryElementGenerated(
string input, string output, string kind, string model
) {
exists(Provenance provenance |
interpretSummary(this, input, output, kind, provenance, model) and
provenance.isGenerated()
)
}
override predicate propagatesFlow( override predicate propagatesFlow(
string input, string output, boolean preservesValue, Provenance p, boolean isExact, string model string input, string output, boolean preservesValue, string model
) { ) {
input = input_ and exists(string kind |
output = output_ and this.relevantSummaryElementManual(input, output, kind, model)
(if kind = "value" then preservesValue = true else preservesValue = false) and or
p = p_ and not this.relevantSummaryElementManual(_, _, _, _) and
isExact = true and this.relevantSummaryElementGenerated(input, output, kind, model)
model = model_ |
if kind = "value" then preservesValue = true else preservesValue = false
)
}
override predicate hasProvenance(Provenance provenance) {
interpretSummary(this, _, _, _, provenance, _)
} }
} }

View File

@@ -20,8 +20,6 @@ module Input implements InputSig<Location, DataFlowImplSpecific::CppDataFlow> {
class SinkBase = Void; class SinkBase = Void;
predicate callableFromSource(SummarizedCallableBase c) { exists(c.getBlock()) }
ArgumentPosition callbackSelfParameterPosition() { result = TDirectPosition(-1) } ArgumentPosition callbackSelfParameterPosition() { result = TDirectPosition(-1) }
ReturnKind getStandardReturnValueKind() { result = getReturnValueKind("") } ReturnKind getStandardReturnValueKind() { result = getReturnValueKind("") }
@@ -151,27 +149,16 @@ module SourceSinkInterpretationInput implements
} }
predicate barrierElement( predicate barrierElement(
Element e, string output, string kind, Public::Provenance provenance, string model Element n, string output, string kind, Public::Provenance provenance, string model
) { ) {
exists( none()
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
barrierModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance, model) and
e = interpretElement(namespace, type, subtypes, name, signature, ext)
)
} }
predicate barrierGuardElement( predicate barrierGuardElement(
Element e, string input, Public::AcceptingValue acceptingvalue, string kind, Element n, string input, Public::AcceptingValue acceptingvalue, string kind,
Public::Provenance provenance, string model Public::Provenance provenance, string model
) { ) {
exists( none()
string package, string type, boolean subtypes, string name, string signature, string ext
|
barrierGuardModel(package, type, subtypes, name, signature, ext, input, acceptingvalue, kind,
provenance, model) and
e = interpretElement(package, type, subtypes, name, signature, ext)
)
} }
private newtype TInterpretNode = private newtype TInterpretNode =

View File

@@ -394,11 +394,6 @@ class FunctionAccess extends Access, @routineexpr {
*/ */
class ParamAccessForType extends Expr, @param_ref { class ParamAccessForType extends Expr, @param_ref {
override string toString() { result = "param access" } 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)) }
} }
/** /**

View File

@@ -1941,61 +1941,3 @@ class BuiltInOperationIsTriviallyRelocatable extends BuiltInOperation, @istrivia
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyRelocatable" } 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" }
}

View File

@@ -387,23 +387,10 @@ class OverloadedArrayExpr extends FunctionCall {
/** /**
* Gets the expression giving the index. * Gets the expression giving the index.
*
* DEPRECATED: Use getArrayOffset/1 instead.
*/ */
deprecated Expr getArrayOffset() { result = this.getArrayOffset(0) } Expr getArrayOffset() {
if exists(this.getQualifier()) then result = this.getChild(0) else result = this.getChild(1)
/**
* 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)
} }
/**
* Gets an expression giving an index.
*/
Expr getAnArrayOffset() { result = this.getArrayOffset(_) }
} }
/** /**

View File

@@ -23,7 +23,7 @@ class Expr extends StmtParent, @expr {
predicate hasChild(Expr e, int n) { e = this.getChild(n) } predicate hasChild(Expr e, int n) { e = this.getChild(n) }
/** Gets the enclosing function of this expression, if any. */ /** Gets the enclosing function of this expression, if any. */
override Function getEnclosingFunction() { result = exprEnclosingElement(this) } Function getEnclosingFunction() { result = exprEnclosingElement(this) }
/** Gets the nearest enclosing set of curly braces around this expression in the source, if any. */ /** Gets the nearest enclosing set of curly braces around this expression in the source, if any. */
BlockStmt getEnclosingBlock() { result = this.getEnclosingStmt().getEnclosingBlock() } BlockStmt getEnclosingBlock() { result = this.getEnclosingStmt().getEnclosingBlock() }

View File

@@ -45,13 +45,13 @@ private string getSingleLocationFilePath(@element e) {
overlay[local] overlay[local]
private string getMultiLocationFilePath(@element e) { private string getMultiLocationFilePath(@element e) {
exists(@location_default loc | exists(@location_default loc |
var_decls(_, e, _, _, loc) exists(@var_decl vd | var_decls(vd, e, _, _, loc))
or or
fun_decls(_, e, _, _, loc) exists(@fun_decl fd | fun_decls(fd, e, _, _, loc))
or or
type_decls(_, e, loc) exists(@type_decl td | type_decls(td, e, loc))
or or
namespace_decls(_, e, loc, _) exists(@namespace_decl nd | namespace_decls(nd, e, loc, _))
| |
result = getLocationFilePath(loc) result = getLocationFilePath(loc)
) )
@@ -62,29 +62,19 @@ private string getMultiLocationFilePath(@element e) {
* overlay variant. * overlay variant.
*/ */
overlay[local] overlay[local]
private predicate isBase() { not isOverlay() } private predicate holdsInBase() { not isOverlay() }
/**
* Holds if `path` was extracted in the overlay database.
*/
overlay[local]
private predicate overlayHasFile(string path) {
isOverlay() and
files(_, path) and
path != ""
}
/** /**
* Discards an element from the base variant if: * Discards an element from the base variant if:
* - It has a single location in a file extracted in the overlay, or * - It has a single location in a changed file, or
* - All of its locations are in files extracted in the overlay. * - All of its locations are in changed files.
*/ */
overlay[discard_entity] overlay[discard_entity]
private predicate discardElement(@element e) { private predicate discardElement(@element e) {
isBase() and holdsInBase() and
( (
overlayHasFile(getSingleLocationFilePath(e)) overlayChangedFiles(getSingleLocationFilePath(e))
or or
forex(string path | path = getMultiLocationFilePath(e) | overlayHasFile(path)) forex(string path | path = getMultiLocationFilePath(e) | overlayChangedFiles(path))
) )
} }

View File

@@ -1144,7 +1144,7 @@ private newtype TDataFlowCall =
} }
private predicate summarizedCallableIsManual(SummarizedCallable sc) { private predicate summarizedCallableIsManual(SummarizedCallable sc) {
sc.asSummarizedCallable().hasManualModel() sc.asSummarizedCallable().applyManualModel()
} }
/** /**

View File

@@ -156,7 +156,7 @@ class Node extends TIRDataFlowNode {
* If `isGLValue()` holds, then the type of this node * If `isGLValue()` holds, then the type of this node
* should be thought of as "pointer to `getType()`". * 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. */ /** Gets the instruction corresponding to this node, if any. */
Instruction asInstruction() { result = this.(InstructionNode).getInstruction() } Instruction asInstruction() { result = this.(InstructionNode).getInstruction() }
@@ -312,13 +312,6 @@ class Node extends TIRDataFlowNode {
*/ */
Expr asDefinition() { result = this.asDefinition(_) } Expr asDefinition() { result = this.asDefinition(_) }
private predicate isCertainStore() {
exists(SsaImpl::Definition def |
SsaImpl::defToNode(this, def, _) and
def.isCertain()
)
}
/** /**
* Gets the definition associated with this node, if any. * Gets the definition associated with this node, if any.
* *
@@ -368,10 +361,11 @@ class Node extends TIRDataFlowNode {
* pointed to by `p`. * pointed to by `p`.
*/ */
Expr asDefinition(boolean uncertain) { Expr asDefinition(boolean uncertain) {
exists(StoreInstruction store | exists(StoreInstruction store, SsaImpl::Definition def |
store = this.asInstruction() and store = this.asInstruction() and
result = asDefinitionImpl(store) and result = asDefinitionImpl(store) and
if this.isCertainStore() then uncertain = false else uncertain = true SsaImpl::defToNode(this, def, _) and
if def.isCertain() then uncertain = false else uncertain = true
) )
} }
@@ -547,7 +541,7 @@ class Node extends TIRDataFlowNode {
/** /**
* Gets an upper bound on the type of this node. * 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. */ /** Gets the location of this element. */
cached cached
@@ -591,7 +585,7 @@ private class Node0 extends Node, TNode0 {
override string toStringImpl() { result = node.toString() } override string toStringImpl() { result = node.toString() }
override Type getType() { result = node.getType() } override DataFlowType getType() { result = node.getType() }
override predicate isGLValue() { node.isGLValue() } override predicate isGLValue() { node.isGLValue() }
} }
@@ -710,7 +704,7 @@ class SsaSynthNode extends Node, TSsaSynthNode {
override Declaration getFunction() { result = node.getBasicBlock().getEnclosingFunction() } 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() } override predicate isGLValue() { node.getSourceVariable().isGLValue() }
@@ -738,7 +732,7 @@ class SsaIteratorNode extends Node, TSsaIteratorNode {
override Declaration getFunction() { result = node.getFunction() } 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() } final override Location getLocationImpl() { result = node.getLocation() }
@@ -798,7 +792,7 @@ class FinalGlobalValue extends Node, TFinalGlobalValue {
override Declaration getFunction() { result = globalUse.getIRFunction().getFunction() } override Declaration getFunction() { result = globalUse.getIRFunction().getFunction() }
override Type getType() { override DataFlowType getType() {
exists(int indirectionIndex | exists(int indirectionIndex |
indirectionIndex = globalUse.getIndirectionIndex() and indirectionIndex = globalUse.getIndirectionIndex() and
result = getTypeImpl(globalUse.getUnderlyingType(), indirectionIndex) result = getTypeImpl(globalUse.getUnderlyingType(), indirectionIndex)
@@ -832,7 +826,7 @@ class InitialGlobalValue extends Node, TInitialGlobalValue {
final override predicate isGLValue() { globalDef.getIndirectionIndex() = 0 } 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() } final override Location getLocationImpl() { result = globalDef.getLocation() }
@@ -859,7 +853,7 @@ class BodyLessParameterNodeImpl extends Node, TBodyLessParameterNodeImpl {
/** Gets the indirection index of this node. */ /** Gets the indirection index of this node. */
int getIndirectionIndex() { result = indirectionIndex } int getIndirectionIndex() { result = indirectionIndex }
override Type getType() { override DataFlowType getType() {
result = getTypeImpl(p.getUnderlyingType(), this.getIndirectionIndex()) result = getTypeImpl(p.getUnderlyingType(), this.getIndirectionIndex())
} }
@@ -1123,8 +1117,8 @@ private module RawIndirectNodes {
override predicate isGLValue() { this.getOperand().isGLValue() } override predicate isGLValue() { this.getOperand().isGLValue() }
override Type getType() { override DataFlowType getType() {
exists(int sub, Type type, boolean isGLValue | exists(int sub, DataFlowType type, boolean isGLValue |
type = getOperandType(this.getOperand(), isGLValue) and type = getOperandType(this.getOperand(), isGLValue) and
if isGLValue = true then sub = 1 else sub = 0 if isGLValue = true then sub = 1 else sub = 0
| |
@@ -1169,8 +1163,8 @@ private module RawIndirectNodes {
override predicate isGLValue() { this.getInstruction().isGLValue() } override predicate isGLValue() { this.getInstruction().isGLValue() }
override Type getType() { override DataFlowType getType() {
exists(int sub, Type type, boolean isGLValue | exists(int sub, DataFlowType type, boolean isGLValue |
type = getInstructionType(this.getInstruction(), isGLValue) and type = getInstructionType(this.getInstruction(), isGLValue) and
if isGLValue = true then sub = 1 else sub = 0 if isGLValue = true then sub = 1 else sub = 0
| |
@@ -1269,7 +1263,7 @@ class FinalParameterNode extends Node, TFinalParameterNode {
result.asSourceCallable() = this.getFunction() result.asSourceCallable() = this.getFunction()
} }
override Type getType() { result = getTypeImpl(p.getUnderlyingType(), indirectionIndex) } override DataFlowType getType() { result = getTypeImpl(p.getUnderlyingType(), indirectionIndex) }
final override Location getLocationImpl() { final override Location getLocationImpl() {
// Parameters can have multiple locations. When there's a unique location we use // Parameters can have multiple locations. When there's a unique location we use
@@ -1545,7 +1539,7 @@ abstract class PostUpdateNode extends Node {
*/ */
abstract Node getPreUpdateNode(); abstract Node getPreUpdateNode();
final override Type getType() { result = this.getPreUpdateNode().getType() } final override DataFlowType getType() { result = this.getPreUpdateNode().getType() }
} }
/** /**
@@ -1638,7 +1632,9 @@ class VariableNode extends Node, TGlobalLikeVariableNode {
result.asSourceCallable() = v 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() { final override Location getLocationImpl() {
// Certain variables (such as parameters) can have multiple locations. // Certain variables (such as parameters) can have multiple locations.
@@ -1726,7 +1722,9 @@ private module Cached {
SsaImpl::ssaFlow(n, succ) and SsaImpl::ssaFlow(n, succ) and
bb1 = n.getBasicBlock() and bb1 = n.getBasicBlock() and
bb2 = succ.getBasicBlock() and bb2 = succ.getBasicBlock() and
bb2.strictlyDominates(bb1) bb1 != bb2 and
bb2.dominates(bb1) and
bb1.getASuccessor+() = bb2
) )
} }
@@ -2421,19 +2419,6 @@ class ContentSet instanceof Content {
} }
} }
private signature class ParamSig;
private module WithParam<ParamSig P> {
/**
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
*
* The expression `e` is expected to be a syntactic part of the guard `g`.
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
* the argument `x`.
*/
signature predicate guardChecksSig(IRGuardCondition g, Expr e, boolean branch, P param);
}
/** /**
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`. * Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
* *
@@ -2455,7 +2440,7 @@ private predicate controls(IRGuardCondition g, Node n, boolean edge) {
* This is expected to be used in `isBarrier`/`isSanitizer` definitions * This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking. * in data flow and taint tracking.
*/ */
module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guardChecks> { module BarrierGuard<guardChecksSig/3 guardChecks> {
bindingset[value, n] bindingset[value, n]
pragma[inline_late] pragma[inline_late]
private predicate convertedExprHasValueNumber(ValueNumber value, Node n) { private predicate convertedExprHasValueNumber(ValueNumber value, Node n) {
@@ -2465,13 +2450,12 @@ module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guar
) )
} }
private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch, P p) { private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch) {
guardChecks(g, n.asOperand().getDef().getConvertedResultExpression(), branch, p) guardChecks(g, n.asOperand().getDef().getConvertedResultExpression(), branch)
} }
/** /**
* Gets an expression node that is safely guarded by the given guard check * Gets an expression node that is safely guarded by the given guard check.
* when the parameter is `p`.
* *
* For example, given the following code: * For example, given the following code:
* ```cpp * ```cpp
@@ -2502,27 +2486,19 @@ module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guar
* *
* NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead. * NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead.
*/ */
Node getABarrierNode(P p) { Node getABarrierNode() {
exists(IRGuardCondition g, ValueNumber value, boolean edge | exists(IRGuardCondition g, ValueNumber value, boolean edge |
convertedExprHasValueNumber(value, result) and convertedExprHasValueNumber(value, result) and
guardChecks(g, guardChecks(g,
pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge, p) and pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge) and
controls(g, result, edge) controls(g, result, edge)
) )
or or
result = SsaImpl::BarrierGuard<P, guardChecksNode/4>::getABarrierNode(p) result = SsaImpl::BarrierGuard<guardChecksNode/3>::getABarrierNode()
} }
/** /**
* Gets an expression node that is safely guarded by the given guard check. * Gets an indirect expression node that is safely guarded by the given guard check.
*
* See `getABarrierNode/1` for examples.
*/
Node getABarrierNode() { result = getABarrierNode(_) }
/**
* Gets an indirect expression node that is safely guarded by the given
* guard check with parameter `p`.
* *
* For example, given the following code: * For example, given the following code:
* ```cpp * ```cpp
@@ -2554,13 +2530,6 @@ module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guar
* *
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead. * NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
*/ */
Node getAnIndirectBarrierNode(P p) { result = getAnIndirectBarrierNode(_, p) }
/**
* Gets an indirect expression node that is safely guarded by the given guard check.
*
* See `getAnIndirectBarrierNode/1` for examples.
*/
Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) } Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
bindingset[value, n] bindingset[value, n]
@@ -2575,10 +2544,10 @@ module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guar
} }
private predicate guardChecksIndirectNode( private predicate guardChecksIndirectNode(
IRGuardCondition g, Node n, boolean branch, int indirectionIndex, P p IRGuardCondition g, Node n, boolean branch, int indirectionIndex
) { ) {
guardChecks(g, n.asIndirectOperand(indirectionIndex).getDef().getConvertedResultExpression(), guardChecks(g, n.asIndirectOperand(indirectionIndex).getDef().getConvertedResultExpression(),
branch, p) branch)
} }
/** /**
@@ -2615,44 +2584,19 @@ module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guar
* *
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead. * NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
*/ */
Node getAnIndirectBarrierNode(int indirectionIndex, P p) { Node getAnIndirectBarrierNode(int indirectionIndex) {
exists(IRGuardCondition g, ValueNumber value, boolean edge | exists(IRGuardCondition g, ValueNumber value, boolean edge |
indirectConvertedExprHasValueNumber(indirectionIndex, value, result) and indirectConvertedExprHasValueNumber(indirectionIndex, value, result) and
guardChecks(g, guardChecks(g,
pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge, p) and pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge) and
controls(g, result, edge) controls(g, result, edge)
) )
or or
result = result =
SsaImpl::BarrierGuardWithIntParam<P, guardChecksIndirectNode/5>::getABarrierNode(indirectionIndex, SsaImpl::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
p)
} }
} }
/**
* Provides a set of barrier nodes for a guard that validates an expression.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module BarrierGuard<guardChecksSig/3 guardChecks> {
private predicate guardChecks(IRGuardCondition g, Expr e, boolean branch, Unit unit) {
guardChecks(g, e, branch) and
exists(unit)
}
import ParameterizedBarrierGuard<Unit, guardChecks/4>
}
private module InstrWithParam<ParamSig P> {
/**
* Holds if the guard `g` validates the instruction `instr` upon evaluating to `branch`.
*/
signature predicate instructionGuardChecksSig(
IRGuardCondition g, Instruction instr, boolean branch, P p
);
}
/** /**
* Holds if the guard `g` validates the instruction `instr` upon evaluating to `branch`. * Holds if the guard `g` validates the instruction `instr` upon evaluating to `branch`.
*/ */
@@ -2664,9 +2608,7 @@ signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction in
* This is expected to be used in `isBarrier`/`isSanitizer` definitions * This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking. * in data flow and taint tracking.
*/ */
module ParameterizedInstructionBarrierGuard< module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> {
ParamSig P, InstrWithParam<P>::instructionGuardChecksSig/4 instructionGuardChecks>
{
bindingset[value, n] bindingset[value, n]
pragma[inline_late] pragma[inline_late]
private predicate operandHasValueNumber(ValueNumber value, Node n) { private predicate operandHasValueNumber(ValueNumber value, Node n) {
@@ -2676,27 +2618,21 @@ module ParameterizedInstructionBarrierGuard<
) )
} }
private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch, P p) { private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch) {
instructionGuardChecks(g, n.asOperand().getDef(), branch, p) instructionGuardChecks(g, n.asOperand().getDef(), branch)
} }
/** /** Gets a node that is safely guarded by the given guard check. */
* Gets a node that is safely guarded by the given guard check with Node getABarrierNode() {
* parameter `p`.
*/
Node getABarrierNode(P p) {
exists(IRGuardCondition g, ValueNumber value, boolean edge | exists(IRGuardCondition g, ValueNumber value, boolean edge |
instructionGuardChecks(g, pragma[only_bind_into](value.getAnInstruction()), edge, p) and instructionGuardChecks(g, pragma[only_bind_into](value.getAnInstruction()), edge) and
operandHasValueNumber(value, result) and operandHasValueNumber(value, result) and
controls(g, result, edge) controls(g, result, edge)
) )
or or
result = SsaImpl::BarrierGuard<P, guardChecksNode/4>::getABarrierNode(p) result = SsaImpl::BarrierGuard<guardChecksNode/3>::getABarrierNode()
} }
/** Gets a node that is safely guarded by the given guard check. */
Node getABarrierNode() { result = getABarrierNode(_) }
bindingset[value, n] bindingset[value, n]
pragma[inline_late] pragma[inline_late]
private predicate indirectOperandHasValueNumber(ValueNumber value, int indirectionIndex, Node n) { private predicate indirectOperandHasValueNumber(ValueNumber value, int indirectionIndex, Node n) {
@@ -2707,52 +2643,25 @@ module ParameterizedInstructionBarrierGuard<
} }
private predicate guardChecksIndirectNode( private predicate guardChecksIndirectNode(
IRGuardCondition g, Node n, boolean branch, int indirectionIndex, P p IRGuardCondition g, Node n, boolean branch, int indirectionIndex
) { ) {
instructionGuardChecks(g, n.asIndirectOperand(indirectionIndex).getDef(), branch, p) instructionGuardChecks(g, n.asIndirectOperand(indirectionIndex).getDef(), branch)
} }
/** /**
* Gets an indirect node with indirection index `indirectionIndex` that is * Gets an indirect node with indirection index `indirectionIndex` that is
* safely guarded by the given guard check with parameter `p`. * safely guarded by the given guard check.
*/ */
Node getAnIndirectBarrierNode(int indirectionIndex, P p) { Node getAnIndirectBarrierNode(int indirectionIndex) {
exists(IRGuardCondition g, ValueNumber value, boolean edge | exists(IRGuardCondition g, ValueNumber value, boolean edge |
instructionGuardChecks(g, pragma[only_bind_into](value.getAnInstruction()), edge, p) and instructionGuardChecks(g, pragma[only_bind_into](value.getAnInstruction()), edge) and
indirectOperandHasValueNumber(value, indirectionIndex, result) and indirectOperandHasValueNumber(value, indirectionIndex, result) and
controls(g, result, edge) controls(g, result, edge)
) )
or or
result = result =
SsaImpl::BarrierGuardWithIntParam<P, guardChecksIndirectNode/5>::getABarrierNode(indirectionIndex, SsaImpl::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
p)
} }
/**
* Gets an indirect node that is safely guarded by the given guard check
* with parameter `p`.
*/
Node getAnIndirectBarrierNode(P p) { result = getAnIndirectBarrierNode(_, p) }
/** Gets an indirect node that is safely guarded by the given guard check. */
Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
}
/**
* Provides a set of barrier nodes for a guard that validates an instruction.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> {
private predicate instructionGuardChecks(
IRGuardCondition g, Instruction i, boolean branch, Unit unit
) {
instructionGuardChecks(g, i, branch) and
exists(unit)
}
import ParameterizedInstructionBarrierGuard<Unit, instructionGuardChecks/4>
} }
/** /**

View File

@@ -15,79 +15,17 @@ private import DataFlowPrivate
import SsaImplCommon import SsaImplCommon
private module SourceVariables { private module SourceVariables {
/**
* Holds if `store` is the `StoreInstruction` generated by a postfix
* increment or decrement operation `e`, and `postCrement` is the operand
* that represents the use of the evaluated value of `e`.
*/
private predicate isUseAfterPostfixCrement0(StoreInstruction store, Operand postCrement) {
exists(
BinaryInstruction binary, IRBlock b, int iPre, int iPost, int iStore, Operand preCrement,
Instruction left
|
binary instanceof AddInstruction
or
binary instanceof PointerAddInstruction
or
binary instanceof SubInstruction
or
binary instanceof PointerSubInstruction
|
store.getSourceValue() = binary and
left = binary.getLeft() and
strictcount(left.getAUse()) = 2 and
left.getAUse() = preCrement and
left.getAUse() = postCrement and
b.getInstruction(iPre) = preCrement.getUse() and
b.getInstruction(iPost) = postCrement.getUse() and
b.getInstruction(iStore) = store and
iPre < iStore and
iStore < iPost
)
}
/**
* Holds if `store` is the `StoreInstruction` generated by an postfix
* increment or decrement operation `e`, and `postCrement` is the fully
* converted operand that represents the use of the evaluated value of `e`.
*/
private predicate isUseAfterPostfixCrement(StoreInstruction store, Operand postCrement) {
isUseAfterPostfixCrement0(store, postCrement) and
conversionFlow(postCrement, _, false, _)
or
exists(Instruction instr, Operand postCrement0 |
isUseAfterPostfixCrement(store, postCrement0) and
conversionFlow(postCrement0, instr, false, _) and
instr = postCrement.getDef()
)
}
private predicate hasSavedPostfixCrementSourceVariable(
BaseSourceVariable base, StoreInstruction store, int ind
) {
exists(BaseSourceVariableInstruction inst, int ind0 |
isUseAfterPostfixCrement(store, _) and
inst.getBaseSourceVariable() = base and
isDef(_, _, store.getDestinationAddressOperand(), inst, ind0, 0) and
ind = [ind0 .. countIndirectionsForCppType(base.getLanguageType()) + 1]
)
}
cached cached
private newtype TSourceVariable = private newtype TSourceVariable =
TNormalSourceVariable(BaseSourceVariable base, int ind) { TMkSourceVariable(BaseSourceVariable base, int ind) {
ind = [0 .. countIndirectionsForCppType(base.getLanguageType()) + 1] ind = [0 .. countIndirectionsForCppType(base.getLanguageType()) + 1]
} or
TSavedPostfixCrementSourceVariable(StoreInstruction store, int ind) {
hasSavedPostfixCrementSourceVariable(_, store, ind)
} }
abstract private class AbstractSourceVariable extends TSourceVariable { class SourceVariable extends TSourceVariable {
BaseSourceVariable base; BaseSourceVariable base;
int ind; int ind;
bindingset[ind] SourceVariable() { this = TMkSourceVariable(base, ind) }
AbstractSourceVariable() { any() }
/** Gets the IR variable associated with this `SourceVariable`, if any. */ /** Gets the IR variable associated with this `SourceVariable`, if any. */
IRVariable getIRVariable() { result = base.(BaseIRVariable).getIRVariable() } IRVariable getIRVariable() { result = base.(BaseIRVariable).getIRVariable() }
@@ -99,7 +37,7 @@ private module SourceVariables {
BaseSourceVariable getBaseVariable() { result = base } BaseSourceVariable getBaseVariable() { result = base }
/** Gets a textual representation of this element. */ /** Gets a textual representation of this element. */
abstract string toString(); string toString() { result = repeatStars(this.getIndirection()) + base.toString() }
/** /**
* Gets the number of loads performed on the base source variable * Gets the number of loads performed on the base source variable
@@ -115,7 +53,7 @@ private module SourceVariables {
* the type of this source variable should be thought of as "pointer * the type of this source variable should be thought of as "pointer
* to `getType()`". * to `getType()`".
*/ */
Type getType() { DataFlowType getType() {
if this.isGLValue() if this.isGLValue()
then result = base.getType() then result = base.getType()
else result = getTypeImpl(base.getType(), ind - 1) else result = getTypeImpl(base.getType(), ind - 1)
@@ -124,53 +62,6 @@ private module SourceVariables {
/** Gets the location of this variable. */ /** Gets the location of this variable. */
Location getLocation() { result = this.getBaseVariable().getLocation() } Location getLocation() { result = this.getBaseVariable().getLocation() }
} }
final class SourceVariable = AbstractSourceVariable;
/**
* A regular source variable. Most source variables are instances of this
* class.
*/
class NormalSourceVariable extends AbstractSourceVariable, TNormalSourceVariable {
NormalSourceVariable() { this = TNormalSourceVariable(base, ind) }
final override string toString() {
result = repeatStars(this.getIndirection()) + base.toString()
}
}
/**
* Before a value is postfix incremented (or decremented) we "save" its
* current value so that the pre-incremented value can be returned to the
* enclosing expression. We use the source variables represented by this
* class to represent the "saved value".
*/
class SavedPostfixCrementSourceVariable extends AbstractSourceVariable,
TSavedPostfixCrementSourceVariable
{
StoreInstruction store;
SavedPostfixCrementSourceVariable() {
this = TSavedPostfixCrementSourceVariable(store, ind) and
hasSavedPostfixCrementSourceVariable(base, store, ind)
}
final override string toString() {
result = repeatStars(this.getIndirection()) + base.toString() + " [before crement]"
}
/**
* Gets the `StoreInstruction` that writes the incremented (or decremented)
* value.
*/
StoreInstruction getStoreInstruction() { result = store }
/**
* Gets the fully converted `Operand` that represents the use of the
* value before the increment.
*/
Operand getOperand() { isUseAfterPostfixCrement(store, result) }
}
} }
import SourceVariables import SourceVariables
@@ -218,43 +109,17 @@ private newtype TDefImpl =
TDirectDefImpl(Operand address, int indirectionIndex) { TDirectDefImpl(Operand address, int indirectionIndex) {
isDef(_, _, address, _, _, indirectionIndex) isDef(_, _, address, _, _, indirectionIndex)
} or } or
TSavedPostfixCrementDefImpl(SavedPostfixCrementSourceVariable sv, int indirectionIndex) {
isDef(_, _, sv.getStoreInstruction().getDestinationAddressOperand(), _, sv.getIndirection(),
indirectionIndex)
} or
TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) { TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
// Represents the initial "definition" of a global variable when entering // Represents the initial "definition" of a global variable when entering
// a function body. // a function body.
isGlobalDefImpl(v, f, _, indirectionIndex) isGlobalDefImpl(v, f, _, indirectionIndex)
} }
pragma[nomagic]
private predicate hasOperandAndIndirection(
SavedPostfixCrementSourceVariable sv, Operand operand, int indirection
) {
sv.getOperand() = operand and
sv.getIndirection() = indirection
}
private predicate hasBeforePostCrementUseImpl(
SavedPostfixCrementSourceVariable sv, Operand operand, int indirectionIndex
) {
not isDef(true, _, operand, _, _, _) and
exists(int indirection |
hasOperandAndIndirection(sv, operand, indirection) and
isUse(_, operand, _, indirection, indirectionIndex)
)
}
cached cached
private newtype TUseImpl = private newtype TUseImpl =
TDirectUseImpl(Operand operand, int indirectionIndex) { TDirectUseImpl(Operand operand, int indirectionIndex) {
isUse(_, operand, _, _, indirectionIndex) and isUse(_, operand, _, _, indirectionIndex) and
not isDef(true, _, operand, _, _, _) and not isDef(true, _, operand, _, _, _)
not hasBeforePostCrementUseImpl(_, operand, indirectionIndex)
} or
TSavedPostfixCrementUseImpl(SavedPostfixCrementSourceVariable sv, int indirectionIndex) {
hasBeforePostCrementUseImpl(sv, _, indirectionIndex)
} or } or
TGlobalUse(GlobalLikeVariable v, IRFunction f, int indirectionIndex) { TGlobalUse(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
// Represents a final "use" of a global variable to ensure that // Represents a final "use" of a global variable to ensure that
@@ -358,8 +223,19 @@ abstract class DefImpl extends TDefImpl {
*/ */
abstract int getIndirection(); abstract int getIndirection();
/**
* Gets the base source variable (i.e., the variable without
* any indirection) of this definition or use.
*/
abstract BaseSourceVariable getBaseSourceVariable();
/** Gets the variable that is defined or used. */ /** Gets the variable that is defined or used. */
abstract SourceVariable getSourceVariable(); SourceVariable getSourceVariable() {
exists(BaseSourceVariable v, int indirection |
sourceVariableHasBaseAndIndex(result, v, indirection) and
defHasSourceVariable(this, v, indirection)
)
}
/** /**
* Holds if this definition is guaranteed to totally overwrite the * Holds if this definition is guaranteed to totally overwrite the
@@ -367,8 +243,8 @@ abstract class DefImpl extends TDefImpl {
*/ */
abstract predicate isCertain(); abstract predicate isCertain();
/** Gets the value written to the destination variable by this definition, if any. */ /** Gets the value written to the destination variable by this definition. */
Node0Impl getValue() { none() } abstract Node0Impl getValue();
/** Gets the operand that represents the address of this definition, if any. */ /** Gets the operand that represents the address of this definition, if any. */
Operand getAddressOperand() { none() } Operand getAddressOperand() { none() }
@@ -417,8 +293,19 @@ abstract class UseImpl extends TUseImpl {
/** Gets the indirection index of this use. */ /** Gets the indirection index of this use. */
final int getIndirectionIndex() { result = indirectionIndex } final int getIndirectionIndex() { result = indirectionIndex }
/**
* Gets the base source variable (i.e., the variable without
* any indirection) of this definition or use.
*/
abstract BaseSourceVariable getBaseSourceVariable();
/** Gets the variable that is defined or used. */ /** Gets the variable that is defined or used. */
abstract SourceVariable getSourceVariable(); SourceVariable getSourceVariable() {
exists(BaseSourceVariable v, int indirection |
sourceVariableHasBaseAndIndex(result, v, indirection) and
useHasSourceVariable(this, v, indirection)
)
}
/** /**
* Holds if this use is guaranteed to read the * Holds if this use is guaranteed to read the
@@ -427,6 +314,18 @@ abstract class UseImpl extends TUseImpl {
abstract predicate isCertain(); abstract predicate isCertain();
} }
pragma[noinline]
private predicate defHasSourceVariable(DefImpl def, BaseSourceVariable bv, int ind) {
bv = def.getBaseSourceVariable() and
ind = def.getIndirection()
}
pragma[noinline]
private predicate useHasSourceVariable(UseImpl use, BaseSourceVariable bv, int ind) {
bv = use.getBaseSourceVariable() and
ind = use.getIndirection()
}
pragma[noinline] pragma[noinline]
private predicate sourceVariableHasBaseAndIndex(SourceVariable v, BaseSourceVariable bv, int ind) { private predicate sourceVariableHasBaseAndIndex(SourceVariable v, BaseSourceVariable bv, int ind) {
v.getBaseVariable() = bv and v.getBaseVariable() = bv and
@@ -459,12 +358,16 @@ abstract private class DefAddressImpl extends DefImpl, TDefAddressImpl {
final override predicate isCertain() { any() } final override predicate isCertain() { any() }
final override Node0Impl getValue() { none() }
override Cpp::Location getLocation() { result = v.getLocation() } override Cpp::Location getLocation() { result = v.getLocation() }
final override NormalSourceVariable getSourceVariable() { final override SourceVariable getSourceVariable() {
result.getBaseVariable() = v and result.getBaseVariable() = v and
result.getIndirection() = 0 result.getIndirection() = 0
} }
final override BaseSourceVariable getBaseSourceVariable() { result = v }
} }
private class DefVariableAddressImpl extends DefAddressImpl { private class DefVariableAddressImpl extends DefAddressImpl {
@@ -510,17 +413,8 @@ private class DirectDef extends DefImpl, TDirectDefImpl {
isDef(_, _, address, result, _, indirectionIndex) isDef(_, _, address, result, _, indirectionIndex)
} }
pragma[nomagic] override BaseSourceVariable getBaseSourceVariable() {
private predicate hasBaseSourceVariableAndIndirection(BaseSourceVariable v, int indirection) { result = this.getBase().getBaseSourceVariable()
v = this.getBase().getBaseSourceVariable() and
indirection = this.getIndirection()
}
final override NormalSourceVariable getSourceVariable() {
exists(BaseSourceVariable v, int indirection |
sourceVariableHasBaseAndIndex(result, v, indirection) and
this.hasBaseSourceVariableAndIndirection(v, indirection)
)
} }
override int getIndirection() { isDef(_, _, address, _, result, indirectionIndex) } override int getIndirection() { isDef(_, _, address, _, result, indirectionIndex) }
@@ -530,32 +424,6 @@ private class DirectDef extends DefImpl, TDirectDefImpl {
override predicate isCertain() { isDef(true, _, address, _, _, indirectionIndex) } override predicate isCertain() { isDef(true, _, address, _, _, indirectionIndex) }
} }
/**
* A definition that "saves" the value of a variable before it is incremented
* or decremented.
*/
private class SavedPostfixCrementDefImpl extends DefImpl, TSavedPostfixCrementDefImpl {
SavedPostfixCrementSourceVariable sv;
SavedPostfixCrementDefImpl() { this = TSavedPostfixCrementDefImpl(sv, indirectionIndex) }
override Cpp::Location getLocation() { result = sv.getStoreInstruction().getLocation() }
final override predicate hasIndexInBlock(IRBlock block, int index) {
sv.getStoreInstruction() = block.getInstruction(index)
}
override string toString() { result = "Def of " + this.getSourceVariable() }
override SourceVariable getSourceVariable() { result = sv }
override int getIndirection() { result = sv.getIndirection() }
override predicate isCertain() {
isDef(true, _, sv.getStoreInstruction().getDestinationAddressOperand(), _, _, indirectionIndex)
}
}
private class DirectUseImpl extends UseImpl, TDirectUseImpl { private class DirectUseImpl extends UseImpl, TDirectUseImpl {
Operand operand; Operand operand;
@@ -564,22 +432,29 @@ private class DirectUseImpl extends UseImpl, TDirectUseImpl {
override string toString() { result = "Use of " + this.getSourceVariable() } override string toString() { result = "Use of " + this.getSourceVariable() }
final override predicate hasIndexInBlock(IRBlock block, int index) { final override predicate hasIndexInBlock(IRBlock block, int index) {
operand.getUse() = block.getInstruction(index) // See the comment in `ssa0`'s `OperandBasedUse` for an explanation of this
// predicate's implementation.
if this.getBase().getAst() = any(Cpp::PostfixCrementOperation c).getOperand()
then
exists(Operand op, int indirection, Instruction base |
indirection = this.getIndirection() and
base = this.getBase() and
op =
min(Operand cand, int i |
isUse(_, cand, base, indirection, indirectionIndex) and
block.getInstruction(i) = cand.getUse()
|
cand order by i
) and
block.getInstruction(index) = op.getUse()
)
else operand.getUse() = block.getInstruction(index)
} }
private BaseSourceVariableInstruction getBase() { isUse(_, operand, result, _, indirectionIndex) } private BaseSourceVariableInstruction getBase() { isUse(_, operand, result, _, indirectionIndex) }
pragma[nomagic] override BaseSourceVariable getBaseSourceVariable() {
private predicate hasBaseSourceVariableAndIndirection(BaseSourceVariable bv, int indirection) { result = this.getBase().getBaseSourceVariable()
this.getBase().getBaseSourceVariable() = bv and
this.getIndirection() = indirection
}
override NormalSourceVariable getSourceVariable() {
exists(BaseSourceVariable v, int indirection |
sourceVariableHasBaseAndIndex(result, v, indirection) and
this.hasBaseSourceVariableAndIndirection(v, indirection)
)
} }
final Operand getOperand() { result = operand } final Operand getOperand() { result = operand }
@@ -593,34 +468,6 @@ private class DirectUseImpl extends UseImpl, TDirectUseImpl {
override Node getNode() { nodeHasOperand(result, operand, indirectionIndex) } override Node getNode() { nodeHasOperand(result, operand, indirectionIndex) }
} }
/**
* The use of the original "saved" variable after the variable has been incremented
* or decremented.
*/
private class SavedPostfixCrementUseImpl extends UseImpl, TSavedPostfixCrementUseImpl {
SavedPostfixCrementSourceVariable sv;
SavedPostfixCrementUseImpl() { this = TSavedPostfixCrementUseImpl(sv, indirectionIndex) }
override string toString() { result = "Use of " + this.getSourceVariable() }
final override predicate hasIndexInBlock(IRBlock block, int index) {
this.getOperand().getUse() = block.getInstruction(index)
}
override SourceVariable getSourceVariable() { result = sv }
final Operand getOperand() { result = sv.getOperand() }
final override Cpp::Location getLocation() { result = this.getOperand().getLocation() }
override int getIndirection() { result = sv.getIndirection() }
override predicate isCertain() { isUse(true, this.getOperand(), _, _, indirectionIndex) }
override Node getNode() { nodeHasOperand(result, this.getOperand(), indirectionIndex) }
}
pragma[nomagic] pragma[nomagic]
private predicate finalParameterNodeHasParameterAndIndex( private predicate finalParameterNodeHasParameterAndIndex(
FinalParameterNode n, Parameter p, int indirectionIndex FinalParameterNode n, Parameter p, int indirectionIndex
@@ -685,18 +532,7 @@ class FinalParameterUse extends UseImpl, TFinalParameterUse {
result instanceof UnknownLocation result instanceof UnknownLocation
} }
pragma[nomagic] override BaseIRVariable getBaseSourceVariable() { result.getIRVariable().getAst() = p }
private predicate hasBaseSourceVariableAndIndirection(BaseIRVariable v, int indirection) {
v.getIRVariable().getAst() = p and
indirection = this.getIndirection()
}
override NormalSourceVariable getSourceVariable() {
exists(BaseIRVariable v, int indirection |
sourceVariableHasBaseAndIndex(result, v, indirection) and
this.hasBaseSourceVariableAndIndirection(v, indirection)
)
}
} }
/** /**
@@ -776,17 +612,8 @@ class GlobalUse extends UseImpl, TGlobalUse {
hasReturnPosition(f, block, index) hasReturnPosition(f, block, index)
} }
pragma[nomagic] override BaseSourceVariable getBaseSourceVariable() {
private predicate hasBaseSourceVariableAndIndirection(BaseIRVariable v, int indirection) { baseSourceVariableIsGlobal(result, global, f)
baseSourceVariableIsGlobal(v, global, f) and
indirection = this.getIndirection()
}
override NormalSourceVariable getSourceVariable() {
exists(BaseIRVariable v, int indirection |
sourceVariableHasBaseAndIndex(result, v, indirection) and
this.hasBaseSourceVariableAndIndirection(v, indirection)
)
} }
final override Cpp::Location getLocation() { result = f.getLocation() } final override Cpp::Location getLocation() { result = f.getLocation() }
@@ -831,15 +658,15 @@ class GlobalDefImpl extends DefImpl, TGlobalDefImpl {
) )
} }
final override NormalSourceVariable getSourceVariable() { /** Gets the global variable associated with this definition. */
exists(BaseSourceVariable v | override BaseSourceVariable getBaseSourceVariable() {
sourceVariableHasBaseAndIndex(result, v, indirectionIndex) and baseSourceVariableIsGlobal(result, global, f)
baseSourceVariableIsGlobal(v, global, f)
)
} }
override int getIndirection() { result = indirectionIndex } override int getIndirection() { result = indirectionIndex }
override Node0Impl getValue() { none() }
override predicate isCertain() { any() } override predicate isCertain() { any() }
/** /**
@@ -877,15 +704,9 @@ predicate defToNode(Node node, Definition def, SourceVariable sv) {
} }
private predicate defToNode(Node node, Definition def) { private predicate defToNode(Node node, Definition def) {
// Only definitions of `NormalSourceVariable` need to be converted into nodeHasOperand(node, def.getValue().asOperand(), def.getIndirectionIndex())
// dataflow nodes. The other case, `SavedPostfixCrementSourceVariable`, or
// are internal definitions that don't have a dataflow node representation. nodeHasInstruction(node, def.getValue().asInstruction(), def.getIndirectionIndex())
def.getSourceVariable() instanceof NormalSourceVariable and
(
nodeHasOperand(node, def.getValue().asOperand(), def.getIndirectionIndex())
or
nodeHasInstruction(node, def.getValue().asInstruction(), def.getIndirectionIndex())
)
or or
node.(InitialGlobalValue).getGlobalDef() = def node.(InitialGlobalValue).getGlobalDef() = def
} }
@@ -1119,16 +940,6 @@ module SsaCached {
SsaImpl::phiHasInputFromBlock(phi, inp, bb) SsaImpl::phiHasInputFromBlock(phi, inp, bb)
} }
cached
predicate uncertainWriteDefinitionInput(Definition uncertain, Definition inp) {
SsaImpl::uncertainWriteDefinitionInput(uncertain, inp)
}
cached
predicate ssaDefReachesEndOfBlock(IRBlock bb, Definition def) {
SsaImpl::ssaDefReachesEndOfBlock(bb, def, _)
}
predicate variableRead = SsaInput::variableRead/4; predicate variableRead = SsaInput::variableRead/4;
predicate variableWrite = SsaInput::variableWrite/4; predicate variableWrite = SsaInput::variableWrite/4;
@@ -1224,23 +1035,13 @@ class SynthNode extends DataFlowIntegrationImpl::SsaNode {
SynthNode() { not this.asDefinition() instanceof SsaImpl::WriteDefinition } SynthNode() { not this.asDefinition() instanceof SsaImpl::WriteDefinition }
} }
private signature class ParamSig; signature predicate guardChecksNodeSig(IRGuards::IRGuardCondition g, Node e, boolean branch);
private module ParamIntPair<ParamSig P> { signature predicate guardChecksNodeSig(
newtype TPair = MkPair(P p, int indirectionIndex) { nodeHasInstruction(_, _, indirectionIndex) } IRGuards::IRGuardCondition g, Node e, boolean branch, int indirectionIndex
} );
private module WithParam<ParamSig P> { module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
signature predicate guardChecksNodeSig(IRGuards::IRGuardCondition g, Node e, boolean gv, P param);
}
private module IntWithParam<ParamSig P> {
signature predicate guardChecksNodeSig(
IRGuards::IRGuardCondition g, Node e, boolean gv, int indirectionIndex, P param
);
}
module BarrierGuardWithIntParam<ParamSig P, IntWithParam<P>::guardChecksNodeSig/5 guardChecksNode> {
private predicate ssaDefReachesCertainUse(Definition def, UseImpl use) { private predicate ssaDefReachesCertainUse(Definition def, UseImpl use) {
exists(SourceVariable v, IRBlock bb, int i | exists(SourceVariable v, IRBlock bb, int i |
use.hasIndexInBlock(bb, i, v) and use.hasIndexInBlock(bb, i, v) and
@@ -1251,44 +1052,34 @@ module BarrierGuardWithIntParam<ParamSig P, IntWithParam<P>::guardChecksNodeSig/
private predicate guardChecksInstr( private predicate guardChecksInstr(
IRGuards::Guards_v1::Guard g, IRGuards::GuardsInput::Expr instr, IRGuards::GuardValue gv, IRGuards::Guards_v1::Guard g, IRGuards::GuardsInput::Expr instr, IRGuards::GuardValue gv,
ParamIntPair<P>::TPair pair int indirectionIndex
) { ) {
exists(Node node, int indirectionIndex, P p | exists(Node node |
pair = ParamIntPair<P>::MkPair(p, indirectionIndex) and
nodeHasInstruction(node, instr, indirectionIndex) and nodeHasInstruction(node, instr, indirectionIndex) and
guardChecksNode(g, node, gv.asBooleanValue(), indirectionIndex, p) guardChecksNode(g, node, gv.asBooleanValue(), indirectionIndex)
) )
} }
private predicate guardChecksWithWrappers( private predicate guardChecksWithWrappers(
DataFlowIntegrationInput::Guard g, SsaImpl::Definition def, IRGuards::GuardValue val, DataFlowIntegrationInput::Guard g, SsaImpl::Definition def, IRGuards::GuardValue val,
ParamIntPair<P>::MkPair pair int indirectionIndex
) { ) {
exists(Instruction e, int indirectionIndex | IRGuards::Guards_v1::ParameterizedValidationWrapper<int, guardChecksInstr/4>::guardChecksDef(g,
IRGuards::Guards_v1::ParameterizedValidationWrapper<ParamIntPair<P>::TPair, guardChecksInstr/4>::guardChecks(g, def, val, indirectionIndex)
e, val, pair) and
pair = ParamIntPair<P>::MkPair(_, indirectionIndex)
|
indirectionIndex = 0 and
def.(Definition).getAUse().getDef() = e
or
def.(Definition).getAnIndirectUse(indirectionIndex).getDef() = e
)
} }
Node getABarrierNode(int indirectionIndex, P p) { Node getABarrierNode(int indirectionIndex) {
// Only get the SynthNodes from the shared implementation, as the ExprNodes cannot // Only get the SynthNodes from the shared implementation, as the ExprNodes cannot
// be matched on SourceVariable. // be matched on SourceVariable.
result.(SsaSynthNode).getSynthNode() = result.(SsaSynthNode).getSynthNode() =
DataFlowIntegrationImpl::BarrierGuardDefWithState<ParamIntPair<P>::MkPair, guardChecksWithWrappers/4>::getABarrierNode(ParamIntPair<P>::MkPair(p, DataFlowIntegrationImpl::BarrierGuardDefWithState<int, guardChecksWithWrappers/4>::getABarrierNode(indirectionIndex)
indirectionIndex))
or or
// Calculate the guarded UseImpls corresponding to ExprNodes directly. // Calculate the guarded UseImpls corresponding to ExprNodes directly.
exists( exists(
DataFlowIntegrationInput::Guard g, IRGuards::GuardValue branch, Definition def, IRBlock bb DataFlowIntegrationInput::Guard g, IRGuards::GuardValue branch, Definition def, IRBlock bb
| |
guardChecksWithWrappers(g, def, branch, indirectionIndex) and
exists(UseImpl use | exists(UseImpl use |
guardChecksWithWrappers(g, def, branch, ParamIntPair<P>::MkPair(p, indirectionIndex)) and
ssaDefReachesCertainUse(def, use) and ssaDefReachesCertainUse(def, use) and
use.getBlock() = bb and use.getBlock() = bb and
DataFlowIntegrationInput::guardControlsBlock(g, bb, branch) and DataFlowIntegrationInput::guardControlsBlock(g, bb, branch) and
@@ -1298,16 +1089,15 @@ module BarrierGuardWithIntParam<ParamSig P, IntWithParam<P>::guardChecksNodeSig/
} }
} }
module BarrierGuard<ParamSig P, WithParam<P>::guardChecksNodeSig/4 guardChecksNode> { module BarrierGuard<guardChecksNodeSig/3 guardChecksNode> {
private predicate guardChecksNode( private predicate guardChecksNode(
IRGuards::IRGuardCondition g, Node e, boolean gv, int indirectionIndex, P p IRGuards::IRGuardCondition g, Node e, boolean branch, int indirectionIndex
) { ) {
indirectionIndex = 0 and guardChecksNode(g, e, branch) and indirectionIndex = 0
guardChecksNode(g, e, gv, p)
} }
Node getABarrierNode(P p) { Node getABarrierNode() {
result = BarrierGuardWithIntParam<P, guardChecksNode/5>::getABarrierNode(0, p) result = BarrierGuardWithIntParam<guardChecksNode/4>::getABarrierNode(0)
} }
} }
@@ -1362,17 +1152,9 @@ class Definition extends SsaImpl::Definition {
private Definition getAPhiInputOrPriorDefinition() { private Definition getAPhiInputOrPriorDefinition() {
result = this.(PhiNode).getAnInput() result = this.(PhiNode).getAnInput()
or or
uncertainWriteDefinitionInput(this, result) SsaImpl::uncertainWriteDefinitionInput(this, result)
} }
/**
* Holds if this SSA definition is live at the end of basic block `bb`.
* That is, this definition reaches the end of basic block `bb`, at which
* point it is still live, without crossing another SSA definition of the
* same source variable.
*/
predicate isLiveAtEndOfBlock(IRBlock bb) { ssaDefReachesEndOfBlock(bb, this) }
/** /**
* Gets a definition that ultimately defines this SSA definition and is * Gets a definition that ultimately defines this SSA definition and is
* not itself a phi node. * not itself a phi node.

View File

@@ -688,9 +688,15 @@ private module Cached {
conversionFlow(mid, instr, false, _) conversionFlow(mid, instr, false, _)
) )
or or
exists(Operand address | exists(int ind0 |
isDereference(operand.getDef(), address, _) and exists(Operand address |
isUseImpl(address, base, ind - 1) isDereference(operand.getDef(), address, _) and
isUseImpl(address, base, ind0)
)
or
isUseImpl(operand.getDef().(InitializeParameterInstruction).getAnOperand(), base, ind0)
|
ind0 = ind - 1
) )
} }

View File

@@ -104,11 +104,7 @@ newtype TInstructionTag =
} or } or
SizeofVlaDimensionTag(int index) { SizeofVlaDimensionTag(int index) {
exists(VlaDeclStmt v | exists(v.getTransitiveVlaDimensionStmt(index))) exists(VlaDeclStmt v | exists(v.getTransitiveVlaDimensionStmt(index)))
} or }
AssertionVarAddressTag() or
AssertionVarLoadTag() or
AssertionOpTag() or
AssertionBranchTag()
class InstructionTag extends TInstructionTag { class InstructionTag extends TInstructionTag {
final string toString() { result = getInstructionTagId(this) } final string toString() { result = getInstructionTagId(this) }
@@ -300,12 +296,4 @@ string getInstructionTagId(TInstructionTag tag) {
tag = CoAwaitBranchTag() and result = "CoAwaitBranch" tag = CoAwaitBranchTag() and result = "CoAwaitBranch"
or or
tag = BoolToIntConversionTag() and result = "BoolToIntConversion" tag = BoolToIntConversionTag() and result = "BoolToIntConversion"
or
tag = AssertionVarAddressTag() and result = "AssertionVarAddress"
or
tag = AssertionVarLoadTag() and result = "AssertionVarLoad"
or
tag = AssertionOpTag() and result = "AssertionOp"
or
tag = AssertionBranchTag() and result = "AssertionBranch"
} }

View File

@@ -1,387 +0,0 @@
private import cpp
private import semmle.code.cpp.ir.internal.IRUtilities
private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.CppType
private import semmle.code.cpp.ir.internal.TempVariableTag
private import InstructionTag
private import TranslatedElement
private import TranslatedStmt
private import TranslatedFunction
/**
* Holds if `s` is a statement that may be an expanded assertion in a
* release build.
*/
pragma[nomagic]
private predicate stmtCandidate(Stmt s) {
not s.isFromUninstantiatedTemplate(_) and
(
// The expansion of `__analysis_assume(x != 0);` when `__analysis_assume` is
// empty is the empty statement.
s instanceof EmptyStmt
or
// The expansion of `assert(x != 0)` when `assert` is `((void)0)` is a zero literal
// with a void type.
exists(Expr e |
e = s.(ExprStmt).getExpr() and
e.getValue() = "0" and
e.getActualType() instanceof VoidType
)
)
}
pragma[nomagic]
private predicate macroInvocationLocation(int startline, Function f, MacroInvocation mi) {
mi.getMacroName() = ["assert", "__analysis_assume"] and
mi.getNumberOfArguments() = 1 and
mi.getLocation().hasLocationInfo(_, startline, _, _, _) and
f.getEntryPoint().isAffectedByMacro(mi)
}
pragma[nomagic]
private predicate stmtParentLocation(int startline, Function f, StmtParent p) {
p.getEnclosingFunction() = f and
p.getLocation().hasLocationInfo(_, startline, _, _, _)
}
/**
* Holds if `mi` is a macro invocation with a name that is known
* to correspond to an assertion macro, and the macro invocation
* is the only thing on the line.
*/
pragma[nomagic]
private predicate assertion0(MacroInvocation mi, Stmt s, string arg) {
stmtCandidate(s) and
s =
unique(StmtParent p, int startline, Function f |
macroInvocationLocation(startline, f, mi) and
stmtParentLocation(startline, f, p) and
// Also do not count the elements from the expanded macro, i.e., when checking
// if `assert(x)` is the only thing on the line we do not count the
// generated `((void)0)` expression.
not p = mi.getAnExpandedElement()
|
p
) and
arg = mi.getUnexpandedArgument(0)
}
private Function getEnclosingFunctionForMacroInvocation(MacroInvocation mi) {
exists(Stmt s |
assertion0(mi, s, _) and
result = s.getEnclosingFunction()
)
}
/**
* Holds if `arg` has two components and the `i`'th component of the string
* `arg` is `s`, and the components are separated by an operation with
* opcode `opcode`.
*/
bindingset[arg]
pragma[inline_late]
private predicate parseArgument(string arg, string s, int i, Opcode opcode) {
s =
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?<=\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
i + 1) and
opcode instanceof Opcode::CompareLE
or
s =
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?>=\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
i + 1) and
opcode instanceof Opcode::CompareGE
or
s =
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?<\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
i + 1) and
opcode instanceof Opcode::CompareLT
or
s =
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?>\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
i + 1) and
opcode instanceof Opcode::CompareGT
or
s =
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?!=\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
i + 1) and
opcode instanceof Opcode::CompareNE
or
s =
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?==\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
i + 1) and
opcode instanceof Opcode::CompareEQ
}
private Element getAChildScope(Element scope) { result.getParentScope() = scope }
private predicate hasAVariable(MacroInvocation mi, Stmt s, Element scope) {
assertion0(mi, s, _) and
s.getParent() = scope
or
hasAVariable(mi, s, getAChildScope(scope))
}
private LocalScopeVariable getVariable(MacroInvocation mi, int i) {
exists(string operand, string arg, Stmt s |
assertion0(mi, s, arg) and
parseArgument(arg, operand, i, _) and
result =
unique(Variable v |
v.getLocation().getStartLine() < s.getLocation().getStartLine() and
hasAVariable(mi, s, v.getParentScope()) and
v.hasName(operand)
|
v
)
)
}
/**
* Holds if the `i`'th component of the macro invocation `mi` with opcode
* `opcode` is a reference to `var`.
*/
private predicate hasVarAccessMacroArgument(MacroInvocation mi, Variable var, int i, Opcode opcode) {
exists(string arg, string s, Function f |
arg = mi.getUnexpandedArgument(0) and
f = getEnclosingFunctionForMacroInvocation(mi) and
parseArgument(arg, s, i, opcode) and
var = getVariable(mi, i)
)
}
/**
* Holds if the `i`'th component of the macro invocation `mi` with opcode
* `opcode` is a constant with the value `k`.
*/
private predicate hasConstMacroArgument(MacroInvocation mi, int k, int i, Opcode opcode) {
exists(string arg, string s |
assertion0(mi, _, arg) and
s.toInt() = k and
parseArgument(arg, s, i, opcode)
)
}
predicate hasAssertionOperand(MacroInvocation mi, int i) {
hasVarAccessMacroArgument(mi, _, i, _)
or
hasConstMacroArgument(mi, _, i, _)
}
private predicate hasAssertionOpcode(MacroInvocation mi, Opcode opcode) {
hasVarAccessMacroArgument(mi, _, _, opcode)
or
hasConstMacroArgument(mi, _, _, opcode)
}
/**
* Holds if `mi` is a macro invocation that is an assertion that should be generated
* in the control-flow graph at `s`.
*/
predicate assertion(MacroInvocation mi, Stmt s) {
assertion0(mi, s, _) and
hasAssertionOperand(mi, 0) and
hasAssertionOperand(mi, 1)
}
/** The translation of an operand of an assertion. */
abstract private class TranslatedAssertionOperand extends TranslatedElement,
TTranslatedAssertionOperand
{
MacroInvocation mi;
int index;
TranslatedAssertionOperand() { this = TTranslatedAssertionOperand(mi, index) }
MacroInvocation getMacroInvocation() { result = mi }
/**
* Gets the statement that is being replaced by the assertion that uses this
* operand.
*/
Stmt getStmt() { assertion(mi, result) }
final override Locatable getAst() { result = this.getStmt() }
final override TranslatedElement getChild(int id) { none() }
final override Declaration getFunction() { result = this.getStmt().getEnclosingFunction() }
/** Gets the instruction which holds the result of this operand. */
abstract Instruction getResult();
final override string toString() { result = "Operand of assertion: " + mi }
/** Gets the index of this operand (i.e., `0` or `1`). */
final int getIndex() { result = index }
}
/** An operand of an assertion that is a variable access. */
class TranslatedAssertionVarAccess extends TranslatedAssertionOperand {
TranslatedAssertionVarAccess() { hasVarAccessMacroArgument(mi, _, index, _) }
Variable getVariable() { hasVarAccessMacroArgument(mi, result, index, _) }
final override IRUserVariable getInstructionVariable(InstructionTag tag) {
tag = AssertionVarAddressTag() and
result.getVariable() = this.getVariable()
}
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(AssertionVarAddressTag()) and kind instanceof GotoEdge
}
final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
tag = AssertionVarAddressTag() and
kind instanceof GotoEdge and
result = this.getInstruction(AssertionVarLoadTag())
or
tag = AssertionVarLoadTag() and
result = getTranslatedAssertionMacroInvocation(mi).getChildSuccessor(this, kind)
}
final override Instruction getALastInstructionInternal() {
result = this.getInstruction(AssertionVarLoadTag())
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
exists(Variable v | v = this.getVariable() |
opcode instanceof Opcode::VariableAddress and
tag = AssertionVarAddressTag() and
resultType = getTypeForGLValue(v.getType())
or
opcode instanceof Opcode::Load and
tag = AssertionVarLoadTag() and
resultType = getTypeForPRValue(v.getType())
)
}
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
tag = AssertionVarLoadTag() and
operandTag instanceof AddressOperandTag and
result = this.getInstruction(AssertionVarAddressTag())
}
final override Instruction getResult() { result = this.getInstruction(AssertionVarLoadTag()) }
}
/** An operand of an assertion that is a constant access. */
private class TranslatedAssertionConst extends TranslatedAssertionOperand {
TranslatedAssertionConst() { hasConstMacroArgument(mi, _, index, _) }
int getConst() { hasConstMacroArgument(mi, result, index, _) }
final override string getInstructionConstantValue(InstructionTag tag) {
tag = OnlyInstructionTag() and
result = this.getConst().toString()
}
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(OnlyInstructionTag()) and
kind instanceof GotoEdge
}
final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
result = getTranslatedAssertionMacroInvocation(mi).getChildSuccessor(this, kind)
}
final override Instruction getALastInstructionInternal() {
result = this.getInstruction(OnlyInstructionTag())
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
opcode instanceof Opcode::Constant and
tag = OnlyInstructionTag() and
resultType = getIntType()
}
final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) }
}
/**
* Gets the `TranslatedAssertionMacroInvocation` corresponding to the macro
* invocation `mi`.
*/
TranslatedAssertionMacroInvocation getTranslatedAssertionMacroInvocation(MacroInvocation mi) {
result.getMacroInvocation() = mi
}
/**
* A synthesized assertion which would have otherwise been invisible because the
* database represents a release build where assertions are disabled.
*/
private class TranslatedAssertionMacroInvocation extends TranslatedStmt {
MacroInvocation mi;
TranslatedAssertionMacroInvocation() { assertion(mi, stmt) }
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getLeft().getFirstInstruction(kind)
}
TranslatedAssertionOperand getLeft() {
result.getMacroInvocation() = mi and
result.getIndex() = 0
}
TranslatedAssertionOperand getRight() {
result.getMacroInvocation() = mi and
result.getIndex() = 1
}
final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
tag = AssertionOpTag() and
kind instanceof GotoEdge and
result = this.getInstruction(AssertionBranchTag())
or
tag = AssertionBranchTag() and
kind instanceof TrueEdge and
result = this.getParent().getChildSuccessor(this, _)
}
final override TranslatedElement getChildInternal(int id) {
id = 0 and result = this.getLeft()
or
id = 1 and result = this.getRight()
}
final override Instruction getALastInstructionInternal() {
result = this.getInstruction(AssertionBranchTag())
}
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = AssertionOpTag() and
resultType = getBoolType() and
hasAssertionOpcode(mi, opcode)
or
tag = AssertionBranchTag() and
resultType = getVoidType() and
opcode instanceof Opcode::ConditionalBranch
}
final override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
child = this.getLeft() and
result = this.getRight().getFirstInstruction(kind)
or
child = this.getRight() and
kind instanceof GotoEdge and
result = this.getInstruction(AssertionOpTag())
}
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
tag = AssertionOpTag() and
(
operandTag instanceof LeftOperandTag and
result = this.getLeft().getResult()
or
operandTag instanceof RightOperandTag and
result = this.getRight().getResult()
)
or
tag = AssertionBranchTag() and
operandTag instanceof ConditionOperandTag and
result = this.getInstruction(AssertionOpTag())
}
MacroInvocation getMacroInvocation() { result = mi }
}

View File

@@ -12,7 +12,6 @@ private import TranslatedFunction
private import TranslatedStmt private import TranslatedStmt
private import TranslatedExpr private import TranslatedExpr
private import IRConstruction private import IRConstruction
private import TranslatedAssertion
private import semmle.code.cpp.models.interfaces.SideEffect private import semmle.code.cpp.models.interfaces.SideEffect
private import SideEffects private import SideEffects
@@ -139,14 +138,6 @@ private predicate ignoreExprAndDescendants(Expr expr) {
// conditionally constructed (until we have a mechanism for calling these only when the // conditionally constructed (until we have a mechanism for calling these only when the
// temporary's constructor was run) // temporary's constructor was run)
isConditionalTemporaryDestructorCall(expr) isConditionalTemporaryDestructorCall(expr)
or
// An assertion in a release build is often defined as `#define assert(x) ((void)0)`.
// We generate a synthetic assertion in release builds, and when we do that the
// expression `((void)0)` should not be translated.
exists(MacroInvocation mi |
assertion(mi, _) and
expr = mi.getExpr().getFullyConverted()
)
} }
/** /**
@@ -918,8 +909,7 @@ newtype TTranslatedElement =
} or } or
// The side effect that initializes newly-allocated memory. // The side effect that initializes newly-allocated memory.
TTranslatedAllocationSideEffect(AllocationExpr expr) { not ignoreSideEffects(expr) } or TTranslatedAllocationSideEffect(AllocationExpr expr) { not ignoreSideEffects(expr) } or
TTranslatedStaticStorageDurationVarInit(Variable var) { Raw::varHasIRFunc(var) } or TTranslatedStaticStorageDurationVarInit(Variable var) { Raw::varHasIRFunc(var) }
TTranslatedAssertionOperand(MacroInvocation mi, int index) { hasAssertionOperand(mi, index) }
/** /**
* Gets the index of the first explicitly initialized element in `initList` * Gets the index of the first explicitly initialized element in `initList`

View File

@@ -2679,7 +2679,7 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr, St
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
operandTag instanceof UnaryOperandTag and operandTag instanceof UnaryOperandTag and
result = getTranslatedFunction(getEnclosingFunction(expr)).getLoadThisInstruction() result = getTranslatedFunction(getEnclosingFunction(expr)).getInitializeThisInstruction()
} }
final override Field getInstructionField(InstructionTag tag) { final override Field getInstructionField(InstructionTag tag) {

View File

@@ -306,11 +306,11 @@ class TranslatedFunction extends TranslatedRootElement, TTranslatedFunction {
final predicate hasReturnValue() { hasReturnValue(func) } final predicate hasReturnValue() { hasReturnValue(func) }
/** /**
* Gets the first load of `this` for this function. Holds only if the function * Gets the single `InitializeThis` instruction for this function. Holds only
* is an instance member function, constructor, or destructor. * if the function is an instance member function, constructor, or destructor.
*/ */
final Instruction getLoadThisInstruction() { final Instruction getInitializeThisInstruction() {
result = getTranslatedThisParameter(func).getInstruction(InitializerIndirectAddressTag()) result = getTranslatedThisParameter(func).getInstruction(InitializerStoreTag())
} }
/** /**
@@ -639,7 +639,7 @@ class TranslatedConstructorInitList extends TranslatedElement, InitializationCon
} }
override Instruction getTargetAddress() { override Instruction getTargetAddress() {
result = getTranslatedFunction(func).getLoadThisInstruction() result = getTranslatedFunction(func).getInitializeThisInstruction()
} }
override Type getTargetType() { result = getTranslatedFunction(func).getThisType() } override Type getTargetType() { result = getTranslatedFunction(func).getThisType() }

View File

@@ -950,7 +950,7 @@ abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStru
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
operandTag instanceof UnaryOperandTag and operandTag instanceof UnaryOperandTag and
result = getTranslatedFunction(this.getFunction()).getLoadThisInstruction() result = getTranslatedFunction(this.getFunction()).getInitializeThisInstruction()
} }
final override predicate getInstructionInheritance( final override predicate getInstructionInheritance(
@@ -1000,7 +1000,7 @@ class TranslatedConstructorDelegationInit extends TranslatedConstructorCallFromC
} }
final override Instruction getReceiver() { final override Instruction getReceiver() {
result = getTranslatedFunction(this.getFunction()).getLoadThisInstruction() result = getTranslatedFunction(this.getFunction()).getInitializeThisInstruction()
} }
} }

View File

@@ -10,7 +10,6 @@ private import TranslatedElement
private import TranslatedExpr private import TranslatedExpr
private import TranslatedFunction private import TranslatedFunction
private import TranslatedInitialization private import TranslatedInitialization
private import TranslatedAssertion
TranslatedStmt getTranslatedStmt(Stmt stmt) { result.getAst() = stmt } TranslatedStmt getTranslatedStmt(Stmt stmt) { result.getAst() = stmt }
@@ -325,16 +324,8 @@ abstract class TranslatedStmt extends TranslatedElement, TTranslatedStmt {
class TranslatedEmptyStmt extends TranslatedStmt { class TranslatedEmptyStmt extends TranslatedStmt {
TranslatedEmptyStmt() { TranslatedEmptyStmt() {
// An assertion macro invocation can expand to stmt instanceof EmptyStmt or
// an empty statement in release builds. In that case stmt instanceof LabelStmt or
// we synthesize the check that would have occurred.
// This is handled by `TranslatedAssertion.qll` and so
// we exclude these statements here.
not assertion(_, stmt) and
stmt instanceof EmptyStmt
or
stmt instanceof LabelStmt
or
stmt instanceof SwitchCase stmt instanceof SwitchCase
} }
@@ -390,7 +381,7 @@ class TranslatedDeclStmt extends TranslatedStmt {
override TranslatedElement getLastChild() { result = this.getChild(this.getChildCount() - 1) } override TranslatedElement getLastChild() { result = this.getChild(this.getChildCount() - 1) }
private int getChildCount() { result = count(int i | exists(this.getDeclarationEntry(i))) } private int getChildCount() { result = count(this.getDeclarationEntry(_)) }
IRDeclarationEntry getIRDeclarationEntry(int index) { IRDeclarationEntry getIRDeclarationEntry(int index) {
result.hasIndex(index) and result.hasIndex(index) and
@@ -429,15 +420,6 @@ class TranslatedDeclStmt extends TranslatedStmt {
class TranslatedExprStmt extends TranslatedStmt { class TranslatedExprStmt extends TranslatedStmt {
override ExprStmt stmt; override ExprStmt stmt;
TranslatedExprStmt() {
// An assertion macro invocation typically expand to the
// expression `((void)0)` in release builds. In that case
// we synthesize the check that would have occurred.
// This is handled by `TranslatedAssertion.qll` and so
// we exclude these statements here.
not assertion(_, stmt)
}
TranslatedExpr getExpr() { result = getTranslatedExpr(stmt.getExpr().getFullyConverted()) } TranslatedExpr getExpr() { result = getTranslatedExpr(stmt.getExpr().getFullyConverted()) }
override TranslatedElement getChildInternal(int id) { id = 0 and result = this.getExpr() } override TranslatedElement getChildInternal(int id) { id = 0 and result = this.getExpr() }

View File

@@ -57,4 +57,3 @@ private import implementations.CAtlFile
private import implementations.CAtlFileMapping private import implementations.CAtlFileMapping
private import implementations.CAtlTemporaryFile private import implementations.CAtlTemporaryFile
private import implementations.CRegKey private import implementations.CRegKey
private import implementations.WinHttp

View File

@@ -16,3 +16,17 @@ private class MySqlExecutionFunction extends SqlExecutionFunction {
override predicate hasSqlArgument(FunctionInput input) { input.isParameterDeref(1) } override predicate hasSqlArgument(FunctionInput input) { input.isParameterDeref(1) }
} }
/**
* The `mysql_real_escape_string` family of functions from the MySQL C API.
*/
private class MySqlBarrierFunction extends SqlBarrierFunction {
MySqlBarrierFunction() {
this.hasName(["mysql_real_escape_string", "mysql_real_escape_string_quote"])
}
override predicate barrierSqlArgument(FunctionInput input, FunctionOutput output) {
input.isParameterDeref(2) and
output.isParameterDeref(1)
}
}

View File

@@ -1,50 +0,0 @@
private import cpp
private import semmle.code.cpp.ir.dataflow.FlowSteps
private import semmle.code.cpp.dataflow.new.DataFlow
/** The `WINHTTP_HEADER_NAME` class from `winhttp.h`. */
class WinHttpHeaderName extends Class {
WinHttpHeaderName() { this.hasGlobalName("_WINHTTP_HEADER_NAME") }
}
/** The `WINHTTP_EXTENDED_HEADER` class from `winhttp.h`. */
class WinHttpExtendedHeader extends Class {
WinHttpExtendedHeader() { this.hasGlobalName("_WINHTTP_EXTENDED_HEADER") }
}
private class WinHttpHeaderNameInheritingContent extends TaintInheritingContent,
DataFlow::FieldContent
{
WinHttpHeaderNameInheritingContent() {
this.getIndirectionIndex() = 2 and
(
this.getAField().getDeclaringType() instanceof WinHttpHeaderName
or
// The extended header looks like:
// struct WINHTTP_EXTENDED_HEADER {
// union { [...] };
// union { [...] };
// };
// So the first declaring type is the anonymous unions, and the declaring
// type of those anonymous unions is the `WINHTTP_EXTENDED_HEADER` struct.
this.getAField().getDeclaringType().getDeclaringType() instanceof WinHttpExtendedHeader
)
}
}
/** The `URL_COMPONENTS` class from `winhttp.h`. */
class WinHttpUrlComponents extends Class {
WinHttpUrlComponents() { this.hasGlobalName("_WINHTTP_URL_COMPONENTS") }
}
private class WinHttpUrlComponentsInheritingContent extends TaintInheritingContent,
DataFlow::FieldContent
{
WinHttpUrlComponentsInheritingContent() {
exists(Field f | f = this.getField() and f.getDeclaringType() instanceof WinHttpUrlComponents |
if f.getType().getUnspecifiedType() instanceof PointerType
then this.getIndirectionIndex() = 2
else this.getIndirectionIndex() = 1
)
}
}

View File

@@ -404,7 +404,7 @@ predicate cmpWithLinearBound(
* For example, if `t` is a signed 32-bit type then holds if `lb` is * For example, if `t` is a signed 32-bit type then holds if `lb` is
* `-2^31` and `ub` is `2^31 - 1`. * `-2^31` and `ub` is `2^31 - 1`.
*/ */
private predicate typeBounds0(ArithmeticType t, float lb, float ub) { private predicate typeBounds(ArithmeticType t, float lb, float ub) {
exists(IntegralType integralType, float limit | exists(IntegralType integralType, float limit |
integralType = t and limit = 2.pow(8 * integralType.getSize()) integralType = t and limit = 2.pow(8 * integralType.getSize())
| |
@@ -423,42 +423,6 @@ private predicate typeBounds0(ArithmeticType t, float lb, float ub) {
t instanceof FloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0 t instanceof FloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
} }
/**
* Gets the underlying type for an enumeration `e`.
*
* If the enumeration does not have an explicit type we approximate it using
* the following rules:
* - The result type is always `signed`, and
* - if the largest value fits in an `int` the result is `int`. Otherwise, the
* result is `long`.
*/
private IntegralType getUnderlyingTypeForEnum(Enum e) {
result = e.getExplicitUnderlyingType()
or
not e.hasExplicitUnderlyingType() and
result.isSigned() and
exists(IntType intType |
if max(e.getAnEnumConstant().getValue().toFloat()) >= 2.pow(8 * intType.getSize() - 1)
then result instanceof LongType
else result = intType
)
}
/**
* Holds if `lb` and `ub` are the lower and upper bounds of the unspecified
* type `t`.
*
* For example, if `t` is a signed 32-bit type then holds if `lb` is
* `-2^31` and `ub` is `2^31 - 1`.
*
* Unlike `typeBounds0`, this predicate also handles `Enum` types.
*/
private predicate typeBounds(Type t, float lb, float ub) {
typeBounds0(t, lb, ub)
or
typeBounds0(getUnderlyingTypeForEnum(t), lb, ub)
}
private Type stripReference(Type t) { private Type stripReference(Type t) {
if t instanceof ReferenceType then result = t.(ReferenceType).getBaseType() else result = t if t instanceof ReferenceType then result = t.(ReferenceType).getBaseType() else result = t
} }

View File

@@ -158,6 +158,22 @@ private class UnsignedBitwiseAndExpr extends BitwiseAndExpr {
} }
} }
/**
* Gets the floor of `v`, with additional logic to work around issues with
* large numbers.
*/
bindingset[v]
float safeFloor(float v) {
// return the floor of v
v.abs() < 2.pow(31) and
result = v.floor()
or
// `floor()` doesn't work correctly on large numbers (since it returns an integer),
// so fall back to unrounded numbers at this scale.
not v.abs() < 2.pow(31) and
result = v
}
/** A `MulExpr` where exactly one operand is constant. */ /** A `MulExpr` where exactly one operand is constant. */
private class MulByConstantExpr extends MulExpr { private class MulByConstantExpr extends MulExpr {
float constant; float constant;
@@ -512,8 +528,8 @@ private module BoundsEstimate {
*/ */
float getBoundsLimit() { float getBoundsLimit() {
// This limit is arbitrary, but low enough that it prevents timeouts on // This limit is arbitrary, but low enough that it prevents timeouts on
// specific observed customer databases (and in the tests). // specific observed customer databases (and the in the tests).
result = 2.0.pow(29) result = 2.0.pow(40)
} }
/** Gets the maximum number of bounds possible for `t` when widening is used. */ /** Gets the maximum number of bounds possible for `t` when widening is used. */
@@ -1250,7 +1266,7 @@ private float getLowerBoundsImpl(Expr expr) {
rsExpr = expr and rsExpr = expr and
left = getFullyConvertedLowerBounds(rsExpr.getLeftOperand()) and left = getFullyConvertedLowerBounds(rsExpr.getLeftOperand()) and
right = getValue(rsExpr.getRightOperand().getFullyConverted()).toInt() and right = getValue(rsExpr.getRightOperand().getFullyConverted()).toInt() and
result = (left / 2.pow(right)).floorFloat() result = safeFloor(left / 2.pow(right))
) )
// Not explicitly modeled by a SimpleRangeAnalysisExpr // Not explicitly modeled by a SimpleRangeAnalysisExpr
) and ) and
@@ -1459,7 +1475,7 @@ private float getUpperBoundsImpl(Expr expr) {
rsExpr = expr and rsExpr = expr and
left = getFullyConvertedUpperBounds(rsExpr.getLeftOperand()) and left = getFullyConvertedUpperBounds(rsExpr.getLeftOperand()) and
right = getValue(rsExpr.getRightOperand().getFullyConverted()).toInt() and right = getValue(rsExpr.getRightOperand().getFullyConverted()).toInt() and
result = (left / 2.pow(right)).floorFloat() result = safeFloor(left / 2.pow(right))
) )
// Not explicitly modeled by a SimpleRangeAnalysisExpr // Not explicitly modeled by a SimpleRangeAnalysisExpr
) and ) and
@@ -1709,22 +1725,6 @@ predicate nonNanGuardedVariable(Expr guard, VariableAccess v, boolean branch) {
nanExcludingComparison(guard, branch) nanExcludingComparison(guard, branch)
} }
/**
* Adjusts a lower bound to its meaning for integral types.
*
* Examples:
* `>= 3.0` becomes `3.0`
* ` > 3.0` becomes `4.0`
* `>= 3.5` becomes `4.0`
* ` > 3.5` becomes `4.0`
*/
bindingset[strictness, lb]
private float adjustLowerBoundIntegral(RelationStrictness strictness, float lb) {
if strictness = Nonstrict() and lb.floorFloat() = lb
then result = lb
else result = lb.floorFloat() + 1
}
/** /**
* If the guard is a comparison of the form `p*v + q <CMP> r`, then this * If the guard is a comparison of the form `p*v + q <CMP> r`, then this
* predicate uses the bounds information for `r` to compute a lower bound * predicate uses the bounds information for `r` to compute a lower bound
@@ -1736,29 +1736,15 @@ private predicate lowerBoundFromGuard(Expr guard, VariableAccess v, float lb, bo
| |
if nonNanGuardedVariable(guard, v, branch) if nonNanGuardedVariable(guard, v, branch)
then then
if getVariableRangeType(v.getTarget()) instanceof IntegralType if
then lb = adjustLowerBoundIntegral(strictness, childLB) strictness = Nonstrict() or
else lb = childLB not getVariableRangeType(v.getTarget()) instanceof IntegralType
then lb = childLB
else lb = childLB + 1
else lb = varMinVal(v.getTarget()) else lb = varMinVal(v.getTarget())
) )
} }
/**
* Adjusts an upper bound to its meaning for integral types.
*
* Examples:
* `<= 3.0` becomes `3.0`
* ` < 3.0` becomes `2.0`
* `<= 3.5` becomes `3.0`
* ` < 3.5` becomes `3.0`
*/
bindingset[strictness, ub]
private float adjustUpperBoundIntegral(RelationStrictness strictness, float ub) {
if strictness = Nonstrict() and ub.ceilFloat() = ub
then result = ub
else result = ub.ceilFloat() - 1
}
/** /**
* If the guard is a comparison of the form `p*v + q <CMP> r`, then this * If the guard is a comparison of the form `p*v + q <CMP> r`, then this
* predicate uses the bounds information for `r` to compute a upper bound * predicate uses the bounds information for `r` to compute a upper bound
@@ -1770,9 +1756,11 @@ private predicate upperBoundFromGuard(Expr guard, VariableAccess v, float ub, bo
| |
if nonNanGuardedVariable(guard, v, branch) if nonNanGuardedVariable(guard, v, branch)
then then
if getVariableRangeType(v.getTarget()) instanceof IntegralType if
then ub = adjustUpperBoundIntegral(strictness, childUB) strictness = Nonstrict() or
else ub = childUB not getVariableRangeType(v.getTarget()) instanceof IntegralType
then ub = childUB
else ub = childUB - 1
else ub = varMaxVal(v.getTarget()) else ub = varMaxVal(v.getTarget())
) )
} }

View File

@@ -20,7 +20,7 @@ class Stmt extends StmtParent, @stmt {
predicate hasChild(Element e, int n) { this.getChild(n) = e } predicate hasChild(Element e, int n) { this.getChild(n) = e }
/** Gets the enclosing function of this statement, if any. */ /** Gets the enclosing function of this statement, if any. */
override Function getEnclosingFunction() { result = stmtEnclosingElement(this) } Function getEnclosingFunction() { result = stmtEnclosingElement(this) }
/** /**
* Gets the nearest enclosing block of this statement in the source, if any. * Gets the nearest enclosing block of this statement in the source, if any.
@@ -159,10 +159,7 @@ private class TStmtParent = @stmt or @expr;
* *
* This is normally a statement, but may be a `StmtExpr`. * This is normally a statement, but may be a `StmtExpr`.
*/ */
class StmtParent extends ControlFlowNode, TStmtParent { class StmtParent extends ControlFlowNode, TStmtParent { }
/** Gets the enclosing function of this element, if any. */
Function getEnclosingFunction() { none() }
}
/** /**
* A C/C++ 'expression' statement. * A C/C++ 'expression' statement.

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