Compare commits

..

11 Commits

Author SHA1 Message Date
Napalys Klicius
d3d608fa33 Updated query description and added a sanitizer 2025-09-04 13:16:37 +00:00
Napalys Klicius
6c751ce934 Merged config classes 2025-09-04 12:31:24 +00:00
Napalys Klicius
4dac80a998 Replace complex wrapper classes with MaD 2025-09-04 12:19:22 +00:00
Napalys Klicius
021aa13ee2 Added change note 2025-07-31 12:45:34 +02:00
Napalys Klicius
791a7e242e Updated qhelp for cors permissive configuration 2025-07-31 11:31:10 +02:00
Napalys Klicius
2baca58b27 Removed deprecations from cors as it was moved out experimental 2025-07-31 11:08:22 +02:00
Napalys Klicius
fd4233e30e Moved apollo modeling to MaD 2025-07-31 10:58:38 +02:00
Napalys Klicius
84ffbbec33 Added missing doc strings 2025-07-30 10:51:38 +00:00
Napalys Klicius
95743d7109 Added inline test expectations for cors permissive config 2025-07-30 10:42:55 +00:00
Napalys Klicius
92daa7d42c Updated suite expectations 2025-07-30 10:32:11 +00:00
Napalys Klicius
358617f533 Move CORS misconfiguration query from experimental to Security 2025-07-30 10:22:59 +00:00
1033 changed files with 12957 additions and 28352 deletions

View File

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

View File

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

View File

@@ -1,11 +1,3 @@
## 0.4.15
No user-facing changes.
## 0.4.14
No user-facing changes.
## 0.4.13
### Bug Fixes

View File

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

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.4.15
lastReleaseVersion: 0.4.13

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 ($@).",

View File

@@ -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 ($@).",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.6.7
lastReleaseVersion: 0.6.5

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `cpp/overrun-write` query now recognizes more bound checks and thus produces fewer false positives.

View File

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

View File

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

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 5.4.1
lastReleaseVersion: 5.3.0

View File

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

View File

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

View File

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

View File

@@ -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))` */

View File

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

View File

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

View File

@@ -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()
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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())
)
)
}

View File

@@ -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())
)
)
}

View File

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

View File

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

View File

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

View File

@@ -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())
)
)
}

View File

@@ -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)
)
}
}
/**

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.4.6
lastReleaseVersion: 1.4.4

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 1.4.7-dev
version: 1.4.5-dev
groups:
- cpp
- queries

View File

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

View File

@@ -38,4 +38,4 @@ where
|
msg = left + op + k + " when " + guard + " is " + value
)
select guard, msg
select guard.getLocation().getStartLine(), msg

View File

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

View File

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

View File

@@ -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, _)
)
}

View File

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