Compare commits

..

3 Commits

Author SHA1 Message Date
Henry Mercer
4d84f99867 Add testing trigger 2024-09-03 14:06:26 +01:00
Henry Mercer
729b9cc0f5 Run ruby build using older nightly 2024-09-03 14:06:09 +01:00
Henry Mercer
386bea0aaa Update fetch-codeql Action to allow specifying a version 2024-09-03 14:05:21 +01:00
5766 changed files with 121718 additions and 248535 deletions

View File

@@ -25,6 +25,5 @@ common --registry=https://bcr.bazel.build
common --@rules_dotnet//dotnet/settings:strict_deps=false
common --experimental_isolated_extension_usages
common --incompatible_use_plus_in_repo_names
try-import %workspace%/local.bazelrc

View File

@@ -6,6 +6,9 @@ inputs:
description: 'The CodeQL channel to use'
required: false
default: 'nightly'
tag_name:
description: 'The tag name of the CodeQL release to use. Leave blank to use the latest release.'
required: false
runs:
using: composite
@@ -15,9 +18,13 @@ runs:
env:
GITHUB_TOKEN: ${{ github.token }}
CHANNEL: ${{ inputs.channel }}
VERSION: ${{ inputs.version }}
run: |
gh extension install github/gh-codeql
gh codeql set-channel "$CHANNEL"
if [[ -n "$VERSION" ]]; then
gh codeql set-version "$VERSION"
fi
gh codeql version
printf "CODEQL_FETCHED_CODEQL_PATH=" >> "${GITHUB_ENV}"
gh codeql version --format=json | jq -r .unpackedLocation >> "${GITHUB_ENV}"

4
.github/labeler.yml vendored
View File

@@ -30,10 +30,6 @@ Ruby:
- ruby/**/*
- change-notes/**/*ruby*
Rust:
- rust/**/*
- change-notes/**/*rust*
Swift:
- swift/**/*
- change-notes/**/*swift*

View File

@@ -1,14 +0,0 @@
### Pull Request checklist
#### All query authors
- [ ] A change note is added if necessary. See [the documentation](https://github.com/github/codeql/blob/main/docs/change-notes.md) in this repository.
- [ ] All new queries have appropriate `.qhelp`. See [the documentation](https://github.com/github/codeql/blob/main/docs/query-help-style-guide.md) in this repository.
- [ ] QL tests are added if necessary. See [Testing custom queries](https://docs.github.com/en/code-security/codeql-cli/using-the-advanced-functionality-of-the-codeql-cli/testing-custom-queries) in the GitHub documentation.
- [ ] New and changed queries have correct query metadata. See [the documentation](https://github.com/github/codeql/blob/main/docs/query-metadata-style-guide.md) in this repository.
#### Internal query authors only
- [ ] Autofixes generated based on these changes are valid, only needed if this PR makes significant changes to `.ql`, `.qll`, or `.qhelp` files. See [the documentation](https://github.com/github/codeql-team/blob/main/docs/best-practices/validating-autofix-for-query-changes.md) (internal access required).
- [ ] Changes are validated [at scale](https://github.com/github/codeql-dca/) (internal access required).
- [ ] Adding a new query? Consider also [adding the query to autofix](https://github.com/github/codeml-autofix/blob/main/docs/updating-query-support.md#adding-a-new-query-to-the-query-suite).

View File

@@ -16,12 +16,11 @@ on:
- "shared/**/*.qll"
- "!**/experimental/**"
- "!ql/**"
- "!rust/**"
- ".github/workflows/check-change-note.yml"
jobs:
check-change-note:
env:
env:
REPO: ${{ github.repository }}
PULL_REQUEST_NUMBER: ${{ github.event.number }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -34,7 +33,7 @@ jobs:
!contains(github.event.pull_request.labels.*.name, 'no-change-note-required')
run: |
change_note_files=$(gh api "repos/$REPO/pulls/$PULL_REQUEST_NUMBER/files" --paginate --jq '.[].filename | select(test("/change-notes/.*[.]md$"))')
if [ -z "$change_note_files" ]; then
echo "No change note found. Either add one, or add the 'no-change-note-required' label."
exit 1

View File

@@ -29,6 +29,45 @@ permissions:
contents: read
jobs:
qlupgrade:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/fetch-codeql
- name: Check DB upgrade scripts
run: |
echo >empty.trap
codeql dataset import -S ql/lib/upgrades/initial/semmlecode.csharp.dbscheme testdb empty.trap
codeql dataset upgrade testdb --additional-packs ql/lib
diff -q testdb/semmlecode.csharp.dbscheme ql/lib/semmlecode.csharp.dbscheme
- name: Check DB downgrade scripts
run: |
echo >empty.trap
rm -rf testdb; codeql dataset import -S ql/lib/semmlecode.csharp.dbscheme testdb empty.trap
codeql resolve upgrades --format=lines --allow-downgrades --additional-packs downgrades \
--dbscheme=ql/lib/semmlecode.csharp.dbscheme --target-dbscheme=downgrades/initial/semmlecode.csharp.dbscheme |
xargs codeql execute upgrades testdb
diff -q testdb/semmlecode.csharp.dbscheme downgrades/initial/semmlecode.csharp.dbscheme
qltest:
if: github.repository_owner == 'github'
runs-on: ubuntu-latest-xl
strategy:
fail-fast: false
matrix:
slice: ["1/2", "2/2"]
steps:
- uses: actions/checkout@v4
- uses: ./csharp/actions/create-extractor-pack
- name: Cache compilation cache
id: query-cache
uses: ./.github/actions/cache-query-compilation
with:
key: csharp-qltest-${{ matrix.slice }}
- name: Run QL tests
run: |
codeql test run --threads=0 --ram 50000 --slice ${{ matrix.slice }} --search-path "${{ github.workspace }}" --check-databases --check-undefined-labels --check-repeated-labels --check-redefined-labels --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
env:
GITHUB_TOKEN: ${{ github.token }}
unit-tests:
strategy:
matrix:

View File

@@ -3,7 +3,6 @@ on:
push:
paths:
- "go/**"
- "shared/**"
- .github/workflows/go-tests.yml
- .github/actions/**
- codeql-workspace.yml
@@ -13,7 +12,6 @@ on:
pull_request:
paths:
- "go/**"
- "shared/**"
- .github/workflows/go-tests.yml
- .github/actions/**
- codeql-workspace.yml

View File

@@ -2,30 +2,6 @@ name: "Ruby: Build"
on:
push:
paths:
- "ruby/**"
- .github/workflows/ruby-build.yml
- .github/actions/fetch-codeql/action.yml
- codeql-workspace.yml
- "shared/tree-sitter-extractor/**"
branches:
- main
- "rc/*"
pull_request:
paths:
- "ruby/**"
- .github/workflows/ruby-build.yml
- .github/actions/fetch-codeql/action.yml
- codeql-workspace.yml
- "shared/tree-sitter-extractor/**"
branches:
- main
- "rc/*"
workflow_dispatch:
inputs:
tag:
description: "Version tag to create"
required: false
env:
CARGO_TERM_COLOR: always
@@ -65,8 +41,8 @@ jobs:
id: cache-extractor
with:
path: |
target/release/codeql-extractor-ruby
target/release/codeql-extractor-ruby.exe
ruby/extractor/target/release/codeql-extractor-ruby
ruby/extractor/target/release/codeql-extractor-ruby.exe
ruby/extractor/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/Cargo.lock') }}-${{ hashFiles('shared/tree-sitter-extractor') }}-${{ hashFiles('ruby/extractor/**/*.rs') }}
- uses: actions/cache@v3
@@ -75,7 +51,7 @@ jobs:
path: |
~/.cargo/registry
~/.cargo/git
target
ruby/target
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-rust-cargo-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/**/Cargo.lock') }}
- name: Check formatting
if: steps.cache-extractor.outputs.cache-hit != 'true'
@@ -91,7 +67,7 @@ jobs:
run: cd extractor && cargo build --release
- name: Generate dbscheme
if: ${{ matrix.os == 'ubuntu-latest' && steps.cache-extractor.outputs.cache-hit != 'true'}}
run: ../target/release/codeql-extractor-ruby generate --dbscheme ql/lib/ruby.dbscheme --library ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
run: extractor/target/release/codeql-extractor-ruby generate --dbscheme ql/lib/ruby.dbscheme --library ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
- uses: actions/upload-artifact@v3
if: ${{ matrix.os == 'ubuntu-latest' }}
with:
@@ -106,8 +82,8 @@ jobs:
with:
name: extractor-${{ matrix.os }}
path: |
target/release/codeql-extractor-ruby
target/release/codeql-extractor-ruby.exe
ruby/extractor/target/release/codeql-extractor-ruby
ruby/extractor/target/release/codeql-extractor-ruby.exe
retention-days: 1
compile-queries:
if: github.repository_owner == 'github'
@@ -116,6 +92,8 @@ jobs:
- uses: actions/checkout@v4
- name: Fetch CodeQL
uses: ./.github/actions/fetch-codeql
with:
version: codeql-bundle-20240902
- name: Cache compilation cache
id: query-cache
uses: ./.github/actions/cache-query-compilation
@@ -140,7 +118,6 @@ jobs:
path: |
${{ runner.temp }}/query-packs/*
retention-days: 1
include-hidden-files: true
package:
runs-on: ubuntu-latest
@@ -177,7 +154,6 @@ jobs:
name: codeql-ruby-pack
path: ruby/codeql-ruby.zip
retention-days: 1
include-hidden-files: true
- uses: actions/download-artifact@v3
with:
name: codeql-ruby-queries
@@ -195,7 +171,6 @@ jobs:
name: codeql-ruby-bundle
path: ruby/codeql-ruby-bundle.zip
retention-days: 1
include-hidden-files: true
test:
defaults:
@@ -212,6 +187,8 @@ jobs:
- uses: actions/checkout@v4
- name: Fetch CodeQL
uses: ./.github/actions/fetch-codeql
with:
version: codeql-bundle-20240902
- name: Download Ruby bundle
uses: actions/download-artifact@v3

View File

@@ -1,58 +0,0 @@
name: "Rust"
on:
pull_request:
paths:
- "rust/**"
- "misc/bazel/**"
- "misc/codegen/**"
- "shared/**"
- "MODULE.bazel"
- .github/workflows/rust.yml
- .github/actions/**
- codeql-workspace.yml
- "!**/*.md"
- "!**/*.qhelp"
branches:
- rust-experiment
- main
- rc/*
- codeql-cli-*
permissions:
contents: read
jobs:
rust-code:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Format
working-directory: rust/extractor
shell: bash
run: |
cargo fmt --check
- name: Compilation
working-directory: rust/extractor
shell: bash
run: cargo check
- name: Clippy
working-directory: rust/extractor
shell: bash
run: |
cargo clippy --fix
git diff --exit-code
rust-codegen:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install CodeQL
uses: ./.github/actions/fetch-codeql
- name: Code generation
shell: bash
run: |
bazel run //rust/codegen
git add .
git diff --exit-code HEAD

6
.gitignore vendored
View File

@@ -65,9 +65,3 @@ node_modules/
# bazel-built in-tree extractor packs
/*/extractor-pack
# Jetbrains IDE files
.idea
# cargo build directory
/target

View File

@@ -5,9 +5,9 @@ repos:
rev: v3.2.0
hooks:
- id: trailing-whitespace
exclude: /test/.*$(?<!\.qlref)|.*\.patch$|.*\.qll?$
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)|.*\.patch
- id: end-of-file-fixer
exclude: /test/.*$(?<!\.qlref)|.*\.patch$|.*\.qll?$
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)|.*\.patch
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v17.0.6
@@ -15,7 +15,7 @@ repos:
- id: clang-format
- repo: https://github.com/pre-commit/mirrors-autopep8
rev: v2.0.4
rev: v1.6.0
hooks:
- id: autopep8
files: ^misc/codegen/.*\.py
@@ -45,7 +45,7 @@ repos:
- id: sync-files
name: Fix files required to be identical
files: \.(qll?|qhelp|swift|toml)$|^config/identical-files\.json$
files: \.(qll?|qhelp|swift)$|^config/identical-files\.json$
language: system
entry: python3 config/sync-files.py --latest
pass_filenames: false
@@ -58,7 +58,7 @@ repos:
- id: swift-codegen
name: Run Swift checked in code generation
files: ^misc/codegen/|^swift/(schema.py$|codegen/|.*/generated/|ql/lib/(swift\.dbscheme$|codeql/swift/elements)|ql/\.generated.list)
files: ^swift/(schema.py$|codegen/|.*/generated/|ql/lib/(swift\.dbscheme$|codeql/swift/elements)|ql/\.generated.list)
language: system
entry: bazel run //swift/codegen -- --quiet
pass_filenames: false
@@ -69,17 +69,3 @@ repos:
language: system
entry: bazel test //misc/codegen/test
pass_filenames: false
- id: rust-codegen
name: Run Rust checked in code generation
files: ^misc/codegen/|^rust/(schema.py$|codegen/|.*/generated/|ql/lib/(rust\.dbscheme$|codeql/rust/elements)|\.generated.list)
language: system
entry: bazel run //rust/codegen -- --quiet
pass_filenames: false
- id: rust-lint
name: Run fmt and clippy on Rust code
files: ^rust/extractor/(.*rs|Cargo.toml)$
language: system
entry: python3 rust/lint.py
pass_filenames: false

2684
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +0,0 @@
# This is the shared workspace file for extractor using shared/tree-sitter/extractor
[workspace]
resolver = "2"
members = [
"shared/tree-sitter-extractor",
"ruby/extractor",
"rust/extractor",
"rust/extractor/macros",
"rust/ast-generator",
]
[patch.crates-io]
# patch for build script bug preventing bazel build
# see https://github.com/rust-lang/rustc_apfloat/pull/17
rustc_apfloat = { git = "https://github.com/redsun82/rustc_apfloat.git", rev = "096d585100636bc2e9f09d7eefec38c5b334d47b" }

View File

@@ -15,10 +15,10 @@ local_path_override(
# see https://registry.bazel.build/ for a list of available packages
bazel_dep(name = "platforms", version = "0.0.10")
bazel_dep(name = "rules_go", version = "0.50.0")
bazel_dep(name = "rules_pkg", version = "1.0.1")
bazel_dep(name = "rules_go", version = "0.49.0")
bazel_dep(name = "rules_pkg", version = "0.10.1")
bazel_dep(name = "rules_nodejs", version = "6.2.0-codeql.1")
bazel_dep(name = "rules_python", version = "0.35.0")
bazel_dep(name = "rules_python", version = "0.32.2")
bazel_dep(name = "bazel_skylib", version = "1.6.1")
bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl")
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
@@ -27,7 +27,7 @@ bazel_dep(name = "rules_kotlin", version = "1.9.4-codeql.1")
bazel_dep(name = "gazelle", version = "0.38.0")
bazel_dep(name = "rules_dotnet", version = "0.15.1")
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
bazel_dep(name = "rules_rust", version = "0.52.2")
bazel_dep(name = "rules_rust", version = "0.49.1")
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
@@ -47,25 +47,21 @@ cp.from_cargo(
)
use_repo(cp, "py_deps")
# deps for ruby+rust, but shortened due to windows file paths
# crate_ruby, but shortened due to windows file paths
r = use_extension(
"@rules_rust//crate_universe:extension.bzl",
"crate",
isolate = True,
)
r.from_cargo(
name = "r",
cargo_lockfile = "//:Cargo.lock",
name = "rd",
cargo_lockfile = "//ruby/extractor:Cargo.lock",
manifests = [
"//:Cargo.toml",
"//ruby/extractor:Cargo.toml",
"//rust/extractor:Cargo.toml",
"//rust/extractor/macros:Cargo.toml",
"//rust/ast-generator:Cargo.toml",
"//shared/tree-sitter-extractor:Cargo.toml",
"//ruby/extractor/codeql-extractor-fake-crate:Cargo.toml",
],
)
use_repo(r, tree_sitter_extractors_deps = "r")
use_repo(r, ruby_deps = "rd")
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
dotnet.toolchain(dotnet_version = "8.0.101")
@@ -128,7 +124,6 @@ use_repo(
"kotlin-compiler-1.9.20-Beta",
"kotlin-compiler-2.0.0-RC1",
"kotlin-compiler-2.0.20-Beta2",
"kotlin-compiler-2.1.0-Beta1",
"kotlin-compiler-embeddable-1.5.0",
"kotlin-compiler-embeddable-1.5.10",
"kotlin-compiler-embeddable-1.5.20",
@@ -142,7 +137,6 @@ use_repo(
"kotlin-compiler-embeddable-1.9.20-Beta",
"kotlin-compiler-embeddable-2.0.0-RC1",
"kotlin-compiler-embeddable-2.0.20-Beta2",
"kotlin-compiler-embeddable-2.1.0-Beta1",
"kotlin-stdlib-1.5.0",
"kotlin-stdlib-1.5.10",
"kotlin-stdlib-1.5.20",
@@ -156,11 +150,10 @@ use_repo(
"kotlin-stdlib-1.9.20-Beta",
"kotlin-stdlib-2.0.0-RC1",
"kotlin-stdlib-2.0.20-Beta2",
"kotlin-stdlib-2.1.0-Beta1",
)
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
go_sdk.download(version = "1.23.1")
go_sdk.download(version = "1.22.2")
go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
go_deps.from_file(go_mod = "//go/extractor:go.mod")

View File

@@ -57,6 +57,10 @@
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
],
"Model as Data Generation Java/C# - CaptureModels": [
"java/ql/src/utils/modelgenerator/internal/CaptureModels.qll",
"csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll"
],
"Sign Java/C#": [
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll"
@@ -352,8 +356,8 @@
"python/ql/test/library-tests/dataflow/model-summaries/InlineTaintTest.ext.yml",
"python/ql/test/library-tests/dataflow/model-summaries/NormalDataflowTest.ext.yml"
],
"Diagnostics.qll": [
"ruby/ql/lib/codeql/ruby/Diagnostics.qll",
"rust/ql/lib/codeql/rust/Diagnostics.qll"
"shared tree-sitter extractor cargo.toml": [
"shared/tree-sitter-extractor/Cargo.toml",
"ruby/extractor/codeql-extractor-fake-crate/Cargo.toml"
]
}

View File

@@ -1,32 +0,0 @@
/*
* Approach: replace conversion expressions of kind 389 (= @c11_generic) by
* conversion expressions of kind 12 (= @parexpr), i.e., a `ParenthesisExpr`,
* and drop the relation which its child expressions, which are just syntactic
* sugar. Parenthesis expressions are equally benign as C11 _Generic expressions,
* and behave similarly in the context of the IR.
*/
class Expr extends @expr {
string toString() { none() }
}
class Location extends @location {
string toString() { none() }
}
class ExprParent extends @exprparent {
string toString() { none() }
}
query predicate new_exprs(Expr expr, int new_kind, Location loc) {
exists(int kind | exprs(expr, kind, loc) | if kind = 389 then new_kind = 12 else new_kind = kind)
}
query predicate new_exprparents(Expr expr, int index, ExprParent expr_parent) {
exprparents(expr, index, expr_parent) and
(
not expr_parent instanceof @expr
or
exists(int kind | exprs(expr_parent.(Expr), kind, _) | kind != 389)
)
}

View File

@@ -1,4 +0,0 @@
description: Expose C11 _Generics
compatibility: partial
exprs.rel: run downgrades.ql new_exprs
exprparents.rel: run downgrades.ql new_exprparents

View File

@@ -1,15 +0,0 @@
class Expr extends @expr {
string toString() { none() }
}
class Location extends @location_expr {
string toString() { none() }
}
predicate isExprRequires(Expr expr) { exists(int kind | exprs(expr, kind, _) | kind = 390) }
from Expr expr, int kind, int kind_new, Location location
where
exprs(expr, kind, location) and
if isExprRequires(expr) then kind_new = 1 else kind_new = kind
select expr, kind_new, location

View File

@@ -1,3 +0,0 @@
description: Add requires expr
compatibility: partial
exprs.rel: run exprs.qlo

View File

@@ -1,18 +0,0 @@
class Function extends @function {
string toString() { none() }
}
class Type extends @type {
string toString() { none() }
}
class Variable extends @variable {
string toString() { none() }
}
from Function func, Type traits, Variable handle, Variable promise
where
coroutine(func, traits) and
coroutine_placeholder_variable(handle, 1, func) and
coroutine_placeholder_variable(promise, 2, func)
select func, traits, handle, promise

View File

@@ -1,4 +0,0 @@
description: Improve handling of coroutine placeholder variables
compatibility: full
coroutine.rel: run coroutine.qlo
coroutine_placeholder_variable.rel: delete

View File

@@ -1,35 +1,3 @@
## 2.0.1
No user-facing changes.
## 2.0.0
### Breaking Changes
* Deleted many deprecated taint-tracking configurations based on `TaintTracking::Configuration`.
* Deleted many deprecated dataflow configurations based on `DataFlow::Configuration`.
* Deleted the deprecated `hasQualifiedName` and `isDefined` predicates from the `Declaration` class, use `hasGlobalName` and `hasDefinition` respectively instead.
* Deleted the `getFullSignature` predicate from the `Function` class, use `getIdentityString(Declaration)` from `semmle.code.cpp.Print` instead.
* Deleted the deprecated `freeCall` predicate from `Alloc.qll`. Use `DeallocationExpr` instead.
* Deleted the deprecated `explorationLimit` predicate from `DataFlow::Configuration`, use `FlowExploration<explorationLimit>` instead.
* Deleted the deprecated `getFieldExpr` predicate from `ClassAggregateLiteral`, use `getAFieldExpr` instead.
* Deleted the deprecated `getElementExpr` predicate from `ArrayOrVectorAggregateLiteral`, use `getAnElementExpr` instead.
### New Features
* Added a class `C11GenericExpr` to represent C11 generic selection expressions. The generic selection is represented as a `Conversion` on the expression that will be selected.
* Added subclasses of `BuiltInOperations` for the `__is_scoped_enum`, `__is_trivially_equality_comparable`, and `__is_trivially_relocatable` builtin operations.
* Added a subclass of `Expr` for `__datasizeof` expressions.
### Minor Analysis Improvements
* Added a data flow model for `swap` member functions, which were previously modeled as taint tracking functions. This change improves the precision of queries where flow through `swap` member functions might affect the results.
* Added a data flow model for `realloc`-like functions, which were previously modeled as a taint tracking functions. This change improves the precision of queries where flow through `realloc`-like functions might affect the results.
## 1.4.2
No user-facing changes.
## 1.4.1
No user-facing changes.

View File

@@ -0,0 +1,5 @@
---
category: feature
---
* Added subclasses of `BuiltInOperations` for the `__is_scoped_enum`, `__is_trivially_equality_comparable`, and `__is_trivially_relocatable` builtin operations.
* Added a subclass of `Expr` for `__datasizeof` expressions.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The `SimpleRangeAnalysis` library (`semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis`) now generates more precise ranges for calls to `fgetc` and `getc`.

View File

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

View File

@@ -1,23 +0,0 @@
## 2.0.0
### Breaking Changes
* Deleted many deprecated taint-tracking configurations based on `TaintTracking::Configuration`.
* Deleted many deprecated dataflow configurations based on `DataFlow::Configuration`.
* Deleted the deprecated `hasQualifiedName` and `isDefined` predicates from the `Declaration` class, use `hasGlobalName` and `hasDefinition` respectively instead.
* Deleted the `getFullSignature` predicate from the `Function` class, use `getIdentityString(Declaration)` from `semmle.code.cpp.Print` instead.
* Deleted the deprecated `freeCall` predicate from `Alloc.qll`. Use `DeallocationExpr` instead.
* Deleted the deprecated `explorationLimit` predicate from `DataFlow::Configuration`, use `FlowExploration<explorationLimit>` instead.
* Deleted the deprecated `getFieldExpr` predicate from `ClassAggregateLiteral`, use `getAFieldExpr` instead.
* Deleted the deprecated `getElementExpr` predicate from `ArrayOrVectorAggregateLiteral`, use `getAnElementExpr` instead.
### New Features
* Added a class `C11GenericExpr` to represent C11 generic selection expressions. The generic selection is represented as a `Conversion` on the expression that will be selected.
* Added subclasses of `BuiltInOperations` for the `__is_scoped_enum`, `__is_trivially_equality_comparable`, and `__is_trivially_relocatable` builtin operations.
* Added a subclass of `Expr` for `__datasizeof` expressions.
### Minor Analysis Improvements
* Added a data flow model for `swap` member functions, which were previously modeled as taint tracking functions. This change improves the precision of queries where flow through `swap` member functions might affect the results.
* Added a data flow model for `realloc`-like functions, which were previously modeled as a taint tracking functions. This change improves the precision of queries where flow through `realloc`-like functions might affect the results.

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 2.0.1
lastReleaseVersion: 1.4.1

View File

@@ -17,7 +17,6 @@ import semmle.code.cpp.File
import semmle.code.cpp.Linkage
import semmle.code.cpp.Location
import semmle.code.cpp.Compilation
import semmle.code.cpp.Concept
import semmle.code.cpp.Element
import semmle.code.cpp.Namespace
import semmle.code.cpp.Specifier

View File

@@ -36,6 +36,16 @@ module PrivateCleartextWrite {
}
}
deprecated class WriteConfig extends TaintTracking::Configuration {
WriteConfig() { this = "Write configuration" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
}
private module WriteConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof Source }

View File

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

View File

@@ -1,14 +0,0 @@
/**
* Provides classes for working with C++ concepts.
*/
import semmle.code.cpp.exprs.Expr
/**
* A C++ requires expression.
*/
class RequiresExpr extends Expr, @requires_expr {
override string toString() { result = "requires ..." }
override string getAPrimaryQlClass() { result = "RequiresExpr" }
}

View File

@@ -60,6 +60,18 @@ class Declaration extends Locatable, @declaration {
*/
string getQualifiedName() { result = underlyingElement(this).(Q::Declaration).getQualifiedName() }
/**
* DEPRECATED: Prefer `hasGlobalName` or the 2-argument or 3-argument
* `hasQualifiedName` predicates. To get the exact same results as this
* predicate in all edge cases, use `getQualifiedName()`.
*
* Holds if this declaration has the fully-qualified name `qualifiedName`.
* See `getQualifiedName`.
*/
deprecated predicate hasQualifiedName(string qualifiedName) {
this.getQualifiedName() = qualifiedName
}
/**
* Holds if this declaration has a fully-qualified name with a name-space
* component of `namespaceQualifier`, a declaring type of `typeQualifier`,
@@ -173,6 +185,9 @@ class Declaration extends Locatable, @declaration {
/** Holds if the declaration has a definition. */
predicate hasDefinition() { exists(this.getDefinition()) }
/** DEPRECATED: Use `hasDefinition` instead. */
deprecated predicate isDefined() { this.hasDefinition() }
/** Gets the preferred location of this declaration, if any. */
override Location getLocation() { none() }

View File

@@ -30,6 +30,46 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
override string getName() { functions(underlyingElement(this), result, _) }
/**
* DEPRECATED: Use `getIdentityString(Declaration)` from `semmle.code.cpp.Print` instead.
* Gets the full signature of this function, including return type, parameter
* types, and template arguments.
*
* For example, in the following code:
* ```
* template<typename T> T min(T x, T y);
* int z = min(5, 7);
* ```
* The full signature of the function called on the last line would be
* `min<int>(int, int) -> int`, and the full signature of the uninstantiated
* template on the first line would be `min<T>(T, T) -> T`.
*/
deprecated string getFullSignature() {
exists(string name, string templateArgs, string args |
result = name + templateArgs + args + " -> " + this.getType().toString() and
name = this.getQualifiedName() and
(
if exists(this.getATemplateArgument())
then
templateArgs =
"<" +
concat(int i |
exists(this.getTemplateArgument(i))
|
this.getTemplateArgument(i).toString(), ", " order by i
) + ">"
else templateArgs = ""
) and
args =
"(" +
concat(int i |
exists(this.getParameter(i))
|
this.getParameter(i).getType().toString(), ", " order by i
) + ")"
)
}
/** Gets a specifier of this function. */
override Specifier getASpecifier() {
funspecifiers(underlyingElement(this), unresolveElement(result)) or
@@ -500,17 +540,6 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
* Gets the nearest enclosing AccessHolder.
*/
override AccessHolder getEnclosingAccessHolder() { result = this.getDeclaringType() }
/**
* Holds if this function has extraction errors that create an `ErrorExpr`.
*/
predicate hasErrors() {
exists(ErrorExpr e |
e.getEnclosingFunction() = this and
// Exclude the first allocator call argument because it is always extracted as `ErrorExpr`.
not exists(NewOrNewArrayExpr new | e = new.getAllocatorCall().getArgument(0))
)
}
}
pragma[noinline]
@@ -662,8 +691,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
/**
* Holds if this declaration is an implicit function declaration, that is,
* where a function is used before it is declared (under older C standards,
* or when there were parse errors).
* where a function is used before it is declared (under older C standards).
*/
predicate isImplicit() { fun_implicit(underlyingElement(this)) }

View File

@@ -286,6 +286,9 @@ abstract class BaseAstNode extends PrintAstNode {
* Gets the AST represented by this node.
*/
final Locatable getAst() { result = ast }
/** DEPRECATED: Alias for getAst */
deprecated Locatable getAST() { result = this.getAst() }
}
/**
@@ -382,21 +385,6 @@ class CastNode extends ConversionNode {
}
}
/**
* A node representing a `C11GenericExpr`.
*/
class C11GenericNode extends ConversionNode {
C11GenericExpr generic;
C11GenericNode() { generic = conv }
override AstNode getChildInternal(int childIndex) {
result = super.getChildInternal(childIndex - count(generic.getAChild()))
or
result.getAst() = generic.getChild(childIndex)
}
}
/**
* A node representing a `StmtExpr`.
*/
@@ -872,15 +860,6 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
or
expr.(BuiltInVarArgsStart).getLastNamedParameter() = ele and pred = "getLastNamedParameter()"
or
expr.(C11GenericExpr).getControllingExpr() = ele and pred = "getControllingExpr()"
or
exists(int n |
expr.(C11GenericExpr).getAssociationType(n) = ele.(TypeName).getType() and
pred = "getAssociationType(" + n + ")"
or
expr.(C11GenericExpr).getAssociationExpr(n) = ele and pred = "getAssociationExpr(" + n + ")"
)
or
expr.(Call).getQualifier() = ele and pred = "getQualifier()"
or
exists(int n | expr.(Call).getArgument(n) = ele and pred = "getArgument(" + n.toString() + ")")

View File

@@ -39,8 +39,8 @@ class Type extends Locatable, @type {
/**
* Gets a specifier of this type, recursively looking through `typedef` and
* `decltype`. For example, in the context of `typedef const int *restrict t`,
* the type `volatile t` has specifiers `volatile` and `restrict` but not
* `decltype`. For example, in the context of `typedef const int *restrict
* t`, the type `volatile t` has specifiers `volatile` and `restrict` but not
* `const` since the `const` is attached to the type being pointed to rather
* than the pointer itself.
*/

View File

@@ -409,18 +409,11 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
exists(ConditionDeclExpr e | e.getVariable() = this and e.getEnclosingFunction() = result)
or
orphaned_variables(underlyingElement(this), unresolveElement(result))
or
coroutine_placeholder_variable(underlyingElement(this), _, unresolveElement(result))
}
override predicate isStatic() {
super.isStatic() or orphaned_variables(underlyingElement(this), _)
}
override predicate isCompilerGenerated() {
super.isCompilerGenerated() or
coroutine_placeholder_variable(underlyingElement(this), _, _)
}
}
/**

View File

@@ -7,6 +7,15 @@ import semmle.code.cpp.models.interfaces.Deallocation
*/
predicate freeFunction(Function f, int argNum) { argNum = f.(DeallocationFunction).getFreedArg() }
/**
* A call to a library routine that frees memory.
*
* DEPRECATED: Use `DeallocationExpr` instead (this also includes `delete` expressions).
*/
deprecated predicate freeCall(FunctionCall fc, Expr arg) {
arg = fc.(DeallocationExpr).getFreedExpr()
}
/**
* Is e some kind of allocation or deallocation (`new`, `alloc`, `realloc`, `delete`, `free` etc)?
*/

View File

@@ -57,7 +57,7 @@ private int isSource(Expr bufferExpr, Element why) {
exists(Type bufferType |
// buffer is the address of a variable
why = bufferExpr.(AddressOfExpr).getAddressable() and
bufferType = why.(Variable).getUnspecifiedType() and
bufferType = why.(Variable).getType() and
result = bufferType.getSize() and
not bufferType instanceof ReferenceType and
not any(Union u).getAMemberVariable() = why

View File

@@ -168,6 +168,14 @@ abstract deprecated class Configuration extends string {
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
/**
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
*
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
deprecated int explorationLimit() { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
@@ -283,8 +291,6 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -168,6 +168,14 @@ abstract deprecated class Configuration extends string {
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
/**
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
*
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
deprecated int explorationLimit() { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
@@ -283,8 +291,6 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -168,6 +168,14 @@ abstract deprecated class Configuration extends string {
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
/**
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
*
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
deprecated int explorationLimit() { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
@@ -283,8 +291,6 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -168,6 +168,14 @@ abstract deprecated class Configuration extends string {
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
/**
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
*
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
deprecated int explorationLimit() { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
@@ -283,8 +291,6 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -168,6 +168,14 @@ abstract deprecated class Configuration extends string {
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
/**
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
*
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
deprecated int explorationLimit() { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
@@ -283,8 +291,6 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -632,106 +632,6 @@ class ParenthesisExpr extends Conversion, @parexpr {
override string getAPrimaryQlClass() { result = "ParenthesisExpr" }
}
/**
* A node representing a C11 `_Generic` selection expression.
*
* For example:
* ```
* _Generic(e, int: "int", default: "unknown")
* ```
*/
class C11GenericExpr extends Conversion, @c11_generic {
int associationCount;
C11GenericExpr() { associationCount = (count(this.getAChild()) - 1) / 2 }
override string toString() { result = "_Generic" }
override string getAPrimaryQlClass() { result = "C11GenericExpr" }
/**
* Gets the controlling expression of the generic selection.
*
* For example, for
* ```
* _Generic(e, int: "a", default: "b")
* ```
* the result is `e`.
*/
Expr getControllingExpr() { result = this.getChild(0) }
/**
* Gets the type of the `n`th element in the association list of the generic selection.
*
* For example, for
* ```
* _Generic(e, int: "a", default: "b")
* ```
* the type of the 0th element is `int`. In the case of the default element the
* type will an instance of `VoidType`.
*/
Type getAssociationType(int n) {
n in [0 .. associationCount - 1] and
result = this.getChild(n * 2 + 1).(TypeName).getType()
}
/**
* Gets the type of an element in the association list of the generic selection.
*/
Type getAnAssociationType() { result = this.getAssociationType(_) }
/**
* Gets the expression of the `n`th element in the association list of
* the generic selection.
*
* For example, for
* ```
* _Generic(e, int: "a", default: "b")
* ```
* the expression for 0th element is `"a"`, and the expression for the
* 1st element is `"b"`. For the selected expression, this predicate
* will yield a `ReuseExpr`, such that
* ```
* this.getAssociationExpr(n).(ReuseExpr).getReusedExpr() = this.getExpr()
* ```
*/
Expr getAssociationExpr(int n) {
n in [0 .. associationCount - 1] and
result = this.getChild(n * 2 + 2)
}
/**
* Gets the expression of an element in the association list of the generic selection.
*/
Expr getAnAssociationExpr() { result = this.getAssociationExpr(_) }
/**
* Holds if the `n`th element of the association list of the generic selection is the
* default element.
*
* For example, for
* ```
* _Generic(e, int: "a", default: "b")
* ```
* this holds for 1.
*/
predicate isDefaultAssociation(int n) { this.getAssociationType(n) instanceof VoidType }
/**
* Holds if the `n`th element of the association list of the generic selection is the
* one whose expression was selected.
*
* For example, with `e` of type `int` and
* ```
* _Generic(e, int: "a", default: "b")
* ```
* this holds for 0.
*/
predicate isSelectedAssociation(int n) {
this.getAssociationExpr(n).(ReuseExpr).getReusedExpr() = this.getExpr()
}
}
/**
* A C/C++ expression that could not be resolved, or that can no longer be
* represented due to a database upgrade or downgrade.
@@ -768,8 +668,6 @@ class AssumeExpr extends Expr, @assume {
/**
* A C/C++ comma expression.
*
* For example:
* ```
* int c = compute1(), compute2(), resulting_value;
* ```

View File

@@ -195,6 +195,17 @@ class ClassAggregateLiteral extends AggregateLiteral {
*/
Expr getAFieldExpr(Field field) { result = this.getFieldExpr(field, _) }
/**
* DEPRECATED: Use `getAFieldExpr` instead.
*
* Gets the expression within the aggregate literal that is used to initialize
* field `field`, if present.
*
* This predicate may have multiple results since a field can be initialized
* multiple times in the same initializer.
*/
deprecated Expr getFieldExpr(Field field) { result = this.getFieldExpr(field, _) }
/**
* Gets the expression within the aggregate literal that is used to initialize
* field `field`, if present. The expression is the `position`'th entry in the
@@ -289,6 +300,17 @@ class ArrayOrVectorAggregateLiteral extends AggregateLiteral {
*/
Expr getAnElementExpr(int elementIndex) { result = this.getElementExpr(elementIndex, _) }
/**
* DEPRECATED: Use `getAnElementExpr` instead.
*
* Gets the expression within the aggregate literal that is used to initialize
* element `elementIndex`, if present.
*
* This predicate may have multiple results since an element can be initialized
* multiple times in the same initializer.
*/
deprecated Expr getElementExpr(int elementIndex) { result = this.getElementExpr(elementIndex, _) }
/**
* Gets the expression within the aggregate literal that is used to initialize
* element `elementIndex`, if present. The expression is the `position`'th entry

View File

@@ -168,6 +168,14 @@ abstract deprecated class Configuration extends string {
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
/**
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
*
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
deprecated int explorationLimit() { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
@@ -283,8 +291,6 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -168,6 +168,14 @@ abstract deprecated class Configuration extends string {
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
/**
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
*
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
deprecated int explorationLimit() { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
@@ -283,8 +291,6 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -168,6 +168,14 @@ abstract deprecated class Configuration extends string {
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
/**
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
*
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
deprecated int explorationLimit() { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
@@ -283,8 +291,6 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -168,6 +168,14 @@ abstract deprecated class Configuration extends string {
*/
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
/**
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
*
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
* measured in approximate number of interprocedural steps.
*/
deprecated int explorationLimit() { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
@@ -283,8 +291,6 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -546,7 +546,7 @@ module ProductFlow {
Flow1::PathGraph::edges(pred1, succ1, _, _) and
exists(ReturnKindExt returnKind |
succ1.getNode() = returnKind.getAnOutNode(call) and
returnKind = getParamReturnPosition(_, pred1.asParameterReturnNode()).getKind()
paramReturnNode(_, pred1.asParameterReturnNode(), _, returnKind)
)
}
@@ -574,7 +574,7 @@ module ProductFlow {
Flow2::PathGraph::edges(pred2, succ2, _, _) and
exists(ReturnKindExt returnKind |
succ2.getNode() = returnKind.getAnOutNode(call) and
returnKind = getParamReturnPosition(_, pred2.asParameterReturnNode()).getKind()
paramReturnNode(_, pred2.asParameterReturnNode(), _, returnKind)
)
}

View File

@@ -50,6 +50,9 @@ abstract private class AbstractIRVariable extends TIRVariable {
*/
abstract Language::AST getAst();
/** DEPRECATED: Alias for getAst */
deprecated Language::AST getAST() { result = this.getAst() }
/**
* Gets an identifier string for the variable. This identifier is unique
* within the function.
@@ -93,6 +96,9 @@ class IRUserVariable extends AbstractIRVariable, TIRUserVariable {
final override Language::AST getAst() { result = var }
/** DEPRECATED: Alias for getAst */
deprecated override Language::AST getAST() { result = this.getAst() }
final override string getUniqueId() {
result = this.getVariable().toString() + " " + this.getVariable().getLocation().toString()
}
@@ -157,6 +163,9 @@ abstract private class AbstractIRGeneratedVariable extends AbstractIRVariable {
final override Language::AST getAst() { result = ast }
/** DEPRECATED: Alias for getAst */
deprecated override Language::AST getAST() { result = this.getAst() }
override string toString() { result = this.getBaseString() + this.getLocationString() }
override string getUniqueId() { none() }

View File

@@ -6,112 +6,6 @@
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
* to dump.
*
* Anatomy of a printed IR instruction
*
* An instruction:
*
* ```
* # 2281| v2281_19(void) = Call[~String] : func:r2281_18, this:r2281_17
* ```
*
* The prefix `# 2281|` specifies that this instruction was generated by the C++ source code on line 2281.
* Scrolling up in the printed output, one will eventually find the name of the file to which the line
* belongs.
*
* `v2281_19(void)` is the result of the instruction. Here, `v` means this is a void result or operand (so
* there should be no later uses of the result; see below for other possible values). The `2281_19` is a
* unique ID for the result. This is usually just the line number plus a small integer suffix to make it
* unique within the function. The type of the result is `void`. In this case, it is `void`, because
* `~String` returns `void`. The type of the result is usually just the name of the appropriate C++ type,
* but it will sometimes be a type like `glval<int>`, which means result holds a glvalue, which at the
* IR level works like a pointer. In other words, in the source code the type was `int`, but it is really
* more like an `int*`. We see this, for example, in `x = y;`, where `x` is a glvalue.
*
* `Call` is the opcode of the instruction. Common opcodes include:
*
* * Arithmetic operations: `Add`, `Sub`, `Mul`, etc.
* * Memory access operations: `Load`, `Store`.
* * Function calls: `Call`.
* * Literals: `Constant`.
* * Variable addresses: `VariableAddress`.
* * Function entry points: `EnterFunction`.
* * Return from a function: `Return`, `ReturnVoid`. Note that the value being returned is set separately by a
* `Store` to a special `#return` variable.
* * Stack unwinding for C++ function that throw and where the exception escapes the function: `Unwind`.
* * Common exit point for `Unwind` and `Return`: `ExitFunction`.
* * SSA-related opcodes: `Phi`, `Chi`.
*
* `[~String]` denotes additional information. The information might be present earlier in the IR, as is the case
* for `Call`, where it is the name of the called function. This is also the case for `Load` and `Store`, where it
* is the name of the variable that loaded or stored (if known). In the case of `Constant`, `FieldAddress`, and
* `VariableAddress`, the information between brackets does not occur earlier.
*
* `func:r2281_18` and `this:r28281_17` are the operands of the instruction. The `func:` prefix denotes the operand
* that holds the address of the called function. The `this:` prefix denotes the argument to the special `this`
* parameter of an instance member function. `r2281_18`, `r2281_17` are the unique IDs of the operands. Each of these
* matches the ID of a previously seen result, showing where that value came from. The `r` means that these are
* "register" operands (see below).
*
* Result and operand kinds:
*
* Every result and operand is one of these three kinds:
*
* * `r` "register". These operands are not stored in any particular memory location. We can think of them as
* temporary values created during the evaluation of an expression. A register operand almost always has one
* use, often in the same block as its definition.
* * `m` "memory". These operands represents accesses to a specific memory location. The location could be a
* local variable, a global variable, a field of an object, an element of an array, or any memory that we happen
* to have a pointer to. These only occur as the result of a `Store`, the source operand of a `Load` or on the
* SSA instructions (`Phi`, `Chi`).
* * `v` "void". Really just a register operand, but we mark register operands of type void with this special prefix
* so we know that there is no actual value there.
*
* Branches in the IR:
*
* The IR is divided into basic blocks. At the end of each block, there are one or more edges showing the possible
* control flow successors of the block.
*
* ```
* # 44| v44_3(void) = ConditionalBranch : r44_2
* #-----| False -> Block 4
* #-----| True -> Block 3
* ```
* Here we have a block that ends with a conditional branch. The two edges show where the control flows to depending
* on whether the condition is true or false.
*
* SSA instructions:
*
* We use `Phi` instructions in SSA to create a single definition for a variable that might be assigned on multiple
* control flow paths. The `Phi` instruction merges the potential values of that variable from each predecessor edge,
* and the resulting definition is then used wherever that variable is accessed later on.
*
* When dealing with aliased memory, we use the `Chi` instruction to create a single definition for memory that might
* or might not have been updated by a store, depending on the actual address that was written to. For example, take:
*
* ```cpp
* int x = 5;
* int y = 7;
* int* p = condition ? &x : &y;
* *p = 6;
* return x;
* ```
*
* At the point where we store to `*p`, we do not know whether `p` points to `x` or `y`. Thus, we do not know whether
* `return x;` is going to return the value that `x` was originally initialized to (5), or whether it will return 6,
* because it was overwritten by `*p = 6;`. We insert a `Chi` instruction immediately after the store to `*p`:
*
* ```
* r2(int) = Constant[6]
* r3(int*) = <<value of p>>
* m4(int) = Store : &r3, r2 // Stores the constant 6 to *p
* m5(unknown) = Chi : total:m1, partial:m4
* ```
* The `partial:` operand represents the memory that was just stored. The `total:` operand represents the previous
* contents of all of the memory that `p` might have pointed to (in this case, both `x` and `y`). The result of the
* `Chi` represents the new contents of whatever memory the `total:` operand referred to. We usually do not know exactly
* which parts of that memory were overwritten, but it does model that any of that memory could have been modified, so
* that later instructions do not assume that the memory was unchanged.
*/
private import internal.IRInternal

View File

@@ -285,6 +285,9 @@ abstract private class MemoryLocation0 extends TMemoryLocation {
predicate isAlwaysAllocatedOnStack() { none() }
final predicate canReuseSsa() { none() }
/** DEPRECATED: Alias for canReuseSsa */
deprecated predicate canReuseSSA() { this.canReuseSsa() }
}
/**
@@ -683,13 +686,8 @@ private Overlap getExtentOverlap(MemoryLocation0 def, MemoryLocation0 use) {
def.getVirtualVariable() = use.getVirtualVariable() and
def instanceof EntireAllocationMemoryLocation and
(
// EntireAllocationMemoryLocation exactly overlaps any EntireAllocationMemoryLocation for the
// same allocation. Checking the allocation, rather than the memory location itself, ensures
// that we get the right relationship between the "must" and "may" memory locations for that
// allocation.
// Note that if one of the locations is a "may" access, the overlap will be downgraded to
// `MustTotallyOverlap` or `MayPartialOverlap` in `getOverlap()`.
use.(EntireAllocationMemoryLocation).getAnAllocation() = def.getAnAllocation() and
// EntireAllocationMemoryLocation exactly overlaps itself.
use instanceof EntireAllocationMemoryLocation and
result instanceof MustExactlyOverlap
or
not use instanceof EntireAllocationMemoryLocation and

View File

@@ -50,6 +50,9 @@ abstract private class AbstractIRVariable extends TIRVariable {
*/
abstract Language::AST getAst();
/** DEPRECATED: Alias for getAst */
deprecated Language::AST getAST() { result = this.getAst() }
/**
* Gets an identifier string for the variable. This identifier is unique
* within the function.
@@ -93,6 +96,9 @@ class IRUserVariable extends AbstractIRVariable, TIRUserVariable {
final override Language::AST getAst() { result = var }
/** DEPRECATED: Alias for getAst */
deprecated override Language::AST getAST() { result = this.getAst() }
final override string getUniqueId() {
result = this.getVariable().toString() + " " + this.getVariable().getLocation().toString()
}
@@ -157,6 +163,9 @@ abstract private class AbstractIRGeneratedVariable extends AbstractIRVariable {
final override Language::AST getAst() { result = ast }
/** DEPRECATED: Alias for getAst */
deprecated override Language::AST getAST() { result = this.getAst() }
override string toString() { result = this.getBaseString() + this.getLocationString() }
override string getUniqueId() { none() }

View File

@@ -6,112 +6,6 @@
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
* to dump.
*
* Anatomy of a printed IR instruction
*
* An instruction:
*
* ```
* # 2281| v2281_19(void) = Call[~String] : func:r2281_18, this:r2281_17
* ```
*
* The prefix `# 2281|` specifies that this instruction was generated by the C++ source code on line 2281.
* Scrolling up in the printed output, one will eventually find the name of the file to which the line
* belongs.
*
* `v2281_19(void)` is the result of the instruction. Here, `v` means this is a void result or operand (so
* there should be no later uses of the result; see below for other possible values). The `2281_19` is a
* unique ID for the result. This is usually just the line number plus a small integer suffix to make it
* unique within the function. The type of the result is `void`. In this case, it is `void`, because
* `~String` returns `void`. The type of the result is usually just the name of the appropriate C++ type,
* but it will sometimes be a type like `glval<int>`, which means result holds a glvalue, which at the
* IR level works like a pointer. In other words, in the source code the type was `int`, but it is really
* more like an `int*`. We see this, for example, in `x = y;`, where `x` is a glvalue.
*
* `Call` is the opcode of the instruction. Common opcodes include:
*
* * Arithmetic operations: `Add`, `Sub`, `Mul`, etc.
* * Memory access operations: `Load`, `Store`.
* * Function calls: `Call`.
* * Literals: `Constant`.
* * Variable addresses: `VariableAddress`.
* * Function entry points: `EnterFunction`.
* * Return from a function: `Return`, `ReturnVoid`. Note that the value being returned is set separately by a
* `Store` to a special `#return` variable.
* * Stack unwinding for C++ function that throw and where the exception escapes the function: `Unwind`.
* * Common exit point for `Unwind` and `Return`: `ExitFunction`.
* * SSA-related opcodes: `Phi`, `Chi`.
*
* `[~String]` denotes additional information. The information might be present earlier in the IR, as is the case
* for `Call`, where it is the name of the called function. This is also the case for `Load` and `Store`, where it
* is the name of the variable that loaded or stored (if known). In the case of `Constant`, `FieldAddress`, and
* `VariableAddress`, the information between brackets does not occur earlier.
*
* `func:r2281_18` and `this:r28281_17` are the operands of the instruction. The `func:` prefix denotes the operand
* that holds the address of the called function. The `this:` prefix denotes the argument to the special `this`
* parameter of an instance member function. `r2281_18`, `r2281_17` are the unique IDs of the operands. Each of these
* matches the ID of a previously seen result, showing where that value came from. The `r` means that these are
* "register" operands (see below).
*
* Result and operand kinds:
*
* Every result and operand is one of these three kinds:
*
* * `r` "register". These operands are not stored in any particular memory location. We can think of them as
* temporary values created during the evaluation of an expression. A register operand almost always has one
* use, often in the same block as its definition.
* * `m` "memory". These operands represents accesses to a specific memory location. The location could be a
* local variable, a global variable, a field of an object, an element of an array, or any memory that we happen
* to have a pointer to. These only occur as the result of a `Store`, the source operand of a `Load` or on the
* SSA instructions (`Phi`, `Chi`).
* * `v` "void". Really just a register operand, but we mark register operands of type void with this special prefix
* so we know that there is no actual value there.
*
* Branches in the IR:
*
* The IR is divided into basic blocks. At the end of each block, there are one or more edges showing the possible
* control flow successors of the block.
*
* ```
* # 44| v44_3(void) = ConditionalBranch : r44_2
* #-----| False -> Block 4
* #-----| True -> Block 3
* ```
* Here we have a block that ends with a conditional branch. The two edges show where the control flows to depending
* on whether the condition is true or false.
*
* SSA instructions:
*
* We use `Phi` instructions in SSA to create a single definition for a variable that might be assigned on multiple
* control flow paths. The `Phi` instruction merges the potential values of that variable from each predecessor edge,
* and the resulting definition is then used wherever that variable is accessed later on.
*
* When dealing with aliased memory, we use the `Chi` instruction to create a single definition for memory that might
* or might not have been updated by a store, depending on the actual address that was written to. For example, take:
*
* ```cpp
* int x = 5;
* int y = 7;
* int* p = condition ? &x : &y;
* *p = 6;
* return x;
* ```
*
* At the point where we store to `*p`, we do not know whether `p` points to `x` or `y`. Thus, we do not know whether
* `return x;` is going to return the value that `x` was originally initialized to (5), or whether it will return 6,
* because it was overwritten by `*p = 6;`. We insert a `Chi` instruction immediately after the store to `*p`:
*
* ```
* r2(int) = Constant[6]
* r3(int*) = <<value of p>>
* m4(int) = Store : &r3, r2 // Stores the constant 6 to *p
* m5(unknown) = Chi : total:m1, partial:m4
* ```
* The `partial:` operand represents the memory that was just stored. The `total:` operand represents the previous
* contents of all of the memory that `p` might have pointed to (in this case, both `x` and `y`). The result of the
* `Chi` represents the new contents of whatever memory the `total:` operand referred to. We usually do not know exactly
* which parts of that memory were overwritten, but it does model that any of that memory could have been modified, so
* that later instructions do not assume that the memory was unchanged.
*/
private import internal.IRInternal

View File

@@ -216,6 +216,9 @@ abstract class TranslatedSideEffects extends TranslatedElement {
final override Locatable getAst() { result = this.getExpr() }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
final override Declaration getFunction() { result = getEnclosingDeclaration(this.getExpr()) }
final override TranslatedElement getChild(int i) {
@@ -613,6 +616,9 @@ class TranslatedArgumentExprSideEffect extends TranslatedArgumentSideEffect,
final override Locatable getAst() { result = arg }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
final override Type getIndirectionType() {
result = arg.getUnspecifiedType().(DerivedType).getBaseType()
or
@@ -645,6 +651,9 @@ class TranslatedStructorQualifierSideEffect extends TranslatedArgumentSideEffect
final override Locatable getAst() { result = call }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
final override Type getIndirectionType() { result = call.getTarget().getDeclaringType() }
final override string getArgString() { result = "this" }
@@ -666,6 +675,9 @@ class TranslatedCallSideEffect extends TranslatedSideEffect, TTranslatedCallSide
override Locatable getAst() { result = expr }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
override Expr getPrimaryExpr() { result = expr }
override predicate sortOrder(int group, int indexInGroup) {
@@ -704,6 +716,9 @@ class TranslatedAllocationSideEffect extends TranslatedSideEffect, TTranslatedAl
override Locatable getAst() { result = expr }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
override Expr getPrimaryExpr() { result = expr }
override predicate sortOrder(int group, int indexInGroup) {

View File

@@ -29,6 +29,9 @@ abstract class TranslatedCondition extends TranslatedElement {
final override Locatable getAst() { result = expr }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
final ConditionContext getConditionContext() { result = this.getParent() }
final Expr getExpr() { result = expr }

View File

@@ -45,6 +45,9 @@ abstract class TranslatedDeclarationEntry extends TranslatedElement, TTranslated
final override string toString() { result = entry.toString() }
final override Locatable getAst() { result = entry.getAst() }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
}
/**
@@ -245,6 +248,9 @@ class TranslatedStaticLocalVariableInitialization extends TranslatedElement,
final override Locatable getAst() { result = entry.getAst() }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
final override LocalVariable getVariable() { result = var }
final override Declaration getFunction() { result = var.getFunction() }
@@ -271,6 +277,9 @@ class TranslatedConditionDecl extends TranslatedLocalVariableDeclaration, TTrans
override Locatable getAst() { result = conditionDeclExpr }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
override Declaration getFunction() { result = getEnclosingFunction(conditionDeclExpr) }
override LocalVariable getVariable() { result = conditionDeclExpr.getVariable() }

View File

@@ -128,9 +128,6 @@ private predicate ignoreExprAndDescendants(Expr expr) {
vaStartExpr.getLastNamedParameter().getFullyConverted() = expr
)
or
// The children of C11 _Generic expressions are just surface syntax.
exists(C11GenericExpr generic | generic.getAChild() = expr)
or
// Do not translate implicit destructor calls for unnamed temporary variables that are
// conditionally constructed (until we have a mechanism for calling these only when the
// temporary's constructor was run)
@@ -435,9 +432,6 @@ predicate ignoreLoad(Expr expr) {
// The load is duplicated from the right operand.
isExtractorFrontendVersion65OrHigher() and expr instanceof CommaExpr
or
// The load is duplicated from the chosen expression.
expr instanceof C11GenericExpr
or
expr.(PointerDereferenceExpr).getOperand().getFullyConverted().getType().getUnspecifiedType()
instanceof FunctionPointerType
or
@@ -767,10 +761,7 @@ newtype TTranslatedElement =
} or
// A statement
TTranslatedStmt(Stmt stmt) { translateStmt(stmt) } or
// The `__except` block of a `__try __except` statement
TTranslatedMicrosoftTryExceptHandler(MicrosoftTryExceptStmt stmt) or
// The `__finally` block of a `__try __finally` statement
TTranslatedMicrosoftTryFinallyHandler(MicrosoftTryFinallyStmt stmt) or
// A function
TTranslatedFunction(Function func) { translateFunction(func) } or
// A constructor init list
@@ -929,6 +920,9 @@ abstract class TranslatedElement extends TTranslatedElement {
*/
abstract Locatable getAst();
/** DEPRECATED: Alias for getAst */
deprecated Locatable getAST() { result = this.getAst() }
/** Gets the location of this element. */
Location getLocation() { result = this.getAst().getLocation() }

View File

@@ -893,8 +893,7 @@ class TranslatedTransparentConversion extends TranslatedTransparentExpr {
(
expr instanceof ParenthesisExpr or
expr instanceof ReferenceDereferenceExpr or
expr instanceof ReferenceToExpr or
expr instanceof C11GenericExpr
expr instanceof ReferenceToExpr
)
}

View File

@@ -67,6 +67,9 @@ class TranslatedFunction extends TranslatedRootElement, TTranslatedFunction {
final override Locatable getAst() { result = func }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
/**
* Gets the function being translated.
*/
@@ -209,13 +212,8 @@ class TranslatedFunction extends TranslatedRootElement, TTranslatedFunction {
(
// Only generate the `Unwind` instruction if there is any exception
// handling present in the function.
exists(TryOrMicrosoftTryStmt try | try.getEnclosingFunction() = func)
or
exists(TryStmt try | try.getEnclosingFunction() = func) or
exists(ThrowExpr throw | throw.getEnclosingFunction() = func)
or
exists(FunctionCall call | call.getEnclosingFunction() = func |
getTranslatedExpr(call).(TranslatedCallExpr).mayThrowException()
)
)
or
tag = AliasedUseTag() and
@@ -485,6 +483,9 @@ class TranslatedThisParameter extends TranslatedParameter, TTranslatedThisParame
final override Locatable getAst() { result = func }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
final override Function getFunction() { result = func }
final override predicate hasIndirection() { any() }
@@ -517,6 +518,9 @@ class TranslatedPositionalParameter extends TranslatedParameter, TTranslatedPara
final override Locatable getAst() { result = param }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
final override Function getFunction() {
result = param.getFunction() or
result = param.getCatchBlock().getEnclosingFunction()
@@ -554,6 +558,9 @@ class TranslatedEllipsisParameter extends TranslatedParameter, TTranslatedEllips
final override Locatable getAst() { result = func }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
final override Function getFunction() { result = func }
final override predicate hasIndirection() { any() }
@@ -590,6 +597,9 @@ class TranslatedConstructorInitList extends TranslatedElement, InitializationCon
override Locatable getAst() { result = func }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
override TranslatedElement getChild(int id) {
exists(ConstructorFieldInit fieldInit |
fieldInit = func.(Constructor).getInitializer(id) and
@@ -667,6 +677,9 @@ class TranslatedDestructorDestructionList extends TranslatedElement,
override Locatable getAst() { result = func }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
override TranslatedElement getChild(int id) {
exists(DestructorFieldDestruction fieldDestruction |
fieldDestruction = func.(Destructor).getDestruction(id) and
@@ -720,6 +733,9 @@ class TranslatedReadEffects extends TranslatedElement, TTranslatedReadEffects {
override Locatable getAst() { result = func }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
override Function getFunction() { result = func }
override string toString() { result = "read effects: " + func.toString() }
@@ -823,6 +839,9 @@ class TranslatedThisReadEffect extends TranslatedReadEffect, TTranslatedThisRead
override Locatable getAst() { result = func }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
override Function getFunction() { result = func }
override string toString() { result = "read effect: this" }
@@ -846,6 +865,9 @@ class TranslatedParameterReadEffect extends TranslatedReadEffect, TTranslatedPar
override Locatable getAst() { result = param }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
override string toString() { result = "read effect: " + param.toString() }
override Function getFunction() { result = param.getFunction() }

View File

@@ -153,6 +153,9 @@ abstract class TranslatedInitialization extends TranslatedElement, TTranslatedIn
final override Locatable getAst() { result = expr }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
/**
* Gets the expression that is doing the initialization.
*/
@@ -525,6 +528,9 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
final override Locatable getAst() { result = ast }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
final override Declaration getFunction() {
result = getEnclosingFunction(ast) or
result = getEnclosingVariable(ast).(GlobalOrNamespaceVariable) or
@@ -695,6 +701,9 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
final override Locatable getAst() { result = initList }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
final override Declaration getFunction() {
result = getEnclosingFunction(initList)
or
@@ -903,6 +912,9 @@ abstract class TranslatedStructorCallFromStructor extends TranslatedElement, Str
final override Locatable getAst() { result = call }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
final override TranslatedElement getChild(int id) {
id = 0 and
result = this.getStructorCall()
@@ -1046,6 +1058,9 @@ class TranslatedConstructorBareInit extends TranslatedElement, TTranslatedConstr
override Locatable getAst() { result = init }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
final override string toString() { result = "construct base (no constructor)" }
override Instruction getFirstInstruction(EdgeKind kind) {

View File

@@ -79,6 +79,11 @@ class TranslatedMicrosoftTryExceptHandler extends TranslatedElement,
tag = TryExceptCompareOneBranch() and
opcode instanceof Opcode::ConditionalBranch and
resultType = getVoidType()
or
// unwind stack
tag = UnwindTag() and
opcode instanceof Opcode::Unwind and
resultType = getVoidType()
}
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
@@ -151,7 +156,7 @@ class TranslatedMicrosoftTryExceptHandler extends TranslatedElement,
// TODO: This is not really correct. The semantics of `EXCEPTION_CONTINUE_EXECUTION` is that
// we should continue execution at the point where the exception occurred. But we don't have
// any instruction to model this behavior.
result = this.getExceptionSuccessorInstruction(any(GotoEdge edge))
result = this.getInstruction(UnwindTag())
or
kind instanceof FalseEdge and
result = this.getInstruction(TryExceptGenerateZero())
@@ -171,7 +176,7 @@ class TranslatedMicrosoftTryExceptHandler extends TranslatedElement,
tag = TryExceptCompareZeroBranch() and
(
kind instanceof TrueEdge and
result = this.getExceptionSuccessorInstruction(any(GotoEdge edge))
result = this.getInstruction(UnwindTag())
or
kind instanceof FalseEdge and
result = this.getInstruction(TryExceptGenerateOne())
@@ -191,6 +196,10 @@ class TranslatedMicrosoftTryExceptHandler extends TranslatedElement,
tag = TryExceptCompareOneBranch() and
kind instanceof TrueEdge and
result = this.getTranslatedHandler().getFirstInstruction(any(GotoEdge edge))
or
// Unwind -> Parent
tag = UnwindTag() and
result = this.getParent().getChildSuccessor(this, kind)
}
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
@@ -206,6 +215,8 @@ class TranslatedMicrosoftTryExceptHandler extends TranslatedElement,
override Instruction getALastInstructionInternal() {
result = this.getTranslatedHandler().getALastInstruction()
or
result = this.getInstruction(UnwindTag())
}
private TranslatedExpr getTranslatedCondition() {
@@ -225,68 +236,6 @@ class TranslatedMicrosoftTryExceptHandler extends TranslatedElement,
}
final override Function getFunction() { result = tryExcept.getEnclosingFunction() }
override Instruction getExceptionSuccessorInstruction(EdgeKind kind) {
// A throw from within a `__except` block flows to the handler for the parent of
// the `__try`.
result = this.getParent().getParent().getExceptionSuccessorInstruction(kind)
}
}
TranslatedMicrosoftTryFinallyHandler getTranslatedMicrosoftTryFinallyHandler(
MicrosoftTryFinallyStmt tryFinally
) {
result.getAst() = tryFinally.getFinally()
}
class TranslatedMicrosoftTryFinallyHandler extends TranslatedElement,
TTranslatedMicrosoftTryFinallyHandler
{
MicrosoftTryFinallyStmt tryFinally;
TranslatedMicrosoftTryFinallyHandler() {
this = TTranslatedMicrosoftTryFinallyHandler(tryFinally)
}
final override string toString() { result = tryFinally.toString() }
final override Locatable getAst() { result = tryFinally.getFinally() }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getTranslatedFinally().getFirstInstruction(kind)
}
override Instruction getALastInstructionInternal() {
result = this.getTranslatedFinally().getALastInstruction()
}
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
child = this.getTranslatedFinally() and
result = this.getParent().getChildSuccessor(this, kind)
}
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) { none() }
override TranslatedElement getChild(int id) {
id = 0 and
result = this.getTranslatedFinally()
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
none()
}
final override Function getFunction() { result = tryFinally.getEnclosingFunction() }
private TranslatedStmt getTranslatedFinally() {
result = getTranslatedStmt(tryFinally.getFinally())
}
override Instruction getExceptionSuccessorInstruction(EdgeKind kind) {
// A throw from within a `__finally` block flows to the handler for the parent of
// the `__try`.
result = this.getParent().getParent().getExceptionSuccessorInstruction(kind)
}
}
abstract class TranslatedStmt extends TranslatedElement, TTranslatedStmt {
@@ -319,6 +268,9 @@ abstract class TranslatedStmt extends TranslatedElement, TTranslatedStmt {
final override Locatable getAst() { result = stmt }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
final override Function getFunction() { result = stmt.getEnclosingFunction() }
}
@@ -634,7 +586,7 @@ class TranslatedNoValueReturnStmt extends TranslatedReturnStmt, TranslatedVariab
/**
* A C/C++ `try` statement, or a `__try __except` or `__try __finally` statement.
*/
class TryOrMicrosoftTryStmt extends Stmt {
private class TryOrMicrosoftTryStmt extends Stmt {
TryOrMicrosoftTryStmt() {
this instanceof TryStmt or
this instanceof MicrosoftTryStmt
@@ -667,9 +619,7 @@ class TryOrMicrosoftTryStmt extends Stmt {
}
/** Gets the `finally` statement (usually a BlockStmt), if any. */
TranslatedElement getTranslatedFinally() {
result = getTranslatedMicrosoftTryFinallyHandler(this)
}
Stmt getFinally() { result = this.(MicrosoftTryFinallyStmt).getFinally() }
}
/**
@@ -739,14 +689,11 @@ class TranslatedTryStmt extends TranslatedStmt {
final override Instruction getExceptionSuccessorInstruction(EdgeKind kind) {
result = this.getHandler(0).getFirstInstruction(kind)
or
not exists(this.getHandler(_)) and
result = this.getFinally().getFirstInstruction(kind)
}
private TranslatedElement getHandler(int index) { result = stmt.getTranslatedHandler(index) }
private TranslatedElement getFinally() { result = stmt.getTranslatedFinally() }
private TranslatedStmt getFinally() { result = getTranslatedStmt(stmt.getFinally()) }
private TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getStmt()) }
}

View File

@@ -50,6 +50,9 @@ abstract private class AbstractIRVariable extends TIRVariable {
*/
abstract Language::AST getAst();
/** DEPRECATED: Alias for getAst */
deprecated Language::AST getAST() { result = this.getAst() }
/**
* Gets an identifier string for the variable. This identifier is unique
* within the function.
@@ -93,6 +96,9 @@ class IRUserVariable extends AbstractIRVariable, TIRUserVariable {
final override Language::AST getAst() { result = var }
/** DEPRECATED: Alias for getAst */
deprecated override Language::AST getAST() { result = this.getAst() }
final override string getUniqueId() {
result = this.getVariable().toString() + " " + this.getVariable().getLocation().toString()
}
@@ -157,6 +163,9 @@ abstract private class AbstractIRGeneratedVariable extends AbstractIRVariable {
final override Language::AST getAst() { result = ast }
/** DEPRECATED: Alias for getAst */
deprecated override Language::AST getAST() { result = this.getAst() }
override string toString() { result = this.getBaseString() + this.getLocationString() }
override string getUniqueId() { none() }

View File

@@ -6,112 +6,6 @@
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
* to dump.
*
* Anatomy of a printed IR instruction
*
* An instruction:
*
* ```
* # 2281| v2281_19(void) = Call[~String] : func:r2281_18, this:r2281_17
* ```
*
* The prefix `# 2281|` specifies that this instruction was generated by the C++ source code on line 2281.
* Scrolling up in the printed output, one will eventually find the name of the file to which the line
* belongs.
*
* `v2281_19(void)` is the result of the instruction. Here, `v` means this is a void result or operand (so
* there should be no later uses of the result; see below for other possible values). The `2281_19` is a
* unique ID for the result. This is usually just the line number plus a small integer suffix to make it
* unique within the function. The type of the result is `void`. In this case, it is `void`, because
* `~String` returns `void`. The type of the result is usually just the name of the appropriate C++ type,
* but it will sometimes be a type like `glval<int>`, which means result holds a glvalue, which at the
* IR level works like a pointer. In other words, in the source code the type was `int`, but it is really
* more like an `int*`. We see this, for example, in `x = y;`, where `x` is a glvalue.
*
* `Call` is the opcode of the instruction. Common opcodes include:
*
* * Arithmetic operations: `Add`, `Sub`, `Mul`, etc.
* * Memory access operations: `Load`, `Store`.
* * Function calls: `Call`.
* * Literals: `Constant`.
* * Variable addresses: `VariableAddress`.
* * Function entry points: `EnterFunction`.
* * Return from a function: `Return`, `ReturnVoid`. Note that the value being returned is set separately by a
* `Store` to a special `#return` variable.
* * Stack unwinding for C++ function that throw and where the exception escapes the function: `Unwind`.
* * Common exit point for `Unwind` and `Return`: `ExitFunction`.
* * SSA-related opcodes: `Phi`, `Chi`.
*
* `[~String]` denotes additional information. The information might be present earlier in the IR, as is the case
* for `Call`, where it is the name of the called function. This is also the case for `Load` and `Store`, where it
* is the name of the variable that loaded or stored (if known). In the case of `Constant`, `FieldAddress`, and
* `VariableAddress`, the information between brackets does not occur earlier.
*
* `func:r2281_18` and `this:r28281_17` are the operands of the instruction. The `func:` prefix denotes the operand
* that holds the address of the called function. The `this:` prefix denotes the argument to the special `this`
* parameter of an instance member function. `r2281_18`, `r2281_17` are the unique IDs of the operands. Each of these
* matches the ID of a previously seen result, showing where that value came from. The `r` means that these are
* "register" operands (see below).
*
* Result and operand kinds:
*
* Every result and operand is one of these three kinds:
*
* * `r` "register". These operands are not stored in any particular memory location. We can think of them as
* temporary values created during the evaluation of an expression. A register operand almost always has one
* use, often in the same block as its definition.
* * `m` "memory". These operands represents accesses to a specific memory location. The location could be a
* local variable, a global variable, a field of an object, an element of an array, or any memory that we happen
* to have a pointer to. These only occur as the result of a `Store`, the source operand of a `Load` or on the
* SSA instructions (`Phi`, `Chi`).
* * `v` "void". Really just a register operand, but we mark register operands of type void with this special prefix
* so we know that there is no actual value there.
*
* Branches in the IR:
*
* The IR is divided into basic blocks. At the end of each block, there are one or more edges showing the possible
* control flow successors of the block.
*
* ```
* # 44| v44_3(void) = ConditionalBranch : r44_2
* #-----| False -> Block 4
* #-----| True -> Block 3
* ```
* Here we have a block that ends with a conditional branch. The two edges show where the control flows to depending
* on whether the condition is true or false.
*
* SSA instructions:
*
* We use `Phi` instructions in SSA to create a single definition for a variable that might be assigned on multiple
* control flow paths. The `Phi` instruction merges the potential values of that variable from each predecessor edge,
* and the resulting definition is then used wherever that variable is accessed later on.
*
* When dealing with aliased memory, we use the `Chi` instruction to create a single definition for memory that might
* or might not have been updated by a store, depending on the actual address that was written to. For example, take:
*
* ```cpp
* int x = 5;
* int y = 7;
* int* p = condition ? &x : &y;
* *p = 6;
* return x;
* ```
*
* At the point where we store to `*p`, we do not know whether `p` points to `x` or `y`. Thus, we do not know whether
* `return x;` is going to return the value that `x` was originally initialized to (5), or whether it will return 6,
* because it was overwritten by `*p = 6;`. We insert a `Chi` instruction immediately after the store to `*p`:
*
* ```
* r2(int) = Constant[6]
* r3(int*) = <<value of p>>
* m4(int) = Store : &r3, r2 // Stores the constant 6 to *p
* m5(unknown) = Chi : total:m1, partial:m4
* ```
* The `partial:` operand represents the memory that was just stored. The `total:` operand represents the previous
* contents of all of the memory that `p` might have pointed to (in this case, both `x` and `y`). The result of the
* `Chi` represents the new contents of whatever memory the `total:` operand referred to. We usually do not know exactly
* which parts of that memory were overwritten, but it does model that any of that memory could have been modified, so
* that later instructions do not assume that the memory was unchanged.
*/
private import internal.IRInternal

View File

@@ -71,6 +71,9 @@ class MemoryLocation extends TMemoryLocation {
final string getUniqueId() { result = var.getUniqueId() }
final predicate canReuseSsa() { canReuseSsaForVariable(var) }
/** DEPRECATED: Alias for canReuseSsa */
deprecated predicate canReuseSSA() { this.canReuseSsa() }
}
predicate canReuseSsaForOldResult(Instruction instr) { none() }

View File

@@ -5,13 +5,13 @@
*/
import semmle.code.cpp.models.interfaces.Allocation
import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.Taint
/**
* An allocation function (such as `realloc`) that has an argument for the size
* in bytes, and an argument for an existing pointer that is to be reallocated.
*/
private class ReallocAllocationFunction extends AllocationFunction, DataFlowFunction {
private class ReallocAllocationFunction extends AllocationFunction, TaintFunction {
int sizeArg;
int reallocArg;
@@ -44,7 +44,7 @@ private class ReallocAllocationFunction extends AllocationFunction, DataFlowFunc
override int getReallocPtrArg() { result = reallocArg }
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isParameterDeref(this.getReallocPtrArg()) and output.isReturnValueDeref()
}
}

View File

@@ -26,7 +26,7 @@ private class Swap extends DataFlowFunction {
* obj1.swap(obj2)
* ```
*/
private class MemberSwap extends DataFlowFunction, MemberFunction, AliasFunction {
private class MemberSwap extends TaintFunction, MemberFunction, AliasFunction {
MemberSwap() {
this.hasName("swap") and
this.getNumberOfParameters() = 1 and
@@ -34,7 +34,7 @@ private class MemberSwap extends DataFlowFunction, MemberFunction, AliasFunction
this.getDeclaringType()
}
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isQualifierObject() and
output.isParameterDeref(0)
or

View File

@@ -118,34 +118,19 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction {
/**
* Gets the position of the first format argument, corresponding with
* the first format specifier in the format string. We ignore all
* implicit function definitions.
* the first format specifier in the format string.
*/
int getFirstFormatArgumentIndex() {
// The formatting function either has a definition in the snapshot, or all
result = this.getNumberOfParameters() and
// the formatting function either has a definition in the snapshot, or all
// `DeclarationEntry`s agree on the number of parameters (otherwise we don't
// really know the correct number)
if this.hasDefinition()
then result = this.getDefinition().getNumberOfParameters()
else result = this.getNumberOfExplicitParameters()
}
/**
* Gets a non-implicit function declaration entry.
*/
private FunctionDeclarationEntry getAnExplicitDeclarationEntry() {
result = this.getADeclarationEntry() and
not result.isImplicit()
}
/**
* Gets the number of parameters, excluding any parameters that have been defined
* from implicit function declarations. If there is some inconsistency in the number
* of parameters, then don't return anything.
*/
private int getNumberOfExplicitParameters() {
forex(FunctionDeclarationEntry fde | fde = this.getAnExplicitDeclarationEntry() |
result = fde.getNumberOfParameters()
(
this.hasDefinition()
or
forall(FunctionDeclarationEntry fde | fde = this.getADeclarationEntry() |
result = fde.getNumberOfParameters()
)
)
}

View File

@@ -192,37 +192,6 @@ private class UnsignedMulExpr extends MulExpr {
}
}
/**
* Gets the value of the `EOF` macro.
*
* This is typically `"-1"`, but this is not guaranteed to be the case on all
* systems.
*/
private int getEofValue() {
exists(MacroInvocation mi |
mi.getMacroName() = "EOF" and
result = unique( | | mi.getExpr().getValue().toInt())
)
}
/** Get standard `getc` function or related variants. */
private class Getc extends Function {
Getc() { this.hasGlobalOrStdOrBslName(["fgetc", "getc"]) }
}
/** A call to `getc` */
private class CallToGetc extends FunctionCall {
CallToGetc() { this.getTarget() instanceof Getc }
}
/**
* A call to `getc` that we can analyze because we know
* the value of the `EOF` macro.
*/
private class AnalyzableCallToGetc extends CallToGetc {
AnalyzableCallToGetc() { exists(getEofValue()) }
}
/**
* Holds if `expr` is effectively a multiplication of `operand` with the
* positive constant `positive`.
@@ -318,8 +287,6 @@ private predicate analyzableExpr(Expr e) {
or
e instanceof RemExpr
or
e instanceof AnalyzableCallToGetc
or
// A conversion is analyzable, provided that its child has an arithmetic
// type. (Sometimes the child is a reference type, and so does not get
// any bounds.) Rather than checking whether the type of the child is
@@ -894,14 +861,6 @@ private float getLowerBoundsImpl(Expr expr) {
)
)
or
exists(AnalyzableCallToGetc getc |
expr = getc and
// from https://en.cppreference.com/w/c/io/fgetc:
// On success, returns the obtained character as an unsigned char
// converted to an int. On failure, returns EOF.
result = min([typeLowerBound(any(UnsignedCharType pct)), getEofValue()])
)
or
// If the conversion is to an arithmetic type then we just return the
// lower bound of the child. We do not need to handle truncation and
// overflow here, because that is done in `getTruncatedLowerBounds`.
@@ -1096,14 +1055,6 @@ private float getUpperBoundsImpl(Expr expr) {
)
)
or
exists(AnalyzableCallToGetc getc |
expr = getc and
// from https://en.cppreference.com/w/c/io/fgetc:
// On success, returns the obtained character as an unsigned char
// converted to an int. On failure, returns EOF.
result = max([typeUpperBound(any(UnsignedCharType pct)), getEofValue()])
)
or
// If the conversion is to an arithmetic type then we just return the
// upper bound of the child. We do not need to handle truncation and
// overflow here, because that is done in `getTruncatedUpperBounds`.

View File

@@ -14,11 +14,7 @@ int getPointedSize(Type t) {
* BufferWrite differ.
*/
abstract class BufferAccess extends Expr {
BufferAccess() {
not this.isUnevaluated() and
//A buffer access must be reachable (not in dead code)
reachable(this)
}
BufferAccess() { not this.isUnevaluated() }
abstract string getName();
@@ -30,8 +26,6 @@ abstract class BufferAccess extends Expr {
* - 1 = buffer range [0, getSize) is accessed entirely.
* - 2 = buffer range [0, getSize) may be accessed partially or entirely.
* - 3 = buffer is accessed at offset getSize - 1.
* - 4 = buffer is accessed with null terminator read protections
* (does not read past null terminator, regardless of access size)
*/
abstract Expr getBuffer(string bufferDesc, int accessType);
@@ -134,7 +128,7 @@ class StrncpyBA extends BufferAccess {
or
result = this.(FunctionCall).getArgument(1) and
bufferDesc = "source buffer" and
accessType = 4
accessType = 2
}
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(2) }

View File

@@ -160,26 +160,6 @@ private module InvalidPointerToDerefBarrier {
}
}
/**
* BEWARE: This configuration uses an unrestricted sink, so accessing its full
* flow computation or any stages beyond the first 2 will likely diverge.
* Stage 1 will still be fast and we use it to restrict the subsequent sink
* computation.
*/
private module InvalidPointerReachesConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { invalidPointerToDerefSource(_, _, source) }
predicate isSink(DataFlow::Node sink) { any() }
predicate isBarrier(DataFlow::Node node) { InvalidPointerToDerefConfig::isBarrier(node) }
int fieldFlowBranchLimit() { result = invalidPointerToDereferenceFieldFlowBranchLimit() }
}
private module InvalidPointerReachesFlow = DataFlow::Global<InvalidPointerReachesConfig>;
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
/**
* A configuration to track flow from a pointer-arithmetic operation found
* by `AllocToInvalidPointerConfig` to a dereference of the pointer.
@@ -193,13 +173,8 @@ private module InvalidPointerToDerefConfig implements DataFlow::StateConfigSig {
invalidPointerToDerefSource(_, pai, source)
}
predicate isSink(DataFlow::Node sink) {
exists(DataFlowImplCommon::NodeEx n |
InvalidPointerReachesFlow::Stages::Stage1::sinkNode(n, _) and
n.asNode() = sink and
isInvalidPointerDerefSink(sink, _, _, _, _)
)
}
pragma[inline]
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _, _, _) }
predicate isSink(DataFlow::Node sink, FlowState pai) { none() }

View File

@@ -353,6 +353,22 @@ module BoostorgAsio {
}
//////////////////////// Dataflow /////////////////////
/**
* Abstract class for flows of protocol values to the first argument of a context
* constructor.
*/
abstract deprecated class SslContextCallAbstractConfig extends DataFlow::Configuration {
bindingset[this]
SslContextCallAbstractConfig() { any() }
override predicate isSink(DataFlow::Node sink) {
exists(ConstructorCall cc, SslContextClass c, Expr e | e = sink.asExpr() |
c.getAContructorCall() = cc and
cc.getArgument(0) = e
)
}
}
/**
* Signature for flows of protocol values to the first argument of a context
* constructor.
@@ -386,6 +402,20 @@ module BoostorgAsio {
import DataFlow::Global<C>
}
/**
* Any protocol value that flows to the first argument of a context constructor.
*/
deprecated class SslContextCallConfig extends SslContextCallAbstractConfig {
SslContextCallConfig() { this = "SslContextCallConfig" }
override predicate isSource(DataFlow::Node source) {
exists(Expr e | e = source.asExpr() |
e.fromSource() and
not e.getLocation().getFile().toString().matches("%/boost/asio/%")
)
}
}
/**
* Any protocol value that flows to the first argument of a context constructor.
*/
@@ -400,6 +430,21 @@ module BoostorgAsio {
module SslContextCallFlow = SslContextCallGlobal<SslContextCallConfig>;
/**
* A banned protocol value that flows to the first argument of a context constructor.
*/
deprecated class SslContextCallBannedProtocolConfig extends SslContextCallAbstractConfig {
SslContextCallBannedProtocolConfig() { this = "SslContextCallBannedProtocolConfig" }
override predicate isSource(DataFlow::Node source) {
exists(Expr e | e = source.asExpr() |
e.fromSource() and
not e.getLocation().getFile().toString().matches("%/boost/asio/%") and
isExprBannedBoostProtocol(e)
)
}
}
/**
* A banned protocol value that flows to the first argument of a context constructor.
*/
@@ -416,6 +461,21 @@ module BoostorgAsio {
module SslContextCallBannedProtocolFlow =
SslContextCallGlobal<SslContextCallBannedProtocolConfig>;
/**
* A TLS 1.2 protocol value that flows to the first argument of a context constructor.
*/
deprecated class SslContextCallTls12ProtocolConfig extends SslContextCallAbstractConfig {
SslContextCallTls12ProtocolConfig() { this = "SslContextCallTls12ProtocolConfig" }
override predicate isSource(DataFlow::Node source) {
exists(Expr e | e = source.asExpr() |
e.fromSource() and
not e.getLocation().getFile().toString().matches("%/boost/asio/%") and
isExprTls12BoostProtocol(e)
)
}
}
/**
* A TLS 1.2 protocol value that flows to the first argument of a context constructor.
*/
@@ -431,6 +491,21 @@ module BoostorgAsio {
module SslContextCallTls12ProtocolFlow = SslContextCallGlobal<SslContextCallTls12ProtocolConfig>;
/**
* A TLS 1.3 protocol value that flows to the first argument of a context constructor.
*/
deprecated class SslContextCallTls13ProtocolConfig extends SslContextCallAbstractConfig {
SslContextCallTls13ProtocolConfig() { this = "SslContextCallTls12ProtocolConfig" }
override predicate isSource(DataFlow::Node source) {
exists(Expr e | e = source.asExpr() |
e.fromSource() and
not e.getLocation().getFile().toString().matches("%/boost/asio/%") and
isExprTls13BoostProtocol(e)
)
}
}
/**
* A TLS 1.3 protocol value that flows to the first argument of a context constructor.
*/
@@ -446,6 +521,21 @@ module BoostorgAsio {
module SslContextCallTls13ProtocolFlow = SslContextCallGlobal<SslContextCallTls13ProtocolConfig>;
/**
* A generic TLS protocol value that flows to the first argument of a context constructor.
*/
deprecated class SslContextCallTlsProtocolConfig extends SslContextCallAbstractConfig {
SslContextCallTlsProtocolConfig() { this = "SslContextCallTlsProtocolConfig" }
override predicate isSource(DataFlow::Node source) {
exists(Expr e | e = source.asExpr() |
e.fromSource() and
not e.getLocation().getFile().toString().matches("%/boost/asio/%") and
isExprTlsBoostProtocol(e)
)
}
}
/**
* A generic TLS protocol value that flows to the first argument of a context constructor.
*/
@@ -461,6 +551,30 @@ module BoostorgAsio {
module SslContextCallTlsProtocolFlow = SslContextCallGlobal<SslContextCallTlsProtocolConfig>;
/**
* A context constructor call that flows to a call to `SetOptions()`.
*/
deprecated class SslContextFlowsToSetOptionConfig extends DataFlow::Configuration {
SslContextFlowsToSetOptionConfig() { this = "SslContextFlowsToSetOptionConfig" }
override predicate isSource(DataFlow::Node source) {
exists(SslContextClass c, ConstructorCall cc |
cc = source.asExpr() and
c.getAContructorCall() = cc
)
}
override predicate isSink(DataFlow::Node sink) {
exists(FunctionCall fc, SslSetOptionsFunction f, Variable v, VariableAccess va |
va = sink.asExpr()
|
f.getACallToThisFunction() = fc and
v.getAnAccess() = va and
va = fc.getQualifier()
)
}
}
/**
* A context constructor call that flows to a call to `SetOptions()`.
*/
@@ -485,6 +599,28 @@ module BoostorgAsio {
module SslContextFlowsToSetOptionFlow = DataFlow::Global<SslContextFlowsToSetOptionConfig>;
/**
* An option value that flows to the first parameter of a call to `SetOptions()`.
*/
deprecated class SslOptionConfig extends DataFlow::Configuration {
SslOptionConfig() { this = "SslOptionConfig" }
override predicate isSource(DataFlow::Node source) {
exists(Expr e | e = source.asExpr() |
e.fromSource() and
not e.getLocation().getFile().toString().matches("%/boost/asio/%")
)
}
override predicate isSink(DataFlow::Node sink) {
exists(SslSetOptionsFunction f, FunctionCall call |
sink.asExpr() = call.getArgument(0) and
f.getACallToThisFunction() = call and
not sink.getLocation().getFile().toString().matches("%/boost/asio/%")
)
}
}
/**
* An option value that flows to the first parameter of a call to `SetOptions()`.
*/

View File

@@ -72,6 +72,7 @@ module FlowFromFree<FlowFromFreeParamSig P> {
predicate isSource(DataFlow::Node node, FlowState state) { isFree(node, _, state, _) }
pragma[inline]
predicate isSink(DataFlow::Node sink, FlowState state) {
exists(Expr e, DataFlow::Node source, DeallocationExpr dealloc |
P::isSink(sink, e) and

View File

@@ -384,23 +384,11 @@ function_return_type(
*/
coroutine(
unique int function: @function ref,
int traits: @type ref
int traits: @type ref,
int handle: @variable ref,
int promise: @variable ref
);
/*
case @coroutine_placeholder_variable.kind of
1 = @handle
| 2 = @promise
| 3 = @init_await_resume
;
*/
coroutine_placeholder_variable(
unique int placeholder_variable: @variable ref,
int kind: int ref,
int function: @function ref
)
/** The `new` function used for allocating the coroutine state, if any. */
coroutine_new(
unique int function: @function ref,
@@ -841,6 +829,22 @@ variable_template_argument_value(
int arg_value: @expr ref
);
/*
Fixed point types
precision(1) = short, precision(2) = default, precision(3) = long
is_unsigned(1) = unsigned is_unsigned(2) = signed
is_fract_type(1) = declared with _Fract
saturating(1) = declared with _Sat
*/
/* TODO
fixedpointtypes(
unique int id: @fixedpointtype,
int precision: int ref,
int is_unsigned: int ref,
int is_fract_type: int ref,
int saturating: int ref);
*/
routinetypes(
unique int id: @routinetype,
int return_type: @type ref
@@ -1206,7 +1210,6 @@ conversionkinds(
| @reference_to
| @ref_indirect
| @temp_init
| @c11_generic
;
/*
@@ -1789,8 +1792,6 @@ case @expr.kind of
| 386 = @isscopedenum
| 387 = @istriviallyrelocatable
| 388 = @datasizeof
| 389 = @c11_generic
| 390 = @requires_expr
;
@var_args_expr = @vastartexpr

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +0,0 @@
description: Expose C11 _Generics
compatibility: backwards

View File

@@ -1,4 +0,0 @@
description: Improve handling of coroutine placeholder variables
compatibility: partial
coroutine.rel: run upgrades.qlo new_coroutine
coroutine_placeholder_variable.rel: run upgrades.qlo new_coroutine_placeholder_variable

View File

@@ -1,19 +0,0 @@
class Function extends @function {
string toString() { none() }
}
class Type extends @type {
string toString() { none() }
}
class Variable extends @variable {
string toString() { none() }
}
query predicate new_coroutine(Function func, Type traits) { coroutine(func, traits, _, _) }
query predicate new_coroutine_placeholder_variable(Variable var, int kind, Function func) {
coroutine(func, _, var, _) and kind = 1
or
coroutine(func, _, _, var) and kind = 2
}

View File

@@ -1,2 +0,0 @@
description: Add requires expressions
compatibility: full

View File

@@ -57,5 +57,5 @@ where
not declarationHasSideEffects(v) and
not exists(AsmStmt s | f = s.getEnclosingFunction()) and
not v.getAnAttribute().getName() = "unused" and
not f.hasErrors() // Unextracted expressions may use `v`
not any(ErrorExpr e).getEnclosingFunction() = f // unextracted expr may use `v`
select v, "Variable " + v.getName() + " is not used."

View File

@@ -1,21 +1,3 @@
## 1.2.4
### Minor Analysis Improvements
* Fixed false positives in the `cpp/wrong-number-format-arguments` ("Too few arguments to formatting function") query when the formatting function has been declared implicitly.
## 1.2.3
### Minor Analysis Improvements
* Removed false positives caused by buffer accesses in unreachable code
* Removed false positives caused by inconsistent type checking
* Add modeling of C functions that don't throw, thereby increasing the precision of the `cpp/incorrect-allocation-error-handling` ("Incorrect allocation-error handling") query. The query now produces additional true positives.
## 1.2.2
No user-facing changes.
## 1.2.1
### Minor Analysis Improvements

View File

@@ -42,9 +42,7 @@ class BufferAccess extends ArrayExpr {
not exists(Macro m |
m.getName() = "strcmp" and
m.getAnInvocation().getAnExpandedElement() = this
) and
//A buffer access must be reachable (not in dead code)
reachable(this)
)
}
int bufferSize() { staticBuffer(this.getArrayBase(), _, result) }

View File

@@ -205,6 +205,20 @@ class ChecksForLeapYearFunctionCall extends FunctionCall {
ChecksForLeapYearFunctionCall() { this.getTarget() instanceof ChecksForLeapYearFunction }
}
/**
* Data flow configuration for finding a variable access that would flow into
* a function call that includes an operation to check for leap year.
*/
deprecated class LeapYearCheckConfiguration extends DataFlow::Configuration {
LeapYearCheckConfiguration() { this = "LeapYearCheckConfiguration" }
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof VariableAccess }
override predicate isSink(DataFlow::Node sink) {
exists(ChecksForLeapYearFunctionCall fc | sink.asExpr() = fc.getAnArgument())
}
}
/**
* Data flow configuration for finding a variable access that would flow into
* a function call that includes an operation to check for leap year.
@@ -219,6 +233,33 @@ private module LeapYearCheckConfig implements DataFlow::ConfigSig {
module LeapYearCheckFlow = DataFlow::Global<LeapYearCheckConfig>;
/**
* Data flow configuration for finding an operation with hardcoded 365 that will flow into
* a `FILEINFO` field.
*/
deprecated class FiletimeYearArithmeticOperationCheckConfiguration extends DataFlow::Configuration {
FiletimeYearArithmeticOperationCheckConfiguration() {
this = "FiletimeYearArithmeticOperationCheckConfiguration"
}
override predicate isSource(DataFlow::Node source) {
exists(Expr e, Operation op | e = source.asExpr() |
op.getAChild*().getValue().toInt() = 365 and
op.getAChild*() = e
)
}
override predicate isSink(DataFlow::Node sink) {
exists(StructLikeClass dds, FieldAccess fa, AssignExpr aexpr, Expr e | e = sink.asExpr() |
dds instanceof PackedTimeType and
fa.getQualifier().getUnderlyingType() = dds and
fa.isModified() and
aexpr.getAChild() = fa and
aexpr.getChild(1).getAChild*() = e
)
}
}
/**
* Data flow configuration for finding an operation with hardcoded 365 that will flow into
* a `FILEINFO` field.
@@ -245,6 +286,51 @@ private module FiletimeYearArithmeticOperationCheckConfig implements DataFlow::C
module FiletimeYearArithmeticOperationCheckFlow =
DataFlow::Global<FiletimeYearArithmeticOperationCheckConfig>;
/**
* Taint configuration for finding an operation with hardcoded 365 that will flow into any known date/time field.
*/
deprecated class PossibleYearArithmeticOperationCheckConfiguration extends TaintTracking::Configuration
{
PossibleYearArithmeticOperationCheckConfiguration() {
this = "PossibleYearArithmeticOperationCheckConfiguration"
}
override predicate isSource(DataFlow::Node source) {
exists(Operation op | op = source.asExpr() |
op.getAChild*().getValue().toInt() = 365 and
(
not op.getParent() instanceof Expr or
op.getParent() instanceof Assignment
)
)
}
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
// flow from anything on the RHS of an assignment to a time/date structure to that
// assignment.
exists(StructLikeClass dds, FieldAccess fa, Assignment aexpr, Expr e |
e = node1.asExpr() and
fa = node2.asExpr()
|
(dds instanceof PackedTimeType or dds instanceof UnpackedTimeType) and
fa.getQualifier().getUnderlyingType() = dds and
aexpr.getLValue() = fa and
aexpr.getRValue().getAChild*() = e
)
}
override predicate isSink(DataFlow::Node sink) {
exists(StructLikeClass dds, FieldAccess fa, AssignExpr aexpr |
aexpr.getRValue() = sink.asExpr()
|
(dds instanceof PackedTimeType or dds instanceof UnpackedTimeType) and
fa.getQualifier().getUnderlyingType() = dds and
fa.isModified() and
aexpr.getLValue() = fa
)
}
}
/**
* Taint configuration for finding an operation with hardcoded 365 that will flow into any known date/time field.
*/

View File

@@ -129,6 +129,24 @@ class NetworkFunctionCall extends FunctionCall {
NetworkFunctionCall() { this.getTarget().hasName(["ntohd", "ntohf", "ntohl", "ntohll", "ntohs"]) }
}
deprecated class NetworkToBufferSizeConfiguration extends DataFlow::Configuration {
NetworkToBufferSizeConfiguration() { this = "NetworkToBufferSizeConfiguration" }
override predicate isSource(DataFlow::Node node) { node.asExpr() instanceof NetworkFunctionCall }
override predicate isSink(DataFlow::Node node) {
node.asExpr() = any(BufferAccess ba).getAccessedLength()
}
override predicate isBarrier(DataFlow::Node node) {
exists(GuardCondition gc, GVN gvn |
gc.getAChild*() = gvn.getAnExpr() and
globalValueNumber(node.asExpr()) = gvn and
gc.controls(node.asExpr().getBasicBlock(), _)
)
}
}
private module NetworkToBufferSizeConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof NetworkFunctionCall }

View File

@@ -29,7 +29,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
override predicate isSource(Instruction source) {
exists(Function func |
// Rule out FPs caused by extraction errors.
not func.hasErrors() and
not any(ErrorExpr e).getEnclosingFunction() = func and
not intentionallyReturnsStackPointer(func) and
func = source.getEnclosingFunction()
|

View File

@@ -65,7 +65,6 @@ predicate isSinkImpl(Instruction sink, VariableAccess va) {
exists(LoadInstruction load |
va = load.getUnconvertedResultExpression() and
not va = commonException() and
not va.getTarget().(LocalVariable).getFunction().hasErrors() and
sink = load.getSourceValue()
)
}

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