Compare commits

..

1 Commits

Author SHA1 Message Date
Arthur Baars
c3ae3a5770 Update 2025-08-25-loc-option.md 2025-09-01 22:39:13 +02:00
1014 changed files with 19474 additions and 52402 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,10 +0,0 @@
{
"paths": [
".github/workflows/*.yml",
".github/workflows/*.yaml",
".github/reusable_workflows/**/*.yml",
".github/reusable_workflows/**/*.yaml",
"**/action.yml",
"**/action.yaml"
]
}

View File

@@ -1,2 +0,0 @@
@echo off
type "%CODEQL_EXTRACTOR_ACTIONS_ROOT%\tools\baseline-config.json"

View File

@@ -1,3 +0,0 @@
#!/bin/sh
cat "$CODEQL_EXTRACTOR_ACTIONS_ROOT/tools/baseline-config.json"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +0,0 @@
## 0.6.9
### Minor Analysis Improvements
* Actions analysis now reports file coverage information on the CodeQL status page.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

@@ -0,0 +1,5 @@
---
category: feature
---
* Added a new class `PchFile` representing precompiled header (PCH) files used during project compilation.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added flow summaries for the `Microsoft::WRL::ComPtr` member functions.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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:
* ```

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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