Compare commits

..

1 Commits

Author SHA1 Message Date
Alex Eyers-Taylor
59cbfe9e75 Kotlin: Update tests for running on the extractor jdk. 2023-10-26 17:52:25 +01:00
6657 changed files with 178171 additions and 619497 deletions

3
.gitattributes vendored
View File

@@ -71,6 +71,3 @@ go/extractor/opencsv/CSVReader.java -text
# `javascript/ql/experimental/adaptivethreatmodeling/test/update_endpoint_test_files.py`.
javascript/ql/experimental/adaptivethreatmodeling/test/endpoint_large_scale/autogenerated/**/*.js linguist-generated=true -merge
javascript/ql/experimental/adaptivethreatmodeling/test/endpoint_large_scale/autogenerated/**/*.ts linguist-generated=true -merge
# Auto-generated modeling for Python
python/ql/lib/semmle/python/frameworks/data/internal/subclass-capture/*.yml linguist-generated=true

View File

@@ -9,8 +9,6 @@ on:
- "*/ql/lib/**/*.ql"
- "*/ql/lib/**/*.qll"
- "*/ql/lib/**/*.yml"
- "shared/**/*.ql"
- "shared/**/*.qll"
- "!**/experimental/**"
- "!ql/**"
- ".github/workflows/check-change-note.yml"

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
- uses: actions/stale@v8
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Comment or remove the `Stale` label in order to avoid having this issue closed in 7 days.'

View File

@@ -28,9 +28,9 @@ jobs:
steps:
- name: Setup dotnet
uses: actions/setup-dotnet@v4
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.100
dotnet-version: 7.0.102
- name: Checkout repository
uses: actions/checkout@v4

View File

@@ -72,15 +72,15 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Setup dotnet
uses: actions/setup-dotnet@v4
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.100
dotnet-version: 7.0.102
- name: Extractor unit tests
run: |
dotnet test -p:RuntimeFrameworkVersion=8.0.0 extractor/Semmle.Util.Tests
dotnet test -p:RuntimeFrameworkVersion=8.0.0 extractor/Semmle.Extraction.Tests
dotnet test -p:RuntimeFrameworkVersion=8.0.0 autobuilder/Semmle.Autobuild.CSharp.Tests
dotnet test -p:RuntimeFrameworkVersion=8.0.0 "${{ github.workspace }}/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests"
dotnet test -p:RuntimeFrameworkVersion=7.0.2 extractor/Semmle.Util.Tests
dotnet test -p:RuntimeFrameworkVersion=7.0.2 extractor/Semmle.Extraction.Tests
dotnet test -p:RuntimeFrameworkVersion=7.0.2 autobuilder/Semmle.Autobuild.CSharp.Tests
dotnet test -p:RuntimeFrameworkVersion=7.0.2 "${{ github.workspace }}/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests"
shell: bash
stubgentest:
runs-on: ubuntu-latest

View File

@@ -15,7 +15,7 @@ jobs:
runs-on: macos-latest
steps:
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
id: go
@@ -50,7 +50,7 @@ jobs:
runs-on: windows-latest-xl
steps:
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
id: go

View File

@@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest-xl
steps:
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
id: go

View File

@@ -12,7 +12,6 @@ on:
- main
paths:
- "java/ql/src/utils/modelgenerator/**/*.*"
- "misc/scripts/models-as-data/*.*"
- ".github/workflows/mad_modelDiff.yml"
permissions:
@@ -62,9 +61,8 @@ jobs:
DATABASE=$2
cd codeql-$QL_VARIANT
SHORTNAME=`basename $DATABASE`
python java/ql/src/utils/modelgenerator/GenerateFlowModel.py --with-summaries --with-sinks $DATABASE $SHORTNAME/$QL_VARIANT
mkdir -p $MODELS/$SHORTNAME
mv java/ql/lib/ext/generated/$SHORTNAME/$QL_VARIANT $MODELS/$SHORTNAME
python java/ql/src/utils/modelgenerator/GenerateFlowModel.py --with-summaries --with-sinks $DATABASE ${SHORTNAME}.temp.model.yml
mv java/ql/lib/ext/generated/${SHORTNAME}.temp.model.yml $MODELS/${SHORTNAME}Generated_${QL_VARIANT}.model.yml
cd ..
}
@@ -87,16 +85,16 @@ jobs:
set -x
MODELS=`pwd`/tmp-models
ls -1 tmp-models/
for m in $MODELS/*/main/*.model.yml ; do
for m in $MODELS/*_main.model.yml ; do
t="${m/main/"pr"}"
basename=`basename $m`
name="diff_${basename/.model.yml/""}"
name="diff_${basename/_main.model.yml/""}"
(diff -w -u $m $t | diff2html -i stdin -F $MODELS/$name.html) || true
done
- uses: actions/upload-artifact@v3
with:
name: models
path: tmp-models/**/**/*.model.yml
path: tmp-models/*.model.yml
retention-days: 20
- uses: actions/upload-artifact@v3
with:

View File

@@ -8,8 +8,6 @@
/swift/ @github/codeql-swift
/misc/codegen/ @github/codeql-swift
/java/kotlin-extractor/ @github/codeql-kotlin
/java/ql/test-kotlin1/ @github/codeql-kotlin
/java/ql/test-kotlin2/ @github/codeql-kotlin
# ML-powered queries
/javascript/ql/experimental/adaptivethreatmodeling/ @github/codeql-ml-powered-queries-reviewers
@@ -44,4 +42,3 @@ WORKSPACE.bazel @github/codeql-ci-reviewers
# Misc
/misc/scripts/accept-expected-changes-from-ci.py @RasmusWL
/misc/scripts/generate-code-scanning-query-list.py @RasmusWL

View File

@@ -1,12 +1,12 @@
provide:
- "*/ql/src/qlpack.yml"
- "*/ql/lib/qlpack.yml"
- "*/ql/test*/qlpack.yml"
- "*/ql/test/qlpack.yml"
- "*/ql/examples/qlpack.yml"
- "*/ql/consistency-queries/qlpack.yml"
- "*/ql/automodel/src/qlpack.yml"
- "*/ql/automodel/test/qlpack.yml"
- "shared/**/qlpack.yml"
- "shared/*/qlpack.yml"
- "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml"
- "go/ql/config/legacy-support/qlpack.yml"
- "go/build/codeql-extractor-go/codeql-extractor.yml"
@@ -29,7 +29,6 @@ provide:
- "swift/extractor-pack/codeql-extractor.yml"
- "swift/integration-tests/qlpack.yml"
- "ql/extractor-pack/codeql-extractor.yml"
- ".github/codeql/extensions/**/codeql-pack.yml"
versionPolicies:
default:

View File

@@ -53,6 +53,14 @@
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
],
"DataFlow Java/C#/Go/Ruby/Python/Swift Flow Summaries": [
"java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll",
"go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll"
],
"SsaReadPosition Java/C#": [
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
@@ -454,6 +462,23 @@
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll",
"swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll"
],
"TypeTracker": [
"python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll",
"ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll"
],
"SummaryTypeTracker": [
"python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll",
"ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll"
],
"AccessPathSyntax": [
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/AccessPathSyntax.qll",
"go/ql/lib/semmle/go/dataflow/internal/AccessPathSyntax.qll",
"java/ql/lib/semmle/code/java/dataflow/internal/AccessPathSyntax.qll",
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/AccessPathSyntax.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/AccessPathSyntax.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/AccessPathSyntax.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/AccessPathSyntax.qll"
],
"IncompleteUrlSubstringSanitization": [
"javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qll",
"ruby/ql/src/queries/security/cwe-020/IncompleteUrlSubstringSanitization.qll"
@@ -473,6 +498,10 @@
"ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModelsExtensions.qll",
"python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModelsExtensions.qll"
],
"Typo database": [
"javascript/ql/src/Expressions/TypoDatabase.qll",
"ql/ql/src/codeql_ql/style/TypoDatabase.qll"
],
"Swift declarations test file": [
"swift/ql/test/extractor-tests/declarations/declarations.swift",
"swift/ql/test/library-tests/ast/declarations.swift"
@@ -505,4 +534,4 @@
"python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ext.yml",
"python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ext.yml"
]
}
}

View File

@@ -145,9 +145,9 @@ namespace Semmle.Autobuild.Cpp.Tests
bool IBuildActions.IsMacOs() => IsMacOs;
public bool IsRunningOnAppleSilicon { get; set; }
public bool IsArm { get; set; }
bool IBuildActions.IsRunningOnAppleSilicon() => IsRunningOnAppleSilicon;
bool IBuildActions.IsArm() => IsArm;
string IBuildActions.PathCombine(params string[] parts)
{
@@ -326,7 +326,7 @@ namespace Semmle.Autobuild.Cpp.Tests
public void TestCppAutobuilderSuccess()
{
Actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test.sln -DisableParallelProcessing"] = 1;
Actions.RunProcess[@"cmd.exe /C scratch\.nuget\nuget.exe restore C:\Project\test.sln -DisableParallelProcessing"] = 0;
Actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test.sln -DisableParallelProcessing"] = 0;
Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program^ Files^ ^(x86^)\Microsoft^ Visual^ Studio^ 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && msbuild C:\Project\test.sln /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"""] = 0;
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "";
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1;
@@ -337,11 +337,10 @@ namespace Semmle.Autobuild.Cpp.Tests
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = true;
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true;
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true;
Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CPP_SCRATCH_DIR"] = "scratch";
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.slx";
Actions.EnumerateDirectories[@"C:\Project"] = "";
Actions.CreateDirectories.Add(@"scratch\.nuget");
Actions.DownloadFiles.Add(("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", @"scratch\.nuget\nuget.exe"));
Actions.CreateDirectories.Add(@"C:\Project\.nuget");
Actions.DownloadFiles.Add(("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", @"C:\Project\.nuget\nuget.exe"));
var autobuilder = CreateAutoBuilder(true);
var solution = new TestSolution(@"C:\Project\test.sln");

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Nullable>enable</Nullable>
@@ -11,12 +11,12 @@
<ItemGroup>
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
<PackageReference Include="xunit" Version="2.6.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4">
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<AssemblyName>Semmle.Autobuild.Cpp</AssemblyName>
<RootNamespace>Semmle.Autobuild.Cpp</RootNamespace>
<ApplicationIcon />
@@ -17,7 +17,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="17.8.3" />
<PackageReference Include="Microsoft.Build" Version="17.3.2" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,3 +0,0 @@
description: Expose whether a function was prototyped or not
compatibility: backwards
function_prototyped.rel: delete

View File

@@ -1,9 +0,0 @@
class Function extends @function {
string toString() { none() }
}
from Function fun, string name, int kind, int kind_new
where
functions(fun, name, kind) and
if kind = 7 or kind = 8 then kind_new = 0 else kind_new = kind
select fun, name, kind_new

View File

@@ -1,3 +0,0 @@
description: Support more function types
compatibility: full
functions.rel: run functions.qlo

View File

@@ -1,2 +0,0 @@
description: Removed @assignpaddexpr and @assignpsubexpr from @assign_bitwise_expr
compatibility: full

View File

@@ -1,6 +1,5 @@
description: Support C++17 if and switch initializers
compatibility: partial
constexpr_if_initialization.rel: delete
if_initialization.rel: delete
switch_initialization.rel: delete
exprparents.rel: run exprparents.qlo

View File

@@ -1,17 +0,0 @@
class AttributeArg extends @attribute_arg {
string toString() { none() }
}
class Attribute extends @attribute {
string toString() { none() }
}
class Location extends @location_default {
string toString() { none() }
}
from AttributeArg arg, int kind, int kind_new, Attribute attr, int index, Location location
where
attribute_args(arg, kind, attr, index, location) and
if arg instanceof @attribute_arg_expr then kind_new = 0 else kind_new = kind
select arg, kind_new, attr, index, location

View File

@@ -1,4 +0,0 @@
description: Support expression attribute arguments
compatibility: partial
attribute_arg_expr.rel: delete
attribute_args.rel: run attribute_args.qlo

View File

@@ -1,2 +0,0 @@
description: Revert removal of uniqueness constraint on link_targets/2
compatibility: backwards

View File

@@ -1,70 +1,3 @@
## 0.12.4
### Minor Analysis Improvements
* Deleted many deprecated predicates and classes with uppercase `XML`, `SSA`, `SAL`, `SQL`, etc. in their names. Use the PascalCased versions instead.
* Deleted the deprecated `StrcatFunction` class, use `semmle.code.cpp.models.implementations.Strcat.qll` instead.
## 0.12.3
### Deprecated APIs
* The `isUserInput`, `userInputArgument`, and `userInputReturned` predicates from `SecurityOptions` have been deprecated. Use `FlowSource` instead.
### New Features
* `UserDefineLiteral` and `DeductionGuide` classes have been added, representing C++11 user defined literals and C++17 deduction guides.
### Minor Analysis Improvements
* Changed the output of `Node.toString` to better reflect how many indirections a given dataflow node has.
* Added a new predicate `Node.asDefinition` on `DataFlow::Node`s for selecting the dataflow node corresponding to a particular definition.
* The deprecated `DefaultTaintTracking` library has been removed.
* The `Guards` library has been replaced with the API-compatible `IRGuards` implementation, which has better precision in some cases.
### Bug Fixes
* Under certain circumstances a function declaration that is not also a definition could be associated with a `Function` that did not have the definition as a `FunctionDeclarationEntry`. This is now fixed when only one definition exists, and a unique `Function` will exist that has both the declaration and the definition as a `FunctionDeclarationEntry`.
## 0.12.2
No user-facing changes.
## 0.12.1
### New Features
* Added an `isPrototyped` predicate to `Function` that holds when the function has a prototype.
## 0.12.0
### Breaking Changes
* The expressions `AssignPointerAddExpr` and `AssignPointerSubExpr` are no longer subtypes of `AssignBitwiseOperation`.
### Minor Analysis Improvements
* The "Returning stack-allocated memory" (`cpp/return-stack-allocated-memory`) query now also detects returning stack-allocated memory allocated by calls to `alloca`, `strdupa`, and `strndupa`.
* Added models for `strlcpy` and `strlcat`.
* Added models for the `sprintf` variants from the `StrSafe.h` header.
* Added SQL API models for `ODBC`.
* Added taint models for `realloc` and related functions.
## 0.11.0
### Breaking Changes
* The `Container` and `Folder` classes now derive from `ElementBase` instead of `Locatable`, and no longer expose the `getLocation` predicate. Use `getURL` instead.
### New Features
* Added a new class `AdditionalCallTarget` for specifying additional call targets.
### Minor Analysis Improvements
* More field accesses are identified as `ImplicitThisFieldAccess`.
* Added support for new floating-point types in C23 and C++23.
## 0.10.1
### Minor Analysis Improvements

View File

@@ -52,18 +52,17 @@ class Options extends string {
/**
* Holds if a call to this function will never return.
*
* By default, this holds for `exit`, `_exit`, `_Exit`, `abort`,
* `__assert_fail`, `longjmp`, `__builtin_unreachable` and any
* function with a `noreturn` or `__noreturn__` attribute or
* `noreturn` specifier.
* By default, this holds for `exit`, `_exit`, `abort`, `__assert_fail`,
* `longjmp`, `__builtin_unreachable` and any function with a
* `noreturn` attribute or specifier.
*/
predicate exits(Function f) {
f.getAnAttribute().hasName(["noreturn", "__noreturn__"])
f.getAnAttribute().hasName("noreturn")
or
f.getASpecifier().hasName("noreturn")
or
f.hasGlobalOrStdName([
"exit", "_exit", "_Exit", "abort", "__assert_fail", "longjmp", "__builtin_unreachable"
"exit", "_exit", "abort", "__assert_fail", "longjmp", "__builtin_unreachable"
])
or
CustomOptions::exits(f) // old Options.qll

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added support for new floating-point types in C23 and C++23.

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* Added a new class `AdditionalCallTarget` for specifying additional call targets.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* More field accesses are identified as `ImplicitThisFieldAccess`.

View File

@@ -0,0 +1,4 @@
---
category: breaking
---
* The `Container` and `Folder` classes now derive from `ElementBase` instead of `Locatable`, and no longer expose the `getLocation` predicate. Use `getURL` instead.

View File

@@ -1,14 +0,0 @@
## 0.11.0
### Breaking Changes
* The `Container` and `Folder` classes now derive from `ElementBase` instead of `Locatable`, and no longer expose the `getLocation` predicate. Use `getURL` instead.
### New Features
* Added a new class `AdditionalCallTarget` for specifying additional call targets.
### Minor Analysis Improvements
* More field accesses are identified as `ImplicitThisFieldAccess`.
* Added support for new floating-point types in C23 and C++23.

View File

@@ -1,13 +0,0 @@
## 0.12.0
### Breaking Changes
* The expressions `AssignPointerAddExpr` and `AssignPointerSubExpr` are no longer subtypes of `AssignBitwiseOperation`.
### Minor Analysis Improvements
* The "Returning stack-allocated memory" (`cpp/return-stack-allocated-memory`) query now also detects returning stack-allocated memory allocated by calls to `alloca`, `strdupa`, and `strndupa`.
* Added models for `strlcpy` and `strlcat`.
* Added models for the `sprintf` variants from the `StrSafe.h` header.
* Added SQL API models for `ODBC`.
* Added taint models for `realloc` and related functions.

View File

@@ -1,5 +0,0 @@
## 0.12.1
### New Features
* Added an `isPrototyped` predicate to `Function` that holds when the function has a prototype.

View File

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

View File

@@ -1,20 +0,0 @@
## 0.12.3
### Deprecated APIs
* The `isUserInput`, `userInputArgument`, and `userInputReturned` predicates from `SecurityOptions` have been deprecated. Use `FlowSource` instead.
### New Features
* `UserDefineLiteral` and `DeductionGuide` classes have been added, representing C++11 user defined literals and C++17 deduction guides.
### Minor Analysis Improvements
* Changed the output of `Node.toString` to better reflect how many indirections a given dataflow node has.
* Added a new predicate `Node.asDefinition` on `DataFlow::Node`s for selecting the dataflow node corresponding to a particular definition.
* The deprecated `DefaultTaintTracking` library has been removed.
* The `Guards` library has been replaced with the API-compatible `IRGuards` implementation, which has better precision in some cases.
### Bug Fixes
* Under certain circumstances a function declaration that is not also a definition could be associated with a `Function` that did not have the definition as a `FunctionDeclarationEntry`. This is now fixed when only one definition exists, and a unique `Function` will exist that has both the declaration and the definition as a `FunctionDeclarationEntry`.

View File

@@ -1,6 +0,0 @@
## 0.12.4
### Minor Analysis Improvements
* Deleted many deprecated predicates and classes with uppercase `XML`, `SSA`, `SAL`, `SQL`, etc. in their names. Use the PascalCased versions instead.
* Deleted the deprecated `StrcatFunction` class, use `semmle.code.cpp.models.implementations.Strcat.qll` instead.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.12.4
lastReleaseVersion: 0.10.1

View File

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

View File

@@ -380,6 +380,9 @@ class Class extends UserType {
*/
predicate isPod() { is_pod_class(underlyingElement(this)) }
/** DEPRECATED: Alias for isPod */
deprecated predicate isPOD() { this.isPod() }
/**
* Holds if this class, struct or union is a standard-layout class
* [N4140 9(7)]. Also holds for structs in C programs.

View File

@@ -112,16 +112,6 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
*/
predicate isDeleted() { function_deleted(underlyingElement(this)) }
/**
* Holds if this function has a prototyped interface.
*
* Functions generally have a prototyped interface, unless they are
* K&R-style functions either without any forward function declaration,
* or with all the forward declarations omitting the parameters of the
* function.
*/
predicate isPrototyped() { function_prototyped(underlyingElement(this)) }
/**
* Holds if this function is explicitly defaulted with the `= default`
* specifier.
@@ -328,7 +318,6 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
MetricFunction getMetrics() { result = this }
/** Holds if this function calls the function `f`. */
pragma[nomagic]
predicate calls(Function f) { this.calls(f, _) }
/**
@@ -339,6 +328,10 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
exists(FunctionCall call |
call.getEnclosingFunction() = this and call.getTarget() = f and call = l
)
or
exists(DestructorCall call |
call.getEnclosingFunction() = this and call.getTarget() = f and call = l
)
}
/** Holds if this function accesses a function or variable or enumerator `a`. */
@@ -882,17 +875,3 @@ class BuiltInFunction extends Function {
}
private predicate suppressUnusedThis(Function f) { any() }
/**
* A C++ user-defined literal [N4140 13.5.8].
*/
class UserDefinedLiteral extends Function {
UserDefinedLiteral() { functions(underlyingElement(this), _, 7) }
}
/**
* A C++ deduction guide [N4659 17.9].
*/
class DeductionGuide extends Function {
DeductionGuide() { functions(underlyingElement(this), _, 8) }
}

View File

@@ -104,6 +104,9 @@ predicate isPodClass03(Class c) {
)
}
/** DEPRECATED: Alias for isPodClass03 */
deprecated predicate isPODClass03 = isPodClass03/1;
/**
* Holds if `t` is a POD type, according to the rules specified in
* C++03 3.9(10):
@@ -123,3 +126,6 @@ predicate isPodType03(Type t) {
isPodType03(ut.(SpecifiedType).getUnspecifiedType())
)
}
/** DEPRECATED: Alias for isPodType03 */
deprecated predicate isPODType03 = isPodType03/1;

View File

@@ -281,11 +281,6 @@ class AttributeArgument extends Element, @attribute_arg {
attribute_arg_constant(underlyingElement(this), unresolveElement(result))
}
/**
* Gets the value of this argument, if its value is an expression.
*/
Expr getValueExpr() { attribute_arg_expr(underlyingElement(this), unresolveElement(result)) }
/**
* Gets the attribute to which this is an argument.
*/
@@ -313,10 +308,7 @@ class AttributeArgument extends Element, @attribute_arg {
else
if underlyingElement(this) instanceof @attribute_arg_constant_expr
then tail = this.getValueConstant().toString()
else
if underlyingElement(this) instanceof @attribute_arg_expr
then tail = this.getValueExpr().toString()
else tail = this.getValueText()
else tail = this.getValueText()
) and
result = prefix + tail
)

View File

@@ -32,6 +32,9 @@ class XmlLocatable extends @xmllocatable, TXmlLocatable {
string toString() { none() } // overridden in subclasses
}
/** DEPRECATED: Alias for XmlLocatable */
deprecated class XMLLocatable = XmlLocatable;
/**
* An `XmlParent` is either an `XmlElement` or an `XmlFile`,
* both of which can contain other elements.
@@ -92,6 +95,9 @@ class XmlParent extends @xmlparent {
string toString() { result = this.getName() }
}
/** DEPRECATED: Alias for XmlParent */
deprecated class XMLParent = XmlParent;
/** An XML file. */
class XmlFile extends XmlParent, File {
XmlFile() { xmlEncoding(this, _) }
@@ -113,8 +119,14 @@ class XmlFile extends XmlParent, File {
/** Gets a DTD associated with this XML file. */
XmlDtd getADtd() { xmlDTDs(result, _, _, _, this) }
/** DEPRECATED: Alias for getADtd */
deprecated XmlDtd getADTD() { result = this.getADtd() }
}
/** DEPRECATED: Alias for XmlFile */
deprecated class XMLFile = XmlFile;
/**
* An XML document type definition (DTD).
*
@@ -151,6 +163,9 @@ class XmlDtd extends XmlLocatable, @xmldtd {
}
}
/** DEPRECATED: Alias for XmlDtd */
deprecated class XMLDTD = XmlDtd;
/**
* An XML element in an XML file.
*
@@ -206,6 +221,9 @@ class XmlElement extends @xmlelement, XmlParent, XmlLocatable {
override string toString() { result = this.getName() }
}
/** DEPRECATED: Alias for XmlElement */
deprecated class XMLElement = XmlElement;
/**
* An attribute that occurs inside an XML element.
*
@@ -236,6 +254,9 @@ class XmlAttribute extends @xmlattribute, XmlLocatable {
override string toString() { result = this.getName() + "=" + this.getValue() }
}
/** DEPRECATED: Alias for XmlAttribute */
deprecated class XMLAttribute = XmlAttribute;
/**
* A namespace used in an XML file.
*
@@ -252,6 +273,9 @@ class XmlNamespace extends XmlLocatable, @xmlnamespace {
/** Gets the URI of this namespace. */
string getUri() { xmlNs(this, _, result, _) }
/** DEPRECATED: Alias for getUri */
deprecated string getURI() { result = this.getUri() }
/** Holds if this namespace has no prefix. */
predicate isDefault() { this.getPrefix() = "" }
@@ -262,6 +286,9 @@ class XmlNamespace extends XmlLocatable, @xmlnamespace {
}
}
/** DEPRECATED: Alias for XmlNamespace */
deprecated class XMLNamespace = XmlNamespace;
/**
* A comment in an XML file.
*
@@ -282,6 +309,9 @@ class XmlComment extends @xmlcomment, XmlLocatable {
override string toString() { result = this.getText() }
}
/** DEPRECATED: Alias for XmlComment */
deprecated class XMLComment = XmlComment;
/**
* A sequence of characters that occurs between opening and
* closing tags of an XML element, excluding other elements.
@@ -305,3 +335,6 @@ class XmlCharacters extends @xmlcharacters, XmlLocatable {
/** Gets a printable representation of this XML character sequence. */
override string toString() { result = this.getCharacters() }
}
/** DEPRECATED: Alias for XmlCharacters */
deprecated class XMLCharacters = XmlCharacters;

View File

@@ -5,6 +5,9 @@ class NullMacro extends Macro {
NullMacro() { this.getHead() = "NULL" }
}
/** DEPRECATED: Alias for NullMacro */
deprecated class NULLMacro = NullMacro;
/** A use of the NULL macro. */
class NULL extends Literal {
NULL() { exists(NullMacro nm | this = nm.getAnInvocation().getAnExpandedElement()) }

View File

@@ -0,0 +1,22 @@
import cpp
/**
* DEPRECATED: use `semmle.code.cpp.models.implementations.Strcat.qll` instead.
*
* A function that concatenates the string from its second argument
* to the string from its first argument, for example `strcat`.
*/
deprecated class StrcatFunction extends Function {
StrcatFunction() {
this.getName() =
[
"strcat", // strcat(dst, src)
"strncat", // strncat(dst, src, max_amount)
"wcscat", // wcscat(dst, src)
"_mbscat", // _mbscat(dst, src)
"wcsncat", // wcsncat(dst, src, max_amount)
"_mbsncat", // _mbsncat(dst, src, max_amount)
"_mbsncat_l" // _mbsncat_l(dst, src, max_amount, locale)
]
}
}

View File

@@ -1,101 +0,0 @@
/**
* A library for detecting general string concatenations.
*/
import cpp
import semmle.code.cpp.models.implementations.Strcat
import semmle.code.cpp.models.interfaces.FormattingFunction
private import semmle.code.cpp.dataflow.new.DataFlow
/**
* A call that performs a string concatenation. A string can be either a C
* string (i.e., a value of type `char*`), or a C++ string (i.e., a value of
* type `std::string`).
*/
class StringConcatenation extends Call {
StringConcatenation() {
// sprintf-like functions, i.e., concat through formatting
this instanceof FormattingFunctionCall
or
this.getTarget() instanceof StrcatFunction
or
this.getTarget() instanceof StrlcatFunction
or
// operator+ and ostream (<<) concat
exists(Call call, Operator op |
call.getTarget() = op and
op.hasQualifiedName(["std", "bsl"], ["operator+", "operator<<"]) and
op.getType()
.stripType()
.(UserType)
.hasQualifiedName(["std", "bsl"], ["basic_string", "basic_ostream"]) and
this = call
)
}
/**
* Gets an operand of this concatenation (one of the string operands being
* concatenated).
* Will not return out param for sprintf-like functions, but will consider the format string
* to be part of the operands.
*/
Expr getAnOperand() {
// The result is an argument of 'this' (a call)
result = this.getAnArgument() and
// addresses odd behavior with overloaded operators
// i.e., "call to operator+" appearing as an operand
// occurs in cases like `string s = s1 + s2 + s3`, which is represented as
// `string s = (s1.operator+(s2)).operator+(s3);`
// By limiting to non-calls we get the leaf operands (the variables or raw strings)
// also, by not enumerating allowed types (variables and strings) we avoid issues
// with missed corner cases or extensions/changes to CodeQL in the future which might
// invalidate that approach.
not result instanceof Call and
// Limit the result type to string
(
result.getUnderlyingType().stripType().getName() = "char"
or
result
.getType()
.getUnspecifiedType()
.(UserType)
.hasQualifiedName(["std", "bsl"], "basic_string")
) and
// when 'this' is a `FormattingFunctionCall` the result must be the format string argument
// or one of the formatting arguments
(
this instanceof FormattingFunctionCall
implies
(
result = this.(FormattingFunctionCall).getFormat()
or
exists(int n |
result = this.getArgument(n) and
n >= this.(FormattingFunctionCall).getTarget().getFirstFormatArgumentIndex()
)
)
)
}
/**
* Gets the data flow node representing the concatenation result.
*/
DataFlow::Node getResultNode() {
if this.getTarget() instanceof StrcatFunction
then
result.asDefiningArgument() =
this.getArgument(this.getTarget().(StrcatFunction).getParamDest())
or
// Hardcoding it is also the return
result.asExpr() = this.(Call)
else
if this.getTarget() instanceof StrlcatFunction
then (
result.asDefiningArgument() =
this.getArgument(this.getTarget().(StrlcatFunction).getParamDest())
) else
if this instanceof FormattingFunctionCall
then result.asDefiningArgument() = this.(FormattingFunctionCall).getOutputArgument(_)
else result.asExpr() = this.(Call)
}
}

View File

@@ -7,7 +7,371 @@ import cpp
import semmle.code.cpp.controlflow.BasicBlocks
import semmle.code.cpp.controlflow.SSA
import semmle.code.cpp.controlflow.Dominance
import IRGuards
/**
* A Boolean condition that guards one or more basic blocks. This includes
* operands of logical operators but not switch statements.
*/
class GuardCondition extends Expr {
GuardCondition() { is_condition(this) }
/**
* Holds if this condition controls `block`, meaning that `block` is only
* entered if the value of this condition is `testIsTrue`.
*
* Illustration:
*
* ```
* [ (testIsTrue) ]
* [ this ----------------succ ---- controlled ]
* [ | | ]
* [ (testIsFalse) | ------ ... ]
* [ other ]
* ```
*
* The predicate holds if all paths to `controlled` go via the `testIsTrue`
* edge of the control-flow graph. In other words, the `testIsTrue` edge
* must dominate `controlled`. This means that `controlled` must be
* dominated by both `this` and `succ` (the target of the `testIsTrue`
* edge). It also means that any other edge into `succ` must be a back-edge
* from a node which is dominated by `succ`.
*
* The short-circuit boolean operations have slightly surprising behavior
* here: because the operation itself only dominates one branch (due to
* being short-circuited) then it will only control blocks dominated by the
* true (for `&&`) or false (for `||`) branch.
*/
cached
predicate controls(BasicBlock controlled, boolean testIsTrue) {
// This condition must determine the flow of control; that is, this
// node must be a top-level condition.
this.controlsBlock(controlled, testIsTrue)
or
exists(BinaryLogicalOperation binop, GuardCondition lhs, GuardCondition rhs |
this = binop and
lhs = binop.getLeftOperand() and
rhs = binop.getRightOperand() and
lhs.controls(controlled, testIsTrue) and
rhs.controls(controlled, testIsTrue)
)
or
exists(GuardCondition ne, GuardCondition operand |
this = operand and
operand = ne.(NotExpr).getOperand() and
ne.controls(controlled, testIsTrue.booleanNot())
)
}
/** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */
cached
predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
compares_lt(this, left, right, k, isLessThan, testIsTrue)
}
/**
* Holds if (determined by this guard) `left < right + k` must be `isLessThan` in `block`.
* If `isLessThan = false` then this implies `left >= right + k`.
*/
cached
predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) {
exists(boolean testIsTrue |
compares_lt(this, left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue)
)
}
/** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */
cached
predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) {
compares_eq(this, left, right, k, areEqual, testIsTrue)
}
/**
* Holds if (determined by this guard) `left == right + k` must be `areEqual` in `block`.
* If `areEqual = false` then this implies `left != right + k`.
*/
cached
predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) {
exists(boolean testIsTrue |
compares_eq(this, left, right, k, areEqual, testIsTrue) and this.controls(block, testIsTrue)
)
}
/**
* Holds if this condition controls `block`, meaning that `block` is only
* entered if the value of this condition is `testIsTrue`. This helper
* predicate does not necessarily hold for binary logical operations like
* `&&` and `||`. See the detailed explanation on predicate `controls`.
*/
private predicate controlsBlock(BasicBlock controlled, boolean testIsTrue) {
exists(BasicBlock thisblock | thisblock.contains(this) |
exists(BasicBlock succ |
testIsTrue = true and succ = this.getATrueSuccessor()
or
testIsTrue = false and succ = this.getAFalseSuccessor()
|
bbDominates(succ, controlled) and
forall(BasicBlock pred | pred.getASuccessor() = succ |
pred = thisblock or bbDominates(succ, pred) or not reachable(pred)
)
)
)
}
}
private predicate is_condition(Expr guard) {
guard.isCondition()
or
is_condition(guard.(BinaryLogicalOperation).getAnOperand())
or
exists(NotExpr cond | is_condition(cond) and cond.getOperand() = guard)
}
/*
* Simplification of equality expressions:
* Simplify conditions in the source to the canonical form l op r + k.
*/
/**
* Holds if `left == right + k` is `areEqual` given that test is `testIsTrue`.
*
* Beware making mistaken logical implications here relating `areEqual` and `testIsTrue`.
*/
private predicate compares_eq(
Expr test, Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue
) {
/* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */
exists(boolean eq | simple_comparison_eq(test, left, right, k, eq) |
areEqual = true and testIsTrue = eq
or
areEqual = false and testIsTrue = eq.booleanNot()
)
or
logical_comparison_eq(test, left, right, k, areEqual, testIsTrue)
or
/* a == b + k => b == a - k */
exists(int mk | k = -mk | compares_eq(test, right, left, mk, areEqual, testIsTrue))
or
complex_eq(test, left, right, k, areEqual, testIsTrue)
or
/* (x is true => (left == right + k)) => (!x is false => (left == right + k)) */
exists(boolean isFalse | testIsTrue = isFalse.booleanNot() |
compares_eq(test.(NotExpr).getOperand(), left, right, k, areEqual, isFalse)
)
}
/**
* If `test => part` and `part => left == right + k` then `test => left == right + k`.
* Similarly for the case where `test` is false.
*/
private predicate logical_comparison_eq(
BinaryLogicalOperation test, Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue
) {
exists(boolean partIsTrue, Expr part | test.impliesValue(part, partIsTrue, testIsTrue) |
compares_eq(part, left, right, k, areEqual, partIsTrue)
)
}
/** Rearrange various simple comparisons into `left == right + k` form. */
private predicate simple_comparison_eq(
ComparisonOperation cmp, Expr left, Expr right, int k, boolean areEqual
) {
left = cmp.getLeftOperand() and
cmp.getOperator() = "==" and
right = cmp.getRightOperand() and
k = 0 and
areEqual = true
or
left = cmp.getLeftOperand() and
cmp.getOperator() = "!=" and
right = cmp.getRightOperand() and
k = 0 and
areEqual = false
}
private predicate complex_eq(
ComparisonOperation cmp, Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue
) {
sub_eq(cmp, left, right, k, areEqual, testIsTrue)
or
add_eq(cmp, left, right, k, areEqual, testIsTrue)
}
// left - x == right + c => left == right + (c+x)
// left == (right - x) + c => left == right + (c-x)
private predicate sub_eq(
ComparisonOperation cmp, Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue
) {
exists(SubExpr lhs, int c, int x |
compares_eq(cmp, lhs, right, c, areEqual, testIsTrue) and
left = lhs.getLeftOperand() and
x = int_value(lhs.getRightOperand()) and
k = c + x
)
or
exists(SubExpr rhs, int c, int x |
compares_eq(cmp, left, rhs, c, areEqual, testIsTrue) and
right = rhs.getLeftOperand() and
x = int_value(rhs.getRightOperand()) and
k = c - x
)
}
// left + x == right + c => left == right + (c-x)
// left == (right + x) + c => left == right + (c+x)
private predicate add_eq(
ComparisonOperation cmp, Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue
) {
exists(AddExpr lhs, int c, int x |
compares_eq(cmp, lhs, right, c, areEqual, testIsTrue) and
(
left = lhs.getLeftOperand() and x = int_value(lhs.getRightOperand())
or
left = lhs.getRightOperand() and x = int_value(lhs.getLeftOperand())
) and
k = c - x
)
or
exists(AddExpr rhs, int c, int x |
compares_eq(cmp, left, rhs, c, areEqual, testIsTrue) and
(
right = rhs.getLeftOperand() and x = int_value(rhs.getRightOperand())
or
right = rhs.getRightOperand() and x = int_value(rhs.getLeftOperand())
) and
k = c + x
)
}
/*
* Simplification of inequality expressions:
* Simplify conditions in the source to the canonical form l < r + k.
*/
/** Holds if `left < right + k` evaluates to `isLt` given that test is `testIsTrue`. */
private predicate compares_lt(
Expr test, Expr left, Expr right, int k, boolean isLt, boolean testIsTrue
) {
/* In the simple case, the test is the comparison, so isLt = testIsTrue */
simple_comparison_lt(test, left, right, k) and isLt = true and testIsTrue = true
or
simple_comparison_lt(test, left, right, k) and isLt = false and testIsTrue = false
or
logical_comparison_lt(test, left, right, k, isLt, testIsTrue)
or
complex_lt(test, left, right, k, isLt, testIsTrue)
or
/* (not (left < right + k)) => (left >= right + k) */
exists(boolean isGe | isLt = isGe.booleanNot() |
compares_ge(test, left, right, k, isGe, testIsTrue)
)
or
/* (x is true => (left < right + k)) => (!x is false => (left < right + k)) */
exists(boolean isFalse | testIsTrue = isFalse.booleanNot() |
compares_lt(test.(NotExpr).getOperand(), left, right, k, isLt, isFalse)
)
}
/** `(a < b + k) => (b > a - k) => (b >= a + (1-k))` */
private predicate compares_ge(
Expr test, Expr left, Expr right, int k, boolean isGe, boolean testIsTrue
) {
exists(int onemk | k = 1 - onemk | compares_lt(test, right, left, onemk, isGe, testIsTrue))
}
/**
* If `test => part` and `part => left < right + k` then `test => left < right + k`.
* Similarly for the case where `test` evaluates false.
*/
private predicate logical_comparison_lt(
BinaryLogicalOperation test, Expr left, Expr right, int k, boolean isLt, boolean testIsTrue
) {
exists(boolean partIsTrue, Expr part | test.impliesValue(part, partIsTrue, testIsTrue) |
compares_lt(part, left, right, k, isLt, partIsTrue)
)
}
/** Rearrange various simple comparisons into `left < right + k` form. */
private predicate simple_comparison_lt(ComparisonOperation cmp, Expr left, Expr right, int k) {
left = cmp.getLeftOperand() and
cmp.getOperator() = "<" and
right = cmp.getRightOperand() and
k = 0
or
left = cmp.getLeftOperand() and
cmp.getOperator() = "<=" and
right = cmp.getRightOperand() and
k = 1
or
right = cmp.getLeftOperand() and
cmp.getOperator() = ">" and
left = cmp.getRightOperand() and
k = 0
or
right = cmp.getLeftOperand() and
cmp.getOperator() = ">=" and
left = cmp.getRightOperand() and
k = 1
}
private predicate complex_lt(
ComparisonOperation cmp, Expr left, Expr right, int k, boolean isLt, boolean testIsTrue
) {
sub_lt(cmp, left, right, k, isLt, testIsTrue)
or
add_lt(cmp, left, right, k, isLt, testIsTrue)
}
// left - x < right + c => left < right + (c+x)
// left < (right - x) + c => left < right + (c-x)
private predicate sub_lt(
ComparisonOperation cmp, Expr left, Expr right, int k, boolean isLt, boolean testIsTrue
) {
exists(SubExpr lhs, int c, int x |
compares_lt(cmp, lhs, right, c, isLt, testIsTrue) and
left = lhs.getLeftOperand() and
x = int_value(lhs.getRightOperand()) and
k = c + x
)
or
exists(SubExpr rhs, int c, int x |
compares_lt(cmp, left, rhs, c, isLt, testIsTrue) and
right = rhs.getLeftOperand() and
x = int_value(rhs.getRightOperand()) and
k = c - x
)
}
// left + x < right + c => left < right + (c-x)
// left < (right + x) + c => left < right + (c+x)
private predicate add_lt(
ComparisonOperation cmp, Expr left, Expr right, int k, boolean isLt, boolean testIsTrue
) {
exists(AddExpr lhs, int c, int x |
compares_lt(cmp, lhs, right, c, isLt, testIsTrue) and
(
left = lhs.getLeftOperand() and x = int_value(lhs.getRightOperand())
or
left = lhs.getRightOperand() and x = int_value(lhs.getLeftOperand())
) and
k = c - x
)
or
exists(AddExpr rhs, int c, int x |
compares_lt(cmp, left, rhs, c, isLt, testIsTrue) and
(
right = rhs.getLeftOperand() and x = int_value(rhs.getRightOperand())
or
right = rhs.getRightOperand() and x = int_value(rhs.getLeftOperand())
) and
k = c + x
)
}
/** The `int` value of integer constant expression. */
private int int_value(Expr e) {
e.getUnderlyingType() instanceof IntegralType and
result = e.getValue().toInt()
}
/** An `SsaDefinition` with an additional predicate `isLt`. */
class GuardedSsa extends SsaDefinition {

View File

@@ -5,8 +5,6 @@
import cpp
import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
/**
* Holds if `block` consists of an `UnreachedInstruction`.
@@ -32,6 +30,11 @@ class GuardCondition extends Expr {
or
// no binary operators in the IR
this.(BinaryLogicalOperation).getAnOperand() instanceof GuardCondition
or
// the IR short-circuits if(!x)
// don't produce a guard condition for `y = !x` and other non-short-circuited cases
not exists(Instruction inst | this.getFullyConverted() = inst.getAst()) and
exists(IRGuardCondition ir | this.(NotExpr).getOperand() = ir.getAst())
}
/**
@@ -137,6 +140,39 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardCondition {
}
}
/**
* A `!` operator in the AST that guards one or more basic blocks, and does not have a corresponding
* IR instruction.
*/
private class GuardConditionFromShortCircuitNot extends GuardCondition, NotExpr {
GuardConditionFromShortCircuitNot() {
not exists(Instruction inst | this.getFullyConverted() = inst.getAst()) and
exists(IRGuardCondition ir | this.getOperand() = ir.getAst())
}
override predicate controls(BasicBlock controlled, boolean testIsTrue) {
this.getOperand().(GuardCondition).controls(controlled, testIsTrue.booleanNot())
}
override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
this.getOperand()
.(GuardCondition)
.comparesLt(left, right, k, isLessThan, testIsTrue.booleanNot())
}
override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) {
this.getOperand().(GuardCondition).ensuresLt(left, right, k, block, isLessThan.booleanNot())
}
override predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) {
this.getOperand().(GuardCondition).comparesEq(left, right, k, areEqual, testIsTrue.booleanNot())
}
override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) {
this.getOperand().(GuardCondition).ensuresEq(left, right, k, block, areEqual.booleanNot())
}
}
/**
* A Boolean condition in the AST that guards one or more basic blocks and has a corresponding IR
* instruction.
@@ -203,30 +239,12 @@ private class GuardConditionFromIR extends GuardCondition {
* `&&` and `||`. See the detailed explanation on predicate `controls`.
*/
private predicate controlsBlock(BasicBlock controlled, boolean testIsTrue) {
exists(IRBlock irb, Instruction instr |
exists(IRBlock irb |
ir.controls(irb, testIsTrue) and
instr = irb.getAnInstruction() and
instr.getAst().(ControlFlowNode).getBasicBlock() = controlled and
not isUnreachedBlock(irb) and
not this.excludeAsControlledInstruction(instr)
irb.getAnInstruction().getAst().(ControlFlowNode).getBasicBlock() = controlled and
not isUnreachedBlock(irb)
)
}
private predicate excludeAsControlledInstruction(Instruction instr) {
// Exclude the temporaries generated by a ternary expression.
exists(TranslatedConditionalExpr tce |
instr = tce.getInstruction(ConditionValueFalseStoreTag())
or
instr = tce.getInstruction(ConditionValueTrueStoreTag())
or
instr = tce.getInstruction(ConditionValueTrueTempAddressTag())
or
instr = tce.getInstruction(ConditionValueFalseTempAddressTag())
)
or
// Exclude unreached instructions, as their AST is the whole function and not a block.
instr instanceof UnreachedInstruction
}
}
/**

View File

@@ -110,8 +110,8 @@ private predicate loopConditionAlwaysUponEntry(ControlFlowNode loop, Expr condit
* should be in this relation.
*/
pragma[noinline]
private predicate isFunction(@element el) {
el instanceof @function
private predicate isFunction(Element el) {
el instanceof Function
or
el.(Expr).getParent() = el
}
@@ -122,7 +122,7 @@ private predicate isFunction(@element el) {
*/
pragma[noopt]
private predicate callHasNoTarget(@funbindexpr fc) {
exists(@function f |
exists(Function f |
funbind(fc, f) and
not isFunction(f)
)

View File

@@ -54,6 +54,18 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam
not f.isStatic()
}
/**
* Holds if the set of viable implementations that can be called by `call`
* might be improved by knowing the call context.
*/
predicate mayBenefitFromCallContext(DataFlowCall call, Function f) { none() }
/**
* Gets a viable dispatch target of `call` in the context `ctx`. This is
* restricted to those `call`s for which a context might make a difference.
*/
Function viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { none() }
/** A parameter position represented by an integer. */
class ParameterPosition extends int {
ParameterPosition() { any(ParameterNode p).isParameterOf(_, this) }

View File

@@ -10,12 +10,10 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
deprecated import FlowStateString
import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -50,7 +48,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract deprecated class Configuration extends string {
abstract class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -191,7 +189,7 @@ abstract deprecated class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
abstract private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -212,7 +210,7 @@ abstract deprecated private class ConfigurationRecursionPrevention extends Confi
}
}
deprecated private FlowState relevantState(Configuration config) {
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -221,17 +219,17 @@ deprecated private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
deprecated TMkConfigState(Configuration config, FlowState state) {
TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private module Config implements FullStateConfigSig {
private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -298,13 +296,13 @@ deprecated private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
deprecated private import Impl<Config> as I
private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
deprecated class PathNode instanceof I::PathNode {
class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -331,10 +329,10 @@ deprecated class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
deprecated final FlowState getState() { result = getState(super.getState()) }
final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -349,9 +347,9 @@ deprecated class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
deprecated module PathGraph = I::PathGraph;
module PathGraph = I::PathGraph;
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -359,10 +357,10 @@ deprecated private predicate hasFlow(Node source, Node sink, Configuration confi
)
}
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated predicate flowsTo = hasFlow/3;
predicate flowsTo = hasFlow/3;

View File

@@ -10,12 +10,10 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
deprecated import FlowStateString
import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -50,7 +48,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract deprecated class Configuration extends string {
abstract class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -191,7 +189,7 @@ abstract deprecated class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
abstract private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -212,7 +210,7 @@ abstract deprecated private class ConfigurationRecursionPrevention extends Confi
}
}
deprecated private FlowState relevantState(Configuration config) {
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -221,17 +219,17 @@ deprecated private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
deprecated TMkConfigState(Configuration config, FlowState state) {
TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private module Config implements FullStateConfigSig {
private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -298,13 +296,13 @@ deprecated private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
deprecated private import Impl<Config> as I
private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
deprecated class PathNode instanceof I::PathNode {
class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -331,10 +329,10 @@ deprecated class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
deprecated final FlowState getState() { result = getState(super.getState()) }
final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -349,9 +347,9 @@ deprecated class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
deprecated module PathGraph = I::PathGraph;
module PathGraph = I::PathGraph;
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -359,10 +357,10 @@ deprecated private predicate hasFlow(Node source, Node sink, Configuration confi
)
}
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated predicate flowsTo = hasFlow/3;
predicate flowsTo = hasFlow/3;

View File

@@ -10,12 +10,10 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
deprecated import FlowStateString
import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -50,7 +48,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract deprecated class Configuration extends string {
abstract class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -191,7 +189,7 @@ abstract deprecated class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
abstract private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -212,7 +210,7 @@ abstract deprecated private class ConfigurationRecursionPrevention extends Confi
}
}
deprecated private FlowState relevantState(Configuration config) {
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -221,17 +219,17 @@ deprecated private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
deprecated TMkConfigState(Configuration config, FlowState state) {
TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private module Config implements FullStateConfigSig {
private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -298,13 +296,13 @@ deprecated private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
deprecated private import Impl<Config> as I
private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
deprecated class PathNode instanceof I::PathNode {
class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -331,10 +329,10 @@ deprecated class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
deprecated final FlowState getState() { result = getState(super.getState()) }
final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -349,9 +347,9 @@ deprecated class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
deprecated module PathGraph = I::PathGraph;
module PathGraph = I::PathGraph;
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -359,10 +357,10 @@ deprecated private predicate hasFlow(Node source, Node sink, Configuration confi
)
}
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated predicate flowsTo = hasFlow/3;
predicate flowsTo = hasFlow/3;

View File

@@ -10,12 +10,10 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
deprecated import FlowStateString
import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -50,7 +48,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract deprecated class Configuration extends string {
abstract class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -191,7 +189,7 @@ abstract deprecated class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
abstract private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -212,7 +210,7 @@ abstract deprecated private class ConfigurationRecursionPrevention extends Confi
}
}
deprecated private FlowState relevantState(Configuration config) {
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -221,17 +219,17 @@ deprecated private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
deprecated TMkConfigState(Configuration config, FlowState state) {
TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private module Config implements FullStateConfigSig {
private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -298,13 +296,13 @@ deprecated private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
deprecated private import Impl<Config> as I
private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
deprecated class PathNode instanceof I::PathNode {
class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -331,10 +329,10 @@ deprecated class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
deprecated final FlowState getState() { result = getState(super.getState()) }
final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -349,9 +347,9 @@ deprecated class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
deprecated module PathGraph = I::PathGraph;
module PathGraph = I::PathGraph;
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -359,10 +357,10 @@ deprecated private predicate hasFlow(Node source, Node sink, Configuration confi
)
}
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated predicate flowsTo = hasFlow/3;
predicate flowsTo = hasFlow/3;

View File

@@ -10,12 +10,10 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
deprecated import FlowStateString
import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -50,7 +48,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract deprecated class Configuration extends string {
abstract class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -191,7 +189,7 @@ abstract deprecated class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
abstract private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -212,7 +210,7 @@ abstract deprecated private class ConfigurationRecursionPrevention extends Confi
}
}
deprecated private FlowState relevantState(Configuration config) {
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -221,17 +219,17 @@ deprecated private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
deprecated TMkConfigState(Configuration config, FlowState state) {
TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private module Config implements FullStateConfigSig {
private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -298,13 +296,13 @@ deprecated private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
deprecated private import Impl<Config> as I
private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
deprecated class PathNode instanceof I::PathNode {
class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -331,10 +329,10 @@ deprecated class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
deprecated final FlowState getState() { result = getState(super.getState()) }
final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -349,9 +347,9 @@ deprecated class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
deprecated module PathGraph = I::PathGraph;
module PathGraph = I::PathGraph;
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -359,10 +357,10 @@ deprecated private predicate hasFlow(Node source, Node sink, Configuration confi
)
}
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated predicate flowsTo = hasFlow/3;
predicate flowsTo = hasFlow/3;

View File

@@ -1,6 +1,4 @@
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* Provides an implementation of global (interprocedural) taint tracking.
* This file re-exports the local (intraprocedural) taint-tracking analysis
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
@@ -14,8 +12,6 @@ import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural taint tracking analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the taint tracking library must define its own unique extension of
@@ -55,7 +51,7 @@ private import TaintTrackingParameter::Private
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
*/
abstract deprecated class Configuration extends DataFlow::Configuration {
abstract class Configuration extends DataFlow::Configuration {
bindingset[this]
Configuration() { any() }

View File

@@ -1,6 +1,4 @@
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* Provides an implementation of global (interprocedural) taint tracking.
* This file re-exports the local (intraprocedural) taint-tracking analysis
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
@@ -14,8 +12,6 @@ import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural taint tracking analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the taint tracking library must define its own unique extension of
@@ -55,7 +51,7 @@ private import TaintTrackingParameter::Private
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
*/
abstract deprecated class Configuration extends DataFlow::Configuration {
abstract class Configuration extends DataFlow::Configuration {
bindingset[this]
Configuration() { any() }

View File

@@ -24,8 +24,8 @@ private predicate isGlobalWithMangledNameAndWithoutDefinition(@mangledname name,
* a unique global variable `complete` with the same name that does have a definition.
*/
private predicate hasTwinWithDefinition(@globalvariable incomplete, @globalvariable complete) {
not variable_instantiation(incomplete, complete) and
exists(@mangledname name |
not variable_instantiation(incomplete, complete) and
isGlobalWithMangledNameAndWithoutDefinition(name, incomplete) and
isGlobalWithMangledNameAndWithDefinition(name, complete)
)

View File

@@ -0,0 +1,21 @@
/**
* DEPRECATED: Use `semmle.code.cpp.ir.dataflow.TaintTracking` as a replacement.
*
* An IR taint tracking library that uses an IR DataFlow configuration to track
* taint from user inputs as defined by `semmle.code.cpp.security.Security`.
*/
import cpp
import semmle.code.cpp.security.Security
private import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl as DefaultTaintTrackingImpl
deprecated predicate predictableOnlyFlow = DefaultTaintTrackingImpl::predictableOnlyFlow/1;
deprecated predicate tainted = DefaultTaintTrackingImpl::tainted/2;
deprecated predicate taintedIncludingGlobalVars =
DefaultTaintTrackingImpl::taintedIncludingGlobalVars/3;
deprecated predicate globalVarFromId = DefaultTaintTrackingImpl::globalVarFromId/1;
deprecated module TaintedWithPath = DefaultTaintTrackingImpl::TaintedWithPath;

View File

@@ -31,11 +31,6 @@ abstract class MustFlowConfiguration extends string {
*/
abstract predicate isSink(Operand sink);
/**
* Holds if data flow through `instr` is prohibited.
*/
predicate isBarrier(Instruction instr) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -53,21 +48,18 @@ abstract class MustFlowConfiguration extends string {
*/
final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) {
this.isSource(source.getInstruction()) and
source.getASuccessor*() = sink
source.getASuccessor+() = sink
}
}
/** Holds if `node` flows from a source. */
pragma[nomagic]
private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) {
not config.isBarrier(node) and
(
config.isSource(node)
or
exists(Instruction mid |
step(mid, node, config) and
flowsFromSource(mid, pragma[only_bind_into](config))
)
config.isSource(node)
or
exists(Instruction mid |
step(mid, node, config) and
flowsFromSource(mid, pragma[only_bind_into](config))
)
}

View File

@@ -249,7 +249,9 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam
* Holds if the set of viable implementations that can be called by `call`
* might be improved by knowing the call context.
*/
predicate mayBenefitFromCallContext(DataFlowCall call) { mayBenefitFromCallContext(call, _, _) }
predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable f) {
mayBenefitFromCallContext(call, f, _)
}
/**
* Holds if `call` is a call through a function pointer, and the pointer

View File

@@ -10,12 +10,10 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
deprecated import FlowStateString
import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -50,7 +48,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract deprecated class Configuration extends string {
abstract class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -191,7 +189,7 @@ abstract deprecated class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
abstract private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -212,7 +210,7 @@ abstract deprecated private class ConfigurationRecursionPrevention extends Confi
}
}
deprecated private FlowState relevantState(Configuration config) {
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -221,17 +219,17 @@ deprecated private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
deprecated TMkConfigState(Configuration config, FlowState state) {
TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private module Config implements FullStateConfigSig {
private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -298,13 +296,13 @@ deprecated private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
deprecated private import Impl<Config> as I
private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
deprecated class PathNode instanceof I::PathNode {
class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -331,10 +329,10 @@ deprecated class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
deprecated final FlowState getState() { result = getState(super.getState()) }
final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -349,9 +347,9 @@ deprecated class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
deprecated module PathGraph = I::PathGraph;
module PathGraph = I::PathGraph;
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -359,10 +357,10 @@ deprecated private predicate hasFlow(Node source, Node sink, Configuration confi
)
}
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated predicate flowsTo = hasFlow/3;
predicate flowsTo = hasFlow/3;

View File

@@ -10,12 +10,10 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
deprecated import FlowStateString
import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -50,7 +48,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract deprecated class Configuration extends string {
abstract class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -191,7 +189,7 @@ abstract deprecated class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
abstract private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -212,7 +210,7 @@ abstract deprecated private class ConfigurationRecursionPrevention extends Confi
}
}
deprecated private FlowState relevantState(Configuration config) {
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -221,17 +219,17 @@ deprecated private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
deprecated TMkConfigState(Configuration config, FlowState state) {
TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private module Config implements FullStateConfigSig {
private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -298,13 +296,13 @@ deprecated private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
deprecated private import Impl<Config> as I
private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
deprecated class PathNode instanceof I::PathNode {
class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -331,10 +329,10 @@ deprecated class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
deprecated final FlowState getState() { result = getState(super.getState()) }
final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -349,9 +347,9 @@ deprecated class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
deprecated module PathGraph = I::PathGraph;
module PathGraph = I::PathGraph;
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -359,10 +357,10 @@ deprecated private predicate hasFlow(Node source, Node sink, Configuration confi
)
}
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated predicate flowsTo = hasFlow/3;
predicate flowsTo = hasFlow/3;

View File

@@ -10,12 +10,10 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
deprecated import FlowStateString
import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -50,7 +48,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract deprecated class Configuration extends string {
abstract class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -191,7 +189,7 @@ abstract deprecated class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
abstract private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -212,7 +210,7 @@ abstract deprecated private class ConfigurationRecursionPrevention extends Confi
}
}
deprecated private FlowState relevantState(Configuration config) {
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -221,17 +219,17 @@ deprecated private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
deprecated TMkConfigState(Configuration config, FlowState state) {
TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private module Config implements FullStateConfigSig {
private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -298,13 +296,13 @@ deprecated private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
deprecated private import Impl<Config> as I
private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
deprecated class PathNode instanceof I::PathNode {
class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -331,10 +329,10 @@ deprecated class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
deprecated final FlowState getState() { result = getState(super.getState()) }
final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -349,9 +347,9 @@ deprecated class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
deprecated module PathGraph = I::PathGraph;
module PathGraph = I::PathGraph;
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -359,10 +357,10 @@ deprecated private predicate hasFlow(Node source, Node sink, Configuration confi
)
}
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated predicate flowsTo = hasFlow/3;
predicate flowsTo = hasFlow/3;

View File

@@ -10,12 +10,10 @@ private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
private import DataFlowImpl
import DataFlowImplCommonPublic
deprecated import FlowStateString
import FlowStateString
private import codeql.util.Unit
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural data flow analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the global data flow library must define its own unique extension
@@ -50,7 +48,7 @@ private import codeql.util.Unit
* should instead depend on a `DataFlow2::Configuration`, a
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
*/
abstract deprecated class Configuration extends string {
abstract class Configuration extends string {
bindingset[this]
Configuration() { any() }
@@ -191,7 +189,7 @@ abstract deprecated class Configuration extends string {
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
*/
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
abstract private class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
@@ -212,7 +210,7 @@ abstract deprecated private class ConfigurationRecursionPrevention extends Confi
}
}
deprecated private FlowState relevantState(Configuration config) {
private FlowState relevantState(Configuration config) {
config.isSource(_, result) or
config.isSink(_, result) or
config.isBarrier(_, result) or
@@ -221,17 +219,17 @@ deprecated private FlowState relevantState(Configuration config) {
}
private newtype TConfigState =
deprecated TMkConfigState(Configuration config, FlowState state) {
TMkConfigState(Configuration config, FlowState state) {
state = relevantState(config) or state instanceof FlowStateEmpty
}
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
deprecated private module Config implements FullStateConfigSig {
private module Config implements FullStateConfigSig {
class FlowState = TConfigState;
predicate isSource(Node source, FlowState state) {
@@ -298,13 +296,13 @@ deprecated private module Config implements FullStateConfigSig {
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
}
deprecated private import Impl<Config> as I
private import Impl<Config> as I
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
deprecated class PathNode instanceof I::PathNode {
class PathNode instanceof I::PathNode {
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
@@ -331,10 +329,10 @@ deprecated class PathNode instanceof I::PathNode {
final Node getNode() { result = super.getNode() }
/** Gets the `FlowState` of this node. */
deprecated final FlowState getState() { result = getState(super.getState()) }
final FlowState getState() { result = getState(super.getState()) }
/** Gets the associated configuration. */
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
final Configuration getConfiguration() { result = getConfig(super.getState()) }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getASuccessor() }
@@ -349,9 +347,9 @@ deprecated class PathNode instanceof I::PathNode {
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
}
deprecated module PathGraph = I::PathGraph;
module PathGraph = I::PathGraph;
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
private predicate hasFlow(Node source, Node sink, Configuration config) {
exists(PathNode source0, PathNode sink0 |
hasFlowPath(source0, sink0, config) and
source0.getNode() = source and
@@ -359,10 +357,10 @@ deprecated private predicate hasFlow(Node source, Node sink, Configuration confi
)
}
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
I::flowPath(source, sink) and source.getConfiguration() = config
}
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
deprecated predicate flowsTo = hasFlow/3;
predicate flowsTo = hasFlow/3;

View File

@@ -20,10 +20,4 @@ module CppDataFlow implements InputSig {
Node exprNode(DataFlowExpr e) { result = Public::exprNode(e) }
predicate getAdditionalFlowIntoCallNodeTerm = Private::getAdditionalFlowIntoCallNodeTerm/2;
predicate validParameterAliasStep = Private::validParameterAliasStep/2;
predicate mayBenefitFromCallContext = Private::mayBenefitFromCallContext/1;
predicate viableImplInCallContext = Private::viableImplInCallContext/2;
}

View File

@@ -6,7 +6,6 @@ private import semmle.code.cpp.ir.internal.IRCppLanguage
private import SsaInternals as Ssa
private import DataFlowImplCommon as DataFlowImplCommon
private import codeql.util.Unit
private import Node0ToString
cached
private module Cached {
@@ -59,41 +58,6 @@ private module Cached {
import Cached
private import Nodes0
/**
* A module for calculating the number of stars (i.e., `*`s) needed for various
* dataflow node `toString` predicates.
*/
module NodeStars {
private int getNumberOfIndirections(Node n) {
result = n.(RawIndirectOperand).getIndirectionIndex()
or
result = n.(RawIndirectInstruction).getIndirectionIndex()
or
result = n.(VariableNode).getIndirectionIndex()
or
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
or
result = n.(FinalParameterNode).getIndirectionIndex()
}
private int maxNumberOfIndirections() { result = max(getNumberOfIndirections(_)) }
private string repeatStars(int n) {
n = 0 and result = ""
or
n = [1 .. maxNumberOfIndirections()] and
result = "*" + repeatStars(n - 1)
}
/**
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
* output for `n`.
*/
string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
}
import NodeStars
class Node0Impl extends TIRDataFlowNode0 {
/**
* INTERNAL: Do not use.
@@ -117,14 +81,6 @@ class Node0Impl extends TIRDataFlowNode0 {
/** Gets the operands corresponding to this node, if any. */
Operand asOperand() { result = this.(OperandNode0).getOperand() }
/** Gets the location of this node. */
final Location getLocation() { result = this.getLocationImpl() }
/** INTERNAL: Do not use. */
Location getLocationImpl() {
none() // overridden by subclasses
}
/** INTERNAL: Do not use. */
string toStringImpl() {
none() // overridden by subclasses
@@ -174,12 +130,10 @@ abstract class InstructionNode0 extends Node0Impl {
override DataFlowType getType() { result = getInstructionType(instr, _) }
override string toStringImpl() { result = instructionToString(instr) }
override Location getLocationImpl() {
if exists(instr.getAst().getLocation())
then result = instr.getAst().getLocation()
else result instanceof UnknownDefaultLocation
override string toStringImpl() {
// This predicate is overridden in subclasses. This default implementation
// does not use `Instruction.toString` because that's expensive to compute.
result = instr.getOpcode().toString()
}
final override predicate isGLValue() { exists(getInstructionType(instr, true)) }
@@ -219,13 +173,7 @@ abstract class OperandNode0 extends Node0Impl {
override DataFlowType getType() { result = getOperandType(op, _) }
override string toStringImpl() { result = operandToString(op) }
override Location getLocationImpl() {
if exists(op.getDef().getAst().getLocation())
then result = op.getDef().getAst().getLocation()
else result instanceof UnknownDefaultLocation
}
override string toStringImpl() { result = op.toString() }
final override predicate isGLValue() { exists(getOperandType(op, true)) }
}
@@ -673,24 +621,6 @@ class GlobalLikeVariable extends Variable {
}
}
/**
* Returns the smallest indirection for the type `t`.
*
* For most types this is `1`, but for `ArrayType`s (which are allocated on
* the stack) this is `0`
*/
int getMinIndirectionsForType(Type t) {
if t.getUnspecifiedType() instanceof Cpp::ArrayType then result = 0 else result = 1
}
private int getMinIndirectionForGlobalUse(Ssa::GlobalUse use) {
result = getMinIndirectionsForType(use.getUnspecifiedType())
}
private int getMinIndirectionForGlobalDef(Ssa::GlobalDef def) {
result = getMinIndirectionsForType(def.getUnspecifiedType())
}
/**
* Holds if data can flow from `node1` to `node2` in a way that loses the
* calling context. For example, this would happen with flow through a
@@ -702,20 +632,20 @@ predicate jumpStep(Node n1, Node n2) {
v = globalUse.getVariable() and
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
globalUse.getIndirectionIndex() = 1 and
v = n2.asVariable()
or
v = n2.asIndirectVariable(globalUse.getIndirection())
v = n2.asIndirectVariable(globalUse.getIndirectionIndex())
)
or
exists(Ssa::GlobalDef globalDef |
v = globalDef.getVariable() and
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
globalDef.getIndirectionIndex() = 1 and
v = n1.asVariable()
or
v = n1.asIndirectVariable(globalDef.getIndirection())
v = n1.asIndirectVariable(globalDef.getIndirectionIndex())
)
)
}
@@ -1177,55 +1107,3 @@ private int countNumberOfBranchesUsingParameter(SwitchInstruction switch, Parame
)
)
}
/**
* Holds if the data-flow step from `node1` to `node2` can be used to
* determine where side-effects may return from a callable.
* For C/C++, this means that the step from `node1` to `node2` not only
* preserves the value, but also preserves the identity of the value.
* For example, the assignment to `x` that reads the value of `*p` in
* ```cpp
* int* p = ...
* int x = *p;
* ```
* does not preserve the identity of `*p`.
*/
bindingset[node1, node2]
pragma[inline_late]
predicate validParameterAliasStep(Node node1, Node node2) {
// When flow-through summaries are computed we track which parameters flow to out-going parameters.
// In an example such as:
// ```
// modify(int* px) { *px = source(); }
// void modify_copy(int* p) {
// int x = *p;
// modify(&x);
// }
// ```
// since dataflow tracks each indirection as a separate SSA variable dataflow
// sees the above roughly as
// ```
// modify(int* px, int deref_px) { deref_px = source(); }
// void modify_copy(int* p, int deref_p) {
// int x = deref_p;
// modify(&x, x);
// }
// ```
// and when dataflow computes flow from a parameter to a post-update node to
// conclude which parameters are "updated" by the call to `modify_copy` it
// finds flow from `x [post update]` to `deref_p [post update]`.
// To prevent this we exclude steps that don't preserve identity. We do this
// by excluding flow from the right-hand side of `StoreInstruction`s to the
// `StoreInstruction`. This is sufficient because, for flow-through summaries,
// we're only interested in indirect parameters such as `deref_p` in the
// exampe above (i.e., the parameters with a non-zero indirection index), and
// if that ever flows to the right-hand side of a `StoreInstruction` then
// there must have been a dereference to reduce its indirection index down to
// 0.
not exists(Operand operand |
node1.asOperand() = operand and
node2.asInstruction().(StoreInstruction).getSourceValueOperand() = operand
)
// TODO: Also block flow through models that don't preserve identity such
// as `strdup`.
}

View File

@@ -1,24 +0,0 @@
/**
* This file contains the class that implements the _debug_ version of
* `toString` for `Instruction` and `Operand` dataflow nodes.
*/
private import semmle.code.cpp.ir.IR
private import codeql.util.Unit
private import Node0ToString
private import DataFlowUtil
private class DebugNode0ToString extends Node0ToString {
DebugNode0ToString() {
// Silence warning about `this` not being bound.
exists(this)
}
override string instructionToString(Instruction i) { result = i.getDumpString() }
override string operandToString(Operand op) {
result = op.getDumpString() + " @ " + op.getUse().getResultId()
}
override string toExprString(Node n) { none() }
}

View File

@@ -0,0 +1,668 @@
/**
* INTERNAL: Do not use.
*
* An IR taint tracking library that uses an IR DataFlow configuration to track
* taint from user inputs as defined by `semmle.code.cpp.security.Security`.
*/
import cpp
import semmle.code.cpp.security.Security
private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.ResolveCall
private import semmle.code.cpp.controlflow.IRGuards
private import semmle.code.cpp.models.interfaces.Taint
private import semmle.code.cpp.models.interfaces.DataFlow
private import semmle.code.cpp.ir.dataflow.TaintTracking
private import semmle.code.cpp.ir.dataflow.TaintTracking2
private import semmle.code.cpp.ir.dataflow.TaintTracking3
private import semmle.code.cpp.ir.dataflow.internal.ModelUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
/**
* A predictable instruction is one where an external user can predict
* the value. For example, a literal in the source code is considered
* predictable.
*/
private predicate predictableInstruction(Instruction instr) {
instr instanceof ConstantInstruction
or
instr instanceof StringConstantInstruction
or
// This could be a conversion on a string literal
predictableInstruction(instr.(UnaryInstruction).getUnary())
}
/**
* Functions that we should only allow taint to flow through (to the return
* value) if all but the source argument are 'predictable'. This is done to
* emulate the old security library's implementation rather than due to any
* strong belief that this is the right approach.
*
* Note that the list itself is not very principled; it consists of all the
* functions listed in the old security library's [default] `isPureFunction`
* that have more than one argument, but are not in the old taint tracking
* library's `returnArgument` predicate.
*/
predicate predictableOnlyFlow(string name) {
name =
[
"strcasestr", "strchnul", "strchr", "strchrnul", "strcmp", "strcspn", "strncmp", "strndup",
"strnlen", "strrchr", "strspn", "strstr", "strtod", "strtof", "strtol", "strtoll", "strtoq",
"strtoul"
]
}
private DataFlow::Node getNodeForSource(Expr source) {
isUserInput(source, _) and
result = getNodeForExpr(source)
}
private DataFlow::Node getNodeForExpr(Expr node) {
node = DataFlow::ExprFlowCached::asExprInternal(result)
or
// Some of the sources in `isUserInput` are intended to match the value of
// an expression, while others (those modeled below) are intended to match
// the taint that propagates out of an argument, like the `char *` argument
// to `gets`. It's impossible here to tell which is which, but the "access
// to argv" source is definitely not intended to match an output argument,
// and it causes false positives if we let it.
//
// This case goes together with the similar (but not identical) rule in
// `nodeIsBarrierIn`.
result = DataFlow::definitionByReferenceNodeFromArgument(node) and
not argv(node.(VariableAccess).getTarget())
}
private predicate conflatePointerAndPointee(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// Flow from `op` to `*op`.
exists(Operand operand, int indirectionIndex |
nodeHasOperand(nodeFrom, operand, indirectionIndex) and
nodeHasOperand(nodeTo, operand, indirectionIndex - 1)
)
or
// Flow from `instr` to `*instr`.
exists(Instruction instr, int indirectionIndex |
nodeHasInstruction(nodeFrom, instr, indirectionIndex) and
nodeHasInstruction(nodeTo, instr, indirectionIndex - 1)
)
}
private module DefaultTaintTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
conflatePointerAndPointee(nodeFrom, nodeTo)
}
}
private module DefaultTaintTrackingFlow = TaintTracking::Global<DefaultTaintTrackingConfig>;
private module ToGlobalVarTaintTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
predicate isSink(DataFlow::Node sink) { sink.asVariable() instanceof GlobalOrNamespaceVariable }
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable))
or
readsVariable(n2.asInstruction(), n1.asVariable().(GlobalOrNamespaceVariable))
}
predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
}
private module ToGlobalVarTaintTrackingFlow = TaintTracking::Global<ToGlobalVarTaintTrackingConfig>;
private module FromGlobalVarTaintTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
// This set of sources should be reasonably small, which is good for
// performance since the set of sinks is very large.
ToGlobalVarTaintTrackingFlow::flowTo(source)
}
predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
// Additional step for flow out of variables. There is no flow _into_
// variables in this configuration, so this step only serves to take flow
// out of a variable that's a source.
readsVariable(n2.asInstruction(), n1.asVariable())
}
predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
}
private module FromGlobalVarTaintTrackingFlow =
TaintTracking::Global<FromGlobalVarTaintTrackingConfig>;
private predicate readsVariable(LoadInstruction load, Variable var) {
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
}
private predicate writesVariable(StoreInstruction store, Variable var) {
store.getDestinationAddress().(VariableAddressInstruction).getAstVariable() = var
}
/**
* A variable that has any kind of upper-bound check anywhere in the program. This is
* biased towards being inclusive because there are a lot of valid ways of doing an
* upper bounds checks if we don't consider where it occurs, for example:
* ```
* if (x < 10) { sink(x); }
*
* if (10 > y) { sink(y); }
*
* if (z > 10) { z = 10; }
* sink(z);
* ```
*/
// TODO: This coarse overapproximation, ported from the old taint tracking
// library, could be replaced with an actual semantic check that a particular
// variable _access_ is guarded by an upper-bound check. We probably don't want
// to do this right away since it could expose a lot of FPs that were
// previously suppressed by this predicate by coincidence.
private predicate hasUpperBoundsCheck(Variable var) {
exists(RelationalOperation oper, VariableAccess access |
oper.getAnOperand() = access and
access.getTarget() = var and
// Comparing to 0 is not an upper bound check
not oper.getAnOperand().getValue() = "0"
)
}
private predicate nodeIsBarrierEqualityCandidate(
DataFlow::Node node, Operand access, Variable checkedVar
) {
exists(Instruction instr | instr = node.asOperand().getDef() |
readsVariable(instr, checkedVar) and
any(IRGuardCondition guard).ensuresEq(access, _, _, instr.getBlock(), true)
)
}
cached
private module Cached {
cached
predicate nodeIsBarrier(DataFlow::Node node) {
exists(Variable checkedVar, Instruction instr | instr = node.asOperand().getDef() |
readsVariable(instr, checkedVar) and
hasUpperBoundsCheck(checkedVar)
)
or
exists(Variable checkedVar, Operand access |
/*
* This node is guarded by a condition that forces the accessed variable
* to equal something else. For example:
* ```
* x = taintsource()
* if (x == 10) {
* taintsink(x); // not considered tainted
* }
* ```
*/
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
readsVariable(access.getDef(), checkedVar)
)
}
cached
predicate nodeIsBarrierIn(DataFlow::Node node) {
// don't use dataflow into taint sources, as this leads to duplicate results.
exists(Expr source | isUserInput(source, _) |
source = DataFlow::ExprFlowCached::asExprInternal(node)
or
// This case goes together with the similar (but not identical) rule in
// `getNodeForSource`.
node = DataFlow::definitionByReferenceNodeFromArgument(source)
)
or
// don't use dataflow into binary instructions if both operands are unpredictable
exists(BinaryInstruction iTo |
iTo = node.asInstruction() and
not predictableInstruction(iTo.getLeft()) and
not predictableInstruction(iTo.getRight()) and
// propagate taint from either the pointer or the offset, regardless of predictability
not iTo instanceof PointerArithmeticInstruction
)
or
// don't use dataflow through calls to pure functions if two or more operands
// are unpredictable
exists(Instruction iFrom1, Instruction iFrom2, CallInstruction iTo |
iTo = node.asInstruction() and
isPureFunction(iTo.getStaticCallTarget().getName()) and
iFrom1 = iTo.getAnArgument() and
iFrom2 = iTo.getAnArgument() and
not predictableInstruction(iFrom1) and
not predictableInstruction(iFrom2) and
iFrom1 != iFrom2
)
}
cached
Element adjustedSink(DataFlow::Node sink) {
// TODO: is it more appropriate to use asConvertedExpr here and avoid
// `getConversion*`? Or will that cause us to miss some cases where there's
// flow to a conversion (like a `ReferenceDereferenceExpr`) and we want to
// pretend there was flow to the converted `Expr` for the sake of
// compatibility.
sink.asExpr().getConversion*() = result
or
// For compatibility, send flow from arguments to parameters, even for
// functions with no body.
exists(FunctionCall call, int i |
sink.asExpr() = call.getArgument(pragma[only_bind_into](i)) and
result = resolveCall(call).getParameter(pragma[only_bind_into](i))
)
or
// For compatibility, send flow into a `Variable` if there is flow to any
// Load or Store of that variable.
exists(CopyInstruction copy |
copy.getSourceValue() = sink.asInstruction() and
(
readsVariable(copy, result) or
writesVariable(copy, result)
) and
not hasUpperBoundsCheck(result)
)
or
// For compatibility, send flow into a `NotExpr` even if it's part of a
// short-circuiting condition and thus might get skipped.
result.(NotExpr).getOperand() = sink.asExpr()
or
// Taint postfix and prefix crement operations when their operand is tainted.
result.(CrementOperation).getAnOperand() = sink.asExpr()
or
// Taint `e1 += e2`, `e &= e2` and friends when `e1` or `e2` is tainted.
result.(AssignOperation).getAnOperand() = sink.asExpr()
or
result =
sink.asOperand()
.(SideEffectOperand)
.getUse()
.(ReadSideEffectInstruction)
.getArgumentDef()
.getUnconvertedResultExpression()
}
/**
* Step to return value of a modeled function when an input taints the
* dereference of the return value.
*/
cached
predicate additionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
exists(CallInstruction call, Function func, FunctionInput modelIn, FunctionOutput modelOut |
n1 = callInput(call, modelIn) and
(
func.(TaintFunction).hasTaintFlow(modelIn, modelOut)
or
func.(DataFlowFunction).hasDataFlow(modelIn, modelOut)
) and
call.getStaticCallTarget() = func and
modelOut.isReturnValueDeref() and
call = n2.asInstruction()
)
}
}
private import Cached
/**
* Holds if `tainted` may contain taint from `source`.
*
* A tainted expression is either directly user input, or is
* computed from user input in a way that users can probably
* control the exact output of the computation.
*
* This doesn't include data flow through global variables.
* If you need that you must call `taintedIncludingGlobalVars`.
*/
cached
predicate tainted(Expr source, Element tainted) {
exists(DataFlow::Node sink |
DefaultTaintTrackingFlow::flow(getNodeForSource(source), sink) and
tainted = adjustedSink(sink)
)
}
/**
* Holds if `tainted` may contain taint from `source`, where the taint passed
* through a global variable named `globalVar`.
*
* A tainted expression is either directly user input, or is
* computed from user input in a way that users can probably
* control the exact output of the computation.
*
* This version gives the same results as tainted but also includes
* data flow through global variables.
*
* The parameter `globalVar` is the qualified name of the last global variable
* used to move the value from source to tainted. If the taint did not pass
* through a global variable, then `globalVar = ""`.
*/
cached
predicate taintedIncludingGlobalVars(Expr source, Element tainted, string globalVar) {
tainted(source, tainted) and
globalVar = ""
or
exists(
DataFlow::VariableNode variableNode, GlobalOrNamespaceVariable global, DataFlow::Node sink
|
global = variableNode.getVariable() and
ToGlobalVarTaintTrackingFlow::flow(getNodeForSource(source), variableNode) and
FromGlobalVarTaintTrackingFlow::flow(variableNode, sink) and
tainted = adjustedSink(sink) and
global = globalVarFromId(globalVar)
)
}
/**
* Gets the global variable whose qualified name is `id`. Use this predicate
* together with `taintedIncludingGlobalVars`. Example:
*
* ```
* exists(string varName |
* taintedIncludingGlobalVars(source, tainted, varName) and
* var = globalVarFromId(varName)
* )
* ```
*/
GlobalOrNamespaceVariable globalVarFromId(string id) { id = result.getQualifiedName() }
/**
* Provides definitions for augmenting source/sink pairs with data-flow paths
* between them. From a `@kind path-problem` query, import this module in the
* global scope, extend `TaintTrackingConfiguration`, and use `taintedWithPath`
* in place of `tainted`.
*
* Importing this module will also import the query predicates that contain the
* taint paths.
*/
module TaintedWithPath {
private newtype TSingleton = MkSingleton()
/**
* A taint-tracking configuration that matches sources and sinks in the same
* way as the `tainted` predicate.
*
* Override `isSink` and `taintThroughGlobals` as needed, but do not provide
* a characteristic predicate.
*/
class TaintTrackingConfiguration extends TSingleton {
/** Override this to specify which elements are sources in this configuration. */
predicate isSource(Expr source) { exists(getNodeForSource(source)) }
/** Override this to specify which elements are sinks in this configuration. */
abstract predicate isSink(Element e);
/** Override this to specify which expressions are barriers in this configuration. */
predicate isBarrier(Expr e) { nodeIsBarrier(getNodeForExpr(e)) }
/**
* Override this predicate to `any()` to allow taint to flow through global
* variables.
*/
predicate taintThroughGlobals() { none() }
/** Gets a textual representation of this element. */
string toString() { result = "TaintTrackingConfiguration" }
}
private module AdjustedConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(TaintTrackingConfiguration cfg, Expr e |
cfg.isSource(e) and source = getNodeForExpr(e)
)
}
predicate isSink(DataFlow::Node sink) {
exists(TaintTrackingConfiguration cfg | cfg.isSink(adjustedSink(sink)))
}
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
conflatePointerAndPointee(n1, n2)
or
// Steps into and out of global variables
exists(TaintTrackingConfiguration cfg | cfg.taintThroughGlobals() |
writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable))
or
readsVariable(n2.asInstruction(), n1.asVariable().(GlobalOrNamespaceVariable))
)
or
additionalTaintStep(n1, n2)
}
predicate isBarrier(DataFlow::Node node) {
exists(TaintTrackingConfiguration cfg, Expr e | cfg.isBarrier(e) and node = getNodeForExpr(e))
}
predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
predicate neverSkip(Node node) { none() }
}
private module AdjustedFlow = TaintTracking::Global<AdjustedConfig>;
/*
* A sink `Element` may map to multiple `DataFlowX::PathNode`s via (the
* inverse of) `adjustedSink`. For example, an `Expr` maps to all its
* conversions, and a `Variable` maps to all loads and stores from it. Because
* the path node is part of the tuple that constitutes the alert, this leads
* to duplicate alerts.
*
* To avoid showing duplicates, we edit the graph to replace the final node
* coming from the data-flow library with a node that matches exactly the
* `Element` sink that's requested.
*
* The same is done for sources.
*/
private newtype TPathNode =
TWrapPathNode(AdjustedFlow::PathNode n) or
// There's a single newtype constructor for both sources and sinks since
// that makes it easiest to deal with the case where source = sink.
TEndpointPathNode(Element e) {
exists(DataFlow::Node sourceNode, DataFlow::Node sinkNode |
AdjustedFlow::flow(sourceNode, sinkNode)
|
sourceNode = getNodeForExpr(e) and
exists(TaintTrackingConfiguration ttCfg | ttCfg.isSource(e))
or
e = adjustedSink(sinkNode) and
exists(TaintTrackingConfiguration ttCfg | ttCfg.isSink(e))
)
}
/** An opaque type used for the nodes of a data-flow path. */
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* 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
) {
none()
}
}
/**
* INTERNAL: Do not use.
*/
module Private {
/** Gets a predecessor `PathNode` of `pathNode`, if any. */
PathNode getAPredecessor(PathNode pathNode) { edges(result, pathNode) }
/** Gets the element that `pathNode` wraps, if any. */
Element getElementFromPathNode(PathNode pathNode) {
exists(DataFlow::Node node | node = pathNode.(WrapPathNode).inner().getNode() |
result = node.asInstruction().getAst()
or
result = node.asOperand().getDef().getAst()
)
or
result = pathNode.(EndpointPathNode).inner()
}
}
private class WrapPathNode extends PathNode, TWrapPathNode {
AdjustedFlow::PathNode inner() { this = TWrapPathNode(result) }
override string toString() { result = this.inner().toString() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.inner().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
private class EndpointPathNode extends PathNode, TEndpointPathNode {
Expr inner() { this = TEndpointPathNode(result) }
override string toString() { result = this.inner().toString() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.inner()
.getLocation()
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
/** A PathNode whose `Element` is a source. It may also be a sink. */
private class InitialPathNode extends EndpointPathNode {
InitialPathNode() { exists(TaintTrackingConfiguration cfg | cfg.isSource(this.inner())) }
}
/** A PathNode whose `Element` is a sink. It may also be a source. */
private class FinalPathNode extends EndpointPathNode {
FinalPathNode() { exists(TaintTrackingConfiguration cfg | cfg.isSink(this.inner())) }
}
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) {
AdjustedFlow::PathGraph::edges(a.(WrapPathNode).inner(), b.(WrapPathNode).inner())
or
// To avoid showing trivial-looking steps, we _replace_ the last node instead
// of adding an edge out of it.
exists(WrapPathNode sinkNode |
AdjustedFlow::PathGraph::edges(a.(WrapPathNode).inner(), sinkNode.inner()) and
b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
)
or
// Same for the first node
exists(WrapPathNode sourceNode |
AdjustedFlow::PathGraph::edges(sourceNode.inner(), b.(WrapPathNode).inner()) and
sourceNode.inner().getNode() = getNodeForExpr(a.(InitialPathNode).inner())
)
or
// Finally, handle the case where the path goes directly from a source to a
// sink, meaning that they both need to be translated.
exists(WrapPathNode sinkNode, WrapPathNode sourceNode |
AdjustedFlow::PathGraph::edges(sourceNode.inner(), sinkNode.inner()) and
sourceNode.inner().getNode() = getNodeForExpr(a.(InitialPathNode).inner()) and
b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
)
}
/**
* Holds if there is flow from `arg` to `out` across a call that can by summarized by the flow
* from `par` to `ret` within it, in the graph of data flow path explanations.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
AdjustedFlow::PathGraph::subpaths(arg.(WrapPathNode).inner(), par.(WrapPathNode).inner(),
ret.(WrapPathNode).inner(), out.(WrapPathNode).inner())
or
// To avoid showing trivial-looking steps, we _replace_ the last node instead
// of adding an edge out of it.
exists(WrapPathNode sinkNode |
AdjustedFlow::PathGraph::subpaths(arg.(WrapPathNode).inner(), par.(WrapPathNode).inner(),
ret.(WrapPathNode).inner(), sinkNode.inner()) and
out.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
)
or
// Same for the first node
exists(WrapPathNode sourceNode |
AdjustedFlow::PathGraph::subpaths(sourceNode.inner(), par.(WrapPathNode).inner(),
ret.(WrapPathNode).inner(), out.(WrapPathNode).inner()) and
sourceNode.inner().getNode() = getNodeForExpr(arg.(InitialPathNode).inner())
)
or
// Finally, handle the case where the path goes directly from a source to a
// sink, meaning that they both need to be translated.
exists(WrapPathNode sinkNode, WrapPathNode sourceNode |
AdjustedFlow::PathGraph::subpaths(sourceNode.inner(), par.(WrapPathNode).inner(),
ret.(WrapPathNode).inner(), sinkNode.inner()) and
sourceNode.inner().getNode() = getNodeForExpr(arg.(InitialPathNode).inner()) and
out.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
)
}
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
key = "semmle.label" and val = n.toString()
}
/**
* Holds if `tainted` may contain taint from `source`, where `sourceNode` and
* `sinkNode` are the corresponding `PathNode`s that can be used in a query
* to provide path explanations. Extend `TaintTrackingConfiguration` to use
* this predicate.
*
* A tainted expression is either directly user input, or is computed from
* user input in a way that users can probably control the exact output of
* the computation.
*/
predicate taintedWithPath(Expr source, Element tainted, PathNode sourceNode, PathNode sinkNode) {
exists(DataFlow::Node flowSource, DataFlow::Node flowSink |
source = sourceNode.(InitialPathNode).inner() and
flowSource = getNodeForExpr(source) and
AdjustedFlow::flow(flowSource, flowSink) and
tainted = adjustedSink(flowSink) and
tainted = sinkNode.(FinalPathNode).inner()
)
}
private predicate isGlobalVariablePathNode(WrapPathNode n) {
n.inner().getNode().asVariable() instanceof GlobalOrNamespaceVariable
or
n.inner().getNode().asIndirectVariable() instanceof GlobalOrNamespaceVariable
}
private predicate edgesWithoutGlobals(PathNode a, PathNode b) {
edges(a, b) and
not isGlobalVariablePathNode(a) and
not isGlobalVariablePathNode(b)
}
/**
* Holds if `tainted` can be reached from a taint source without passing
* through a global variable.
*/
predicate taintedWithoutGlobals(Element tainted) {
exists(PathNode sourceNode, FinalPathNode sinkNode |
AdjustedConfig::isSource(sourceNode.(WrapPathNode).inner().getNode()) and
edgesWithoutGlobals+(sourceNode, sinkNode) and
tainted = sinkNode.inner()
)
}
}

View File

@@ -1,53 +0,0 @@
/**
* This file imports the class that is used to construct the strings used by
* `Node.ToString`.
*
* Normally, this file should just import `NormalNode0ToString` to compute the
* efficient `toString`, but for debugging purposes one can import
* `DebugPrinting.qll` to better correlate the dataflow nodes with their
* underlying instructions and operands.
*/
private import semmle.code.cpp.ir.IR
private import codeql.util.Unit
private import DataFlowUtil
import NormalNode0ToString // Change this import to control which version should be used.
/** An abstract class to control the behavior of `Node.toString`. */
abstract class Node0ToString extends Unit {
/**
* Gets the string that should be used by `OperandNode.toString` to print the
* dataflow node whose underlying operand is `op.`
*/
abstract string operandToString(Operand op);
/**
* Gets the string that should be used by `InstructionNode.toString` to print
* the dataflow node whose underlying instruction is `instr`.
*/
abstract string instructionToString(Instruction i);
/**
* Gets the string representation of the `Expr` associated with `n`, if any.
*/
abstract string toExprString(Node n);
}
/**
* Gets the string that should be used by `OperandNode.toString` to print the
* dataflow node whose underlying operand is `op.`
*/
string operandToString(Operand op) { result = any(Node0ToString s).operandToString(op) }
/**
* Gets the string that should be used by `InstructionNode.toString` to print
* the dataflow node whose underlying instruction is `instr`.
*/
string instructionToString(Instruction instr) {
result = any(Node0ToString s).instructionToString(instr)
}
/**
* Gets the string representation of the `Expr` associated with `n`, if any.
*/
string toExprString(Node n) { result = any(Node0ToString s).toExprString(n) }

View File

@@ -1,36 +0,0 @@
/**
* This file contains the class that implements the non-debug version of
* `toString` for `Instruction` and `Operand` dataflow nodes.
*/
private import semmle.code.cpp.ir.IR
private import codeql.util.Unit
private import Node0ToString
private import DataFlowUtil
private import DataFlowPrivate
private class NormalNode0ToString extends Node0ToString {
NormalNode0ToString() {
// Silence warning about `this` not being bound.
exists(this)
}
override string instructionToString(Instruction i) {
if i.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = i.getAst().toString()
}
override string operandToString(Operand op) {
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = op.getDef().getAst().toString()
}
override string toExprString(Node n) {
result = n.asExpr(0).toString()
or
not exists(n.asExpr()) and
result = stars(n) + n.asIndirectExpr(0, 1).toString()
}
}

View File

@@ -1,12 +0,0 @@
private import cpp
private import semmle.code.cpp.ir.IR
private import SsaInternals as Ssa
/**
* A property provider that hides all instructions and operands that are not relevant for IR dataflow.
*/
class DataFlowRelevantIRPropertyProvider extends IRPropertyProvider {
override predicate shouldPrintOperand(Operand operand) { not Ssa::ignoreOperand(operand) }
override predicate shouldPrintInstruction(Instruction instr) { not Ssa::ignoreInstruction(instr) }
}

View File

@@ -1,7 +1,6 @@
private import cpp
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private import SsaInternals as Ssa
private import PrintIRUtilities
@@ -34,9 +33,9 @@ private string getNodeProperty(Node node, string key) {
key = "flow" and
result =
strictconcat(string flow, boolean to, int order1, int order2 |
flow = getFromFlow(node, order1, order2) + "->" + stars(node) + "@" and to = false
flow = getFromFlow(node, order1, order2) + "->" + starsForNode(node) + "@" and to = false
or
flow = stars(node) + "@->" + getToFlow(node, order1, order2) and to = true
flow = starsForNode(node) + "@->" + getToFlow(node, order1, order2) and to = true
|
flow, ", " order by to, order1, order2, flow
)
@@ -60,4 +59,8 @@ class LocalFlowPropertyProvider extends IRPropertyProvider {
result = getNodeProperty(node, key)
)
}
override predicate shouldPrintOperand(Operand operand) { not Ssa::ignoreOperand(operand) }
override predicate shouldPrintInstruction(Instruction instr) { not Ssa::ignoreInstruction(instr) }
}

View File

@@ -7,14 +7,37 @@ private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private string stars(int k) {
k =
[0 .. max([
any(RawIndirectInstruction n).getIndirectionIndex(),
any(RawIndirectOperand n).getIndirectionIndex()
]
)] and
(if k = 0 then result = "" else result = "*" + stars(k - 1))
}
string starsForNode(Node node) {
exists(int indirectionIndex |
node.(IndirectInstruction).hasInstructionAndIndirectionIndex(_, indirectionIndex) or
node.(IndirectOperand).hasOperandAndIndirectionIndex(_, indirectionIndex)
|
result = stars(indirectionIndex)
)
or
not node instanceof IndirectInstruction and
not node instanceof IndirectOperand and
result = ""
}
private Instruction getInstruction(Node n, string stars) {
result = [n.asInstruction(), n.(RawIndirectInstruction).getInstruction()] and
stars = stars(n)
stars = starsForNode(n)
}
private Operand getOperand(Node n, string stars) {
result = [n.asOperand(), n.(RawIndirectOperand).getOperand()] and
stars = stars(n)
stars = starsForNode(n)
}
/**

View File

@@ -16,15 +16,6 @@ private module SourceVariables {
ind = [0 .. countIndirectionsForCppType(base.getLanguageType()) + 1]
}
private int maxNumberOfIndirections() { result = max(SourceVariable sv | | sv.getIndirection()) }
private string repeatStars(int n) {
n = 0 and result = ""
or
n = [1 .. maxNumberOfIndirections()] and
result = "*" + repeatStars(n - 1)
}
class SourceVariable extends TSourceVariable {
SsaInternals0::SourceVariable base;
int ind;
@@ -41,7 +32,13 @@ private module SourceVariables {
SsaInternals0::SourceVariable getBaseVariable() { result = base }
/** Gets a textual representation of this element. */
string toString() { result = repeatStars(this.getIndirection()) + base.toString() }
string toString() {
ind = 0 and
result = this.getBaseVariable().toString()
or
ind > 0 and
result = this.getBaseVariable().toString() + " indirection"
}
/**
* Gets the number of loads performed on the base source variable
@@ -62,9 +59,6 @@ private module SourceVariables {
then result = base.getType()
else result = getTypeImpl(base.getType(), ind - 1)
}
/** Gets the location of this variable. */
Location getLocation() { result = this.getBaseVariable().getLocation() }
}
}
@@ -119,12 +113,22 @@ private newtype TDefOrUseImpl =
TGlobalUse(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
// Represents a final "use" of a global variable to ensure that
// the assignment to a global variable isn't ruled out as dead.
isGlobalUse(v, f, _, indirectionIndex)
exists(VariableAddressInstruction vai, int defIndex |
vai.getEnclosingIRFunction() = f and
vai.getAstVariable() = v and
isDef(_, _, _, vai, _, defIndex) and
indirectionIndex = [0 .. defIndex] + 1
)
} or
TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
// Represents the initial "definition" of a global variable when entering
// a function body.
isGlobalDefImpl(v, f, _, indirectionIndex)
exists(VariableAddressInstruction vai |
vai.getEnclosingIRFunction() = f and
vai.getAstVariable() = v and
isUse(_, _, vai, _, indirectionIndex) and
not isDef(_, _, vai.getAUse(), _, _, _)
)
} or
TIteratorDef(
Operand iteratorDerefAddress, BaseSourceVariableInstruction container, int indirectionIndex
@@ -146,32 +150,6 @@ private newtype TDefOrUseImpl =
)
}
private predicate isGlobalUse(
GlobalLikeVariable v, IRFunction f, int indirection, int indirectionIndex
) {
// Generate a "global use" at the end of the function body if there's a
// direct definition somewhere in the body of the function
indirection =
min(int cand, VariableAddressInstruction vai |
vai.getEnclosingIRFunction() = f and
vai.getAstVariable() = v and
isDef(_, _, _, vai, cand, indirectionIndex)
|
cand
)
}
private predicate isGlobalDefImpl(
GlobalLikeVariable v, IRFunction f, int indirection, int indirectionIndex
) {
exists(VariableAddressInstruction vai |
vai.getEnclosingIRFunction() = f and
vai.getAstVariable() = v and
isUse(_, _, vai, indirection, indirectionIndex) and
not isDef(_, _, _, vai, _, indirectionIndex)
)
}
private predicate unspecifiedTypeIsModifiableAt(Type unspecified, int indirectionIndex) {
indirectionIndex = [1 .. getIndirectionForUnspecifiedType(unspecified).getNumberOfIndirections()] and
exists(CppType cppType |
@@ -452,57 +430,6 @@ class FinalParameterUse extends UseImpl, TFinalParameterUse {
}
}
/**
* A use that models a synthetic "last use" of a global variable just before a
* function returns.
*
* We model global variable flow by:
* - Inserting a last use of any global variable that's modified by a function
* - Flowing from the last use to the `VariableNode` that represents the global
* variable.
* - Flowing from the `VariableNode` to an "initial def" of the global variable
* in any function that may read the global variable.
* - Flowing from the initial definition to any subsequent uses of the global
* variable in the function body.
*
* For example, consider the following pair of functions:
* ```cpp
* int global;
* int source();
* void sink(int);
*
* void set_global() {
* global = source();
* }
*
* void read_global() {
* sink(global);
* }
* ```
* we insert global uses and defs so that (from the point-of-view of dataflow)
* the above scenario looks like:
* ```cpp
* int global; // (1)
* int source();
* void sink(int);
*
* void set_global() {
* global = source();
* __global_use(global); // (2)
* }
*
* void read_global() {
* global = __global_def; // (3)
* sink(global); // (4)
* }
* ```
* and flow from `source()` to the argument of `sink` is then modeled as
* follows:
* 1. Flow from `source()` to `(2)` (via SSA).
* 2. Flow from `(2)` to `(1)` (via a `jumpStep`).
* 3. Flow from `(1)` to `(3)` (via a `jumpStep`).
* 4. Flow from `(3)` to `(4)` (via SSA).
*/
class GlobalUse extends UseImpl, TGlobalUse {
GlobalLikeVariable global;
IRFunction f;
@@ -511,7 +438,7 @@ class GlobalUse extends UseImpl, TGlobalUse {
override FinalGlobalValue getNode() { result.getGlobalUse() = this }
override int getIndirection() { isGlobalUse(global, f, result, ind) }
override int getIndirection() { result = ind + 1 }
/** Gets the global variable associated with this use. */
GlobalLikeVariable getVariable() { result = global }
@@ -533,9 +460,7 @@ class GlobalUse extends UseImpl, TGlobalUse {
)
}
override SourceVariable getSourceVariable() {
sourceVariableIsGlobal(result, global, f, this.getIndirection())
}
override SourceVariable getSourceVariable() { sourceVariableIsGlobal(result, global, f, ind) }
final override Cpp::Location getLocation() { result = f.getLocation() }
@@ -550,12 +475,6 @@ class GlobalUse extends UseImpl, TGlobalUse {
override BaseSourceVariableInstruction getBase() { none() }
}
/**
* A definition that models a synthetic "initial definition" of a global
* variable just after the function entry point.
*
* See the QLDoc for `GlobalUse` for how this is used.
*/
class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
GlobalLikeVariable global;
IRFunction f;
@@ -582,18 +501,16 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
/** Gets the global variable associated with this definition. */
override SourceVariable getSourceVariable() {
sourceVariableIsGlobal(result, global, f, this.getIndirection())
sourceVariableIsGlobal(result, global, f, indirectionIndex)
}
int getIndirection() { result = indirectionIndex }
/**
* Gets the type of this use after specifiers have been deeply stripped
* and typedefs have been resolved.
*/
Type getUnspecifiedType() { result = global.getUnspecifiedType() }
override string toString() { result = "Def of " + this.getSourceVariable() }
override string toString() { result = "GlobalDef" }
override Location getLocation() { result = f.getLocation() }
@@ -609,10 +526,7 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
*/
predicate adjacentDefRead(DefOrUse defOrUse1, UseOrPhi use) {
exists(IRBlock bb1, int i1, SourceVariable v |
defOrUse1
.asDefOrUse()
.hasIndexInBlock(pragma[only_bind_out](bb1), pragma[only_bind_out](i1),
pragma[only_bind_out](v))
defOrUse1.asDefOrUse().hasIndexInBlock(bb1, i1, v)
|
exists(IRBlock bb2, int i2, DefinitionExt def |
adjacentDefReadExt(pragma[only_bind_into](def), pragma[only_bind_into](bb1),
@@ -634,11 +548,7 @@ predicate adjacentDefRead(DefOrUse defOrUse1, UseOrPhi use) {
* flows to `useOrPhi`.
*/
private predicate globalDefToUse(GlobalDef globalDef, UseOrPhi useOrPhi) {
exists(IRBlock bb1, int i1, SourceVariable v |
globalDef
.hasIndexInBlock(pragma[only_bind_out](bb1), pragma[only_bind_out](i1),
pragma[only_bind_out](v))
|
exists(IRBlock bb1, int i1, SourceVariable v | globalDef.hasIndexInBlock(bb1, i1, v) |
exists(IRBlock bb2, int i2 |
adjacentDefReadExt(_, pragma[only_bind_into](bb1), pragma[only_bind_into](i1),
pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) and
@@ -944,7 +854,7 @@ private predicate sourceVariableIsGlobal(
)
}
private module SsaInput implements SsaImplCommon::InputSig<Location> {
private module SsaInput implements SsaImplCommon::InputSig {
import InputSigCommon
import SourceVariables
@@ -1070,7 +980,7 @@ class GlobalDef extends TGlobalDef, SsaDefOrUse {
final override Location getLocation() { result = global.getLocation() }
/** Gets a textual representation of this definition. */
override string toString() { result = global.toString() }
override string toString() { result = "GlobalDef" }
/**
* Holds if this definition has index `index` in block `block`, and
@@ -1080,9 +990,6 @@ class GlobalDef extends TGlobalDef, SsaDefOrUse {
global.hasIndexInBlock(block, index, sv)
}
/** Gets the indirection index of this definition. */
int getIndirection() { result = global.getIndirection() }
/** Gets the indirection index of this definition. */
int getIndirectionIndex() { result = global.getIndirectionIndex() }
@@ -1167,7 +1074,7 @@ class Def extends DefOrUse {
predicate isCertain() { defOrUse.isCertain() }
}
private module SsaImpl = SsaImplCommon::Make<Location, SsaInput>;
private module SsaImpl = SsaImplCommon::Make<SsaInput>;
class PhiNode extends SsaImpl::DefinitionExt {
PhiNode() {

View File

@@ -377,9 +377,6 @@ abstract private class AbstractBaseSourceVariable extends TBaseSourceVariable {
/** Gets a textual representation of this element. */
abstract string toString();
/** Gets the location of this variable. */
abstract Location getLocation();
/** Gets the type of this base source variable. */
final DataFlowType getType() { this.getLanguageType().hasUnspecifiedType(result, _) }
@@ -398,8 +395,6 @@ class BaseIRVariable extends AbstractBaseSourceVariable, TBaseIRVariable {
override string toString() { result = var.toString() }
override Location getLocation() { result = var.getLocation() }
override CppType getLanguageType() { result = var.getLanguageType() }
}
@@ -412,47 +407,63 @@ class BaseCallVariable extends AbstractBaseSourceVariable, TBaseCallVariable {
override string toString() { result = call.toString() }
override Location getLocation() { result = call.getLocation() }
override CppType getLanguageType() { result = getResultLanguageType(call) }
}
private module IsModifiableAtImpl {
pragma[nomagic]
private predicate isUnderlyingIndirectionType(Type t) {
t = any(Indirection ind).getUnderlyingType()
}
/**
* Holds if the value pointed to by `operand` can potentially be
* modified be the caller.
*/
predicate isModifiableByCall(ArgumentOperand operand, int indirectionIndex) {
exists(CallInstruction call, int index, CppType type |
indirectionIndex = [1 .. countIndirectionsForCppType(type)] and
type = getLanguageType(operand) and
call.getArgumentOperand(index) = operand and
if index = -1
then
// A qualifier is "modifiable" if:
// 1. the member function is not const specified, or
// 2. the member function is `const` specified, but returns a pointer or reference
// type that is non-const.
//
// To see why this is necessary, consider the following function:
// ```
// struct C {
// void* data_;
// void* data() const { return data; }
// };
// ...
// C c;
// memcpy(c.data(), source, 16)
// ```
// the data pointed to by `c.data_` is potentially modified by the call to `memcpy` even though
// `C::data` has a const specifier. So we further place the restriction that the type returned
// by `call` should not be of the form `const T*` (for some deeply const type `T`).
if call.getStaticCallTarget() instanceof Cpp::ConstMemberFunction
then
exists(PointerOrArrayOrReferenceType resultType |
resultType = call.getResultType() and
not resultType.isDeeplyConstBelow()
)
else any()
else
// An argument is modifiable if it's a non-const pointer or reference type.
isModifiableAt(type, indirectionIndex)
)
}
/**
* Holds if the `indirectionIndex`'th dereference of a value of type
* `cppType` is a type that can be modified (either by modifying the value
* itself or one of its fields if it's a class type).
*
* For example, a value of type `const int* const` cannot be modified
* at any indirection index (because it's a constant pointer to constant
* data), and a value of type `int *const *` is modifiable at indirection index
* 2 only.
*
* A value of type `const S2* s2` where `s2` is
* ```cpp
* struct S { int x; }
* ```
* can be modified at indirection index 1. This is to ensure that we generate
* a `PostUpdateNode` for the argument corresponding to the `s2` parameter in
* an example such as:
* ```cpp
* void set_field(const S2* s2)
* {
* s2->s->x = 42;
* }
* ```
*/
bindingset[cppType, indirectionIndex]
pragma[inline_late]
private predicate impl(CppType cppType, int indirectionIndex) {
exists(Type pointerType, Type base |
isUnderlyingIndirectionType(pointerType) and
cppType.hasUnderlyingType(pointerType, _) and
/**
* Holds if `t` is a pointer or reference type that supports at least `indirectionIndex` number
* of indirections, and the `indirectionIndex` indirection cannot be modfiied by passing a
* value of `t` to a function.
*/
private predicate isModifiableAtImpl(CppType cppType, int indirectionIndex) {
indirectionIndex = [1 .. countIndirectionsForCppType(cppType)] and
(
exists(Type pointerType, Type base, Type t |
pointerType = t.getUnderlyingType() and
pointerType = any(Indirection ind).getUnderlyingType() and
cppType.hasType(t, _) and
base = getTypeImpl(pointerType, indirectionIndex)
|
// The value cannot be modified if it has a const specifier,
@@ -462,114 +473,28 @@ private module IsModifiableAtImpl {
// one of the members was modified.
exists(base.stripType().(Cpp::Class).getAField())
)
}
/**
* Holds if `cppType` is modifiable with an indirection index of at least 1.
*
* This predicate factored out into a separate predicate for two reasons:
* - This predicate needs to be recursive because, if a type is modifiable
* at indirection `i`, then it's also modifiable at indirection index `i+1`
* (because the pointer could be completely re-assigned at indirection `i`).
* - We special-case indirection index `0` so that pointer arguments that can
* be modified at some index always have a `PostUpdateNode` at indiretion
* index 0 even though the 0'th indirection can never be modified by a
* callee.
*/
private predicate isModifiableAtImplAtLeast1(CppType cppType, int indirectionIndex) {
indirectionIndex = [1 .. countIndirectionsForCppType(cppType)] and
(
impl(cppType, indirectionIndex)
or
// If the `indirectionIndex`'th dereference of a type can be modified
// then so can the `indirectionIndex + 1`'th dereference.
isModifiableAtImplAtLeast1(cppType, indirectionIndex - 1)
)
}
/**
* Holds if `cppType` is modifiable at indirection index 0.
*
* In reality, the 0'th indirection of a pointer (i.e., the pointer itself)
* can never be modified by a callee, but it is sometimes useful to be able
* to specify the value of the pointer, as its coming out of a function, as
* a source of dataflow since the shared library's reverse-read mechanism
* then ensures that field-flow is accounted for.
*/
private predicate isModifiableAtImplAt0(CppType cppType) { impl(cppType, 0) }
/**
* Holds if `t` is a pointer or reference type that supports at least
* `indirectionIndex` number of indirections, and the `indirectionIndex`
* indirection cannot be modfiied by passing a value of `t` to a function.
*/
private predicate isModifiableAtImpl(CppType cppType, int indirectionIndex) {
isModifiableAtImplAtLeast1(cppType, indirectionIndex)
or
indirectionIndex = 0 and
isModifiableAtImplAt0(cppType)
}
/**
* Holds if `t` is a type with at least `indirectionIndex` number of
* indirections, and the `indirectionIndex` indirection can be modified by
* passing a value of type `t` to a function function.
*/
bindingset[indirectionIndex]
predicate isModifiableAt(CppType cppType, int indirectionIndex) {
isModifiableAtImpl(cppType, indirectionIndex)
or
exists(PointerWrapper pw, Type t |
cppType.hasType(t, _) and
t.stripType() = pw and
not pw.pointsToConst()
)
}
/**
* Holds if the value pointed to by `operand` can potentially be
* modified be the caller.
*/
predicate isModifiableByCall(ArgumentOperand operand, int indirectionIndex) {
exists(CallInstruction call, int index, CppType type |
indirectionIndex = [0 .. countIndirectionsForCppType(type)] and
type = getLanguageType(operand) and
call.getArgumentOperand(index) = operand and
if index = -1
then
// A qualifier is "modifiable" if:
// 1. the member function is not const specified, or
// 2. the member function is `const` specified, but returns a pointer or reference
// type that is non-const.
//
// To see why this is necessary, consider the following function:
// ```
// struct C {
// void* data_;
// void* data() const { return data; }
// };
// ...
// C c;
// memcpy(c.data(), source, 16)
// ```
// the data pointed to by `c.data_` is potentially modified by the call to `memcpy` even though
// `C::data` has a const specifier. So we further place the restriction that the type returned
// by `call` should not be of the form `const T*` (for some deeply const type `T`).
if call.getStaticCallTarget() instanceof Cpp::ConstMemberFunction
then
exists(PointerOrArrayOrReferenceType resultType |
resultType = call.getResultType() and
not resultType.isDeeplyConstBelow()
)
else any()
else
// An argument is modifiable if it's a non-const pointer or reference type.
isModifiableAt(type, indirectionIndex)
)
}
// If the `indirectionIndex`'th dereference of a type can be modified
// then so can the `indirectionIndex + 1`'th dereference.
isModifiableAtImpl(cppType, indirectionIndex - 1)
)
}
import IsModifiableAtImpl
/**
* Holds if `t` is a type with at least `indirectionIndex` number of indirections,
* and the `indirectionIndex` indirection can be modified by passing a value of
* type `t` to a function function.
*/
bindingset[indirectionIndex]
predicate isModifiableAt(CppType cppType, int indirectionIndex) {
isModifiableAtImpl(cppType, indirectionIndex)
or
exists(PointerWrapper pw, Type t |
cppType.hasType(t, _) and
t.stripType() = pw and
not pw.pointsToConst()
)
}
abstract class BaseSourceVariableInstruction extends Instruction {
/** Gets the base source variable accessed by this instruction. */
@@ -947,7 +872,7 @@ private module Cached {
upper = countIndirectionsForCppType(type) and
ind = ind0 + [lower .. upper] and
indirectionIndex = ind - (ind0 + lower) and
lower = getMinIndirectionsForType(any(Type t | type.hasUnspecifiedType(t, _)))
(if type.hasType(any(Cpp::ArrayType arrayType), true) then lower = 0 else lower = 1)
)
}

View File

@@ -72,16 +72,6 @@ private predicate operandToInstructionTaintStep(Operand opFrom, Instruction inst
or
instrTo.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union
)
or
// Taint from int to boolean casts. This ensures that we have flow to `!x` in:
// ```cpp
// x = integer_source();
// if(!x) { ... }
// ```
exists(Operand zero |
zero.getDef().(ConstantValueInstruction).getValue() = "0" and
instrTo.(CompareNEInstruction).hasOperands(opFrom, zero)
)
}
/**

View File

@@ -229,7 +229,7 @@ private class FinalParameterUse extends UseImpl, TFinalParameterUse {
override predicate isCertain() { any() }
}
private module SsaInput implements SsaImplCommon::InputSig<Location> {
private module SsaInput implements SsaImplCommon::InputSig {
import InputSigCommon
import SourceVariables
@@ -335,7 +335,7 @@ class Def extends DefOrUse {
predicate isIteratorDef() { defOrUse instanceof IteratorDef }
}
private module SsaImpl = SsaImplCommon::Make<Location, SsaInput>;
private module SsaImpl = SsaImplCommon::Make<SsaInput>;
class PhiNode extends SsaImpl::DefinitionExt {
PhiNode() {

View File

@@ -1,6 +1,4 @@
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* Provides an implementation of global (interprocedural) taint tracking.
* This file re-exports the local (intraprocedural) taint-tracking analysis
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
@@ -14,8 +12,6 @@ import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural taint tracking analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the taint tracking library must define its own unique extension of
@@ -55,7 +51,7 @@ private import TaintTrackingParameter::Private
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
*/
abstract deprecated class Configuration extends DataFlow::Configuration {
abstract class Configuration extends DataFlow::Configuration {
bindingset[this]
Configuration() { any() }

View File

@@ -1,6 +1,4 @@
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* Provides an implementation of global (interprocedural) taint tracking.
* This file re-exports the local (intraprocedural) taint-tracking analysis
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
@@ -14,8 +12,6 @@ import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural taint tracking analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the taint tracking library must define its own unique extension of
@@ -55,7 +51,7 @@ private import TaintTrackingParameter::Private
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
*/
abstract deprecated class Configuration extends DataFlow::Configuration {
abstract class Configuration extends DataFlow::Configuration {
bindingset[this]
Configuration() { any() }

View File

@@ -1,6 +1,4 @@
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* Provides an implementation of global (interprocedural) taint tracking.
* This file re-exports the local (intraprocedural) taint-tracking analysis
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
@@ -14,8 +12,6 @@ import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
/**
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
*
* A configuration of interprocedural taint tracking analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the taint tracking library must define its own unique extension of
@@ -55,7 +51,7 @@ private import TaintTrackingParameter::Private
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
*/
abstract deprecated class Configuration extends DataFlow::Configuration {
abstract class Configuration extends DataFlow::Configuration {
bindingset[this]
Configuration() { any() }

View File

@@ -12,9 +12,6 @@ int getConstantValue(Instruction instr) {
or
result = getConstantValue(instr.(CopyInstruction).getSourceValue())
or
getConstantValue(instr.(LogicalNotInstruction).getUnary()) != 0 and
result = 0
or
exists(PhiInstruction phi |
phi = instr and
result = unique(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef()))
@@ -29,25 +26,28 @@ private predicate binaryInstructionOperands(BinaryInstruction instr, int left, i
pragma[noinline]
private int getBinaryInstructionValue(BinaryInstruction instr) {
exists(int left, int right | binaryInstructionOperands(instr, left, right) |
instr instanceof AddInstruction and result = add(left, right)
or
instr instanceof SubInstruction and result = sub(left, right)
or
instr instanceof MulInstruction and result = mul(left, right)
or
instr instanceof DivInstruction and result = div(left, right)
or
instr instanceof CompareEQInstruction and result = compareEQ(left, right)
or
instr instanceof CompareNEInstruction and result = compareNE(left, right)
or
instr instanceof CompareLTInstruction and result = compareLT(left, right)
or
instr instanceof CompareGTInstruction and result = compareGT(left, right)
or
instr instanceof CompareLEInstruction and result = compareLE(left, right)
or
instr instanceof CompareGEInstruction and result = compareGE(left, right)
exists(int left, int right |
binaryInstructionOperands(instr, left, right) and
(
instr instanceof AddInstruction and result = add(left, right)
or
instr instanceof SubInstruction and result = sub(left, right)
or
instr instanceof MulInstruction and result = mul(left, right)
or
instr instanceof DivInstruction and result = div(left, right)
or
instr instanceof CompareEQInstruction and result = compareEQ(left, right)
or
instr instanceof CompareNEInstruction and result = compareNE(left, right)
or
instr instanceof CompareLTInstruction and result = compareLT(left, right)
or
instr instanceof CompareGTInstruction and result = compareGT(left, right)
or
instr instanceof CompareLEInstruction and result = compareLE(left, right)
or
instr instanceof CompareGEInstruction and result = compareGE(left, right)
)
)
}

View File

@@ -1068,3 +1068,6 @@ module Ssa {
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
}
/** DEPRECATED: Alias for Ssa */
deprecated module SSA = Ssa;

View File

@@ -3,6 +3,13 @@ import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Rea
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSsaInstructions as SsaInstructions
/** DEPRECATED: Alias for SsaInstructions */
deprecated module SSAInstructions = SsaInstructions;
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import AliasedSSA as Alias
import semmle.code.cpp.ir.implementation.internal.TOperand::AliasedSsaOperands as SsaOperands
/** DEPRECATED: Alias for SsaOperands */
deprecated module SSAOperands = SsaOperands;

View File

@@ -2,3 +2,6 @@ import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSsa
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSsa
/** DEPRECATED: Alias for AliasedSsa */
deprecated module AliasedSSA = AliasedSsa;

View File

@@ -23,8 +23,9 @@ private module Internal {
newtype TOperand =
// RAW
TRegisterOperand(TRawInstruction useInstr, RegisterOperandTag tag, TRawInstruction defInstr) {
defInstr = unique( | | RawConstruction::getRegisterOperandDefinition(useInstr, tag)) and
not RawConstruction::isInCycle(useInstr)
defInstr = RawConstruction::getRegisterOperandDefinition(useInstr, tag) and
not RawConstruction::isInCycle(useInstr) and
strictcount(RawConstruction::getRegisterOperandDefinition(useInstr, tag)) = 1
} or
// Placeholder for Phi and Chi operands in stages that don't have the corresponding instructions
TNoOperand() { none() } or

View File

@@ -12,9 +12,6 @@ int getConstantValue(Instruction instr) {
or
result = getConstantValue(instr.(CopyInstruction).getSourceValue())
or
getConstantValue(instr.(LogicalNotInstruction).getUnary()) != 0 and
result = 0
or
exists(PhiInstruction phi |
phi = instr and
result = unique(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef()))
@@ -29,25 +26,28 @@ private predicate binaryInstructionOperands(BinaryInstruction instr, int left, i
pragma[noinline]
private int getBinaryInstructionValue(BinaryInstruction instr) {
exists(int left, int right | binaryInstructionOperands(instr, left, right) |
instr instanceof AddInstruction and result = add(left, right)
or
instr instanceof SubInstruction and result = sub(left, right)
or
instr instanceof MulInstruction and result = mul(left, right)
or
instr instanceof DivInstruction and result = div(left, right)
or
instr instanceof CompareEQInstruction and result = compareEQ(left, right)
or
instr instanceof CompareNEInstruction and result = compareNE(left, right)
or
instr instanceof CompareLTInstruction and result = compareLT(left, right)
or
instr instanceof CompareGTInstruction and result = compareGT(left, right)
or
instr instanceof CompareLEInstruction and result = compareLE(left, right)
or
instr instanceof CompareGEInstruction and result = compareGE(left, right)
exists(int left, int right |
binaryInstructionOperands(instr, left, right) and
(
instr instanceof AddInstruction and result = add(left, right)
or
instr instanceof SubInstruction and result = sub(left, right)
or
instr instanceof MulInstruction and result = mul(left, right)
or
instr instanceof DivInstruction and result = div(left, right)
or
instr instanceof CompareEQInstruction and result = compareEQ(left, right)
or
instr instanceof CompareNEInstruction and result = compareNE(left, right)
or
instr instanceof CompareLTInstruction and result = compareLT(left, right)
or
instr instanceof CompareGTInstruction and result = compareGT(left, right)
or
instr instanceof CompareLEInstruction and result = compareLE(left, right)
or
instr instanceof CompareGEInstruction and result = compareGE(left, right)
)
)
}

View File

@@ -77,6 +77,24 @@ class TranslatedParenthesisCondition extends TranslatedFlexibleCondition {
}
}
class TranslatedNotCondition extends TranslatedFlexibleCondition {
override NotExpr expr;
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
child = this.getOperand() and
result = this.getConditionContext().getChildFalseSuccessor(this)
}
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
child = this.getOperand() and
result = this.getConditionContext().getChildTrueSuccessor(this)
}
override TranslatedCondition getOperand() {
result = getTranslatedCondition(expr.getOperand().getFullyConverted())
}
}
abstract class TranslatedNativeCondition extends TranslatedCondition, TTranslatedNativeCondition {
TranslatedNativeCondition() { this = TTranslatedNativeCondition(expr) }

View File

@@ -190,7 +190,10 @@ private predicate isNativeCondition(Expr expr) {
* depending on context.
*/
private predicate isFlexibleCondition(Expr expr) {
expr instanceof ParenthesisExpr and
(
expr instanceof ParenthesisExpr or
expr instanceof NotExpr
) and
usedAsCondition(expr) and
not isIRConstant(expr)
}
@@ -215,6 +218,11 @@ private predicate usedAsCondition(Expr expr) {
condExpr.getCondition().getFullyConverted() = expr and not condExpr.isTwoOperand()
)
or
exists(NotExpr notExpr |
notExpr.getOperand().getFullyConverted() = expr and
usedAsCondition(notExpr)
)
or
exists(ParenthesisExpr paren |
paren.getExpr() = expr and
usedAsCondition(paren)

View File

@@ -12,9 +12,6 @@ int getConstantValue(Instruction instr) {
or
result = getConstantValue(instr.(CopyInstruction).getSourceValue())
or
getConstantValue(instr.(LogicalNotInstruction).getUnary()) != 0 and
result = 0
or
exists(PhiInstruction phi |
phi = instr and
result = unique(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef()))
@@ -29,25 +26,28 @@ private predicate binaryInstructionOperands(BinaryInstruction instr, int left, i
pragma[noinline]
private int getBinaryInstructionValue(BinaryInstruction instr) {
exists(int left, int right | binaryInstructionOperands(instr, left, right) |
instr instanceof AddInstruction and result = add(left, right)
or
instr instanceof SubInstruction and result = sub(left, right)
or
instr instanceof MulInstruction and result = mul(left, right)
or
instr instanceof DivInstruction and result = div(left, right)
or
instr instanceof CompareEQInstruction and result = compareEQ(left, right)
or
instr instanceof CompareNEInstruction and result = compareNE(left, right)
or
instr instanceof CompareLTInstruction and result = compareLT(left, right)
or
instr instanceof CompareGTInstruction and result = compareGT(left, right)
or
instr instanceof CompareLEInstruction and result = compareLE(left, right)
or
instr instanceof CompareGEInstruction and result = compareGE(left, right)
exists(int left, int right |
binaryInstructionOperands(instr, left, right) and
(
instr instanceof AddInstruction and result = add(left, right)
or
instr instanceof SubInstruction and result = sub(left, right)
or
instr instanceof MulInstruction and result = mul(left, right)
or
instr instanceof DivInstruction and result = div(left, right)
or
instr instanceof CompareEQInstruction and result = compareEQ(left, right)
or
instr instanceof CompareNEInstruction and result = compareNE(left, right)
or
instr instanceof CompareLTInstruction and result = compareLT(left, right)
or
instr instanceof CompareGTInstruction and result = compareGT(left, right)
or
instr instanceof CompareLEInstruction and result = compareLE(left, right)
or
instr instanceof CompareGEInstruction and result = compareGE(left, right)
)
)
}

View File

@@ -1068,3 +1068,6 @@ module Ssa {
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
}
/** DEPRECATED: Alias for Ssa */
deprecated module SSA = Ssa;

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