mirror of
https://github.com/github/codeql.git
synced 2026-05-30 11:01:24 +02:00
Compare commits
1 Commits
idrissrio/
...
aibaars-pa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3ae3a5770 |
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.300
|
||||
dotnet-version: 9.0.100
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
|
||||
10
.github/workflows/csharp-qltest.yml
vendored
10
.github/workflows/csharp-qltest.yml
vendored
@@ -43,14 +43,14 @@ jobs:
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.300
|
||||
dotnet-version: 9.0.100
|
||||
- name: Extractor unit tests
|
||||
run: |
|
||||
dotnet tool restore
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.5 extractor/Semmle.Util.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.5 extractor/Semmle.Extraction.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.5 autobuilder/Semmle.Autobuild.CSharp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.5 autobuilder/Semmle.Autobuild.Cpp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.0 extractor/Semmle.Util.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.0 extractor/Semmle.Extraction.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.0 autobuilder/Semmle.Autobuild.CSharp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.0 autobuilder/Semmle.Autobuild.Cpp.Tests
|
||||
shell: bash
|
||||
stubgentest:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
2
.github/workflows/query-list.yml
vendored
2
.github/workflows/query-list.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Download CodeQL CLI
|
||||
# Look under the `codeql` directory, as this is where we checked out the `github/codeql` repo
|
||||
# Look under the `codeql` directory, as this is where we checked out the `github/codeql` repo
|
||||
uses: ./codeql/.github/actions/fetch-codeql
|
||||
- name: Build code scanning query list
|
||||
run: |
|
||||
|
||||
@@ -26,7 +26,7 @@ bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||
bazel_dep(name = "fmt", version = "10.0.0")
|
||||
bazel_dep(name = "rules_kotlin", version = "2.1.3-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.40.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.19.2-codeql.1")
|
||||
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 = "zstd", version = "1.5.5.bcr.1")
|
||||
@@ -172,7 +172,7 @@ http_archive(
|
||||
)
|
||||
|
||||
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
|
||||
dotnet.toolchain(dotnet_version = "9.0.300")
|
||||
dotnet.toolchain(dotnet_version = "9.0.100")
|
||||
use_repo(dotnet, "dotnet_toolchains")
|
||||
|
||||
register_toolchains("@dotnet_toolchains//:all")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
name: "actions"
|
||||
aliases: []
|
||||
display_name: "GitHub Actions"
|
||||
version: 0.0.1
|
||||
column_kind: "utf16"
|
||||
@@ -7,11 +8,9 @@ build_modes:
|
||||
- none
|
||||
default_queries:
|
||||
- codeql/actions-queries
|
||||
# Actions workflows are not reported separately by the GitHub API, so we can't
|
||||
# associate them with a specific language.
|
||||
file_coverage_languages: []
|
||||
github_api_languages: []
|
||||
scc_languages:
|
||||
- YAML
|
||||
scc_languages: []
|
||||
file_types:
|
||||
- name: workflow
|
||||
display_name: GitHub Actions workflow files
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"paths": [
|
||||
".github/workflows/*.yml",
|
||||
".github/workflows/*.yaml",
|
||||
".github/reusable_workflows/**/*.yml",
|
||||
".github/reusable_workflows/**/*.yaml",
|
||||
"**/action.yml",
|
||||
"**/action.yaml"
|
||||
]
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
@echo off
|
||||
type "%CODEQL_EXTRACTOR_ACTIONS_ROOT%\tools\baseline-config.json"
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cat "$CODEQL_EXTRACTOR_ACTIONS_ROOT/tools/baseline-config.json"
|
||||
@@ -1,4 +1,3 @@
|
||||
ql/actions/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionCritical.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql
|
||||
ql/actions/ql/src/Security/CWE-094/CodeInjectionCritical.ql
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
ql/actions/ql/src/Debug/SyntaxError.ql
|
||||
ql/actions/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionCritical.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionMedium.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
ql/actions/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionCritical.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionMedium.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
## 0.4.17
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.16
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.15
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.16
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.17
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.17
|
||||
lastReleaseVersion: 0.4.15
|
||||
|
||||
@@ -70,8 +70,8 @@ class Location extends TLocation, TBaseLocation {
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `sc` of line `sl` to
|
||||
* column `ec` of line `el` in file `p`.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Providing locations in CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
|
||||
@@ -261,7 +261,7 @@ class If extends AstNode instanceof IfImpl {
|
||||
}
|
||||
|
||||
/**
|
||||
* An Environment node representing a deployment environment.
|
||||
* An Environemnt node representing a deployment environment.
|
||||
*/
|
||||
class Environment extends AstNode instanceof EnvironmentImpl {
|
||||
string getName() { result = super.getName() }
|
||||
|
||||
@@ -125,11 +125,12 @@ abstract class AstNodeImpl extends TAstNode {
|
||||
* Gets the enclosing Step.
|
||||
*/
|
||||
StepImpl getEnclosingStep() {
|
||||
this instanceof StepImpl and
|
||||
result = this
|
||||
or
|
||||
this instanceof ScalarValueImpl and
|
||||
result.getAChildNode*() = this.getParentNode()
|
||||
if this instanceof StepImpl
|
||||
then result = this
|
||||
else
|
||||
if this instanceof ScalarValueImpl
|
||||
then result.getAChildNode*() = this.getParentNode()
|
||||
else none()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1415,8 +1416,9 @@ class ExternalJobImpl extends JobImpl, UsesImpl {
|
||||
override string getVersion() {
|
||||
exists(YamlString name |
|
||||
n.lookup("uses") = name and
|
||||
not name.getValue().matches("\\.%") and
|
||||
result = name.getValue().regexpCapture(repoUsesParser(), 4)
|
||||
if not name.getValue().matches("\\.%")
|
||||
then result = name.getValue().regexpCapture(repoUsesParser(), 4)
|
||||
else none()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ private module Cached {
|
||||
/**
|
||||
* Holds if `cfn` is the `i`th node in basic block `bb`.
|
||||
*
|
||||
* In other words, `i` is the shortest distance from a node `bbStart`
|
||||
* In other words, `i` is the shortest distance from a node `bb`
|
||||
* that starts a basic block to `cfn` along the `intraBBSucc` relation.
|
||||
*/
|
||||
cached
|
||||
|
||||
@@ -3,8 +3,6 @@ private import codeql.controlflow.Cfg as CfgShared
|
||||
private import codeql.Locations
|
||||
|
||||
module Completion {
|
||||
import codeql.controlflow.SuccessorType
|
||||
|
||||
private newtype TCompletion =
|
||||
TSimpleCompletion() or
|
||||
TBooleanCompletion(boolean b) { b in [false, true] } or
|
||||
@@ -27,7 +25,7 @@ module Completion {
|
||||
|
||||
override predicate isValidFor(AstNode e) { not any(Completion c).isValidForSpecific(e) }
|
||||
|
||||
override DirectSuccessor getAMatchingSuccessorType() { any() }
|
||||
override NormalSuccessor getAMatchingSuccessorType() { any() }
|
||||
}
|
||||
|
||||
class BooleanCompletion extends NormalCompletion, TBooleanCompletion {
|
||||
@@ -51,6 +49,34 @@ module Completion {
|
||||
|
||||
override ReturnSuccessor getAMatchingSuccessorType() { any() }
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TSuccessorType =
|
||||
TNormalSuccessor() or
|
||||
TBooleanSuccessor(boolean b) { b in [false, true] } or
|
||||
TReturnSuccessor()
|
||||
|
||||
class SuccessorType extends TSuccessorType {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class NormalSuccessor extends SuccessorType, TNormalSuccessor {
|
||||
override string toString() { result = "successor" }
|
||||
}
|
||||
|
||||
class BooleanSuccessor extends SuccessorType, TBooleanSuccessor {
|
||||
boolean value;
|
||||
|
||||
BooleanSuccessor() { this = TBooleanSuccessor(value) }
|
||||
|
||||
override string toString() { result = value.toString() }
|
||||
|
||||
boolean getValue() { result = value }
|
||||
}
|
||||
|
||||
class ReturnSuccessor extends SuccessorType, TReturnSuccessor {
|
||||
override string toString() { result = "return" }
|
||||
}
|
||||
}
|
||||
|
||||
module CfgScope {
|
||||
@@ -101,8 +127,14 @@ private module Implementation implements CfgShared::InputSig<Location> {
|
||||
last(scope.(CompositeAction), e, c)
|
||||
}
|
||||
|
||||
predicate successorTypeIsSimple(SuccessorType t) { t instanceof NormalSuccessor }
|
||||
|
||||
predicate successorTypeIsCondition(SuccessorType t) { t instanceof BooleanSuccessor }
|
||||
|
||||
SuccessorType getAMatchingSuccessorType(Completion c) { result = c.getAMatchingSuccessorType() }
|
||||
|
||||
predicate isAbnormalExitType(SuccessorType t) { none() }
|
||||
|
||||
int idOfAstNode(AstNode node) { none() }
|
||||
|
||||
int idOfCfgScope(CfgScope scope) { none() }
|
||||
|
||||
@@ -63,10 +63,10 @@ predicate madSource(DataFlow::Node source, string kind, string fieldName) {
|
||||
(
|
||||
if fieldName.trim().matches("env.%")
|
||||
then source.asExpr() = uses.getInScopeEnvVarExpr(fieldName.trim().replaceAll("env.", ""))
|
||||
else (
|
||||
fieldName.trim().matches("output.%") and
|
||||
source.asExpr() = uses
|
||||
)
|
||||
else
|
||||
if fieldName.trim().matches("output.%")
|
||||
then source.asExpr() = uses
|
||||
else none()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -31,14 +31,14 @@ abstract class RemoteFlowSource extends SourceNode {
|
||||
class GitHubCtxSource extends RemoteFlowSource {
|
||||
string flag;
|
||||
string event;
|
||||
GitHubExpression e;
|
||||
|
||||
GitHubCtxSource() {
|
||||
exists(GitHubExpression e |
|
||||
this.asExpr() = e and
|
||||
// github.head_ref
|
||||
e.getFieldName() = "head_ref" and
|
||||
flag = "branch"
|
||||
|
|
||||
this.asExpr() = e and
|
||||
// github.head_ref
|
||||
e.getFieldName() = "head_ref" and
|
||||
flag = "branch" and
|
||||
(
|
||||
event = e.getATriggerEvent().getName() and
|
||||
event = "pull_request_target"
|
||||
or
|
||||
@@ -148,6 +148,7 @@ class GhCLICommandSource extends RemoteFlowSource, CommandSource {
|
||||
class GitHubEventPathSource extends RemoteFlowSource, CommandSource {
|
||||
string cmd;
|
||||
string flag;
|
||||
string access_path;
|
||||
Run run;
|
||||
|
||||
// Examples
|
||||
@@ -162,7 +163,7 @@ class GitHubEventPathSource extends RemoteFlowSource, CommandSource {
|
||||
run.getScript().getACommand() = cmd and
|
||||
cmd.matches("jq%") and
|
||||
cmd.matches("%GITHUB_EVENT_PATH%") and
|
||||
exists(string regexp, string access_path |
|
||||
exists(string regexp |
|
||||
untrustedEventPropertiesDataModel(regexp, flag) and
|
||||
not flag = "json" and
|
||||
access_path = "github.event" + cmd.regexpCapture(".*\\s+([^\\s]+)\\s+.*", 1) and
|
||||
|
||||
@@ -19,6 +19,7 @@ abstract class ArgumentInjectionSink extends DataFlow::Node {
|
||||
*/
|
||||
class ArgumentInjectionFromEnvVarSink extends ArgumentInjectionSink {
|
||||
string command;
|
||||
string argument;
|
||||
|
||||
ArgumentInjectionFromEnvVarSink() {
|
||||
exists(Run run, string var |
|
||||
@@ -27,7 +28,7 @@ class ArgumentInjectionFromEnvVarSink extends ArgumentInjectionSink {
|
||||
exists(run.getInScopeEnvVarExpr(var)) or
|
||||
var = "GITHUB_HEAD_REF"
|
||||
) and
|
||||
run.getScript().getAnEnvReachingArgumentInjectionSink(var, command, _)
|
||||
run.getScript().getAnEnvReachingArgumentInjectionSink(var, command, argument)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -43,12 +44,13 @@ class ArgumentInjectionFromEnvVarSink extends ArgumentInjectionSink {
|
||||
*/
|
||||
class ArgumentInjectionFromCommandSink extends ArgumentInjectionSink {
|
||||
string command;
|
||||
string argument;
|
||||
|
||||
ArgumentInjectionFromCommandSink() {
|
||||
exists(CommandSource source, Run run |
|
||||
run = source.getEnclosingRun() and
|
||||
this.asExpr() = run.getScript() and
|
||||
run.getScript().getACmdReachingArgumentInjectionSink(source.getCommand(), command, _)
|
||||
run.getScript().getACmdReachingArgumentInjectionSink(source.getCommand(), command, argument)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +125,8 @@ class LegitLabsDownloadArtifactActionStep extends UntrustedArtifactDownloadStep,
|
||||
}
|
||||
|
||||
class ActionsGitHubScriptDownloadStep extends UntrustedArtifactDownloadStep, UsesStep {
|
||||
string script;
|
||||
|
||||
ActionsGitHubScriptDownloadStep() {
|
||||
// eg:
|
||||
// - uses: actions/github-script@v6
|
||||
@@ -147,14 +149,12 @@ class ActionsGitHubScriptDownloadStep extends UntrustedArtifactDownloadStep, Use
|
||||
// var fs = require('fs');
|
||||
// fs.writeFileSync('${{github.workspace}}/test-results.zip', Buffer.from(download.data));
|
||||
this.getCallee() = "actions/github-script" and
|
||||
exists(string script |
|
||||
this.getArgument("script") = script and
|
||||
script.matches("%listWorkflowRunArtifacts(%") and
|
||||
script.matches("%downloadArtifact(%") and
|
||||
script.matches("%writeFileSync(%") and
|
||||
// Filter out artifacts that were created by pull-request.
|
||||
not script.matches("%exclude_pull_requests: true%")
|
||||
)
|
||||
this.getArgument("script") = script and
|
||||
script.matches("%listWorkflowRunArtifacts(%") and
|
||||
script.matches("%downloadArtifact(%") and
|
||||
script.matches("%writeFileSync(%") and
|
||||
// Filter out artifacts that were created by pull-request.
|
||||
not script.matches("%exclude_pull_requests: true%")
|
||||
}
|
||||
|
||||
override string getPath() {
|
||||
@@ -171,10 +171,10 @@ class ActionsGitHubScriptDownloadStep extends UntrustedArtifactDownloadStep, Use
|
||||
.getScript()
|
||||
.getACommand()
|
||||
.regexpCapture(unzipRegexp() + unzipDirArgRegexp(), 3)))
|
||||
else (
|
||||
this.getAFollowingStep().(Run).getScript().getACommand().regexpMatch(unzipRegexp()) and
|
||||
result = "GITHUB_WORKSPACE/"
|
||||
)
|
||||
else
|
||||
if this.getAFollowingStep().(Run).getScript().getACommand().regexpMatch(unzipRegexp())
|
||||
then result = "GITHUB_WORKSPACE/"
|
||||
else none()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,13 +207,12 @@ class GHRunArtifactDownloadStep extends UntrustedArtifactDownloadStep, Run {
|
||||
.getScript()
|
||||
.getACommand()
|
||||
.regexpCapture(unzipRegexp() + unzipDirArgRegexp(), 3)))
|
||||
else (
|
||||
(
|
||||
else
|
||||
if
|
||||
this.getAFollowingStep().(Run).getScript().getACommand().regexpMatch(unzipRegexp()) or
|
||||
this.getScript().getACommand().regexpMatch(unzipRegexp())
|
||||
) and
|
||||
result = "GITHUB_WORKSPACE/"
|
||||
)
|
||||
then result = "GITHUB_WORKSPACE/"
|
||||
else none()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,15 +259,15 @@ class DirectArtifactDownloadStep extends UntrustedArtifactDownloadStep, Run {
|
||||
|
||||
class ArtifactPoisoningSink extends DataFlow::Node {
|
||||
UntrustedArtifactDownloadStep download;
|
||||
PoisonableStep poisonable;
|
||||
|
||||
ArtifactPoisoningSink() {
|
||||
exists(PoisonableStep poisonable |
|
||||
download.getAFollowingStep() = poisonable and
|
||||
// excluding artifacts downloaded to the temporary directory
|
||||
not download.getPath().regexpMatch("^/tmp.*") and
|
||||
not download.getPath().regexpMatch("^\\$\\{\\{\\s*runner\\.temp\\s*}}.*") and
|
||||
not download.getPath().regexpMatch("^\\$RUNNER_TEMP.*")
|
||||
|
|
||||
download.getAFollowingStep() = poisonable and
|
||||
// excluding artifacts downloaded to the temporary directory
|
||||
not download.getPath().regexpMatch("^/tmp.*") and
|
||||
not download.getPath().regexpMatch("^\\$\\{\\{\\s*runner\\.temp\\s*}}.*") and
|
||||
not download.getPath().regexpMatch("^\\$RUNNER_TEMP.*") and
|
||||
(
|
||||
poisonable.(Run).getScript() = this.asExpr() and
|
||||
(
|
||||
// Check if the poisonable step is a local script execution step
|
||||
|
||||
@@ -159,8 +159,11 @@ abstract class CommentVsHeadDateCheck extends ControlCheck {
|
||||
|
||||
/* Specific implementations of control checks */
|
||||
class LabelIfCheck extends LabelCheck instanceof If {
|
||||
string condition;
|
||||
|
||||
LabelIfCheck() {
|
||||
exists(string condition | condition = normalizeExpr(this.getCondition()) |
|
||||
condition = normalizeExpr(this.getCondition()) and
|
||||
(
|
||||
// eg: contains(github.event.pull_request.labels.*.name, 'safe to test')
|
||||
condition.regexpMatch(".*(^|[^!])contains\\(\\s*github\\.event\\.pull_request\\.labels\\b.*")
|
||||
or
|
||||
|
||||
@@ -55,8 +55,12 @@ class EnvVarInjectionFromFileReadSink extends EnvVarInjectionSink {
|
||||
* echo "COMMIT_MESSAGE=${COMMIT_MESSAGE}" >> $GITHUB_ENV
|
||||
*/
|
||||
class EnvVarInjectionFromCommandSink extends EnvVarInjectionSink {
|
||||
CommandSource inCommand;
|
||||
string injectedVar;
|
||||
string command;
|
||||
|
||||
EnvVarInjectionFromCommandSink() {
|
||||
exists(Run run, CommandSource inCommand, string injectedVar, string command |
|
||||
exists(Run run |
|
||||
this.asExpr() = inCommand.getEnclosingRun().getScript() and
|
||||
run = inCommand.getEnclosingRun() and
|
||||
run.getScript().getACmdReachingGitHubEnvWrite(inCommand.getCommand(), injectedVar) and
|
||||
@@ -82,8 +86,12 @@ class EnvVarInjectionFromCommandSink extends EnvVarInjectionSink {
|
||||
* echo "FOO=$BODY" >> $GITHUB_ENV
|
||||
*/
|
||||
class EnvVarInjectionFromEnvVarSink extends EnvVarInjectionSink {
|
||||
string inVar;
|
||||
string injectedVar;
|
||||
string command;
|
||||
|
||||
EnvVarInjectionFromEnvVarSink() {
|
||||
exists(Run run, string inVar, string injectedVar, string command |
|
||||
exists(Run run |
|
||||
run.getScript() = this.asExpr() and
|
||||
exists(run.getInScopeEnvVarExpr(inVar)) and
|
||||
run.getScript().getAnEnvReachingGitHubEnvWrite(inVar, injectedVar) and
|
||||
|
||||
@@ -99,14 +99,18 @@ class OutputClobberingFromEnvVarSink extends OutputClobberingSink {
|
||||
* echo $BODY
|
||||
*/
|
||||
class WorkflowCommandClobberingFromEnvVarSink extends OutputClobberingSink {
|
||||
string clobbering_var;
|
||||
string clobbered_value;
|
||||
|
||||
WorkflowCommandClobberingFromEnvVarSink() {
|
||||
exists(Run run, string workflow_cmd_stmt, string clobbering_stmt, string clobbering_var |
|
||||
exists(Run run, string workflow_cmd_stmt, string clobbering_stmt |
|
||||
run.getScript() = this.asExpr() and
|
||||
run.getScript().getAStmt() = clobbering_stmt and
|
||||
clobbering_stmt.regexpMatch("echo\\s+(-e\\s+)?(\"|')?\\$(\\{)?" + clobbering_var + ".*") and
|
||||
exists(run.getInScopeEnvVarExpr(clobbering_var)) and
|
||||
run.getScript().getAStmt() = workflow_cmd_stmt and
|
||||
exists(trimQuotes(workflow_cmd_stmt.regexpCapture(".*::set-output\\s+name=.*::(.*)", 1)))
|
||||
clobbered_value =
|
||||
trimQuotes(workflow_cmd_stmt.regexpCapture(".*::set-output\\s+name=.*::(.*)", 1))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import actions
|
||||
|
||||
class UnversionedImmutableAction extends UsesStep {
|
||||
string immutable_action;
|
||||
|
||||
UnversionedImmutableAction() {
|
||||
isImmutableAction(this, _) and
|
||||
isImmutableAction(this, immutable_action) and
|
||||
not isSemVer(this.getVersion())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-all
|
||||
version: 0.4.17
|
||||
version: 0.4.16-dev
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
## 0.6.9
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Actions analysis now reports file coverage information on the CodeQL status page.
|
||||
|
||||
## 0.6.8
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.7
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* @id actions/diagnostics/successfully-extracted-files
|
||||
* @name Extracted files
|
||||
* @description List all files that were extracted.
|
||||
* @kind diagnostic
|
||||
* @tags successfully-extracted-files
|
||||
*/
|
||||
|
||||
private import codeql.Locations
|
||||
|
||||
from File f
|
||||
where exists(f.getRelativePath())
|
||||
select f, ""
|
||||
@@ -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 # scripts in package.json from PR would be executed here
|
||||
npm build
|
||||
|
||||
- uses: completely/fakeaction@v2
|
||||
|
||||
@@ -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 # scripts in package.json from PR would be executed here
|
||||
npm build
|
||||
|
||||
- uses: completely/fakeaction@v2
|
||||
|
||||
@@ -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 # scripts in package.json from PR would be executed here
|
||||
npm build
|
||||
|
||||
- uses: completely/fakeaction@v2
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.8
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,5 +0,0 @@
|
||||
## 0.6.9
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Actions analysis now reports file coverage information on the CodeQL status page.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.9
|
||||
lastReleaseVersion: 0.6.7
|
||||
|
||||
@@ -37,6 +37,8 @@ where
|
||||
)
|
||||
or
|
||||
// upload artifact is not used in the same workflow
|
||||
not download.getEnclosingWorkflow().getAJob().(LocalJob).getAStep() instanceof UsesStep
|
||||
not exists(UsesStep upload |
|
||||
download.getEnclosingWorkflow().getAJob().(LocalJob).getAStep() = upload
|
||||
)
|
||||
)
|
||||
select download, "Potential artifact poisoning"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-queries
|
||||
version: 0.6.9
|
||||
version: 0.6.8-dev
|
||||
library: false
|
||||
warnOnImplicitThis: true
|
||||
groups: [actions, queries]
|
||||
|
||||
@@ -177,12 +177,6 @@ def insert_overlay_caller_annotations(lines):
|
||||
out_lines.append(line)
|
||||
return out_lines
|
||||
|
||||
explicitly_global = set([
|
||||
"java/ql/lib/semmle/code/java/dispatch/VirtualDispatch.qll",
|
||||
"java/ql/lib/semmle/code/java/dispatch/DispatchFlow.qll",
|
||||
"java/ql/lib/semmle/code/java/dispatch/ObjFlow.qll",
|
||||
"java/ql/lib/semmle/code/java/dispatch/internal/Unification.qll",
|
||||
])
|
||||
|
||||
def annotate_as_appropriate(filename, lines):
|
||||
'''
|
||||
@@ -202,9 +196,6 @@ def annotate_as_appropriate(filename, lines):
|
||||
((filename.endswith("Query.qll") or filename.endswith("Config.qll")) and
|
||||
any("implements DataFlow::ConfigSig" in line for line in lines))):
|
||||
return None
|
||||
elif filename in explicitly_global:
|
||||
# These files are explicitly global and should not be annotated.
|
||||
return None
|
||||
elif not any(line for line in lines if line.strip()):
|
||||
return None
|
||||
|
||||
|
||||
@@ -7,10 +7,12 @@ ql/cpp/ql/src/Diagnostics/ExtractedFiles.ql
|
||||
ql/cpp/ql/src/Diagnostics/ExtractionWarnings.ql
|
||||
ql/cpp/ql/src/Diagnostics/FailedExtractorInvocations.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Memory Management/PointerOverflow.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql
|
||||
@@ -28,6 +30,7 @@ ql/cpp/ql/src/Security/CWE/CWE-120/VeryLikelyOverrunWrite.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql
|
||||
@@ -40,6 +43,7 @@ ql/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-416/UseOfStringAfterLifetimeEnds.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-416/UseOfUniquePointerAfterLifetimeEnds.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-611/XXE.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.ql
|
||||
|
||||
@@ -1,24 +1,3 @@
|
||||
## 5.6.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The predicate `getAContructorCall` in the class `SslContextClass` has been deprecated. Use `getAConstructorCall` instead.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added predicates `getTransitiveNumberOfVlaDimensionStmts`, `getTransitiveVlaDimensionStmt`, and `getParentVlaDecl` to `VlaDeclStmt` for handling `VlaDeclStmt`s whose base type is defined in terms of another `VlaDeclStmt` via a `typedef`.
|
||||
|
||||
## 5.5.0
|
||||
|
||||
### New Features
|
||||
|
||||
* Added a new class `PchFile` representing precompiled header (PCH) files used during project compilation.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added flow summaries for the `Microsoft::WRL::ComPtr` member functions.
|
||||
* 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.
|
||||
|
||||
## 5.4.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -35,7 +35,7 @@ class CustomOptions extends Options {
|
||||
override predicate returnsNull(Call call) { Options.super.returnsNull(call) }
|
||||
|
||||
/**
|
||||
* Holds if a call to the function `f` will never return.
|
||||
* Holds if a call to this function will never return.
|
||||
*
|
||||
* By default, this holds for `exit`, `_exit`, `abort`, `__assert_fail`,
|
||||
* `longjmp`, `error`, `__builtin_unreachable` and any function with a
|
||||
|
||||
4
cpp/ql/lib/change-notes/2025-08-19-virtual-dispatch.md
Normal file
4
cpp/ql/lib/change-notes/2025-08-19-virtual-dispatch.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
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.
|
||||
5
cpp/ql/lib/change-notes/2025-08-27-pch.md
Normal file
5
cpp/ql/lib/change-notes/2025-08-27-pch.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added a new class `PchFile` representing precompiled header (PCH) files used during project compilation.
|
||||
|
||||
4
cpp/ql/lib/change-notes/2025-08-28-comptr.md
Normal file
4
cpp/ql/lib/change-notes/2025-08-28-comptr.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added flow summaries for the `Microsoft::WRL::ComPtr` member functions.
|
||||
@@ -1,10 +0,0 @@
|
||||
## 5.5.0
|
||||
|
||||
### New Features
|
||||
|
||||
* Added a new class `PchFile` representing precompiled header (PCH) files used during project compilation.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added flow summaries for the `Microsoft::WRL::ComPtr` member functions.
|
||||
* The new dataflow/taint-tracking library (`semmle.code.cpp.dataflow.new.DataFlow` and `semmle.code.cpp.dataflow.new.TaintTracking`) now resolves virtual function calls more precisely. This results in fewer false positives when running dataflow/taint-tracking queries on C++ projects.
|
||||
@@ -1,9 +0,0 @@
|
||||
## 5.6.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The predicate `getAContructorCall` in the class `SslContextClass` has been deprecated. Use `getAConstructorCall` instead.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added predicates `getTransitiveNumberOfVlaDimensionStmts`, `getTransitiveVlaDimensionStmt`, and `getParentVlaDecl` to `VlaDeclStmt` for handling `VlaDeclStmt`s whose base type is defined in terms of another `VlaDeclStmt` via a `typedef`.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 5.6.0
|
||||
lastReleaseVersion: 5.4.1
|
||||
|
||||
@@ -127,7 +127,7 @@ abstract class CryptographicAlgorithm extends CryptographicArtifact {
|
||||
/**
|
||||
* Normalizes a raw name into a normalized name as found in `CryptoAlgorithmNames.qll`.
|
||||
* Subclassess should override for more api-specific normalization.
|
||||
* By default, converts a raw name to upper-case with no hyphen, underscore, hash, or space.
|
||||
* By deafult, converts a raw name to upper-case with no hyphen, underscore, hash, or space.
|
||||
*/
|
||||
bindingset[s]
|
||||
string normalizeName(string s) {
|
||||
|
||||
@@ -652,14 +652,14 @@ module KeyGeneration {
|
||||
* Trace from EVP_PKEY_CTX* at algorithm sink to keygen,
|
||||
* users can then extrapolatae the matching algorithm from the alg sink to the keygen
|
||||
*/
|
||||
module EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSizeConfig implements DataFlow::ConfigSig {
|
||||
module EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSize implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isEVP_PKEY_CTX_Source(source, _) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isKeyGen_EVP_PKEY_CTX_Sink(sink, _) }
|
||||
}
|
||||
|
||||
module EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSize_Flow =
|
||||
DataFlow::Global<EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSizeConfig>;
|
||||
DataFlow::Global<EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSize>;
|
||||
|
||||
/**
|
||||
* UNKNOWN key sizes to general purpose key generation functions (i.e., that take in no key size and assume
|
||||
|
||||
@@ -59,7 +59,7 @@ private string privateNormalizeFunctionName(Function f, string algType) {
|
||||
*
|
||||
* The predicate attempts to restrict normalization to what looks like an openssl
|
||||
* library by looking for functions only in an openssl path (see `isPossibleOpenSSLFunction`).
|
||||
* This may give false positive functions if a directory erronously appears to be openssl;
|
||||
* This may give false postive functions if a directory erronously appears to be openssl;
|
||||
* however, we take the stance that if a function
|
||||
* exists strongly mapping to a known function name in a directory such as these,
|
||||
* regardless of whether its actually a part of openSSL or not, we will analyze it as though it were.
|
||||
|
||||
@@ -49,7 +49,7 @@ private string privateNormalizeFunctionName(Function f, string algType) {
|
||||
*
|
||||
* The predicate attempts to restrict normalization to what looks like an openssl
|
||||
* library by looking for functions only in an openssl path (see `isPossibleOpenSSLFunction`).
|
||||
* This may give false positive functions if a directory erronously appears to be openssl;
|
||||
* This may give false postive functions if a directory erronously appears to be openssl;
|
||||
* however, we take the stance that if a function
|
||||
* exists strongly mapping to a known function name in a directory such as these,
|
||||
* regardless of whether its actually a part of openSSL or not, we will analyze it as though it were.
|
||||
|
||||
@@ -31,7 +31,7 @@ predicate knownPassthroughFunction(Function f, int inInd, int outInd) {
|
||||
|
||||
/**
|
||||
* `c` is a call to a function that preserves the algorithm but changes its form.
|
||||
* `inExpr` is the input argument passing through to, `outExpr` is the next expression in a dataflow step associated with `c`
|
||||
* `onExpr` is the input argument passing through to, `outExpr` is the next expression in a dataflow step associated with `c`
|
||||
*/
|
||||
predicate knownPassthoughCall(Call c, Expr inExpr, Expr outExpr) {
|
||||
exists(int inInd, int outInd |
|
||||
|
||||
@@ -298,11 +298,10 @@ private predicate boundFlowStep(Instruction i, NonPhiOperand op, int delta, bool
|
||||
else
|
||||
if strictlyNegative(x)
|
||||
then upper = true and delta = -1
|
||||
else (
|
||||
negative(x) and
|
||||
upper = true and
|
||||
delta = 0
|
||||
)
|
||||
else
|
||||
if negative(x)
|
||||
then upper = true and delta = 0
|
||||
else none()
|
||||
)
|
||||
or
|
||||
exists(Operand x |
|
||||
@@ -322,11 +321,10 @@ private predicate boundFlowStep(Instruction i, NonPhiOperand op, int delta, bool
|
||||
else
|
||||
if strictlyNegative(x)
|
||||
then upper = false and delta = 1
|
||||
else (
|
||||
negative(x) and
|
||||
upper = false and
|
||||
delta = 0
|
||||
)
|
||||
else
|
||||
if negative(x)
|
||||
then upper = false and delta = 0
|
||||
else none()
|
||||
)
|
||||
or
|
||||
i.(RemInstruction).getRightOperand() = op and positive(op) and delta = -1 and upper = true
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 5.6.0
|
||||
version: 5.4.2-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -198,7 +198,7 @@ class ConceptIdExpr extends Expr, @concept_id {
|
||||
final Locatable getATemplateArgumentKind() { result = this.getTemplateArgumentKind(_) }
|
||||
|
||||
/**
|
||||
* Gets template argument at index `index` passed to the concept, if any.
|
||||
* Gets the `i`th template argument passed to the concept.
|
||||
*
|
||||
* For example, if:
|
||||
* ```cpp
|
||||
@@ -219,7 +219,7 @@ class ConceptIdExpr extends Expr, @concept_id {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kind of the template argument value at index `index` passed to the concept, if any.
|
||||
* Gets the kind of the `i`th template argument value passed to the concept.
|
||||
*
|
||||
* For example, if:
|
||||
* ```cpp
|
||||
|
||||
@@ -223,8 +223,8 @@ class Declaration extends Locatable, @declaration {
|
||||
final Locatable getATemplateArgumentKind() { result = this.getTemplateArgumentKind(_) }
|
||||
|
||||
/**
|
||||
* Gets the template argument at index `index` used to instantiate this declaration from a
|
||||
* template, if any.
|
||||
* Gets the `i`th template argument used to instantiate this declaration from a
|
||||
* template.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
@@ -245,9 +245,9 @@ class Declaration extends Locatable, @declaration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the template argument value at index `index` used to instantiate this declaration
|
||||
* from a template. When called on a template, this will return the template
|
||||
* parameter value at index `index` if it exists.
|
||||
* Gets the `i`th template argument value used to instantiate this declaration
|
||||
* from a template. When called on a template, this will return the `i`th template
|
||||
* parameter value if it exists.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
|
||||
@@ -877,7 +877,7 @@ class FormatLiteral extends Literal instanceof StringLiteral {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the char type required by the `n`th conversion specifier.
|
||||
* Gets the char type required by the nth conversion specifier.
|
||||
* - in the base case this is the default for the formatting function
|
||||
* (e.g. `char` for `printf`, `char` or `wchar_t` for `wprintf`).
|
||||
* - the `%C` format character reverses wideness.
|
||||
@@ -922,7 +922,7 @@ class FormatLiteral extends Literal instanceof StringLiteral {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string type required by the `n`th conversion specifier.
|
||||
* Gets the string type required by the nth conversion specifier.
|
||||
* - in the base case this is the default for the formatting function
|
||||
* (e.g. `char *` for `printf`, `char *` or `wchar_t *` for `wprintf`).
|
||||
* - the `%S` format character reverses wideness on some platforms.
|
||||
|
||||
@@ -101,7 +101,7 @@ predicate postDominates(ControlFlowNode postDominator, ControlFlowNode node) {
|
||||
*/
|
||||
|
||||
/**
|
||||
* Holds if `dom` is an immediate dominator of `node` in the control-flow
|
||||
* Holds if `dominator` is an immediate dominator of `node` in the control-flow
|
||||
* graph of basic blocks.
|
||||
*/
|
||||
predicate bbIDominates(BasicBlock dom, BasicBlock node) =
|
||||
@@ -117,7 +117,7 @@ private predicate bb_predecessor(BasicBlock succ, BasicBlock pred) { bb_successo
|
||||
private predicate bb_exit(ExitBasicBlock exit) { any() }
|
||||
|
||||
/**
|
||||
* Holds if `pDom` is an immediate post-dominator of `node` in the control-flow
|
||||
* Holds if `postDominator` is an immediate post-dominator of `node` in the control-flow
|
||||
* graph of basic blocks.
|
||||
*/
|
||||
predicate bbIPostDominates(BasicBlock pDom, BasicBlock node) =
|
||||
|
||||
@@ -72,20 +72,6 @@ abstract private class GuardConditionImpl extends Expr {
|
||||
*/
|
||||
abstract predicate valueControls(BasicBlock controlled, AbstractValue v);
|
||||
|
||||
/**
|
||||
* Holds if the control-flow edge `(pred, succ)` may be taken only if
|
||||
* the value of this condition is `v`.
|
||||
*/
|
||||
abstract predicate valueControlsEdge(BasicBlock pred, BasicBlock succ, AbstractValue v);
|
||||
|
||||
/**
|
||||
* Holds if the control-flow edge `(pred, succ)` may be taken only if
|
||||
* this the value of this condition is `testIsTrue`.
|
||||
*/
|
||||
final predicate controlsEdge(BasicBlock pred, BasicBlock succ, boolean testIsTrue) {
|
||||
this.valueControlsEdge(pred, succ, any(BooleanValue bv | bv.getValue() = testIsTrue))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this condition controls `controlled`, meaning that `controlled` is only
|
||||
* entered if the value of this condition is `testIsTrue`.
|
||||
@@ -189,58 +175,6 @@ abstract private class GuardConditionImpl extends Expr {
|
||||
*/
|
||||
pragma[inline]
|
||||
abstract predicate ensuresEq(Expr e, int k, BasicBlock block, boolean areEqual);
|
||||
|
||||
/**
|
||||
* Holds if (determined by this guard) `left == right + k` must be `areEqual` on the edge from
|
||||
* `pred` to `succ`. If `areEqual = false` then this implies `left != right + k`.
|
||||
*/
|
||||
pragma[inline]
|
||||
final predicate ensuresEqEdge(
|
||||
Expr left, Expr right, int k, BasicBlock pred, BasicBlock succ, boolean areEqual
|
||||
) {
|
||||
exists(boolean testIsTrue |
|
||||
this.comparesEq(left, right, k, areEqual, testIsTrue) and
|
||||
this.controlsEdge(pred, succ, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if (determined by this guard) `e == k` must be `areEqual` on the edge from
|
||||
* `pred` to `succ`. If `areEqual = false` then this implies `e != k`.
|
||||
*/
|
||||
pragma[inline]
|
||||
final predicate ensuresEqEdge(Expr e, int k, BasicBlock pred, BasicBlock succ, boolean areEqual) {
|
||||
exists(AbstractValue v |
|
||||
this.comparesEq(e, k, areEqual, v) and
|
||||
this.valueControlsEdge(pred, succ, v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if (determined by this guard) `left < right + k` must be `isLessThan` on the edge from
|
||||
* `pred` to `succ`. If `isLessThan = false` then this implies `left >= right + k`.
|
||||
*/
|
||||
pragma[inline]
|
||||
final predicate ensuresLtEdge(
|
||||
Expr left, Expr right, int k, BasicBlock pred, BasicBlock succ, boolean isLessThan
|
||||
) {
|
||||
exists(boolean testIsTrue |
|
||||
this.comparesLt(left, right, k, isLessThan, testIsTrue) and
|
||||
this.controlsEdge(pred, succ, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if (determined by this guard) `e < k` must be `isLessThan` on the edge from
|
||||
* `pred` to `succ`. If `isLessThan = false` then this implies `e >= k`.
|
||||
*/
|
||||
pragma[inline]
|
||||
final predicate ensuresLtEdge(Expr e, int k, BasicBlock pred, BasicBlock succ, boolean isLessThan) {
|
||||
exists(AbstractValue v |
|
||||
this.comparesLt(e, k, isLessThan, v) and
|
||||
this.valueControlsEdge(pred, succ, v)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
final class GuardCondition = GuardConditionImpl;
|
||||
@@ -253,16 +187,6 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardConditionImpl
|
||||
this.(BinaryLogicalOperation).getAnOperand() instanceof GuardCondition
|
||||
}
|
||||
|
||||
override predicate valueControlsEdge(BasicBlock pred, BasicBlock succ, AbstractValue v) {
|
||||
exists(BinaryLogicalOperation binop, GuardCondition lhs, GuardCondition rhs |
|
||||
this = binop and
|
||||
lhs = binop.getLeftOperand() and
|
||||
rhs = binop.getRightOperand() and
|
||||
lhs.valueControlsEdge(pred, succ, v) and
|
||||
rhs.valueControlsEdge(pred, succ, v)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate valueControls(BasicBlock controlled, AbstractValue v) {
|
||||
exists(BinaryLogicalOperation binop, GuardCondition lhs, GuardCondition rhs |
|
||||
this = binop and
|
||||
@@ -350,25 +274,6 @@ private predicate controlsBlock(IRGuardCondition ir, BasicBlock controlled, Abst
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ir` controls the `(pred, succ)` edge, meaning that the edge
|
||||
* `(pred, succ)` is only taken if the value of this condition is `v`. This
|
||||
* helper predicate does not necessarily hold for binary logical operations
|
||||
* like `&&` and `||`.
|
||||
* See the detailed explanation on predicate `controlsEdge`.
|
||||
*/
|
||||
private predicate controlsEdge(
|
||||
IRGuardCondition ir, BasicBlock pred, BasicBlock succ, AbstractValue v
|
||||
) {
|
||||
exists(IRBlock irPred, IRBlock irSucc |
|
||||
ir.valueControlsEdge(irPred, irSucc, v) and
|
||||
nonExcludedIRAndBasicBlock(irPred, pred) and
|
||||
nonExcludedIRAndBasicBlock(irSucc, succ) and
|
||||
not isUnreachedBlock(irPred) and
|
||||
not isUnreachedBlock(irSucc)
|
||||
)
|
||||
}
|
||||
|
||||
private class GuardConditionFromNotExpr extends GuardConditionImpl {
|
||||
IRGuardCondition ir;
|
||||
|
||||
@@ -390,10 +295,6 @@ private class GuardConditionFromNotExpr extends GuardConditionImpl {
|
||||
controlsBlock(ir, controlled, v.getDualValue())
|
||||
}
|
||||
|
||||
override predicate valueControlsEdge(BasicBlock pred, BasicBlock succ, AbstractValue v) {
|
||||
controlsEdge(ir, pred, succ, v.getDualValue())
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
|
||||
exists(Instruction li, Instruction ri |
|
||||
@@ -482,10 +383,6 @@ private class GuardConditionFromIR extends GuardConditionImpl {
|
||||
controlsBlock(ir, controlled, v)
|
||||
}
|
||||
|
||||
override predicate valueControlsEdge(BasicBlock pred, BasicBlock succ, AbstractValue v) {
|
||||
controlsEdge(ir, pred, succ, v)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
|
||||
exists(Instruction li, Instruction ri |
|
||||
|
||||
@@ -1042,8 +1042,8 @@ private predicate subEdgeIncludingDestructors(Pos p1, Node n1, Node n2, Pos p2)
|
||||
* - `MicrosoftTryFinallyStmt`: On the edge following the `__finally` block for
|
||||
* the case where an exception was thrown and needs to be propagated.
|
||||
*/
|
||||
DestructorCall getSynthesisedDestructorCallAfterNode(Node node, int index) {
|
||||
synthetic_destructor_call(node, index, result)
|
||||
DestructorCall getSynthesisedDestructorCallAfterNode(Node n, int i) {
|
||||
synthetic_destructor_call(n, i, result)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -834,10 +834,8 @@ class ContentSet instanceof Content {
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
super.hasLocationInfo(path, sl, sc, el, ec)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2273,10 +2273,8 @@ class ContentSet instanceof Content {
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
super.hasLocationInfo(path, sl, sc, el, ec)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* Provides classes that specify the conditions under which control flows along a given edge.
|
||||
*/
|
||||
|
||||
private import codeql.controlflow.SuccessorType
|
||||
private import internal.EdgeKindInternal
|
||||
|
||||
private newtype TEdgeKind =
|
||||
@@ -29,21 +28,6 @@ abstract private class EdgeKindImpl extends TEdgeKind {
|
||||
|
||||
final class EdgeKind = EdgeKindImpl;
|
||||
|
||||
private SuccessorType getAMatchingSpecificSuccessorType(EdgeKind k) {
|
||||
result.(BooleanSuccessor).getValue() = true and k instanceof TrueEdge
|
||||
or
|
||||
result.(BooleanSuccessor).getValue() = false and k instanceof FalseEdge
|
||||
or
|
||||
result instanceof ExceptionSuccessor and k instanceof ExceptionEdge
|
||||
}
|
||||
|
||||
SuccessorType getAMatchingSuccessorType(EdgeKind k) {
|
||||
result = getAMatchingSpecificSuccessorType(k)
|
||||
or
|
||||
not exists(getAMatchingSpecificSuccessorType(k)) and
|
||||
result instanceof DirectSuccessor
|
||||
}
|
||||
|
||||
/**
|
||||
* A "goto" edge, representing the unconditional successor of an `Instruction`
|
||||
* or `IRBlock`.
|
||||
|
||||
@@ -265,10 +265,10 @@ private predicate isEntryBlock(TIRBlock block) {
|
||||
}
|
||||
|
||||
module IRCfg implements BB::CfgSig<Language::Location> {
|
||||
private import codeql.controlflow.SuccessorType
|
||||
|
||||
class ControlFlowNode = Instruction;
|
||||
|
||||
class SuccessorType = EdgeKind;
|
||||
|
||||
final private class FinalIRBlock = IRBlock;
|
||||
|
||||
class BasicBlock extends FinalIRBlock {
|
||||
@@ -280,12 +280,7 @@ module IRCfg implements BB::CfgSig<Language::Location> {
|
||||
|
||||
BasicBlock getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
BasicBlock getASuccessor(SuccessorType t) {
|
||||
exists(EdgeKind k |
|
||||
result = super.getSuccessor(k) and
|
||||
t = getAMatchingSuccessorType(k)
|
||||
)
|
||||
}
|
||||
BasicBlock getASuccessor(SuccessorType t) { result = super.getSuccessor(t) }
|
||||
|
||||
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ newtype TValueNumber =
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(Instruction instr) { uniqueValueNumber(instr) }
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
@@ -129,14 +129,12 @@ private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
count(instr.(InheritanceConversionInstruction).getBaseClass()) != 1 or
|
||||
count(instr.(InheritanceConversionInstruction).getDerivedClass()) != 1
|
||||
)
|
||||
or
|
||||
count(instr.getEnclosingIRFunction()) != 1
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -146,7 +144,7 @@ private predicate variableAddressValueNumber(
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -156,7 +154,7 @@ private predicate initializeParameterValueNumber(
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getResultIRType()) = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
@@ -164,7 +162,7 @@ private predicate constantValueNumber(
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
@@ -173,7 +171,7 @@ private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field,
|
||||
TValueNumber objectAddress
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getField()) = field and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
@@ -184,7 +182,7 @@ private predicate binaryValueNumber0(
|
||||
TValueNumber valueNumber
|
||||
) {
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
(
|
||||
isLeft = true and
|
||||
@@ -208,7 +206,7 @@ private predicate pointerArithmeticValueNumber0(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
boolean isLeft, TValueNumber valueNumber
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getElementSize() = elementSize and
|
||||
(
|
||||
@@ -231,7 +229,7 @@ private predicate pointerArithmeticValueNumber(
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
@@ -244,7 +242,7 @@ private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand and
|
||||
unique( | | instr.getBaseClass()) = baseClass and
|
||||
@@ -256,7 +254,7 @@ private predicate loadTotalOverlapValueNumber0(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber valueNumber,
|
||||
boolean isAddress
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
(
|
||||
isAddress = true and
|
||||
@@ -279,7 +277,8 @@ private predicate loadTotalOverlapValueNumber(
|
||||
* Holds if `instr` should be assigned a unique value number because this library does not know how
|
||||
* to determine if two instances of that instruction are equivalent.
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr) {
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
(
|
||||
not numberableInstruction(instr)
|
||||
@@ -295,8 +294,10 @@ cached
|
||||
TValueNumber tvalueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
uniqueValueNumber(instr) and
|
||||
result = TUniqueValueNumber(instr)
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,64 +311,68 @@ TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef
|
||||
* value number.
|
||||
*/
|
||||
private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc | irFunc = instr.getEnclosingIRFunction() |
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
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())
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result = TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
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())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -265,10 +265,10 @@ private predicate isEntryBlock(TIRBlock block) {
|
||||
}
|
||||
|
||||
module IRCfg implements BB::CfgSig<Language::Location> {
|
||||
private import codeql.controlflow.SuccessorType
|
||||
|
||||
class ControlFlowNode = Instruction;
|
||||
|
||||
class SuccessorType = EdgeKind;
|
||||
|
||||
final private class FinalIRBlock = IRBlock;
|
||||
|
||||
class BasicBlock extends FinalIRBlock {
|
||||
@@ -280,12 +280,7 @@ module IRCfg implements BB::CfgSig<Language::Location> {
|
||||
|
||||
BasicBlock getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
BasicBlock getASuccessor(SuccessorType t) {
|
||||
exists(EdgeKind k |
|
||||
result = super.getSuccessor(k) and
|
||||
t = getAMatchingSuccessorType(k)
|
||||
)
|
||||
}
|
||||
BasicBlock getASuccessor(SuccessorType t) { result = super.getSuccessor(t) }
|
||||
|
||||
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ newtype TValueNumber =
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(Instruction instr) { uniqueValueNumber(instr) }
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
@@ -129,14 +129,12 @@ private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
count(instr.(InheritanceConversionInstruction).getBaseClass()) != 1 or
|
||||
count(instr.(InheritanceConversionInstruction).getDerivedClass()) != 1
|
||||
)
|
||||
or
|
||||
count(instr.getEnclosingIRFunction()) != 1
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -146,7 +144,7 @@ private predicate variableAddressValueNumber(
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -156,7 +154,7 @@ private predicate initializeParameterValueNumber(
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getResultIRType()) = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
@@ -164,7 +162,7 @@ private predicate constantValueNumber(
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
@@ -173,7 +171,7 @@ private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field,
|
||||
TValueNumber objectAddress
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getField()) = field and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
@@ -184,7 +182,7 @@ private predicate binaryValueNumber0(
|
||||
TValueNumber valueNumber
|
||||
) {
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
(
|
||||
isLeft = true and
|
||||
@@ -208,7 +206,7 @@ private predicate pointerArithmeticValueNumber0(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
boolean isLeft, TValueNumber valueNumber
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getElementSize() = elementSize and
|
||||
(
|
||||
@@ -231,7 +229,7 @@ private predicate pointerArithmeticValueNumber(
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
@@ -244,7 +242,7 @@ private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand and
|
||||
unique( | | instr.getBaseClass()) = baseClass and
|
||||
@@ -256,7 +254,7 @@ private predicate loadTotalOverlapValueNumber0(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber valueNumber,
|
||||
boolean isAddress
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
(
|
||||
isAddress = true and
|
||||
@@ -279,7 +277,8 @@ private predicate loadTotalOverlapValueNumber(
|
||||
* Holds if `instr` should be assigned a unique value number because this library does not know how
|
||||
* to determine if two instances of that instruction are equivalent.
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr) {
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
(
|
||||
not numberableInstruction(instr)
|
||||
@@ -295,8 +294,10 @@ cached
|
||||
TValueNumber tvalueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
uniqueValueNumber(instr) and
|
||||
result = TUniqueValueNumber(instr)
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,64 +311,68 @@ TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef
|
||||
* value number.
|
||||
*/
|
||||
private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc | irFunc = instr.getEnclosingIRFunction() |
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
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())
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result = TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
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())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -97,14 +97,7 @@ newtype TInstructionTag =
|
||||
exists(Stmt s | exists(s.getImplicitDestructorCall(index)))
|
||||
} or
|
||||
CoAwaitBranchTag() or
|
||||
BoolToIntConversionTag() or
|
||||
SizeofVlaBaseSizeTag() or
|
||||
SizeofVlaConversionTag(int index) {
|
||||
exists(VlaDeclStmt v | exists(v.getTransitiveVlaDimensionStmt(index)))
|
||||
} or
|
||||
SizeofVlaDimensionTag(int index) {
|
||||
exists(VlaDeclStmt v | exists(v.getTransitiveVlaDimensionStmt(index)))
|
||||
}
|
||||
BoolToIntConversionTag()
|
||||
|
||||
class InstructionTag extends TInstructionTag {
|
||||
final string toString() { result = getInstructionTagId(this) }
|
||||
|
||||
@@ -123,16 +123,13 @@ private predicate ignoreExprAndDescendants(Expr expr) {
|
||||
// or
|
||||
ignoreExprAndDescendants(getRealParent(expr)) // recursive case
|
||||
or
|
||||
// va_start does not evaluate its argument, so we do not need to translate it.
|
||||
// va_start doesn't evaluate its argument, so we don't need to translate it.
|
||||
exists(BuiltInVarArgsStart vaStartExpr |
|
||||
vaStartExpr.getLastNamedParameter().getFullyConverted() = expr
|
||||
)
|
||||
or
|
||||
// sizeof does not evaluate its argument, so we do not need to translate it.
|
||||
exists(SizeofExprOperator sizeofExpr | sizeofExpr.getExprOperand().getFullyConverted() = expr)
|
||||
or
|
||||
// The children of C11 _Generic expressions are just surface syntax.
|
||||
exists(C11GenericExpr generic | generic.getAChild().getFullyConverted() = expr)
|
||||
exists(C11GenericExpr generic | generic.getAChild() = expr)
|
||||
or
|
||||
// Do not translate implicit destructor calls for unnamed temporary variables that are
|
||||
// conditionally constructed (until we have a mechanism for calling these only when the
|
||||
|
||||
@@ -187,7 +187,7 @@ Variable getEnclosingVariable(Expr e) {
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of the "core" part of an expression. This is the part of
|
||||
* The IR translation of the "core" part of an expression. This is the part of
|
||||
* the expression that produces the result value of the expression, before any
|
||||
* lvalue-to-rvalue conversion on the result. Every expression has a single
|
||||
* `TranslatedCoreExpr`.
|
||||
@@ -4094,155 +4094,6 @@ class TranslatedStmtExpr extends TranslatedNonConstantExpr {
|
||||
TranslatedStmt getStmt() { result = getTranslatedStmt(expr.getStmt()) }
|
||||
}
|
||||
|
||||
private VlaDeclStmt getVlaDeclStmt(Expr expr, int pointerDerefCount) {
|
||||
expr.(VariableAccess).getTarget() = result.getVariable() and
|
||||
pointerDerefCount = 0
|
||||
or
|
||||
not expr.(PointerDereferenceExpr).getOperand() instanceof AddressOfExpr and
|
||||
result = getVlaDeclStmt(expr.(PointerDereferenceExpr).getOperand(), pointerDerefCount - 1)
|
||||
or
|
||||
// Skip sequences of the form `*&...`
|
||||
result =
|
||||
getVlaDeclStmt(expr.(PointerDereferenceExpr).getOperand().(AddressOfExpr).getOperand(),
|
||||
pointerDerefCount)
|
||||
or
|
||||
result = getVlaDeclStmt(expr.(ArrayExpr).getArrayBase(), pointerDerefCount - 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of `SizeofExprOperator` when its result is non-constant, i.e.,
|
||||
* when the operand expression refers to a variable length array.
|
||||
*/
|
||||
class TranslatedSizeofExpr extends TranslatedNonConstantExpr {
|
||||
override SizeofExprOperator expr;
|
||||
VlaDeclStmt vlaDeclStmt;
|
||||
int vlaDimensions;
|
||||
int pointerDerefCount;
|
||||
|
||||
TranslatedSizeofExpr() {
|
||||
vlaDeclStmt = getVlaDeclStmt(expr.getExprOperand(), pointerDerefCount) and
|
||||
vlaDimensions = vlaDeclStmt.getTransitiveNumberOfVlaDimensionStmts() and
|
||||
pointerDerefCount < vlaDimensions
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
result = this.getInstruction(SizeofVlaBaseSizeTag()) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getALastInstructionInternal() {
|
||||
result = this.getInstruction(SizeofVlaDimensionTag(vlaDimensions - 1))
|
||||
}
|
||||
|
||||
final override TranslatedElement getChildInternal(int id) { none() }
|
||||
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
opcode instanceof Opcode::Constant and
|
||||
tag = SizeofVlaBaseSizeTag() and
|
||||
resultType = this.getResultType()
|
||||
or
|
||||
exists(int n, Type dimType |
|
||||
pointerDerefCount <= n and
|
||||
n < vlaDimensions and
|
||||
dimType = this.getDimensionExpr(n).getUnderlyingType() and
|
||||
tag = SizeofVlaConversionTag(n)
|
||||
|
|
||||
(
|
||||
expr.getUnderlyingType() = dimType and
|
||||
opcode instanceof Opcode::CopyValue
|
||||
or
|
||||
not expr.getUnderlyingType() = dimType and
|
||||
opcode instanceof Opcode::Convert
|
||||
)
|
||||
) and
|
||||
resultType = this.getResultType()
|
||||
or
|
||||
opcode instanceof Opcode::Mul and
|
||||
exists(int n | pointerDerefCount <= n and n < vlaDimensions | tag = SizeofVlaDimensionTag(n)) and
|
||||
resultType = this.getResultType()
|
||||
}
|
||||
|
||||
final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
|
||||
tag = SizeofVlaBaseSizeTag() and
|
||||
result = this.getInstruction(SizeofVlaConversionTag(pointerDerefCount)) and
|
||||
kind instanceof GotoEdge
|
||||
or
|
||||
exists(int n | pointerDerefCount <= n and n < vlaDimensions |
|
||||
tag = SizeofVlaConversionTag(n) and
|
||||
result = this.getInstruction(SizeofVlaDimensionTag(n))
|
||||
) and
|
||||
kind instanceof GotoEdge
|
||||
or
|
||||
exists(int n | pointerDerefCount <= n and n < vlaDimensions - 1 |
|
||||
tag = SizeofVlaDimensionTag(n) and
|
||||
result = this.getInstruction(SizeofVlaConversionTag(n + 1))
|
||||
) and
|
||||
kind instanceof GotoEdge
|
||||
or
|
||||
tag = SizeofVlaDimensionTag(vlaDimensions - 1) and
|
||||
result = this.getParent().getChildSuccessor(this, kind)
|
||||
}
|
||||
|
||||
override string getInstructionConstantValue(InstructionTag tag) {
|
||||
tag = SizeofVlaBaseSizeTag() and
|
||||
result = this.getBaseType(vlaDeclStmt).getSize().toString()
|
||||
}
|
||||
|
||||
private Type getBaseType(VlaDeclStmt v) {
|
||||
not exists(v.getParentVlaDecl()) and
|
||||
(
|
||||
result =
|
||||
this.getBaseType(v.getVariable().getUnderlyingType(), v.getNumberOfVlaDimensionStmts())
|
||||
or
|
||||
result = this.getBaseType(v.getType().getUnderlyingType(), v.getNumberOfVlaDimensionStmts())
|
||||
)
|
||||
or
|
||||
result = this.getBaseType(v.getParentVlaDecl())
|
||||
}
|
||||
|
||||
private Type getBaseType(Type type, int n) {
|
||||
n = 0 and
|
||||
result = type
|
||||
or
|
||||
result = this.getBaseType(type.(DerivedType).getBaseType(), n - 1)
|
||||
}
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
exists(int n | pointerDerefCount <= n and n < vlaDimensions |
|
||||
tag = SizeofVlaConversionTag(n) and
|
||||
(
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getTranslatedExpr(this.getDimensionExpr(n)).getResult()
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(int n | pointerDerefCount <= n and n < vlaDimensions |
|
||||
tag = SizeofVlaDimensionTag(n) and
|
||||
(
|
||||
operandTag instanceof LeftOperandTag and
|
||||
(
|
||||
n - 1 >= pointerDerefCount and
|
||||
result = this.getInstruction(SizeofVlaDimensionTag(n - 1))
|
||||
or
|
||||
n - 1 < pointerDerefCount and
|
||||
result = this.getInstruction(SizeofVlaBaseSizeTag())
|
||||
)
|
||||
or
|
||||
operandTag instanceof RightOperandTag and
|
||||
result = this.getInstruction(SizeofVlaConversionTag(n))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private Expr getDimensionExpr(int n) {
|
||||
result = vlaDeclStmt.getTransitiveVlaDimensionStmt(n).getDimensionExpr().getFullyConverted()
|
||||
}
|
||||
|
||||
final override Instruction getResult() {
|
||||
result = this.getInstruction(SizeofVlaDimensionTag(vlaDimensions - 1))
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedErrorExpr extends TranslatedSingleInstructionExpr {
|
||||
override ErrorExpr expr;
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ CppType getEllipsisVariablePRValueType() {
|
||||
CppType getEllipsisVariableGLValueType() { result = getTypeForGLValue(any(UnknownType t)) }
|
||||
|
||||
/**
|
||||
* Holds if the function `func` returns a value, as opposed to returning `void`.
|
||||
* Holds if the function returns a value, as opposed to returning `void`.
|
||||
*/
|
||||
predicate hasReturnValue(Function func) { not func.getUnspecifiedType() instanceof VoidType }
|
||||
|
||||
|
||||
@@ -601,7 +601,7 @@ class TranslatedReturnVoidStmt extends TranslatedReturnStmt {
|
||||
* The IR translation of an implicit `return` statement generated by the extractor to handle control
|
||||
* flow that reaches the end of a non-`void`-returning function body. Such control flow
|
||||
* produces undefined behavior in C++ but not in C. However even in C using the return value is
|
||||
* undefined behavior. We make it return uninitialized memory to get as much flow as possible.
|
||||
* undefined behaviour. We make it return uninitialized memory to get as much flow as possible.
|
||||
*/
|
||||
class TranslatedNoValueReturnStmt extends TranslatedReturnStmt, TranslatedVariableInitialization {
|
||||
TranslatedNoValueReturnStmt() {
|
||||
|
||||
@@ -265,10 +265,10 @@ private predicate isEntryBlock(TIRBlock block) {
|
||||
}
|
||||
|
||||
module IRCfg implements BB::CfgSig<Language::Location> {
|
||||
private import codeql.controlflow.SuccessorType
|
||||
|
||||
class ControlFlowNode = Instruction;
|
||||
|
||||
class SuccessorType = EdgeKind;
|
||||
|
||||
final private class FinalIRBlock = IRBlock;
|
||||
|
||||
class BasicBlock extends FinalIRBlock {
|
||||
@@ -280,12 +280,7 @@ module IRCfg implements BB::CfgSig<Language::Location> {
|
||||
|
||||
BasicBlock getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
BasicBlock getASuccessor(SuccessorType t) {
|
||||
exists(EdgeKind k |
|
||||
result = super.getSuccessor(k) and
|
||||
t = getAMatchingSuccessorType(k)
|
||||
)
|
||||
}
|
||||
BasicBlock getASuccessor(SuccessorType t) { result = super.getSuccessor(t) }
|
||||
|
||||
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ newtype TValueNumber =
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(Instruction instr) { uniqueValueNumber(instr) }
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
@@ -129,14 +129,12 @@ private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
count(instr.(InheritanceConversionInstruction).getBaseClass()) != 1 or
|
||||
count(instr.(InheritanceConversionInstruction).getDerivedClass()) != 1
|
||||
)
|
||||
or
|
||||
count(instr.getEnclosingIRFunction()) != 1
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -146,7 +144,7 @@ private predicate variableAddressValueNumber(
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -156,7 +154,7 @@ private predicate initializeParameterValueNumber(
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getResultIRType()) = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
@@ -164,7 +162,7 @@ private predicate constantValueNumber(
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
@@ -173,7 +171,7 @@ private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field,
|
||||
TValueNumber objectAddress
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getField()) = field and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
@@ -184,7 +182,7 @@ private predicate binaryValueNumber0(
|
||||
TValueNumber valueNumber
|
||||
) {
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
(
|
||||
isLeft = true and
|
||||
@@ -208,7 +206,7 @@ private predicate pointerArithmeticValueNumber0(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
boolean isLeft, TValueNumber valueNumber
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getElementSize() = elementSize and
|
||||
(
|
||||
@@ -231,7 +229,7 @@ private predicate pointerArithmeticValueNumber(
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
@@ -244,7 +242,7 @@ private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand and
|
||||
unique( | | instr.getBaseClass()) = baseClass and
|
||||
@@ -256,7 +254,7 @@ private predicate loadTotalOverlapValueNumber0(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber valueNumber,
|
||||
boolean isAddress
|
||||
) {
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
(
|
||||
isAddress = true and
|
||||
@@ -279,7 +277,8 @@ private predicate loadTotalOverlapValueNumber(
|
||||
* Holds if `instr` should be assigned a unique value number because this library does not know how
|
||||
* to determine if two instances of that instruction are equivalent.
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr) {
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
(
|
||||
not numberableInstruction(instr)
|
||||
@@ -295,8 +294,10 @@ cached
|
||||
TValueNumber tvalueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
uniqueValueNumber(instr) and
|
||||
result = TUniqueValueNumber(instr)
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,64 +311,68 @@ TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef
|
||||
* value number.
|
||||
*/
|
||||
private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc | irFunc = instr.getEnclosingIRFunction() |
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
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())
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result = TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
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())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -49,8 +49,7 @@ Type getVariableType(Variable v) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the database contains a `switchCase` label with the specified minimum `minValue`
|
||||
* and maximum `maxValue` value.
|
||||
* Holds if the database contains a `case` label with the specified minimum and maximum value.
|
||||
*/
|
||||
predicate hasCaseEdge(SwitchCase switchCase, string minValue, string maxValue) {
|
||||
minValue = switchCase.getExpr().getFullyConverted().getValue() and
|
||||
|
||||
@@ -371,7 +371,7 @@ class FunctionOutput extends TFunctionOutput {
|
||||
/**
|
||||
* Holds if this is the output value pointed to by a pointer parameter to a function, or the
|
||||
* output value referred to by a reference parameter to a function, where the parameter has
|
||||
* index `i`.
|
||||
* index `index`.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
@@ -389,7 +389,7 @@ class FunctionOutput extends TFunctionOutput {
|
||||
/**
|
||||
* Holds if this is the output value pointed to by a pointer parameter (through `ind` number
|
||||
* of indirections) to a function, or the output value referred to by a reference parameter to
|
||||
* a function, where the parameter has index `i`.
|
||||
* a function, where the parameter has index `index`.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
|
||||
@@ -307,12 +307,13 @@ class SemStoreExpr extends SemUnaryExpr {
|
||||
}
|
||||
|
||||
class SemConditionalExpr extends SemKnownExpr {
|
||||
SemExpr condition;
|
||||
SemExpr trueResult;
|
||||
SemExpr falseResult;
|
||||
|
||||
SemConditionalExpr() {
|
||||
opcode instanceof Opcode::Conditional and
|
||||
Specific::conditionalExpr(this, type, any(SemExpr condition), trueResult, falseResult)
|
||||
Specific::conditionalExpr(this, type, condition, trueResult, falseResult)
|
||||
}
|
||||
|
||||
final SemExpr getBranchExpr(boolean branch) {
|
||||
|
||||
@@ -21,9 +21,7 @@ class FileWrite extends Expr {
|
||||
Expr getDest() { fileWrite(this, _, result) }
|
||||
|
||||
/**
|
||||
* Gets the conversion character from `source` for this write, if it exists and is known.
|
||||
* For example in the following code the write of `value1` has conversion character `"s"`, whereas
|
||||
* the write of `value2` has no conversion specifier.
|
||||
* Gets the conversion character for this write, if it exists and is known. For example in the following code the write of `value1` has conversion character `"s"`, whereas the write of `value2` has no conversion specifier.
|
||||
* ```
|
||||
* fprintf(file, "%s", value1);
|
||||
* stream << value2;
|
||||
|
||||
@@ -191,19 +191,11 @@ module BoostorgAsio {
|
||||
class SslContextClass extends Class {
|
||||
SslContextClass() { this.getQualifiedName() = "boost::asio::ssl::context" }
|
||||
|
||||
/**
|
||||
* Gets a constructor call, if any.
|
||||
*/
|
||||
ConstructorCall getAConstructorCall() {
|
||||
ConstructorCall getAContructorCall() {
|
||||
this.getAConstructor().getACallToThisFunction() = result and
|
||||
not result.getLocation().getFile().toString().matches("%/boost/asio/%") and
|
||||
result.fromSource()
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getAConstructorCall` instead.
|
||||
*/
|
||||
deprecated ConstructorCall getAContructorCall() { result = this.getAConstructorCall() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -376,7 +368,7 @@ module BoostorgAsio {
|
||||
*/
|
||||
default predicate isSink(DataFlow::Node sink) {
|
||||
exists(ConstructorCall cc, SslContextClass c, Expr e | e = sink.asExpr() |
|
||||
c.getAConstructorCall() = cc and
|
||||
c.getAContructorCall() = cc and
|
||||
cc.getArgument(0) = e
|
||||
)
|
||||
}
|
||||
@@ -476,7 +468,7 @@ module BoostorgAsio {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(SslContextClass c, ConstructorCall cc |
|
||||
cc = source.asExpr() and
|
||||
c.getAConstructorCall() = cc
|
||||
c.getAContructorCall() = cc
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -2355,20 +2355,6 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of VLA dimension statements in this VLA declaration
|
||||
* statement and transitively of the VLA declaration used to define its
|
||||
* base type. if any.
|
||||
*/
|
||||
int getTransitiveNumberOfVlaDimensionStmts() {
|
||||
not exists(this.getParentVlaDecl()) and
|
||||
result = this.getNumberOfVlaDimensionStmts()
|
||||
or
|
||||
result =
|
||||
this.getNumberOfVlaDimensionStmts() +
|
||||
this.getParentVlaDecl().getTransitiveNumberOfVlaDimensionStmts()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `i`th VLA dimension statement in this VLA
|
||||
* declaration statement.
|
||||
@@ -2381,19 +2367,6 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `i`th VLA dimension statement in this VLA declaration
|
||||
* statement or transitively of the VLA declaration used to define
|
||||
* its base type.
|
||||
*/
|
||||
VlaDimensionStmt getTransitiveVlaDimensionStmt(int i) {
|
||||
i < this.getNumberOfVlaDimensionStmts() and
|
||||
result = this.getVlaDimensionStmt(i)
|
||||
or
|
||||
result =
|
||||
this.getParentVlaDecl().getTransitiveVlaDimensionStmt(i - this.getNumberOfVlaDimensionStmts())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type that this VLA declaration statement relates to,
|
||||
* if any.
|
||||
@@ -2405,31 +2378,4 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl {
|
||||
* if any.
|
||||
*/
|
||||
Variable getVariable() { variable_vla(unresolveElement(result), underlyingElement(this)) }
|
||||
|
||||
/**
|
||||
* Get the VLA declaration used to define the base type of
|
||||
* this VLA declaration, if any.
|
||||
*/
|
||||
VlaDeclStmt getParentVlaDecl() {
|
||||
exists(Variable v, Type baseType |
|
||||
v = this.getVariable() and
|
||||
baseType = this.getBaseType(v.getType(), this.getNumberOfVlaDimensionStmts())
|
||||
|
|
||||
result.getType() = baseType
|
||||
)
|
||||
or
|
||||
exists(Type t, Type baseType |
|
||||
t = this.getType().(TypedefType).getBaseType() and
|
||||
baseType = this.getBaseType(t, this.getNumberOfVlaDimensionStmts())
|
||||
|
|
||||
result.getType() = baseType
|
||||
)
|
||||
}
|
||||
|
||||
private Type getBaseType(Type type, int n) {
|
||||
n = 0 and
|
||||
result = type
|
||||
or
|
||||
result = this.getBaseType(type.(DerivedType).getBaseType(), n - 1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,17 +164,12 @@ predicate valueOccurrenceCount(string value, int n) {
|
||||
n > 20
|
||||
}
|
||||
|
||||
predicate occurrenceCount(Literal lit, string value, int n) {
|
||||
predicate occurenceCount(Literal lit, string value, int n) {
|
||||
valueOccurrenceCount(value, n) and
|
||||
value = lit.getValue() and
|
||||
nonTrivialValue(_, lit)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `occurrenceCount` instead.
|
||||
*/
|
||||
deprecated predicate occurenceCount = occurrenceCount/3;
|
||||
|
||||
/*
|
||||
* Literals repeated frequently
|
||||
*/
|
||||
@@ -183,7 +178,7 @@ predicate check(Literal lit, string value, int n, File f) {
|
||||
// Check that the literal is nontrivial
|
||||
not trivial(lit) and
|
||||
// Check that it is repeated a number of times
|
||||
occurrenceCount(lit, value, n) and
|
||||
occurenceCount(lit, value, n) and
|
||||
n > 20 and
|
||||
f = lit.getFile() and
|
||||
// Exclude generated files
|
||||
|
||||
@@ -1,21 +1,3 @@
|
||||
## 1.5.0
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* The queries `cpp/wrong-type-format-argument`, `cpp/comparison-with-wider-type`, `cpp/integer-multiplication-cast-to-long`, `cpp/implicit-function-declaration` and `cpp/suspicious-add-sizeof` have had their precisions reduced from `high` to `medium`. They will also now give alerts for projects built with `build-mode: none`.
|
||||
* The queries `cpp/wrong-type-format-argument`, `cpp/comparison-with-wider-type`, `cpp/integer-multiplication-cast-to-long` and `cpp/suspicious-add-sizeof` are no longer included in the `code-scanning` suite.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* The predicate `occurenceCount` in the file module `MagicConstants` has been deprecated. Use `occurrenceCount` instead.
|
||||
* The predicate `additionalAdditionOrSubstractionCheckForLeapYear` in the file module `LeapYear` has been deprecated. Use `additionalAdditionOrSubtractionCheckForLeapYear` instead.
|
||||
|
||||
## 1.4.7
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed an inconsistency across languages where most have a `Customizations.qll` file for adding customizations, but not all did.
|
||||
|
||||
## 1.4.6
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -4,9 +4,13 @@ private import semmle.code.cpp.controlflow.IRGuards
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
|
||||
private predicate exprInBooleanContext(Expr e) {
|
||||
exists(IRGuardCondition gc, Instruction i |
|
||||
i.getUnconvertedResultExpression() = e and
|
||||
gc.comparesEq(valueNumber(i).getAUse(), 0, _, _)
|
||||
exists(IRGuardCondition gc |
|
||||
exists(Instruction i |
|
||||
i.getUnconvertedResultExpression() = e and
|
||||
gc.comparesEq(valueNumber(i).getAUse(), 0, _, _)
|
||||
)
|
||||
or
|
||||
gc.getUnconvertedResultExpression() = e
|
||||
)
|
||||
}
|
||||
|
||||
@@ -32,18 +36,20 @@ private string getEofValue() {
|
||||
* Holds if the value of `call` has been checked to not equal `EOF`.
|
||||
*/
|
||||
private predicate checkedForEof(ScanfFunctionCall call) {
|
||||
exists(IRGuardCondition gc, CallInstruction i | i.getUnconvertedResultExpression() = call |
|
||||
exists(int val | gc.comparesEq(valueNumber(i).getAUse(), val, _, _) |
|
||||
// call == EOF
|
||||
val = getEofValue().toInt()
|
||||
exists(IRGuardCondition gc |
|
||||
exists(CallInstruction i | i.getUnconvertedResultExpression() = call |
|
||||
exists(int val | gc.comparesEq(valueNumber(i).getAUse(), val, _, _) |
|
||||
// call == EOF
|
||||
val = getEofValue().toInt()
|
||||
or
|
||||
// call == [any positive number]
|
||||
val > 0
|
||||
)
|
||||
or
|
||||
// call == [any positive number]
|
||||
val > 0
|
||||
)
|
||||
or
|
||||
exists(int val | gc.comparesLt(valueNumber(i).getAUse(), val, true, _) |
|
||||
// call < [any non-negative number] (EOF is guaranteed to be negative)
|
||||
val >= 0
|
||||
exists(int val | gc.comparesLt(valueNumber(i).getAUse(), val, true, _) |
|
||||
// call < [any non-negative number] (EOF is guaranteed to be negative)
|
||||
val >= 0
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 8.1
|
||||
* @precision medium
|
||||
* @precision high
|
||||
* @id cpp/integer-multiplication-cast-to-long
|
||||
* @tags reliability
|
||||
* security
|
||||
@@ -179,6 +179,7 @@ predicate overflows(MulExpr me, Type t) {
|
||||
|
||||
from MulExpr me, Type t1, Type t2
|
||||
where
|
||||
not any(Compilation c).buildModeNone() and
|
||||
t1 = me.getType().getUnderlyingType() and
|
||||
t2 = me.getConversion().getType().getUnderlyingType() and
|
||||
t1.getSize() < t2.getSize() and
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @security-severity 7.5
|
||||
* @precision medium
|
||||
* @precision high
|
||||
* @id cpp/wrong-type-format-argument
|
||||
* @tags reliability
|
||||
* correctness
|
||||
@@ -154,6 +154,7 @@ int sizeof_IntType() { exists(IntType it | result = it.getSize()) }
|
||||
|
||||
from FormattingFunctionCall ffc, int n, Expr arg, Type expected, Type actual
|
||||
where
|
||||
not any(Compilation c).buildModeNone() and
|
||||
(
|
||||
formattingFunctionCallExpectedType(ffc, n, expected) and
|
||||
formattingFunctionCallActualType(ffc, n, arg, actual) and
|
||||
|
||||
@@ -128,18 +128,11 @@ abstract class LeapYearFieldAccess extends YearFieldAccess {
|
||||
/**
|
||||
* Holds if the top-level binary operation includes an addition or subtraction operator with an operand specified by `valueToCheck`.
|
||||
*/
|
||||
predicate additionalAdditionOrSubtractionCheckForLeapYear(int valueToCheck) {
|
||||
predicate additionalAdditionOrSubstractionCheckForLeapYear(int valueToCheck) {
|
||||
additionalLogicalCheck(this, "+", valueToCheck) or
|
||||
additionalLogicalCheck(this, "-", valueToCheck)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `additionalAdditionOrSubtractionCheckForLeapYear` instead.
|
||||
*/
|
||||
deprecated predicate additionalAdditionOrSubstractionCheckForLeapYear(int valueToCheck) {
|
||||
this.additionalAdditionOrSubtractionCheckForLeapYear(valueToCheck)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this object is used on a modulus 4 operation, which would likely indicate the start of a leap year check.
|
||||
*/
|
||||
@@ -187,13 +180,13 @@ class StructTmLeapYearFieldAccess extends LeapYearFieldAccess {
|
||||
this.additionalModulusCheckForLeapYear(100) and
|
||||
// tm_year represents years since 1900
|
||||
(
|
||||
this.additionalAdditionOrSubtractionCheckForLeapYear(1900)
|
||||
this.additionalAdditionOrSubstractionCheckForLeapYear(1900)
|
||||
or
|
||||
// some systems may use 2000 for 2-digit year conversions
|
||||
this.additionalAdditionOrSubtractionCheckForLeapYear(2000)
|
||||
this.additionalAdditionOrSubstractionCheckForLeapYear(2000)
|
||||
or
|
||||
// converting from/to Unix epoch
|
||||
this.additionalAdditionOrSubtractionCheckForLeapYear(1970)
|
||||
this.additionalAdditionOrSubstractionCheckForLeapYear(1970)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import cpp
|
||||
import semmle.code.cpp.security.boostorg.asio.protocols
|
||||
|
||||
predicate isSourceImpl(DataFlow::Node source, ConstructorCall cc) {
|
||||
exists(BoostorgAsio::SslContextClass c | c.getAConstructorCall() = cc and cc = source.asExpr())
|
||||
exists(BoostorgAsio::SslContextClass c | c.getAContructorCall() = cc and cc = source.asExpr())
|
||||
}
|
||||
|
||||
predicate isSinkImpl(DataFlow::Node sink, FunctionCall fcSetOptions) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* may lead to unpredictable behavior.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @precision high
|
||||
* @id cpp/implicit-function-declaration
|
||||
* @tags correctness
|
||||
* maintainability
|
||||
@@ -38,6 +38,7 @@ predicate isCompiledAsC(File f) {
|
||||
|
||||
from FunctionDeclarationEntry fdeIm, FunctionCall fc
|
||||
where
|
||||
not any(Compilation c).buildModeNone() and
|
||||
isCompiledAsC(fdeIm.getFile()) and
|
||||
not isFromMacroDefinition(fc) and
|
||||
fdeIm.isImplicit() and
|
||||
|
||||
@@ -20,14 +20,12 @@ class RangeFunction extends Function {
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
super.getLocation().hasLocationInfo(path, sl, sc, _, _) and
|
||||
(
|
||||
this.getBlock().getLocation().hasLocationInfo(filepath, _, _, endline, endcolumn)
|
||||
this.getBlock().getLocation().hasLocationInfo(path, _, _, el, ec)
|
||||
or
|
||||
not exists(this.getBlock()) and endline = startline + 1 and endcolumn = 1
|
||||
not exists(this.getBlock()) and el = sl + 1 and ec = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ predicate lessThanOrEqual(IRGuardCondition g, Expr e, boolean branch) {
|
||||
g.comparesEq(left, _, _, true, branch)
|
||||
|
|
||||
interestingLessThanOrEqual(left) and
|
||||
left.getDef().getConvertedResultExpression() = e
|
||||
left.getDef().getUnconvertedResultExpression() = e
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 7.8
|
||||
* @precision medium
|
||||
* @precision high
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-190
|
||||
@@ -51,6 +51,7 @@ int getComparisonSizeAdjustment(Expr e) {
|
||||
|
||||
from Loop l, RelationalOperation rel, VariableAccess small, Expr large
|
||||
where
|
||||
not any(Compilation c).buildModeNone() and
|
||||
small = rel.getLesserOperand() and
|
||||
large = rel.getGreaterOperand() and
|
||||
rel = l.getCondition().getAChild*() and
|
||||
|
||||
@@ -25,10 +25,10 @@ import semmle.code.cpp.controlflow.IRGuards as IRGuards
|
||||
predicate outOfBoundsExpr(Expr expr, string kind) {
|
||||
if convertedExprMightOverflowPositively(expr)
|
||||
then kind = "overflow"
|
||||
else (
|
||||
convertedExprMightOverflowNegatively(expr) and
|
||||
kind = "overflow negatively"
|
||||
)
|
||||
else
|
||||
if convertedExprMightOverflowNegatively(expr)
|
||||
then kind = "overflow negatively"
|
||||
else none()
|
||||
}
|
||||
|
||||
predicate isSource(FS::FlowSource source, string sourceType) { sourceType = source.getSourceType() }
|
||||
|
||||
@@ -55,9 +55,30 @@ predicate resultIsChecked(SslGetPeerCertificateCall getCertCall, ControlFlowNode
|
||||
predicate certIsZero(
|
||||
SslGetPeerCertificateCall getCertCall, ControlFlowNode node1, ControlFlowNode node2
|
||||
) {
|
||||
exists(Expr cert |
|
||||
cert = globalValueNumber(getCertCall).getAnExpr() and
|
||||
node1.(GuardCondition).ensuresEqEdge(cert, 0, _, node2.getBasicBlock(), true)
|
||||
exists(Expr cert | cert = globalValueNumber(getCertCall).getAnExpr() |
|
||||
exists(GuardCondition guard, Expr zero |
|
||||
zero.getValue().toInt() = 0 and
|
||||
node1 = guard and
|
||||
(
|
||||
// if (cert == zero) {
|
||||
guard.comparesEq(cert, zero, 0, true, true) and
|
||||
node2 = guard.getATrueSuccessor()
|
||||
or
|
||||
// if (cert != zero) { }
|
||||
guard.comparesEq(cert, zero, 0, false, true) and
|
||||
node2 = guard.getAFalseSuccessor()
|
||||
)
|
||||
)
|
||||
or
|
||||
(
|
||||
// if (cert) { }
|
||||
node1 = cert
|
||||
or
|
||||
// if (!cert) {
|
||||
node1.(NotExpr).getAChild() = cert
|
||||
) and
|
||||
node2 = node1.getASuccessor() and
|
||||
not cert.(GuardCondition).controls(node2, true) // cert may be false
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -31,28 +31,27 @@ private predicate hasConditionalInitialization(
|
||||
class ConditionallyInitializedVariable extends LocalVariable {
|
||||
ConditionalInitializationCall call;
|
||||
ConditionalInitializationFunction f;
|
||||
VariableAccess initAccess;
|
||||
Evidence e;
|
||||
|
||||
ConditionallyInitializedVariable() {
|
||||
// Find a call that conditionally initializes this variable
|
||||
exists(VariableAccess initAccess |
|
||||
hasConditionalInitialization(f, call, this, initAccess, e) and
|
||||
// Ignore cases where the variable is assigned prior to the call
|
||||
not reaches(this.getAnAssignedValue(), initAccess) and
|
||||
// Ignore cases where the variable is assigned field-wise prior to the call.
|
||||
not exists(FieldAccess fa |
|
||||
exists(Assignment a |
|
||||
fa = getAFieldAccess(this) and
|
||||
a.getLValue() = fa
|
||||
)
|
||||
|
|
||||
reaches(fa, initAccess)
|
||||
) and
|
||||
// Ignore cases where the variable is assigned by a prior call to an initialization function
|
||||
not exists(Call c |
|
||||
this.getAnAccess() = getAnInitializedArgument(c).(AddressOfExpr).getOperand() and
|
||||
reaches(c, initAccess)
|
||||
hasConditionalInitialization(f, call, this, initAccess, e) and
|
||||
// Ignore cases where the variable is assigned prior to the call
|
||||
not reaches(this.getAnAssignedValue(), initAccess) and
|
||||
// Ignore cases where the variable is assigned field-wise prior to the call.
|
||||
not exists(FieldAccess fa |
|
||||
exists(Assignment a |
|
||||
fa = getAFieldAccess(this) and
|
||||
a.getLValue() = fa
|
||||
)
|
||||
|
|
||||
reaches(fa, initAccess)
|
||||
) and
|
||||
// Ignore cases where the variable is assigned by a prior call to an initialization function
|
||||
not exists(Call c |
|
||||
this.getAnAccess() = getAnInitializedArgument(c).(AddressOfExpr).getOperand() and
|
||||
reaches(c, initAccess)
|
||||
) and
|
||||
/*
|
||||
* Static local variables with constant initializers do not have the initializer expr as part of
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 8.8
|
||||
* @precision medium
|
||||
* @precision high
|
||||
* @id cpp/suspicious-add-sizeof
|
||||
* @tags security
|
||||
* external/cwe/cwe-468
|
||||
@@ -24,6 +24,7 @@ private predicate isCharSzPtrExpr(Expr e) {
|
||||
|
||||
from Expr sizeofExpr, Expr e
|
||||
where
|
||||
not any(Compilation c).buildModeNone() and
|
||||
// If we see an addWithSizeof then we expect the type of
|
||||
// the pointer expression to be `char*` or `void*`. Otherwise it
|
||||
// is probably a mistake.
|
||||
|
||||
@@ -41,7 +41,7 @@ predicate deleteMayThrow(DeleteOrDeleteArrayExpr deleteExpr) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the function `f` may throw an exception when called. That is, if the body of the function looks
|
||||
* Holds if the function may throw an exception when called. That is, if the body of the function looks
|
||||
* like it might throw an exception, and the function does not have a `noexcept` or `throw()` specifier.
|
||||
*/
|
||||
predicate functionMayThrow(Function f) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
## 1.4.7
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed an inconsistency across languages where most have a `Customizations.qll` file for adding customizations, but not all did.
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Fixed an inconsistency across languages where most have a `Customizations.qll` file for adding customizations, but not all did.
|
||||
@@ -1,11 +0,0 @@
|
||||
## 1.5.0
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* The queries `cpp/wrong-type-format-argument`, `cpp/comparison-with-wider-type`, `cpp/integer-multiplication-cast-to-long`, `cpp/implicit-function-declaration` and `cpp/suspicious-add-sizeof` have had their precisions reduced from `high` to `medium`. They will also now give alerts for projects built with `build-mode: none`.
|
||||
* The queries `cpp/wrong-type-format-argument`, `cpp/comparison-with-wider-type`, `cpp/integer-multiplication-cast-to-long` and `cpp/suspicious-add-sizeof` are no longer included in the `code-scanning` suite.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* The predicate `occurenceCount` in the file module `MagicConstants` has been deprecated. Use `occurrenceCount` instead.
|
||||
* The predicate `additionalAdditionOrSubstractionCheckForLeapYear` in the file module `LeapYear` has been deprecated. Use `additionalAdditionOrSubtractionCheckForLeapYear` instead.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user