mirror of
https://github.com/github/codeql.git
synced 2026-05-26 17:11:24 +02:00
Compare commits
11 Commits
alexet/all
...
move-cors-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3d608fa33 | ||
|
|
6c751ce934 | ||
|
|
4dac80a998 | ||
|
|
021aa13ee2 | ||
|
|
791a7e242e | ||
|
|
2baca58b27 | ||
|
|
fd4233e30e | ||
|
|
84ffbbec33 | ||
|
|
95743d7109 | ||
|
|
92daa7d42c | ||
|
|
358617f533 |
7
.bazelrc
7
.bazelrc
@@ -30,13 +30,6 @@ common --registry=https://bcr.bazel.build
|
||||
|
||||
common --@rules_dotnet//dotnet/settings:strict_deps=false
|
||||
|
||||
# we only configure a nightly toolchain
|
||||
common --@rules_rust//rust/toolchain/channel=nightly
|
||||
|
||||
# rust does not like the gold linker, while bazel does by default, so let's avoid using it
|
||||
common:linux --linkopt=-fuse-ld=lld
|
||||
common:macos --linkopt=-fuse-ld=lld
|
||||
|
||||
# Reduce this eventually to empty, once we've fixed all our usages of java, and https://github.com/bazel-contrib/rules_go/issues/4193 is fixed
|
||||
common --incompatible_autoload_externally="+@rules_java,+@rules_shell"
|
||||
|
||||
|
||||
57
MODULE.bazel
57
MODULE.bazel
@@ -15,7 +15,7 @@ local_path_override(
|
||||
# see https://registry.bazel.build/ for a list of available packages
|
||||
|
||||
bazel_dep(name = "platforms", version = "0.0.11")
|
||||
bazel_dep(name = "rules_go", version = "0.56.1")
|
||||
bazel_dep(name = "rules_go", version = "0.50.1")
|
||||
bazel_dep(name = "rules_pkg", version = "1.0.1")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.2.0-codeql.1")
|
||||
bazel_dep(name = "rules_python", version = "0.40.0")
|
||||
@@ -28,7 +28,7 @@ bazel_dep(name = "rules_kotlin", version = "2.1.3-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.40.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.17.4")
|
||||
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
|
||||
bazel_dep(name = "rules_rust", version = "0.63.0")
|
||||
bazel_dep(name = "rules_rust", version = "0.58.0")
|
||||
bazel_dep(name = "zstd", version = "1.5.5.bcr.1")
|
||||
|
||||
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
|
||||
@@ -38,10 +38,7 @@ bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True
|
||||
RUST_EDITION = "2024"
|
||||
|
||||
# run buildutils-internal/scripts/fill-rust-sha256s.py when updating (internal repo)
|
||||
# a nightly toolchain is required to enable experimental_use_cc_common_link, which we require internally
|
||||
# we prefer to run the same version as internally, even if experimental_use_cc_common_link is not really
|
||||
# required in this repo
|
||||
RUST_VERSION = "nightly/2025-08-01"
|
||||
RUST_VERSION = "1.86.0"
|
||||
|
||||
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
|
||||
rust.toolchain(
|
||||
@@ -53,26 +50,26 @@ rust.toolchain(
|
||||
],
|
||||
# generated by buildutils-internal/scripts/fill-rust-sha256s.py (internal repo)
|
||||
sha256s = {
|
||||
"2025-08-01/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "9bbeaf5d3fc7247d31463a9083aa251c995cc50662c8219e7a2254d76a72a9a4",
|
||||
"2025-08-01/rustc-nightly-x86_64-apple-darwin.tar.xz": "c9ea539a8eff0d5d162701f99f9e1aabe14dd0dfb420d62362817a5d09219de7",
|
||||
"2025-08-01/rustc-nightly-aarch64-apple-darwin.tar.xz": "ae83feebbc39cfd982e4ecc8297731fe79c185173aee138467b334c5404b3773",
|
||||
"2025-08-01/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "9f170c30d802a349be60cf52ec46260802093cb1013ad667fc0d528b7b10152f",
|
||||
"2025-08-01/clippy-nightly-x86_64-unknown-linux-gnu.tar.xz": "9ae5f3cd8f557c4f6df522597c69d14398cf604cfaed2b83e767c4b77a7eaaf6",
|
||||
"2025-08-01/clippy-nightly-x86_64-apple-darwin.tar.xz": "983cb9ee0b6b968188e04ab2d33743d54764b2681ce565e1b3f2b9135c696a3e",
|
||||
"2025-08-01/clippy-nightly-aarch64-apple-darwin.tar.xz": "ed2219dbc49d088225e1b7c5c4390fa295066e071fddaa2714018f6bb39ddbf0",
|
||||
"2025-08-01/clippy-nightly-x86_64-pc-windows-msvc.tar.xz": "911f40ab5cbdd686f40e00965271fe47c4805513a308ed01f30eafb25b448a50",
|
||||
"2025-08-01/cargo-nightly-x86_64-unknown-linux-gnu.tar.xz": "106463c284e48e4904c717471eeec2be5cc83a9d2cae8d6e948b52438cad2e69",
|
||||
"2025-08-01/cargo-nightly-x86_64-apple-darwin.tar.xz": "6ad35c40efc41a8c531ea43235058347b6902d98a9693bf0aed7fc16d5590cef",
|
||||
"2025-08-01/cargo-nightly-aarch64-apple-darwin.tar.xz": "dd28c365e9d298abc3154c797720ad36a0058f131265c9978b4c8e4e37012c8a",
|
||||
"2025-08-01/cargo-nightly-x86_64-pc-windows-msvc.tar.xz": "7b431286e12d6b3834b038f078389a00cac73f351e8c3152b2504a3c06420b3b",
|
||||
"2025-08-01/llvm-tools-nightly-x86_64-unknown-linux-gnu.tar.xz": "e342e305d7927cc288d386983b2bc253cfad3776b113386e903d0b302648ef47",
|
||||
"2025-08-01/llvm-tools-nightly-x86_64-apple-darwin.tar.xz": "e44dd3506524d85c37b3a54bcc91d01378fd2c590b2db5c5974d12f05c1b84d1",
|
||||
"2025-08-01/llvm-tools-nightly-aarch64-apple-darwin.tar.xz": "0c1b5f46dd81be4a9227b10283a0fcaa39c14fea7e81aea6fd6d9887ff6cdc41",
|
||||
"2025-08-01/llvm-tools-nightly-x86_64-pc-windows-msvc.tar.xz": "423e5fd11406adccbc31b8456ceb7375ce055cdf45e90d2c3babeb2d7f58383f",
|
||||
"2025-08-01/rust-std-nightly-x86_64-unknown-linux-gnu.tar.xz": "3c0ceb46a252647a1d4c7116d9ccae684fa5e42aaf3296419febd2c962c3b41d",
|
||||
"2025-08-01/rust-std-nightly-x86_64-apple-darwin.tar.xz": "3be416003cab10f767390a753d1d16ae4d26c7421c03c98992cf1943e5b0efe8",
|
||||
"2025-08-01/rust-std-nightly-aarch64-apple-darwin.tar.xz": "4046ac0ef951cb056b5028a399124f60999fa37792eab69d008d8d7965f389b4",
|
||||
"2025-08-01/rust-std-nightly-x86_64-pc-windows-msvc.tar.xz": "191ed9d8603c3a4fe5a7bbbc2feb72049078dae2df3d3b7d5dedf3abbf823e6e",
|
||||
"rustc-1.86.0-x86_64-unknown-linux-gnu.tar.xz": "4438b809ce4a083af31ed17aeeedcc8fc60ccffc0625bef1926620751b6989d7",
|
||||
"rustc-1.86.0-x86_64-apple-darwin.tar.xz": "42b76253626febb7912541a30d3379f463dec89581aad4cb72c6c04fb5a71dc5",
|
||||
"rustc-1.86.0-aarch64-apple-darwin.tar.xz": "23b8f52102249a47ab5bc859d54c9a3cb588a3259ba3f00f557d50edeca4fde9",
|
||||
"rustc-1.86.0-x86_64-pc-windows-msvc.tar.xz": "fdde839fea274529a31e51eb85c6df1782cc8479c9d1bc24e2914d66a0de41ab",
|
||||
"clippy-1.86.0-x86_64-unknown-linux-gnu.tar.xz": "02aaff2c1407d2da8dba19aa4970dd873e311902b120a66cbcdbe51eb8836edf",
|
||||
"clippy-1.86.0-x86_64-apple-darwin.tar.xz": "bb85efda7bbffaf124867f5ca36d50932b1e8f533c62ee923438afb32ff8fe9a",
|
||||
"clippy-1.86.0-aarch64-apple-darwin.tar.xz": "239fa3a604b124f0312f2af08537874a1227dba63385484b468cca62e7c4f2f2",
|
||||
"clippy-1.86.0-x86_64-pc-windows-msvc.tar.xz": "d00498f47d49219f032e2c5eeebdfc3d32317c0dc3d3fd7125327445bc482cb4",
|
||||
"cargo-1.86.0-x86_64-unknown-linux-gnu.tar.xz": "c5c1590f7e9246ad9f4f97cfe26ffa92707b52a769726596a9ef81565ebd908b",
|
||||
"cargo-1.86.0-x86_64-apple-darwin.tar.xz": "af163eb02d1a178044d1b4f2375960efd47130f795f6e33d09e345454bb26f4e",
|
||||
"cargo-1.86.0-aarch64-apple-darwin.tar.xz": "3cb13873d48c3e1e4cc684d42c245226a11fba52af6b047c3346ed654e7a05c0",
|
||||
"cargo-1.86.0-x86_64-pc-windows-msvc.tar.xz": "e57a9d89619b5604899bac443e68927bdd371e40f2e03e18950b6ceb3eb67966",
|
||||
"llvm-tools-1.86.0-x86_64-unknown-linux-gnu.tar.xz": "282145ab7a63c98b625856f44b905b4dc726b497246b824632a5790debe95a78",
|
||||
"llvm-tools-1.86.0-x86_64-apple-darwin.tar.xz": "b55706e92f7da989207c50c13c7add483a9fedd233bc431b106eca2a8f151ec9",
|
||||
"llvm-tools-1.86.0-aarch64-apple-darwin.tar.xz": "04d3618c686845853585f036e3211eb9e18f2d290f4610a7a78bdc1fcce1ebd9",
|
||||
"llvm-tools-1.86.0-x86_64-pc-windows-msvc.tar.xz": "721a17cc8dc219177e4277a3592253934ef08daa1e1b12eda669a67d15fad8dd",
|
||||
"rust-std-1.86.0-x86_64-unknown-linux-gnu.tar.xz": "67be7184ea388d8ce0feaf7fdea46f1775cfc2970930264343b3089898501d37",
|
||||
"rust-std-1.86.0-x86_64-apple-darwin.tar.xz": "3b1140d54870a080080e84700143f4a342fbd02a410a319b05d9c02e7dcf44cc",
|
||||
"rust-std-1.86.0-aarch64-apple-darwin.tar.xz": "0fb121fb3b8fa9027d79ff598500a7e5cd086ddbc3557482ed3fdda00832c61b",
|
||||
"rust-std-1.86.0-x86_64-pc-windows-msvc.tar.xz": "3d5354b7b9cb950b58bff3fce18a652aa374bb30c8f70caebd3bd0b43cb41a33",
|
||||
},
|
||||
versions = [RUST_VERSION],
|
||||
)
|
||||
@@ -233,7 +230,7 @@ use_repo(
|
||||
"kotlin-compiler-2.1.0-Beta1",
|
||||
"kotlin-compiler-2.1.20-Beta1",
|
||||
"kotlin-compiler-2.2.0-Beta1",
|
||||
"kotlin-compiler-2.2.20-Beta2",
|
||||
"kotlin-compiler-2.2.20-Beta1",
|
||||
"kotlin-compiler-embeddable-1.6.0",
|
||||
"kotlin-compiler-embeddable-1.6.20",
|
||||
"kotlin-compiler-embeddable-1.7.0",
|
||||
@@ -246,7 +243,7 @@ use_repo(
|
||||
"kotlin-compiler-embeddable-2.1.0-Beta1",
|
||||
"kotlin-compiler-embeddable-2.1.20-Beta1",
|
||||
"kotlin-compiler-embeddable-2.2.0-Beta1",
|
||||
"kotlin-compiler-embeddable-2.2.20-Beta2",
|
||||
"kotlin-compiler-embeddable-2.2.20-Beta1",
|
||||
"kotlin-stdlib-1.6.0",
|
||||
"kotlin-stdlib-1.6.20",
|
||||
"kotlin-stdlib-1.7.0",
|
||||
@@ -259,11 +256,11 @@ use_repo(
|
||||
"kotlin-stdlib-2.1.0-Beta1",
|
||||
"kotlin-stdlib-2.1.20-Beta1",
|
||||
"kotlin-stdlib-2.2.0-Beta1",
|
||||
"kotlin-stdlib-2.2.20-Beta2",
|
||||
"kotlin-stdlib-2.2.20-Beta1",
|
||||
)
|
||||
|
||||
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
|
||||
go_sdk.download(version = "1.25.0")
|
||||
go_sdk.download(version = "1.24.0")
|
||||
|
||||
go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
|
||||
go_deps.from_file(go_mod = "//go/extractor:go.mod")
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
## 0.4.15
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.14
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.13
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.14
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.15
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.15
|
||||
lastReleaseVersion: 0.4.13
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
private import actions
|
||||
private import codeql.actions.TaintTracking
|
||||
private import codeql.actions.dataflow.ExternalFlow
|
||||
private import codeql.actions.security.ControlChecks
|
||||
import codeql.actions.dataflow.FlowSources
|
||||
import codeql.actions.DataFlow
|
||||
|
||||
@@ -66,16 +65,6 @@ class ArgumentInjectionFromMaDSink extends ArgumentInjectionSink {
|
||||
override string getCommand() { result = "unknown" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the event that is relevant for the given node in the context of argument injection.
|
||||
*
|
||||
* This is used to highlight the event in the query results when an alert is raised.
|
||||
*/
|
||||
Event getRelevantEventInPrivilegedContext(DataFlow::Node node) {
|
||||
inPrivilegedContext(node.asExpr(), result) and
|
||||
not exists(ControlCheck check | check.protects(node.asExpr(), result, "argument-injection"))
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unsafe user input
|
||||
* that is used to construct and evaluate a code script.
|
||||
@@ -99,16 +88,6 @@ private module ArgumentInjectionConfig implements DataFlow::ConfigSig {
|
||||
run.getScript().getAnEnvReachingArgumentInjectionSink(var, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
result = sink.getLocation()
|
||||
or
|
||||
result = getRelevantEventInPrivilegedContext(sink).getLocation()
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks flow of unsafe user input that is used to construct and evaluate a code script. */
|
||||
|
||||
@@ -4,7 +4,6 @@ import codeql.actions.DataFlow
|
||||
import codeql.actions.dataflow.FlowSources
|
||||
import codeql.actions.security.PoisonableSteps
|
||||
import codeql.actions.security.UntrustedCheckoutQuery
|
||||
import codeql.actions.security.ControlChecks
|
||||
|
||||
string unzipRegexp() { result = "(unzip|tar)\\s+.*" }
|
||||
|
||||
@@ -293,16 +292,6 @@ class ArtifactPoisoningSink extends DataFlow::Node {
|
||||
string getPath() { result = download.getPath() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the event that is relevant for the given node in the context of artifact poisoning.
|
||||
*
|
||||
* This is used to highlight the event in the query results when an alert is raised.
|
||||
*/
|
||||
Event getRelevantEventInPrivilegedContext(DataFlow::Node node) {
|
||||
inPrivilegedContext(node.asExpr(), result) and
|
||||
not exists(ControlCheck check | check.protects(node.asExpr(), result, "artifact-poisoning"))
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unsafe artifacts
|
||||
* that is used may lead to artifact poisoning
|
||||
@@ -329,16 +318,6 @@ private module ArtifactPoisoningConfig implements DataFlow::ConfigSig {
|
||||
exists(run.getScript().getAFileReadCommand())
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
result = sink.getLocation()
|
||||
or
|
||||
result = getRelevantEventInPrivilegedContext(sink).getLocation()
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks flow of unsafe artifacts that is used in an insecure way. */
|
||||
|
||||
@@ -3,8 +3,6 @@ private import codeql.actions.TaintTracking
|
||||
private import codeql.actions.dataflow.ExternalFlow
|
||||
import codeql.actions.dataflow.FlowSources
|
||||
import codeql.actions.DataFlow
|
||||
import codeql.actions.security.ControlChecks
|
||||
import codeql.actions.security.CachePoisoningQuery
|
||||
|
||||
class CodeInjectionSink extends DataFlow::Node {
|
||||
CodeInjectionSink() {
|
||||
@@ -13,46 +11,6 @@ class CodeInjectionSink extends DataFlow::Node {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the relevant event for the sink in CodeInjectionCritical.ql.
|
||||
*/
|
||||
Event getRelevantCriticalEventForSink(DataFlow::Node sink) {
|
||||
inPrivilegedContext(sink.asExpr(), result) and
|
||||
not exists(ControlCheck check | check.protects(sink.asExpr(), result, "code-injection")) and
|
||||
// exclude cases where the sink is a JS script and the expression uses toJson
|
||||
not exists(UsesStep script |
|
||||
script.getCallee() = "actions/github-script" and
|
||||
script.getArgumentExpr("script") = sink.asExpr() and
|
||||
exists(getAToJsonReferenceExpression(sink.asExpr().(Expression).getExpression(), _))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the relevant event for the sink in CachePoisoningViaCodeInjection.ql.
|
||||
*/
|
||||
Event getRelevantCachePoisoningEventForSink(DataFlow::Node sink) {
|
||||
exists(LocalJob job |
|
||||
job = sink.asExpr().getEnclosingJob() and
|
||||
job.getATriggerEvent() = result and
|
||||
// job can be triggered by an external user
|
||||
result.isExternallyTriggerable() and
|
||||
// excluding privileged workflows since they can be exploited in easier circumstances
|
||||
// which is covered by `actions/code-injection/critical`
|
||||
not job.isPrivilegedExternallyTriggerable(result) and
|
||||
(
|
||||
// the workflow runs in the context of the default branch
|
||||
runsOnDefaultBranch(result)
|
||||
or
|
||||
// the workflow caller runs in the context of the default branch
|
||||
result.getName() = "workflow_call" and
|
||||
exists(ExternalJob caller |
|
||||
caller.getCallee() = job.getLocation().getFile().getRelativePath() and
|
||||
runsOnDefaultBranch(caller.getATriggerEvent())
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unsafe user input
|
||||
* that is used to construct and evaluate a code script.
|
||||
@@ -77,18 +35,6 @@ private module CodeInjectionConfig implements DataFlow::ConfigSig {
|
||||
exists(run.getScript().getAFileReadCommand())
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
result = sink.getLocation()
|
||||
or
|
||||
result = getRelevantCriticalEventForSink(sink).getLocation()
|
||||
or
|
||||
result = getRelevantCachePoisoningEventForSink(sink).getLocation()
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks flow of unsafe user input that is used to construct and evaluate a code script. */
|
||||
|
||||
@@ -3,20 +3,11 @@ private import codeql.actions.TaintTracking
|
||||
private import codeql.actions.dataflow.ExternalFlow
|
||||
import codeql.actions.dataflow.FlowSources
|
||||
import codeql.actions.DataFlow
|
||||
import codeql.actions.security.ControlChecks
|
||||
|
||||
private class CommandInjectionSink extends DataFlow::Node {
|
||||
CommandInjectionSink() { madSink(this, "command-injection") }
|
||||
}
|
||||
|
||||
/** Get the relevant event for the sink in CommandInjectionCritical.ql. */
|
||||
Event getRelevantEventInPrivilegedContext(DataFlow::Node sink) {
|
||||
inPrivilegedContext(sink.asExpr(), result) and
|
||||
not exists(ControlCheck check |
|
||||
check.protects(sink.asExpr(), result, ["command-injection", "code-injection"])
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unsafe user input
|
||||
* that is used to construct and evaluate a system command.
|
||||
@@ -25,16 +16,6 @@ private module CommandInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof CommandInjectionSink }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
result = sink.getLocation()
|
||||
or
|
||||
result = getRelevantEventInPrivilegedContext(sink).getLocation()
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks flow of unsafe user input that is used to construct and evaluate a system command. */
|
||||
|
||||
@@ -72,25 +72,6 @@ class EnvPathInjectionFromMaDSink extends EnvPathInjectionSink {
|
||||
EnvPathInjectionFromMaDSink() { madSink(this, "envpath-injection") }
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the relevant event for a sink in EnvPathInjectionCritical.ql where the source type is "artifact".
|
||||
*/
|
||||
Event getRelevantArtifactEventInPrivilegedContext(DataFlow::Node sink) {
|
||||
inPrivilegedContext(sink.asExpr(), result) and
|
||||
not exists(ControlCheck check |
|
||||
check.protects(sink.asExpr(), result, ["untrusted-checkout", "artifact-poisoning"])
|
||||
) and
|
||||
sink instanceof EnvPathInjectionFromFileReadSink
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the relevant event for a sink in EnvPathInjectionCritical.ql where the source type is not "artifact".
|
||||
*/
|
||||
Event getRelevantNonArtifactEventInPrivilegedContext(DataFlow::Node sink) {
|
||||
inPrivilegedContext(sink.asExpr(), result) and
|
||||
not exists(ControlCheck check | check.protects(sink.asExpr(), result, "code-injection"))
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unsafe user input
|
||||
* that is used to construct and evaluate an environment variable.
|
||||
@@ -127,18 +108,6 @@ private module EnvPathInjectionConfig implements DataFlow::ConfigSig {
|
||||
exists(run.getScript().getAFileReadCommand())
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
result = sink.getLocation()
|
||||
or
|
||||
result = getRelevantArtifactEventInPrivilegedContext(sink).getLocation()
|
||||
or
|
||||
result = getRelevantNonArtifactEventInPrivilegedContext(sink).getLocation()
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks flow of unsafe user input that is used to construct and evaluate the PATH environment variable. */
|
||||
|
||||
@@ -126,32 +126,6 @@ class EnvVarInjectionFromMaDSink extends EnvVarInjectionSink {
|
||||
EnvVarInjectionFromMaDSink() { madSink(this, "envvar-injection") }
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the relevant event for a sink in EnvVarInjectionCritical.ql where the source type is "artifact".
|
||||
*/
|
||||
Event getRelevantArtifactEventInPrivilegedContext(DataFlow::Node sink) {
|
||||
inPrivilegedContext(sink.asExpr(), result) and
|
||||
not exists(ControlCheck check |
|
||||
check
|
||||
.protects(sink.asExpr(), result,
|
||||
["envvar-injection", "untrusted-checkout", "artifact-poisoning"])
|
||||
) and
|
||||
(
|
||||
sink instanceof EnvVarInjectionFromFileReadSink or
|
||||
madSink(sink, "envvar-injection")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the relevant event for a sink in EnvVarInjectionCritical.ql where the source type is not "artifact".
|
||||
*/
|
||||
Event getRelevantNonArtifactEventInPrivilegedContext(DataFlow::Node sink) {
|
||||
inPrivilegedContext(sink.asExpr(), result) and
|
||||
not exists(ControlCheck check |
|
||||
check.protects(sink.asExpr(), result, ["envvar-injection", "code-injection"])
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unsafe user input
|
||||
* that is used to construct and evaluate an environment variable.
|
||||
@@ -189,18 +163,6 @@ private module EnvVarInjectionConfig implements DataFlow::ConfigSig {
|
||||
exists(run.getScript().getAFileReadCommand())
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
result = sink.getLocation()
|
||||
or
|
||||
result = getRelevantArtifactEventInPrivilegedContext(sink).getLocation()
|
||||
or
|
||||
result = getRelevantNonArtifactEventInPrivilegedContext(sink).getLocation()
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks flow of unsafe user input that is used to construct and evaluate an environment variable. */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-all
|
||||
version: 0.4.16-dev
|
||||
version: 0.4.14-dev
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
## 0.6.7
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.6
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -21,12 +21,18 @@ import codeql.actions.security.ControlChecks
|
||||
from EnvPathInjectionFlow::PathNode source, EnvPathInjectionFlow::PathNode sink, Event event
|
||||
where
|
||||
EnvPathInjectionFlow::flowPath(source, sink) and
|
||||
inPrivilegedContext(sink.getNode().asExpr(), event) and
|
||||
(
|
||||
not source.getNode().(RemoteFlowSource).getSourceType() = "artifact" and
|
||||
event = getRelevantNonArtifactEventInPrivilegedContext(sink.getNode())
|
||||
not exists(ControlCheck check |
|
||||
check.protects(sink.getNode().asExpr(), event, "code-injection")
|
||||
)
|
||||
or
|
||||
source.getNode().(RemoteFlowSource).getSourceType() = "artifact" and
|
||||
event = getRelevantArtifactEventInPrivilegedContext(sink.getNode())
|
||||
not exists(ControlCheck check |
|
||||
check.protects(sink.getNode().asExpr(), event, ["untrusted-checkout", "artifact-poisoning"])
|
||||
) and
|
||||
sink.getNode() instanceof EnvPathInjectionFromFileReadSink
|
||||
)
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential PATH environment variable injection in $@, which may be controlled by an external user ($@).",
|
||||
|
||||
@@ -22,15 +22,26 @@ import codeql.actions.security.ControlChecks
|
||||
from EnvVarInjectionFlow::PathNode source, EnvVarInjectionFlow::PathNode sink, Event event
|
||||
where
|
||||
EnvVarInjectionFlow::flowPath(source, sink) and
|
||||
inPrivilegedContext(sink.getNode().asExpr(), event) and
|
||||
// exclude paths to file read sinks from non-artifact sources
|
||||
(
|
||||
// source is text
|
||||
not source.getNode().(RemoteFlowSource).getSourceType() = "artifact" and
|
||||
event = getRelevantNonArtifactEventInPrivilegedContext(sink.getNode())
|
||||
not exists(ControlCheck check |
|
||||
check.protects(sink.getNode().asExpr(), event, ["envvar-injection", "code-injection"])
|
||||
)
|
||||
or
|
||||
// source is an artifact or a file from an untrusted checkout
|
||||
source.getNode().(RemoteFlowSource).getSourceType() = "artifact" and
|
||||
event = getRelevantArtifactEventInPrivilegedContext(sink.getNode())
|
||||
not exists(ControlCheck check |
|
||||
check
|
||||
.protects(sink.getNode().asExpr(), event,
|
||||
["envvar-injection", "untrusted-checkout", "artifact-poisoning"])
|
||||
) and
|
||||
(
|
||||
sink.getNode() instanceof EnvVarInjectionFromFileReadSink or
|
||||
madSink(sink.getNode(), "envvar-injection")
|
||||
)
|
||||
)
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential environment variable injection in $@, which may be controlled by an external user ($@).",
|
||||
|
||||
@@ -22,8 +22,15 @@ import codeql.actions.security.ControlChecks
|
||||
from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink, Event event
|
||||
where
|
||||
CodeInjectionFlow::flowPath(source, sink) and
|
||||
event = getRelevantCriticalEventForSink(sink.getNode()) and
|
||||
source.getNode().(RemoteFlowSource).getEventName() = event.getName()
|
||||
inPrivilegedContext(sink.getNode().asExpr(), event) and
|
||||
source.getNode().(RemoteFlowSource).getEventName() = event.getName() and
|
||||
not exists(ControlCheck check | check.protects(sink.getNode().asExpr(), event, "code-injection")) and
|
||||
// exclude cases where the sink is a JS script and the expression uses toJson
|
||||
not exists(UsesStep script |
|
||||
script.getCallee() = "actions/github-script" and
|
||||
script.getArgumentExpr("script") = sink.getNode().asExpr() and
|
||||
exists(getAToJsonReferenceExpression(sink.getNode().asExpr().(Expression).getExpression(), _))
|
||||
)
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential code injection in $@, which may be controlled by an external user ($@).", sink,
|
||||
sink.getNode().asExpr().(Expression).getRawExpression(), event, event.getName()
|
||||
|
||||
@@ -18,13 +18,30 @@ import codeql.actions.security.CachePoisoningQuery
|
||||
import CodeInjectionFlow::PathGraph
|
||||
import codeql.actions.security.ControlChecks
|
||||
|
||||
from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink, Event event
|
||||
from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink, LocalJob job, Event event
|
||||
where
|
||||
CodeInjectionFlow::flowPath(source, sink) and
|
||||
event = getRelevantCachePoisoningEventForSink(sink.getNode()) and
|
||||
job = sink.getNode().asExpr().getEnclosingJob() and
|
||||
job.getATriggerEvent() = event and
|
||||
// job can be triggered by an external user
|
||||
event.isExternallyTriggerable() and
|
||||
// the checkout is not controlled by an access check
|
||||
not exists(ControlCheck check |
|
||||
check.protects(source.getNode().asExpr(), event, "code-injection")
|
||||
) and
|
||||
// excluding privileged workflows since they can be exploited in easier circumstances
|
||||
// which is covered by `actions/code-injection/critical`
|
||||
not job.isPrivilegedExternallyTriggerable(event) and
|
||||
(
|
||||
// the workflow runs in the context of the default branch
|
||||
runsOnDefaultBranch(event)
|
||||
or
|
||||
// the workflow caller runs in the context of the default branch
|
||||
event.getName() = "workflow_call" and
|
||||
exists(ExternalJob caller |
|
||||
caller.getCallee() = job.getLocation().getFile().getRelativePath() and
|
||||
runsOnDefaultBranch(caller.getATriggerEvent())
|
||||
)
|
||||
)
|
||||
select sink.getNode(), source, sink,
|
||||
"Unprivileged code injection in $@, which may lead to cache poisoning ($@).", sink,
|
||||
|
||||
@@ -19,7 +19,10 @@ import codeql.actions.security.ControlChecks
|
||||
from ArtifactPoisoningFlow::PathNode source, ArtifactPoisoningFlow::PathNode sink, Event event
|
||||
where
|
||||
ArtifactPoisoningFlow::flowPath(source, sink) and
|
||||
event = getRelevantEventInPrivilegedContext(sink.getNode())
|
||||
inPrivilegedContext(sink.getNode().asExpr(), event) and
|
||||
not exists(ControlCheck check |
|
||||
check.protects(sink.getNode().asExpr(), event, "artifact-poisoning")
|
||||
)
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential artifact poisoning in $@, which may be controlled by an external user ($@).", sink,
|
||||
sink.getNode().toString(), event, event.getName()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Overview
|
||||
|
||||
GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. A potentially dangerous misuse of the triggers such as `pull_request_target` or `issue_comment` followed by an explicit checkout of untrusted code (Pull Request HEAD) may lead to repository compromise if untrusted code gets executed (e.g., due to a modified build script) in a privileged job.
|
||||
GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. A potentially dangerous misuse of the triggers such as `pull_request_target` or `issue_comment` followed by an explicit checkout of untrusted code (Pull Request HEAD) may lead to repository compromise if untrusted code gets executed in a privileged job.
|
||||
|
||||
## Recommendation
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v1
|
||||
- run: |
|
||||
npm install # scripts in package.json from PR would be executed here
|
||||
npm install
|
||||
npm build
|
||||
|
||||
- uses: completely/fakeaction@v2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Overview
|
||||
|
||||
GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. A potentially dangerous misuse of the triggers such as `pull_request_target` or `issue_comment` followed by an explicit checkout of untrusted code (Pull Request HEAD) may lead to repository compromise if untrusted code gets executed (e.g., due to a modified build script) in a privileged job.
|
||||
GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. A potentially dangerous misuse of the triggers such as `pull_request_target` or `issue_comment` followed by an explicit checkout of untrusted code (Pull Request HEAD) may lead to repository compromise if untrusted code gets executed in a privileged job.
|
||||
|
||||
## Recommendation
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v1
|
||||
- run: |
|
||||
npm install # scripts in package.json from PR would be executed here
|
||||
npm install
|
||||
npm build
|
||||
|
||||
- uses: completely/fakeaction@v2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Overview
|
||||
|
||||
GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. A potentially dangerous misuse of the triggers such as `pull_request_target` or `issue_comment` followed by an explicit checkout of untrusted code (Pull Request HEAD) may lead to repository compromise if untrusted code gets executed (e.g., due to a modified build script) in a privileged job.
|
||||
GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. A potentially dangerous misuse of the triggers such as `pull_request_target` or `issue_comment` followed by an explicit checkout of untrusted code (Pull Request HEAD) may lead to repository compromise if untrusted code gets executed in a privileged job.
|
||||
|
||||
## Recommendation
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v1
|
||||
- run: |
|
||||
npm install # scripts in package.json from PR would be executed here
|
||||
npm install
|
||||
npm build
|
||||
|
||||
- uses: completely/fakeaction@v2
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.6
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.7
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.7
|
||||
lastReleaseVersion: 0.6.5
|
||||
|
||||
@@ -21,7 +21,10 @@ import codeql.actions.security.ControlChecks
|
||||
from CommandInjectionFlow::PathNode source, CommandInjectionFlow::PathNode sink, Event event
|
||||
where
|
||||
CommandInjectionFlow::flowPath(source, sink) and
|
||||
event = getRelevantEventInPrivilegedContext(sink.getNode())
|
||||
inPrivilegedContext(sink.getNode().asExpr(), event) and
|
||||
not exists(ControlCheck check |
|
||||
check.protects(sink.getNode().asExpr(), event, ["command-injection", "code-injection"])
|
||||
)
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential command injection in $@, which may be controlled by an external user ($@).", sink,
|
||||
sink.getNode().asExpr().(Expression).getRawExpression(), event, event.getName()
|
||||
|
||||
@@ -20,7 +20,10 @@ import codeql.actions.security.ControlChecks
|
||||
from ArgumentInjectionFlow::PathNode source, ArgumentInjectionFlow::PathNode sink, Event event
|
||||
where
|
||||
ArgumentInjectionFlow::flowPath(source, sink) and
|
||||
event = getRelevantEventInPrivilegedContext(sink.getNode())
|
||||
inPrivilegedContext(sink.getNode().asExpr(), event) and
|
||||
not exists(ControlCheck check |
|
||||
check.protects(sink.getNode().asExpr(), event, "argument-injection")
|
||||
)
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential argument injection in $@ command, which may be controlled by an external user ($@).",
|
||||
sink, sink.getNode().(ArgumentInjectionSink).getCommand(), event, event.getName()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-queries
|
||||
version: 0.6.8-dev
|
||||
version: 0.6.6-dev
|
||||
library: false
|
||||
warnOnImplicitThis: true
|
||||
groups: [actions, queries]
|
||||
|
||||
@@ -1,21 +1,3 @@
|
||||
## 5.4.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The guards libraries (`semmle.code.cpp.controlflow.Guards` and `semmle.code.cpp.controlflow.IRGuards`) have been improved to recognize more guards.
|
||||
* Improved dataflow through global variables in the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow` and `semmle.code.cpp.dataflow.new.TaintTracking`). Queries based on these libraries will produce more results on codebases with many global variables.
|
||||
* The global value numbering library (`semmle.code.cpp.valuenumbering.GlobalValueNumbering` and `semmle.code.cpp.ir.ValueNumbering`) has been improved so more expressions are assigned the same value number.
|
||||
|
||||
## 5.4.0
|
||||
|
||||
### New Features
|
||||
|
||||
* Exposed various SSA-related classes (`Definition`, `PhiNode`, `ExplicitDefinition`, `DirectExplicitDefinition`, and `IndirectExplicitDefinition`) which were previously only usable inside the internal dataflow directory.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/overrun-write` query now recognizes more bound checks and thus produces fewer false positives.
|
||||
|
||||
## 5.3.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* Contains customizations to the standard library.
|
||||
*
|
||||
* This module is imported by `cpp.qll`, so any customizations defined here automatically
|
||||
* apply to all queries.
|
||||
*
|
||||
* Typical examples of customizations include adding new subclasses of abstract classes such as
|
||||
* the `RemoteFlowSource` class to model frameworks that are not covered by the standard library.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
4
cpp/ql/lib/change-notes/2025-07-23-overrun-write.md
Normal file
4
cpp/ql/lib/change-notes/2025-07-23-overrun-write.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/overrun-write` query now recognizes more bound checks and thus produces fewer false positives.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The new dataflow/taint-tracking library (`semmle.code.cpp.dataflow.new.DataFlow` and `semmle.code.cpp.dataflow.new.TaintTracking`) now resolves virtual function calls more precisely. This results in fewer false positives when running dataflow/taint-tracking queries on C++ projects.
|
||||
@@ -1,9 +0,0 @@
|
||||
## 5.4.0
|
||||
|
||||
### New Features
|
||||
|
||||
* Exposed various SSA-related classes (`Definition`, `PhiNode`, `ExplicitDefinition`, `DirectExplicitDefinition`, and `IndirectExplicitDefinition`) which were previously only usable inside the internal dataflow directory.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/overrun-write` query now recognizes more bound checks and thus produces fewer false positives.
|
||||
@@ -1,7 +0,0 @@
|
||||
## 5.4.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The guards libraries (`semmle.code.cpp.controlflow.Guards` and `semmle.code.cpp.controlflow.IRGuards`) have been improved to recognize more guards.
|
||||
* Improved dataflow through global variables in the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow` and `semmle.code.cpp.dataflow.new.TaintTracking`). Queries based on these libraries will produce more results on codebases with many global variables.
|
||||
* The global value numbering library (`semmle.code.cpp.valuenumbering.GlobalValueNumbering` and `semmle.code.cpp.ir.ValueNumbering`) has been improved so more expressions are assigned the same value number.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 5.4.1
|
||||
lastReleaseVersion: 5.3.0
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* https://github.com/cplusplus/draft/raw/master/papers/n4140.pdf
|
||||
*/
|
||||
|
||||
import Customizations
|
||||
import semmle.code.cpp.File
|
||||
import semmle.code.cpp.Linkage
|
||||
import semmle.code.cpp.Location
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 5.4.2-dev
|
||||
version: 5.3.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -57,18 +57,6 @@ private Class getRootType(FieldAccess fa) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of `v`. This predicate does not have a result when the
|
||||
* unspecified type of `v` is a `ReferenceType`.
|
||||
*/
|
||||
private int getVariableSize(Variable v) {
|
||||
exists(Type t |
|
||||
t = v.getUnspecifiedType() and
|
||||
not t instanceof ReferenceType and
|
||||
result = t.getSize()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the buffer access at `va`.
|
||||
*/
|
||||
@@ -76,8 +64,12 @@ private int getSize(VariableAccess va) {
|
||||
exists(Variable v | va.getTarget() = v |
|
||||
// If `v` is not a field then the size of the buffer is just
|
||||
// the size of the type of `v`.
|
||||
not v instanceof Field and
|
||||
result = getVariableSize(v)
|
||||
exists(Type t |
|
||||
t = v.getUnspecifiedType() and
|
||||
not v instanceof Field and
|
||||
not t instanceof ReferenceType and
|
||||
result = t.getSize()
|
||||
)
|
||||
or
|
||||
exists(Class c, int trueSize |
|
||||
// Otherwise, we find the "outermost" object and compute the size
|
||||
@@ -100,7 +92,7 @@ private int getSize(VariableAccess va) {
|
||||
// buffer is `12 - 4 = 8`.
|
||||
c = getRootType(va) and
|
||||
// we calculate the size based on the last field, to avoid including any padding after it
|
||||
trueSize = max(Field f | | f.getOffsetInClass(c) + getVariableSize(f)) and
|
||||
trueSize = max(Field f | | f.getOffsetInClass(c) + f.getUnspecifiedType().getSize()) and
|
||||
result = trueSize - v.(Field).getOffsetInClass(c)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -936,77 +936,6 @@ private module Cached {
|
||||
ValueNumber getUnary() { result.getAnInstruction() = instr.getUnary() }
|
||||
}
|
||||
|
||||
signature predicate sinkSig(Instruction instr);
|
||||
|
||||
private module BooleanInstruction<sinkSig/1 isSink> {
|
||||
/**
|
||||
* Holds if `i1` flows to `i2` in a single step and `i2` is not an
|
||||
* instruction that produces a value of Boolean type.
|
||||
*/
|
||||
private predicate stepToNonBoolean(Instruction i1, Instruction i2) {
|
||||
not i2.getResultIRType() instanceof IRBooleanType and
|
||||
(
|
||||
i2.(CopyInstruction).getSourceValue() = i1
|
||||
or
|
||||
i2.(ConvertInstruction).getUnary() = i1
|
||||
or
|
||||
i2.(BuiltinExpectCallInstruction).getArgument(0) = i1
|
||||
)
|
||||
}
|
||||
|
||||
private predicate rev(Instruction instr) {
|
||||
isSink(instr)
|
||||
or
|
||||
exists(Instruction instr1 |
|
||||
rev(instr1) and
|
||||
stepToNonBoolean(instr, instr1)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasBooleanType(Instruction instr) {
|
||||
instr.getResultIRType() instanceof IRBooleanType
|
||||
}
|
||||
|
||||
private predicate fwd(Instruction instr) {
|
||||
rev(instr) and
|
||||
(
|
||||
hasBooleanType(instr)
|
||||
or
|
||||
exists(Instruction instr0 |
|
||||
fwd(instr0) and
|
||||
stepToNonBoolean(instr0, instr)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate prunedStep(Instruction i1, Instruction i2) {
|
||||
fwd(i1) and
|
||||
fwd(i2) and
|
||||
stepToNonBoolean(i1, i2)
|
||||
}
|
||||
|
||||
private predicate stepsPlus(Instruction i1, Instruction i2) =
|
||||
doublyBoundedFastTC(prunedStep/2, hasBooleanType/1, isSink/1)(i1, i2)
|
||||
|
||||
/**
|
||||
* Gets the Boolean-typed instruction that defines `instr` before any
|
||||
* integer conversions are applied, if any.
|
||||
*/
|
||||
Instruction get(Instruction instr) {
|
||||
isSink(instr) and
|
||||
(
|
||||
result = instr
|
||||
or
|
||||
stepsPlus(result, instr)
|
||||
) and
|
||||
hasBooleanType(result)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate isUnaryComparesEqLeft(Instruction instr) {
|
||||
unary_compares_eq(_, instr.getAUse(), 0, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `left == right + k` is `areEqual` given that test is `testIsTrue`.
|
||||
*
|
||||
@@ -1037,19 +966,14 @@ private module Cached {
|
||||
)
|
||||
or
|
||||
compares_eq(test.(BuiltinExpectCallValueNumber).getCondition(), left, right, k, areEqual, value)
|
||||
}
|
||||
|
||||
private predicate isConvertedBool(Instruction instr) {
|
||||
instr.getResultIRType() instanceof IRBooleanType
|
||||
or
|
||||
exists(Operand l, BooleanValue bv |
|
||||
// 1. test = value -> int(l) = 0 is !bv
|
||||
unary_compares_eq(test, l, 0, bv.getValue().booleanNot(), value) and
|
||||
// 2. l = bv -> left + right is areEqual
|
||||
compares_eq(valueNumber(BooleanInstruction<isUnaryComparesEqLeft/1>::get(l.getDef())), left,
|
||||
right, k, areEqual, bv)
|
||||
// We want this to hold:
|
||||
// `test = value -> left + right is areEqual`
|
||||
// Applying 2 we need to show:
|
||||
// `test = value -> l = bv`
|
||||
// And `l = bv` holds by `int(l) = 0 is !bv`
|
||||
)
|
||||
isConvertedBool(instr.(ConvertInstruction).getUnary())
|
||||
or
|
||||
isConvertedBool(instr.(BuiltinExpectCallInstruction).getCondition())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1082,11 +1006,19 @@ private module Cached {
|
||||
k = k1 + k2
|
||||
)
|
||||
or
|
||||
// See argument for why this is correct in compares_eq
|
||||
exists(Operand l, BooleanValue bv |
|
||||
unary_compares_eq(test, l, 0, bv.getValue().booleanNot(), value) and
|
||||
unary_compares_eq(valueNumber(BooleanInstruction<isUnaryComparesEqLeft/1>::get(l.getDef())),
|
||||
op, k, areEqual, bv)
|
||||
exists(CompareValueNumber cmp, Operand left, Operand right, AbstractValue v |
|
||||
test = cmp and
|
||||
pragma[only_bind_into](cmp)
|
||||
.hasOperands(pragma[only_bind_into](left), pragma[only_bind_into](right)) and
|
||||
isConvertedBool(left.getDef()) and
|
||||
int_value(right.getDef()) = 0 and
|
||||
unary_compares_eq(valueNumberOfOperand(left), op, k, areEqual, v)
|
||||
|
|
||||
cmp instanceof CompareNEValueNumber and
|
||||
v = value
|
||||
or
|
||||
cmp instanceof CompareEQValueNumber and
|
||||
v.getDualValue() = value
|
||||
)
|
||||
or
|
||||
unary_compares_eq(test.(BuiltinExpectCallValueNumber).getCondition(), op, k, areEqual, value)
|
||||
@@ -1184,26 +1116,70 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isBuiltInExpectArg(Instruction instr) {
|
||||
instr = any(BuiltinExpectCallInstruction buildinExpect).getArgument(0)
|
||||
}
|
||||
|
||||
/** A call to the builtin operation `__builtin_expect`. */
|
||||
private class BuiltinExpectCallInstruction extends CallInstruction {
|
||||
BuiltinExpectCallInstruction() { this.getStaticCallTarget().hasName("__builtin_expect") }
|
||||
|
||||
/** Gets the condition of this call. */
|
||||
Instruction getCondition() {
|
||||
result = BooleanInstruction<isBuiltInExpectArg/1>::get(this.getArgument(0))
|
||||
Instruction getCondition() { result = this.getConditionOperand().getDef() }
|
||||
|
||||
Operand getConditionOperand() {
|
||||
// The first parameter of `__builtin_expect` has type `long`. So we skip
|
||||
// the conversion when inferring guards.
|
||||
result = this.getArgument(0).(ConvertInstruction).getUnaryOperand()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `left == right + k` is `areEqual` if `cmp` evaluates to `value`,
|
||||
* and `cmp` is an instruction that compares the value of
|
||||
* `__builtin_expect(left == right + k, _)` to `0`.
|
||||
*/
|
||||
private predicate builtin_expect_eq(
|
||||
CompareValueNumber cmp, Operand left, Operand right, int k, boolean areEqual,
|
||||
AbstractValue value
|
||||
) {
|
||||
exists(BuiltinExpectCallValueNumber call, Instruction const, AbstractValue innerValue |
|
||||
int_value(const) = 0 and
|
||||
cmp.hasOperands(call.getAUse(), const.getAUse()) and
|
||||
compares_eq(call.getCondition(), left, right, k, areEqual, innerValue)
|
||||
|
|
||||
cmp instanceof CompareNEValueNumber and
|
||||
value = innerValue
|
||||
or
|
||||
cmp instanceof CompareEQValueNumber and
|
||||
value.getDualValue() = innerValue
|
||||
)
|
||||
}
|
||||
|
||||
private predicate complex_eq(
|
||||
ValueNumber cmp, Operand left, Operand right, int k, boolean areEqual, AbstractValue value
|
||||
) {
|
||||
sub_eq(cmp, left, right, k, areEqual, value)
|
||||
or
|
||||
add_eq(cmp, left, right, k, areEqual, value)
|
||||
or
|
||||
builtin_expect_eq(cmp, left, right, k, areEqual, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `op == k` is `areEqual` if `cmp` evaluates to `value`, and `cmp` is
|
||||
* an instruction that compares the value of `__builtin_expect(op == k, _)` to `0`.
|
||||
*/
|
||||
private predicate unary_builtin_expect_eq(
|
||||
CompareValueNumber cmp, Operand op, int k, boolean areEqual, AbstractValue value
|
||||
) {
|
||||
exists(BuiltinExpectCallValueNumber call, Instruction const, AbstractValue innerValue |
|
||||
int_value(const) = 0 and
|
||||
cmp.hasOperands(call.getAUse(), const.getAUse()) and
|
||||
unary_compares_eq(call.getCondition(), op, k, areEqual, innerValue)
|
||||
|
|
||||
cmp instanceof CompareNEValueNumber and
|
||||
value = innerValue
|
||||
or
|
||||
cmp instanceof CompareEQValueNumber and
|
||||
value.getDualValue() = innerValue
|
||||
)
|
||||
}
|
||||
|
||||
private predicate unary_complex_eq(
|
||||
@@ -1212,6 +1188,8 @@ private module Cached {
|
||||
unary_sub_eq(test, op, k, areEqual, value)
|
||||
or
|
||||
unary_add_eq(test, op, k, areEqual, value)
|
||||
or
|
||||
unary_builtin_expect_eq(test, op, k, areEqual, value)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1237,15 +1215,6 @@ private module Cached {
|
||||
exists(AbstractValue dual | value = dual.getDualValue() |
|
||||
compares_lt(test.(LogicalNotValueNumber).getUnary(), left, right, k, isLt, dual)
|
||||
)
|
||||
or
|
||||
compares_lt(test.(BuiltinExpectCallValueNumber).getCondition(), left, right, k, isLt, value)
|
||||
or
|
||||
// See argument for why this is correct in compares_eq
|
||||
exists(Operand l, BooleanValue bv |
|
||||
unary_compares_eq(test, l, 0, bv.getValue().booleanNot(), value) and
|
||||
compares_lt(valueNumber(BooleanInstruction<isUnaryComparesEqLeft/1>::get(l.getDef())), left,
|
||||
right, k, isLt, bv)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `op < k` evaluates to `isLt` given that `test` evaluates to `value`. */
|
||||
@@ -1265,15 +1234,6 @@ private module Cached {
|
||||
int_value(const) = k1 and
|
||||
k = k1 + k2
|
||||
)
|
||||
or
|
||||
compares_lt(test.(BuiltinExpectCallValueNumber).getCondition(), op, k, isLt, value)
|
||||
or
|
||||
// See argument for why this is correct in compares_eq
|
||||
exists(Operand l, BooleanValue bv |
|
||||
unary_compares_eq(test, l, 0, bv.getValue().booleanNot(), value) and
|
||||
compares_lt(valueNumber(BooleanInstruction<isUnaryComparesEqLeft/1>::get(l.getDef())), op, k,
|
||||
isLt, bv)
|
||||
)
|
||||
}
|
||||
|
||||
/** `(a < b + k) => (b > a - k) => (b >= a + (1-k))` */
|
||||
|
||||
@@ -15,13 +15,6 @@ class StandardSsa extends SsaHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: If possible, prefer the SSA classes exposed by the new dataflow
|
||||
* library:
|
||||
* ```
|
||||
* import semmle.code.cpp.dataflow.new.DataFlow
|
||||
* // use `DataFlow::Ssa::Definition`
|
||||
* ```
|
||||
*
|
||||
* A definition of one or more SSA variables, including phi node definitions.
|
||||
* An _SSA variable_, as defined in the literature, is effectively the pair of
|
||||
* an `SsaDefinition d` and a `StackVariable v`, written `(d, v)` in this
|
||||
|
||||
@@ -1,21 +1,223 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import DataFlowPrivate as DataFlowPrivate
|
||||
private import DataFlowPrivate
|
||||
private import DataFlowUtil
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
private import codeql.typetracking.TypeTracking
|
||||
private import SsaImpl as SsaImpl
|
||||
|
||||
/**
|
||||
* Holds if `f` has name `qualifiedName` and `nparams` parameter count. This is
|
||||
* an approximation of its signature for the purpose of matching functions that
|
||||
* might be the same across link targets.
|
||||
* Gets a function that might be called by `call`.
|
||||
*
|
||||
* This predicate does not take additional call targets
|
||||
* from `AdditionalCallTarget` into account.
|
||||
*/
|
||||
private predicate functionSignature(Function f, string qualifiedName, int nparams) {
|
||||
qualifiedName = f.getQualifiedName() and
|
||||
nparams = f.getNumberOfParameters() and
|
||||
not f.isStatic()
|
||||
cached
|
||||
DataFlowCallable defaultViableCallable(DataFlowCall call) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
result = call.getStaticCallTarget()
|
||||
or
|
||||
// If the target of the call does not have a body in the snapshot, it might
|
||||
// be because the target is just a header declaration, and the real target
|
||||
// will be determined at run time when the caller and callee are linked
|
||||
// together by the operating system's dynamic linker. In case a _unique_
|
||||
// function with the right signature is present in the database, we return
|
||||
// that as a potential callee.
|
||||
exists(string qualifiedName, int nparams |
|
||||
callSignatureWithoutBody(qualifiedName, nparams, call.asCallInstruction()) and
|
||||
functionSignatureWithBody(qualifiedName, nparams, result.getUnderlyingCallable()) and
|
||||
strictcount(Function other | functionSignatureWithBody(qualifiedName, nparams, other)) = 1
|
||||
)
|
||||
or
|
||||
// Virtual dispatch
|
||||
result.asSourceCallable() = call.(VirtualDispatch::DataSensitiveCall).resolve()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a function that might be called by `call`.
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable viableCallable(DataFlowCall call) {
|
||||
result = defaultViableCallable(call)
|
||||
or
|
||||
// Additional call targets
|
||||
result.getUnderlyingCallable() =
|
||||
any(AdditionalCallTarget additional)
|
||||
.viableTarget(call.asCallInstruction().getUnconvertedResultExpression())
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides virtual dispatch support compatible with the original
|
||||
* implementation of `semmle.code.cpp.security.TaintTracking`.
|
||||
*/
|
||||
private module VirtualDispatch {
|
||||
/** A call that may dispatch differently depending on the qualifier value. */
|
||||
abstract class DataSensitiveCall extends DataFlowCall {
|
||||
/**
|
||||
* Gets the node whose value determines the target of this call. This node
|
||||
* could be the qualifier of a virtual dispatch or the function-pointer
|
||||
* expression in a call to a function pointer. What they have in common is
|
||||
* that we need to find out which data flows there, and then it's up to the
|
||||
* `resolve` predicate to stitch that information together and resolve the
|
||||
* call.
|
||||
*/
|
||||
abstract DataFlow::Node getDispatchValue();
|
||||
|
||||
/** Gets a candidate target for this call. */
|
||||
abstract Function resolve();
|
||||
|
||||
/**
|
||||
* Whether `src` can flow to this call.
|
||||
*
|
||||
* Searches backwards from `getDispatchValue()` to `src`. The `allowFromArg`
|
||||
* parameter is true when the search is allowed to continue backwards into
|
||||
* a parameter; non-recursive callers should pass `_` for `allowFromArg`.
|
||||
*/
|
||||
predicate flowsFrom(DataFlow::Node src, boolean allowFromArg) {
|
||||
src = this.getDispatchValue() and allowFromArg = true
|
||||
or
|
||||
exists(DataFlow::Node other, boolean allowOtherFromArg |
|
||||
this.flowsFrom(other, allowOtherFromArg)
|
||||
|
|
||||
// Call argument
|
||||
exists(DataFlowCall call, Position i |
|
||||
other
|
||||
.(DataFlow::ParameterNode)
|
||||
.isParameterOf(pragma[only_bind_into](call).getStaticCallTarget(), i) and
|
||||
src.(ArgumentNode).argumentOf(call, pragma[only_bind_into](pragma[only_bind_out](i)))
|
||||
) and
|
||||
allowOtherFromArg = true and
|
||||
allowFromArg = true
|
||||
or
|
||||
// Call return
|
||||
exists(DataFlowCall call, ReturnKind returnKind |
|
||||
other = getAnOutNode(call, returnKind) and
|
||||
returnNodeWithKindAndEnclosingCallable(src, returnKind, call.getStaticCallTarget())
|
||||
) and
|
||||
allowFromArg = false
|
||||
or
|
||||
// Local flow
|
||||
DataFlow::localFlowStep(src, other) and
|
||||
allowFromArg = allowOtherFromArg
|
||||
or
|
||||
// Flow from global variable to load.
|
||||
exists(LoadInstruction load, GlobalOrNamespaceVariable var |
|
||||
var = src.asVariable() and
|
||||
other.asInstruction() = load and
|
||||
addressOfGlobal(load.getSourceAddress(), var) and
|
||||
// The `allowFromArg` concept doesn't play a role when `src` is a
|
||||
// global variable, so we just set it to a single arbitrary value for
|
||||
// performance.
|
||||
allowFromArg = true
|
||||
)
|
||||
or
|
||||
// Flow from store to global variable.
|
||||
exists(StoreInstruction store, GlobalOrNamespaceVariable var |
|
||||
var = other.asVariable() and
|
||||
store = src.asInstruction() and
|
||||
storeIntoGlobal(store, var) and
|
||||
// Setting `allowFromArg` to `true` like in the base case means we
|
||||
// treat a store to a global variable like the dispatch itself: flow
|
||||
// may come from anywhere.
|
||||
allowFromArg = true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate storeIntoGlobal(StoreInstruction store, GlobalOrNamespaceVariable var) {
|
||||
addressOfGlobal(store.getDestinationAddress(), var)
|
||||
}
|
||||
|
||||
/** Holds if `addressInstr` is an instruction that produces the address of `var`. */
|
||||
private predicate addressOfGlobal(Instruction addressInstr, GlobalOrNamespaceVariable var) {
|
||||
// Access directly to the global variable
|
||||
addressInstr.(VariableAddressInstruction).getAstVariable() = var
|
||||
or
|
||||
// Access to a field on a global union
|
||||
exists(FieldAddressInstruction fa |
|
||||
fa = addressInstr and
|
||||
fa.getObjectAddress().(VariableAddressInstruction).getAstVariable() = var and
|
||||
fa.getField().getDeclaringType() instanceof Union
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A ReturnNode with its ReturnKind and its enclosing callable.
|
||||
*
|
||||
* Used to fix a join ordering issue in flowsFrom.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate returnNodeWithKindAndEnclosingCallable(
|
||||
ReturnNode node, ReturnKind kind, DataFlowCallable callable
|
||||
) {
|
||||
node.getKind() = kind and
|
||||
node.getFunction() = callable.getUnderlyingCallable()
|
||||
}
|
||||
|
||||
/** Call through a function pointer. */
|
||||
private class DataSensitiveExprCall extends DataSensitiveCall {
|
||||
DataSensitiveExprCall() { not exists(this.getStaticCallTarget()) }
|
||||
|
||||
override DataFlow::Node getDispatchValue() { result.asOperand() = this.getCallTargetOperand() }
|
||||
|
||||
override Function resolve() {
|
||||
exists(FunctionInstruction fi |
|
||||
this.flowsFrom(DataFlow::instructionNode(fi), _) and
|
||||
result = fi.getFunctionSymbol()
|
||||
) and
|
||||
(
|
||||
this.getNumberOfArguments() <= result.getEffectiveNumberOfParameters() and
|
||||
this.getNumberOfArguments() >= result.getEffectiveNumberOfParameters()
|
||||
or
|
||||
result.isVarargs()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Call to a virtual function. */
|
||||
private class DataSensitiveOverriddenFunctionCall extends DataSensitiveCall {
|
||||
DataSensitiveOverriddenFunctionCall() {
|
||||
exists(
|
||||
this.getStaticCallTarget()
|
||||
.getUnderlyingCallable()
|
||||
.(VirtualFunction)
|
||||
.getAnOverridingFunction()
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getDispatchValue() { result.asInstruction() = this.getArgument(-1) }
|
||||
|
||||
override MemberFunction resolve() {
|
||||
exists(Class overridingClass |
|
||||
this.overrideMayAffectCall(overridingClass, result) and
|
||||
this.hasFlowFromCastFrom(overridingClass)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `this` is a virtual function call whose static target is
|
||||
* overridden by `overridingFunction` in `overridingClass`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate overrideMayAffectCall(Class overridingClass, MemberFunction overridingFunction) {
|
||||
overridingFunction.getAnOverriddenFunction+() =
|
||||
this.getStaticCallTarget().getUnderlyingCallable().(VirtualFunction) and
|
||||
overridingFunction.getDeclaringType() = overridingClass
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the qualifier of `this` has flow from an upcast from
|
||||
* `derivedClass`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate hasFlowFromCastFrom(Class derivedClass) {
|
||||
exists(ConvertToBaseInstruction toBase |
|
||||
this.flowsFrom(DataFlow::instructionNode(toBase), _) and
|
||||
derivedClass = toBase.getDerivedClass()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,319 +243,34 @@ private predicate callSignatureWithoutBody(string qualifiedName, int nparams, Ca
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a function that might be called by `call`.
|
||||
*
|
||||
* This predicate does not take additional call targets
|
||||
* from `AdditionalCallTarget` into account.
|
||||
* Holds if `f` has name `qualifiedName` and `nparams` parameter count. This is
|
||||
* an approximation of its signature for the purpose of matching functions that
|
||||
* might be the same across link targets.
|
||||
*/
|
||||
cached
|
||||
DataFlowPrivate::DataFlowCallable defaultViableCallable(DataFlowPrivate::DataFlowCall call) {
|
||||
result = defaultViableCallableWithoutLambda(call)
|
||||
or
|
||||
result = DataFlowImplCommon::viableCallableLambda(call, _)
|
||||
}
|
||||
|
||||
private DataFlowPrivate::DataFlowCallable defaultViableCallableWithoutLambda(
|
||||
DataFlowPrivate::DataFlowCall call
|
||||
) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
result = call.getStaticCallTarget()
|
||||
or
|
||||
// If the target of the call does not have a body in the snapshot, it might
|
||||
// be because the target is just a header declaration, and the real target
|
||||
// will be determined at run time when the caller and callee are linked
|
||||
// together by the operating system's dynamic linker. In case a _unique_
|
||||
// function with the right signature is present in the database, we return
|
||||
// that as a potential callee.
|
||||
exists(string qualifiedName, int nparams |
|
||||
callSignatureWithoutBody(qualifiedName, nparams, call.asCallInstruction()) and
|
||||
functionSignatureWithBody(qualifiedName, nparams, result.getUnderlyingCallable()) and
|
||||
strictcount(Function other | functionSignatureWithBody(qualifiedName, nparams, other)) = 1
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a function that might be called by `call`.
|
||||
*/
|
||||
private DataFlowPrivate::DataFlowCallable nonVirtualDispatch(DataFlowPrivate::DataFlowCall call) {
|
||||
result = defaultViableCallableWithoutLambda(call)
|
||||
or
|
||||
// Additional call targets
|
||||
result.getUnderlyingCallable() =
|
||||
any(AdditionalCallTarget additional)
|
||||
.viableTarget(call.asCallInstruction().getUnconvertedResultExpression())
|
||||
}
|
||||
|
||||
private class RelevantNode extends Node {
|
||||
RelevantNode() { this.getType().stripType() instanceof Class }
|
||||
}
|
||||
|
||||
private signature DataFlowPrivate::DataFlowCallable methodDispatchSig(
|
||||
DataFlowPrivate::DataFlowCall c
|
||||
);
|
||||
|
||||
private predicate ignoreConstructor(Expr e) {
|
||||
e instanceof ConstructorDirectInit or
|
||||
e instanceof ConstructorVirtualInit or
|
||||
e instanceof ConstructorDelegationInit or
|
||||
exists(ConstructorFieldInit init | init.getExpr() = e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` is either:
|
||||
* - the post-update node of a qualifier after a call to a constructor which
|
||||
* constructs an object containing at least one virtual function.
|
||||
* - a node which represents a derived-to-base instruction that converts from `c`.
|
||||
*/
|
||||
private predicate qualifierSourceImpl(RelevantNode n, Class c) {
|
||||
// Object construction
|
||||
exists(CallInstruction call, ThisArgumentOperand qualifier, Call e |
|
||||
qualifier = call.getThisArgumentOperand() and
|
||||
n.(PostUpdateNode).getPreUpdateNode().asOperand() = qualifier and
|
||||
call.getStaticCallTarget() instanceof Constructor and
|
||||
qualifier.getType().stripType() = c and
|
||||
c.getABaseClass*().getAMemberFunction().isVirtual() and
|
||||
e = call.getUnconvertedResultExpression() and
|
||||
not ignoreConstructor(e)
|
||||
|
|
||||
exists(c.getABaseClass())
|
||||
or
|
||||
exists(c.getADerivedClass())
|
||||
)
|
||||
or
|
||||
// Conversion to a base class
|
||||
exists(ConvertToBaseInstruction convert |
|
||||
// Only keep the most specific cast
|
||||
not convert.getUnary() instanceof ConvertToBaseInstruction and
|
||||
n.asInstruction() = convert and
|
||||
convert.getDerivedClass() = c and
|
||||
c.getABaseClass*().getAMemberFunction().isVirtual()
|
||||
)
|
||||
}
|
||||
|
||||
private module TrackVirtualDispatch<methodDispatchSig/1 virtualDispatch0> {
|
||||
/**
|
||||
* Gets a possible runtime target of `c` using both static call-target
|
||||
* information, and call-target resolution from `virtualDispatch0`.
|
||||
*/
|
||||
private DataFlowPrivate::DataFlowCallable dispatch(DataFlowPrivate::DataFlowCall c) {
|
||||
result = nonVirtualDispatch(c) or
|
||||
result = virtualDispatch0(c)
|
||||
}
|
||||
|
||||
private module TtInput implements TypeTrackingInput<Location> {
|
||||
final class Node = RelevantNode;
|
||||
|
||||
class LocalSourceNode extends Node {
|
||||
LocalSourceNode() {
|
||||
this instanceof ParameterNode
|
||||
or
|
||||
this instanceof DataFlowPrivate::OutNode
|
||||
or
|
||||
DataFlowPrivate::readStep(_, _, this)
|
||||
or
|
||||
DataFlowPrivate::storeStep(_, _, this)
|
||||
or
|
||||
DataFlowPrivate::jumpStep(_, this)
|
||||
or
|
||||
qualifierSourceImpl(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
final private class ContentSetFinal = ContentSet;
|
||||
|
||||
class Content extends ContentSetFinal {
|
||||
Content() {
|
||||
exists(DataFlow::Content c |
|
||||
this.isSingleton(c) and
|
||||
c.getIndirectionIndex() = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class ContentFilter extends Content {
|
||||
Content getAMatchingContent() { result = this }
|
||||
}
|
||||
|
||||
predicate compatibleContents(Content storeContents, Content loadContents) {
|
||||
storeContents = loadContents
|
||||
}
|
||||
|
||||
predicate simpleLocalSmallStep(Node nodeFrom, Node nodeTo) {
|
||||
nodeFrom.getFunction() instanceof Function and
|
||||
simpleLocalFlowStep(nodeFrom, nodeTo, _)
|
||||
}
|
||||
|
||||
predicate levelStepNoCall(Node n1, LocalSourceNode n2) { none() }
|
||||
|
||||
predicate levelStepCall(Node n1, LocalSourceNode n2) { none() }
|
||||
|
||||
predicate storeStep(Node n1, Node n2, Content f) { DataFlowPrivate::storeStep(n1, f, n2) }
|
||||
|
||||
predicate callStep(Node n1, LocalSourceNode n2) {
|
||||
exists(DataFlowPrivate::DataFlowCall call, DataFlowPrivate::Position pos |
|
||||
n1.(DataFlowPrivate::ArgumentNode).argumentOf(call, pos) and
|
||||
n2.(ParameterNode).isParameterOf(dispatch(call), pos)
|
||||
)
|
||||
}
|
||||
|
||||
predicate returnStep(Node n1, LocalSourceNode n2) {
|
||||
exists(DataFlowPrivate::DataFlowCallable callable, DataFlowPrivate::DataFlowCall call |
|
||||
n1.(DataFlowPrivate::ReturnNode).getEnclosingCallable() = callable and
|
||||
callable = dispatch(call) and
|
||||
n2 = DataFlowPrivate::getAnOutNode(call, n1.(DataFlowPrivate::ReturnNode).getKind())
|
||||
)
|
||||
}
|
||||
|
||||
predicate loadStep(Node n1, LocalSourceNode n2, Content f) {
|
||||
DataFlowPrivate::readStep(n1, f, n2)
|
||||
}
|
||||
|
||||
predicate loadStoreStep(Node nodeFrom, Node nodeTo, Content f1, Content f2) { none() }
|
||||
|
||||
predicate withContentStep(Node nodeFrom, LocalSourceNode nodeTo, ContentFilter f) { none() }
|
||||
|
||||
predicate withoutContentStep(Node nodeFrom, LocalSourceNode nodeTo, ContentFilter f) { none() }
|
||||
|
||||
predicate jumpStep(Node n1, LocalSourceNode n2) { DataFlowPrivate::jumpStep(n1, n2) }
|
||||
|
||||
predicate hasFeatureBacktrackStoreTarget() { none() }
|
||||
}
|
||||
|
||||
private predicate qualifierSource(RelevantNode n) { qualifierSourceImpl(n, _) }
|
||||
|
||||
/**
|
||||
* Holds if `n` is the qualifier of `call` which targets the virtual member
|
||||
* function `mf`.
|
||||
*/
|
||||
private predicate qualifierOfVirtualCallImpl(
|
||||
RelevantNode n, CallInstruction call, MemberFunction mf
|
||||
) {
|
||||
n.asOperand() = call.getThisArgumentOperand() and
|
||||
call.getStaticCallTarget() = mf and
|
||||
mf.isVirtual()
|
||||
}
|
||||
|
||||
private predicate qualifierOfVirtualCall(RelevantNode n) { qualifierOfVirtualCallImpl(n, _, _) }
|
||||
|
||||
private import TypeTracking<Location, TtInput>::TypeTrack<qualifierSource/1>::Graph<qualifierOfVirtualCall/1>
|
||||
|
||||
private predicate edgePlus(PathNode n1, PathNode n2) = fastTC(edges/2)(n1, n2)
|
||||
|
||||
/**
|
||||
* Gets the most specific implementation of `mf` that may be called when the
|
||||
* qualifier has runtime type `c`.
|
||||
*/
|
||||
private MemberFunction mostSpecific(MemberFunction mf, Class c) {
|
||||
qualifierOfVirtualCallImpl(_, _, mf) and
|
||||
mf.getAnOverridingFunction*() = result and
|
||||
(
|
||||
result.getDeclaringType() = c
|
||||
or
|
||||
not c.getAMemberFunction().getAnOverriddenFunction*() = mf and
|
||||
result = mostSpecific(mf, c.getABaseClass())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible pair of end-points `(p1, p2)` where:
|
||||
* - `p1` is a derived-to-base conversion that converts from some
|
||||
* class `derived`, and
|
||||
* - `p2` is the qualifier of a call to a virtual function that may
|
||||
* target `callable`, and
|
||||
* - `callable` is the most specific implementation that may be called when
|
||||
* the qualifier has type `derived`.
|
||||
*/
|
||||
private predicate pairCand(
|
||||
PathNode p1, PathNode p2, DataFlowPrivate::DataFlowCallable callable,
|
||||
DataFlowPrivate::DataFlowCall call
|
||||
) {
|
||||
exists(Class derived, MemberFunction mf |
|
||||
qualifierSourceImpl(p1.getNode(), derived) and
|
||||
qualifierOfVirtualCallImpl(p2.getNode(), call.asCallInstruction(), mf) and
|
||||
p1.isSource() and
|
||||
p2.isSink() and
|
||||
callable.asSourceCallable() = mostSpecific(mf, derived)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a possible run-time target of `call`. */
|
||||
DataFlowPrivate::DataFlowCallable virtualDispatch(DataFlowPrivate::DataFlowCall call) {
|
||||
exists(PathNode p1, PathNode p2 | p1 = p2 or edgePlus(p1, p2) | pairCand(p1, p2, result, call))
|
||||
}
|
||||
}
|
||||
|
||||
private DataFlowPrivate::DataFlowCallable noDisp(DataFlowPrivate::DataFlowCall call) { none() }
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlowPrivate::DataFlowCallable d1(DataFlowPrivate::DataFlowCall call) {
|
||||
result = TrackVirtualDispatch<noDisp/1>::virtualDispatch(call)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlowPrivate::DataFlowCallable d2(DataFlowPrivate::DataFlowCall call) {
|
||||
result = TrackVirtualDispatch<d1/1>::virtualDispatch(call)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlowPrivate::DataFlowCallable d3(DataFlowPrivate::DataFlowCall call) {
|
||||
result = TrackVirtualDispatch<d2/1>::virtualDispatch(call)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlowPrivate::DataFlowCallable d4(DataFlowPrivate::DataFlowCall call) {
|
||||
result = TrackVirtualDispatch<d3/1>::virtualDispatch(call)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlowPrivate::DataFlowCallable d5(DataFlowPrivate::DataFlowCall call) {
|
||||
result = TrackVirtualDispatch<d4/1>::virtualDispatch(call)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlowPrivate::DataFlowCallable d6(DataFlowPrivate::DataFlowCall call) {
|
||||
result = TrackVirtualDispatch<d5/1>::virtualDispatch(call)
|
||||
}
|
||||
|
||||
/** Gets a function that might be called by `call`. */
|
||||
cached
|
||||
DataFlowPrivate::DataFlowCallable viableCallable(DataFlowPrivate::DataFlowCall call) {
|
||||
not exists(d6(call)) and
|
||||
result = nonVirtualDispatch(call)
|
||||
or
|
||||
result = d6(call)
|
||||
private predicate functionSignature(Function f, string qualifiedName, int nparams) {
|
||||
qualifiedName = f.getQualifiedName() and
|
||||
nparams = f.getNumberOfParameters() and
|
||||
not f.isStatic()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the set of viable implementations that can be called by `call`
|
||||
* might be improved by knowing the call context.
|
||||
*/
|
||||
predicate mayBenefitFromCallContext(DataFlowPrivate::DataFlowCall call) {
|
||||
mayBenefitFromCallContext(call, _, _)
|
||||
}
|
||||
|
||||
private predicate localLambdaFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
localFlowStep(nodeFrom, nodeTo)
|
||||
or
|
||||
DataFlowPrivate::additionalLambdaFlowStep(nodeFrom, nodeTo, _)
|
||||
}
|
||||
predicate mayBenefitFromCallContext(DataFlowCall call) { mayBenefitFromCallContext(call, _, _) }
|
||||
|
||||
/**
|
||||
* Holds if `call` is a call through a function pointer, and the pointer
|
||||
* value is given as the `arg`'th argument to `f`.
|
||||
*/
|
||||
private predicate mayBenefitFromCallContext(
|
||||
DataFlowPrivate::DataFlowCall call, DataFlowPrivate::DataFlowCallable f, int arg
|
||||
VirtualDispatch::DataSensitiveCall call, DataFlowCallable f, int arg
|
||||
) {
|
||||
f = pragma[only_bind_out](call).getEnclosingCallable() and
|
||||
exists(InitializeParameterInstruction init |
|
||||
not exists(call.getStaticCallTarget())
|
||||
or
|
||||
exists(call.getStaticCallSourceTarget().(VirtualFunction).getAnOverridingFunction())
|
||||
|
|
||||
not exists(call.getStaticCallTarget()) and
|
||||
init.getEnclosingFunction() = f.getUnderlyingCallable() and
|
||||
localLambdaFlowStep+(instructionNode(init),
|
||||
operandNode(call.asCallInstruction().getCallTargetOperand())) and
|
||||
call.flowsFrom(DataFlow::instructionNode(init), _) and
|
||||
init.getParameter().getIndex() = arg
|
||||
)
|
||||
}
|
||||
@@ -362,11 +279,9 @@ private predicate mayBenefitFromCallContext(
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
*/
|
||||
DataFlowPrivate::DataFlowCallable viableImplInCallContext(
|
||||
DataFlowPrivate::DataFlowCall call, DataFlowPrivate::DataFlowCall ctx
|
||||
) {
|
||||
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableCallable(call) and
|
||||
exists(int i, DataFlowPrivate::DataFlowCallable f |
|
||||
exists(int i, DataFlowCallable f |
|
||||
mayBenefitFromCallContext(pragma[only_bind_into](call), f, i) and
|
||||
f = ctx.getStaticCallTarget() and
|
||||
result.asSourceCallable() =
|
||||
@@ -376,8 +291,4 @@ DataFlowPrivate::DataFlowCallable viableImplInCallContext(
|
||||
|
||||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
pragma[inline]
|
||||
predicate parameterMatch(
|
||||
DataFlowPrivate::ParameterPosition ppos, DataFlowPrivate::ArgumentPosition apos
|
||||
) {
|
||||
ppos = apos
|
||||
}
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
|
||||
@@ -4,7 +4,7 @@ private import semmle.code.cpp.ir.IR
|
||||
private import DataFlowDispatch
|
||||
private import semmle.code.cpp.ir.internal.IRCppLanguage
|
||||
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import SsaImpl as Ssa
|
||||
private import SsaInternals as Ssa
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
private import codeql.util.Unit
|
||||
private import Node0ToString
|
||||
@@ -332,13 +332,6 @@ private module IndirectInstructions {
|
||||
|
||||
import IndirectInstructions
|
||||
|
||||
predicate isPostUpdateNodeImpl(Operand operand, int indirectionIndex) {
|
||||
operand = any(FieldAddress fa).getObjectAddressOperand() and
|
||||
indirectionIndex = [0 .. Ssa::countIndirectionsForCppType(Ssa::getLanguageType(operand))]
|
||||
or
|
||||
Ssa::isModifiableByCall(operand, indirectionIndex)
|
||||
}
|
||||
|
||||
/** Gets the callable in which this node occurs. */
|
||||
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
|
||||
|
||||
@@ -1492,14 +1485,7 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
|
||||
}
|
||||
|
||||
/** Extra data-flow steps needed for lambda flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) {
|
||||
preservesValue = false and
|
||||
exists(ContentSet cs | cs.isSingleton(any(UnionContent uc)) |
|
||||
storeStep(nodeFrom, cs, nodeTo)
|
||||
or
|
||||
readStep(nodeFrom, cs, nodeTo)
|
||||
)
|
||||
}
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
|
||||
|
||||
predicate knownSourceModel(Node source, string model) { External::sourceNode(source, _, model) }
|
||||
|
||||
@@ -1996,23 +1982,19 @@ module IteratorFlow {
|
||||
|
||||
predicate allowFlowIntoUncertainDef(IteratorSsa::UncertainWriteDefinition def) { any() }
|
||||
|
||||
class GuardValue = Void;
|
||||
|
||||
class Guard extends Void {
|
||||
predicate hasValueBranchEdge(
|
||||
SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, GuardValue val
|
||||
) {
|
||||
predicate hasBranchEdge(SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, boolean branch) {
|
||||
none()
|
||||
}
|
||||
|
||||
predicate valueControlsBranchEdge(
|
||||
SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, GuardValue val
|
||||
predicate controlsBranchEdge(
|
||||
SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, boolean branch
|
||||
) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
predicate guardDirectlyControlsBlock(Guard guard, SsaInput::BasicBlock bb, GuardValue val) {
|
||||
predicate guardDirectlyControlsBlock(Guard guard, SsaInput::BasicBlock bb, boolean branch) {
|
||||
none()
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ private import semmle.code.cpp.models.interfaces.DataFlow
|
||||
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import DataFlowPrivate
|
||||
private import ModelUtil
|
||||
private import SsaImpl as SsaImpl
|
||||
private import SsaInternals as Ssa
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
private import codeql.util.Unit
|
||||
private import Node0ToString
|
||||
@@ -39,35 +39,38 @@ private newtype TIRDataFlowNode =
|
||||
TNode0(Node0Impl node) { DataFlowImplCommon::forceCachingInSameStage() } or
|
||||
TGlobalLikeVariableNode(GlobalLikeVariable var, int indirectionIndex) {
|
||||
indirectionIndex =
|
||||
[getMinIndirectionsForType(var.getUnspecifiedType()) .. SsaImpl::getMaxIndirectionsForType(var.getUnspecifiedType())]
|
||||
[getMinIndirectionsForType(var.getUnspecifiedType()) .. Ssa::getMaxIndirectionsForType(var.getUnspecifiedType())]
|
||||
} or
|
||||
TPostUpdateNodeImpl(Operand operand, int indirectionIndex) {
|
||||
isPostUpdateNodeImpl(operand, indirectionIndex)
|
||||
operand = any(FieldAddress fa).getObjectAddressOperand() and
|
||||
indirectionIndex = [0 .. Ssa::countIndirectionsForCppType(Ssa::getLanguageType(operand))]
|
||||
or
|
||||
Ssa::isModifiableByCall(operand, indirectionIndex)
|
||||
} or
|
||||
TSsaSynthNode(SsaImpl::SynthNode n) or
|
||||
TSsaSynthNode(Ssa::SynthNode n) or
|
||||
TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
|
||||
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
|
||||
SsaImpl::hasRawIndirectOperand(node.asOperand(), indirectionIndex)
|
||||
Ssa::hasRawIndirectOperand(node.asOperand(), indirectionIndex)
|
||||
} or
|
||||
TRawIndirectInstruction0(Node0Impl node, int indirectionIndex) {
|
||||
not exists(node.asOperand()) and
|
||||
SsaImpl::hasRawIndirectInstruction(node.asInstruction(), indirectionIndex)
|
||||
Ssa::hasRawIndirectInstruction(node.asInstruction(), indirectionIndex)
|
||||
} or
|
||||
TFinalParameterNode(Parameter p, int indirectionIndex) {
|
||||
exists(SsaImpl::FinalParameterUse use |
|
||||
exists(Ssa::FinalParameterUse use |
|
||||
use.getParameter() = p and
|
||||
use.getIndirectionIndex() = indirectionIndex
|
||||
)
|
||||
} or
|
||||
TFinalGlobalValue(SsaImpl::GlobalUse globalUse) or
|
||||
TInitialGlobalValue(SsaImpl::GlobalDef globalUse) or
|
||||
TFinalGlobalValue(Ssa::GlobalUse globalUse) or
|
||||
TInitialGlobalValue(Ssa::GlobalDef globalUse) or
|
||||
TBodyLessParameterNodeImpl(Parameter p, int indirectionIndex) {
|
||||
// Rule out parameters of catch blocks.
|
||||
not exists(p.getCatchBlock()) and
|
||||
// We subtract one because `getMaxIndirectionsForType` returns the maximum
|
||||
// indirection for a glvalue of a given type, and this doesn't apply to
|
||||
// parameters.
|
||||
indirectionIndex = [0 .. SsaImpl::getMaxIndirectionsForType(p.getUnspecifiedType()) - 1] and
|
||||
indirectionIndex = [0 .. Ssa::getMaxIndirectionsForType(p.getUnspecifiedType()) - 1] and
|
||||
not any(InitializeParameterInstruction init).getParameter() = p
|
||||
} or
|
||||
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn)
|
||||
@@ -78,7 +81,7 @@ private newtype TIRDataFlowNode =
|
||||
class FieldAddress extends Operand {
|
||||
FieldAddressInstruction fai;
|
||||
|
||||
FieldAddress() { fai = this.getDef() and not SsaImpl::ignoreOperand(this) }
|
||||
FieldAddress() { fai = this.getDef() and not Ssa::ignoreOperand(this) }
|
||||
|
||||
/** Gets the field associated with this instruction. */
|
||||
Field getField() { result = fai.getField() }
|
||||
@@ -123,7 +126,7 @@ predicate conversionFlow(
|
||||
)
|
||||
or
|
||||
additional = true and
|
||||
SsaImpl::isAdditionalConversionFlow(opFrom, instrTo)
|
||||
Ssa::isAdditionalConversionFlow(opFrom, instrTo)
|
||||
)
|
||||
or
|
||||
isPointerArith = true and
|
||||
@@ -180,7 +183,7 @@ class Node extends TIRDataFlowNode {
|
||||
or
|
||||
this.asOperand().getUse() = block.getInstruction(i)
|
||||
or
|
||||
exists(SsaImpl::SynthNode ssaNode |
|
||||
exists(Ssa::SynthNode ssaNode |
|
||||
this.(SsaSynthNode).getSynthNode() = ssaNode and
|
||||
ssaNode.getBasicBlock() = block and
|
||||
ssaNode.getIndex() = i
|
||||
@@ -361,10 +364,10 @@ class Node extends TIRDataFlowNode {
|
||||
* pointed to by `p`.
|
||||
*/
|
||||
Expr asDefinition(boolean uncertain) {
|
||||
exists(StoreInstruction store, SsaImpl::Definition def |
|
||||
exists(StoreInstruction store, Ssa::Definition def |
|
||||
store = this.asInstruction() and
|
||||
result = asDefinitionImpl(store) and
|
||||
SsaImpl::defToNode(this, def, _) and
|
||||
Ssa::defToNode(this, def, _) and
|
||||
if def.isCertain() then uncertain = false else uncertain = true
|
||||
)
|
||||
}
|
||||
@@ -624,7 +627,7 @@ class OperandNode extends Node, Node0 {
|
||||
* For example, `stripPointers(int*&)` is `int*` and `stripPointers(int*)` is `int`.
|
||||
*/
|
||||
Type stripPointer(Type t) {
|
||||
result = any(SsaImpl::Indirection ind | ind.getType() = t).getBaseType()
|
||||
result = any(Ssa::Indirection ind | ind.getType() = t).getBaseType()
|
||||
or
|
||||
result = t.(PointerToMemberType).getBaseType()
|
||||
or
|
||||
@@ -691,12 +694,12 @@ class PostFieldUpdateNode extends PostUpdateNodeImpl {
|
||||
* in a data flow graph.
|
||||
*/
|
||||
class SsaSynthNode extends Node, TSsaSynthNode {
|
||||
SsaImpl::SynthNode node;
|
||||
Ssa::SynthNode node;
|
||||
|
||||
SsaSynthNode() { this = TSsaSynthNode(node) }
|
||||
|
||||
/** Gets the synthesized SSA node associated with this node. */
|
||||
SsaImpl::SynthNode getSynthNode() { result = node }
|
||||
Ssa::SynthNode getSynthNode() { result = node }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asSourceCallable() = this.getFunction()
|
||||
@@ -779,12 +782,12 @@ class SideEffectOperandNode extends Node instanceof IndirectOperand {
|
||||
* from a function body.
|
||||
*/
|
||||
class FinalGlobalValue extends Node, TFinalGlobalValue {
|
||||
SsaImpl::GlobalUse globalUse;
|
||||
Ssa::GlobalUse globalUse;
|
||||
|
||||
FinalGlobalValue() { this = TFinalGlobalValue(globalUse) }
|
||||
|
||||
/** Gets the underlying SSA use. */
|
||||
SsaImpl::GlobalUse getGlobalUse() { result = globalUse }
|
||||
Ssa::GlobalUse getGlobalUse() { result = globalUse }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asSourceCallable() = this.getFunction()
|
||||
@@ -795,7 +798,7 @@ class FinalGlobalValue extends Node, TFinalGlobalValue {
|
||||
override DataFlowType getType() {
|
||||
exists(int indirectionIndex |
|
||||
indirectionIndex = globalUse.getIndirectionIndex() and
|
||||
result = getTypeImpl(globalUse.getUnderlyingType(), indirectionIndex)
|
||||
result = getTypeImpl(globalUse.getUnderlyingType(), indirectionIndex - 1)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -811,12 +814,12 @@ class FinalGlobalValue extends Node, TFinalGlobalValue {
|
||||
* a function body.
|
||||
*/
|
||||
class InitialGlobalValue extends Node, TInitialGlobalValue {
|
||||
SsaImpl::GlobalDef globalDef;
|
||||
Ssa::GlobalDef globalDef;
|
||||
|
||||
InitialGlobalValue() { this = TInitialGlobalValue(globalDef) }
|
||||
|
||||
/** Gets the underlying SSA definition. */
|
||||
SsaImpl::GlobalDef getGlobalDef() { result = globalDef }
|
||||
Ssa::GlobalDef getGlobalDef() { result = globalDef }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asSourceCallable() = this.getFunction()
|
||||
@@ -1285,11 +1288,11 @@ class UninitializedNode extends Node {
|
||||
LocalVariable v;
|
||||
|
||||
UninitializedNode() {
|
||||
exists(SsaImpl::Definition def, SsaImpl::SourceVariable sv |
|
||||
exists(Ssa::Definition def, Ssa::SourceVariable sv |
|
||||
def.getIndirectionIndex() = 0 and
|
||||
def.getValue().asInstruction() instanceof UninitializedInstruction and
|
||||
SsaImpl::defToNode(this, def, sv) and
|
||||
v = sv.getBaseVariable().(SsaImpl::BaseIRVariable).getIRVariable().getAst()
|
||||
Ssa::defToNode(this, def, sv) and
|
||||
v = sv.getBaseVariable().(Ssa::BaseIRVariable).getIRVariable().getAst()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1719,7 +1722,7 @@ private module Cached {
|
||||
cached
|
||||
predicate flowsToBackEdge(Node n) {
|
||||
exists(Node succ, IRBlock bb1, IRBlock bb2 |
|
||||
SsaImpl::ssaFlow(n, succ) and
|
||||
Ssa::ssaFlow(n, succ) and
|
||||
bb1 = n.getBasicBlock() and
|
||||
bb2 = succ.getBasicBlock() and
|
||||
bb1 != bb2 and
|
||||
@@ -1817,7 +1820,7 @@ private module Cached {
|
||||
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
|
||||
(
|
||||
// Def-use/Use-use flow
|
||||
SsaImpl::ssaFlow(nodeFrom, nodeTo)
|
||||
Ssa::ssaFlow(nodeFrom, nodeTo)
|
||||
or
|
||||
IteratorFlow::localFlowStep(nodeFrom, nodeTo)
|
||||
or
|
||||
@@ -1830,7 +1833,7 @@ private module Cached {
|
||||
|
|
||||
simpleOperandLocalFlowStep(iFrom, opTo) and
|
||||
// Omit when the instruction node also represents the operand.
|
||||
not iFrom = SsaImpl::getIRRepresentationOfOperand(opTo)
|
||||
not iFrom = Ssa::getIRRepresentationOfOperand(opTo)
|
||||
)
|
||||
or
|
||||
// Indirect operand -> (indirect) instruction flow
|
||||
@@ -1903,7 +1906,7 @@ private module Cached {
|
||||
// We also want a write coming out of an `OutNode` to flow `nodeTo`.
|
||||
// This is different from `reverseFlowInstruction` since `nodeFrom` can never
|
||||
// be an `OutNode` when it's defined by an instruction.
|
||||
SsaImpl::outNodeHasAddressAndIndex(nodeFrom, address, indirectionIndex)
|
||||
Ssa::outNodeHasAddressAndIndex(nodeFrom, address, indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2096,7 +2099,7 @@ private newtype TContent =
|
||||
TFieldContent(Field f, int indirectionIndex) {
|
||||
// the indirection index for field content starts at 1 (because `TFieldContent` is thought of as
|
||||
// the address of the field, `FieldAddress` in the IR).
|
||||
indirectionIndex = [1 .. SsaImpl::getMaxIndirectionsForType(f.getUnspecifiedType())] and
|
||||
indirectionIndex = [1 .. Ssa::getMaxIndirectionsForType(f.getUnspecifiedType())] and
|
||||
// Reads and writes of union fields are tracked using `UnionContent`.
|
||||
not f.getDeclaringType() instanceof Union
|
||||
} or
|
||||
@@ -2108,9 +2111,7 @@ private newtype TContent =
|
||||
// field can be read by any read of the union's fields. Again, the indirection index
|
||||
// is 1-based (because 0 is considered the address).
|
||||
indirectionIndex =
|
||||
[1 .. max(SsaImpl::getMaxIndirectionsForType(getAFieldWithSize(u, bytes)
|
||||
.getUnspecifiedType())
|
||||
)]
|
||||
[1 .. max(Ssa::getMaxIndirectionsForType(getAFieldWithSize(u, bytes).getUnspecifiedType()))]
|
||||
)
|
||||
} or
|
||||
TElementContent(int indirectionIndex) {
|
||||
@@ -2353,7 +2354,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
controls(g, result, edge)
|
||||
)
|
||||
or
|
||||
result = SsaImpl::BarrierGuard<guardChecksNode/3>::getABarrierNode()
|
||||
result = Ssa::BarrierGuard<guardChecksNode/3>::getABarrierNode()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2452,7 +2453,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
)
|
||||
or
|
||||
result =
|
||||
SsaImpl::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
|
||||
Ssa::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2489,7 +2490,7 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
|
||||
controls(g, result, edge)
|
||||
)
|
||||
or
|
||||
result = SsaImpl::BarrierGuard<guardChecksNode/3>::getABarrierNode()
|
||||
result = Ssa::BarrierGuard<guardChecksNode/3>::getABarrierNode()
|
||||
}
|
||||
|
||||
bindingset[value, n]
|
||||
@@ -2519,7 +2520,7 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
|
||||
)
|
||||
or
|
||||
result =
|
||||
SsaImpl::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
|
||||
Ssa::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2575,16 +2576,3 @@ Function getARuntimeTarget(Call call) {
|
||||
result = DataFlowImplCommon::viableCallableLambda(dfCall, _).asSourceCallable()
|
||||
)
|
||||
}
|
||||
|
||||
/** A module that provides static single assignment (SSA) information. */
|
||||
module Ssa {
|
||||
class Definition = SsaImpl::Definition;
|
||||
|
||||
class ExplicitDefinition = SsaImpl::ExplicitDefinition;
|
||||
|
||||
class DirectExplicitDefinition = SsaImpl::DirectExplicitDefinition;
|
||||
|
||||
class IndirectExplicitDefinition = SsaImpl::IndirectExplicitDefinition;
|
||||
|
||||
class PhiNode = SsaImpl::PhiNode;
|
||||
}
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
private import SsaImpl as Ssa
|
||||
private import SsaInternals as Ssa
|
||||
|
||||
/**
|
||||
* Gets the instruction that goes into `input` for `call`.
|
||||
*/
|
||||
Node callInput(CallInstruction call, FunctionInput input) {
|
||||
DataFlow::Node callInput(CallInstruction call, FunctionInput input) {
|
||||
// An argument or qualifier
|
||||
exists(int index |
|
||||
result.asOperand() = call.getArgumentOperand(index) and
|
||||
@@ -62,8 +62,8 @@ Node callOutput(CallInstruction call, FunctionOutput output) {
|
||||
result = callOutputWithIndirectionIndex(call, output, _)
|
||||
}
|
||||
|
||||
Node callInput(CallInstruction call, FunctionInput input, int d) {
|
||||
exists(Node n | n = callInput(call, input) and d > 0 |
|
||||
DataFlow::Node callInput(CallInstruction call, FunctionInput input, int d) {
|
||||
exists(DataFlow::Node n | n = callInput(call, input) and d > 0 |
|
||||
// An argument or qualifier
|
||||
hasOperandAndIndex(result, n.asOperand(), d)
|
||||
or
|
||||
@@ -85,7 +85,7 @@ private IndirectReturnOutNode getIndirectReturnOutNode(CallInstruction call, int
|
||||
*/
|
||||
bindingset[d]
|
||||
Node callOutput(CallInstruction call, FunctionOutput output, int d) {
|
||||
exists(Node n, int indirectionIndex |
|
||||
exists(DataFlow::Node n, int indirectionIndex |
|
||||
n = callOutputWithIndirectionIndex(call, output, indirectionIndex) and d > 0
|
||||
|
|
||||
// The return value
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import SsaImpl as Ssa
|
||||
private import SsaInternals as Ssa
|
||||
|
||||
/**
|
||||
* A property provider that hides all instructions and operands that are not relevant for IR dataflow.
|
||||
|
||||
@@ -2,7 +2,7 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import SsaImpl as Ssa
|
||||
private import SsaInternals as Ssa
|
||||
private import PrintIRUtilities
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
private import codeql.ssa.Ssa as Ssa
|
||||
private import codeql.ssa.Ssa as SsaImplCommon
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import DataFlowUtil
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
@@ -12,7 +12,7 @@ private import semmle.code.cpp.ir.internal.IRCppLanguage
|
||||
private import semmle.code.cpp.ir.dataflow.internal.ModelUtil
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedInitialization
|
||||
private import DataFlowPrivate
|
||||
import SsaImplCommon
|
||||
import SsaInternalsCommon
|
||||
|
||||
private module SourceVariables {
|
||||
cached
|
||||
@@ -143,14 +143,7 @@ private predicate isGlobalUse(
|
||||
min(int cand, VariableAddressInstruction vai |
|
||||
vai.getEnclosingIRFunction() = f and
|
||||
vai.getAstVariable() = v and
|
||||
(
|
||||
isDef(_, _, _, vai, cand, indirectionIndex)
|
||||
or
|
||||
exists(Operand operand |
|
||||
isUse(_, operand, vai, cand, indirectionIndex) and
|
||||
isPostUpdateNodeImpl(operand, indirectionIndex)
|
||||
)
|
||||
)
|
||||
isDef(_, _, _, vai, cand, indirectionIndex)
|
||||
|
|
||||
cand
|
||||
)
|
||||
@@ -756,9 +749,9 @@ private predicate modeledFlowBarrier(Node n) {
|
||||
partialFlowFunc = call.getStaticCallTarget() and
|
||||
not partialFlowFunc.isPartialWrite(output)
|
||||
|
|
||||
partialFlowFunc.(DataFlow::DataFlowFunction).hasDataFlow(_, output)
|
||||
call.getStaticCallTarget().(DataFlow::DataFlowFunction).hasDataFlow(_, output)
|
||||
or
|
||||
partialFlowFunc.(Taint::TaintFunction).hasTaintFlow(_, output)
|
||||
call.getStaticCallTarget().(Taint::TaintFunction).hasTaintFlow(_, output)
|
||||
)
|
||||
or
|
||||
exists(Operand operand, Instruction instr, Node n0, int indirectionIndex |
|
||||
@@ -891,7 +884,7 @@ private predicate baseSourceVariableIsGlobal(
|
||||
)
|
||||
}
|
||||
|
||||
private module SsaInput implements Ssa::InputSig<Location> {
|
||||
private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
import InputSigCommon
|
||||
import SourceVariables
|
||||
|
||||
@@ -965,11 +958,9 @@ class GlobalDef extends Definition {
|
||||
GlobalLikeVariable getVariable() { result = impl.getVariable() }
|
||||
}
|
||||
|
||||
private module SsaImpl = Ssa::Make<Location, SsaInput>;
|
||||
private module SsaImpl = SsaImplCommon::Make<Location, SsaInput>;
|
||||
|
||||
private module DataFlowIntegrationInput implements SsaImpl::DataFlowIntegrationInputSig {
|
||||
private import codeql.util.Boolean
|
||||
|
||||
class Expr extends Instruction {
|
||||
Expr() {
|
||||
exists(IRBlock bb, int i |
|
||||
@@ -1001,14 +992,10 @@ private module DataFlowIntegrationInput implements SsaImpl::DataFlowIntegrationI
|
||||
result instanceof FalseEdge
|
||||
}
|
||||
|
||||
class GuardValue = Boolean;
|
||||
|
||||
class Guard instanceof IRGuards::IRGuardCondition {
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasValueBranchEdge(
|
||||
SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, GuardValue branch
|
||||
) {
|
||||
predicate hasBranchEdge(SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, boolean branch) {
|
||||
exists(EdgeKind kind |
|
||||
super.getBlock() = bb1 and
|
||||
kind = getConditionalEdge(branch) and
|
||||
@@ -1016,14 +1003,12 @@ private module DataFlowIntegrationInput implements SsaImpl::DataFlowIntegrationI
|
||||
)
|
||||
}
|
||||
|
||||
predicate valueControlsBranchEdge(
|
||||
SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, GuardValue branch
|
||||
) {
|
||||
this.hasValueBranchEdge(bb1, bb2, branch)
|
||||
predicate controlsBranchEdge(SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, boolean branch) {
|
||||
this.hasBranchEdge(bb1, bb2, branch)
|
||||
}
|
||||
}
|
||||
|
||||
predicate guardDirectlyControlsBlock(Guard guard, SsaInput::BasicBlock bb, GuardValue branch) {
|
||||
predicate guardDirectlyControlsBlock(Guard guard, SsaInput::BasicBlock bb, boolean branch) {
|
||||
guard.(IRGuards::IRGuardCondition).controls(bb, branch)
|
||||
}
|
||||
|
||||
@@ -1052,8 +1037,7 @@ module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
|
||||
}
|
||||
|
||||
private predicate guardChecks(
|
||||
DataFlowIntegrationInput::Guard g, SsaImpl::Definition def,
|
||||
DataFlowIntegrationInput::GuardValue branch, int indirectionIndex
|
||||
DataFlowIntegrationInput::Guard g, SsaImpl::Definition def, boolean branch, int indirectionIndex
|
||||
) {
|
||||
exists(UseImpl use |
|
||||
guardChecksNode(g, use.getNode(), branch, indirectionIndex) and
|
||||
@@ -1132,11 +1116,9 @@ class PhiNode extends Definition instanceof SsaImpl::PhiNode {
|
||||
|
||||
/** An static single assignment (SSA) definition. */
|
||||
class Definition extends SsaImpl::Definition {
|
||||
private Definition getAPhiInputOrPriorDefinition() {
|
||||
result = this.(PhiNode).getAnInput()
|
||||
or
|
||||
SsaImpl::uncertainWriteDefinitionInput(this, result)
|
||||
}
|
||||
// TODO: Include prior definitions of uncertain writes or rename predicate
|
||||
// i.e. the disjunct `SsaImpl::uncertainWriteDefinitionInput(this, result)`
|
||||
private Definition getAPhiInputOrPriorDefinition() { result = this.(PhiNode).getAnInput() }
|
||||
|
||||
/**
|
||||
* Gets a definition that ultimately defines this SSA definition and is
|
||||
@@ -1147,36 +1129,6 @@ class Definition extends SsaImpl::Definition {
|
||||
not result instanceof PhiNode
|
||||
}
|
||||
|
||||
/** Gets an `Operand` that represents a use of this definition. */
|
||||
Operand getAUse() {
|
||||
exists(SourceVariable sv, IRBlock bb, int i, UseImpl use |
|
||||
ssaDefReachesRead(sv, this, bb, i) and
|
||||
use.hasIndexInBlock(bb, i, sv) and
|
||||
result = use.getNode().asOperand()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an `Operand` that represents an indirect use of this definition.
|
||||
*
|
||||
* The use is indirect because the operand represents a pointer that points
|
||||
* to the value written by this definition. For example in:
|
||||
* ```cpp
|
||||
* 1. int x = 42;
|
||||
* 2. int* p = &x;
|
||||
* ```
|
||||
* There is an `ExplicitDefinition` corresponding to `x = 42` on line 1 and
|
||||
* the definition has an indirect use on line 2 because `&x` points to the
|
||||
* value that was defined by the definition.
|
||||
*/
|
||||
Operand getAnIndirectUse(int indirectionIndex) {
|
||||
exists(SourceVariable sv, IRBlock bb, int i, UseImpl use |
|
||||
ssaDefReachesRead(sv, this, bb, i) and
|
||||
use.hasIndexInBlock(bb, i, sv) and
|
||||
result = use.getNode().asIndirectOperand(indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
@@ -1209,63 +1161,4 @@ class Definition extends SsaImpl::Definition {
|
||||
Type getUnspecifiedType() { result = this.getUnderlyingType().getUnspecifiedType() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An SSA definition that corresponds to an explicit definition.
|
||||
*/
|
||||
class ExplicitDefinition extends Definition, SsaImpl::WriteDefinition {
|
||||
DefImpl def;
|
||||
|
||||
ExplicitDefinition() {
|
||||
exists(IRBlock bb, int i, SourceVariable sv |
|
||||
this.definesAt(sv, bb, i) and
|
||||
def.hasIndexInBlock(sv, bb, i)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` computing the value that is written to the
|
||||
* associated SSA variable by this SSA definition.
|
||||
*
|
||||
* If `this.getIndirectionIndex() = 0` (i.e., if `this` is an instance of
|
||||
* `DirectExplicitDefinition`) then the SSA variable is present in the source
|
||||
* code.
|
||||
* However, if `this.getIndirectionIndex() > 0` (i.e., if `this` is an
|
||||
* instance of `IndirectExplicitDefinition`) then the SSA variable associated
|
||||
* with this definition represents the memory pointed to by a variable in the
|
||||
* source code.
|
||||
*/
|
||||
Instruction getAssignedInstruction() { result = def.getValue().asInstruction() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An explicit SSA definition that writes an indirect value to a pointer.
|
||||
*
|
||||
* For example in:
|
||||
* ```cpp
|
||||
* int x = 42; // (1)
|
||||
* int* p = &x; // (2)
|
||||
* ```
|
||||
* There are three `ExplicitDefinition`:
|
||||
* 1. A `DirectExplicitDefinition` at (1) which writes `42` to the SSA variable
|
||||
* corresponding to `x`.
|
||||
* 2. A `DirectExplicitDefinition` at (2) which writes `&x` to the SSA variable
|
||||
* corresponding to `p`.
|
||||
* 3. A `IndirectExplicitDefinition` at (2) which writes `*&x` (i.e., `x`) to
|
||||
* the SSA variable corresponding to `*p`.
|
||||
*/
|
||||
class IndirectExplicitDefinition extends ExplicitDefinition {
|
||||
IndirectExplicitDefinition() { this.getIndirectionIndex() > 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* An SSA definition that corresponds to an explicit definition.
|
||||
*
|
||||
* Unlike `ExplicitDefinition` this class does not include indirect
|
||||
* explicit definition. See `IndirectExplicitDefinition` if you want to include
|
||||
* those.
|
||||
*/
|
||||
class DirectExplicitDefinition extends ExplicitDefinition {
|
||||
DirectExplicitDefinition() { this.getIndirectionIndex() = 0 }
|
||||
}
|
||||
|
||||
import SsaCached
|
||||
@@ -5,7 +5,7 @@ private import semmle.code.cpp.models.interfaces.DataFlow
|
||||
private import semmle.code.cpp.models.interfaces.SideEffect
|
||||
private import DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
private import SsaImpl as Ssa
|
||||
private import SsaInternals as Ssa
|
||||
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.cpp.ir.dataflow.FlowSteps
|
||||
|
||||
|
||||
@@ -43,23 +43,6 @@ newtype TValueNumber =
|
||||
} or
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
* where `T` and `U` only differ in specifiers. For example, if `T` is `int`
|
||||
* and `U` is `const T` this is a conversion from a non-const integer to a
|
||||
* const integer.
|
||||
*
|
||||
* Generally, the value number of a converted value is different from the value
|
||||
* number of an unconverted value, but conversions which only modify specifiers
|
||||
* leave the resulting value bitwise identical to the old value.
|
||||
*/
|
||||
class TypePreservingConvertInstruction extends ConvertInstruction {
|
||||
TypePreservingConvertInstruction() {
|
||||
pragma[only_bind_out](this.getResultType().getUnspecifiedType()) =
|
||||
pragma[only_bind_out](this.getUnary().getResultType().getUnspecifiedType())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
|
||||
* operand.
|
||||
@@ -233,7 +216,6 @@ private predicate unaryValueNumber(
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
not instr instanceof TypePreservingConvertInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
@@ -369,10 +351,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -43,23 +43,6 @@ newtype TValueNumber =
|
||||
} or
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
* where `T` and `U` only differ in specifiers. For example, if `T` is `int`
|
||||
* and `U` is `const T` this is a conversion from a non-const integer to a
|
||||
* const integer.
|
||||
*
|
||||
* Generally, the value number of a converted value is different from the value
|
||||
* number of an unconverted value, but conversions which only modify specifiers
|
||||
* leave the resulting value bitwise identical to the old value.
|
||||
*/
|
||||
class TypePreservingConvertInstruction extends ConvertInstruction {
|
||||
TypePreservingConvertInstruction() {
|
||||
pragma[only_bind_out](this.getResultType().getUnspecifiedType()) =
|
||||
pragma[only_bind_out](this.getUnary().getResultType().getUnspecifiedType())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
|
||||
* operand.
|
||||
@@ -233,7 +216,6 @@ private predicate unaryValueNumber(
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
not instr instanceof TypePreservingConvertInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
@@ -369,10 +351,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -96,8 +96,7 @@ newtype TInstructionTag =
|
||||
exists(Expr e | exists(e.getImplicitDestructorCall(index))) or
|
||||
exists(Stmt s | exists(s.getImplicitDestructorCall(index)))
|
||||
} or
|
||||
CoAwaitBranchTag() or
|
||||
BoolToIntConversionTag()
|
||||
CoAwaitBranchTag()
|
||||
|
||||
class InstructionTag extends TInstructionTag {
|
||||
final string toString() { result = getInstructionTagId(this) }
|
||||
@@ -287,6 +286,4 @@ string getInstructionTagId(TInstructionTag tag) {
|
||||
)
|
||||
or
|
||||
tag = CoAwaitBranchTag() and result = "CoAwaitBranch"
|
||||
or
|
||||
tag = BoolToIntConversionTag() and result = "BoolToIntConversion"
|
||||
}
|
||||
|
||||
@@ -509,41 +509,6 @@ predicate hasTranslatedSyntheticTemporaryObject(Expr expr) {
|
||||
not expr.hasLValueToRValueConversion()
|
||||
}
|
||||
|
||||
Opcode comparisonOpcode(ComparisonOperation expr) {
|
||||
expr instanceof EQExpr and result instanceof Opcode::CompareEQ
|
||||
or
|
||||
expr instanceof NEExpr and result instanceof Opcode::CompareNE
|
||||
or
|
||||
expr instanceof LTExpr and result instanceof Opcode::CompareLT
|
||||
or
|
||||
expr instanceof GTExpr and result instanceof Opcode::CompareGT
|
||||
or
|
||||
expr instanceof LEExpr and result instanceof Opcode::CompareLE
|
||||
or
|
||||
expr instanceof GEExpr and result instanceof Opcode::CompareGE
|
||||
}
|
||||
|
||||
private predicate parentExpectsBool(Expr child) {
|
||||
any(NotExpr notExpr).getOperand() = child
|
||||
or
|
||||
usedAsCondition(child)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `expr` should have a `TranslatedSyntheticBoolToIntConversion` on it.
|
||||
*/
|
||||
predicate hasTranslatedSyntheticBoolToIntConversion(Expr expr) {
|
||||
not ignoreExpr(expr) and
|
||||
not isIRConstant(expr) and
|
||||
not parentExpectsBool(expr) and
|
||||
expr.getUnspecifiedType() instanceof IntType and
|
||||
(
|
||||
expr instanceof NotExpr
|
||||
or
|
||||
exists(comparisonOpcode(expr))
|
||||
)
|
||||
}
|
||||
|
||||
class StaticInitializedStaticLocalVariable extends StaticLocalVariable {
|
||||
StaticInitializedStaticLocalVariable() {
|
||||
this.hasInitializer() and
|
||||
@@ -682,9 +647,6 @@ newtype TTranslatedElement =
|
||||
// A temporary object that we had to synthesize ourselves, so that we could do a field access or
|
||||
// method call on a prvalue.
|
||||
TTranslatedSyntheticTemporaryObject(Expr expr) { hasTranslatedSyntheticTemporaryObject(expr) } or
|
||||
TTranslatedSyntheticBoolToIntConversion(Expr expr) {
|
||||
hasTranslatedSyntheticBoolToIntConversion(expr)
|
||||
} or
|
||||
// For expressions that would not otherwise generate an instruction.
|
||||
TTranslatedResultCopy(Expr expr) {
|
||||
not ignoreExpr(expr) and
|
||||
|
||||
@@ -216,8 +216,7 @@ abstract class TranslatedCoreExpr extends TranslatedExpr {
|
||||
not hasTranslatedLoad(expr) and
|
||||
not hasTranslatedSyntheticTemporaryObject(expr) and
|
||||
// If there's a result copy, then this expression's result is the copy.
|
||||
not exprNeedsCopyIfNotLoaded(expr) and
|
||||
not hasTranslatedSyntheticBoolToIntConversion(expr)
|
||||
not exprNeedsCopyIfNotLoaded(expr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,12 +358,11 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of a node synthesized to adjust the value category or type of its operand.
|
||||
* The IR translation of a node synthesized to adjust the value category of its operand.
|
||||
* One of:
|
||||
* - `TranslatedLoad` - Convert from glvalue to prvalue by loading from the location.
|
||||
* - `TranslatedSyntheticTemporaryObject` - Convert from prvalue to glvalue by storing to a
|
||||
* temporary variable.
|
||||
* - `TranslatedSyntheticBoolToIntConversion` - Convert a prvalue Boolean to a prvalue integer.
|
||||
*/
|
||||
abstract class TranslatedValueCategoryAdjustment extends TranslatedExpr {
|
||||
final override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
@@ -515,45 +513,6 @@ class TranslatedSyntheticTemporaryObject extends TranslatedValueCategoryAdjustme
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedSyntheticBoolToIntConversion extends TranslatedValueCategoryAdjustment,
|
||||
TTranslatedSyntheticBoolToIntConversion
|
||||
{
|
||||
TranslatedSyntheticBoolToIntConversion() { this = TTranslatedSyntheticBoolToIntConversion(expr) }
|
||||
|
||||
override string toString() { result = "Bool-to-int conversion of " + expr.toString() }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
opcode instanceof Opcode::Convert and
|
||||
tag = BoolToIntConversionTag() and
|
||||
resultType = getIntType()
|
||||
}
|
||||
|
||||
override predicate isResultGLValue() { none() }
|
||||
|
||||
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
|
||||
tag = BoolToIntConversionTag() and
|
||||
result = this.getParent().getChildSuccessor(this, kind)
|
||||
}
|
||||
|
||||
override Instruction getALastInstructionInternal() {
|
||||
result = this.getInstruction(BoolToIntConversionTag())
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
|
||||
child = this.getOperand() and
|
||||
result = this.getInstruction(BoolToIntConversionTag()) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getResult() { result = this.getInstruction(BoolToIntConversionTag()) }
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = BoolToIntConversionTag() and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = this.getOperand().getResult()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* IR translation of an expression that simply returns its result. We generate an otherwise useless
|
||||
* `CopyValue` instruction for these expressions so that there is at least one instruction
|
||||
@@ -1835,6 +1794,20 @@ private Opcode binaryArithmeticOpcode(BinaryArithmeticOperation expr) {
|
||||
expr instanceof PointerDiffExpr and result instanceof Opcode::PointerDiff
|
||||
}
|
||||
|
||||
private Opcode comparisonOpcode(ComparisonOperation expr) {
|
||||
expr instanceof EQExpr and result instanceof Opcode::CompareEQ
|
||||
or
|
||||
expr instanceof NEExpr and result instanceof Opcode::CompareNE
|
||||
or
|
||||
expr instanceof LTExpr and result instanceof Opcode::CompareLT
|
||||
or
|
||||
expr instanceof GTExpr and result instanceof Opcode::CompareGT
|
||||
or
|
||||
expr instanceof LEExpr and result instanceof Opcode::CompareLE
|
||||
or
|
||||
expr instanceof GEExpr and result instanceof Opcode::CompareGE
|
||||
}
|
||||
|
||||
private Opcode spaceShipOpcode(SpaceshipExpr expr) {
|
||||
exists(expr) and
|
||||
result instanceof Opcode::Spaceship
|
||||
|
||||
@@ -43,23 +43,6 @@ newtype TValueNumber =
|
||||
} or
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
* where `T` and `U` only differ in specifiers. For example, if `T` is `int`
|
||||
* and `U` is `const T` this is a conversion from a non-const integer to a
|
||||
* const integer.
|
||||
*
|
||||
* Generally, the value number of a converted value is different from the value
|
||||
* number of an unconverted value, but conversions which only modify specifiers
|
||||
* leave the resulting value bitwise identical to the old value.
|
||||
*/
|
||||
class TypePreservingConvertInstruction extends ConvertInstruction {
|
||||
TypePreservingConvertInstruction() {
|
||||
pragma[only_bind_out](this.getResultType().getUnspecifiedType()) =
|
||||
pragma[only_bind_out](this.getUnary().getResultType().getUnspecifiedType())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
|
||||
* operand.
|
||||
@@ -233,7 +216,6 @@ private predicate unaryValueNumber(
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
not instr instanceof TypePreservingConvertInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
@@ -369,10 +351,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -170,16 +170,6 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction {
|
||||
output.isParameterDeref(this.getOutputParameterIndex(_))
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate isPartialWrite(FunctionOutput output) {
|
||||
exists(int outputParameterIndex |
|
||||
output.isParameterDeref(outputParameterIndex) and
|
||||
// We require the output to be a stream since that definitely means that
|
||||
// it's a partial write. If it's not a stream then it will most likely
|
||||
// fill the whole buffer.
|
||||
outputParameterIndex = this.getOutputParameterIndex(true)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,9 +14,6 @@ import semmle.code.cpp.ConfigurationTestFile
|
||||
from GlobalVariable gv
|
||||
where
|
||||
gv.getName().length() <= 3 and
|
||||
// We will give an alert for the TemplateVariable, so we don't
|
||||
// need to also give one for each instantiation
|
||||
not gv instanceof VariableTemplateInstantiation and
|
||||
not gv.isStatic() and
|
||||
not gv.getFile() instanceof ConfigurationTestFile // variables in files generated during configuration are likely false positives
|
||||
select gv,
|
||||
|
||||
@@ -1,16 +1,3 @@
|
||||
## 1.4.6
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/short-global-name` query will no longer give alerts for instantiations of template variables, only for the template itself.
|
||||
* Fixed a false positive in `cpp/overflow-buffer` when the type of the destination buffer is a reference to a class/struct type.
|
||||
|
||||
## 1.4.5
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The "Initialization code not run" query (`cpp/initialization-not-run`) no longer reports an alert on static global variables that have no dereference.
|
||||
|
||||
## 1.4.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -32,18 +32,9 @@ predicate called(Function f) {
|
||||
exists(FunctionAccess fa | fa.getTarget() = f)
|
||||
}
|
||||
|
||||
predicate staticWithoutDereference(GlobalVariable v) {
|
||||
v.isStatic() and
|
||||
not exists(VariableAccess va |
|
||||
va = v.getAnAccess() and
|
||||
dereferenced(va)
|
||||
)
|
||||
}
|
||||
|
||||
from GlobalVariable v
|
||||
where
|
||||
global(v) and
|
||||
not staticWithoutDereference(v) and
|
||||
not exists(VariableAccess lval |
|
||||
v.getAnAccess() = lval and
|
||||
lval.isUsedAsLValue() and
|
||||
|
||||
@@ -82,16 +82,6 @@ module OverflowDestinationConfig implements DataFlow::ConfigSig {
|
||||
nodeIsBarrierEqualityCandidate(node, access, checkedVar)
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(FunctionCall fc | result = fc.getLocation() |
|
||||
sourceSized(fc, sink.asIndirectConvertedExpr())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module OverflowDestination = TaintTracking::Global<OverflowDestinationConfig>;
|
||||
|
||||
@@ -168,19 +168,6 @@ module NonConstFlowConfig implements DataFlow::ConfigSig {
|
||||
cannotContainString(t)
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
result = sink.getLocation()
|
||||
or
|
||||
exists(FormattingFunctionCall call, Expr formatString | result = call.getLocation() |
|
||||
isSinkImpl(sink, formatString) and
|
||||
call.getArgument(call.getFormatParameterIndex()) = formatString
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module NonConstFlow = TaintTracking::Global<NonConstFlowConfig>;
|
||||
|
||||
@@ -215,10 +215,6 @@ private module LeapYearCheckConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(ChecksForLeapYearFunctionCall fc | sink.asExpr() = fc.getAnArgument())
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() {
|
||||
none() // only used negatively in UncheckedLeapYearAfterYearModification.ql
|
||||
}
|
||||
}
|
||||
|
||||
module LeapYearCheckFlow = DataFlow::Global<LeapYearCheckConfig>;
|
||||
@@ -289,14 +285,6 @@ private module PossibleYearArithmeticOperationCheckConfig implements DataFlow::C
|
||||
aexpr.getLValue() = fa
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) {
|
||||
result = source.asExpr().getLocation()
|
||||
}
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) { result = sink.asExpr().getLocation() }
|
||||
}
|
||||
|
||||
module PossibleYearArithmeticOperationCheckFlow =
|
||||
|
||||
@@ -93,12 +93,6 @@ module TaintedPathConfig implements DataFlow::ConfigSig {
|
||||
// make sinks barriers so that we only report the closest instance
|
||||
isSink(node)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
result = sink.asIndirectArgument().getLocation()
|
||||
}
|
||||
}
|
||||
|
||||
module TaintedPath = TaintTracking::Global<TaintedPathConfig>;
|
||||
|
||||
@@ -150,17 +150,6 @@ module ExecTaintConfig implements DataFlow::StateConfigSig {
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(DataFlow::Node concatResult, Expr command, ExecState state |
|
||||
result = [concatResult.getLocation(), command.getLocation()] and
|
||||
isSink(sink, state) and
|
||||
isSinkImpl(sink, command, _) and
|
||||
concatResult = state.getOutgoingNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module ExecTaint = TaintTracking::GlobalWithState<ExecTaintConfig>;
|
||||
|
||||
@@ -39,12 +39,6 @@ module Config implements DataFlow::ConfigSig {
|
||||
or
|
||||
node.asCertainDefinition().getUnspecifiedType() instanceof ArithmeticType
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) {
|
||||
exists(QueryString query | result = query.getLocation() | query = source.asIndirectExpr())
|
||||
}
|
||||
}
|
||||
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
@@ -54,12 +54,6 @@ module SqlTaintedConfig implements DataFlow::ConfigSig {
|
||||
sql.barrierSqlArgument(input, _)
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(Expr taintedArg | result = taintedArg.getLocation() | taintedArg = asSinkExpr(sink))
|
||||
}
|
||||
}
|
||||
|
||||
module SqlTainted = TaintTracking::Global<SqlTaintedConfig>;
|
||||
|
||||
@@ -124,12 +124,6 @@ module Config implements DataFlow::ConfigSig {
|
||||
// Block flow if the node is guarded by any <, <= or = operations.
|
||||
node = DataFlow::BarrierGuard<lessThanOrEqual/3>::getABarrierNode()
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(BufferWrite bw | result = bw.getLocation() | isSink(sink, bw, _))
|
||||
}
|
||||
}
|
||||
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
@@ -43,12 +43,6 @@ private module Config implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(VariableAccess va | result = va.getLocation() | isSink(sink, va))
|
||||
}
|
||||
}
|
||||
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
@@ -106,12 +106,6 @@ module Config implements DataFlow::ConfigSig {
|
||||
not iTo instanceof PointerArithmeticInstruction
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(Expr e | result = e.getLocation() | isSink(sink, _, e))
|
||||
}
|
||||
}
|
||||
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
@@ -120,12 +120,6 @@ module UncontrolledArithConfig implements DataFlow::ConfigSig {
|
||||
// block unintended flow to pointers
|
||||
node.asExpr().getUnspecifiedType() instanceof PointerType
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) {
|
||||
result = getExpr(source).getLocation()
|
||||
}
|
||||
}
|
||||
|
||||
module UncontrolledArith = TaintTracking::Global<UncontrolledArithConfig>;
|
||||
|
||||
@@ -113,12 +113,6 @@ module Config implements DataFlow::ConfigSig {
|
||||
not iTo instanceof PointerArithmeticInstruction
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(VariableAccess va | result = va.getLocation() | isSink(sink, va, _))
|
||||
}
|
||||
}
|
||||
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
@@ -91,12 +91,6 @@ module TaintedAllocationSizeConfig implements DataFlow::ConfigSig {
|
||||
// to duplicate results)
|
||||
any(HeuristicAllocationFunction f).getAParameter() = node.asParameter()
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(Expr alloc | result = alloc.getLocation() | allocSink(alloc, sink))
|
||||
}
|
||||
}
|
||||
|
||||
module TaintedAllocationSize = TaintTracking::Global<TaintedAllocationSizeConfig>;
|
||||
|
||||
@@ -72,12 +72,6 @@ module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isSource(source, _) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(Expr condition | result = condition.getLocation() | isSink(sink, condition))
|
||||
}
|
||||
}
|
||||
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
@@ -31,14 +31,6 @@ module VerifyResultConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(GuardCondition guard | guard.getAChild*() = sink.asExpr())
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(GuardCondition guard | result = guard.getLocation() |
|
||||
guard.comparesEq(sink.asExpr(), _, 0, false, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module VerifyResult = DataFlow::Global<VerifyResultConfig>;
|
||||
|
||||
@@ -47,12 +47,6 @@ module ToBufferConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isSinkImpl(sink, _) }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(SensitiveBufferWrite w | result = w.getLocation() | isSinkImpl(sink, w))
|
||||
}
|
||||
}
|
||||
|
||||
module ToBufferFlow = TaintTracking::Global<ToBufferConfig>;
|
||||
|
||||
@@ -31,16 +31,6 @@ module FromSensitiveConfig implements DataFlow::ConfigSig {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.asExpr().getUnspecifiedType() instanceof IntegralType
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node sourceNode) {
|
||||
exists(SensitiveExpr source | result = source.getLocation() | isSourceImpl(sourceNode, source))
|
||||
}
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(FileWrite w | result = w.getLocation() | isSinkImpl(sink, w, _))
|
||||
}
|
||||
}
|
||||
|
||||
module FromSensitiveFlow = TaintTracking::Global<FromSensitiveConfig>;
|
||||
|
||||
@@ -245,14 +245,6 @@ module FromSensitiveConfig implements DataFlow::ConfigSig {
|
||||
// sources to not get path duplication.
|
||||
isSource(node)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(NetworkSendRecv networkSendRecv | result = networkSendRecv.getLocation() |
|
||||
isSinkSendRecv(sink, networkSendRecv)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module FromSensitiveFlow = TaintTracking::Global<FromSensitiveConfig>;
|
||||
@@ -274,10 +266,6 @@ module ToEncryptionConfig implements DataFlow::ConfigSig {
|
||||
// sources to not get path duplication.
|
||||
isSource(node)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() {
|
||||
none() // only used negatively
|
||||
}
|
||||
}
|
||||
|
||||
module ToEncryptionFlow = TaintTracking::Global<ToEncryptionConfig>;
|
||||
@@ -293,10 +281,6 @@ module FromEncryptionConfig implements DataFlow::ConfigSig {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.asExpr().getUnspecifiedType() instanceof IntegralType
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() {
|
||||
none() // only used negatively
|
||||
}
|
||||
}
|
||||
|
||||
module FromEncryptionFlow = TaintTracking::Global<FromEncryptionConfig>;
|
||||
|
||||
@@ -123,20 +123,6 @@ module FromSensitiveConfig implements DataFlow::ConfigSig {
|
||||
content.(DataFlow::FieldContent).getField() = getRecField(t.stripType())
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) {
|
||||
exists(SensitiveExpr sensitive | result = sensitive.getLocation() |
|
||||
isSourceImpl(source, sensitive)
|
||||
)
|
||||
}
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(SqliteFunctionCall sqliteCall | result = sqliteCall.getLocation() |
|
||||
isSinkImpl(sink, sqliteCall, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module FromSensitiveFlow = TaintTracking::Global<FromSensitiveConfig>;
|
||||
|
||||
@@ -87,14 +87,6 @@ module HttpStringToUrlOpenConfig implements DataFlow::ConfigSig {
|
||||
sink.asIndirectExpr() = fc.getArgument(3)
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) {
|
||||
result = source.asIndirectExpr().getLocation()
|
||||
}
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
module HttpStringToUrlOpen = TaintTracking::Global<HttpStringToUrlOpenConfig>;
|
||||
|
||||
@@ -44,12 +44,6 @@ module KeyStrengthFlowConfig implements DataFlow::ConfigSig {
|
||||
exists(getMinimumKeyStrength(name, param))
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(FunctionCall fc | result = fc.getLocation() | sink.asExpr() = fc.getArgument(_))
|
||||
}
|
||||
}
|
||||
|
||||
module KeyStrengthFlow = DataFlow::Global<KeyStrengthFlowConfig>;
|
||||
|
||||
@@ -145,18 +145,6 @@ module Config implements DataFlow::StateConfigSig {
|
||||
// ```
|
||||
result instanceof DataFlow::FeatureHasSinkCallContext
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(DataFlow::Node mid, FlowState state | result = mid.getLocation() |
|
||||
destroyedToBeginSink(sink) and
|
||||
isSink(sink, state) and
|
||||
state = Config::DestroyedToBegin(mid)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module Flow = DataFlow::GlobalWithState<Config>;
|
||||
|
||||
@@ -62,16 +62,6 @@ module NullAppNameCreateProcessFunctionConfig implements DataFlow::ConfigSig {
|
||||
val = call.getArgument(call.getApplicationNameArgumentId())
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(CreateProcessFunctionCall call | result = call.getLocation() |
|
||||
sink.asExpr() = call.getArgument(call.getApplicationNameArgumentId())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module NullAppNameCreateProcessFunction = DataFlow::Global<NullAppNameCreateProcessFunctionConfig>;
|
||||
@@ -92,16 +82,6 @@ module QuotedCommandInCreateProcessFunctionConfig implements DataFlow::ConfigSig
|
||||
val = call.getArgument(call.getCommandLineArgumentId())
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(CreateProcessFunctionCall call | result = call.getLocation() |
|
||||
sink.asExpr() = call.getArgument(call.getCommandLineArgumentId())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module QuotedCommandInCreateProcessFunction =
|
||||
|
||||
@@ -37,16 +37,6 @@ module NullDaclConfig implements DataFlow::ConfigSig {
|
||||
val = call.getArgument(2)
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(SetSecurityDescriptorDaclFunctionCall call | result = call.getLocation() |
|
||||
sink.asExpr() = call.getArgument(2)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module NullDaclFlow = DataFlow::Global<NullDaclConfig>;
|
||||
@@ -78,10 +68,6 @@ module NonNullDaclConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(SetSecurityDescriptorDaclFunctionCall call | sink.asExpr() = call.getArgument(2))
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() {
|
||||
none() // only used negatively
|
||||
}
|
||||
}
|
||||
|
||||
module NonNullDaclFlow = DataFlow::Global<NonNullDaclConfig>;
|
||||
|
||||
@@ -65,16 +65,6 @@ module Config implements DataFlow::ConfigSig {
|
||||
iFrom1 != iFrom2
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
result = sink.getLocation()
|
||||
or
|
||||
exists(Expr raise | result = raise.getLocation() |
|
||||
sensitiveCondition([sink.asExpr(), sink.asIndirectExpr()], raise)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
@@ -178,10 +178,6 @@ module Config implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(UnsafeCast cast).getUnconverted() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = 0 }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() {
|
||||
none() // used both positively and negatively
|
||||
}
|
||||
}
|
||||
|
||||
module Flow = DataFlow::Global<Config>;
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Fixed an inconsistency across languages where most have a `Customizations.qll` file for adding customizations, but not all did.
|
||||
@@ -1,5 +0,0 @@
|
||||
## 1.4.5
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The "Initialization code not run" query (`cpp/initialization-not-run`) no longer reports an alert on static global variables that have no dereference.
|
||||
@@ -1,6 +0,0 @@
|
||||
## 1.4.6
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/short-global-name` query will no longer give alerts for instantiations of template variables, only for the template itself.
|
||||
* Fixed a false positive in `cpp/overflow-buffer` when the type of the destination buffer is a reference to a class/struct type.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.4.6
|
||||
lastReleaseVersion: 1.4.4
|
||||
|
||||
@@ -183,20 +183,6 @@ module ArrayAddressToDerefConfig implements DataFlow::StateConfigSig {
|
||||
pointerArithOverflow(pai, _)
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) {
|
||||
exists(Variable v | result = v.getLocation() | isSourceImpl(source, v))
|
||||
}
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(PointerArithmeticInstruction pai, Instruction deref |
|
||||
result = [pai, deref].getLocation() and
|
||||
isInvalidPointerDerefSink2(sink, deref, _) and
|
||||
isSink(sink, ArrayAddressToDerefConfig::TOverflowArithmetic(pai))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module ArrayAddressToDerefFlow = DataFlow::GlobalWithState<ArrayAddressToDerefConfig>;
|
||||
|
||||
@@ -28,14 +28,6 @@ module DecompressionTaintConfig implements DataFlow::ConfigSig {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
any(DecompressionFlowStep s).isAdditionalFlowStep(node1, node2)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(FunctionCall fc | result = [sink.getLocation(), fc.getLocation()] | isSink(fc, sink))
|
||||
}
|
||||
}
|
||||
|
||||
module DecompressionTaint = TaintTracking::Global<DecompressionTaintConfig>;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 1.4.7-dev
|
||||
version: 1.4.5-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -44,8 +44,6 @@
|
||||
| test.c:198:8:198:8 | b |
|
||||
| test.c:206:7:206:8 | ! ... |
|
||||
| test.c:206:8:206:8 | c |
|
||||
| test.c:215:6:215:18 | call to __builtin_expect |
|
||||
| test.c:219:9:219:22 | call to __builtin_expect |
|
||||
| test.cpp:18:8:18:10 | call to get |
|
||||
| test.cpp:31:7:31:13 | ... == ... |
|
||||
| test.cpp:42:13:42:20 | call to getABool |
|
||||
@@ -94,15 +92,3 @@
|
||||
| test.cpp:241:9:241:43 | ... && ... |
|
||||
| test.cpp:241:22:241:30 | ... == ... |
|
||||
| test.cpp:241:35:241:43 | ... == ... |
|
||||
| test.cpp:247:6:247:18 | ... == ... |
|
||||
| test.cpp:253:6:253:18 | ... != ... |
|
||||
| test.cpp:260:6:260:18 | ... == ... |
|
||||
| test.cpp:266:6:266:18 | ... != ... |
|
||||
| test.cpp:273:6:273:17 | ... == ... |
|
||||
| test.cpp:279:6:279:17 | ... != ... |
|
||||
| test.cpp:287:6:287:19 | ... == ... |
|
||||
| test.cpp:293:6:293:19 | ... != ... |
|
||||
| test.cpp:300:6:300:19 | ... == ... |
|
||||
| test.cpp:306:6:306:19 | ... != ... |
|
||||
| test.cpp:312:6:312:18 | ... == ... |
|
||||
| test.cpp:318:6:318:18 | ... != ... |
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -38,4 +38,4 @@ where
|
||||
|
|
||||
msg = left + op + k + " when " + guard + " is " + value
|
||||
)
|
||||
select guard, msg
|
||||
select guard.getLocation().getStartLine(), msg
|
||||
|
||||
@@ -1,196 +1,165 @@
|
||||
| test.c:7:9:7:13 | ... > ... | false | test.c:10:12:11:14 | { ... } |
|
||||
| test.c:7:9:7:13 | ... > ... | true | test.c:7:16:9:14 | { ... } |
|
||||
| test.c:17:8:17:12 | ... < ... | true | test.c:17:17:17:21 | y |
|
||||
| test.c:17:8:17:12 | ... < ... | true | test.c:18:9:18:14 | ExprStmt |
|
||||
| test.c:17:8:17:21 | ... && ... | true | test.c:18:9:18:14 | ExprStmt |
|
||||
| test.c:17:17:17:21 | ... > ... | true | test.c:18:9:18:14 | ExprStmt |
|
||||
| test.c:26:11:26:15 | ... > ... | false | test.c:2:5:2:8 | test |
|
||||
| test.c:26:11:26:15 | ... > ... | false | test.c:31:5:34:13 | ExprStmt |
|
||||
| test.c:26:11:26:15 | ... > ... | false | test.c:34:16:34:21 | j |
|
||||
| test.c:26:11:26:15 | ... > ... | false | test.c:34:29:34:26 | { ... } |
|
||||
| test.c:26:11:26:15 | ... > ... | false | test.c:39:5:42:13 | ExprStmt |
|
||||
| test.c:26:11:26:15 | ... > ... | false | test.c:42:5:42:26 | label ...: |
|
||||
| test.c:26:11:26:15 | ... > ... | false | test.c:42:16:42:21 | j |
|
||||
| test.c:26:11:26:15 | ... > ... | false | test.c:42:29:44:16 | { ... } |
|
||||
| test.c:26:11:26:15 | ... > ... | false | test.c:45:13:45:20 | if (...) ... |
|
||||
| test.c:26:11:26:15 | ... > ... | false | test.c:45:23:47:22 | { ... } |
|
||||
| test.c:26:11:26:15 | ... > ... | false | test.c:51:14:53:21 | { ... } |
|
||||
| test.c:26:11:26:15 | ... > ... | false | test.c:56:5:58:14 | label ...: |
|
||||
| test.c:26:11:26:15 | ... > ... | false | test.c:58:19:58:23 | y |
|
||||
| test.c:26:11:26:15 | ... > ... | false | test.c:58:26:66:12 | { ... } |
|
||||
| test.c:26:11:26:15 | ... > ... | false | test.c:62:9:62:16 | return ... |
|
||||
| test.c:26:11:26:15 | ... > ... | true | test.c:26:18:28:11 | { ... } |
|
||||
| test.c:34:16:34:21 | ... < ... | false | test.c:2:5:2:8 | test |
|
||||
| test.c:34:16:34:21 | ... < ... | false | test.c:39:5:42:13 | ExprStmt |
|
||||
| test.c:34:16:34:21 | ... < ... | false | test.c:42:5:42:26 | label ...: |
|
||||
| test.c:34:16:34:21 | ... < ... | false | test.c:42:16:42:21 | j |
|
||||
| test.c:34:16:34:21 | ... < ... | false | test.c:42:29:44:16 | { ... } |
|
||||
| test.c:34:16:34:21 | ... < ... | false | test.c:45:13:45:20 | if (...) ... |
|
||||
| test.c:34:16:34:21 | ... < ... | false | test.c:45:23:47:22 | { ... } |
|
||||
| test.c:34:16:34:21 | ... < ... | false | test.c:51:14:53:21 | { ... } |
|
||||
| test.c:34:16:34:21 | ... < ... | false | test.c:56:5:58:14 | label ...: |
|
||||
| test.c:34:16:34:21 | ... < ... | false | test.c:58:19:58:23 | y |
|
||||
| test.c:34:16:34:21 | ... < ... | false | test.c:58:26:66:12 | { ... } |
|
||||
| test.c:34:16:34:21 | ... < ... | false | test.c:62:9:62:16 | return ... |
|
||||
| test.c:34:16:34:21 | ... < ... | true | test.c:34:29:34:26 | { ... } |
|
||||
| test.c:42:16:42:21 | ... < ... | true | test.c:42:5:42:26 | label ...: |
|
||||
| test.c:42:16:42:21 | ... < ... | true | test.c:42:29:44:16 | { ... } |
|
||||
| test.c:42:16:42:21 | ... < ... | true | test.c:45:13:45:20 | if (...) ... |
|
||||
| test.c:42:16:42:21 | ... < ... | true | test.c:45:23:47:22 | { ... } |
|
||||
| test.c:42:16:42:21 | ... < ... | true | test.c:51:14:53:21 | { ... } |
|
||||
| test.c:44:12:44:16 | ... > ... | false | test.c:42:5:42:26 | label ...: |
|
||||
| test.c:44:12:44:16 | ... > ... | false | test.c:51:14:53:21 | { ... } |
|
||||
| test.c:44:12:44:16 | ... > ... | true | test.c:45:13:45:20 | if (...) ... |
|
||||
| test.c:44:12:44:16 | ... > ... | true | test.c:45:23:47:22 | { ... } |
|
||||
| test.c:45:16:45:20 | ... > ... | true | test.c:45:23:47:22 | { ... } |
|
||||
| test.c:58:9:58:14 | ... == ... | false | test.c:58:19:58:23 | y |
|
||||
| test.c:58:9:58:14 | ... == ... | false | test.c:62:9:62:16 | return ... |
|
||||
| test.c:58:9:58:23 | ... \|\| ... | false | test.c:62:9:62:16 | return ... |
|
||||
| test.c:58:19:58:23 | ... < ... | false | test.c:62:9:62:16 | return ... |
|
||||
| test.c:75:9:75:14 | ... == ... | false | test.c:78:12:79:14 | { ... } |
|
||||
| test.c:75:9:75:14 | ... == ... | true | test.c:75:17:77:14 | { ... } |
|
||||
| test.c:85:8:85:13 | ... == ... | true | test.c:85:18:85:23 | y |
|
||||
| test.c:85:8:85:13 | ... == ... | true | test.c:86:9:86:14 | ExprStmt |
|
||||
| test.c:85:8:85:23 | ... && ... | true | test.c:86:9:86:14 | ExprStmt |
|
||||
| test.c:85:18:85:23 | ... != ... | true | test.c:86:9:86:14 | ExprStmt |
|
||||
| test.c:94:11:94:16 | ... != ... | false | test.c:70:5:70:9 | test2 |
|
||||
| test.c:94:11:94:16 | ... != ... | false | test.c:99:5:102:13 | ExprStmt |
|
||||
| test.c:94:11:94:16 | ... != ... | false | test.c:102:16:102:21 | j |
|
||||
| test.c:94:11:94:16 | ... != ... | false | test.c:102:29:102:26 | { ... } |
|
||||
| test.c:94:11:94:16 | ... != ... | false | test.c:107:5:109:14 | ExprStmt |
|
||||
| test.c:94:11:94:16 | ... != ... | false | test.c:109:19:109:23 | y |
|
||||
| test.c:94:11:94:16 | ... != ... | false | test.c:109:26:117:12 | { ... } |
|
||||
| test.c:94:11:94:16 | ... != ... | false | test.c:113:9:113:16 | return ... |
|
||||
| test.c:94:11:94:16 | ... != ... | true | test.c:94:19:96:11 | { ... } |
|
||||
| test.c:102:16:102:21 | ... < ... | false | test.c:70:5:70:9 | test2 |
|
||||
| test.c:102:16:102:21 | ... < ... | false | test.c:107:5:109:14 | ExprStmt |
|
||||
| test.c:102:16:102:21 | ... < ... | false | test.c:109:19:109:23 | y |
|
||||
| test.c:102:16:102:21 | ... < ... | false | test.c:109:26:117:12 | { ... } |
|
||||
| test.c:102:16:102:21 | ... < ... | false | test.c:113:9:113:16 | return ... |
|
||||
| test.c:102:16:102:21 | ... < ... | true | test.c:102:29:102:26 | { ... } |
|
||||
| test.c:109:9:109:14 | ... == ... | false | test.c:109:19:109:23 | y |
|
||||
| test.c:109:9:109:14 | ... == ... | false | test.c:113:9:113:16 | return ... |
|
||||
| test.c:109:9:109:23 | ... \|\| ... | false | test.c:113:9:113:16 | return ... |
|
||||
| test.c:109:19:109:23 | ... < ... | false | test.c:113:9:113:16 | return ... |
|
||||
| test.c:126:7:126:7 | 1 | true | test.c:126:12:126:26 | call to test3_condition |
|
||||
| test.c:126:7:126:7 | 1 | true | test.c:126:31:128:16 | { ... } |
|
||||
| test.c:126:7:126:7 | 1 | true | test.c:131:3:131:7 | if (...) ... |
|
||||
| test.c:126:7:126:7 | 1 | true | test.c:131:10:132:16 | { ... } |
|
||||
| test.c:126:7:126:7 | 1 | true | test.c:134:1:123:10 | return ... |
|
||||
| test.c:126:7:126:28 | ... && ... | true | test.c:126:31:128:16 | { ... } |
|
||||
| test.c:126:12:126:26 | call to test3_condition | true | test.c:126:31:128:16 | { ... } |
|
||||
| test.c:131:7:131:7 | b | true | test.c:131:10:132:16 | { ... } |
|
||||
| test.c:137:7:137:7 | 0 | false | test.c:142:3:136:10 | return ... |
|
||||
| test.c:146:7:146:8 | ! ... | true | test.c:146:11:147:9 | { ... } |
|
||||
| test.c:146:8:146:8 | x | false | test.c:146:11:147:9 | { ... } |
|
||||
| test.c:152:8:152:8 | p | true | test.c:152:11:154:5 | { ... } |
|
||||
| test.c:158:8:158:9 | ! ... | true | test.c:158:12:160:5 | { ... } |
|
||||
| test.c:158:9:158:9 | p | false | test.c:158:12:160:5 | { ... } |
|
||||
| test.c:164:8:164:8 | s | true | test.c:164:11:166:5 | { ... } |
|
||||
| test.c:170:8:170:9 | ! ... | true | test.c:170:12:172:5 | { ... } |
|
||||
| test.c:170:9:170:9 | s | false | test.c:170:12:172:5 | { ... } |
|
||||
| test.c:176:8:176:15 | ! ... | true | test.c:176:18:178:5 | { ... } |
|
||||
| test.c:176:10:176:14 | ... < ... | false | test.c:176:18:178:5 | { ... } |
|
||||
| test.c:182:8:182:34 | ! ... | true | test.c:182:37:184:5 | { ... } |
|
||||
| test.c:182:10:182:20 | ... >= ... | true | test.c:181:25:182:20 | { ... } |
|
||||
| test.c:182:10:182:20 | ... >= ... | true | test.c:182:25:182:33 | foo |
|
||||
| test.c:182:10:182:33 | ... && ... | false | test.c:182:37:184:5 | { ... } |
|
||||
| test.c:182:10:182:33 | ... && ... | true | test.c:181:25:182:20 | { ... } |
|
||||
| test.c:182:25:182:33 | ... < ... | true | test.c:181:25:182:20 | { ... } |
|
||||
| test.c:190:7:190:8 | ! ... | true | test.c:190:11:192:3 | { ... } |
|
||||
| test.c:190:8:190:8 | c | false | test.c:190:11:192:3 | { ... } |
|
||||
| test.c:198:7:198:8 | ! ... | true | test.c:198:11:200:3 | { ... } |
|
||||
| test.c:198:8:198:8 | b | false | test.c:198:11:200:3 | { ... } |
|
||||
| test.c:206:7:206:8 | ! ... | true | test.c:206:11:208:3 | { ... } |
|
||||
| test.c:206:8:206:8 | c | false | test.c:206:11:208:3 | { ... } |
|
||||
| test.c:215:6:215:18 | call to __builtin_expect | true | test.c:215:21:217:5 | { ... } |
|
||||
| test.c:219:9:219:22 | call to __builtin_expect | true | test.c:219:25:221:5 | { ... } |
|
||||
| test.cpp:18:8:18:10 | call to get | true | test.cpp:19:5:19:14 | ExprStmt |
|
||||
| test.cpp:31:7:31:13 | ... == ... | false | test.cpp:30:6:30:16 | doSomething |
|
||||
| test.cpp:31:7:31:13 | ... == ... | false | test.cpp:34:1:34:1 | return ... |
|
||||
| test.cpp:31:7:31:13 | ... == ... | true | test.cpp:30:6:30:16 | doSomething |
|
||||
| test.cpp:31:7:31:13 | ... == ... | true | test.cpp:31:16:32:21 | { ... } |
|
||||
| test.cpp:42:13:42:20 | call to getABool | true | test.cpp:43:9:45:23 | { ... } |
|
||||
| test.cpp:61:10:61:10 | i | Case[0] | test.cpp:62:5:64:12 | case ...: |
|
||||
| test.cpp:61:10:61:10 | i | Case[1] | test.cpp:65:5:66:10 | case ...: |
|
||||
| test.cpp:74:10:74:10 | i | Case[0..10] | test.cpp:75:5:77:12 | case ...: |
|
||||
| test.cpp:74:10:74:10 | i | Case[11..20] | test.cpp:78:5:79:10 | case ...: |
|
||||
| test.cpp:93:6:93:6 | c | true | test.cpp:93:9:94:7 | { ... } |
|
||||
| test.cpp:99:6:99:6 | f | true | test.cpp:99:9:100:7 | { ... } |
|
||||
| test.cpp:105:6:105:14 | ... != ... | true | test.cpp:105:17:106:7 | { ... } |
|
||||
| test.cpp:111:6:111:14 | ... != ... | true | test.cpp:111:17:112:7 | { ... } |
|
||||
| test.cpp:122:9:122:9 | b | true | test.cpp:123:5:125:20 | { ... } |
|
||||
| test.cpp:122:9:122:9 | b | true | test.cpp:125:23:125:29 | return ... |
|
||||
| test.cpp:125:13:125:20 | ! ... | true | test.cpp:125:23:125:29 | return ... |
|
||||
| test.cpp:125:14:125:17 | call to safe | false | test.cpp:125:23:125:29 | return ... |
|
||||
| test.cpp:131:6:131:21 | call to __builtin_expect | true | test.cpp:131:40:132:9 | { ... } |
|
||||
| test.cpp:135:6:135:21 | call to __builtin_expect | true | test.cpp:135:40:136:9 | { ... } |
|
||||
| test.cpp:141:6:141:21 | call to __builtin_expect | true | test.cpp:141:36:142:9 | { ... } |
|
||||
| test.cpp:145:6:145:21 | call to __builtin_expect | true | test.cpp:145:36:146:9 | { ... } |
|
||||
| test.cpp:152:7:152:8 | ! ... | true | test.cpp:152:11:153:9 | { ... } |
|
||||
| test.cpp:152:8:152:8 | b | false | test.cpp:152:11:153:9 | { ... } |
|
||||
| test.cpp:160:7:160:8 | ! ... | true | test.cpp:160:11:162:3 | { ... } |
|
||||
| test.cpp:160:8:160:8 | c | false | test.cpp:160:11:162:3 | { ... } |
|
||||
| test.cpp:168:7:168:8 | ! ... | true | test.cpp:168:11:170:3 | { ... } |
|
||||
| test.cpp:168:8:168:8 | b | false | test.cpp:168:11:170:3 | { ... } |
|
||||
| test.cpp:176:7:176:8 | ! ... | true | test.cpp:176:11:178:3 | { ... } |
|
||||
| test.cpp:176:8:176:8 | c | false | test.cpp:176:11:178:3 | { ... } |
|
||||
| test.cpp:182:6:182:16 | ! ... | false | test.cpp:185:10:188:7 | { ... } |
|
||||
| test.cpp:182:6:182:16 | ! ... | true | test.cpp:182:19:184:7 | { ... } |
|
||||
| test.cpp:182:8:182:9 | b1 | true | test.cpp:181:41:182:9 | { ... } |
|
||||
| test.cpp:182:8:182:9 | b1 | true | test.cpp:182:14:182:15 | b2 |
|
||||
| test.cpp:182:8:182:15 | ... && ... | false | test.cpp:182:19:184:7 | { ... } |
|
||||
| test.cpp:182:8:182:15 | ... && ... | true | test.cpp:181:41:182:9 | { ... } |
|
||||
| test.cpp:182:8:182:15 | ... && ... | true | test.cpp:185:10:188:7 | { ... } |
|
||||
| test.cpp:182:14:182:15 | b2 | true | test.cpp:181:41:182:9 | { ... } |
|
||||
| test.cpp:193:6:193:16 | ! ... | false | test.cpp:197:10:199:7 | { ... } |
|
||||
| test.cpp:193:6:193:16 | ! ... | true | test.cpp:193:19:196:7 | { ... } |
|
||||
| test.cpp:193:8:193:9 | b1 | false | test.cpp:192:40:193:9 | { ... } |
|
||||
| test.cpp:193:8:193:9 | b1 | false | test.cpp:193:14:193:15 | b2 |
|
||||
| test.cpp:193:8:193:15 | ... \|\| ... | false | test.cpp:192:40:193:9 | { ... } |
|
||||
| test.cpp:193:8:193:15 | ... \|\| ... | false | test.cpp:193:19:196:7 | { ... } |
|
||||
| test.cpp:193:8:193:15 | ... \|\| ... | true | test.cpp:197:10:199:7 | { ... } |
|
||||
| test.cpp:193:14:193:15 | b2 | false | test.cpp:192:40:193:9 | { ... } |
|
||||
| test.cpp:211:9:211:15 | ... == ... | true | test.cpp:211:18:212:13 | { ... } |
|
||||
| test.cpp:214:9:214:17 | ... == ... | true | test.cpp:214:20:215:13 | { ... } |
|
||||
| test.cpp:217:9:217:15 | ... == ... | true | test.cpp:217:18:218:13 | { ... } |
|
||||
| test.cpp:220:9:220:14 | ... == ... | true | test.cpp:220:17:221:13 | { ... } |
|
||||
| test.cpp:223:9:223:16 | ... == ... | true | test.cpp:223:19:224:13 | { ... } |
|
||||
| test.cpp:226:9:226:14 | ... == ... | true | test.cpp:226:17:227:13 | { ... } |
|
||||
| test.cpp:229:9:229:14 | ... == ... | true | test.cpp:229:17:230:13 | { ... } |
|
||||
| test.cpp:232:9:232:18 | ... == ... | true | test.cpp:232:21:233:13 | { ... } |
|
||||
| test.cpp:235:9:235:17 | ... == ... | true | test.cpp:235:20:236:13 | { ... } |
|
||||
| test.cpp:238:9:238:17 | ... == ... | true | test.cpp:238:20:239:13 | { ... } |
|
||||
| test.cpp:241:9:241:17 | ... == ... | true | test.cpp:241:22:241:30 | ms |
|
||||
| test.cpp:241:9:241:17 | ... == ... | true | test.cpp:241:35:241:43 | ms |
|
||||
| test.cpp:241:9:241:17 | ... == ... | true | test.cpp:241:46:242:13 | { ... } |
|
||||
| test.cpp:241:9:241:30 | ... && ... | true | test.cpp:241:35:241:43 | ms |
|
||||
| test.cpp:241:9:241:30 | ... && ... | true | test.cpp:241:46:242:13 | { ... } |
|
||||
| test.cpp:241:9:241:43 | ... && ... | true | test.cpp:241:46:242:13 | { ... } |
|
||||
| test.cpp:241:22:241:30 | ... == ... | true | test.cpp:241:35:241:43 | ms |
|
||||
| test.cpp:241:22:241:30 | ... == ... | true | test.cpp:241:46:242:13 | { ... } |
|
||||
| test.cpp:241:35:241:43 | ... == ... | true | test.cpp:241:46:242:13 | { ... } |
|
||||
| test.cpp:247:6:247:18 | ... == ... | false | test.cpp:249:10:251:3 | { ... } |
|
||||
| test.cpp:247:6:247:18 | ... == ... | true | test.cpp:247:21:249:3 | { ... } |
|
||||
| test.cpp:253:6:253:18 | ... != ... | false | test.cpp:255:10:257:3 | { ... } |
|
||||
| test.cpp:253:6:253:18 | ... != ... | true | test.cpp:253:21:255:3 | { ... } |
|
||||
| test.cpp:260:6:260:18 | ... == ... | false | test.cpp:262:10:264:3 | { ... } |
|
||||
| test.cpp:260:6:260:18 | ... == ... | true | test.cpp:260:21:262:3 | { ... } |
|
||||
| test.cpp:266:6:266:18 | ... != ... | false | test.cpp:268:10:270:3 | { ... } |
|
||||
| test.cpp:266:6:266:18 | ... != ... | true | test.cpp:266:21:268:3 | { ... } |
|
||||
| test.cpp:273:6:273:17 | ... == ... | false | test.cpp:275:10:277:3 | { ... } |
|
||||
| test.cpp:273:6:273:17 | ... == ... | true | test.cpp:273:20:275:3 | { ... } |
|
||||
| test.cpp:279:6:279:17 | ... != ... | false | test.cpp:281:10:283:3 | { ... } |
|
||||
| test.cpp:279:6:279:17 | ... != ... | true | test.cpp:279:20:281:3 | { ... } |
|
||||
| test.cpp:287:6:287:19 | ... == ... | false | test.cpp:289:10:291:3 | { ... } |
|
||||
| test.cpp:287:6:287:19 | ... == ... | true | test.cpp:287:22:289:3 | { ... } |
|
||||
| test.cpp:293:6:293:19 | ... != ... | false | test.cpp:295:10:297:3 | { ... } |
|
||||
| test.cpp:293:6:293:19 | ... != ... | true | test.cpp:293:22:295:3 | { ... } |
|
||||
| test.cpp:300:6:300:19 | ... == ... | false | test.cpp:302:10:304:3 | { ... } |
|
||||
| test.cpp:300:6:300:19 | ... == ... | true | test.cpp:300:22:302:3 | { ... } |
|
||||
| test.cpp:306:6:306:19 | ... != ... | false | test.cpp:308:10:310:3 | { ... } |
|
||||
| test.cpp:306:6:306:19 | ... != ... | true | test.cpp:306:22:308:3 | { ... } |
|
||||
| test.cpp:312:6:312:18 | ... == ... | false | test.cpp:314:10:316:3 | { ... } |
|
||||
| test.cpp:312:6:312:18 | ... == ... | true | test.cpp:312:21:314:3 | { ... } |
|
||||
| test.cpp:318:6:318:18 | ... != ... | false | test.cpp:320:10:322:3 | { ... } |
|
||||
| test.cpp:318:6:318:18 | ... != ... | true | test.cpp:318:21:320:3 | { ... } |
|
||||
| test.c:7:9:7:13 | ... > ... | false | 10 | 11 |
|
||||
| test.c:7:9:7:13 | ... > ... | true | 7 | 9 |
|
||||
| test.c:17:8:17:12 | ... < ... | true | 17 | 17 |
|
||||
| test.c:17:8:17:12 | ... < ... | true | 18 | 18 |
|
||||
| test.c:17:8:17:21 | ... && ... | true | 18 | 18 |
|
||||
| test.c:17:17:17:21 | ... > ... | true | 18 | 18 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 2 | 2 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 31 | 34 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 34 | 34 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 39 | 42 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 42 | 42 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 42 | 44 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 45 | 45 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 45 | 47 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 51 | 53 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 56 | 58 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 58 | 58 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 58 | 66 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 62 | 62 |
|
||||
| test.c:26:11:26:15 | ... > ... | true | 26 | 28 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 2 | 2 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 39 | 42 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 42 | 42 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 42 | 44 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 45 | 45 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 45 | 47 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 51 | 53 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 56 | 58 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 58 | 58 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 58 | 66 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 62 | 62 |
|
||||
| test.c:34:16:34:21 | ... < ... | true | 34 | 34 |
|
||||
| test.c:42:16:42:21 | ... < ... | true | 42 | 42 |
|
||||
| test.c:42:16:42:21 | ... < ... | true | 42 | 44 |
|
||||
| test.c:42:16:42:21 | ... < ... | true | 45 | 45 |
|
||||
| test.c:42:16:42:21 | ... < ... | true | 45 | 47 |
|
||||
| test.c:42:16:42:21 | ... < ... | true | 51 | 53 |
|
||||
| test.c:44:12:44:16 | ... > ... | false | 42 | 42 |
|
||||
| test.c:44:12:44:16 | ... > ... | false | 51 | 53 |
|
||||
| test.c:44:12:44:16 | ... > ... | true | 45 | 45 |
|
||||
| test.c:44:12:44:16 | ... > ... | true | 45 | 47 |
|
||||
| test.c:45:16:45:20 | ... > ... | true | 45 | 47 |
|
||||
| test.c:58:9:58:14 | ... == ... | false | 58 | 58 |
|
||||
| test.c:58:9:58:14 | ... == ... | false | 62 | 62 |
|
||||
| test.c:58:9:58:23 | ... \|\| ... | false | 62 | 62 |
|
||||
| test.c:58:19:58:23 | ... < ... | false | 62 | 62 |
|
||||
| test.c:75:9:75:14 | ... == ... | false | 78 | 79 |
|
||||
| test.c:75:9:75:14 | ... == ... | true | 75 | 77 |
|
||||
| test.c:85:8:85:13 | ... == ... | true | 85 | 85 |
|
||||
| test.c:85:8:85:13 | ... == ... | true | 86 | 86 |
|
||||
| test.c:85:8:85:23 | ... && ... | true | 86 | 86 |
|
||||
| test.c:85:18:85:23 | ... != ... | true | 86 | 86 |
|
||||
| test.c:94:11:94:16 | ... != ... | false | 70 | 70 |
|
||||
| test.c:94:11:94:16 | ... != ... | false | 99 | 102 |
|
||||
| test.c:94:11:94:16 | ... != ... | false | 102 | 102 |
|
||||
| test.c:94:11:94:16 | ... != ... | false | 107 | 109 |
|
||||
| test.c:94:11:94:16 | ... != ... | false | 109 | 109 |
|
||||
| test.c:94:11:94:16 | ... != ... | false | 109 | 117 |
|
||||
| test.c:94:11:94:16 | ... != ... | false | 113 | 113 |
|
||||
| test.c:94:11:94:16 | ... != ... | true | 94 | 96 |
|
||||
| test.c:102:16:102:21 | ... < ... | false | 70 | 70 |
|
||||
| test.c:102:16:102:21 | ... < ... | false | 107 | 109 |
|
||||
| test.c:102:16:102:21 | ... < ... | false | 109 | 109 |
|
||||
| test.c:102:16:102:21 | ... < ... | false | 109 | 117 |
|
||||
| test.c:102:16:102:21 | ... < ... | false | 113 | 113 |
|
||||
| test.c:102:16:102:21 | ... < ... | true | 102 | 102 |
|
||||
| test.c:109:9:109:14 | ... == ... | false | 109 | 109 |
|
||||
| test.c:109:9:109:14 | ... == ... | false | 113 | 113 |
|
||||
| test.c:109:9:109:23 | ... \|\| ... | false | 113 | 113 |
|
||||
| test.c:109:19:109:23 | ... < ... | false | 113 | 113 |
|
||||
| test.c:126:7:126:7 | 1 | true | 126 | 126 |
|
||||
| test.c:126:7:126:7 | 1 | true | 126 | 128 |
|
||||
| test.c:126:7:126:7 | 1 | true | 131 | 131 |
|
||||
| test.c:126:7:126:7 | 1 | true | 131 | 132 |
|
||||
| test.c:126:7:126:7 | 1 | true | 134 | 123 |
|
||||
| test.c:126:7:126:28 | ... && ... | true | 126 | 128 |
|
||||
| test.c:126:12:126:26 | call to test3_condition | true | 126 | 128 |
|
||||
| test.c:131:7:131:7 | b | true | 131 | 132 |
|
||||
| test.c:137:7:137:7 | 0 | false | 142 | 136 |
|
||||
| test.c:146:7:146:8 | ! ... | true | 146 | 147 |
|
||||
| test.c:146:8:146:8 | x | false | 146 | 147 |
|
||||
| test.c:152:8:152:8 | p | true | 152 | 154 |
|
||||
| test.c:158:8:158:9 | ! ... | true | 158 | 160 |
|
||||
| test.c:158:9:158:9 | p | false | 158 | 160 |
|
||||
| test.c:164:8:164:8 | s | true | 164 | 166 |
|
||||
| test.c:170:8:170:9 | ! ... | true | 170 | 172 |
|
||||
| test.c:170:9:170:9 | s | false | 170 | 172 |
|
||||
| test.c:176:8:176:15 | ! ... | true | 176 | 178 |
|
||||
| test.c:176:10:176:14 | ... < ... | false | 176 | 178 |
|
||||
| test.c:182:8:182:34 | ! ... | true | 182 | 184 |
|
||||
| test.c:182:10:182:20 | ... >= ... | true | 181 | 182 |
|
||||
| test.c:182:10:182:20 | ... >= ... | true | 182 | 182 |
|
||||
| test.c:182:10:182:33 | ... && ... | false | 182 | 184 |
|
||||
| test.c:182:10:182:33 | ... && ... | true | 181 | 182 |
|
||||
| test.c:182:25:182:33 | ... < ... | true | 181 | 182 |
|
||||
| test.c:190:7:190:8 | ! ... | true | 190 | 192 |
|
||||
| test.c:190:8:190:8 | c | false | 190 | 192 |
|
||||
| test.c:198:7:198:8 | ! ... | true | 198 | 200 |
|
||||
| test.c:198:8:198:8 | b | false | 198 | 200 |
|
||||
| test.c:206:7:206:8 | ! ... | true | 206 | 208 |
|
||||
| test.c:206:8:206:8 | c | false | 206 | 208 |
|
||||
| test.cpp:18:8:18:10 | call to get | true | 19 | 19 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | false | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | false | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | true | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | true | 31 | 32 |
|
||||
| test.cpp:42:13:42:20 | call to getABool | true | 43 | 45 |
|
||||
| test.cpp:61:10:61:10 | i | Case[0] | 62 | 64 |
|
||||
| test.cpp:61:10:61:10 | i | Case[1] | 65 | 66 |
|
||||
| test.cpp:74:10:74:10 | i | Case[0..10] | 75 | 77 |
|
||||
| test.cpp:74:10:74:10 | i | Case[11..20] | 78 | 79 |
|
||||
| test.cpp:93:6:93:6 | c | true | 93 | 94 |
|
||||
| test.cpp:99:6:99:6 | f | true | 99 | 100 |
|
||||
| test.cpp:105:6:105:14 | ... != ... | true | 105 | 106 |
|
||||
| test.cpp:111:6:111:14 | ... != ... | true | 111 | 112 |
|
||||
| test.cpp:122:9:122:9 | b | true | 123 | 125 |
|
||||
| test.cpp:122:9:122:9 | b | true | 125 | 125 |
|
||||
| test.cpp:125:13:125:20 | ! ... | true | 125 | 125 |
|
||||
| test.cpp:125:14:125:17 | call to safe | false | 125 | 125 |
|
||||
| test.cpp:131:6:131:21 | call to __builtin_expect | true | 131 | 132 |
|
||||
| test.cpp:135:6:135:21 | call to __builtin_expect | true | 135 | 136 |
|
||||
| test.cpp:141:6:141:21 | call to __builtin_expect | true | 141 | 142 |
|
||||
| test.cpp:145:6:145:21 | call to __builtin_expect | true | 145 | 146 |
|
||||
| test.cpp:152:7:152:8 | ! ... | true | 152 | 153 |
|
||||
| test.cpp:152:8:152:8 | b | false | 152 | 153 |
|
||||
| test.cpp:160:7:160:8 | ! ... | true | 160 | 162 |
|
||||
| test.cpp:160:8:160:8 | c | false | 160 | 162 |
|
||||
| test.cpp:168:7:168:8 | ! ... | true | 168 | 170 |
|
||||
| test.cpp:168:8:168:8 | b | false | 168 | 170 |
|
||||
| test.cpp:176:7:176:8 | ! ... | true | 176 | 178 |
|
||||
| test.cpp:176:8:176:8 | c | false | 176 | 178 |
|
||||
| test.cpp:182:6:182:16 | ! ... | false | 185 | 188 |
|
||||
| test.cpp:182:6:182:16 | ! ... | true | 182 | 184 |
|
||||
| test.cpp:182:8:182:9 | b1 | true | 181 | 182 |
|
||||
| test.cpp:182:8:182:9 | b1 | true | 182 | 182 |
|
||||
| test.cpp:182:8:182:15 | ... && ... | false | 182 | 184 |
|
||||
| test.cpp:182:8:182:15 | ... && ... | true | 181 | 182 |
|
||||
| test.cpp:182:8:182:15 | ... && ... | true | 185 | 188 |
|
||||
| test.cpp:182:14:182:15 | b2 | true | 181 | 182 |
|
||||
| test.cpp:193:6:193:16 | ! ... | false | 197 | 199 |
|
||||
| test.cpp:193:6:193:16 | ! ... | true | 193 | 196 |
|
||||
| test.cpp:193:8:193:9 | b1 | false | 192 | 193 |
|
||||
| test.cpp:193:8:193:9 | b1 | false | 193 | 193 |
|
||||
| test.cpp:193:8:193:15 | ... \|\| ... | false | 192 | 193 |
|
||||
| test.cpp:193:8:193:15 | ... \|\| ... | false | 193 | 196 |
|
||||
| test.cpp:193:8:193:15 | ... \|\| ... | true | 197 | 199 |
|
||||
| test.cpp:193:14:193:15 | b2 | false | 192 | 193 |
|
||||
| test.cpp:211:9:211:15 | ... == ... | true | 211 | 212 |
|
||||
| test.cpp:214:9:214:17 | ... == ... | true | 214 | 215 |
|
||||
| test.cpp:217:9:217:15 | ... == ... | true | 217 | 218 |
|
||||
| test.cpp:220:9:220:14 | ... == ... | true | 220 | 221 |
|
||||
| test.cpp:223:9:223:16 | ... == ... | true | 223 | 224 |
|
||||
| test.cpp:226:9:226:14 | ... == ... | true | 226 | 227 |
|
||||
| test.cpp:229:9:229:14 | ... == ... | true | 229 | 230 |
|
||||
| test.cpp:232:9:232:18 | ... == ... | true | 232 | 233 |
|
||||
| test.cpp:235:9:235:17 | ... == ... | true | 235 | 236 |
|
||||
| test.cpp:238:9:238:17 | ... == ... | true | 238 | 239 |
|
||||
| test.cpp:241:9:241:17 | ... == ... | true | 241 | 241 |
|
||||
| test.cpp:241:9:241:17 | ... == ... | true | 241 | 242 |
|
||||
| test.cpp:241:9:241:30 | ... && ... | true | 241 | 241 |
|
||||
| test.cpp:241:9:241:30 | ... && ... | true | 241 | 242 |
|
||||
| test.cpp:241:9:241:43 | ... && ... | true | 241 | 242 |
|
||||
| test.cpp:241:22:241:30 | ... == ... | true | 241 | 241 |
|
||||
| test.cpp:241:22:241:30 | ... == ... | true | 241 | 242 |
|
||||
| test.cpp:241:35:241:43 | ... == ... | true | 241 | 242 |
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
from GuardCondition guard, AbstractValue value, BasicBlock block
|
||||
where guard.valueControls(block, value)
|
||||
select guard, value, block
|
||||
from GuardCondition guard, AbstractValue value, int start, int end
|
||||
where
|
||||
exists(BasicBlock block |
|
||||
guard.valueControls(block, value) and
|
||||
block.hasLocationInfo(_, start, _, end, _)
|
||||
)
|
||||
select guard, value, start, end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,23 +8,31 @@ import cpp
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
query predicate binary(
|
||||
GuardCondition guard, Expr left, string op, Expr right, int k, BasicBlock block
|
||||
GuardCondition guard, Expr left, string op, Expr right, int k, int start, int end
|
||||
) {
|
||||
guard.ensuresLt(left, right, k, block, true) and op = "<"
|
||||
or
|
||||
guard.ensuresLt(left, right, k, block, false) and op = ">="
|
||||
or
|
||||
guard.ensuresEq(left, right, k, block, true) and op = "=="
|
||||
or
|
||||
guard.ensuresEq(left, right, k, block, false) and op = "!="
|
||||
exists(BasicBlock block |
|
||||
guard.ensuresLt(left, right, k, block, true) and op = "<"
|
||||
or
|
||||
guard.ensuresLt(left, right, k, block, false) and op = ">="
|
||||
or
|
||||
guard.ensuresEq(left, right, k, block, true) and op = "=="
|
||||
or
|
||||
guard.ensuresEq(left, right, k, block, false) and op = "!="
|
||||
|
|
||||
block.hasLocationInfo(_, start, _, end, _)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate unary(GuardCondition guard, Expr left, string op, int k, BasicBlock block) {
|
||||
guard.ensuresLt(left, k, block, true) and op = "<"
|
||||
or
|
||||
guard.ensuresLt(left, k, block, false) and op = ">="
|
||||
or
|
||||
guard.ensuresEq(left, k, block, true) and op = "=="
|
||||
or
|
||||
guard.ensuresEq(left, k, block, false) and op = "!="
|
||||
query predicate unary(GuardCondition guard, Expr left, string op, int k, int start, int end) {
|
||||
exists(BasicBlock block |
|
||||
guard.ensuresLt(left, k, block, true) and op = "<"
|
||||
or
|
||||
guard.ensuresLt(left, k, block, false) and op = ">="
|
||||
or
|
||||
guard.ensuresEq(left, k, block, true) and op = "=="
|
||||
or
|
||||
guard.ensuresEq(left, k, block, false) and op = "!="
|
||||
|
|
||||
block.hasLocationInfo(_, start, _, end, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -206,17 +206,4 @@ void test14(int a, int b) {
|
||||
if (!c) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
# define likely(x) __builtin_expect(!!(x), 1)
|
||||
|
||||
void test15(int a, int b)
|
||||
{
|
||||
if (likely(a > b)) {
|
||||
|
||||
}
|
||||
|
||||
if (likely(a > 42)) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user