Compare commits

..

32 Commits

Author SHA1 Message Date
Ian Lynagh
12ca801ecf Merge pull request #10350 from github/release-prep/2.10.5
Release preparation for version 2.10.5
2022-09-08 13:38:47 +01:00
github-actions[bot]
a9d80a5a48 Release preparation for version 2.10.5 2022-09-08 11:35:54 +00:00
Dave Bartolomeo
950445500a Merge pull request #10321 from MathiasVP/speedup-using-expired-stack-address-2
C++: Speedup 'cpp/using-expired-stack-address' by avoiding a large ne…
2022-09-07 09:33:20 -04:00
Mathias Vorreiter Pedersen
d6b8f25312 C++: Add more tests. 2022-09-06 15:22:10 +01:00
Mathias Vorreiter Pedersen
9745073024 C++: Speedup 'cpp/using-expired-stack-address' by avoiding a large negation. 2022-09-06 14:33:33 +01:00
Tom Hvitved
9fd9a04c2f Merge pull request #10277 from hvitved/csharp/dotnet-publish-inject
C#: Also inject `/p:UseSharedCompilation=false` into `dotnet publish`
2022-09-06 09:02:00 +02:00
Arthur Baars
e8d13d156d Merge pull request #10298 from aibaars/suppress-require
Ruby: exclude 'require' and 'require_relative' definitions from call graph
2022-09-05 20:58:38 +02:00
Arthur Baars
b2431d0b50 Ruby: exclude 'require' and 'require_relative' definitions from call graph
The syntax_suggest library redefines Kernel.require/require_relative.
Somehow this causes performance issues on ruby/ruby. As a workaround
we exclude 'require' and 'require_relative'.
2022-09-05 16:52:52 +02:00
Tom Hvitved
d8b352c2e6 C#: Use -p: instead of /p: with dotnet
Makes a difference for `dotnet run` where the option will otherwise be considered
an argument to the program that is run.
2022-09-05 10:40:00 +02:00
Tom Hvitved
623ba7926f C#: Fix /p:UseSharedCompilation=false tracer injection for dotnet run 2022-09-04 09:54:21 +02:00
Tom Hvitved
99d9fe14c8 C#: Also inject dotnet (pack|test|run) 2022-09-02 14:17:23 +02:00
Tom Hvitved
7c12139c9e C#: Also inject /p:UseSharedCompilation=false into dotnet publish 2022-09-02 13:51:22 +02:00
Ian Lynagh
7dc5bdafe3 Merge pull request #10186 from github/post-release-prep/codeql-cli-2.10.4
Post-release preparation for codeql-cli-2.10.4
2022-08-31 17:29:57 +01:00
Erik Krogh Kristensen
2aec53b7fb Merge pull request #10215 from erik-krogh/wayToLargeRangeAgainstRC
put a limit on the length of the equivalent range
2022-08-30 10:37:07 +02:00
erik-krogh
e2caf3e8c0 put a limit on the length of the equivalent range 2022-08-30 09:29:22 +02:00
github-actions[bot]
3b4ad3c4f1 Post-release preparation for codeql-cli-2.10.4 2022-08-26 09:32:11 +00:00
Ian Lynagh
f318dd5e0e Merge pull request #10174 from github/release-prep/2.10.4
Release preparation for version 2.10.4
2022-08-25 16:30:33 +01:00
Ian Lynagh
ef98ce16f8 Update javascript/ql/lib/CHANGELOG.md
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2022-08-25 14:25:38 +01:00
Ian Lynagh
711e769382 Update go/ql/lib/change-notes/released/0.2.4.md
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2022-08-25 14:25:30 +01:00
Ian Lynagh
b951e94d85 Update go/ql/lib/CHANGELOG.md
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2022-08-25 14:25:20 +01:00
Ian Lynagh
f20825ae55 Update python/ql/lib/CHANGELOG.md
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2022-08-25 14:25:10 +01:00
Ian Lynagh
b21883292d Update python/ql/lib/change-notes/released/0.5.4.md
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2022-08-25 14:24:58 +01:00
Ian Lynagh
a904438828 Update ruby/ql/lib/CHANGELOG.md
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2022-08-25 14:24:44 +01:00
Ian Lynagh
5cd4e0d3b1 Update ruby/ql/lib/change-notes/released/0.3.4.md
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2022-08-25 14:24:38 +01:00
Ian Lynagh
40b1825ef1 Update javascript/ql/lib/change-notes/released/0.2.4.md
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2022-08-25 14:24:20 +01:00
Ian Lynagh
9a3b540551 Update csharp/ql/src/change-notes/released/0.3.3.md
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2022-08-25 14:24:11 +01:00
Ian Lynagh
fb12d85d3c Update csharp/ql/src/CHANGELOG.md
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2022-08-25 14:24:00 +01:00
Ian Lynagh
0479a59640 Update csharp/ql/lib/change-notes/released/0.3.4.md
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2022-08-25 14:23:44 +01:00
Ian Lynagh
5e06277b38 Update cpp/ql/lib/change-notes/released/0.3.4.md
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2022-08-25 14:23:38 +01:00
Ian Lynagh
d0ecb9f54b Update csharp/ql/lib/CHANGELOG.md
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2022-08-25 14:23:32 +01:00
Ian Lynagh
badb2b7f13 Update cpp/ql/lib/CHANGELOG.md
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2022-08-25 14:23:25 +01:00
github-actions[bot]
0f63bc077f Release preparation for version 2.10.4 2022-08-25 12:52:26 +00:00
665 changed files with 49839 additions and 92334 deletions

View File

@@ -462,6 +462,9 @@
],
"SSA C#": [
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll",
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll",
"csharp/ql/lib/semmle/code/cil/internal/SsaImplCommon.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImplCommon.qll",
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/SsaImplCommon.qll"
@@ -581,22 +584,22 @@
],
"Swift declarations test file": [
"swift/ql/test/extractor-tests/declarations/declarations.swift",
"swift/ql/test/library-tests/ast/declarations.swift"
"swift/ql/test/library-tests/parent/declarations.swift"
],
"Swift statements test file": [
"swift/ql/test/extractor-tests/statements/statements.swift",
"swift/ql/test/library-tests/ast/statements.swift"
"swift/ql/test/library-tests/parent/statements.swift"
],
"Swift expressions test file": [
"swift/ql/test/extractor-tests/expressions/expressions.swift",
"swift/ql/test/library-tests/ast/expressions.swift"
"swift/ql/test/library-tests/parent/expressions.swift"
],
"Swift patterns test file": [
"swift/ql/test/extractor-tests/patterns/patterns.swift",
"swift/ql/test/library-tests/ast/patterns.swift"
"swift/ql/test/library-tests/parent/patterns.swift"
],
"IncompleteMultiCharacterSanitization JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/IncompleteMultiCharacterSanitizationQuery.qll",
"ruby/ql/lib/codeql/ruby/security/IncompleteMultiCharacterSanitizationQuery.qll"
]
}
}

View File

@@ -1,3 +1,21 @@
## 0.3.5
## 0.3.4
### Deprecated APIs
* Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.
### New Features
* Added support for getting the link targets of global and namespace variables.
* Added a `BlockAssignExpr` class, which models a `memcpy`-like operation used in compiler generated copy/move constructors and assignment operations.
### Minor Analysis Improvements
* All deprecated predicates/classes/modules that have been deprecated for over a year have been deleted.
## 0.3.3
### New Features

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* Added a `BlockAssignExpr` class, which models a `memcpy`-like operation used in compiler generated copy/move constructors and assignment operations.

View File

@@ -1,6 +0,0 @@
---
category: minorAnalysis
---
* All deprecated predicates/classes/modules that have been deprecated for over a year have been
deleted.

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* Added support for getting the link targets of global and namespace variables.

View File

@@ -1,5 +0,0 @@
---
category: deprecated
---
* Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.

View File

@@ -0,0 +1,15 @@
## 0.3.4
### Deprecated APIs
* Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.
### New Features
* Added support for getting the link targets of global and namespace variables.
* Added a `BlockAssignExpr` class, which models a `memcpy`-like operation used in compiler generated copy/move constructors and assignment operations.
### Minor Analysis Improvements
* All deprecated predicates/classes/modules that have been deprecated for over a year have been deleted.

View File

@@ -0,0 +1 @@
## 0.3.5

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.3.3
lastReleaseVersion: 0.3.5

View File

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

View File

@@ -404,10 +404,7 @@ class Class extends UserType {
* compiled for. For this reason, the `is_pod_class` predicate is
* generated by the extractor.
*/
predicate isPod() { is_pod_class(underlyingElement(this)) }
/** DEPRECATED: Alias for isPod */
deprecated predicate isPOD() { this.isPod() }
predicate isPOD() { is_pod_class(underlyingElement(this)) }
/**
* Holds if this class, struct or union is a standard-layout class

View File

@@ -79,17 +79,17 @@ predicate isAggregateType03(Type t) {
* user-defined copy assignment operator and no user-defined destructor.
* A POD class is a class that is either a POD-struct or a POD-union.
*/
predicate isPodClass03(Class c) {
predicate isPODClass03(Class c) {
isAggregateClass03(c) and
not exists(Variable v |
v.getDeclaringType() = c and
not v.isStatic()
|
not isPodType03(v.getType())
not isPODType03(v.getType())
or
exists(ArrayType at |
at = v.getType() and
not isPodType03(at.getBaseType())
not isPODType03(at.getBaseType())
)
or
v.getType() instanceof ReferenceType
@@ -104,9 +104,6 @@ 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):
@@ -115,17 +112,14 @@ deprecated predicate isPODClass03 = isPodClass03/1;
* such types and cv-qualified versions of these types (3.9.3) are
* collectively called POD types.
*/
predicate isPodType03(Type t) {
predicate isPODType03(Type t) {
exists(Type ut | ut = t.getUnderlyingType() |
isScalarType03(ut)
or
isPodClass03(ut)
isPODClass03(ut)
or
exists(ArrayType at | at = ut and isPodType03(at.getBaseType()))
exists(ArrayType at | at = ut and isPODType03(at.getBaseType()))
or
isPodType03(ut.(SpecifiedType).getUnspecifiedType())
isPODType03(ut.(SpecifiedType).getUnspecifiedType())
)
}
/** DEPRECATED: Alias for isPodType03 */
deprecated predicate isPODType03 = isPodType03/1;

View File

@@ -238,7 +238,7 @@ predicate dependsOnTransitive(DependsSource src, Element dest) {
/**
* A dependency that targets a TypeDeclarationEntry.
*/
private predicate dependsOnTde(Element src, Type t, TypeDeclarationEntry dest) {
private predicate dependsOnTDE(Element src, Type t, TypeDeclarationEntry dest) {
dependsOnTransitive(src, t) and
getDeclarationEntries(t, dest)
}
@@ -247,8 +247,8 @@ private predicate dependsOnTde(Element src, Type t, TypeDeclarationEntry dest) {
* A dependency that targets a visible TypeDeclarationEntry.
*/
pragma[noopt]
private predicate dependsOnVisibleTde(Element src, Type t, TypeDeclarationEntry dest) {
dependsOnTde(src, t, dest) and
private predicate dependsOnVisibleTDE(Element src, Type t, TypeDeclarationEntry dest) {
dependsOnTDE(src, t, dest) and
exists(File g | g = dest.getFile() |
exists(File f | f = src.getFile() | f.getAnIncludedFile*() = g)
)
@@ -260,8 +260,8 @@ private predicate dependsOnVisibleTde(Element src, Type t, TypeDeclarationEntry
private predicate dependsOnDeclarationEntry(Element src, DeclarationEntry dest) {
exists(Type t |
// dependency from a Type use -> unique visible TDE
dependsOnVisibleTde(src, t, dest) and
strictcount(TypeDeclarationEntry alt | dependsOnVisibleTde(src, t, alt)) = 1
dependsOnVisibleTDE(src, t, dest) and
strictcount(TypeDeclarationEntry alt | dependsOnVisibleTDE(src, t, alt)) = 1
)
or
exists(TypedefType mid |

View File

@@ -1,14 +1,11 @@
import semmle.code.cpp.Macro
/** A macro defining NULL. */
class NullMacro extends Macro {
NullMacro() { this.getHead() = "NULL" }
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()) }
NULL() { exists(NULLMacro nm | this = nm.getAnInvocation().getAnExpandedElement()) }
}

View File

@@ -474,7 +474,7 @@ module FlowVar_internal {
}
/** Type-specialized version of `getEnclosingElement`. */
private ControlFlowNode getCfnParent(ControlFlowNode node) { result = node.getEnclosingElement() }
private ControlFlowNode getCFNParent(ControlFlowNode node) { result = node.getEnclosingElement() }
/**
* A for-loop or while-loop whose condition is always true upon entry but not
@@ -526,7 +526,7 @@ module FlowVar_internal {
}
private predicate bbInLoopCondition(BasicBlock bb) {
getCfnParent*(bb.getANode()) = this.(Loop).getCondition()
getCFNParent*(bb.getANode()) = this.(Loop).getCondition()
}
private predicate bbInLoop(BasicBlock bb) {

View File

@@ -0,0 +1,18 @@
private import semmle.code.cpp.ir.IR
private import SsaInternals as Ssa
class BasicBlock = IRBlock;
class SourceVariable = Ssa::SourceVariable;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class ExitBasicBlock extends IRBlock {
ExitBasicBlock() { this.getLastInstruction() instanceof ExitFunctionInstruction }
}
predicate variableWrite = Ssa::variableWrite/4;
predicate variableRead = Ssa::variableRead/4;

View File

@@ -1,10 +1,10 @@
import SsaImplCommon
private import cpp as Cpp
private import semmle.code.cpp.ir.IR
private import DataFlowUtil
private import DataFlowImplCommon as DataFlowImplCommon
private import semmle.code.cpp.models.interfaces.Allocation as Alloc
private import semmle.code.cpp.models.interfaces.DataFlow as DataFlow
private import SsaImplCommon as SsaImplCommon
private module SourceVariables {
private newtype TSourceVariable =
@@ -38,6 +38,8 @@ private module SourceVariables {
}
}
import SourceVariables
cached
private newtype TDefOrUse =
TExplicitDef(Instruction store) { explicitWrite(_, store, _) } or
@@ -84,7 +86,7 @@ abstract class Def extends DefOrUse {
Instruction getInstruction() { result = store }
/** Gets the variable that is defined by this definition. */
abstract SourceVariables::SourceVariable getSourceVariable();
abstract SourceVariable getSourceVariable();
/** Holds if this definition is guaranteed to happen. */
abstract predicate isCertain();
@@ -101,10 +103,10 @@ abstract class Def extends DefOrUse {
private class ExplicitDef extends Def, TExplicitDef {
ExplicitDef() { this = TExplicitDef(store) }
override SourceVariables::SourceVariable getSourceVariable() {
override SourceVariable getSourceVariable() {
exists(VariableInstruction var |
explicitWrite(_, this.getInstruction(), var) and
result.(SourceVariables::SourceIRVariable).getIRVariable() = var.getIRVariable()
result.(SourceIRVariable).getIRVariable() = var.getIRVariable()
)
}
@@ -114,11 +116,11 @@ private class ExplicitDef extends Def, TExplicitDef {
private class ParameterDef extends Def, TInitializeParam {
ParameterDef() { this = TInitializeParam(store) }
override SourceVariables::SourceVariable getSourceVariable() {
result.(SourceVariables::SourceIRVariable).getIRVariable() =
override SourceVariable getSourceVariable() {
result.(SourceIRVariable).getIRVariable() =
store.(InitializeParameterInstruction).getIRVariable()
or
result.(SourceVariables::SourceIRVariableIndirection).getUnderlyingIRVariable() =
result.(SourceIRVariableIndirection).getUnderlyingIRVariable() =
store.(InitializeIndirectionInstruction).getIRVariable()
}
@@ -136,7 +138,7 @@ abstract class Use extends DefOrUse {
override string toString() { result = "Use" }
/** Gets the variable that is used by this use. */
abstract SourceVariables::SourceVariable getSourceVariable();
abstract SourceVariable getSourceVariable();
override IRBlock getBlock() { result = use.getUse().getBlock() }
@@ -146,14 +148,12 @@ abstract class Use extends DefOrUse {
private class ExplicitUse extends Use, TExplicitUse {
ExplicitUse() { this = TExplicitUse(use) }
override SourceVariables::SourceVariable getSourceVariable() {
override SourceVariable getSourceVariable() {
exists(VariableInstruction var |
use.getDef() = var and
if use.getUse() instanceof ReadSideEffectInstruction
then
result.(SourceVariables::SourceIRVariableIndirection).getUnderlyingIRVariable() =
var.getIRVariable()
else result.(SourceVariables::SourceIRVariable).getIRVariable() = var.getIRVariable()
then result.(SourceIRVariableIndirection).getUnderlyingIRVariable() = var.getIRVariable()
else result.(SourceIRVariable).getIRVariable() = var.getIRVariable()
)
}
}
@@ -161,11 +161,10 @@ private class ExplicitUse extends Use, TExplicitUse {
private class ReturnParameterIndirection extends Use, TReturnParamIndirection {
ReturnParameterIndirection() { this = TReturnParamIndirection(use) }
override SourceVariables::SourceVariable getSourceVariable() {
override SourceVariable getSourceVariable() {
exists(ReturnIndirectionInstruction ret |
returnParameterIndirection(use, ret) and
result.(SourceVariables::SourceIRVariableIndirection).getUnderlyingIRVariable() =
ret.getIRVariable()
result.(SourceIRVariableIndirection).getUnderlyingIRVariable() = ret.getIRVariable()
)
}
}
@@ -611,45 +610,27 @@ private module Cached {
import Cached
private module SsaInput implements SsaImplCommon::InputSig {
private import semmle.code.cpp.ir.IR
class BasicBlock = IRBlock;
class SourceVariable = SourceVariables::SourceVariable;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class ExitBasicBlock extends IRBlock {
ExitBasicBlock() { this.getLastInstruction() instanceof ExitFunctionInstruction }
}
/**
* Holds if the `i`'th write in block `bb` writes to the variable `v`.
* `certain` is `true` if the write is guaranteed to overwrite the entire variable.
*/
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
DataFlowImplCommon::forceCachingInSameStage() and
exists(Def def |
def.hasIndexInBlock(bb, i) and
v = def.getSourceVariable() and
(if def.isCertain() then certain = true else certain = false)
)
}
/**
* Holds if the `i`'th read in block `bb` reads to the variable `v`.
* `certain` is `true` if the read is guaranteed. For C++, this is always the case.
*/
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(Use use |
use.hasIndexInBlock(bb, i) and
v = use.getSourceVariable() and
certain = true
)
}
/**
* Holds if the `i`'th write in block `bb` writes to the variable `v`.
* `certain` is `true` if the write is guaranteed to overwrite the entire variable.
*/
predicate variableWrite(IRBlock bb, int i, SourceVariable v, boolean certain) {
DataFlowImplCommon::forceCachingInSameStage() and
exists(Def def |
def.hasIndexInBlock(bb, i) and
v = def.getSourceVariable() and
(if def.isCertain() then certain = true else certain = false)
)
}
import SsaImplCommon::Make<SsaInput>
/**
* Holds if the `i`'th read in block `bb` reads to the variable `v`.
* `certain` is `true` if the read is guaranteed. For C++, this is always the case.
*/
predicate variableRead(IRBlock bb, int i, SourceVariable v, boolean certain) {
exists(Use use |
use.hasIndexInBlock(bb, i) and
v = use.getSourceVariable() and
certain = true
)
}

View File

@@ -165,7 +165,7 @@ private ControlFlowNode mostRecentSideEffect(ControlFlowNode node) {
/** Used to represent the "global value number" of an expression. */
cached
private newtype GvnBase =
private newtype GVNBase =
GVN_IntConst(int val, Type t) { mk_IntConst(val, t, _) } or
GVN_FloatConst(float val, Type t) { mk_FloatConst(val, t, _) } or
// If the local variable does not have a defining value, then
@@ -221,8 +221,8 @@ private newtype GvnBase =
* expression with this `GVN` and using its `toString` and `getLocation`
* methods.
*/
class GVN extends GvnBase {
GVN() { this instanceof GvnBase }
class GVN extends GVNBase {
GVN() { this instanceof GVNBase }
/** Gets an expression that has this GVN. */
Expr getAnExpr() { this = globalValueNumber(result) }

View File

@@ -63,17 +63,17 @@ class VariableDeclarationLine extends TVariableDeclarationInfo {
/**
* Gets a `VariableDeclarationEntry` on this line.
*/
VariableDeclarationEntry getAVde() { vdeInfo(result, c, f, line) }
VariableDeclarationEntry getAVDE() { vdeInfo(result, c, f, line) }
/**
* Gets the start column of the first `VariableDeclarationEntry` on this line.
*/
int getStartColumn() { result = min(this.getAVde().getLocation().getStartColumn()) }
int getStartColumn() { result = min(this.getAVDE().getLocation().getStartColumn()) }
/**
* Gets the end column of the last `VariableDeclarationEntry` on this line.
*/
int getEndColumn() { result = max(this.getAVde().getLocation().getEndColumn()) }
int getEndColumn() { result = max(this.getAVDE().getLocation().getEndColumn()) }
/**
* Gets the rank of this `VariableDeclarationLine` in its file and class
@@ -134,13 +134,13 @@ class VariableDeclarationGroup extends VariableDeclarationLine {
count(VariableDeclarationLine l |
l = this.getProximateNext*()
|
l.getAVde().getVariable().getName()
l.getAVDE().getVariable().getName()
)
}
override string toString() {
this.getCount() = 1 and
result = "declaration of " + this.getAVde().getVariable().getName()
result = "declaration of " + this.getAVDE().getVariable().getName()
or
this.getCount() > 1 and
result = "group of " + this.getCount() + " fields here"

View File

@@ -29,4 +29,7 @@ where
n = strictcount(ComplexStmt s | s = b.getAStmt()) and
n > 3 and
complexStmt = b.getAStmt()
select b, "Block with too many statements (" + n.toString() + " complex statements in the block)."
select b,
"Block with too many statements (" + n.toString() +
" complex statements in the block). Complex statements at: $@", complexStmt,
complexStmt.toString()

View File

@@ -110,4 +110,4 @@ where
emptyBlock(s, eb) and
not emptyBlockContainsNonchild(eb) and
not lineComment(eb)
select eb, "Empty block without comment."
select eb, "Empty block without comment"

View File

@@ -16,7 +16,7 @@ import cpp
class JumpTarget extends Stmt {
JumpTarget() { exists(GotoStmt g | g.getTarget() = this) }
FunctionDeclarationEntry getFde() { result.getBlock() = this.getParentStmt+() }
FunctionDeclarationEntry getFDE() { result.getBlock() = this.getParentStmt+() }
predicate isForward() {
exists(GotoStmt g | g.getTarget() = this |
@@ -33,8 +33,8 @@ class JumpTarget extends Stmt {
from FunctionDeclarationEntry fde, int nforward, int nbackward
where
nforward = strictcount(JumpTarget t | t.getFde() = fde and t.isForward()) and
nbackward = strictcount(JumpTarget t | t.getFde() = fde and t.isBackward()) and
nforward = strictcount(JumpTarget t | t.getFDE() = fde and t.isForward()) and
nbackward = strictcount(JumpTarget t | t.getFDE() = fde and t.isBackward()) and
nforward != 1 and
nbackward != 1
select fde,

View File

@@ -1,3 +1,11 @@
## 0.3.4
## 0.3.3
### Minor Analysis Improvements
* The "Cleartext storage of sensitive information in buffer" (`cpp/cleartext-storage-buffer`) query has been improved to produce fewer false positives.
## 0.3.2
### Minor Analysis Improvements

View File

@@ -12,4 +12,4 @@
import CommentedOutCode
from CommentedOutCode comment
select comment, "This comment appears to contain commented-out code."
select comment, "This comment appears to contain commented-out code"

View File

@@ -1,6 +1,7 @@
/**
* @name Sign check of bitwise operation
* @description Checking the sign of the result of a bitwise operation may yield unexpected results.
* @description Checking the sign of a bitwise operation often has surprising
* edge cases.
* @kind problem
* @problem.severity warning
* @precision high
@@ -25,4 +26,4 @@ where
forall(int op | op = lhs.(BitwiseAndExpr).getAnOperand().getValue().toInt() | op < 0) and
// exception for cases involving macros
not e.isAffectedByMacro()
select e, "Potentially unsafe sign check of a bitwise operation."
select e, "Potential unsafe sign check of a bitwise operation."

View File

@@ -21,4 +21,4 @@ where
FloatingPointType and
not ro.getAnOperand().isConstant() and // comparisons to constants generate too many false positives
not left.(VariableAccess).getTarget() = right.(VariableAccess).getTarget() // skip self comparison
select ro, "Equality checks on floating point values can yield unexpected results."
select ro, "Equality test on floating point values may not behave as expected."

View File

@@ -13,11 +13,10 @@
import cpp
from EnumSwitch es, float missing, float total, EnumConstant case
from EnumSwitch es, float missing, float total
where
not es.hasDefaultCase() and
missing = count(es.getAMissingCase()) and
total = missing + count(es.getASwitchCase()) and
missing / total < 0.3 and
case = es.getAMissingCase()
select es, "Switch statement does not have a case for $@.", case, case.getName()
missing / total < 0.3
select es, "Switch statement is missing case for " + es.getAMissingCase().getName()

View File

@@ -163,19 +163,46 @@ TGlobalAddress globalAddress(Instruction instr) {
result = globalAddress(instr.(PointerOffsetInstruction).getLeft())
}
/** Gets a `StoreInstruction` that may be executed after executing `store`. */
pragma[inline]
StoreInstruction getAStoreStrictlyAfter(StoreInstruction store) {
exists(IRBlock block, int index1, int index2 |
block.getInstruction(index1) = store and
block.getInstruction(index2) = result and
index2 > index1
/**
* Gets a first `StoreInstruction` that writes to address `globalAddress` reachable
* from `block`.
*/
StoreInstruction getFirstStore(IRBlock block, TGlobalAddress globalAddress) {
1 = getStoreRank(result, block, globalAddress)
or
not exists(getStoreRank(_, block, globalAddress)) and
result = getFirstStore(block.getASuccessor(), globalAddress)
}
/**
* Gets the rank of `store` in block `block` (i.e., a rank of `1` means that it is the
* first `store` to write to `globalAddress`, a rank of `2` means it's the second, etc.)
*/
int getStoreRank(StoreInstruction store, IRBlock block, TGlobalAddress globalAddress) {
blockStoresToAddress(block, _, store, globalAddress) and
store =
rank[result](StoreInstruction anotherStore, int i |
blockStoresToAddress(_, i, anotherStore, globalAddress)
|
anotherStore order by i
)
}
/**
* Gets a next subsequent `StoreInstruction` to write to `globalAddress`
* after `store` has done so.
*/
StoreInstruction getANextStoreTo(StoreInstruction store, TGlobalAddress globalAddress) {
exists(IRBlock block, int rnk |
rnk = getStoreRank(store, block, globalAddress) and
rnk + 1 = getStoreRank(result, block, globalAddress)
)
or
exists(IRBlock block1, IRBlock block2 |
store.getBlock() = block1 and
result.getBlock() = block2 and
block1.getASuccessor+() = block2
exists(IRBlock block, int rnk, IRBlock succ |
rnk = getStoreRank(store, block, globalAddress) and
not rnk + 1 = getStoreRank(_, block, globalAddress) and
succ = block.getASuccessor() and
result = getFirstStore(succ, globalAddress)
)
}
@@ -192,7 +219,7 @@ predicate stackAddressEscapes(
stackPointerFlowsToUse(store.getSourceValue(), vai)
) and
// Ensure there's no subsequent store that overrides the global address.
not globalAddress = globalAddress(getAStoreStrictlyAfter(store).getDestinationAddress())
not exists(getANextStoreTo(store, globalAddress))
}
predicate blockStoresToAddress(

View File

@@ -13,7 +13,7 @@ import SAL
from Parameter p, Call c, Expr arg
where
any(SalNotNull a).getDeclaration() = p and
any(SALNotNull a).getDeclaration() = p and
c.getTarget() = p.getFunction() and
arg = c.getArgument(p.getIndex()) and
nullValue(arg)

View File

@@ -18,7 +18,7 @@ from Function f, FunctionCall call
where
call.getTarget() = f and
call instanceof ExprInVoidContext and
any(SalCheckReturn a).getDeclaration() = f and
any(SALCheckReturn a).getDeclaration() = f and
not getOptions().okToIgnoreReturnValue(call)
select call, "Return value of $@ discarded although a SAL annotation " + "requires inspecting it.",
f, f.getName()

View File

@@ -11,7 +11,7 @@ import SAL
/** Holds if `e` has SAL annotation `name`. */
predicate hasAnnotation(DeclarationEntry e, string name) {
exists(SalAnnotation a |
exists(SALAnnotation a |
a.getMacro().getName() = name and
a.getDeclarationEntry() = e
)
@@ -21,7 +21,7 @@ predicate hasAnnotation(DeclarationEntry e, string name) {
predicate inheritsDeclAnnotations(DeclarationEntry e) {
// Is directly annotated
e.isDefinition() and
exists(SalAnnotation a | a.getMacro().getName() = "_Use_decl_annotations_" |
exists(SALAnnotation a | a.getMacro().getName() = "_Use_decl_annotations_" |
a.getDeclarationEntry() = e
)
or

View File

@@ -8,8 +8,8 @@ import cpp
/**
* A SAL macro defined in `sal.h` or a similar header file.
*/
class SalMacro extends Macro {
SalMacro() {
class SALMacro extends Macro {
SALMacro() {
this.getFile().getBaseName() =
["sal.h", "specstrings_strict.h", "specstrings.h", "w32p.h", "minwindef.h"] and
(
@@ -22,18 +22,15 @@ class SalMacro extends Macro {
}
}
/** DEPRECATED: Alias for SalMacro */
deprecated class SALMacro = SalMacro;
pragma[noinline]
private predicate isTopLevelMacroAccess(MacroAccess ma) { not exists(ma.getParentInvocation()) }
/**
* An invocation of a SAL macro (excluding invocations inside other macros).
*/
class SalAnnotation extends MacroInvocation {
SalAnnotation() {
this.getMacro() instanceof SalMacro and
class SALAnnotation extends MacroInvocation {
SALAnnotation() {
this.getMacro() instanceof SALMacro and
isTopLevelMacroAccess(this)
}
@@ -50,29 +47,23 @@ class SalAnnotation extends MacroInvocation {
}
}
/** DEPRECATED: Alias for SalAnnotation */
deprecated class SALAnnotation = SalAnnotation;
/**
* A SAL macro indicating that the return value of a function should always be
* checked.
*/
class SalCheckReturn extends SalAnnotation {
SalCheckReturn() {
this.getMacro().(SalMacro).getName() = ["_Check_return_", "_Must_inspect_result_"]
class SALCheckReturn extends SALAnnotation {
SALCheckReturn() {
this.getMacro().(SALMacro).getName() = ["_Check_return_", "_Must_inspect_result_"]
}
}
/** DEPRECATED: Alias for SalCheckReturn */
deprecated class SALCheckReturn = SalCheckReturn;
/**
* A SAL macro indicating that a pointer variable or return value should not be
* `NULL`.
*/
class SalNotNull extends SalAnnotation {
SalNotNull() {
exists(SalMacro m | m = this.getMacro() |
class SALNotNull extends SALAnnotation {
SALNotNull() {
exists(SALMacro m | m = this.getMacro() |
not m.getName().matches("%\\_opt\\_%") and
(
m.getName().matches("_In%") or
@@ -89,15 +80,12 @@ class SalNotNull extends SalAnnotation {
}
}
/** DEPRECATED: Alias for SalNotNull */
deprecated class SALNotNull = SalNotNull;
/**
* A SAL macro indicating that a value may be `NULL`.
*/
class SalMaybeNull extends SalAnnotation {
SalMaybeNull() {
exists(SalMacro m | m = this.getMacro() |
class SALMaybeNull extends SALAnnotation {
SALMaybeNull() {
exists(SALMacro m | m = this.getMacro() |
m.getName().matches("%\\_opt\\_%") or
m.getName().matches("\\_Ret_maybenull\\_%") or
m.getName() = "_Result_nullonfailure_"
@@ -105,17 +93,14 @@ class SalMaybeNull extends SalAnnotation {
}
}
/** DEPRECATED: Alias for SalMaybeNull */
deprecated class SALMaybeNull = SalMaybeNull;
/**
* A parameter annotated by one or more SAL annotations.
*/
class SalParameter extends Parameter {
class SALParameter extends Parameter {
/** One of this parameter's annotations. */
SalAnnotation a;
SALAnnotation a;
SalParameter() { annotatesAt(a, this.getADeclarationEntry(), _, _) }
SALParameter() { annotatesAt(a, this.getADeclarationEntry(), _, _) }
predicate isIn() { a.getMacroName().toLowerCase().matches("%\\_in%") }
@@ -124,17 +109,14 @@ class SalParameter extends Parameter {
predicate isInOut() { a.getMacroName().toLowerCase().matches("%\\_inout%") }
}
/** DEPRECATED: Alias for SalParameter */
deprecated class SALParameter = SalParameter;
///////////////////////////////////////////////////////////////////////////////
// Implementation details
/**
* Holds if `a` annotates the declaration entry `d` and
* its start position is the `idx`th position in `file` that holds a SAL element.
*/
private predicate annotatesAt(SalAnnotation a, DeclarationEntry d, File file, int idx) {
annotatesAtPosition(a.(SalElement).getStartPosition(), d, file, idx)
private predicate annotatesAt(SALAnnotation a, DeclarationEntry d, File file, int idx) {
annotatesAtPosition(a.(SALElement).getStartPosition(), d, file, idx)
}
/**
@@ -145,12 +127,12 @@ private predicate annotatesAt(SalAnnotation a, DeclarationEntry d, File file, in
// For performance reasons, do not mention the annotation itself here,
// but compute with positions instead. This performs better on databases
// with many annotations at the same position.
private predicate annotatesAtPosition(SalPosition pos, DeclarationEntry d, File file, int idx) {
private predicate annotatesAtPosition(SALPosition pos, DeclarationEntry d, File file, int idx) {
pos = salRelevantPositionAt(file, idx) and
salAnnotationPos(pos) and
(
// Base case: `pos` right before `d`
d.(SalElement).getStartPosition() = salRelevantPositionAt(file, idx + 1)
d.(SALElement).getStartPosition() = salRelevantPositionAt(file, idx + 1)
or
// Recursive case: `pos` right before some annotation on `d`
annotatesAtPosition(_, d, file, idx + 1)
@@ -161,10 +143,10 @@ private predicate annotatesAtPosition(SalPosition pos, DeclarationEntry d, File
* A SAL element, that is, a SAL annotation or a declaration entry
* that may have SAL annotations.
*/
library class SalElement extends Element {
SalElement() {
containsSalAnnotation(this.(DeclarationEntry).getFile()) or
this instanceof SalAnnotation
library class SALElement extends Element {
SALElement() {
containsSALAnnotation(this.(DeclarationEntry).getFile()) or
this instanceof SALAnnotation
}
predicate hasStartPosition(File file, int line, int col) {
@@ -191,28 +173,25 @@ library class SalElement extends Element {
)
}
SalPosition getStartPosition() {
SALPosition getStartPosition() {
exists(File file, int line, int col |
this.hasStartPosition(file, line, col) and
result = MkSalPosition(file, line, col)
result = MkSALPosition(file, line, col)
)
}
}
/** DEPRECATED: Alias for SalElement */
deprecated class SALElement = SalElement;
/** Holds if `file` contains a SAL annotation. */
pragma[noinline]
private predicate containsSalAnnotation(File file) { any(SalAnnotation a).getFile() = file }
private predicate containsSALAnnotation(File file) { any(SALAnnotation a).getFile() = file }
/**
* A source-file position of a `SALElement`. Unlike location, this denotes a
* point in the file rather than a range.
*/
private newtype SalPosition =
MkSalPosition(File file, int line, int col) {
exists(SalElement e |
private newtype SALPosition =
MkSALPosition(File file, int line, int col) {
exists(SALElement e |
e.hasStartPosition(file, line, col)
or
e.hasEndPosition(file, line, col)
@@ -221,18 +200,18 @@ private newtype SalPosition =
/** Holds if `pos` is the start position of a SAL annotation. */
pragma[noinline]
private predicate salAnnotationPos(SalPosition pos) {
any(SalAnnotation a).(SalElement).getStartPosition() = pos
private predicate salAnnotationPos(SALPosition pos) {
any(SALAnnotation a).(SALElement).getStartPosition() = pos
}
/**
* Gets the `idx`th position in `file` that holds a SAL element,
* ordering positions lexicographically by their start line and start column.
*/
private SalPosition salRelevantPositionAt(File file, int idx) {
private SALPosition salRelevantPositionAt(File file, int idx) {
result =
rank[idx](SalPosition pos, int line, int col |
pos = MkSalPosition(file, line, col)
rank[idx](SALPosition pos, int line, int col |
pos = MkSALPosition(file, line, col)
|
pos order by line, col
)

View File

@@ -24,7 +24,7 @@ where
if e = DefinitionInSnapshot()
then defined = ""
else
if e = SuggestiveSalAnnotation()
if e = SuggestiveSALAnnotation()
then defined = "externally defined (SAL) "
else defined = "externally defined (CSV) "
)

View File

@@ -149,7 +149,7 @@ newtype Evidence =
* The function is externally defined, but the parameter has an `_out` SAL annotation which
* suggests that it is initialized in the function.
*/
SuggestiveSalAnnotation() or
SuggestiveSALAnnotation() or
/**
* We have been given a CSV file which indicates this parameter is conditionally initialized.
*/
@@ -198,8 +198,8 @@ class InitializationFunction extends Function {
or
// If we have no definition, we look at SAL annotations
not this.hasDefinition() and
this.getParameter(i).(SalParameter).isOut() and
evidence = SuggestiveSalAnnotation()
this.getParameter(i).(SALParameter).isOut() and
evidence = SuggestiveSALAnnotation()
or
// We have some external information that this function conditionally initializes
not this.hasDefinition() and

View File

@@ -19,8 +19,8 @@ import DataFlow::PathGraph
/**
* A configuration for tracking XML objects and their states.
*/
class XxeConfiguration extends DataFlow::Configuration {
XxeConfiguration() { this = "XXEConfiguration" }
class XXEConfiguration extends DataFlow::Configuration {
XXEConfiguration() { this = "XXEConfiguration" }
override predicate isSource(DataFlow::Node node, string flowstate) {
any(XmlLibrary l).configurationSource(node, flowstate)
@@ -45,7 +45,7 @@ class XxeConfiguration extends DataFlow::Configuration {
}
}
from XxeConfiguration conf, DataFlow::PathNode source, DataFlow::PathNode sink
from XXEConfiguration conf, DataFlow::PathNode source, DataFlow::PathNode sink
where conf.hasFlowPath(source, sink)
select sink, source, sink,
"This $@ is not configured to prevent an XML external entity (XXE) attack.", source, "XML parser"

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The alert message of many queries have been changed to make the message consistent with other languages.

View File

@@ -1,4 +1,5 @@
---
category: minorAnalysis
---
## 0.3.3
### Minor Analysis Improvements
* The "Cleartext storage of sensitive information in buffer" (`cpp/cleartext-storage-buffer`) query has been improved to produce fewer false positives.

View File

@@ -0,0 +1 @@
## 0.3.4

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.3.2
lastReleaseVersion: 0.3.4

View File

@@ -16,17 +16,17 @@ import cpp
// pointers. This will obviously not catch code that uses inline assembly to achieve
// self-modification, nor will it spot the use of OS mechanisms to write into process
// memory (such as WriteProcessMemory under Windows).
predicate maybeSmcConversion(Type t1, Type t2) {
predicate maybeSMCConversion(Type t1, Type t2) {
t1 instanceof FunctionPointerType and
t2 instanceof PointerType and
not t2 instanceof FunctionPointerType and
not t2 instanceof VoidPointerType
or
maybeSmcConversion(t2, t1)
maybeSMCConversion(t2, t1)
}
from Expr e
where
e.fromSource() and
maybeSmcConversion(e.getUnderlyingType(), e.getActualType())
maybeSMCConversion(e.getUnderlyingType(), e.getActualType())
select e, "AV Rule 2: There shall not be any self-modifying code."

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 0.3.3-dev
version: 0.3.4
groups:
- cpp
- queries

View File

@@ -1,5 +1,5 @@
import cpp
from Class c, boolean ispod
where if c.isPod() then ispod = true else ispod = false
where if c.isPOD() then ispod = true else ispod = false
select c, ispod

View File

@@ -1,5 +1,5 @@
import semmle.code.cpp.PODType03
from Class c, boolean ispod
where if isPodClass03(c) then ispod = true else ispod = false
where if isPODClass03(c) then ispod = true else ispod = false
select c, ispod

View File

@@ -1,4 +1,4 @@
import Microsoft.SAL
from SalAnnotation a
from SALAnnotation a
select a, a.getDeclaration()

View File

@@ -1,3 +1,3 @@
| empty_block.cpp:9:10:9:11 | { ... } | Empty block without comment. |
| empty_block.cpp:12:10:13:3 | { ... } | Empty block without comment. |
| empty_block.cpp:20:10:21:3 | { ... } | Empty block without comment. |
| empty_block.cpp:9:10:9:11 | { ... } | Empty block without comment |
| empty_block.cpp:12:10:13:3 | { ... } | Empty block without comment |
| empty_block.cpp:20:10:21:3 | { ... } | Empty block without comment |

View File

@@ -1,20 +1,20 @@
| test2.cpp:37:1:37:39 | // int myFunction() { return myValue; } | This comment appears to contain commented-out code. |
| test2.cpp:39:1:39:45 | // int myFunction() const { return myValue; } | This comment appears to contain commented-out code. |
| test2.cpp:41:1:41:54 | // int myFunction() const noexcept { return myValue; } | This comment appears to contain commented-out code. |
| test2.cpp:43:1:43:18 | // #define MYMACRO | This comment appears to contain commented-out code. |
| test2.cpp:45:1:45:23 | // #include "include.h" | This comment appears to contain commented-out code. |
| test2.cpp:47:1:51:2 | /*\n#ifdef\nvoid myFunction();\n#endif\n*/ | This comment appears to contain commented-out code. |
| test2.cpp:59:1:59:24 | // #if(defined(MYMACRO)) | This comment appears to contain commented-out code. |
| test2.cpp:63:1:63:15 | // #pragma once | This comment appears to contain commented-out code. |
| test2.cpp:65:1:65:17 | // # pragma once | This comment appears to contain commented-out code. |
| test2.cpp:67:1:67:19 | /*#error"myerror"*/ | This comment appears to contain commented-out code. |
| test2.cpp:91:1:95:2 | /*\n#ifdef MYMACRO\n\t// ...\n#endif // #ifdef MYMACRO\n*/ | This comment appears to contain commented-out code. |
| test2.cpp:107:21:107:43 | // #include "config2.h" | This comment appears to contain commented-out code. |
| test2.cpp:115:16:115:35 | /* #ifdef MYMACRO */ | This comment appears to contain commented-out code. |
| test2.cpp:117:1:117:24 | // commented_out_code(); | This comment appears to contain commented-out code. |
| test2.cpp:120:2:120:25 | // commented_out_code(); | This comment appears to contain commented-out code. |
| test.c:2:1:2:22 | // commented out code; | This comment appears to contain commented-out code. |
| test.c:4:1:7:8 | // some; | This comment appears to contain commented-out code. |
| test.c:9:1:13:8 | // also; | This comment appears to contain commented-out code. |
| test.c:21:1:26:2 | /*\n some;\n commented;\n out;\n code;\n*/ | This comment appears to contain commented-out code. |
| test.c:28:1:34:2 | /*\n also;\n this\n is;\n commented-out\n code;\n*/ | This comment appears to contain commented-out code. |
| test2.cpp:37:1:37:39 | // int myFunction() { return myValue; } | This comment appears to contain commented-out code |
| test2.cpp:39:1:39:45 | // int myFunction() const { return myValue; } | This comment appears to contain commented-out code |
| test2.cpp:41:1:41:54 | // int myFunction() const noexcept { return myValue; } | This comment appears to contain commented-out code |
| test2.cpp:43:1:43:18 | // #define MYMACRO | This comment appears to contain commented-out code |
| test2.cpp:45:1:45:23 | // #include "include.h" | This comment appears to contain commented-out code |
| test2.cpp:47:1:51:2 | /*\n#ifdef\nvoid myFunction();\n#endif\n*/ | This comment appears to contain commented-out code |
| test2.cpp:59:1:59:24 | // #if(defined(MYMACRO)) | This comment appears to contain commented-out code |
| test2.cpp:63:1:63:15 | // #pragma once | This comment appears to contain commented-out code |
| test2.cpp:65:1:65:17 | // # pragma once | This comment appears to contain commented-out code |
| test2.cpp:67:1:67:19 | /*#error"myerror"*/ | This comment appears to contain commented-out code |
| test2.cpp:91:1:95:2 | /*\n#ifdef MYMACRO\n\t// ...\n#endif // #ifdef MYMACRO\n*/ | This comment appears to contain commented-out code |
| test2.cpp:107:21:107:43 | // #include "config2.h" | This comment appears to contain commented-out code |
| test2.cpp:115:16:115:35 | /* #ifdef MYMACRO */ | This comment appears to contain commented-out code |
| test2.cpp:117:1:117:24 | // commented_out_code(); | This comment appears to contain commented-out code |
| test2.cpp:120:2:120:25 | // commented_out_code(); | This comment appears to contain commented-out code |
| test.c:2:1:2:22 | // commented out code; | This comment appears to contain commented-out code |
| test.c:4:1:7:8 | // some; | This comment appears to contain commented-out code |
| test.c:9:1:13:8 | // also; | This comment appears to contain commented-out code |
| test.c:21:1:26:2 | /*\n some;\n commented;\n out;\n code;\n*/ | This comment appears to contain commented-out code |
| test.c:28:1:34:2 | /*\n also;\n this\n is;\n commented-out\n code;\n*/ | This comment appears to contain commented-out code |

View File

@@ -1,4 +1,4 @@
| bsc.cpp:2:10:2:32 | ... > ... | Potentially unsafe sign check of a bitwise operation. |
| bsc.cpp:6:10:6:32 | ... > ... | Potentially unsafe sign check of a bitwise operation. |
| bsc.cpp:18:10:18:28 | ... > ... | Potentially unsafe sign check of a bitwise operation. |
| bsc.cpp:22:10:22:28 | ... < ... | Potentially unsafe sign check of a bitwise operation. |
| bsc.cpp:2:10:2:32 | ... > ... | Potential unsafe sign check of a bitwise operation. |
| bsc.cpp:6:10:6:32 | ... > ... | Potential unsafe sign check of a bitwise operation. |
| bsc.cpp:18:10:18:28 | ... > ... | Potential unsafe sign check of a bitwise operation. |
| bsc.cpp:22:10:22:28 | ... < ... | Potential unsafe sign check of a bitwise operation. |

View File

@@ -1,4 +1,4 @@
| c.c:10:5:10:10 | ... == ... | Equality checks on floating point values can yield unexpected results. |
| c.c:14:5:14:14 | ... == ... | Equality checks on floating point values can yield unexpected results. |
| c.c:16:5:16:12 | ... == ... | Equality checks on floating point values can yield unexpected results. |
| c.c:17:5:17:12 | ... == ... | Equality checks on floating point values can yield unexpected results. |
| c.c:10:5:10:10 | ... == ... | Equality test on floating point values may not behave as expected. |
| c.c:14:5:14:14 | ... == ... | Equality test on floating point values may not behave as expected. |
| c.c:16:5:16:12 | ... == ... | Equality test on floating point values may not behave as expected. |
| c.c:17:5:17:12 | ... == ... | Equality test on floating point values may not behave as expected. |

View File

@@ -64,6 +64,10 @@ edges
| test.cpp:201:5:201:17 | EnterFunction: maybe_deref_p | test.cpp:201:5:201:17 | VariableAddress: maybe_deref_p |
| test.cpp:210:3:210:9 | Call: call to escape1 | test.cpp:201:5:201:17 | EnterFunction: maybe_deref_p |
| test.cpp:210:3:210:9 | Call: call to escape1 | test.cpp:201:5:201:17 | VariableAddress: maybe_deref_p |
| test.cpp:234:3:234:13 | Store: ... = ... | test.cpp:238:3:238:9 | Call: call to escape2 |
| test.cpp:238:3:238:9 | Call: call to escape2 | test.cpp:239:17:239:17 | Load: p |
| test.cpp:263:3:263:13 | Store: ... = ... | test.cpp:267:3:267:9 | Call: call to escape3 |
| test.cpp:267:3:267:9 | Call: call to escape3 | test.cpp:268:17:268:17 | Load: p |
#select
| test.cpp:15:16:15:16 | Load: p | test.cpp:10:3:10:13 | Store: ... = ... | test.cpp:15:16:15:16 | Load: p | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:9:7:9:7 | x | x | test.cpp:10:3:10:13 | Store: ... = ... | here |
| test.cpp:24:16:24:16 | Load: p | test.cpp:10:3:10:13 | Store: ... = ... | test.cpp:24:16:24:16 | Load: p | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:9:7:9:7 | x | x | test.cpp:10:3:10:13 | Store: ... = ... | here |
@@ -90,3 +94,5 @@ edges
| test.cpp:180:14:180:19 | Load: * ... | test.cpp:154:3:154:22 | Store: ... = ... | test.cpp:180:14:180:19 | Load: * ... | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:133:7:133:8 | b2 | b2 | test.cpp:154:3:154:22 | Store: ... = ... | here |
| test.cpp:181:13:181:20 | Load: access to array | test.cpp:155:3:155:21 | Store: ... = ... | test.cpp:181:13:181:20 | Load: access to array | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:134:7:134:8 | b3 | b3 | test.cpp:155:3:155:21 | Store: ... = ... | here |
| test.cpp:182:14:182:19 | Load: * ... | test.cpp:156:3:156:25 | Store: ... = ... | test.cpp:182:14:182:19 | Load: * ... | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:134:7:134:8 | b3 | b3 | test.cpp:156:3:156:25 | Store: ... = ... | here |
| test.cpp:239:17:239:17 | Load: p | test.cpp:234:3:234:13 | Store: ... = ... | test.cpp:239:17:239:17 | Load: p | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:232:7:232:7 | x | x | test.cpp:234:3:234:13 | Store: ... = ... | here |
| test.cpp:268:17:268:17 | Load: p | test.cpp:263:3:263:13 | Store: ... = ... | test.cpp:268:17:268:17 | Load: p | Stack variable $@ escapes $@ and is used after it has expired. | test.cpp:260:7:260:7 | x | x | test.cpp:263:3:263:13 | Store: ... = ... | here |

View File

@@ -209,4 +209,61 @@ int maybe_deref_p(bool b) {
int field_indirect_maybe_bad(bool b) {
escape1();
return maybe_deref_p(b);
}
// These next tests cover subsequent stores to the same address in the same basic block.
static struct S100 s102;
void not_escape1() {
int x;
s102.p = &x;
s102.p = nullptr;
}
void calls_not_escape1() {
not_escape1();
int x = *s102.p; // GOOD
}
static struct S100 s103;
void escape2() {
int x;
s103.p = nullptr;
s103.p = &x;
}
void calls_escape2() {
escape2();
int x = *s103.p; // BAD
}
bool unknown();
static struct S100 s104;
void not_escape2() {
int x;
s104.p = &x;
if(unknown()) { }
s104.p = nullptr;
}
void calls_not_escape2() {
not_escape2();
int x = *s104.p; // GOOD
}
static struct S100 s105;
void escape3() {
int x;
s105.p = nullptr;
if(unknown()) { }
s105.p = &x;
}
void calls_escape3() {
escape3();
int x = *s105.p; // BAD
}

View File

@@ -35,10 +35,3 @@ options:
the code (for example if it uses inaccessible dependencies).
type: string
pattern: "^(false|true)$"
cil:
title: Whether to enable CIL extraction.
description: >
A value indicating, whether CIL extraction should be enabled.
The default is 'true'.
type: string
pattern: "^(false|true)$"

View File

@@ -9,7 +9,7 @@ Microsoft.Extensions.Caching.Memory,,,46,,,,,,,,,,,,45,1
Microsoft.Extensions.Configuration,,,83,,,,,,,,,,,,80,3
Microsoft.Extensions.DependencyInjection,,,62,,,,,,,,,,,,62,
Microsoft.Extensions.DependencyModel,,,12,,,,,,,,,,,,12,
Microsoft.Extensions.FileProviders,,,16,,,,,,,,,,,,16,
Microsoft.Extensions.FileProviders,,,15,,,,,,,,,,,,15,
Microsoft.Extensions.FileSystemGlobbing,,,15,,,,,,,,,,,,13,2
Microsoft.Extensions.Hosting,,,17,,,,,,,,,,,,16,1
Microsoft.Extensions.Http,,,10,,,,,,,,,,,,10,
@@ -24,5 +24,5 @@ Microsoft.Win32,,,8,,,,,,,,,,,,8,
MySql.Data.MySqlClient,48,,,,,,,,,,48,,,,,
Newtonsoft.Json,,,91,,,,,,,,,,,,73,18
ServiceStack,194,,7,27,,,,,,75,92,,,,7,
System,65,4,12081,,8,8,9,,4,,33,3,1,3,10139,1942
System,43,4,11809,,1,1,1,,4,,33,3,1,3,9867,1942
Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,
1 package sink source summary sink:code sink:encryption-decryptor sink:encryption-encryptor sink:encryption-keyprop sink:encryption-symmetrickey sink:html sink:remote sink:sql sink:xss source:file source:local summary:taint summary:value
9 Microsoft.Extensions.Configuration 83 80 3
10 Microsoft.Extensions.DependencyInjection 62 62
11 Microsoft.Extensions.DependencyModel 12 12
12 Microsoft.Extensions.FileProviders 16 15 16 15
13 Microsoft.Extensions.FileSystemGlobbing 15 13 2
14 Microsoft.Extensions.Hosting 17 16 1
15 Microsoft.Extensions.Http 10 10
24 MySql.Data.MySqlClient 48 48
25 Newtonsoft.Json 91 73 18
26 ServiceStack 194 7 27 75 92 7
27 System 65 43 4 12081 11809 8 1 8 1 9 1 4 33 3 1 3 10139 9867 1942
28 Windows.Security.Cryptography.Core 1 1

View File

@@ -8,7 +8,7 @@ C# framework & library support
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
System,"``System.*``, ``System``",4,12081,65,7
Others,"``Dapper``, ``JsonToItemsTaskFactory``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NETCore.Platforms.BuildTasks``, ``Microsoft.VisualBasic``, ``Microsoft.Win32``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``Windows.Security.Cryptography.Core``",,555,138,
Totals,,4,12643,397,7
System,"``System.*``, ``System``",4,11809,43,7
Others,"``Dapper``, ``JsonToItemsTaskFactory``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NETCore.Platforms.BuildTasks``, ``Microsoft.VisualBasic``, ``Microsoft.Win32``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``Windows.Security.Cryptography.Core``",,554,138,
Totals,,4,12370,375,7

View File

@@ -1,2 +0,0 @@
description: Introduce '--cil' flag in the comments. This does not make any changes to the dbscheme.
compatibility: full

View File

@@ -18,11 +18,14 @@ namespace Semmle.Extraction.CSharp
if (args.Length > 0 && args[0] == "--dotnetexec")
{
var compilerRegEx = new Regex(@"csc\.exe|mcs\.exe|csc\.dll", RegexOptions.Compiled);
for (var i = 1; i < args.Length; i++)
var cil = args.Length > 1 && args[1] == "--cil";
for (var i = cil ? 2 : 1; i < args.Length; i++)
{
if (compilerRegEx.IsMatch(args[i]))
{
var argsList = new List<string>();
if (cil)
argsList.Add("--cil");
argsList.Add("--compiler");
argsList.Add(args[i]);
if (i + 1 < args.Length)

View File

@@ -56,6 +56,7 @@ namespace Semmle.Extraction.CSharp.Standalone
CSharp.Extractor.SetInvariantCulture();
var options = Options.Create(args);
// options.CIL = true; // To do: Enable this
if (options.Help)
{

View File

@@ -22,7 +22,7 @@ namespace Semmle.Extraction.Tests
{
options = CSharp.Options.CreateWithEnvironment(Array.Empty<string>());
Assert.True(options.Cache);
Assert.True(options.CIL);
Assert.False(options.CIL);
Assert.Null(options.Framework);
Assert.Null(options.CompilerName);
Assert.Empty(options.CompilerArguments);
@@ -51,20 +51,10 @@ namespace Semmle.Extraction.Tests
[Fact]
public void CIL()
{
options = CSharp.Options.CreateWithEnvironment(Array.Empty<string>());
options = CSharp.Options.CreateWithEnvironment(new string[] { "--cil" });
Assert.True(options.CIL);
Environment.SetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_OPTION_CIL", "false");
options = CSharp.Options.CreateWithEnvironment(Array.Empty<string>());
options = CSharp.Options.CreateWithEnvironment(new string[] { "--cil", "--nocil" });
Assert.False(options.CIL);
Environment.SetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_OPTION_CIL", "true");
options = CSharp.Options.CreateWithEnvironment(Array.Empty<string>());
Assert.True(options.CIL);
Environment.SetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_OPTION_CIL", null);
options = CSharp.Options.CreateWithEnvironment(Array.Empty<string>());
Assert.True(options.CIL);
}
[Fact]
@@ -131,6 +121,22 @@ namespace Semmle.Extraction.Tests
Assert.Equal("foo", options.Framework);
}
[Fact]
public void EnvironmentVariables()
{
Environment.SetEnvironmentVariable("LGTM_INDEX_EXTRACTOR", "--cil c");
options = CSharp.Options.CreateWithEnvironment(new string[] { "a", "b" });
Assert.True(options.CIL);
Assert.Equal("a", options.CompilerArguments[0]);
Assert.Equal("b", options.CompilerArguments[1]);
Assert.Equal("c", options.CompilerArguments[2]);
Environment.SetEnvironmentVariable("LGTM_INDEX_EXTRACTOR", "");
Environment.SetEnvironmentVariable("LGTM_INDEX_EXTRACTOR", "--nocil");
options = CSharp.Options.CreateWithEnvironment(new string[] { "--cil" });
Assert.False(options.CIL);
}
[Fact]
public void StandaloneDefaults()
{

View File

@@ -28,7 +28,7 @@ namespace Semmle.Extraction
/// <summary>
/// Holds if CIL should be extracted.
/// </summary>
public bool CIL { get; private set; } = true;
public bool CIL { get; private set; } = false;
/// <summary>
/// Holds if assemblies shouldn't be extracted twice.
@@ -50,6 +50,7 @@ namespace Semmle.Extraction
/// </summary>
public bool QlTest { get; private set; } = false;
/// <summary>
/// The compression algorithm used for trap files.
/// </summary>
@@ -72,9 +73,6 @@ namespace Semmle.Extraction
return true;
}
return false;
case "cil":
CIL = Boolean.Parse(value);
return true;
default:
return false;
}
@@ -99,6 +97,9 @@ namespace Semmle.Extraction
case "cache":
Cache = value;
return true;
case "cil":
CIL = value;
return true;
case "pdb":
PDB = value;
CIL = true;

View File

@@ -17,7 +17,7 @@ namespace Semmle.Util
bool HandleOption(string key, string value);
/// <summary>
/// Handle a flag of the form "--cache" or "--nocache"
/// Handle a flag of the form "--cil" or "--nocil"
/// </summary>
/// <param name="key">The name of the flag. This is case sensitive.</param>
/// <param name="value">True if set, or false if prefixed by "--no"</param>
@@ -40,7 +40,6 @@ namespace Semmle.Util
public static class OptionsExtensions
{
private static readonly string[] ExtractorOptions = new[] { "trap_compression", "cil" };
private static string? GetExtractorOption(string name) =>
Environment.GetEnvironmentVariable($"CODEQL_EXTRACTOR_CSHARP_OPTION_{name.ToUpper()}");
@@ -48,14 +47,12 @@ namespace Semmle.Util
{
var extractorOptions = new List<string>();
foreach (var option in ExtractorOptions)
var trapCompression = GetExtractorOption("trap_compression");
if (!string.IsNullOrEmpty(trapCompression))
{
var value = GetExtractorOption(option);
if (!string.IsNullOrEmpty(value))
{
extractorOptions.Add($"--{option}:{value}");
}
extractorOptions.Add($"--trap_compression:{trapCompression}");
}
return extractorOptions;
}

View File

@@ -1,3 +1,7 @@
## 1.2.5
## 1.2.4
## 1.2.3
## 1.2.2

View File

@@ -0,0 +1 @@
## 1.2.4

View File

@@ -0,0 +1 @@
## 1.2.5

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.2.3
lastReleaseVersion: 1.2.5

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
version: 1.2.4-dev
version: 1.2.5
groups:
- csharp
- solorigate

View File

@@ -1,3 +1,7 @@
## 1.2.5
## 1.2.4
## 1.2.3
## 1.2.2

View File

@@ -15,7 +15,7 @@ import experimental.code.csharp.Cryptography.NonCryptographicHashes
from Variable v, Literal l, LoopStmt loop, Expr additional_xor
where
maybeUsedInFnvFunction(v, _, _, loop) and
maybeUsedInFNVFunction(v, _, _, loop) and
(
exists(BitwiseXorExpr xor2 | xor2.getAnOperand() = l and additional_xor = xor2 |
loop.getAControlFlowExitNode().getASuccessor*() = xor2.getAControlFlowNode() and

View File

@@ -0,0 +1 @@
## 1.2.4

View File

@@ -0,0 +1 @@
## 1.2.5

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.2.3
lastReleaseVersion: 1.2.5

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
version: 1.2.4-dev
version: 1.2.5
groups:
- csharp
- solorigate

View File

@@ -1,8 +1,8 @@
import csharp
import semmle.code.csharp.dataflow.internal.SsaImpl::Consistency as Consistency
import semmle.code.csharp.dataflow.internal.SsaImplCommon::Consistency
import Ssa
class MyRelevantDefinition extends Consistency::RelevantDefinition, Ssa::Definition {
class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition {
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
@@ -10,14 +10,6 @@ class MyRelevantDefinition extends Consistency::RelevantDefinition, Ssa::Definit
}
}
query predicate nonUniqueDef = Consistency::nonUniqueDef/4;
query predicate readWithoutDef = Consistency::readWithoutDef/3;
query predicate deadDef = Consistency::deadDef/2;
query predicate notDominatedByDef = Consistency::notDominatedByDef/4;
query predicate localDeclWithSsaDef(LocalVariableDeclExpr d) {
// Local variables in C# must be initialized before every use, so uninitialized
// local variables should not have an SSA definition, as that would imply that

View File

@@ -1,3 +1,16 @@
## 0.3.5
## 0.3.4
### Deprecated APIs
* Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.
### Minor Analysis Improvements
* All deprecated predicates/classes/modules that have been deprecated for over a year have been deleted.
## 0.3.3
## 0.3.2

View File

@@ -1,6 +0,0 @@
---
category: minorAnalysis
---
* All deprecated predicates/classes/modules that have been deprecated for over a year have been
deleted.

View File

@@ -1,5 +0,0 @@
---
category: deprecated
---
* Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.

View File

@@ -0,0 +1,10 @@
## 0.3.4
### Deprecated APIs
* Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.
### Minor Analysis Improvements
* All deprecated predicates/classes/modules that have been deprecated for over a year have been deleted.

View File

@@ -0,0 +1 @@
## 0.3.5

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.3.3
lastReleaseVersion: 0.3.5

View File

@@ -13,7 +13,7 @@ private import semmle.code.csharp.dataflow.TaintTracking2
predicate maybeANonCryptogrphicHash(Callable callable, Variable v, Expr xor, Expr mul, LoopStmt loop) {
callable = loop.getEnclosingCallable() and
(
maybeUsedInFnvFunction(v, xor, mul, loop) or
maybeUsedInFNVFunction(v, xor, mul, loop) or
maybeUsedInElfHashFunction(v, xor, mul, loop)
)
}
@@ -23,7 +23,7 @@ predicate maybeANonCryptogrphicHash(Callable callable, Variable v, Expr xor, Exp
* where there is a loop statement `loop` where the variable `v` is used in an xor `xor` expression
* followed by a multiplication `mul` expression.
*/
predicate maybeUsedInFnvFunction(Variable v, Operation xor, Operation mul, LoopStmt loop) {
predicate maybeUsedInFNVFunction(Variable v, Operation xor, Operation mul, LoopStmt loop) {
exists(Expr e1, Expr e2 |
e1.getAChild*() = v.getAnAccess() and
e2.getAChild*() = v.getAnAccess() and
@@ -37,9 +37,6 @@ predicate maybeUsedInFnvFunction(Variable v, Operation xor, Operation mul, LoopS
loop.getAChild*() = xor.getEnclosingStmt()
}
/** DEPRECATED: Alias for maybeUsedInFnvFunction */
deprecated predicate maybeUsedInFNVFunction = maybeUsedInFnvFunction/4;
/**
* Holds if the arguments are used in a way that resembles an Elf-Hash hash function
* where there is a loop statement `loop` where the variable `v` is used in an xor `xor` expression

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-all
version: 0.3.4-dev
version: 0.3.5
groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp

View File

@@ -8,12 +8,13 @@ private import CIL
* Provides classes for working with static single assignment (SSA) form.
*/
module Ssa {
private import internal.SsaImpl as SsaImpl
private import internal.SsaImplCommon as SsaImpl
private import internal.SsaImpl
/** An SSA definition. */
class Definition extends SsaImpl::Definition {
/** Gets a read of this SSA definition. */
final ReadAccess getARead() { result = SsaImpl::getARead(this) }
final ReadAccess getARead() { result = getARead(this) }
/** Gets the underlying variable update, if any. */
final VariableUpdate getVariableUpdate() {
@@ -24,11 +25,11 @@ module Ssa {
}
/** Gets a first read of this SSA definition. */
final ReadAccess getAFirstRead() { result = SsaImpl::getAFirstRead(this) }
final ReadAccess getAFirstRead() { result = getAFirstRead(this) }
/** Holds if `first` and `second` are adjacent reads of this SSA definition. */
final predicate hasAdjacentReads(ReadAccess first, ReadAccess second) {
SsaImpl::hasAdjacentReads(this, first, second)
hasAdjacentReads(this, first, second)
}
private Definition getAPhiInput() { result = this.(PhiNode).getAnInput() }
@@ -51,7 +52,7 @@ module Ssa {
final override Location getLocation() { result = this.getBasicBlock().getLocation() }
/** Gets an input to this phi node. */
final Definition getAnInput() { result = SsaImpl::getAPhiInput(this) }
final Definition getAnInput() { result = getAPhiInput(this) }
/**
* Holds if if `def` is an input to this phi node, and a reference to `def` at
@@ -59,7 +60,7 @@ module Ssa {
* other references.
*/
final predicate hasLastInputRef(Definition def, BasicBlock bb, int i) {
SsaImpl::hasLastInputRef(this, def, bb, i)
hasLastInputRef(this, def, bb, i)
}
}
}

View File

@@ -1,40 +1,8 @@
private import cil
private import semmle.code.csharp.dataflow.internal.SsaImplCommon as SsaImplCommon
private module SsaInput implements SsaImplCommon::InputSig {
class BasicBlock = CIL::BasicBlock;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class ExitBasicBlock = CIL::ExitBasicBlock;
class SourceVariable = CIL::StackVariable;
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
forceCachingInSameStage() and
exists(CIL::VariableUpdate vu |
vu.updatesAt(bb, i) and
v = vu.getVariable() and
certain = true
)
}
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(CIL::ReadAccess ra | bb.getNode(i) = ra |
ra.getTarget() = v and
certain = true
)
}
}
import SsaImplCommon::Make<SsaInput>
private import semmle.code.cil.CIL
private import SsaImplCommon
cached
private module Cached {
private import CIL
cached
predicate forceCachingInSameStage() { any() }

View File

@@ -0,0 +1,795 @@
/**
* Provides a language-independent implementation of static single assignment
* (SSA) form.
*/
private import SsaImplSpecific
private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb }
/**
* Liveness analysis (based on source variables) to restrict the size of the
* SSA representation.
*/
private module Liveness {
/**
* A classification of variable references into reads (of a given kind) and
* (certain or uncertain) writes.
*/
private newtype TRefKind =
Read(boolean certain) { certain in [false, true] } or
Write(boolean certain) { certain in [false, true] }
private class RefKind extends TRefKind {
string toString() {
exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")")
or
exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")")
}
int getOrder() {
this = Read(_) and
result = 0
or
this = Write(_) and
result = 1
}
}
/**
* Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`.
*/
predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain))
or
exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain))
}
private newtype OrderedRefIndex =
MkOrderedRefIndex(int i, int tag) {
exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder())
}
private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) {
ref(bb, i, v, k) and
result = MkOrderedRefIndex(i, ord) and
ord = k.getOrder()
}
/**
* Gets the (1-based) rank of the reference to `v` at the `i`th node of
* basic block `bb`, which has the given reference kind `k`.
*
* Reads are considered before writes when they happen at the same index.
*/
private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) {
refOrd(bb, i, v, k, _) =
rank[result](int j, int ord, OrderedRefIndex res |
res = refOrd(bb, j, v, _, ord)
|
res order by j, ord
)
}
private int maxRefRank(BasicBlock bb, SourceVariable v) {
result = refRank(bb, _, v, _) and
not result + 1 = refRank(bb, _, v, _)
}
predicate lastRefIsRead(BasicBlock bb, SourceVariable v) {
maxRefRank(bb, v) = refRank(bb, _, v, Read(_))
}
/**
* Gets the (1-based) rank of the first reference to `v` inside basic block `bb`
* that is either a read or a certain write.
*/
private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) {
result =
min(int r, RefKind k |
r = refRank(bb, _, v, k) and
k != Write(false)
|
r
)
}
/**
* Holds if source variable `v` is live at the beginning of basic block `bb`.
*/
predicate liveAtEntry(BasicBlock bb, SourceVariable v) {
// The first read or certain write to `v` inside `bb` is a read
refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v)
or
// There is no certain write to `v` inside `bb`, but `v` is live at entry
// to a successor basic block of `bb`
not exists(firstReadOrCertainWrite(bb, v)) and
liveAtExit(bb, v)
}
/**
* Holds if source variable `v` is live at the end of basic block `bb`.
*/
predicate liveAtExit(BasicBlock bb, SourceVariable v) {
liveAtEntry(getABasicBlockSuccessor(bb), v)
}
/**
* Holds if variable `v` is live in basic block `bb` at index `i`.
* The rank of `i` is `rnk` as defined by `refRank()`.
*/
private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) {
exists(RefKind kind | rnk = refRank(bb, i, v, kind) |
rnk = maxRefRank(bb, v) and
liveAtExit(bb, v)
or
ref(bb, i, v, kind) and
kind = Read(_)
or
exists(RefKind nextKind |
liveAtRank(bb, _, v, rnk + 1) and
rnk + 1 = refRank(bb, _, v, nextKind) and
nextKind != Write(true)
)
)
}
/**
* Holds if variable `v` is live after the (certain or uncertain) write at
* index `i` inside basic block `bb`.
*/
predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) {
exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk))
}
}
private import Liveness
/**
* Holds if `df` is in the dominance frontier of `bb`.
*
* This is equivalent to:
*
* ```ql
* bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and
* not bb = getImmediateBasicBlockDominator+(df)
* ```
*/
private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) {
bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df)
or
exists(BasicBlock prev | inDominanceFrontier(prev, df) |
bb = getImmediateBasicBlockDominator(prev) and
not bb = getImmediateBasicBlockDominator(df)
)
}
/**
* Holds if `bb` is in the dominance frontier of a block containing a
* definition of `v`.
*/
pragma[noinline]
private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) {
exists(BasicBlock defbb, Definition def |
def.definesAt(v, defbb, _) and
inDominanceFrontier(defbb, bb)
)
}
cached
newtype TDefinition =
TWriteDef(SourceVariable v, BasicBlock bb, int i) {
variableWrite(bb, i, v, _) and
liveAfterWrite(bb, i, v)
} or
TPhiNode(SourceVariable v, BasicBlock bb) {
inDefDominanceFrontier(bb, v) and
liveAtEntry(bb, v)
}
private module SsaDefReaches {
newtype TSsaRefKind =
SsaActualRead() or
SsaPhiRead() or
SsaDef()
class SsaRead = SsaActualRead or SsaPhiRead;
/**
* A classification of SSA variable references into reads and definitions.
*/
class SsaRefKind extends TSsaRefKind {
string toString() {
this = SsaActualRead() and
result = "SsaActualRead"
or
this = SsaPhiRead() and
result = "SsaPhiRead"
or
this = SsaDef() and
result = "SsaDef"
}
int getOrder() {
this instanceof SsaRead and
result = 0
or
this = SsaDef() and
result = 1
}
}
/**
* Holds if `bb` is in the dominance frontier of a block containing a
* read of `v`.
*/
pragma[nomagic]
private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) {
exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) |
lastRefIsRead(readbb, v)
or
phiRead(readbb, v)
)
}
/**
* Holds if a phi-read node should be inserted for variable `v` at the beginning
* of basic block `bb`.
*
* Phi-read nodes are like normal phi nodes, but they are inserted based on reads
* instead of writes, and only if the dominance-frontier block does not already
* contain a reference (read or write) to `v`. Unlike normal phi nodes, this is
* an internal implementation detail that is not exposed.
*
* The motivation for adding phi-reads is to improve performance of the use-use
* calculation in cases where there is a large number of reads that can reach the
* same join-point, and from there reach a large number of basic blocks. Example:
*
* ```cs
* if (a)
* use(x);
* else if (b)
* use(x);
* else if (c)
* use(x);
* else if (d)
* use(x);
* // many more ifs ...
*
* // phi-read for `x` inserted here
*
* // program not mentioning `x`, with large basic block graph
*
* use(x);
* ```
*
* Without phi-reads, the analysis has to replicate reachability for each of
* the guarded uses of `x`. However, with phi-reads, the analysis will limit
* each conditional use of `x` to reach the basic block containing the phi-read
* node for `x`, and only that basic block will have to compute reachability
* through the remainder of the large program.
*
* Like normal reads, each phi-read node `phi-read` can be reached from exactly
* one SSA definition (without passing through another definition): Assume, for
* the sake of contradiction, that there are two reaching definitions `def1` and
* `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest
* dominating definition will prevent the other from reaching `phi-read`. So, at
* least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`.
* Then `def1` must go through one of its dominance-frontier blocks in order to
* reach `phi-read`. However, such a block will always start with a (normal) phi
* node, which contradicts reachability.
*
* Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`,
* will dominate `phi-read`. Assuming it doesn't means that the path from `def`
* to `phi-read` goes through a dominance-frontier block, and hence a phi node,
* which contradicts reachability.
*/
pragma[nomagic]
predicate phiRead(BasicBlock bb, SourceVariable v) {
inReadDominanceFrontier(bb, v) and
liveAtEntry(bb, v) and
// only if there are no other references to `v` inside `bb`
not ref(bb, _, v, _) and
not exists(Definition def | def.definesAt(v, bb, _))
}
/**
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
* either a read (when `k` is `SsaRead()`) or an SSA definition (when `k`
* is `SsaDef()`).
*
* Unlike `Liveness::ref`, this includes `phi` nodes.
*/
pragma[nomagic]
predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
variableRead(bb, i, v, _) and
k = SsaActualRead()
or
phiRead(bb, v) and
i = -1 and
k = SsaPhiRead()
or
any(Definition def).definesAt(v, bb, i) and
k = SsaDef()
}
private newtype OrderedSsaRefIndex =
MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) }
private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) {
ssaRef(bb, i, v, k) and
result = MkOrderedSsaRefIndex(i, k) and
ord = k.getOrder()
}
/**
* Gets the (1-based) rank of the reference to `v` at the `i`th node of basic
* block `bb`, which has the given reference kind `k`.
*
* For example, if `bb` is a basic block with a phi node for `v` (considered
* to be at index -1), reads `v` at node 2, and defines it at node 5, we have:
*
* ```ql
* ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node
* ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2
* ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5
* ```
*
* Reads are considered before writes when they happen at the same index.
*/
int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
ssaRefOrd(bb, i, v, k, _) =
rank[result](int j, int ord, OrderedSsaRefIndex res |
res = ssaRefOrd(bb, j, v, _, ord)
|
res order by j, ord
)
}
int maxSsaRefRank(BasicBlock bb, SourceVariable v) {
result = ssaRefRank(bb, _, v, _) and
not result + 1 = ssaRefRank(bb, _, v, _)
}
/**
* Holds if the SSA definition `def` reaches rank index `rnk` in its own
* basic block `bb`.
*/
predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) {
exists(int i |
rnk = ssaRefRank(bb, i, v, SsaDef()) and
def.definesAt(v, bb, i)
)
or
ssaDefReachesRank(bb, def, rnk - 1, v) and
rnk = ssaRefRank(bb, _, v, any(SsaRead k))
}
/**
* Holds if the SSA definition of `v` at `def` reaches index `i` in the same
* basic block `bb`, without crossing another SSA definition of `v`.
*/
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
exists(int rnk |
ssaDefReachesRank(bb, def, rnk, v) and
rnk = ssaRefRank(bb, i, v, any(SsaRead k))
)
}
/**
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
*/
int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) {
v = def.getSourceVariable() and
result = ssaRefRank(bb, i, v, k) and
(
ssaDefReachesRead(_, def, bb, i)
or
def.definesAt(_, bb, i)
)
}
/**
* Holds if the reference to `def` at index `i` in basic block `bb` is the
* last reference to `v` inside `bb`.
*/
pragma[noinline]
predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) {
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
}
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) {
exists(ssaDefRank(def, v, bb, _, k))
}
pragma[noinline]
private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) {
ssaDefReachesEndOfBlock(bb, def, _) and
not defOccursInBlock(_, bb, def.getSourceVariable(), _)
}
/**
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
* `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_
* predecessor of `bb2`, and the underlying variable for `def` is neither read
* nor written in any block on the path between `bb1` and `bb2`.
*
* Phi reads are considered as normal reads for this predicate.
*/
pragma[nomagic]
private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
defOccursInBlock(def, bb1, _, _) and
bb2 = getABasicBlockSuccessor(bb1)
or
exists(BasicBlock mid |
varBlockReachesInclPhiRead(def, bb1, mid) and
ssaDefReachesThroughBlock(def, mid) and
bb2 = getABasicBlockSuccessor(mid)
)
}
pragma[nomagic]
private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) {
varBlockReachesInclPhiRead(def, bb1, bb2) and
defOccursInBlock(def, bb2, v, SsaPhiRead())
}
pragma[nomagic]
private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and
ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()])
or
exists(BasicBlock mid |
varBlockReachesExclPhiRead(def, mid, bb2) and
phiReadStep(def, _, bb1, mid)
)
}
/**
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
* the underlying variable `v` of `def` is accessed in basic block `bb2`
* (either a read or a write), `bb2` is a transitive successor of `bb1`, and
* `v` is neither read nor written in any block on the path between `bb1`
* and `bb2`.
*/
pragma[nomagic]
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
varBlockReachesExclPhiRead(def, bb1, bb2) and
not defOccursInBlock(def, bb1, _, SsaPhiRead())
}
pragma[nomagic]
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
varBlockReaches(def, bb1, bb2) and
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1
}
/**
* Holds if `def` is accessed in basic block `bb` (either a read or a write),
* `bb1` can reach a transitive successor `bb2` where `def` is no longer live,
* and `v` is neither read nor written in any block on the path between `bb`
* and `bb2`.
*/
pragma[nomagic]
predicate varBlockReachesExit(Definition def, BasicBlock bb) {
exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) |
not defOccursInBlock(def, bb2, _, _) and
not ssaDefReachesEndOfBlock(bb2, def, _)
)
or
exists(BasicBlock mid |
varBlockReachesExit(def, mid) and
phiReadStep(def, _, bb, mid)
)
}
}
predicate phiReadExposedForTesting = phiRead/2;
private import SsaDefReaches
pragma[nomagic]
predicate liveThrough(BasicBlock bb, SourceVariable v) {
liveAtExit(bb, v) and
not ssaRef(bb, _, v, SsaDef())
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if the SSA definition of `v` at `def` reaches the end of basic
* block `bb`, at which point it is still live, without crossing another
* SSA definition of `v`.
*/
pragma[nomagic]
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) {
exists(int last |
last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and
ssaDefReachesRank(bb, def, last, v) and
liveAtExit(bb, v)
)
or
// The construction of SSA form ensures that each read of a variable is
// dominated by its definition. An SSA definition therefore reaches a
// control flow node if it is the _closest_ SSA definition that dominates
// the node. If two definitions dominate a node then one must dominate the
// other, so therefore the definition of _closest_ is given by the dominator
// tree. Thus, reaching definitions can be calculated in terms of dominance.
ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and
liveThrough(bb, pragma[only_bind_into](v))
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`.
*/
pragma[nomagic]
predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) {
exists(SourceVariable v, BasicBlock bbDef |
phi.definesAt(v, bbDef, _) and
getABasicBlockPredecessor(bbDef) = bb and
ssaDefReachesEndOfBlock(bb, inp, v)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if the SSA definition of `v` at `def` reaches a read at index `i` in
* basic block `bb`, without crossing another SSA definition of `v`. The read
* is of kind `rk`.
*/
pragma[nomagic]
predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) {
ssaDefReachesReadWithinBlock(v, def, bb, i)
or
ssaRef(bb, i, v, any(SsaRead k)) and
ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and
not ssaDefReachesReadWithinBlock(v, _, bb, i)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read
* or a write), `def` is read at index `i2` in basic block `bb2`, and there is a
* path between them without any read of `def`.
*/
pragma[nomagic]
predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
exists(int rnk |
rnk = ssaDefRank(def, _, bb1, i1, _) and
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and
variableRead(bb1, i2, _, _) and
bb2 = bb1
)
or
lastSsaRef(def, _, bb1, i1) and
defAdjacentRead(def, bb1, bb2, i2)
}
pragma[noinline]
private predicate adjacentDefRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v
) {
adjacentDefRead(def, bb1, i1, bb2, i2) and
v = def.getSourceVariable()
}
private predicate adjacentDefReachesRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) |
ssaRef(bb1, i1, v, SsaDef())
or
variableRead(bb1, i1, v, true)
)
or
exists(BasicBlock bb3, int i3 |
adjacentDefReachesRead(def, bb1, i1, bb3, i3) and
variableRead(bb3, i3, _, false) and
adjacentDefRead(def, bb3, i3, bb2, i2)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Same as `adjacentDefRead`, but ignores uncertain reads.
*/
pragma[nomagic]
predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
variableRead(bb2, i2, _, true)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if the node at index `i` in `bb` is a last reference to SSA definition
* `def`. The reference is last because it can reach another write `next`,
* without passing through another read or write.
*/
pragma[nomagic]
predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) {
exists(SourceVariable v |
// Next reference to `v` inside `bb` is a write
exists(int rnk, int j |
rnk = ssaDefRank(def, v, bb, i, _) and
next.definesAt(v, bb, j) and
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
)
or
// Can reach a write using one or more steps
lastSsaRef(def, v, bb, i) and
exists(BasicBlock bb2 |
varBlockReaches(def, bb, bb2) and
1 = ssaDefRank(next, v, bb2, _, SsaDef())
)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if `inp` is an immediately preceding definition of uncertain definition
* `def`. Since `def` is uncertain, the value from the preceding definition might
* still be valid.
*/
pragma[nomagic]
predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) {
lastRefRedef(inp, _, _, def)
}
private predicate adjacentDefReachesUncertainRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
variableRead(bb2, i2, _, false)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Same as `lastRefRedef`, but ignores uncertain reads.
*/
pragma[nomagic]
predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) {
lastRefRedef(def, bb, i, next) and
not variableRead(bb, i, def.getSourceVariable(), false)
or
exists(BasicBlock bb0, int i0 |
lastRefRedef(def, bb0, i0, next) and
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if the node at index `i` in `bb` is a last reference to SSA
* definition `def`.
*
* That is, the node can reach the end of the enclosing callable, or another
* SSA definition for the underlying source variable, without passing through
* another read.
*/
pragma[nomagic]
predicate lastRef(Definition def, BasicBlock bb, int i) {
// Can reach another definition
lastRefRedef(def, bb, i, _)
or
exists(SourceVariable v | lastSsaRef(def, v, bb, i) |
// Can reach exit directly
bb instanceof ExitBasicBlock
or
// Can reach a block using one or more steps, where `def` is no longer live
varBlockReachesExit(def, bb)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Same as `lastRefRedef`, but ignores uncertain reads.
*/
pragma[nomagic]
predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) {
lastRef(def, bb, i) and
not variableRead(bb, i, def.getSourceVariable(), false)
or
exists(BasicBlock bb0, int i0 |
lastRef(def, bb0, i0) and
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
)
}
/** A static single assignment (SSA) definition. */
class Definition extends TDefinition {
/** Gets the source variable underlying this SSA definition. */
SourceVariable getSourceVariable() { this.definesAt(result, _, _) }
/**
* Holds if this SSA definition defines `v` at index `i` in basic block `bb`.
* Phi nodes are considered to be at index `-1`, while normal variable writes
* are at the index of the control flow node they wrap.
*/
final predicate definesAt(SourceVariable v, BasicBlock bb, int i) {
this = TWriteDef(v, bb, i)
or
this = TPhiNode(v, bb) and i = -1
}
/** Gets the basic block to which this SSA definition belongs. */
final BasicBlock getBasicBlock() { this.definesAt(_, result, _) }
/** Gets a textual representation of this SSA definition. */
string toString() { none() }
}
/** An SSA definition that corresponds to a write. */
class WriteDefinition extends Definition, TWriteDef {
private SourceVariable v;
private BasicBlock bb;
private int i;
WriteDefinition() { this = TWriteDef(v, bb, i) }
override string toString() { result = "WriteDef" }
}
/** A phi node. */
class PhiNode extends Definition, TPhiNode {
override string toString() { result = "Phi" }
}
/**
* An SSA definition that represents an uncertain update of the underlying
* source variable.
*/
class UncertainWriteDefinition extends WriteDefinition {
UncertainWriteDefinition() {
exists(SourceVariable v, BasicBlock bb, int i |
this.definesAt(v, bb, i) and
variableWrite(bb, i, v, false)
)
}
}
/** Provides a set of consistency queries. */
module Consistency {
abstract class RelevantDefinition extends Definition {
abstract predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
);
}
query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
ssaDefReachesRead(v, def, bb, i) and
not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i)))
}
query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) {
variableRead(bb, i, v, _) and
not ssaDefReachesRead(v, _, bb, i)
}
query predicate deadDef(RelevantDefinition def, SourceVariable v) {
v = def.getSourceVariable() and
not ssaDefReachesRead(_, def, _, _) and
not phiHasInputFromBlock(_, def, _) and
not uncertainWriteDefinitionInput(_, def)
}
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
ssaDefReachesReadWithinBlock(v, def, bb, i) and
(bb != bbDef or i < iDef)
or
ssaDefReachesRead(v, def, bb, i) and
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
)
}
}

View File

@@ -0,0 +1,30 @@
/** Provides the CIL specific parameters for `SsaImplCommon.qll`. */
private import cil
private import SsaImpl
class BasicBlock = CIL::BasicBlock;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class ExitBasicBlock = CIL::ExitBasicBlock;
class SourceVariable = CIL::StackVariable;
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
forceCachingInSameStage() and
exists(CIL::VariableUpdate vu |
vu.updatesAt(bb, i) and
v = vu.getVariable() and
certain = true
)
}
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(CIL::ReadAccess ra | bb.getNode(i) = ra |
ra.getTarget() = v and
certain = true
)
}

View File

@@ -192,7 +192,8 @@ class BasicBlock extends TBasicBlockStart {
* Gets the basic block that immediately dominates this basic block, if any.
*
* That is, all paths reaching this basic block from some entry point
* basic block must go through the result.
* basic block must go through the result, which is an immediate basic block
* predecessor of this basic block.
*
* Example:
*
@@ -206,7 +207,8 @@ class BasicBlock extends TBasicBlockStart {
*
* The basic block starting on line 2 is an immediate dominator of
* the basic block online 4 (all paths from the entry point of `M`
* to `return s.Length;` must go through the null check.
* to `return s.Length;` must go through the null check, and the null check
* is an immediate predecessor of `return s.Length;`).
*/
BasicBlock getImmediateDominator() { bbIDominates(result, this) }

View File

@@ -6,158 +6,26 @@ import csharp
* scope variables.
*/
module PreSsa {
private import AssignableDefinitions
private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl
private import semmle.code.csharp.controlflow.internal.PreBasicBlocks as PreBasicBlocks
private import semmle.code.csharp.dataflow.internal.SsaImplCommon as SsaImplCommon
private predicate definitionAt(
AssignableDefinition def, SsaInput::BasicBlock bb, int i, SsaInput::SourceVariable v
) {
bb.getElement(i) = def.getExpr() and
v = def.getTarget() and
// In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x`
not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def |
second.getAssignment() = first.getAssignment() and
second.getEvaluationOrder() > first.getEvaluationOrder() and
second.getTarget() = v
)
or
def.(ImplicitParameterDefinition).getParameter() = v and
exists(Callable c | v = c.getAParameter() |
scopeFirst(c, bb) and
i = -1
)
}
predicate implicitEntryDef(Callable c, SsaInput::BasicBlock bb, SsaInput::SourceVariable v) {
not v instanceof LocalScopeVariable and
c = v.getACallable() and
scopeFirst(c, bb)
}
module SsaInput implements SsaImplCommon::InputSig {
class BasicBlock = PreBasicBlocks::PreBasicBlock;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class ExitBasicBlock extends BasicBlock {
ExitBasicBlock() { scopeLast(_, this.getLastElement(), _) }
}
/** Holds if `a` is assigned in non-constructor callable `c`. */
pragma[nomagic]
private predicate assignableDefinition(Assignable a, Callable c) {
exists(AssignableDefinition def | def.getTarget() = a |
c = def.getEnclosingCallable() and
not c instanceof Constructor
)
}
/** Holds if `a` is accessed in callable `c`. */
pragma[nomagic]
private predicate assignableAccess(Assignable a, Callable c) {
exists(AssignableAccess aa | aa.getTarget() = a | c = aa.getEnclosingCallable())
}
pragma[nomagic]
private predicate assignableNoCapturing(Assignable a, Callable c) {
assignableAccess(a, c) and
/*
* The code below is equivalent to
* ```ql
* not exists(Callable other | assignableDefinition(a, other) | other != c)
* ```
* but it avoids a Cartesian product in the compiler generated antijoin
* predicate.
*/
(
not assignableDefinition(a, _)
or
c = unique(Callable c0 | assignableDefinition(a, c0) | c0)
)
}
pragma[noinline]
private predicate assignableNoComplexQualifiers(Assignable a) {
forall(QualifiableExpr qe | qe.(AssignableAccess).getTarget() = a | qe.targetIsThisInstance())
}
/**
* A simple assignable. Either a local scope variable or a field/property
* that behaves like a local scope variable.
*/
class SourceVariable extends Assignable {
private Callable c;
SourceVariable() {
(
this instanceof LocalScopeVariable
or
this = any(Field f | not f.isVolatile())
or
this = any(TrivialProperty tp | not tp.isOverridableOrImplementable())
) and
assignableNoCapturing(this, c) and
assignableNoComplexQualifiers(this)
}
/** Gets a callable in which this simple assignable can be analyzed. */
Callable getACallable() { result = c }
}
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(AssignableDefinition def |
definitionAt(def, bb, i, v) and
if def.getTargetAccess().isRefArgument() then certain = false else certain = true
)
or
exists(Callable c |
implicitEntryDef(c, bb, v) and
i = -1 and
certain = true
)
}
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(AssignableRead read |
read = bb.getElement(i) and
read.getTarget() = v and
certain = true
)
or
v =
any(LocalScopeVariable lsv |
lsv.getCallable() = bb.(ExitBasicBlock).getEnclosingCallable() and
i = bb.length() and
(lsv.isRef() or v.(Parameter).isOut()) and
certain = false
)
}
}
private module SsaImpl = SsaImplCommon::Make<SsaInput>;
import pressa.SsaImplSpecific
private import pressa.SsaImplCommon as SsaImpl
class Definition extends SsaImpl::Definition {
final AssignableRead getARead() {
exists(SsaInput::BasicBlock bb, int i |
exists(BasicBlock bb, int i |
SsaImpl::ssaDefReachesRead(_, this, bb, i) and
result = bb.getElement(i)
)
}
final AssignableDefinition getDefinition() {
exists(SsaInput::BasicBlock bb, int i, SsaInput::SourceVariable v |
exists(BasicBlock bb, int i, SourceVariable v |
this.definesAt(v, bb, i) and
definitionAt(result, bb, i, v)
)
}
final AssignableRead getAFirstRead() {
exists(SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2 |
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
this.definesAt(_, bb1, i1) and
SsaImpl::adjacentDefRead(this, bb1, i1, bb2, i2) and
result = bb2.getElement(i2)
@@ -174,14 +42,14 @@ module PreSsa {
not result instanceof PhiNode
}
final predicate isLiveAtEndOfBlock(SsaInput::BasicBlock bb) {
final predicate isLiveAtEndOfBlock(BasicBlock bb) {
SsaImpl::ssaDefReachesEndOfBlock(bb, this, _)
}
Location getLocation() {
result = this.getDefinition().getLocation()
or
exists(Callable c, SsaInput::BasicBlock bb, SsaInput::SourceVariable v |
exists(Callable c, BasicBlock bb, SourceVariable v |
this.definesAt(v, bb, -1) and
implicitEntryDef(c, bb, v) and
result = c.getLocation()
@@ -196,9 +64,9 @@ module PreSsa {
}
predicate adjacentReadPairSameVar(AssignableRead read1, AssignableRead read2) {
exists(SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2 |
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
read1 = bb1.getElement(i1) and
SsaInput::variableRead(bb1, i1, _, true) and
variableRead(bb1, i1, _, true) and
SsaImpl::adjacentDefRead(_, bb1, i1, bb2, i2) and
read2 = bb2.getElement(i2)
)

View File

@@ -0,0 +1,795 @@
/**
* Provides a language-independent implementation of static single assignment
* (SSA) form.
*/
private import SsaImplSpecific
private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb }
/**
* Liveness analysis (based on source variables) to restrict the size of the
* SSA representation.
*/
private module Liveness {
/**
* A classification of variable references into reads (of a given kind) and
* (certain or uncertain) writes.
*/
private newtype TRefKind =
Read(boolean certain) { certain in [false, true] } or
Write(boolean certain) { certain in [false, true] }
private class RefKind extends TRefKind {
string toString() {
exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")")
or
exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")")
}
int getOrder() {
this = Read(_) and
result = 0
or
this = Write(_) and
result = 1
}
}
/**
* Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`.
*/
predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain))
or
exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain))
}
private newtype OrderedRefIndex =
MkOrderedRefIndex(int i, int tag) {
exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder())
}
private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) {
ref(bb, i, v, k) and
result = MkOrderedRefIndex(i, ord) and
ord = k.getOrder()
}
/**
* Gets the (1-based) rank of the reference to `v` at the `i`th node of
* basic block `bb`, which has the given reference kind `k`.
*
* Reads are considered before writes when they happen at the same index.
*/
private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) {
refOrd(bb, i, v, k, _) =
rank[result](int j, int ord, OrderedRefIndex res |
res = refOrd(bb, j, v, _, ord)
|
res order by j, ord
)
}
private int maxRefRank(BasicBlock bb, SourceVariable v) {
result = refRank(bb, _, v, _) and
not result + 1 = refRank(bb, _, v, _)
}
predicate lastRefIsRead(BasicBlock bb, SourceVariable v) {
maxRefRank(bb, v) = refRank(bb, _, v, Read(_))
}
/**
* Gets the (1-based) rank of the first reference to `v` inside basic block `bb`
* that is either a read or a certain write.
*/
private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) {
result =
min(int r, RefKind k |
r = refRank(bb, _, v, k) and
k != Write(false)
|
r
)
}
/**
* Holds if source variable `v` is live at the beginning of basic block `bb`.
*/
predicate liveAtEntry(BasicBlock bb, SourceVariable v) {
// The first read or certain write to `v` inside `bb` is a read
refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v)
or
// There is no certain write to `v` inside `bb`, but `v` is live at entry
// to a successor basic block of `bb`
not exists(firstReadOrCertainWrite(bb, v)) and
liveAtExit(bb, v)
}
/**
* Holds if source variable `v` is live at the end of basic block `bb`.
*/
predicate liveAtExit(BasicBlock bb, SourceVariable v) {
liveAtEntry(getABasicBlockSuccessor(bb), v)
}
/**
* Holds if variable `v` is live in basic block `bb` at index `i`.
* The rank of `i` is `rnk` as defined by `refRank()`.
*/
private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) {
exists(RefKind kind | rnk = refRank(bb, i, v, kind) |
rnk = maxRefRank(bb, v) and
liveAtExit(bb, v)
or
ref(bb, i, v, kind) and
kind = Read(_)
or
exists(RefKind nextKind |
liveAtRank(bb, _, v, rnk + 1) and
rnk + 1 = refRank(bb, _, v, nextKind) and
nextKind != Write(true)
)
)
}
/**
* Holds if variable `v` is live after the (certain or uncertain) write at
* index `i` inside basic block `bb`.
*/
predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) {
exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk))
}
}
private import Liveness
/**
* Holds if `df` is in the dominance frontier of `bb`.
*
* This is equivalent to:
*
* ```ql
* bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and
* not bb = getImmediateBasicBlockDominator+(df)
* ```
*/
private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) {
bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df)
or
exists(BasicBlock prev | inDominanceFrontier(prev, df) |
bb = getImmediateBasicBlockDominator(prev) and
not bb = getImmediateBasicBlockDominator(df)
)
}
/**
* Holds if `bb` is in the dominance frontier of a block containing a
* definition of `v`.
*/
pragma[noinline]
private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) {
exists(BasicBlock defbb, Definition def |
def.definesAt(v, defbb, _) and
inDominanceFrontier(defbb, bb)
)
}
cached
newtype TDefinition =
TWriteDef(SourceVariable v, BasicBlock bb, int i) {
variableWrite(bb, i, v, _) and
liveAfterWrite(bb, i, v)
} or
TPhiNode(SourceVariable v, BasicBlock bb) {
inDefDominanceFrontier(bb, v) and
liveAtEntry(bb, v)
}
private module SsaDefReaches {
newtype TSsaRefKind =
SsaActualRead() or
SsaPhiRead() or
SsaDef()
class SsaRead = SsaActualRead or SsaPhiRead;
/**
* A classification of SSA variable references into reads and definitions.
*/
class SsaRefKind extends TSsaRefKind {
string toString() {
this = SsaActualRead() and
result = "SsaActualRead"
or
this = SsaPhiRead() and
result = "SsaPhiRead"
or
this = SsaDef() and
result = "SsaDef"
}
int getOrder() {
this instanceof SsaRead and
result = 0
or
this = SsaDef() and
result = 1
}
}
/**
* Holds if `bb` is in the dominance frontier of a block containing a
* read of `v`.
*/
pragma[nomagic]
private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) {
exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) |
lastRefIsRead(readbb, v)
or
phiRead(readbb, v)
)
}
/**
* Holds if a phi-read node should be inserted for variable `v` at the beginning
* of basic block `bb`.
*
* Phi-read nodes are like normal phi nodes, but they are inserted based on reads
* instead of writes, and only if the dominance-frontier block does not already
* contain a reference (read or write) to `v`. Unlike normal phi nodes, this is
* an internal implementation detail that is not exposed.
*
* The motivation for adding phi-reads is to improve performance of the use-use
* calculation in cases where there is a large number of reads that can reach the
* same join-point, and from there reach a large number of basic blocks. Example:
*
* ```cs
* if (a)
* use(x);
* else if (b)
* use(x);
* else if (c)
* use(x);
* else if (d)
* use(x);
* // many more ifs ...
*
* // phi-read for `x` inserted here
*
* // program not mentioning `x`, with large basic block graph
*
* use(x);
* ```
*
* Without phi-reads, the analysis has to replicate reachability for each of
* the guarded uses of `x`. However, with phi-reads, the analysis will limit
* each conditional use of `x` to reach the basic block containing the phi-read
* node for `x`, and only that basic block will have to compute reachability
* through the remainder of the large program.
*
* Like normal reads, each phi-read node `phi-read` can be reached from exactly
* one SSA definition (without passing through another definition): Assume, for
* the sake of contradiction, that there are two reaching definitions `def1` and
* `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest
* dominating definition will prevent the other from reaching `phi-read`. So, at
* least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`.
* Then `def1` must go through one of its dominance-frontier blocks in order to
* reach `phi-read`. However, such a block will always start with a (normal) phi
* node, which contradicts reachability.
*
* Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`,
* will dominate `phi-read`. Assuming it doesn't means that the path from `def`
* to `phi-read` goes through a dominance-frontier block, and hence a phi node,
* which contradicts reachability.
*/
pragma[nomagic]
predicate phiRead(BasicBlock bb, SourceVariable v) {
inReadDominanceFrontier(bb, v) and
liveAtEntry(bb, v) and
// only if there are no other references to `v` inside `bb`
not ref(bb, _, v, _) and
not exists(Definition def | def.definesAt(v, bb, _))
}
/**
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
* either a read (when `k` is `SsaRead()`) or an SSA definition (when `k`
* is `SsaDef()`).
*
* Unlike `Liveness::ref`, this includes `phi` nodes.
*/
pragma[nomagic]
predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
variableRead(bb, i, v, _) and
k = SsaActualRead()
or
phiRead(bb, v) and
i = -1 and
k = SsaPhiRead()
or
any(Definition def).definesAt(v, bb, i) and
k = SsaDef()
}
private newtype OrderedSsaRefIndex =
MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) }
private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) {
ssaRef(bb, i, v, k) and
result = MkOrderedSsaRefIndex(i, k) and
ord = k.getOrder()
}
/**
* Gets the (1-based) rank of the reference to `v` at the `i`th node of basic
* block `bb`, which has the given reference kind `k`.
*
* For example, if `bb` is a basic block with a phi node for `v` (considered
* to be at index -1), reads `v` at node 2, and defines it at node 5, we have:
*
* ```ql
* ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node
* ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2
* ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5
* ```
*
* Reads are considered before writes when they happen at the same index.
*/
int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
ssaRefOrd(bb, i, v, k, _) =
rank[result](int j, int ord, OrderedSsaRefIndex res |
res = ssaRefOrd(bb, j, v, _, ord)
|
res order by j, ord
)
}
int maxSsaRefRank(BasicBlock bb, SourceVariable v) {
result = ssaRefRank(bb, _, v, _) and
not result + 1 = ssaRefRank(bb, _, v, _)
}
/**
* Holds if the SSA definition `def` reaches rank index `rnk` in its own
* basic block `bb`.
*/
predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) {
exists(int i |
rnk = ssaRefRank(bb, i, v, SsaDef()) and
def.definesAt(v, bb, i)
)
or
ssaDefReachesRank(bb, def, rnk - 1, v) and
rnk = ssaRefRank(bb, _, v, any(SsaRead k))
}
/**
* Holds if the SSA definition of `v` at `def` reaches index `i` in the same
* basic block `bb`, without crossing another SSA definition of `v`.
*/
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
exists(int rnk |
ssaDefReachesRank(bb, def, rnk, v) and
rnk = ssaRefRank(bb, i, v, any(SsaRead k))
)
}
/**
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
*/
int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) {
v = def.getSourceVariable() and
result = ssaRefRank(bb, i, v, k) and
(
ssaDefReachesRead(_, def, bb, i)
or
def.definesAt(_, bb, i)
)
}
/**
* Holds if the reference to `def` at index `i` in basic block `bb` is the
* last reference to `v` inside `bb`.
*/
pragma[noinline]
predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) {
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
}
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) {
exists(ssaDefRank(def, v, bb, _, k))
}
pragma[noinline]
private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) {
ssaDefReachesEndOfBlock(bb, def, _) and
not defOccursInBlock(_, bb, def.getSourceVariable(), _)
}
/**
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
* `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_
* predecessor of `bb2`, and the underlying variable for `def` is neither read
* nor written in any block on the path between `bb1` and `bb2`.
*
* Phi reads are considered as normal reads for this predicate.
*/
pragma[nomagic]
private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
defOccursInBlock(def, bb1, _, _) and
bb2 = getABasicBlockSuccessor(bb1)
or
exists(BasicBlock mid |
varBlockReachesInclPhiRead(def, bb1, mid) and
ssaDefReachesThroughBlock(def, mid) and
bb2 = getABasicBlockSuccessor(mid)
)
}
pragma[nomagic]
private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) {
varBlockReachesInclPhiRead(def, bb1, bb2) and
defOccursInBlock(def, bb2, v, SsaPhiRead())
}
pragma[nomagic]
private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and
ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()])
or
exists(BasicBlock mid |
varBlockReachesExclPhiRead(def, mid, bb2) and
phiReadStep(def, _, bb1, mid)
)
}
/**
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
* the underlying variable `v` of `def` is accessed in basic block `bb2`
* (either a read or a write), `bb2` is a transitive successor of `bb1`, and
* `v` is neither read nor written in any block on the path between `bb1`
* and `bb2`.
*/
pragma[nomagic]
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
varBlockReachesExclPhiRead(def, bb1, bb2) and
not defOccursInBlock(def, bb1, _, SsaPhiRead())
}
pragma[nomagic]
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
varBlockReaches(def, bb1, bb2) and
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1
}
/**
* Holds if `def` is accessed in basic block `bb` (either a read or a write),
* `bb1` can reach a transitive successor `bb2` where `def` is no longer live,
* and `v` is neither read nor written in any block on the path between `bb`
* and `bb2`.
*/
pragma[nomagic]
predicate varBlockReachesExit(Definition def, BasicBlock bb) {
exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) |
not defOccursInBlock(def, bb2, _, _) and
not ssaDefReachesEndOfBlock(bb2, def, _)
)
or
exists(BasicBlock mid |
varBlockReachesExit(def, mid) and
phiReadStep(def, _, bb, mid)
)
}
}
predicate phiReadExposedForTesting = phiRead/2;
private import SsaDefReaches
pragma[nomagic]
predicate liveThrough(BasicBlock bb, SourceVariable v) {
liveAtExit(bb, v) and
not ssaRef(bb, _, v, SsaDef())
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if the SSA definition of `v` at `def` reaches the end of basic
* block `bb`, at which point it is still live, without crossing another
* SSA definition of `v`.
*/
pragma[nomagic]
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) {
exists(int last |
last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and
ssaDefReachesRank(bb, def, last, v) and
liveAtExit(bb, v)
)
or
// The construction of SSA form ensures that each read of a variable is
// dominated by its definition. An SSA definition therefore reaches a
// control flow node if it is the _closest_ SSA definition that dominates
// the node. If two definitions dominate a node then one must dominate the
// other, so therefore the definition of _closest_ is given by the dominator
// tree. Thus, reaching definitions can be calculated in terms of dominance.
ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and
liveThrough(bb, pragma[only_bind_into](v))
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`.
*/
pragma[nomagic]
predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) {
exists(SourceVariable v, BasicBlock bbDef |
phi.definesAt(v, bbDef, _) and
getABasicBlockPredecessor(bbDef) = bb and
ssaDefReachesEndOfBlock(bb, inp, v)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if the SSA definition of `v` at `def` reaches a read at index `i` in
* basic block `bb`, without crossing another SSA definition of `v`. The read
* is of kind `rk`.
*/
pragma[nomagic]
predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) {
ssaDefReachesReadWithinBlock(v, def, bb, i)
or
ssaRef(bb, i, v, any(SsaRead k)) and
ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and
not ssaDefReachesReadWithinBlock(v, _, bb, i)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read
* or a write), `def` is read at index `i2` in basic block `bb2`, and there is a
* path between them without any read of `def`.
*/
pragma[nomagic]
predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
exists(int rnk |
rnk = ssaDefRank(def, _, bb1, i1, _) and
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and
variableRead(bb1, i2, _, _) and
bb2 = bb1
)
or
lastSsaRef(def, _, bb1, i1) and
defAdjacentRead(def, bb1, bb2, i2)
}
pragma[noinline]
private predicate adjacentDefRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v
) {
adjacentDefRead(def, bb1, i1, bb2, i2) and
v = def.getSourceVariable()
}
private predicate adjacentDefReachesRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) |
ssaRef(bb1, i1, v, SsaDef())
or
variableRead(bb1, i1, v, true)
)
or
exists(BasicBlock bb3, int i3 |
adjacentDefReachesRead(def, bb1, i1, bb3, i3) and
variableRead(bb3, i3, _, false) and
adjacentDefRead(def, bb3, i3, bb2, i2)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Same as `adjacentDefRead`, but ignores uncertain reads.
*/
pragma[nomagic]
predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
variableRead(bb2, i2, _, true)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if the node at index `i` in `bb` is a last reference to SSA definition
* `def`. The reference is last because it can reach another write `next`,
* without passing through another read or write.
*/
pragma[nomagic]
predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) {
exists(SourceVariable v |
// Next reference to `v` inside `bb` is a write
exists(int rnk, int j |
rnk = ssaDefRank(def, v, bb, i, _) and
next.definesAt(v, bb, j) and
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
)
or
// Can reach a write using one or more steps
lastSsaRef(def, v, bb, i) and
exists(BasicBlock bb2 |
varBlockReaches(def, bb, bb2) and
1 = ssaDefRank(next, v, bb2, _, SsaDef())
)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if `inp` is an immediately preceding definition of uncertain definition
* `def`. Since `def` is uncertain, the value from the preceding definition might
* still be valid.
*/
pragma[nomagic]
predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) {
lastRefRedef(inp, _, _, def)
}
private predicate adjacentDefReachesUncertainRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
variableRead(bb2, i2, _, false)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Same as `lastRefRedef`, but ignores uncertain reads.
*/
pragma[nomagic]
predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) {
lastRefRedef(def, bb, i, next) and
not variableRead(bb, i, def.getSourceVariable(), false)
or
exists(BasicBlock bb0, int i0 |
lastRefRedef(def, bb0, i0, next) and
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if the node at index `i` in `bb` is a last reference to SSA
* definition `def`.
*
* That is, the node can reach the end of the enclosing callable, or another
* SSA definition for the underlying source variable, without passing through
* another read.
*/
pragma[nomagic]
predicate lastRef(Definition def, BasicBlock bb, int i) {
// Can reach another definition
lastRefRedef(def, bb, i, _)
or
exists(SourceVariable v | lastSsaRef(def, v, bb, i) |
// Can reach exit directly
bb instanceof ExitBasicBlock
or
// Can reach a block using one or more steps, where `def` is no longer live
varBlockReachesExit(def, bb)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Same as `lastRefRedef`, but ignores uncertain reads.
*/
pragma[nomagic]
predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) {
lastRef(def, bb, i) and
not variableRead(bb, i, def.getSourceVariable(), false)
or
exists(BasicBlock bb0, int i0 |
lastRef(def, bb0, i0) and
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
)
}
/** A static single assignment (SSA) definition. */
class Definition extends TDefinition {
/** Gets the source variable underlying this SSA definition. */
SourceVariable getSourceVariable() { this.definesAt(result, _, _) }
/**
* Holds if this SSA definition defines `v` at index `i` in basic block `bb`.
* Phi nodes are considered to be at index `-1`, while normal variable writes
* are at the index of the control flow node they wrap.
*/
final predicate definesAt(SourceVariable v, BasicBlock bb, int i) {
this = TWriteDef(v, bb, i)
or
this = TPhiNode(v, bb) and i = -1
}
/** Gets the basic block to which this SSA definition belongs. */
final BasicBlock getBasicBlock() { this.definesAt(_, result, _) }
/** Gets a textual representation of this SSA definition. */
string toString() { none() }
}
/** An SSA definition that corresponds to a write. */
class WriteDefinition extends Definition, TWriteDef {
private SourceVariable v;
private BasicBlock bb;
private int i;
WriteDefinition() { this = TWriteDef(v, bb, i) }
override string toString() { result = "WriteDef" }
}
/** A phi node. */
class PhiNode extends Definition, TPhiNode {
override string toString() { result = "Phi" }
}
/**
* An SSA definition that represents an uncertain update of the underlying
* source variable.
*/
class UncertainWriteDefinition extends WriteDefinition {
UncertainWriteDefinition() {
exists(SourceVariable v, BasicBlock bb, int i |
this.definesAt(v, bb, i) and
variableWrite(bb, i, v, false)
)
}
}
/** Provides a set of consistency queries. */
module Consistency {
abstract class RelevantDefinition extends Definition {
abstract predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
);
}
query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
ssaDefReachesRead(v, def, bb, i) and
not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i)))
}
query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) {
variableRead(bb, i, v, _) and
not ssaDefReachesRead(v, _, bb, i)
}
query predicate deadDef(RelevantDefinition def, SourceVariable v) {
v = def.getSourceVariable() and
not ssaDefReachesRead(_, def, _, _) and
not phiHasInputFromBlock(_, def, _) and
not uncertainWriteDefinitionInput(_, def)
}
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
ssaDefReachesReadWithinBlock(v, def, bb, i) and
(bb != bbDef or i < iDef)
or
ssaDefReachesRead(v, def, bb, i) and
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
)
}
}

View File

@@ -0,0 +1,130 @@
/** Provides the C# specific parameters for `SsaImplCommon.qll`. */
private import csharp
private import AssignableDefinitions
private import semmle.code.csharp.controlflow.internal.PreBasicBlocks as PreBasicBlocks
private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl
class BasicBlock = PreBasicBlocks::PreBasicBlock;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class ExitBasicBlock extends BasicBlock {
ExitBasicBlock() { scopeLast(_, this.getLastElement(), _) }
}
/** Holds if `a` is assigned in non-constructor callable `c`. */
pragma[nomagic]
private predicate assignableDefinition(Assignable a, Callable c) {
exists(AssignableDefinition def | def.getTarget() = a |
c = def.getEnclosingCallable() and
not c instanceof Constructor
)
}
/** Holds if `a` is accessed in callable `c`. */
pragma[nomagic]
private predicate assignableAccess(Assignable a, Callable c) {
exists(AssignableAccess aa | aa.getTarget() = a | c = aa.getEnclosingCallable())
}
pragma[nomagic]
private predicate assignableNoCapturing(Assignable a, Callable c) {
assignableAccess(a, c) and
/*
* The code below is equivalent to
* ```ql
* not exists(Callable other | assignableDefinition(a, other) | other != c)
* ```
* but it avoids a Cartesian product in the compiler generated antijoin
* predicate.
*/
(
not assignableDefinition(a, _)
or
c = unique(Callable c0 | assignableDefinition(a, c0) | c0)
)
}
pragma[noinline]
private predicate assignableNoComplexQualifiers(Assignable a) {
forall(QualifiableExpr qe | qe.(AssignableAccess).getTarget() = a | qe.targetIsThisInstance())
}
/**
* A simple assignable. Either a local scope variable or a field/property
* that behaves like a local scope variable.
*/
class SourceVariable extends Assignable {
private Callable c;
SourceVariable() {
(
this instanceof LocalScopeVariable
or
this = any(Field f | not f.isVolatile())
or
this = any(TrivialProperty tp | not tp.isOverridableOrImplementable())
) and
assignableNoCapturing(this, c) and
assignableNoComplexQualifiers(this)
}
/** Gets a callable in which this simple assignable can be analyzed. */
Callable getACallable() { result = c }
}
predicate definitionAt(AssignableDefinition def, BasicBlock bb, int i, SourceVariable v) {
bb.getElement(i) = def.getExpr() and
v = def.getTarget() and
// In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x`
not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def |
second.getAssignment() = first.getAssignment() and
second.getEvaluationOrder() > first.getEvaluationOrder() and
second.getTarget() = v
)
or
def.(ImplicitParameterDefinition).getParameter() = v and
exists(Callable c | v = c.getAParameter() |
scopeFirst(c, bb) and
i = -1
)
}
predicate implicitEntryDef(Callable c, BasicBlock bb, SourceVariable v) {
not v instanceof LocalScopeVariable and
c = v.getACallable() and
scopeFirst(c, bb)
}
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(AssignableDefinition def |
definitionAt(def, bb, i, v) and
if def.getTargetAccess().isRefArgument() then certain = false else certain = true
)
or
exists(Callable c |
implicitEntryDef(c, bb, v) and
i = -1 and
certain = true
)
}
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(AssignableRead read |
read = bb.getElement(i) and
read.getTarget() = v and
certain = true
)
or
v =
any(LocalScopeVariable lsv |
lsv.getCallable() = bb.(ExitBasicBlock).getEnclosingCallable() and
i = bb.length() and
(lsv.isRef() or v.(Parameter).isOut()) and
certain = false
)
}

View File

@@ -12,8 +12,6 @@
* `namespace; type; subtypes; name; signature; ext; input; output; kind; provenance`
* - Negative Summaries:
* `namespace; type; name; signature; provenance`
* A negative summary is used to indicate that there is no flow via a callable.
*
* The interpretation of a row is similar to API-graphs with a left-to-right
* reading.
* 1. The `namespace` column selects a namespace.

View File

@@ -4,74 +4,19 @@ import csharp
* Provides a simple SSA implementation for local scope variables.
*/
module BaseSsa {
private import AssignableDefinitions
private import semmle.code.csharp.dataflow.internal.SsaImplCommon as SsaImplCommon
/**
* Holds if the `i`th node of basic block `bb` is assignable definition `def`,
* targeting local scope variable `v`.
*/
private predicate definitionAt(
AssignableDefinition def, ControlFlow::BasicBlock bb, int i, SsaInput::SourceVariable v
) {
bb.getNode(i) = def.getAControlFlowNode() and
v = def.getTarget() and
// In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x`
not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def |
second.getAssignment() = first.getAssignment() and
second.getEvaluationOrder() > first.getEvaluationOrder() and
second.getTarget() = v
)
}
private module SsaInput implements SsaImplCommon::InputSig {
class BasicBlock = ControlFlow::BasicBlock;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
result = bb.getImmediateDominator()
}
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class ExitBasicBlock = ControlFlow::BasicBlocks::ExitBlock;
pragma[noinline]
private Callable getAnAssigningCallable(LocalScopeVariable v) {
result = any(AssignableDefinition def | def.getTarget() = v).getEnclosingCallable()
}
class SourceVariable extends LocalScopeVariable {
SourceVariable() { not getAnAssigningCallable(this) != getAnAssigningCallable(this) }
}
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(AssignableDefinition def |
definitionAt(def, bb, i, v) and
if def.isCertain() then certain = true else certain = false
)
}
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(AssignableRead read |
read.getAControlFlowNode() = bb.getNode(i) and
read.getTarget() = v and
certain = true
)
}
}
private module SsaImpl = SsaImplCommon::Make<SsaInput>;
import basessa.SsaImplSpecific
private import basessa.SsaImplCommon as SsaImpl
class Definition extends SsaImpl::Definition {
final AssignableRead getARead() {
exists(ControlFlow::BasicBlock bb, int i |
exists(BasicBlock bb, int i |
SsaImpl::ssaDefReachesRead(_, this, bb, i) and
result.getAControlFlowNode() = bb.getNode(i)
)
}
final AssignableDefinition getDefinition() {
exists(ControlFlow::BasicBlock bb, int i, SsaInput::SourceVariable v |
exists(BasicBlock bb, int i, SourceVariable v |
this.definesAt(v, bb, i) and
definitionAt(result, bb, i, v)
)

View File

@@ -3,53 +3,7 @@
*/
import csharp
private import SsaImplCommon as SsaImplCommon
private import AssignableDefinitions
private module SsaInput implements SsaImplCommon::InputSig {
class BasicBlock = ControlFlow::BasicBlock;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class ExitBasicBlock = ControlFlow::BasicBlocks::ExitBlock;
class SourceVariable = Ssa::SourceVariable;
/**
* Holds if the `i`th node of basic block `bb` is a (potential) write to source
* variable `v`. The Boolean `certain` indicates whether the write is certain.
*
* This includes implicit writes via calls.
*/
predicate variableWrite(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) {
variableWriteDirect(bb, i, v, certain)
or
variableWriteQualifier(bb, i, v, certain)
or
updatesNamedFieldOrProp(bb, i, _, v, _) and
certain = false
or
updatesCapturedVariable(bb, i, _, v, _, _) and
certain = false
}
/**
* Holds if the `i`th of basic block `bb` reads source variable `v`.
*
* This includes implicit reads via calls.
*/
predicate variableRead(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) {
variableReadActual(bb, i, v) and
certain = true
or
variableReadPseudo(bb, i, v) and
certain = false
}
}
import SsaImplCommon::Make<SsaInput>
import SsaImplCommon
/**
* Holds if the `i`th node of basic block `bb` reads source variable `v`.
@@ -851,6 +805,24 @@ private module CapturedVariableImpl {
}
}
/**
* Holds if the `i`th node of basic block `bb` is a (potential) write to source
* variable `v`. The Boolean `certain` indicates whether the write is certain.
*
* This includes implicit writes via calls.
*/
predicate variableWrite(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) {
variableWriteDirect(bb, i, v, certain)
or
variableWriteQualifier(bb, i, v, certain)
or
updatesNamedFieldOrProp(bb, i, _, v, _) and
certain = false
or
updatesCapturedVariable(bb, i, _, v, _, _) and
certain = false
}
/**
* Liveness analysis to restrict the size of the SSA representation for
* captured variables.
@@ -1067,6 +1039,19 @@ private predicate variableReadPseudo(ControlFlow::BasicBlock bb, int i, Ssa::Sou
capturedReadIn(bb, i, v, _, _, _)
}
/**
* Holds if the `i`th of basic block `bb` reads source variable `v`.
*
* This includes implicit reads via calls.
*/
predicate variableRead(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) {
variableReadActual(bb, i, v) and
certain = true
or
variableReadPseudo(bb, i, v) and
certain = false
}
cached
private module Cached {
cached
@@ -1166,7 +1151,7 @@ private module Cached {
predicate variableWriteQualifier(
ControlFlow::BasicBlock bb, int i, QualifiedFieldOrPropSourceVariable v, boolean certain
) {
SsaInput::variableWrite(bb, i, v.getQualifier(), certain) and
variableWrite(bb, i, v.getQualifier(), certain) and
// Eliminate corner case where a call definition can overlap with a
// qualifier definition: if method `M` updates field `F`, then a call
// to `M` is both an update of `x.M` and `x.M.M`, so the former call

View File

@@ -0,0 +1,19 @@
/** Provides the C# specific parameters for `SsaImplCommon.qll`. */
private import csharp
private import AssignableDefinitions
private import SsaImpl as SsaImpl
class BasicBlock = ControlFlow::BasicBlock;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class ExitBasicBlock = ControlFlow::BasicBlocks::ExitBlock;
class SourceVariable = Ssa::SourceVariable;
predicate variableWrite = SsaImpl::variableWrite/4;
predicate variableRead = SsaImpl::variableRead/4;

View File

@@ -0,0 +1,795 @@
/**
* Provides a language-independent implementation of static single assignment
* (SSA) form.
*/
private import SsaImplSpecific
private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb }
/**
* Liveness analysis (based on source variables) to restrict the size of the
* SSA representation.
*/
private module Liveness {
/**
* A classification of variable references into reads (of a given kind) and
* (certain or uncertain) writes.
*/
private newtype TRefKind =
Read(boolean certain) { certain in [false, true] } or
Write(boolean certain) { certain in [false, true] }
private class RefKind extends TRefKind {
string toString() {
exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")")
or
exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")")
}
int getOrder() {
this = Read(_) and
result = 0
or
this = Write(_) and
result = 1
}
}
/**
* Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`.
*/
predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain))
or
exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain))
}
private newtype OrderedRefIndex =
MkOrderedRefIndex(int i, int tag) {
exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder())
}
private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) {
ref(bb, i, v, k) and
result = MkOrderedRefIndex(i, ord) and
ord = k.getOrder()
}
/**
* Gets the (1-based) rank of the reference to `v` at the `i`th node of
* basic block `bb`, which has the given reference kind `k`.
*
* Reads are considered before writes when they happen at the same index.
*/
private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) {
refOrd(bb, i, v, k, _) =
rank[result](int j, int ord, OrderedRefIndex res |
res = refOrd(bb, j, v, _, ord)
|
res order by j, ord
)
}
private int maxRefRank(BasicBlock bb, SourceVariable v) {
result = refRank(bb, _, v, _) and
not result + 1 = refRank(bb, _, v, _)
}
predicate lastRefIsRead(BasicBlock bb, SourceVariable v) {
maxRefRank(bb, v) = refRank(bb, _, v, Read(_))
}
/**
* Gets the (1-based) rank of the first reference to `v` inside basic block `bb`
* that is either a read or a certain write.
*/
private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) {
result =
min(int r, RefKind k |
r = refRank(bb, _, v, k) and
k != Write(false)
|
r
)
}
/**
* Holds if source variable `v` is live at the beginning of basic block `bb`.
*/
predicate liveAtEntry(BasicBlock bb, SourceVariable v) {
// The first read or certain write to `v` inside `bb` is a read
refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v)
or
// There is no certain write to `v` inside `bb`, but `v` is live at entry
// to a successor basic block of `bb`
not exists(firstReadOrCertainWrite(bb, v)) and
liveAtExit(bb, v)
}
/**
* Holds if source variable `v` is live at the end of basic block `bb`.
*/
predicate liveAtExit(BasicBlock bb, SourceVariable v) {
liveAtEntry(getABasicBlockSuccessor(bb), v)
}
/**
* Holds if variable `v` is live in basic block `bb` at index `i`.
* The rank of `i` is `rnk` as defined by `refRank()`.
*/
private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) {
exists(RefKind kind | rnk = refRank(bb, i, v, kind) |
rnk = maxRefRank(bb, v) and
liveAtExit(bb, v)
or
ref(bb, i, v, kind) and
kind = Read(_)
or
exists(RefKind nextKind |
liveAtRank(bb, _, v, rnk + 1) and
rnk + 1 = refRank(bb, _, v, nextKind) and
nextKind != Write(true)
)
)
}
/**
* Holds if variable `v` is live after the (certain or uncertain) write at
* index `i` inside basic block `bb`.
*/
predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) {
exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk))
}
}
private import Liveness
/**
* Holds if `df` is in the dominance frontier of `bb`.
*
* This is equivalent to:
*
* ```ql
* bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and
* not bb = getImmediateBasicBlockDominator+(df)
* ```
*/
private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) {
bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df)
or
exists(BasicBlock prev | inDominanceFrontier(prev, df) |
bb = getImmediateBasicBlockDominator(prev) and
not bb = getImmediateBasicBlockDominator(df)
)
}
/**
* Holds if `bb` is in the dominance frontier of a block containing a
* definition of `v`.
*/
pragma[noinline]
private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) {
exists(BasicBlock defbb, Definition def |
def.definesAt(v, defbb, _) and
inDominanceFrontier(defbb, bb)
)
}
cached
newtype TDefinition =
TWriteDef(SourceVariable v, BasicBlock bb, int i) {
variableWrite(bb, i, v, _) and
liveAfterWrite(bb, i, v)
} or
TPhiNode(SourceVariable v, BasicBlock bb) {
inDefDominanceFrontier(bb, v) and
liveAtEntry(bb, v)
}
private module SsaDefReaches {
newtype TSsaRefKind =
SsaActualRead() or
SsaPhiRead() or
SsaDef()
class SsaRead = SsaActualRead or SsaPhiRead;
/**
* A classification of SSA variable references into reads and definitions.
*/
class SsaRefKind extends TSsaRefKind {
string toString() {
this = SsaActualRead() and
result = "SsaActualRead"
or
this = SsaPhiRead() and
result = "SsaPhiRead"
or
this = SsaDef() and
result = "SsaDef"
}
int getOrder() {
this instanceof SsaRead and
result = 0
or
this = SsaDef() and
result = 1
}
}
/**
* Holds if `bb` is in the dominance frontier of a block containing a
* read of `v`.
*/
pragma[nomagic]
private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) {
exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) |
lastRefIsRead(readbb, v)
or
phiRead(readbb, v)
)
}
/**
* Holds if a phi-read node should be inserted for variable `v` at the beginning
* of basic block `bb`.
*
* Phi-read nodes are like normal phi nodes, but they are inserted based on reads
* instead of writes, and only if the dominance-frontier block does not already
* contain a reference (read or write) to `v`. Unlike normal phi nodes, this is
* an internal implementation detail that is not exposed.
*
* The motivation for adding phi-reads is to improve performance of the use-use
* calculation in cases where there is a large number of reads that can reach the
* same join-point, and from there reach a large number of basic blocks. Example:
*
* ```cs
* if (a)
* use(x);
* else if (b)
* use(x);
* else if (c)
* use(x);
* else if (d)
* use(x);
* // many more ifs ...
*
* // phi-read for `x` inserted here
*
* // program not mentioning `x`, with large basic block graph
*
* use(x);
* ```
*
* Without phi-reads, the analysis has to replicate reachability for each of
* the guarded uses of `x`. However, with phi-reads, the analysis will limit
* each conditional use of `x` to reach the basic block containing the phi-read
* node for `x`, and only that basic block will have to compute reachability
* through the remainder of the large program.
*
* Like normal reads, each phi-read node `phi-read` can be reached from exactly
* one SSA definition (without passing through another definition): Assume, for
* the sake of contradiction, that there are two reaching definitions `def1` and
* `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest
* dominating definition will prevent the other from reaching `phi-read`. So, at
* least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`.
* Then `def1` must go through one of its dominance-frontier blocks in order to
* reach `phi-read`. However, such a block will always start with a (normal) phi
* node, which contradicts reachability.
*
* Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`,
* will dominate `phi-read`. Assuming it doesn't means that the path from `def`
* to `phi-read` goes through a dominance-frontier block, and hence a phi node,
* which contradicts reachability.
*/
pragma[nomagic]
predicate phiRead(BasicBlock bb, SourceVariable v) {
inReadDominanceFrontier(bb, v) and
liveAtEntry(bb, v) and
// only if there are no other references to `v` inside `bb`
not ref(bb, _, v, _) and
not exists(Definition def | def.definesAt(v, bb, _))
}
/**
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
* either a read (when `k` is `SsaRead()`) or an SSA definition (when `k`
* is `SsaDef()`).
*
* Unlike `Liveness::ref`, this includes `phi` nodes.
*/
pragma[nomagic]
predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
variableRead(bb, i, v, _) and
k = SsaActualRead()
or
phiRead(bb, v) and
i = -1 and
k = SsaPhiRead()
or
any(Definition def).definesAt(v, bb, i) and
k = SsaDef()
}
private newtype OrderedSsaRefIndex =
MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) }
private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) {
ssaRef(bb, i, v, k) and
result = MkOrderedSsaRefIndex(i, k) and
ord = k.getOrder()
}
/**
* Gets the (1-based) rank of the reference to `v` at the `i`th node of basic
* block `bb`, which has the given reference kind `k`.
*
* For example, if `bb` is a basic block with a phi node for `v` (considered
* to be at index -1), reads `v` at node 2, and defines it at node 5, we have:
*
* ```ql
* ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node
* ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2
* ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5
* ```
*
* Reads are considered before writes when they happen at the same index.
*/
int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
ssaRefOrd(bb, i, v, k, _) =
rank[result](int j, int ord, OrderedSsaRefIndex res |
res = ssaRefOrd(bb, j, v, _, ord)
|
res order by j, ord
)
}
int maxSsaRefRank(BasicBlock bb, SourceVariable v) {
result = ssaRefRank(bb, _, v, _) and
not result + 1 = ssaRefRank(bb, _, v, _)
}
/**
* Holds if the SSA definition `def` reaches rank index `rnk` in its own
* basic block `bb`.
*/
predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) {
exists(int i |
rnk = ssaRefRank(bb, i, v, SsaDef()) and
def.definesAt(v, bb, i)
)
or
ssaDefReachesRank(bb, def, rnk - 1, v) and
rnk = ssaRefRank(bb, _, v, any(SsaRead k))
}
/**
* Holds if the SSA definition of `v` at `def` reaches index `i` in the same
* basic block `bb`, without crossing another SSA definition of `v`.
*/
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
exists(int rnk |
ssaDefReachesRank(bb, def, rnk, v) and
rnk = ssaRefRank(bb, i, v, any(SsaRead k))
)
}
/**
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
*/
int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) {
v = def.getSourceVariable() and
result = ssaRefRank(bb, i, v, k) and
(
ssaDefReachesRead(_, def, bb, i)
or
def.definesAt(_, bb, i)
)
}
/**
* Holds if the reference to `def` at index `i` in basic block `bb` is the
* last reference to `v` inside `bb`.
*/
pragma[noinline]
predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) {
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
}
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) {
exists(ssaDefRank(def, v, bb, _, k))
}
pragma[noinline]
private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) {
ssaDefReachesEndOfBlock(bb, def, _) and
not defOccursInBlock(_, bb, def.getSourceVariable(), _)
}
/**
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
* `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_
* predecessor of `bb2`, and the underlying variable for `def` is neither read
* nor written in any block on the path between `bb1` and `bb2`.
*
* Phi reads are considered as normal reads for this predicate.
*/
pragma[nomagic]
private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
defOccursInBlock(def, bb1, _, _) and
bb2 = getABasicBlockSuccessor(bb1)
or
exists(BasicBlock mid |
varBlockReachesInclPhiRead(def, bb1, mid) and
ssaDefReachesThroughBlock(def, mid) and
bb2 = getABasicBlockSuccessor(mid)
)
}
pragma[nomagic]
private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) {
varBlockReachesInclPhiRead(def, bb1, bb2) and
defOccursInBlock(def, bb2, v, SsaPhiRead())
}
pragma[nomagic]
private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and
ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()])
or
exists(BasicBlock mid |
varBlockReachesExclPhiRead(def, mid, bb2) and
phiReadStep(def, _, bb1, mid)
)
}
/**
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
* the underlying variable `v` of `def` is accessed in basic block `bb2`
* (either a read or a write), `bb2` is a transitive successor of `bb1`, and
* `v` is neither read nor written in any block on the path between `bb1`
* and `bb2`.
*/
pragma[nomagic]
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
varBlockReachesExclPhiRead(def, bb1, bb2) and
not defOccursInBlock(def, bb1, _, SsaPhiRead())
}
pragma[nomagic]
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
varBlockReaches(def, bb1, bb2) and
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1
}
/**
* Holds if `def` is accessed in basic block `bb` (either a read or a write),
* `bb1` can reach a transitive successor `bb2` where `def` is no longer live,
* and `v` is neither read nor written in any block on the path between `bb`
* and `bb2`.
*/
pragma[nomagic]
predicate varBlockReachesExit(Definition def, BasicBlock bb) {
exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) |
not defOccursInBlock(def, bb2, _, _) and
not ssaDefReachesEndOfBlock(bb2, def, _)
)
or
exists(BasicBlock mid |
varBlockReachesExit(def, mid) and
phiReadStep(def, _, bb, mid)
)
}
}
predicate phiReadExposedForTesting = phiRead/2;
private import SsaDefReaches
pragma[nomagic]
predicate liveThrough(BasicBlock bb, SourceVariable v) {
liveAtExit(bb, v) and
not ssaRef(bb, _, v, SsaDef())
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if the SSA definition of `v` at `def` reaches the end of basic
* block `bb`, at which point it is still live, without crossing another
* SSA definition of `v`.
*/
pragma[nomagic]
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) {
exists(int last |
last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and
ssaDefReachesRank(bb, def, last, v) and
liveAtExit(bb, v)
)
or
// The construction of SSA form ensures that each read of a variable is
// dominated by its definition. An SSA definition therefore reaches a
// control flow node if it is the _closest_ SSA definition that dominates
// the node. If two definitions dominate a node then one must dominate the
// other, so therefore the definition of _closest_ is given by the dominator
// tree. Thus, reaching definitions can be calculated in terms of dominance.
ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and
liveThrough(bb, pragma[only_bind_into](v))
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`.
*/
pragma[nomagic]
predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) {
exists(SourceVariable v, BasicBlock bbDef |
phi.definesAt(v, bbDef, _) and
getABasicBlockPredecessor(bbDef) = bb and
ssaDefReachesEndOfBlock(bb, inp, v)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if the SSA definition of `v` at `def` reaches a read at index `i` in
* basic block `bb`, without crossing another SSA definition of `v`. The read
* is of kind `rk`.
*/
pragma[nomagic]
predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) {
ssaDefReachesReadWithinBlock(v, def, bb, i)
or
ssaRef(bb, i, v, any(SsaRead k)) and
ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and
not ssaDefReachesReadWithinBlock(v, _, bb, i)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read
* or a write), `def` is read at index `i2` in basic block `bb2`, and there is a
* path between them without any read of `def`.
*/
pragma[nomagic]
predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
exists(int rnk |
rnk = ssaDefRank(def, _, bb1, i1, _) and
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and
variableRead(bb1, i2, _, _) and
bb2 = bb1
)
or
lastSsaRef(def, _, bb1, i1) and
defAdjacentRead(def, bb1, bb2, i2)
}
pragma[noinline]
private predicate adjacentDefRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v
) {
adjacentDefRead(def, bb1, i1, bb2, i2) and
v = def.getSourceVariable()
}
private predicate adjacentDefReachesRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) |
ssaRef(bb1, i1, v, SsaDef())
or
variableRead(bb1, i1, v, true)
)
or
exists(BasicBlock bb3, int i3 |
adjacentDefReachesRead(def, bb1, i1, bb3, i3) and
variableRead(bb3, i3, _, false) and
adjacentDefRead(def, bb3, i3, bb2, i2)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Same as `adjacentDefRead`, but ignores uncertain reads.
*/
pragma[nomagic]
predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
variableRead(bb2, i2, _, true)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if the node at index `i` in `bb` is a last reference to SSA definition
* `def`. The reference is last because it can reach another write `next`,
* without passing through another read or write.
*/
pragma[nomagic]
predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) {
exists(SourceVariable v |
// Next reference to `v` inside `bb` is a write
exists(int rnk, int j |
rnk = ssaDefRank(def, v, bb, i, _) and
next.definesAt(v, bb, j) and
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
)
or
// Can reach a write using one or more steps
lastSsaRef(def, v, bb, i) and
exists(BasicBlock bb2 |
varBlockReaches(def, bb, bb2) and
1 = ssaDefRank(next, v, bb2, _, SsaDef())
)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if `inp` is an immediately preceding definition of uncertain definition
* `def`. Since `def` is uncertain, the value from the preceding definition might
* still be valid.
*/
pragma[nomagic]
predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) {
lastRefRedef(inp, _, _, def)
}
private predicate adjacentDefReachesUncertainRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
variableRead(bb2, i2, _, false)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Same as `lastRefRedef`, but ignores uncertain reads.
*/
pragma[nomagic]
predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) {
lastRefRedef(def, bb, i, next) and
not variableRead(bb, i, def.getSourceVariable(), false)
or
exists(BasicBlock bb0, int i0 |
lastRefRedef(def, bb0, i0, next) and
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if the node at index `i` in `bb` is a last reference to SSA
* definition `def`.
*
* That is, the node can reach the end of the enclosing callable, or another
* SSA definition for the underlying source variable, without passing through
* another read.
*/
pragma[nomagic]
predicate lastRef(Definition def, BasicBlock bb, int i) {
// Can reach another definition
lastRefRedef(def, bb, i, _)
or
exists(SourceVariable v | lastSsaRef(def, v, bb, i) |
// Can reach exit directly
bb instanceof ExitBasicBlock
or
// Can reach a block using one or more steps, where `def` is no longer live
varBlockReachesExit(def, bb)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Same as `lastRefRedef`, but ignores uncertain reads.
*/
pragma[nomagic]
predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) {
lastRef(def, bb, i) and
not variableRead(bb, i, def.getSourceVariable(), false)
or
exists(BasicBlock bb0, int i0 |
lastRef(def, bb0, i0) and
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
)
}
/** A static single assignment (SSA) definition. */
class Definition extends TDefinition {
/** Gets the source variable underlying this SSA definition. */
SourceVariable getSourceVariable() { this.definesAt(result, _, _) }
/**
* Holds if this SSA definition defines `v` at index `i` in basic block `bb`.
* Phi nodes are considered to be at index `-1`, while normal variable writes
* are at the index of the control flow node they wrap.
*/
final predicate definesAt(SourceVariable v, BasicBlock bb, int i) {
this = TWriteDef(v, bb, i)
or
this = TPhiNode(v, bb) and i = -1
}
/** Gets the basic block to which this SSA definition belongs. */
final BasicBlock getBasicBlock() { this.definesAt(_, result, _) }
/** Gets a textual representation of this SSA definition. */
string toString() { none() }
}
/** An SSA definition that corresponds to a write. */
class WriteDefinition extends Definition, TWriteDef {
private SourceVariable v;
private BasicBlock bb;
private int i;
WriteDefinition() { this = TWriteDef(v, bb, i) }
override string toString() { result = "WriteDef" }
}
/** A phi node. */
class PhiNode extends Definition, TPhiNode {
override string toString() { result = "Phi" }
}
/**
* An SSA definition that represents an uncertain update of the underlying
* source variable.
*/
class UncertainWriteDefinition extends WriteDefinition {
UncertainWriteDefinition() {
exists(SourceVariable v, BasicBlock bb, int i |
this.definesAt(v, bb, i) and
variableWrite(bb, i, v, false)
)
}
}
/** Provides a set of consistency queries. */
module Consistency {
abstract class RelevantDefinition extends Definition {
abstract predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
);
}
query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
ssaDefReachesRead(v, def, bb, i) and
not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i)))
}
query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) {
variableRead(bb, i, v, _) and
not ssaDefReachesRead(v, _, bb, i)
}
query predicate deadDef(RelevantDefinition def, SourceVariable v) {
v = def.getSourceVariable() and
not ssaDefReachesRead(_, def, _, _) and
not phiHasInputFromBlock(_, def, _) and
not uncertainWriteDefinitionInput(_, def)
}
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
ssaDefReachesReadWithinBlock(v, def, bb, i) and
(bb != bbDef or i < iDef)
or
ssaDefReachesRead(v, def, bb, i) and
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
)
}
}

View File

@@ -0,0 +1,51 @@
/** Provides the C# specific parameters for `SsaImplCommon.qll`. */
private import csharp
private import AssignableDefinitions
class BasicBlock = ControlFlow::BasicBlock;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class ExitBasicBlock = ControlFlow::BasicBlocks::ExitBlock;
pragma[noinline]
private Callable getAnAssigningCallable(LocalScopeVariable v) {
result = any(AssignableDefinition def | def.getTarget() = v).getEnclosingCallable()
}
class SourceVariable extends LocalScopeVariable {
SourceVariable() { not getAnAssigningCallable(this) != getAnAssigningCallable(this) }
}
/**
* Holds if the `i`th node of basic block `bb` is assignable definition `def`,
* targeting local scope variable `v`.
*/
predicate definitionAt(AssignableDefinition def, BasicBlock bb, int i, SourceVariable v) {
bb.getNode(i) = def.getAControlFlowNode() and
v = def.getTarget() and
// In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x`
not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def |
second.getAssignment() = first.getAssignment() and
second.getEvaluationOrder() > first.getEvaluationOrder() and
second.getTarget() = v
)
}
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(AssignableDefinition def |
definitionAt(def, bb, i, v) and
if def.isCertain() then certain = true else certain = false
)
}
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(AssignableRead read |
read.getAControlFlowNode() = bb.getNode(i) and
read.getTarget() = v and
certain = true
)
}

View File

@@ -1,8 +1,9 @@
/** Provides a module for importing negative models. */
/**
* A module importing all generated negative Models as Data models.
*/
import csharp
private module GeneratedFrameworks {
private import generated.dotnet.NegativeRuntime
}

View File

@@ -3237,6 +3237,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.CodeDom.Compiler;IndentedTextWriter;Close;();generated",
"System.CodeDom.Compiler;IndentedTextWriter;DisposeAsync;();generated",
"System.CodeDom.Compiler;IndentedTextWriter;Flush;();generated",
"System.CodeDom.Compiler;IndentedTextWriter;FlushAsync;();generated",
"System.CodeDom.Compiler;IndentedTextWriter;IndentedTextWriter;(System.IO.TextWriter);generated",
"System.CodeDom.Compiler;IndentedTextWriter;OutputTabs;();generated",
"System.CodeDom.Compiler;IndentedTextWriter;OutputTabsAsync;();generated",
@@ -3280,6 +3281,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.CodeDom.Compiler;IndentedTextWriter;WriteLineAsync;(System.String);generated",
"System.CodeDom.Compiler;IndentedTextWriter;WriteLineAsync;(System.Text.StringBuilder,System.Threading.CancellationToken);generated",
"System.CodeDom.Compiler;IndentedTextWriter;WriteLineNoTabs;(System.String);generated",
"System.CodeDom.Compiler;IndentedTextWriter;WriteLineNoTabsAsync;(System.String);generated",
"System.CodeDom.Compiler;IndentedTextWriter;get_Indent;();generated",
"System.CodeDom.Compiler;IndentedTextWriter;set_Indent;(System.Int32);generated",
"System.CodeDom.Compiler;TempFileCollection;AddFile;(System.String,System.Boolean);generated",
@@ -3457,6 +3459,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.CodeDom;CodeNamespaceImport;set_LinePragma;(System.CodeDom.CodeLinePragma);generated",
"System.CodeDom;CodeNamespaceImportCollection;Clear;();generated",
"System.CodeDom;CodeNamespaceImportCollection;Contains;(System.Object);generated",
"System.CodeDom;CodeNamespaceImportCollection;GetEnumerator;();generated",
"System.CodeDom;CodeNamespaceImportCollection;IndexOf;(System.Object);generated",
"System.CodeDom;CodeNamespaceImportCollection;Remove;(System.Object);generated",
"System.CodeDom;CodeNamespaceImportCollection;RemoveAt;(System.Int32);generated",
@@ -3609,6 +3612,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Collections.Concurrent;ConcurrentDictionary<,>;Contains;(System.Collections.Generic.KeyValuePair<TKey,TValue>);generated",
"System.Collections.Concurrent;ConcurrentDictionary<,>;Contains;(System.Object);generated",
"System.Collections.Concurrent;ConcurrentDictionary<,>;ContainsKey;(TKey);generated",
"System.Collections.Concurrent;ConcurrentDictionary<,>;GetEnumerator;();generated",
"System.Collections.Concurrent;ConcurrentDictionary<,>;Remove;(System.Collections.Generic.KeyValuePair<TKey,TValue>);generated",
"System.Collections.Concurrent;ConcurrentDictionary<,>;Remove;(System.Object);generated",
"System.Collections.Concurrent;ConcurrentDictionary<,>;Remove;(TKey);generated",
@@ -3672,7 +3676,9 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Collections.Generic;ByteEqualityComparer;Equals;(System.Object);generated",
"System.Collections.Generic;ByteEqualityComparer;GetHashCode;();generated",
"System.Collections.Generic;ByteEqualityComparer;GetHashCode;(System.Byte);generated",
"System.Collections.Generic;CollectionExtensions;AsReadOnly<,>;(System.Collections.Generic.IDictionary<TKey,TValue>);generated",
"System.Collections.Generic;CollectionExtensions;GetValueOrDefault<,>;(System.Collections.Generic.IReadOnlyDictionary<TKey,TValue>,TKey);generated",
"System.Collections.Generic;CollectionExtensions;TryAdd<,>;(System.Collections.Generic.IDictionary<TKey,TValue>,TKey,TValue);generated",
"System.Collections.Generic;Comparer<>;Compare;(System.Object,System.Object);generated",
"System.Collections.Generic;Comparer<>;Compare;(T,T);generated",
"System.Collections.Generic;Comparer<>;get_Default;();generated",
@@ -3813,6 +3819,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Collections.Generic;KeyNotFoundException;KeyNotFoundException;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated",
"System.Collections.Generic;KeyNotFoundException;KeyNotFoundException;(System.String);generated",
"System.Collections.Generic;KeyNotFoundException;KeyNotFoundException;(System.String,System.Exception);generated",
"System.Collections.Generic;KeyValuePair;Create<,>;(TKey,TValue);generated",
"System.Collections.Generic;KeyValuePair<,>;ToString;();generated",
"System.Collections.Generic;LinkedList<>+Enumerator;Dispose;();generated",
"System.Collections.Generic;LinkedList<>+Enumerator;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated",
@@ -4165,6 +4172,9 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Collections.Immutable;ImmutableDictionary;CreateBuilder<,>;();generated",
"System.Collections.Immutable;ImmutableDictionary;CreateBuilder<,>;(System.Collections.Generic.IEqualityComparer<TKey>);generated",
"System.Collections.Immutable;ImmutableDictionary;CreateBuilder<,>;(System.Collections.Generic.IEqualityComparer<TKey>,System.Collections.Generic.IEqualityComparer<TValue>);generated",
"System.Collections.Immutable;ImmutableDictionary;CreateRange<,>;(System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>);generated",
"System.Collections.Immutable;ImmutableDictionary;CreateRange<,>;(System.Collections.Generic.IEqualityComparer<TKey>,System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>);generated",
"System.Collections.Immutable;ImmutableDictionary;CreateRange<,>;(System.Collections.Generic.IEqualityComparer<TKey>,System.Collections.Generic.IEqualityComparer<TValue>,System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>);generated",
"System.Collections.Immutable;ImmutableDictionary;GetValueOrDefault<,>;(System.Collections.Immutable.IImmutableDictionary<TKey,TValue>,TKey);generated",
"System.Collections.Immutable;ImmutableDictionary<,>+Builder;Clear;();generated",
"System.Collections.Immutable;ImmutableDictionary<,>+Builder;Contains;(System.Collections.Generic.KeyValuePair<TKey,TValue>);generated",
@@ -4254,8 +4264,10 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Collections.Immutable;ImmutableInterlocked;TryRemove<,>;(System.Collections.Immutable.ImmutableDictionary<TKey,TValue>,TKey,TValue);generated",
"System.Collections.Immutable;ImmutableInterlocked;TryUpdate<,>;(System.Collections.Immutable.ImmutableDictionary<TKey,TValue>,TKey,TValue,TValue);generated",
"System.Collections.Immutable;ImmutableList;Create<>;();generated",
"System.Collections.Immutable;ImmutableList;Create<>;(T);generated",
"System.Collections.Immutable;ImmutableList;Create<>;(T[]);generated",
"System.Collections.Immutable;ImmutableList;CreateBuilder<>;();generated",
"System.Collections.Immutable;ImmutableList;CreateRange<>;(System.Collections.Generic.IEnumerable<T>);generated",
"System.Collections.Immutable;ImmutableList;IndexOf<>;(System.Collections.Immutable.IImmutableList<T>,T);generated",
"System.Collections.Immutable;ImmutableList;IndexOf<>;(System.Collections.Immutable.IImmutableList<T>,T,System.Collections.Generic.IEqualityComparer<T>);generated",
"System.Collections.Immutable;ImmutableList;IndexOf<>;(System.Collections.Immutable.IImmutableList<T>,T,System.Int32);generated",
@@ -4319,6 +4331,9 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Collections.Immutable;ImmutableQueue<>;get_IsEmpty;();generated",
"System.Collections.Immutable;ImmutableSortedDictionary;Create<,>;();generated",
"System.Collections.Immutable;ImmutableSortedDictionary;CreateBuilder<,>;();generated",
"System.Collections.Immutable;ImmutableSortedDictionary;CreateRange<,>;(System.Collections.Generic.IComparer<TKey>,System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>);generated",
"System.Collections.Immutable;ImmutableSortedDictionary;CreateRange<,>;(System.Collections.Generic.IComparer<TKey>,System.Collections.Generic.IEqualityComparer<TValue>,System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>);generated",
"System.Collections.Immutable;ImmutableSortedDictionary;CreateRange<,>;(System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>);generated",
"System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;Clear;();generated",
"System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;Contains;(System.Collections.Generic.KeyValuePair<TKey,TValue>);generated",
"System.Collections.Immutable;ImmutableSortedDictionary<,>+Builder;Contains;(System.Object);generated",
@@ -4338,6 +4353,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;Dispose;();generated",
"System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;MoveNext;();generated",
"System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;Reset;();generated",
"System.Collections.Immutable;ImmutableSortedDictionary<,>+Enumerator;get_Current;();generated",
"System.Collections.Immutable;ImmutableSortedDictionary<,>;Clear;();generated",
"System.Collections.Immutable;ImmutableSortedDictionary<,>;Contains;(System.Collections.Generic.KeyValuePair<TKey,TValue>);generated",
"System.Collections.Immutable;ImmutableSortedDictionary<,>;Contains;(System.Object);generated",
@@ -4354,6 +4370,8 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Collections.Immutable;ImmutableSortedDictionary<,>;get_IsReadOnly;();generated",
"System.Collections.Immutable;ImmutableSortedDictionary<,>;get_IsSynchronized;();generated",
"System.Collections.Immutable;ImmutableSortedSet;Create<>;();generated",
"System.Collections.Immutable;ImmutableSortedSet;Create<>;(System.Collections.Generic.IComparer<T>,T);generated",
"System.Collections.Immutable;ImmutableSortedSet;Create<>;(T);generated",
"System.Collections.Immutable;ImmutableSortedSet;Create<>;(T[]);generated",
"System.Collections.Immutable;ImmutableSortedSet;CreateBuilder<>;();generated",
"System.Collections.Immutable;ImmutableSortedSet<>+Builder;Clear;();generated",
@@ -4367,6 +4385,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Collections.Immutable;ImmutableSortedSet<>+Builder;Overlaps;(System.Collections.Generic.IEnumerable<T>);generated",
"System.Collections.Immutable;ImmutableSortedSet<>+Builder;Remove;(T);generated",
"System.Collections.Immutable;ImmutableSortedSet<>+Builder;SetEquals;(System.Collections.Generic.IEnumerable<T>);generated",
"System.Collections.Immutable;ImmutableSortedSet<>+Builder;SymmetricExceptWith;(System.Collections.Generic.IEnumerable<T>);generated",
"System.Collections.Immutable;ImmutableSortedSet<>+Builder;get_Count;();generated",
"System.Collections.Immutable;ImmutableSortedSet<>+Builder;get_IsReadOnly;();generated",
"System.Collections.Immutable;ImmutableSortedSet<>+Builder;get_IsSynchronized;();generated",
@@ -4380,6 +4399,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Collections.Immutable;ImmutableSortedSet<>;ExceptWith;(System.Collections.Generic.IEnumerable<T>);generated",
"System.Collections.Immutable;ImmutableSortedSet<>;IndexOf;(System.Object);generated",
"System.Collections.Immutable;ImmutableSortedSet<>;IndexOf;(T);generated",
"System.Collections.Immutable;ImmutableSortedSet<>;Intersect;(System.Collections.Generic.IEnumerable<T>);generated",
"System.Collections.Immutable;ImmutableSortedSet<>;IntersectWith;(System.Collections.Generic.IEnumerable<T>);generated",
"System.Collections.Immutable;ImmutableSortedSet<>;IsProperSubsetOf;(System.Collections.Generic.IEnumerable<T>);generated",
"System.Collections.Immutable;ImmutableSortedSet<>;IsProperSupersetOf;(System.Collections.Generic.IEnumerable<T>);generated",
@@ -4391,6 +4411,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Collections.Immutable;ImmutableSortedSet<>;Remove;(T);generated",
"System.Collections.Immutable;ImmutableSortedSet<>;RemoveAt;(System.Int32);generated",
"System.Collections.Immutable;ImmutableSortedSet<>;SetEquals;(System.Collections.Generic.IEnumerable<T>);generated",
"System.Collections.Immutable;ImmutableSortedSet<>;SymmetricExcept;(System.Collections.Generic.IEnumerable<T>);generated",
"System.Collections.Immutable;ImmutableSortedSet<>;SymmetricExceptWith;(System.Collections.Generic.IEnumerable<T>);generated",
"System.Collections.Immutable;ImmutableSortedSet<>;UnionWith;(System.Collections.Generic.IEnumerable<T>);generated",
"System.Collections.Immutable;ImmutableSortedSet<>;get_Count;();generated",
@@ -4798,6 +4819,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.ComponentModel.Composition.Hosting;AggregateCatalog;AggregateCatalog;(System.Collections.Generic.IEnumerable<System.ComponentModel.Composition.Primitives.ComposablePartCatalog>);generated",
"System.ComponentModel.Composition.Hosting;AggregateCatalog;AggregateCatalog;(System.ComponentModel.Composition.Primitives.ComposablePartCatalog[]);generated",
"System.ComponentModel.Composition.Hosting;AggregateCatalog;Dispose;(System.Boolean);generated",
"System.ComponentModel.Composition.Hosting;AggregateCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated",
"System.ComponentModel.Composition.Hosting;AggregateCatalog;OnChanged;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated",
"System.ComponentModel.Composition.Hosting;AggregateCatalog;OnChanging;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated",
"System.ComponentModel.Composition.Hosting;AggregateExportProvider;AggregateExportProvider;(System.Collections.Generic.IEnumerable<System.ComponentModel.Composition.Hosting.ExportProvider>);generated",
@@ -4805,11 +4827,13 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.ComponentModel.Composition.Hosting;AggregateExportProvider;Dispose;(System.Boolean);generated",
"System.ComponentModel.Composition.Hosting;ApplicationCatalog;ApplicationCatalog;();generated",
"System.ComponentModel.Composition.Hosting;ApplicationCatalog;Dispose;(System.Boolean);generated",
"System.ComponentModel.Composition.Hosting;ApplicationCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated",
"System.ComponentModel.Composition.Hosting;ApplicationCatalog;ToString;();generated",
"System.ComponentModel.Composition.Hosting;ApplicationCatalog;get_DisplayName;();generated",
"System.ComponentModel.Composition.Hosting;ApplicationCatalog;get_Origin;();generated",
"System.ComponentModel.Composition.Hosting;AssemblyCatalog;AssemblyCatalog;(System.String);generated",
"System.ComponentModel.Composition.Hosting;AssemblyCatalog;Dispose;(System.Boolean);generated",
"System.ComponentModel.Composition.Hosting;AssemblyCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated",
"System.ComponentModel.Composition.Hosting;AssemblyCatalog;get_Origin;();generated",
"System.ComponentModel.Composition.Hosting;AtomicComposition;AtomicComposition;();generated",
"System.ComponentModel.Composition.Hosting;AtomicComposition;Complete;();generated",
@@ -4845,6 +4869,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.ComponentModel.Composition.Hosting;CompositionContainer;SatisfyImportsOnce;(System.ComponentModel.Composition.Primitives.ComposablePart);generated",
"System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;CompositionScopeDefinition;();generated",
"System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;Dispose;(System.Boolean);generated",
"System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated",
"System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;OnChanged;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated",
"System.ComponentModel.Composition.Hosting;CompositionScopeDefinition;OnChanging;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated",
"System.ComponentModel.Composition.Hosting;CompositionService;Dispose;();generated",
@@ -4854,6 +4879,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.ComponentModel.Composition.Hosting;DirectoryCatalog;DirectoryCatalog;(System.String,System.Reflection.ReflectionContext);generated",
"System.ComponentModel.Composition.Hosting;DirectoryCatalog;DirectoryCatalog;(System.String,System.Reflection.ReflectionContext,System.ComponentModel.Composition.Primitives.ICompositionElement);generated",
"System.ComponentModel.Composition.Hosting;DirectoryCatalog;Dispose;(System.Boolean);generated",
"System.ComponentModel.Composition.Hosting;DirectoryCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated",
"System.ComponentModel.Composition.Hosting;DirectoryCatalog;OnChanged;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated",
"System.ComponentModel.Composition.Hosting;DirectoryCatalog;OnChanging;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated",
"System.ComponentModel.Composition.Hosting;DirectoryCatalog;Refresh;();generated",
@@ -4876,6 +4902,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.ComponentModel.Composition.Hosting;ExportsChangeEventArgs;get_AtomicComposition;();generated",
"System.ComponentModel.Composition.Hosting;ExportsChangeEventArgs;set_AtomicComposition;(System.ComponentModel.Composition.Hosting.AtomicComposition);generated",
"System.ComponentModel.Composition.Hosting;FilteredCatalog;Dispose;(System.Boolean);generated",
"System.ComponentModel.Composition.Hosting;FilteredCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated",
"System.ComponentModel.Composition.Hosting;FilteredCatalog;IncludeDependencies;();generated",
"System.ComponentModel.Composition.Hosting;FilteredCatalog;IncludeDependents;();generated",
"System.ComponentModel.Composition.Hosting;FilteredCatalog;OnChanged;(System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs);generated",
@@ -4909,6 +4936,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.ComponentModel.Composition.Primitives;ComposablePartCatalog;ComposablePartCatalog;();generated",
"System.ComponentModel.Composition.Primitives;ComposablePartCatalog;Dispose;();generated",
"System.ComponentModel.Composition.Primitives;ComposablePartCatalog;Dispose;(System.Boolean);generated",
"System.ComponentModel.Composition.Primitives;ComposablePartCatalog;GetExports;(System.ComponentModel.Composition.Primitives.ImportDefinition);generated",
"System.ComponentModel.Composition.Primitives;ComposablePartDefinition;ComposablePartDefinition;();generated",
"System.ComponentModel.Composition.Primitives;ComposablePartDefinition;CreatePart;();generated",
"System.ComponentModel.Composition.Primitives;ComposablePartDefinition;get_ExportDefinitions;();generated",
@@ -6336,6 +6364,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.ComponentModel;TypeConverter+SimplePropertyDescriptor;get_ComponentType;();generated",
"System.ComponentModel;TypeConverter+SimplePropertyDescriptor;get_IsReadOnly;();generated",
"System.ComponentModel;TypeConverter+SimplePropertyDescriptor;get_PropertyType;();generated",
"System.ComponentModel;TypeConverter+StandardValuesCollection;GetEnumerator;();generated",
"System.ComponentModel;TypeConverter+StandardValuesCollection;get_Count;();generated",
"System.ComponentModel;TypeConverter+StandardValuesCollection;get_IsSynchronized;();generated",
"System.ComponentModel;TypeConverter+StandardValuesCollection;get_SyncRoot;();generated",
@@ -7482,9 +7511,14 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Data.Common;DbCommand;DbCommand;();generated",
"System.Data.Common;DbCommand;DisposeAsync;();generated",
"System.Data.Common;DbCommand;ExecuteDbDataReader;(System.Data.CommandBehavior);generated",
"System.Data.Common;DbCommand;ExecuteDbDataReaderAsync;(System.Data.CommandBehavior,System.Threading.CancellationToken);generated",
"System.Data.Common;DbCommand;ExecuteNonQuery;();generated",
"System.Data.Common;DbCommand;ExecuteNonQueryAsync;();generated",
"System.Data.Common;DbCommand;ExecuteNonQueryAsync;(System.Threading.CancellationToken);generated",
"System.Data.Common;DbCommand;ExecuteReaderAsync;();generated",
"System.Data.Common;DbCommand;ExecuteReaderAsync;(System.Data.CommandBehavior);generated",
"System.Data.Common;DbCommand;ExecuteReaderAsync;(System.Data.CommandBehavior,System.Threading.CancellationToken);generated",
"System.Data.Common;DbCommand;ExecuteReaderAsync;(System.Threading.CancellationToken);generated",
"System.Data.Common;DbCommand;ExecuteScalar;();generated",
"System.Data.Common;DbCommand;ExecuteScalarAsync;();generated",
"System.Data.Common;DbCommand;ExecuteScalarAsync;(System.Threading.CancellationToken);generated",
@@ -7568,6 +7602,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Data.Common;DbConnectionStringBuilder;GetDefaultEvent;();generated",
"System.Data.Common;DbConnectionStringBuilder;GetDefaultProperty;();generated",
"System.Data.Common;DbConnectionStringBuilder;GetEditor;(System.Type);generated",
"System.Data.Common;DbConnectionStringBuilder;GetEnumerator;();generated",
"System.Data.Common;DbConnectionStringBuilder;GetEvents;();generated",
"System.Data.Common;DbConnectionStringBuilder;GetEvents;(System.Attribute[]);generated",
"System.Data.Common;DbConnectionStringBuilder;GetProperties;(System.Collections.Hashtable);generated",
@@ -7635,6 +7670,8 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Data.Common;DbDataReader;GetDecimal;(System.Int32);generated",
"System.Data.Common;DbDataReader;GetDouble;(System.Int32);generated",
"System.Data.Common;DbDataReader;GetFieldType;(System.Int32);generated",
"System.Data.Common;DbDataReader;GetFieldValueAsync<>;(System.Int32);generated",
"System.Data.Common;DbDataReader;GetFieldValueAsync<>;(System.Int32,System.Threading.CancellationToken);generated",
"System.Data.Common;DbDataReader;GetFloat;(System.Int32);generated",
"System.Data.Common;DbDataReader;GetGuid;(System.Int32);generated",
"System.Data.Common;DbDataReader;GetInt16;(System.Int32);generated",
@@ -7644,6 +7681,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Data.Common;DbDataReader;GetOrdinal;(System.String);generated",
"System.Data.Common;DbDataReader;GetProviderSpecificFieldType;(System.Int32);generated",
"System.Data.Common;DbDataReader;GetSchemaTable;();generated",
"System.Data.Common;DbDataReader;GetSchemaTableAsync;(System.Threading.CancellationToken);generated",
"System.Data.Common;DbDataReader;GetStream;(System.Int32);generated",
"System.Data.Common;DbDataReader;GetString;(System.Int32);generated",
"System.Data.Common;DbDataReader;GetValue;(System.Int32);generated",
@@ -8955,6 +8993,9 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Data;DataColumnChangeEventArgs;get_ProposedValue;();generated",
"System.Data;DataColumnChangeEventArgs;get_Row;();generated",
"System.Data;DataColumnChangeEventArgs;set_ProposedValue;(System.Object);generated",
"System.Data;DataColumnCollection;Add;();generated",
"System.Data;DataColumnCollection;Add;(System.String,System.Type);generated",
"System.Data;DataColumnCollection;Add;(System.String,System.Type,System.String);generated",
"System.Data;DataColumnCollection;CanRemove;(System.Data.DataColumn);generated",
"System.Data;DataColumnCollection;Clear;();generated",
"System.Data;DataColumnCollection;Contains;(System.String);generated",
@@ -8977,6 +9018,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Data;DataReaderExtensions;GetDecimal;(System.Data.Common.DbDataReader,System.String);generated",
"System.Data;DataReaderExtensions;GetDouble;(System.Data.Common.DbDataReader,System.String);generated",
"System.Data;DataReaderExtensions;GetFieldType;(System.Data.Common.DbDataReader,System.String);generated",
"System.Data;DataReaderExtensions;GetFieldValueAsync<>;(System.Data.Common.DbDataReader,System.String,System.Threading.CancellationToken);generated",
"System.Data;DataReaderExtensions;GetFloat;(System.Data.Common.DbDataReader,System.String);generated",
"System.Data;DataReaderExtensions;GetInt16;(System.Data.Common.DbDataReader,System.String);generated",
"System.Data;DataReaderExtensions;GetInt32;(System.Data.Common.DbDataReader,System.String);generated",
@@ -8994,6 +9036,10 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Data;DataRelation;get_Nested;();generated",
"System.Data;DataRelation;get_ParentTable;();generated",
"System.Data;DataRelation;set_Nested;(System.Boolean);generated",
"System.Data;DataRelationCollection;Add;(System.Data.DataColumn,System.Data.DataColumn);generated",
"System.Data;DataRelationCollection;Add;(System.Data.DataColumn[],System.Data.DataColumn[]);generated",
"System.Data;DataRelationCollection;Add;(System.String,System.Data.DataColumn,System.Data.DataColumn);generated",
"System.Data;DataRelationCollection;Add;(System.String,System.Data.DataColumn[],System.Data.DataColumn[]);generated",
"System.Data;DataRelationCollection;AddCore;(System.Data.DataRelation);generated",
"System.Data;DataRelationCollection;CanRemove;(System.Data.DataRelation);generated",
"System.Data;DataRelationCollection;Clear;();generated",
@@ -9240,6 +9286,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Data;DataTableClearEventArgs;get_Table;();generated",
"System.Data;DataTableClearEventArgs;get_TableName;();generated",
"System.Data;DataTableClearEventArgs;get_TableNamespace;();generated",
"System.Data;DataTableCollection;Add;();generated",
"System.Data;DataTableCollection;CanRemove;(System.Data.DataTable);generated",
"System.Data;DataTableCollection;Clear;();generated",
"System.Data;DataTableCollection;Contains;(System.String);generated",
@@ -13395,15 +13442,19 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Drawing.Printing;PrinterResolution;set_X;(System.Int32);generated",
"System.Drawing.Printing;PrinterResolution;set_Y;(System.Int32);generated",
"System.Drawing.Printing;PrinterSettings+PaperSizeCollection;CopyTo;(System.Drawing.Printing.PaperSize[],System.Int32);generated",
"System.Drawing.Printing;PrinterSettings+PaperSizeCollection;GetEnumerator;();generated",
"System.Drawing.Printing;PrinterSettings+PaperSizeCollection;get_Count;();generated",
"System.Drawing.Printing;PrinterSettings+PaperSizeCollection;get_IsSynchronized;();generated",
"System.Drawing.Printing;PrinterSettings+PaperSourceCollection;CopyTo;(System.Drawing.Printing.PaperSource[],System.Int32);generated",
"System.Drawing.Printing;PrinterSettings+PaperSourceCollection;GetEnumerator;();generated",
"System.Drawing.Printing;PrinterSettings+PaperSourceCollection;get_Count;();generated",
"System.Drawing.Printing;PrinterSettings+PaperSourceCollection;get_IsSynchronized;();generated",
"System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;CopyTo;(System.Drawing.Printing.PrinterResolution[],System.Int32);generated",
"System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;GetEnumerator;();generated",
"System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;get_Count;();generated",
"System.Drawing.Printing;PrinterSettings+PrinterResolutionCollection;get_IsSynchronized;();generated",
"System.Drawing.Printing;PrinterSettings+StringCollection;CopyTo;(System.String[],System.Int32);generated",
"System.Drawing.Printing;PrinterSettings+StringCollection;GetEnumerator;();generated",
"System.Drawing.Printing;PrinterSettings+StringCollection;get_Count;();generated",
"System.Drawing.Printing;PrinterSettings+StringCollection;get_IsSynchronized;();generated",
"System.Drawing.Printing;PrinterSettings;Clone;();generated",
@@ -15734,10 +15785,12 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.IO.Compression;DeflateStream;EndWrite;(System.IAsyncResult);generated",
"System.IO.Compression;DeflateStream;Flush;();generated",
"System.IO.Compression;DeflateStream;Read;(System.Span<System.Byte>);generated",
"System.IO.Compression;DeflateStream;ReadAsync;(System.Memory<System.Byte>,System.Threading.CancellationToken);generated",
"System.IO.Compression;DeflateStream;ReadByte;();generated",
"System.IO.Compression;DeflateStream;Seek;(System.Int64,System.IO.SeekOrigin);generated",
"System.IO.Compression;DeflateStream;SetLength;(System.Int64);generated",
"System.IO.Compression;DeflateStream;Write;(System.ReadOnlySpan<System.Byte>);generated",
"System.IO.Compression;DeflateStream;WriteAsync;(System.ReadOnlyMemory<System.Byte>,System.Threading.CancellationToken);generated",
"System.IO.Compression;DeflateStream;WriteByte;(System.Byte);generated",
"System.IO.Compression;DeflateStream;get_CanRead;();generated",
"System.IO.Compression;DeflateStream;get_CanSeek;();generated",
@@ -15753,10 +15806,12 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.IO.Compression;GZipStream;GZipStream;(System.IO.Stream,System.IO.Compression.CompressionLevel);generated",
"System.IO.Compression;GZipStream;GZipStream;(System.IO.Stream,System.IO.Compression.CompressionMode);generated",
"System.IO.Compression;GZipStream;Read;(System.Span<System.Byte>);generated",
"System.IO.Compression;GZipStream;ReadAsync;(System.Memory<System.Byte>,System.Threading.CancellationToken);generated",
"System.IO.Compression;GZipStream;ReadByte;();generated",
"System.IO.Compression;GZipStream;Seek;(System.Int64,System.IO.SeekOrigin);generated",
"System.IO.Compression;GZipStream;SetLength;(System.Int64);generated",
"System.IO.Compression;GZipStream;Write;(System.ReadOnlySpan<System.Byte>);generated",
"System.IO.Compression;GZipStream;WriteAsync;(System.ReadOnlyMemory<System.Byte>,System.Threading.CancellationToken);generated",
"System.IO.Compression;GZipStream;WriteByte;(System.Byte);generated",
"System.IO.Compression;GZipStream;get_CanRead;();generated",
"System.IO.Compression;GZipStream;get_CanSeek;();generated",
@@ -16328,6 +16383,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.IO;BinaryWriter;BinaryWriter;(System.IO.Stream,System.Text.Encoding);generated",
"System.IO;BinaryWriter;Close;();generated", "System.IO;BinaryWriter;Dispose;();generated",
"System.IO;BinaryWriter;Dispose;(System.Boolean);generated",
"System.IO;BinaryWriter;DisposeAsync;();generated",
"System.IO;BinaryWriter;Flush;();generated",
"System.IO;BinaryWriter;Seek;(System.Int32,System.IO.SeekOrigin);generated",
"System.IO;BinaryWriter;Write7BitEncodedInt64;(System.Int64);generated",
@@ -16718,14 +16774,18 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.IO;Stream;DisposeAsync;();generated",
"System.IO;Stream;EndRead;(System.IAsyncResult);generated",
"System.IO;Stream;EndWrite;(System.IAsyncResult);generated",
"System.IO;Stream;Flush;();generated", "System.IO;Stream;ObjectInvariant;();generated",
"System.IO;Stream;Flush;();generated", "System.IO;Stream;FlushAsync;();generated",
"System.IO;Stream;FlushAsync;(System.Threading.CancellationToken);generated",
"System.IO;Stream;ObjectInvariant;();generated",
"System.IO;Stream;Read;(System.Span<System.Byte>);generated",
"System.IO;Stream;ReadAsync;(System.Memory<System.Byte>,System.Threading.CancellationToken);generated",
"System.IO;Stream;ReadByte;();generated",
"System.IO;Stream;Seek;(System.Int64,System.IO.SeekOrigin);generated",
"System.IO;Stream;SetLength;(System.Int64);generated",
"System.IO;Stream;ValidateBufferArguments;(System.Byte[],System.Int32,System.Int32);generated",
"System.IO;Stream;ValidateCopyToArguments;(System.IO.Stream,System.Int32);generated",
"System.IO;Stream;Write;(System.ReadOnlySpan<System.Byte>);generated",
"System.IO;Stream;WriteAsync;(System.ReadOnlyMemory<System.Byte>,System.Threading.CancellationToken);generated",
"System.IO;Stream;WriteByte;(System.Byte);generated",
"System.IO;Stream;get_CanRead;();generated", "System.IO;Stream;get_CanSeek;();generated",
"System.IO;Stream;get_CanTimeout;();generated",
@@ -16745,6 +16805,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.IO;StreamWriter;Dispose;(System.Boolean);generated",
"System.IO;StreamWriter;DisposeAsync;();generated",
"System.IO;StreamWriter;Flush;();generated",
"System.IO;StreamWriter;FlushAsync;();generated",
"System.IO;StreamWriter;StreamWriter;(System.IO.Stream);generated",
"System.IO;StreamWriter;StreamWriter;(System.IO.Stream,System.Text.Encoding);generated",
"System.IO;StreamWriter;StreamWriter;(System.IO.Stream,System.Text.Encoding,System.Int32);generated",
@@ -16763,8 +16824,15 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.IO;StreamWriter;Write;(System.String,System.Object,System.Object);generated",
"System.IO;StreamWriter;Write;(System.String,System.Object,System.Object,System.Object);generated",
"System.IO;StreamWriter;Write;(System.String,System.Object[]);generated",
"System.IO;StreamWriter;WriteAsync;(System.Char);generated",
"System.IO;StreamWriter;WriteAsync;(System.Char[],System.Int32,System.Int32);generated",
"System.IO;StreamWriter;WriteAsync;(System.String);generated",
"System.IO;StreamWriter;WriteLine;(System.ReadOnlySpan<System.Char>);generated",
"System.IO;StreamWriter;WriteLine;(System.String);generated",
"System.IO;StreamWriter;WriteLineAsync;();generated",
"System.IO;StreamWriter;WriteLineAsync;(System.Char);generated",
"System.IO;StreamWriter;WriteLineAsync;(System.Char[],System.Int32,System.Int32);generated",
"System.IO;StreamWriter;WriteLineAsync;(System.String);generated",
"System.IO;StreamWriter;get_AutoFlush;();generated",
"System.IO;StreamWriter;set_AutoFlush;(System.Boolean);generated",
"System.IO;StringReader;Close;();generated",
@@ -16777,8 +16845,10 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.IO;StringWriter;StringWriter;(System.Text.StringBuilder);generated",
"System.IO;StringWriter;Write;(System.Char);generated",
"System.IO;StringWriter;Write;(System.ReadOnlySpan<System.Char>);generated",
"System.IO;StringWriter;Write;(System.Text.StringBuilder);generated",
"System.IO;StringWriter;WriteAsync;(System.Char);generated",
"System.IO;StringWriter;WriteLine;(System.ReadOnlySpan<System.Char>);generated",
"System.IO;StringWriter;WriteLine;(System.Text.StringBuilder);generated",
"System.IO;StringWriter;WriteLineAsync;(System.Char);generated",
"System.IO;StringWriter;get_Encoding;();generated",
"System.IO;TextReader;Close;();generated", "System.IO;TextReader;Dispose;();generated",
@@ -16787,6 +16857,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.IO;TextWriter;Close;();generated", "System.IO;TextWriter;Dispose;();generated",
"System.IO;TextWriter;Dispose;(System.Boolean);generated",
"System.IO;TextWriter;DisposeAsync;();generated", "System.IO;TextWriter;Flush;();generated",
"System.IO;TextWriter;FlushAsync;();generated",
"System.IO;TextWriter;TextWriter;();generated",
"System.IO;TextWriter;Write;(System.Boolean);generated",
"System.IO;TextWriter;Write;(System.Char);generated",
@@ -16801,6 +16872,9 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.IO;TextWriter;Write;(System.Text.StringBuilder);generated",
"System.IO;TextWriter;Write;(System.UInt32);generated",
"System.IO;TextWriter;Write;(System.UInt64);generated",
"System.IO;TextWriter;WriteAsync;(System.Char);generated",
"System.IO;TextWriter;WriteAsync;(System.Char[],System.Int32,System.Int32);generated",
"System.IO;TextWriter;WriteAsync;(System.String);generated",
"System.IO;TextWriter;WriteLine;();generated",
"System.IO;TextWriter;WriteLine;(System.Boolean);generated",
"System.IO;TextWriter;WriteLine;(System.Char);generated",
@@ -16810,8 +16884,13 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.IO;TextWriter;WriteLine;(System.Int64);generated",
"System.IO;TextWriter;WriteLine;(System.ReadOnlySpan<System.Char>);generated",
"System.IO;TextWriter;WriteLine;(System.Single);generated",
"System.IO;TextWriter;WriteLine;(System.Text.StringBuilder);generated",
"System.IO;TextWriter;WriteLine;(System.UInt32);generated",
"System.IO;TextWriter;WriteLine;(System.UInt64);generated",
"System.IO;TextWriter;WriteLineAsync;();generated",
"System.IO;TextWriter;WriteLineAsync;(System.Char);generated",
"System.IO;TextWriter;WriteLineAsync;(System.Char[],System.Int32,System.Int32);generated",
"System.IO;TextWriter;WriteLineAsync;(System.String);generated",
"System.IO;TextWriter;get_Encoding;();generated",
"System.IO;UnmanagedMemoryAccessor;Dispose;();generated",
"System.IO;UnmanagedMemoryAccessor;Dispose;(System.Boolean);generated",
@@ -18015,6 +18094,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Net.Http.Headers;HttpHeadersNonValidated+Enumerator;Reset;();generated",
"System.Net.Http.Headers;HttpHeadersNonValidated;Contains;(System.String);generated",
"System.Net.Http.Headers;HttpHeadersNonValidated;ContainsKey;(System.String);generated",
"System.Net.Http.Headers;HttpHeadersNonValidated;GetEnumerator;();generated",
"System.Net.Http.Headers;HttpHeadersNonValidated;get_Count;();generated",
"System.Net.Http.Headers;HttpRequestHeaders;get_Accept;();generated",
"System.Net.Http.Headers;HttpRequestHeaders;get_AcceptCharset;();generated",
@@ -18203,6 +18283,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Net.Http.Json;JsonContent;TryComputeLength;(System.Int64);generated",
"System.Net.Http.Json;JsonContent;get_ObjectType;();generated",
"System.Net.Http.Json;JsonContent;get_Value;();generated",
"System.Net.Http;ByteArrayContent;CreateContentReadStreamAsync;();generated",
"System.Net.Http;ByteArrayContent;TryComputeLength;(System.Int64);generated",
"System.Net.Http;DelegatingHandler;DelegatingHandler;();generated",
"System.Net.Http;DelegatingHandler;Dispose;(System.Boolean);generated",
@@ -18302,6 +18383,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Net.Http;HttpClientHandler;set_UseDefaultCredentials;(System.Boolean);generated",
"System.Net.Http;HttpClientHandler;set_UseProxy;(System.Boolean);generated",
"System.Net.Http;HttpContent;CreateContentReadStreamAsync;();generated",
"System.Net.Http;HttpContent;CreateContentReadStreamAsync;(System.Threading.CancellationToken);generated",
"System.Net.Http;HttpContent;Dispose;();generated",
"System.Net.Http;HttpContent;Dispose;(System.Boolean);generated",
"System.Net.Http;HttpContent;HttpContent;();generated",
@@ -18390,6 +18472,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Net.Http;MultipartContent;get_HeaderEncodingSelector;();generated",
"System.Net.Http;MultipartFormDataContent;MultipartFormDataContent;();generated",
"System.Net.Http;MultipartFormDataContent;MultipartFormDataContent;(System.String);generated",
"System.Net.Http;ReadOnlyMemoryContent;CreateContentReadStreamAsync;();generated",
"System.Net.Http;ReadOnlyMemoryContent;SerializeToStream;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);generated",
"System.Net.Http;ReadOnlyMemoryContent;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext);generated",
"System.Net.Http;ReadOnlyMemoryContent;SerializeToStreamAsync;(System.IO.Stream,System.Net.TransportContext,System.Threading.CancellationToken);generated",
@@ -19020,6 +19103,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Net.Quic;QuicStreamAbortedException;QuicStreamAbortedException;(System.String,System.Int64);generated",
"System.Net.Quic;QuicStreamAbortedException;get_ErrorCode;();generated",
"System.Net.Security;AuthenticatedStream;Dispose;(System.Boolean);generated",
"System.Net.Security;AuthenticatedStream;DisposeAsync;();generated",
"System.Net.Security;AuthenticatedStream;get_IsAuthenticated;();generated",
"System.Net.Security;AuthenticatedStream;get_IsEncrypted;();generated",
"System.Net.Security;AuthenticatedStream;get_IsMutuallyAuthenticated;();generated",
@@ -19244,6 +19328,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Net.Sockets;SendPacketsElement;set_MemoryBuffer;(System.Nullable<System.ReadOnlyMemory<System.Byte>>);generated",
"System.Net.Sockets;SendPacketsElement;set_OffsetLong;(System.Int64);generated",
"System.Net.Sockets;Socket;AcceptAsync;();generated",
"System.Net.Sockets;Socket;AcceptAsync;(System.Net.Sockets.Socket);generated",
"System.Net.Sockets;Socket;CancelConnectAsync;(System.Net.Sockets.SocketAsyncEventArgs);generated",
"System.Net.Sockets;Socket;Close;();generated",
"System.Net.Sockets;Socket;Close;(System.Int32);generated",
@@ -19258,6 +19343,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Net.Sockets;Socket;DuplicateAndClose;(System.Int32);generated",
"System.Net.Sockets;Socket;EndAccept;(System.Byte[],System.IAsyncResult);generated",
"System.Net.Sockets;Socket;EndAccept;(System.Byte[],System.Int32,System.IAsyncResult);generated",
"System.Net.Sockets;Socket;EndAccept;(System.IAsyncResult);generated",
"System.Net.Sockets;Socket;EndConnect;(System.IAsyncResult);generated",
"System.Net.Sockets;Socket;EndDisconnect;(System.IAsyncResult);generated",
"System.Net.Sockets;Socket;EndReceive;(System.IAsyncResult);generated",
@@ -19292,6 +19378,10 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Net.Sockets;Socket;ReceiveAsync;(System.ArraySegment<System.Byte>,System.Net.Sockets.SocketFlags);generated",
"System.Net.Sockets;Socket;ReceiveAsync;(System.Collections.Generic.IList<System.ArraySegment<System.Byte>>);generated",
"System.Net.Sockets;Socket;ReceiveAsync;(System.Collections.Generic.IList<System.ArraySegment<System.Byte>>,System.Net.Sockets.SocketFlags);generated",
"System.Net.Sockets;Socket;ReceiveFromAsync;(System.ArraySegment<System.Byte>,System.Net.EndPoint);generated",
"System.Net.Sockets;Socket;ReceiveFromAsync;(System.ArraySegment<System.Byte>,System.Net.Sockets.SocketFlags,System.Net.EndPoint);generated",
"System.Net.Sockets;Socket;ReceiveMessageFromAsync;(System.ArraySegment<System.Byte>,System.Net.EndPoint);generated",
"System.Net.Sockets;Socket;ReceiveMessageFromAsync;(System.ArraySegment<System.Byte>,System.Net.Sockets.SocketFlags,System.Net.EndPoint);generated",
"System.Net.Sockets;Socket;Select;(System.Collections.IList,System.Collections.IList,System.Collections.IList,System.Int32);generated",
"System.Net.Sockets;Socket;Send;(System.Byte[]);generated",
"System.Net.Sockets;Socket;Send;(System.Byte[],System.Int32,System.Int32,System.Net.Sockets.SocketFlags);generated",
@@ -19391,11 +19481,14 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Net.Sockets;SocketInformation;set_Options;(System.Net.Sockets.SocketInformationOptions);generated",
"System.Net.Sockets;SocketInformation;set_ProtocolInformation;(System.Byte[]);generated",
"System.Net.Sockets;SocketTaskExtensions;AcceptAsync;(System.Net.Sockets.Socket);generated",
"System.Net.Sockets;SocketTaskExtensions;AcceptAsync;(System.Net.Sockets.Socket,System.Net.Sockets.Socket);generated",
"System.Net.Sockets;SocketTaskExtensions;ConnectAsync;(System.Net.Sockets.Socket,System.Net.IPAddress[],System.Int32);generated",
"System.Net.Sockets;SocketTaskExtensions;ConnectAsync;(System.Net.Sockets.Socket,System.Net.IPAddress[],System.Int32,System.Threading.CancellationToken);generated",
"System.Net.Sockets;SocketTaskExtensions;ConnectAsync;(System.Net.Sockets.Socket,System.String,System.Int32);generated",
"System.Net.Sockets;SocketTaskExtensions;ReceiveAsync;(System.Net.Sockets.Socket,System.ArraySegment<System.Byte>,System.Net.Sockets.SocketFlags);generated",
"System.Net.Sockets;SocketTaskExtensions;ReceiveAsync;(System.Net.Sockets.Socket,System.Collections.Generic.IList<System.ArraySegment<System.Byte>>,System.Net.Sockets.SocketFlags);generated",
"System.Net.Sockets;SocketTaskExtensions;ReceiveFromAsync;(System.Net.Sockets.Socket,System.ArraySegment<System.Byte>,System.Net.Sockets.SocketFlags,System.Net.EndPoint);generated",
"System.Net.Sockets;SocketTaskExtensions;ReceiveMessageFromAsync;(System.Net.Sockets.Socket,System.ArraySegment<System.Byte>,System.Net.Sockets.SocketFlags,System.Net.EndPoint);generated",
"System.Net.Sockets;SocketTaskExtensions;SendAsync;(System.Net.Sockets.Socket,System.ArraySegment<System.Byte>,System.Net.Sockets.SocketFlags);generated",
"System.Net.Sockets;SocketTaskExtensions;SendAsync;(System.Net.Sockets.Socket,System.Collections.Generic.IList<System.ArraySegment<System.Byte>>,System.Net.Sockets.SocketFlags);generated",
"System.Net.Sockets;TcpClient;Close;();generated",
@@ -19437,6 +19530,8 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Net.Sockets;TcpListener;AcceptTcpClientAsync;(System.Threading.CancellationToken);generated",
"System.Net.Sockets;TcpListener;AllowNatTraversal;(System.Boolean);generated",
"System.Net.Sockets;TcpListener;Create;(System.Int32);generated",
"System.Net.Sockets;TcpListener;EndAcceptSocket;(System.IAsyncResult);generated",
"System.Net.Sockets;TcpListener;EndAcceptTcpClient;(System.IAsyncResult);generated",
"System.Net.Sockets;TcpListener;Pending;();generated",
"System.Net.Sockets;TcpListener;Start;();generated",
"System.Net.Sockets;TcpListener;Start;(System.Int32);generated",
@@ -19653,6 +19748,10 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Net;CredentialCache;Remove;(System.Uri,System.String);generated",
"System.Net;CredentialCache;get_DefaultCredentials;();generated",
"System.Net;CredentialCache;get_DefaultNetworkCredentials;();generated",
"System.Net;Dns;EndGetHostAddresses;(System.IAsyncResult);generated",
"System.Net;Dns;EndGetHostByName;(System.IAsyncResult);generated",
"System.Net;Dns;EndGetHostEntry;(System.IAsyncResult);generated",
"System.Net;Dns;EndResolve;(System.IAsyncResult);generated",
"System.Net;Dns;GetHostAddresses;(System.String);generated",
"System.Net;Dns;GetHostAddresses;(System.String,System.Net.Sockets.AddressFamily);generated",
"System.Net;Dns;GetHostAddressesAsync;(System.String);generated",
@@ -19696,6 +19795,8 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Net;EndpointPermission;get_Port;();generated",
"System.Net;EndpointPermission;get_Transport;();generated",
"System.Net;FileWebRequest;Abort;();generated",
"System.Net;FileWebRequest;EndGetRequestStream;(System.IAsyncResult);generated",
"System.Net;FileWebRequest;EndGetResponse;(System.IAsyncResult);generated",
"System.Net;FileWebRequest;FileWebRequest;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated",
"System.Net;FileWebRequest;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated",
"System.Net;FileWebRequest;GetRequestStreamAsync;();generated",
@@ -19850,6 +19951,9 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Net;HttpWebRequest;AddRange;(System.String,System.Int32,System.Int32);generated",
"System.Net;HttpWebRequest;AddRange;(System.String,System.Int64);generated",
"System.Net;HttpWebRequest;AddRange;(System.String,System.Int64,System.Int64);generated",
"System.Net;HttpWebRequest;EndGetRequestStream;(System.IAsyncResult);generated",
"System.Net;HttpWebRequest;EndGetRequestStream;(System.IAsyncResult,System.Net.TransportContext);generated",
"System.Net;HttpWebRequest;EndGetResponse;(System.IAsyncResult);generated",
"System.Net;HttpWebRequest;GetObjectData;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated",
"System.Net;HttpWebRequest;HttpWebRequest;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated",
"System.Net;HttpWebRequest;get_AllowAutoRedirect;();generated",
@@ -19998,7 +20102,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Net;NetworkCredential;get_SecurePassword;();generated",
"System.Net;NetworkCredential;set_SecurePassword;(System.Security.SecureString);generated",
"System.Net;PathList;GetCookiesCount;();generated",
"System.Net;PathList;get_Count;();generated",
"System.Net;PathList;get_Count;();generated", "System.Net;PathList;get_Values;();generated",
"System.Net;PathList;set_Item;(System.String,System.Object);generated",
"System.Net;ProtocolViolationException;ProtocolViolationException;();generated",
"System.Net;ProtocolViolationException;ProtocolViolationException;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated",
@@ -20384,7 +20488,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Numerics;BigInteger;Log;(System.Numerics.BigInteger,System.Double);generated",
"System.Numerics;BigInteger;ModPow;(System.Numerics.BigInteger,System.Numerics.BigInteger,System.Numerics.BigInteger);generated",
"System.Numerics;BigInteger;Multiply;(System.Numerics.BigInteger,System.Numerics.BigInteger);generated",
"System.Numerics;BigInteger;Negate;(System.Numerics.BigInteger);generated",
"System.Numerics;BigInteger;Parse;(System.ReadOnlySpan<System.Char>,System.Globalization.NumberStyles,System.IFormatProvider);generated",
"System.Numerics;BigInteger;Parse;(System.String);generated",
"System.Numerics;BigInteger;Parse;(System.String,System.Globalization.NumberStyles);generated",
@@ -20450,7 +20553,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Numerics;BigInteger;op_Multiply;(System.Numerics.BigInteger,System.Numerics.BigInteger);generated",
"System.Numerics;BigInteger;op_OnesComplement;(System.Numerics.BigInteger);generated",
"System.Numerics;BigInteger;op_Subtraction;(System.Numerics.BigInteger,System.Numerics.BigInteger);generated",
"System.Numerics;BigInteger;op_UnaryNegation;(System.Numerics.BigInteger);generated",
"System.Numerics;BitOperations;IsPow2;(System.Int32);generated",
"System.Numerics;BitOperations;IsPow2;(System.Int64);generated",
"System.Numerics;BitOperations;IsPow2;(System.IntPtr);generated",
@@ -23374,6 +23476,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Resources;ResourceSet;Dispose;(System.Boolean);generated",
"System.Resources;ResourceSet;GetDefaultReader;();generated",
"System.Resources;ResourceSet;GetDefaultWriter;();generated",
"System.Resources;ResourceSet;GetEnumerator;();generated",
"System.Resources;ResourceSet;GetObject;(System.String);generated",
"System.Resources;ResourceSet;GetObject;(System.String,System.Boolean);generated",
"System.Resources;ResourceSet;GetString;(System.String);generated",
@@ -23588,8 +23691,6 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Runtime.CompilerServices;DisablePrivateReflectionAttribute;DisablePrivateReflectionAttribute;();generated",
"System.Runtime.CompilerServices;DiscardableAttribute;DiscardableAttribute;();generated",
"System.Runtime.CompilerServices;DynamicAttribute;DynamicAttribute;();generated",
"System.Runtime.CompilerServices;DynamicAttribute;DynamicAttribute;(System.Boolean[]);generated",
"System.Runtime.CompilerServices;DynamicAttribute;get_TransformFlags;();generated",
"System.Runtime.CompilerServices;EnumeratorCancellationAttribute;EnumeratorCancellationAttribute;();generated",
"System.Runtime.CompilerServices;FixedAddressValueTypeAttribute;FixedAddressValueTypeAttribute;();generated",
"System.Runtime.CompilerServices;FixedBufferAttribute;FixedBufferAttribute;(System.Type,System.Int32);generated",
@@ -29575,6 +29676,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Security.Cryptography.Pkcs;Pkcs12SafeContents;Decrypt;(System.ReadOnlySpan<System.Byte>);generated",
"System.Security.Cryptography.Pkcs;Pkcs12SafeContents;Decrypt;(System.ReadOnlySpan<System.Char>);generated",
"System.Security.Cryptography.Pkcs;Pkcs12SafeContents;Decrypt;(System.String);generated",
"System.Security.Cryptography.Pkcs;Pkcs12SafeContents;GetBags;();generated",
"System.Security.Cryptography.Pkcs;Pkcs12SafeContents;Pkcs12SafeContents;();generated",
"System.Security.Cryptography.Pkcs;Pkcs12SafeContents;get_ConfidentialityMode;();generated",
"System.Security.Cryptography.Pkcs;Pkcs12SafeContents;get_IsReadOnly;();generated",
@@ -29882,6 +29984,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Security.Cryptography.X509Certificates;X509Certificate;get_Handle;();generated",
"System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;MoveNext;();generated",
"System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;Reset;();generated",
"System.Security.Cryptography.X509Certificates;X509CertificateCollection+X509CertificateEnumerator;X509CertificateEnumerator;(System.Security.Cryptography.X509Certificates.X509CertificateCollection);generated",
"System.Security.Cryptography.X509Certificates;X509CertificateCollection;Contains;(System.Security.Cryptography.X509Certificates.X509Certificate);generated",
"System.Security.Cryptography.X509Certificates;X509CertificateCollection;GetHashCode;();generated",
"System.Security.Cryptography.X509Certificates;X509CertificateCollection;IndexOf;(System.Security.Cryptography.X509Certificates.X509Certificate);generated",
@@ -30051,6 +30154,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Security.Cryptography.Xml;EncryptionPropertyCollection;get_IsReadOnly;();generated",
"System.Security.Cryptography.Xml;EncryptionPropertyCollection;get_IsSynchronized;();generated",
"System.Security.Cryptography.Xml;IRelDecryptor;Decrypt;(System.Security.Cryptography.Xml.EncryptionMethod,System.Security.Cryptography.Xml.KeyInfo,System.IO.Stream);generated",
"System.Security.Cryptography.Xml;KeyInfo;GetEnumerator;(System.Type);generated",
"System.Security.Cryptography.Xml;KeyInfo;GetXml;();generated",
"System.Security.Cryptography.Xml;KeyInfo;KeyInfo;();generated",
"System.Security.Cryptography.Xml;KeyInfo;get_Count;();generated",
@@ -30117,6 +30221,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Security.Cryptography.Xml;Transform;Transform;();generated",
"System.Security.Cryptography.Xml;Transform;get_InputTypes;();generated",
"System.Security.Cryptography.Xml;Transform;get_OutputTypes;();generated",
"System.Security.Cryptography.Xml;TransformChain;GetEnumerator;();generated",
"System.Security.Cryptography.Xml;TransformChain;TransformChain;();generated",
"System.Security.Cryptography.Xml;TransformChain;get_Count;();generated",
"System.Security.Cryptography.Xml;X509IssuerSerial;get_IssuerName;();generated",
@@ -34289,6 +34394,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Text.Json.Serialization;ReferenceResolver;GetReference;(System.Object,System.Boolean);generated",
"System.Text.Json.Serialization;ReferenceResolver;ResolveReference;(System.String);generated",
"System.Text.Json.SourceGeneration;JsonSourceGenerator;Execute;(Microsoft.CodeAnalysis.GeneratorExecutionContext);generated",
"System.Text.Json.SourceGeneration;JsonSourceGenerator;GetSerializableTypes;();generated",
"System.Text.Json.SourceGeneration;JsonSourceGenerator;Initialize;(Microsoft.CodeAnalysis.GeneratorInitializationContext);generated",
"System.Text.Json.SourceGeneration;JsonSourceGenerator;Initialize;(Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext);generated",
"System.Text.Json;JsonDocument;Dispose;();generated",
@@ -35318,6 +35424,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Threading.RateLimiting;MetadataName<>;op_Inequality;(System.Threading.RateLimiting.MetadataName<>,System.Threading.RateLimiting.MetadataName<>);generated",
"System.Threading.RateLimiting;RateLimitLease;Dispose;();generated",
"System.Threading.RateLimiting;RateLimitLease;Dispose;(System.Boolean);generated",
"System.Threading.RateLimiting;RateLimitLease;GetAllMetadata;();generated",
"System.Threading.RateLimiting;RateLimitLease;TryGetMetadata;(System.String,System.Object);generated",
"System.Threading.RateLimiting;RateLimitLease;get_IsAcquired;();generated",
"System.Threading.RateLimiting;RateLimitLease;get_MetadataNames;();generated",
@@ -35400,6 +35507,10 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Threading.Tasks.Dataflow;DataflowBlock;OutputAvailableAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>);generated",
"System.Threading.Tasks.Dataflow;DataflowBlock;OutputAvailableAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>,System.Threading.CancellationToken);generated",
"System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAllAsync<>;(System.Threading.Tasks.Dataflow.IReceivableSourceBlock<TOutput>,System.Threading.CancellationToken);generated",
"System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>);generated",
"System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>,System.Threading.CancellationToken);generated",
"System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>,System.TimeSpan);generated",
"System.Threading.Tasks.Dataflow;DataflowBlock;ReceiveAsync<>;(System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>,System.TimeSpan,System.Threading.CancellationToken);generated",
"System.Threading.Tasks.Dataflow;DataflowBlock;SendAsync<>;(System.Threading.Tasks.Dataflow.ITargetBlock<TInput>,TInput);generated",
"System.Threading.Tasks.Dataflow;DataflowBlockOptions;DataflowBlockOptions;();generated",
"System.Threading.Tasks.Dataflow;DataflowBlockOptions;get_BoundedCapacity;();generated",
@@ -36612,10 +36723,13 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Xml.Schema;XmlSchemaParticle;set_MinOccursString;(System.String);generated",
"System.Xml.Schema;XmlSchemaPatternFacet;XmlSchemaPatternFacet;();generated",
"System.Xml.Schema;XmlSchemaRedefine;XmlSchemaRedefine;();generated",
"System.Xml.Schema;XmlSchemaSet;Add;(System.Xml.Schema.XmlSchemaSet);generated",
"System.Xml.Schema;XmlSchemaSet;Compile;();generated",
"System.Xml.Schema;XmlSchemaSet;Contains;(System.String);generated",
"System.Xml.Schema;XmlSchemaSet;Contains;(System.Xml.Schema.XmlSchema);generated",
"System.Xml.Schema;XmlSchemaSet;CopyTo;(System.Xml.Schema.XmlSchema[],System.Int32);generated",
"System.Xml.Schema;XmlSchemaSet;RemoveRecursive;(System.Xml.Schema.XmlSchema);generated",
"System.Xml.Schema;XmlSchemaSet;Schemas;();generated",
"System.Xml.Schema;XmlSchemaSet;Schemas;(System.String);generated",
"System.Xml.Schema;XmlSchemaSet;XmlSchemaSet;();generated",
"System.Xml.Schema;XmlSchemaSet;get_Count;();generated",
@@ -36868,6 +36982,7 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Xml.Serialization;XmlSerializationWriter;WriteEmptyTag;(System.String,System.String);generated",
"System.Xml.Serialization;XmlSerializationWriter;WriteEndElement;();generated",
"System.Xml.Serialization;XmlSerializationWriter;WriteEndElement;(System.Object);generated",
"System.Xml.Serialization;XmlSerializationWriter;WriteId;(System.Object);generated",
"System.Xml.Serialization;XmlSerializationWriter;WriteNamespaceDeclarations;(System.Xml.Serialization.XmlSerializerNamespaces);generated",
"System.Xml.Serialization;XmlSerializationWriter;WriteNullTagEncoded;(System.String);generated",
"System.Xml.Serialization;XmlSerializationWriter;WriteNullTagEncoded;(System.String,System.String);generated",
@@ -36876,6 +36991,8 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System.Xml.Serialization;XmlSerializationWriter;WriteNullableQualifiedNameEncoded;(System.String,System.String,System.Xml.XmlQualifiedName,System.Xml.XmlQualifiedName);generated",
"System.Xml.Serialization;XmlSerializationWriter;WriteNullableQualifiedNameLiteral;(System.String,System.String,System.Xml.XmlQualifiedName);generated",
"System.Xml.Serialization;XmlSerializationWriter;WriteReferencedElements;();generated",
"System.Xml.Serialization;XmlSerializationWriter;WriteReferencingElement;(System.String,System.String,System.Object);generated",
"System.Xml.Serialization;XmlSerializationWriter;WriteReferencingElement;(System.String,System.String,System.Object,System.Boolean);generated",
"System.Xml.Serialization;XmlSerializationWriter;WriteStartDocument;();generated",
"System.Xml.Serialization;XmlSerializationWriter;WriteStartElement;(System.String);generated",
"System.Xml.Serialization;XmlSerializationWriter;WriteStartElement;(System.String,System.String);generated",
@@ -41046,7 +41163,29 @@ private class RuntimeNegativesummaryCsv extends NegativeSummaryModelCsv {
"System;Tuple<>;Equals;(System.Object,System.Collections.IEqualityComparer);generated",
"System;Tuple<>;GetHashCode;();generated",
"System;Tuple<>;GetHashCode;(System.Collections.IEqualityComparer);generated",
"System;Tuple<>;get_Length;();generated", "System;Type;Equals;(System.Object);generated",
"System;Tuple<>;get_Length;();generated",
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13,T14,System.ValueTuple<T15,T16,T17,T18,T19,T20,T21>>>);generated",
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13,T14,System.ValueTuple<T15,T16,T17,T18,T19,T20>>>);generated",
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13,T14,System.ValueTuple<T15,T16,T17,T18,T19>>>);generated",
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13,T14,System.ValueTuple<T15,T16,T17,T18>>>);generated",
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13,T14,System.ValueTuple<T15,T16,T17>>>);generated",
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13,T14,System.ValueTuple<T15,T16>>>);generated",
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13,T14,System.ValueTuple<T15>>>);generated",
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13,T14>>);generated",
"System;TupleExtensions;ToTuple<,,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12,T13>>);generated",
"System;TupleExtensions;ToTuple<,,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11,T12>>);generated",
"System;TupleExtensions;ToTuple<,,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10,T11>>);generated",
"System;TupleExtensions;ToTuple<,,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9,T10>>);generated",
"System;TupleExtensions;ToTuple<,,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8,T9>>);generated",
"System;TupleExtensions;ToTuple<,,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7,System.ValueTuple<T8>>);generated",
"System;TupleExtensions;ToTuple<,,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6,T7>);generated",
"System;TupleExtensions;ToTuple<,,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5,T6>);generated",
"System;TupleExtensions;ToTuple<,,,,>;(System.ValueTuple<T1,T2,T3,T4,T5>);generated",
"System;TupleExtensions;ToTuple<,,,>;(System.ValueTuple<T1,T2,T3,T4>);generated",
"System;TupleExtensions;ToTuple<,,>;(System.ValueTuple<T1,T2,T3>);generated",
"System;TupleExtensions;ToTuple<,>;(System.ValueTuple<T1,T2>);generated",
"System;TupleExtensions;ToTuple<>;(System.ValueTuple<T1>);generated",
"System;Type;Equals;(System.Object);generated",
"System;Type;Equals;(System.Type);generated", "System;Type;GetArrayRank;();generated",
"System;Type;GetAttributeFlagsImpl;();generated",
"System;Type;GetConstructorImpl;(System.Reflection.BindingFlags,System.Reflection.Binder,System.Reflection.CallingConventions,System.Type[],System.Reflection.ParameterModifier[]);generated",

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