mirror of
https://github.com/github/codeql.git
synced 2026-04-29 02:35:15 +02:00
Merge branch 'main' into codeql-spark-run-21376405640
This commit is contained in:
1
.github/workflows/ql-for-ql-build.yml
vendored
1
.github/workflows/ql-for-ql-build.yml
vendored
@@ -27,6 +27,7 @@ jobs:
|
||||
uses: github/codeql-action/init@main
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
tools: nightly
|
||||
- uses: ./.github/actions/os-version
|
||||
id: os_version
|
||||
### Build the extractor ###
|
||||
|
||||
2
.github/workflows/ql-for-ql-tests.yml
vendored
2
.github/workflows/ql-for-ql-tests.yml
vendored
@@ -30,6 +30,7 @@ jobs:
|
||||
uses: github/codeql-action/init@main
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
tools: nightly
|
||||
- uses: ./.github/actions/os-version
|
||||
id: os_version
|
||||
- uses: actions/cache@v3
|
||||
@@ -75,6 +76,7 @@ jobs:
|
||||
uses: github/codeql-action/init@main
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
tools: nightly
|
||||
- uses: ./.github/actions/os-version
|
||||
id: os_version
|
||||
- uses: actions/cache@v3
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Fixed a crash when analysing a `${{ ... }}` expression over around 300 characters in length.
|
||||
@@ -27,8 +27,8 @@ string getADelimitedExpression(YamlString s, int offset) {
|
||||
// not just the last (greedy match) or first (reluctant match).
|
||||
result =
|
||||
s.getValue()
|
||||
.regexpFind("\\$\\{\\{(?:[^}]|}(?!}))*\\}\\}", _, offset)
|
||||
.regexpCapture("(\\$\\{\\{(?:[^}]|}(?!}))*\\}\\})", 1)
|
||||
.regexpFind("\\$\\{\\{(?:[^}]|}(?!}))*+\\}\\}", _, offset)
|
||||
.regexpCapture("(\\$\\{\\{(?:[^}]|}(?!}))*+\\}\\})", 1)
|
||||
.trim()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-all
|
||||
version: 0.4.26
|
||||
version: 0.4.27-dev
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-queries
|
||||
version: 0.6.18
|
||||
version: 0.6.19-dev
|
||||
library: false
|
||||
warnOnImplicitThis: true
|
||||
groups: [actions, queries]
|
||||
|
||||
1002
actions/ql/test/library-tests/very-long-expression/.github/workflows/very_long_expression_node.yml
vendored
Normal file
1002
actions/ql/test/library-tests/very-long-expression/.github/workflows/very_long_expression_node.yml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
| 97418 |
|
||||
@@ -0,0 +1,5 @@
|
||||
import codeql.actions.ast.internal.Ast
|
||||
|
||||
int getAnExpressionLength() { result = any(ExpressionImpl e).toString().length() }
|
||||
|
||||
select max(getAnExpressionLength())
|
||||
2483
cpp/downgrades/83100310bf73eefc37c1d8d0ac98b2ca3019c7b6/old.dbscheme
Normal file
2483
cpp/downgrades/83100310bf73eefc37c1d8d0ac98b2ca3019c7b6/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Sections for databaseMetadata and overlayChangedFiles
|
||||
compatibility: full
|
||||
2489
cpp/downgrades/9439176c1d1312787926458dd54d65a849069118/old.dbscheme
Normal file
2489
cpp/downgrades/9439176c1d1312787926458dd54d65a849069118/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
||||
class PreprocessorDirective extends @preprocdirect {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_default {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from PreprocessorDirective ppd, int kind, int kind_new, Location l
|
||||
where
|
||||
preprocdirects(ppd, kind, l) and
|
||||
if kind = 17 then kind_new = /* ppd_warning */ 18 else kind_new = kind
|
||||
select ppd, kind_new, l
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
description: Support embed preprocessor directive
|
||||
compatibility: partial
|
||||
embeds.rel: delete
|
||||
preprocdirects.rel: run preprocdirects.qlo
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The predicate `SummarizedCallable.propagatesFlow` has been extended with the columns `Provenance p` and `boolean isExact`, and as a consequence the predicates `SummarizedCallable.hasProvenance` and `SummarizedCallable.hasExactModel` have been removed.
|
||||
4
cpp/ql/lib/change-notes/2026-01-19-embed.md
Normal file
4
cpp/ql/lib/change-notes/2026-01-19-embed.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added a subclass `Embed` of `PreprocessorDirective` for C23 and C++26 `#embed` preprocessor directives.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added modules `DataFlow::ParameterizedBarrierGuard` and `DataFlow::ParameterizedInstructionBarrierGuard`. These modules provide the same features as `DataFlow::BarrierGuard` and `DataFlow::InstructionBarrierGuard`, but allow for an additional parameter to support properly using them in dataflow configurations that uses flow states.
|
||||
4
cpp/ql/lib/change-notes/2026-01-23-as-definition.md
Normal file
4
cpp/ql/lib/change-notes/2026-01-23-as-definition.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Fixed a bug which caused `Node.asDefinition()` to not have a result for certain assignments.
|
||||
4
cpp/ql/lib/change-notes/2026-01-23-mysql.md
Normal file
4
cpp/ql/lib/change-notes/2026-01-23-mysql.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added `taint` summary models and `sql-injection` barrier models for the mySQL `mysql_real_escape_string` and `mysql_real_escape_string_quote` escaping functions.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `Buffer.qll` library will no longer report incorrect buffer sizes on certain malformed databases. As a result, the queries `cpp/static-buffer-overflow`, `cpp/overflow-buffer`, `cpp/badly-bounded-write`, `cpp/overrunning-write`, `cpp/overrunning-write-with-float`, and `cpp/very-likely-overrunning-write` will report fewer false positives on such databases.
|
||||
14
cpp/ql/lib/ext/MySql.model.yml
Normal file
14
cpp/ql/lib/ext/MySql.model.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
# partial model of the MySQL api
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
|
||||
- ["", "", False, "mysql_real_escape_string", "", "", "Argument[*2]", "Argument[*1]", "taint", "manual"]
|
||||
- ["", "", False, "mysql_real_escape_string_quote", "", "", "Argument[*2]", "Argument[*1]", "taint", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: barrierModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
|
||||
- ["", "", False, "mysql_real_escape_string", "", "", "Argument[*1]", "sql-injection", "manual"]
|
||||
- ["", "", False, "mysql_real_escape_string_quote", "", "", "Argument[*1]", "sql-injection", "manual"]
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 7.0.0
|
||||
version: 7.0.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -192,6 +192,15 @@ class Element extends ElementBase {
|
||||
*/
|
||||
predicate isAffectedByMacro() { affectedByMacro(this) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Holds if this element is affected by the expansion of `mi`.
|
||||
*/
|
||||
predicate isAffectedByMacro(MacroInvocation mi) {
|
||||
affectedbymacroexpansion(underlyingElement(this), unresolveElement(mi))
|
||||
}
|
||||
|
||||
private Element getEnclosingElementPref() {
|
||||
enclosingfunction(underlyingElement(this), unresolveElement(result)) or
|
||||
result.(Function) = stmtEnclosingElement(this) or
|
||||
|
||||
@@ -239,6 +239,9 @@ class MacroInvocation extends MacroAccess {
|
||||
macro_argument_unexpanded(underlyingElement(this), i, result)
|
||||
}
|
||||
|
||||
/** Gets the number of arguments for this macro invocation. */
|
||||
int getNumberOfArguments() { result = count(int i | exists(this.getUnexpandedArgument(i)) | i) }
|
||||
|
||||
/**
|
||||
* Gets the `i`th _expanded_ argument of this macro invocation, where the
|
||||
* first argument has `i = 0`. The result has been expanded for macros _and_
|
||||
|
||||
@@ -328,3 +328,27 @@ class PreprocessorPragma extends PreprocessorDirective, @ppd_pragma {
|
||||
class PreprocessorLine extends PreprocessorDirective, @ppd_line {
|
||||
override string toString() { result = "#line " + this.getHead() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C23 or C++26 `#embed` preprocessor directive. For example, the following code
|
||||
* contains one `Embed` directive:
|
||||
* ```cpp
|
||||
* char arr[] = {
|
||||
* #embed "bin"
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class Embed extends PreprocessorDirective, @ppd_embed {
|
||||
override string toString() { result = "#embed " + this.getIncludeText() }
|
||||
|
||||
/**
|
||||
* Gets the token which occurs after `#embed`, for example `"filename"`
|
||||
* or `<filename>`.
|
||||
*/
|
||||
string getIncludeText() { result = this.getHead() }
|
||||
|
||||
/**
|
||||
* Gets the file directly embedded by this `#embed`.
|
||||
*/
|
||||
File getEmbeddedFile() { embeds(underlyingElement(this), unresolveElement(result)) }
|
||||
}
|
||||
|
||||
@@ -62,11 +62,13 @@ private Class getRootType(FieldAccess fa) {
|
||||
* unspecified type of `v` is a `ReferenceType`.
|
||||
*/
|
||||
private int getVariableSize(Variable v) {
|
||||
exists(Type t |
|
||||
t = v.getUnspecifiedType() and
|
||||
not t instanceof ReferenceType and
|
||||
result = t.getSize()
|
||||
)
|
||||
result =
|
||||
unique(Type t |
|
||||
t = v.getUnspecifiedType() and
|
||||
not t instanceof ReferenceType
|
||||
|
|
||||
t.getSize()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,30 +81,32 @@ private int getSize(VariableAccess va) {
|
||||
not v instanceof Field and
|
||||
result = getVariableSize(v)
|
||||
or
|
||||
exists(Class c, int trueSize |
|
||||
// Otherwise, we find the "outermost" object and compute the size
|
||||
// as the difference between the size of the type of the "outermost
|
||||
// object" and the offset of the field relative to that type.
|
||||
// For example, consider the following structs:
|
||||
// ```
|
||||
// struct S {
|
||||
// uint32_t x;
|
||||
// uint32_t y;
|
||||
// };
|
||||
// struct S2 {
|
||||
// S s;
|
||||
// uint32_t z;
|
||||
// };
|
||||
// ```
|
||||
// Given an object `S2 s2` the size of the buffer `&s2.s.y`
|
||||
// is the size of the base object type (i.e., `S2`) minutes the offset
|
||||
// of `y` relative to the type `S2` (i.e., `4`). So the size of the
|
||||
// buffer is `12 - 4 = 8`.
|
||||
c = getRootType(va) and
|
||||
// we calculate the size based on the last field, to avoid including any padding after it
|
||||
trueSize = max(Field f | | f.getOffsetInClass(c) + getVariableSize(f)) and
|
||||
result = trueSize - v.(Field).getOffsetInClass(c)
|
||||
)
|
||||
result =
|
||||
unique(Class c, int trueSize |
|
||||
// Otherwise, we find the "outermost" object and compute the size
|
||||
// as the difference between the size of the type of the "outermost
|
||||
// object" and the offset of the field relative to that type.
|
||||
// For example, consider the following structs:
|
||||
// ```
|
||||
// struct S {
|
||||
// uint32_t x;
|
||||
// uint32_t y;
|
||||
// };
|
||||
// struct S2 {
|
||||
// S s;
|
||||
// uint32_t z;
|
||||
// };
|
||||
// ```
|
||||
// Given an object `S2 s2` the size of the buffer `&s2.s.y`
|
||||
// is the size of the base object type (i.e., `S2`) minus the offset
|
||||
// of `y` relative to the type `S2` (i.e., `4`). So the size of the
|
||||
// buffer is `12 - 4 = 8`.
|
||||
c = getRootType(va) and
|
||||
// we calculate the size based on the last field, to avoid including any padding after it
|
||||
trueSize = max(Field f | | f.getOffsetInClass(c) + getVariableSize(f))
|
||||
|
|
||||
trueSize - v.(Field).getOffsetInClass(c)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -116,12 +120,8 @@ private int isSource(Expr bufferExpr, Element why) {
|
||||
exists(Variable bufferVar | bufferVar = bufferExpr.(VariableAccess).getTarget() |
|
||||
// buffer is a fixed size array
|
||||
exists(bufferVar.getUnspecifiedType().(ArrayType).getSize()) and
|
||||
result =
|
||||
unique(int size | // more generous than .getSize() itself, when the array is a class field or similar.
|
||||
size = getSize(bufferExpr)
|
||||
|
|
||||
size
|
||||
) and
|
||||
// more generous than .getSize() itself, when the array is a class field or similar.
|
||||
result = getSize(bufferExpr) and
|
||||
why = bufferVar and
|
||||
not memberMayBeVarSize(_, bufferVar) and
|
||||
not exists(BuiltInOperationBuiltInOffsetOf offsetof | offsetof.getAChild*() = bufferExpr) and
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
|
||||
import cpp
|
||||
private import new.DataFlow
|
||||
private import semmle.code.cpp.controlflow.IRGuards
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as Private
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import internal.FlowSummaryImpl
|
||||
@@ -367,6 +368,8 @@ private predicate elementSpec(
|
||||
) {
|
||||
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or
|
||||
sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or
|
||||
barrierModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or
|
||||
barrierGuardModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _) or
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _)
|
||||
}
|
||||
|
||||
@@ -1028,6 +1031,84 @@ private module Cached {
|
||||
isSinkNode(n, kind, model) and n.asNode() = node
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TKindModelPair =
|
||||
TMkPair(string kind, string model) { isBarrierGuardNode(_, _, kind, model) }
|
||||
|
||||
private GuardValue convertAcceptingValue(Public::AcceptingValue av) {
|
||||
av.isTrue() and result.asBooleanValue() = true
|
||||
or
|
||||
av.isFalse() and result.asBooleanValue() = false
|
||||
or
|
||||
// NOTE: The below cases don't contribute anything currently since the
|
||||
// callers immediately use `.asBooleanValue()` to convert the `GuardValue`
|
||||
// to a boolean. Once we're willing to accept the breaking change of
|
||||
// converting the barrier guard API to use `GuardValue`s instead `Boolean`s
|
||||
// we can remove this restriction.
|
||||
av.isNoException() and result.getDualValue().isThrowsException()
|
||||
or
|
||||
av.isZero() and result.asIntValue() = 0
|
||||
or
|
||||
av.isNotZero() and result.getDualValue().asIntValue() = 0
|
||||
or
|
||||
av.isNull() and result.isNullValue()
|
||||
or
|
||||
av.isNotNull() and result.isNonNullValue()
|
||||
}
|
||||
|
||||
private predicate barrierGuardChecks(IRGuardCondition g, Expr e, boolean gv, TKindModelPair kmp) {
|
||||
exists(
|
||||
SourceSinkInterpretationInput::InterpretNode n, Public::AcceptingValue acceptingvalue,
|
||||
string kind, string model
|
||||
|
|
||||
isBarrierGuardNode(n, acceptingvalue, kind, model) and
|
||||
n.asNode().asExpr() = e and
|
||||
kmp = TMkPair(kind, model) and
|
||||
gv = convertAcceptingValue(acceptingvalue).asBooleanValue() and
|
||||
n.asNode().(Private::ArgumentNode).getCall().asCallInstruction() = g
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TKindModelPairIntPair =
|
||||
MkKindModelPairIntPair(TKindModelPair pair, int indirectionIndex) {
|
||||
indirectionIndex > 0 and
|
||||
Private::nodeHasInstruction(_, _, indirectionIndex) and
|
||||
exists(pair)
|
||||
}
|
||||
|
||||
private predicate indirectBarrierGuardChecks(
|
||||
IRGuardCondition g, Expr e, boolean gv, TKindModelPairIntPair kmp
|
||||
) {
|
||||
exists(
|
||||
SourceSinkInterpretationInput::InterpretNode interpretNode,
|
||||
Public::AcceptingValue acceptingvalue, string kind, string model, int indirectionIndex,
|
||||
Private::ArgumentNode arg
|
||||
|
|
||||
isBarrierGuardNode(interpretNode, acceptingvalue, kind, model) and
|
||||
arg = interpretNode.asNode() and
|
||||
arg.asIndirectExpr(indirectionIndex) = e and
|
||||
kmp = MkKindModelPairIntPair(TMkPair(kind, model), indirectionIndex) and
|
||||
gv = convertAcceptingValue(acceptingvalue).asBooleanValue() and
|
||||
arg.getCall().asCallInstruction() = g
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is specified as a barrier with the given kind in a MaD flow
|
||||
* model.
|
||||
*/
|
||||
cached
|
||||
predicate barrierNode(DataFlow::Node node, string kind, string model) {
|
||||
exists(SourceSinkInterpretationInput::InterpretNode n |
|
||||
isBarrierNode(n, kind, model) and n.asNode() = node
|
||||
)
|
||||
or
|
||||
DataFlow::ParameterizedBarrierGuard<TKindModelPair, barrierGuardChecks/4>::getABarrierNode(TMkPair(kind,
|
||||
model)) = node
|
||||
or
|
||||
DataFlow::ParameterizedBarrierGuard<TKindModelPairIntPair, indirectBarrierGuardChecks/4>::getAnIndirectBarrierNode(MkKindModelPairIntPair(TMkPair(kind,
|
||||
model), _)) = node
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
@@ -1044,6 +1125,12 @@ predicate sourceNode(DataFlow::Node node, string kind) { sourceNode(node, kind,
|
||||
*/
|
||||
predicate sinkNode(DataFlow::Node node, string kind) { sinkNode(node, kind, _) }
|
||||
|
||||
/**
|
||||
* Holds if `node` is specified as a barrier with the given kind in a MaD flow
|
||||
* model.
|
||||
*/
|
||||
predicate barrierNode(DataFlow::Node node, string kind) { barrierNode(node, kind, _) }
|
||||
|
||||
private predicate interpretSummary(
|
||||
Function f, string input, string output, string kind, string provenance, string model
|
||||
) {
|
||||
@@ -1058,40 +1145,22 @@ private predicate interpretSummary(
|
||||
|
||||
// adapter class for converting Mad summaries to `SummarizedCallable`s
|
||||
private class SummarizedCallableAdapter extends SummarizedCallable {
|
||||
SummarizedCallableAdapter() { interpretSummary(this, _, _, _, _, _) }
|
||||
string input_;
|
||||
string output_;
|
||||
string kind;
|
||||
Provenance p_;
|
||||
string model_;
|
||||
|
||||
private predicate relevantSummaryElementManual(
|
||||
string input, string output, string kind, string model
|
||||
) {
|
||||
exists(Provenance provenance |
|
||||
interpretSummary(this, input, output, kind, provenance, model) and
|
||||
provenance.isManual()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate relevantSummaryElementGenerated(
|
||||
string input, string output, string kind, string model
|
||||
) {
|
||||
exists(Provenance provenance |
|
||||
interpretSummary(this, input, output, kind, provenance, model) and
|
||||
provenance.isGenerated()
|
||||
)
|
||||
}
|
||||
SummarizedCallableAdapter() { interpretSummary(this, input_, output_, kind, p_, model_) }
|
||||
|
||||
override predicate propagatesFlow(
|
||||
string input, string output, boolean preservesValue, string model
|
||||
string input, string output, boolean preservesValue, Provenance p, boolean isExact, string model
|
||||
) {
|
||||
exists(string kind |
|
||||
this.relevantSummaryElementManual(input, output, kind, model)
|
||||
or
|
||||
not this.relevantSummaryElementManual(_, _, _, _) and
|
||||
this.relevantSummaryElementGenerated(input, output, kind, model)
|
||||
|
|
||||
if kind = "value" then preservesValue = true else preservesValue = false
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasProvenance(Provenance provenance) {
|
||||
interpretSummary(this, _, _, _, provenance, _)
|
||||
input = input_ and
|
||||
output = output_ and
|
||||
(if kind = "value" then preservesValue = true else preservesValue = false) and
|
||||
p = p_ and
|
||||
isExact = true and
|
||||
model = model_
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ module Input implements InputSig<Location, DataFlowImplSpecific::CppDataFlow> {
|
||||
|
||||
class SinkBase = Void;
|
||||
|
||||
predicate callableFromSource(SummarizedCallableBase c) { exists(c.getBlock()) }
|
||||
|
||||
ArgumentPosition callbackSelfParameterPosition() { result = TDirectPosition(-1) }
|
||||
|
||||
ReturnKind getStandardReturnValueKind() { result = getReturnValueKind("") }
|
||||
@@ -149,16 +151,27 @@ module SourceSinkInterpretationInput implements
|
||||
}
|
||||
|
||||
predicate barrierElement(
|
||||
Element n, string output, string kind, Public::Provenance provenance, string model
|
||||
Element e, string output, string kind, Public::Provenance provenance, string model
|
||||
) {
|
||||
none()
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
barrierModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance, model) and
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
)
|
||||
}
|
||||
|
||||
predicate barrierGuardElement(
|
||||
Element n, string input, Public::AcceptingValue acceptingvalue, string kind,
|
||||
Element e, string input, Public::AcceptingValue acceptingvalue, string kind,
|
||||
Public::Provenance provenance, string model
|
||||
) {
|
||||
none()
|
||||
exists(
|
||||
string package, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
barrierGuardModel(package, type, subtypes, name, signature, ext, input, acceptingvalue, kind,
|
||||
provenance, model) and
|
||||
e = interpretElement(package, type, subtypes, name, signature, ext)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TInterpretNode =
|
||||
|
||||
@@ -23,7 +23,7 @@ class Expr extends StmtParent, @expr {
|
||||
predicate hasChild(Expr e, int n) { e = this.getChild(n) }
|
||||
|
||||
/** Gets the enclosing function of this expression, if any. */
|
||||
Function getEnclosingFunction() { result = exprEnclosingElement(this) }
|
||||
override Function getEnclosingFunction() { result = exprEnclosingElement(this) }
|
||||
|
||||
/** Gets the nearest enclosing set of curly braces around this expression in the source, if any. */
|
||||
BlockStmt getEnclosingBlock() { result = this.getEnclosingStmt().getEnclosingBlock() }
|
||||
|
||||
@@ -45,13 +45,13 @@ private string getSingleLocationFilePath(@element e) {
|
||||
overlay[local]
|
||||
private string getMultiLocationFilePath(@element e) {
|
||||
exists(@location_default loc |
|
||||
exists(@var_decl vd | var_decls(vd, e, _, _, loc))
|
||||
var_decls(_, e, _, _, loc)
|
||||
or
|
||||
exists(@fun_decl fd | fun_decls(fd, e, _, _, loc))
|
||||
fun_decls(_, e, _, _, loc)
|
||||
or
|
||||
exists(@type_decl td | type_decls(td, e, loc))
|
||||
type_decls(_, e, loc)
|
||||
or
|
||||
exists(@namespace_decl nd | namespace_decls(nd, e, loc, _))
|
||||
namespace_decls(_, e, loc, _)
|
||||
|
|
||||
result = getLocationFilePath(loc)
|
||||
)
|
||||
@@ -62,7 +62,7 @@ private string getMultiLocationFilePath(@element e) {
|
||||
* overlay variant.
|
||||
*/
|
||||
overlay[local]
|
||||
private predicate holdsInBase() { not isOverlay() }
|
||||
private predicate isBase() { not isOverlay() }
|
||||
|
||||
/**
|
||||
* Discards an element from the base variant if:
|
||||
@@ -71,7 +71,7 @@ private predicate holdsInBase() { not isOverlay() }
|
||||
*/
|
||||
overlay[discard_entity]
|
||||
private predicate discardElement(@element e) {
|
||||
holdsInBase() and
|
||||
isBase() and
|
||||
(
|
||||
overlayChangedFiles(getSingleLocationFilePath(e))
|
||||
or
|
||||
|
||||
@@ -1144,7 +1144,7 @@ private newtype TDataFlowCall =
|
||||
}
|
||||
|
||||
private predicate summarizedCallableIsManual(SummarizedCallable sc) {
|
||||
sc.asSummarizedCallable().applyManualModel()
|
||||
sc.asSummarizedCallable().hasManualModel()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -312,6 +312,13 @@ class Node extends TIRDataFlowNode {
|
||||
*/
|
||||
Expr asDefinition() { result = this.asDefinition(_) }
|
||||
|
||||
private predicate isCertainStore() {
|
||||
exists(SsaImpl::Definition def |
|
||||
SsaImpl::defToNode(this, def, _) and
|
||||
def.isCertain()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the definition associated with this node, if any.
|
||||
*
|
||||
@@ -361,11 +368,10 @@ class Node extends TIRDataFlowNode {
|
||||
* pointed to by `p`.
|
||||
*/
|
||||
Expr asDefinition(boolean uncertain) {
|
||||
exists(StoreInstruction store, SsaImpl::Definition def |
|
||||
exists(StoreInstruction store |
|
||||
store = this.asInstruction() and
|
||||
result = asDefinitionImpl(store) and
|
||||
SsaImpl::defToNode(this, def, _) and
|
||||
if def.isCertain() then uncertain = false else uncertain = true
|
||||
if this.isCertainStore() then uncertain = false else uncertain = true
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2417,6 +2423,19 @@ class ContentSet instanceof Content {
|
||||
}
|
||||
}
|
||||
|
||||
private signature class ParamSig;
|
||||
|
||||
private module WithParam<ParamSig P> {
|
||||
/**
|
||||
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
|
||||
*
|
||||
* The expression `e` is expected to be a syntactic part of the guard `g`.
|
||||
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
|
||||
* the argument `x`.
|
||||
*/
|
||||
signature predicate guardChecksSig(IRGuardCondition g, Expr e, boolean branch, P param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
|
||||
*
|
||||
@@ -2438,7 +2457,7 @@ private predicate controls(IRGuardCondition g, Node n, boolean edge) {
|
||||
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
|
||||
* in data flow and taint tracking.
|
||||
*/
|
||||
module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guardChecks> {
|
||||
bindingset[value, n]
|
||||
pragma[inline_late]
|
||||
private predicate convertedExprHasValueNumber(ValueNumber value, Node n) {
|
||||
@@ -2448,12 +2467,13 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch) {
|
||||
guardChecks(g, n.asOperand().getDef().getConvertedResultExpression(), branch)
|
||||
private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch, P p) {
|
||||
guardChecks(g, n.asOperand().getDef().getConvertedResultExpression(), branch, p)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression node that is safely guarded by the given guard check.
|
||||
* Gets an expression node that is safely guarded by the given guard check
|
||||
* when the parameter is `p`.
|
||||
*
|
||||
* For example, given the following code:
|
||||
* ```cpp
|
||||
@@ -2484,19 +2504,27 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
*
|
||||
* NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead.
|
||||
*/
|
||||
Node getABarrierNode() {
|
||||
Node getABarrierNode(P p) {
|
||||
exists(IRGuardCondition g, ValueNumber value, boolean edge |
|
||||
convertedExprHasValueNumber(value, result) and
|
||||
guardChecks(g,
|
||||
pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge) and
|
||||
pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge, p) and
|
||||
controls(g, result, edge)
|
||||
)
|
||||
or
|
||||
result = SsaImpl::BarrierGuard<guardChecksNode/3>::getABarrierNode()
|
||||
result = SsaImpl::BarrierGuard<P, guardChecksNode/4>::getABarrierNode(p)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an indirect expression node that is safely guarded by the given guard check.
|
||||
* Gets an expression node that is safely guarded by the given guard check.
|
||||
*
|
||||
* See `getABarrierNode/1` for examples.
|
||||
*/
|
||||
Node getABarrierNode() { result = getABarrierNode(_) }
|
||||
|
||||
/**
|
||||
* Gets an indirect expression node that is safely guarded by the given
|
||||
* guard check with parameter `p`.
|
||||
*
|
||||
* For example, given the following code:
|
||||
* ```cpp
|
||||
@@ -2528,6 +2556,13 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
*
|
||||
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
|
||||
*/
|
||||
Node getAnIndirectBarrierNode(P p) { result = getAnIndirectBarrierNode(_, p) }
|
||||
|
||||
/**
|
||||
* Gets an indirect expression node that is safely guarded by the given guard check.
|
||||
*
|
||||
* See `getAnIndirectBarrierNode/1` for examples.
|
||||
*/
|
||||
Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
|
||||
|
||||
bindingset[value, n]
|
||||
@@ -2542,10 +2577,10 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
}
|
||||
|
||||
private predicate guardChecksIndirectNode(
|
||||
IRGuardCondition g, Node n, boolean branch, int indirectionIndex
|
||||
IRGuardCondition g, Node n, boolean branch, int indirectionIndex, P p
|
||||
) {
|
||||
guardChecks(g, n.asIndirectOperand(indirectionIndex).getDef().getConvertedResultExpression(),
|
||||
branch)
|
||||
branch, p)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2582,19 +2617,44 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
*
|
||||
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
|
||||
*/
|
||||
Node getAnIndirectBarrierNode(int indirectionIndex) {
|
||||
Node getAnIndirectBarrierNode(int indirectionIndex, P p) {
|
||||
exists(IRGuardCondition g, ValueNumber value, boolean edge |
|
||||
indirectConvertedExprHasValueNumber(indirectionIndex, value, result) and
|
||||
guardChecks(g,
|
||||
pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge) and
|
||||
pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge, p) and
|
||||
controls(g, result, edge)
|
||||
)
|
||||
or
|
||||
result =
|
||||
SsaImpl::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
|
||||
SsaImpl::BarrierGuardWithIntParam<P, guardChecksIndirectNode/5>::getABarrierNode(indirectionIndex,
|
||||
p)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a set of barrier nodes for a guard that validates an expression.
|
||||
*
|
||||
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
|
||||
* in data flow and taint tracking.
|
||||
*/
|
||||
module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
private predicate guardChecks(IRGuardCondition g, Expr e, boolean branch, Unit unit) {
|
||||
guardChecks(g, e, branch) and
|
||||
exists(unit)
|
||||
}
|
||||
|
||||
import ParameterizedBarrierGuard<Unit, guardChecks/4>
|
||||
}
|
||||
|
||||
private module InstrWithParam<ParamSig P> {
|
||||
/**
|
||||
* Holds if the guard `g` validates the instruction `instr` upon evaluating to `branch`.
|
||||
*/
|
||||
signature predicate instructionGuardChecksSig(
|
||||
IRGuardCondition g, Instruction instr, boolean branch, P p
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the guard `g` validates the instruction `instr` upon evaluating to `branch`.
|
||||
*/
|
||||
@@ -2606,7 +2666,9 @@ signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction in
|
||||
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
|
||||
* in data flow and taint tracking.
|
||||
*/
|
||||
module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> {
|
||||
module ParameterizedInstructionBarrierGuard<
|
||||
ParamSig P, InstrWithParam<P>::instructionGuardChecksSig/4 instructionGuardChecks>
|
||||
{
|
||||
bindingset[value, n]
|
||||
pragma[inline_late]
|
||||
private predicate operandHasValueNumber(ValueNumber value, Node n) {
|
||||
@@ -2616,21 +2678,27 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
|
||||
)
|
||||
}
|
||||
|
||||
private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch) {
|
||||
instructionGuardChecks(g, n.asOperand().getDef(), branch)
|
||||
private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch, P p) {
|
||||
instructionGuardChecks(g, n.asOperand().getDef(), branch, p)
|
||||
}
|
||||
|
||||
/** Gets a node that is safely guarded by the given guard check. */
|
||||
Node getABarrierNode() {
|
||||
/**
|
||||
* Gets a node that is safely guarded by the given guard check with
|
||||
* parameter `p`.
|
||||
*/
|
||||
Node getABarrierNode(P p) {
|
||||
exists(IRGuardCondition g, ValueNumber value, boolean edge |
|
||||
instructionGuardChecks(g, pragma[only_bind_into](value.getAnInstruction()), edge) and
|
||||
instructionGuardChecks(g, pragma[only_bind_into](value.getAnInstruction()), edge, p) and
|
||||
operandHasValueNumber(value, result) and
|
||||
controls(g, result, edge)
|
||||
)
|
||||
or
|
||||
result = SsaImpl::BarrierGuard<guardChecksNode/3>::getABarrierNode()
|
||||
result = SsaImpl::BarrierGuard<P, guardChecksNode/4>::getABarrierNode(p)
|
||||
}
|
||||
|
||||
/** Gets a node that is safely guarded by the given guard check. */
|
||||
Node getABarrierNode() { result = getABarrierNode(_) }
|
||||
|
||||
bindingset[value, n]
|
||||
pragma[inline_late]
|
||||
private predicate indirectOperandHasValueNumber(ValueNumber value, int indirectionIndex, Node n) {
|
||||
@@ -2641,25 +2709,52 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
|
||||
}
|
||||
|
||||
private predicate guardChecksIndirectNode(
|
||||
IRGuardCondition g, Node n, boolean branch, int indirectionIndex
|
||||
IRGuardCondition g, Node n, boolean branch, int indirectionIndex, P p
|
||||
) {
|
||||
instructionGuardChecks(g, n.asIndirectOperand(indirectionIndex).getDef(), branch)
|
||||
instructionGuardChecks(g, n.asIndirectOperand(indirectionIndex).getDef(), branch, p)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an indirect node with indirection index `indirectionIndex` that is
|
||||
* safely guarded by the given guard check.
|
||||
* safely guarded by the given guard check with parameter `p`.
|
||||
*/
|
||||
Node getAnIndirectBarrierNode(int indirectionIndex) {
|
||||
Node getAnIndirectBarrierNode(int indirectionIndex, P p) {
|
||||
exists(IRGuardCondition g, ValueNumber value, boolean edge |
|
||||
instructionGuardChecks(g, pragma[only_bind_into](value.getAnInstruction()), edge) and
|
||||
instructionGuardChecks(g, pragma[only_bind_into](value.getAnInstruction()), edge, p) and
|
||||
indirectOperandHasValueNumber(value, indirectionIndex, result) and
|
||||
controls(g, result, edge)
|
||||
)
|
||||
or
|
||||
result =
|
||||
SsaImpl::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
|
||||
SsaImpl::BarrierGuardWithIntParam<P, guardChecksIndirectNode/5>::getABarrierNode(indirectionIndex,
|
||||
p)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an indirect node that is safely guarded by the given guard check
|
||||
* with parameter `p`.
|
||||
*/
|
||||
Node getAnIndirectBarrierNode(P p) { result = getAnIndirectBarrierNode(_, p) }
|
||||
|
||||
/** Gets an indirect node that is safely guarded by the given guard check. */
|
||||
Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a set of barrier nodes for a guard that validates an instruction.
|
||||
*
|
||||
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
|
||||
* in data flow and taint tracking.
|
||||
*/
|
||||
module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> {
|
||||
private predicate instructionGuardChecks(
|
||||
IRGuardCondition g, Instruction i, boolean branch, Unit unit
|
||||
) {
|
||||
instructionGuardChecks(g, i, branch) and
|
||||
exists(unit)
|
||||
}
|
||||
|
||||
import ParameterizedInstructionBarrierGuard<Unit, instructionGuardChecks/4>
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -940,6 +940,16 @@ module SsaCached {
|
||||
SsaImpl::phiHasInputFromBlock(phi, inp, bb)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate uncertainWriteDefinitionInput(Definition uncertain, Definition inp) {
|
||||
SsaImpl::uncertainWriteDefinitionInput(uncertain, inp)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate ssaDefReachesEndOfBlock(IRBlock bb, Definition def) {
|
||||
SsaImpl::ssaDefReachesEndOfBlock(bb, def, _)
|
||||
}
|
||||
|
||||
predicate variableRead = SsaInput::variableRead/4;
|
||||
|
||||
predicate variableWrite = SsaInput::variableWrite/4;
|
||||
@@ -1035,13 +1045,23 @@ class SynthNode extends DataFlowIntegrationImpl::SsaNode {
|
||||
SynthNode() { not this.asDefinition() instanceof SsaImpl::WriteDefinition }
|
||||
}
|
||||
|
||||
signature predicate guardChecksNodeSig(IRGuards::IRGuardCondition g, Node e, boolean branch);
|
||||
private signature class ParamSig;
|
||||
|
||||
signature predicate guardChecksNodeSig(
|
||||
IRGuards::IRGuardCondition g, Node e, boolean branch, int indirectionIndex
|
||||
);
|
||||
private module ParamIntPair<ParamSig P> {
|
||||
newtype TPair = MkPair(P p, int indirectionIndex) { nodeHasInstruction(_, _, indirectionIndex) }
|
||||
}
|
||||
|
||||
module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
|
||||
private module WithParam<ParamSig P> {
|
||||
signature predicate guardChecksNodeSig(IRGuards::IRGuardCondition g, Node e, boolean gv, P param);
|
||||
}
|
||||
|
||||
private module IntWithParam<ParamSig P> {
|
||||
signature predicate guardChecksNodeSig(
|
||||
IRGuards::IRGuardCondition g, Node e, boolean gv, int indirectionIndex, P param
|
||||
);
|
||||
}
|
||||
|
||||
module BarrierGuardWithIntParam<ParamSig P, IntWithParam<P>::guardChecksNodeSig/5 guardChecksNode> {
|
||||
private predicate ssaDefReachesCertainUse(Definition def, UseImpl use) {
|
||||
exists(SourceVariable v, IRBlock bb, int i |
|
||||
use.hasIndexInBlock(bb, i, v) and
|
||||
@@ -1052,21 +1072,23 @@ module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
|
||||
|
||||
private predicate guardChecksInstr(
|
||||
IRGuards::Guards_v1::Guard g, IRGuards::GuardsInput::Expr instr, IRGuards::GuardValue gv,
|
||||
int indirectionIndex
|
||||
ParamIntPair<P>::TPair pair
|
||||
) {
|
||||
exists(Node node |
|
||||
exists(Node node, int indirectionIndex, P p |
|
||||
pair = ParamIntPair<P>::MkPair(p, indirectionIndex) and
|
||||
nodeHasInstruction(node, instr, indirectionIndex) and
|
||||
guardChecksNode(g, node, gv.asBooleanValue(), indirectionIndex)
|
||||
guardChecksNode(g, node, gv.asBooleanValue(), indirectionIndex, p)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate guardChecksWithWrappers(
|
||||
DataFlowIntegrationInput::Guard g, SsaImpl::Definition def, IRGuards::GuardValue val,
|
||||
int indirectionIndex
|
||||
ParamIntPair<P>::MkPair pair
|
||||
) {
|
||||
exists(Instruction e |
|
||||
IRGuards::Guards_v1::ParameterizedValidationWrapper<int, guardChecksInstr/4>::guardChecks(g,
|
||||
e, val, indirectionIndex)
|
||||
exists(Instruction e, int indirectionIndex |
|
||||
IRGuards::Guards_v1::ParameterizedValidationWrapper<ParamIntPair<P>::TPair, guardChecksInstr/4>::guardChecks(g,
|
||||
e, val, pair) and
|
||||
pair = ParamIntPair<P>::MkPair(_, indirectionIndex)
|
||||
|
|
||||
indirectionIndex = 0 and
|
||||
def.(Definition).getAUse().getDef() = e
|
||||
@@ -1075,18 +1097,19 @@ module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
|
||||
)
|
||||
}
|
||||
|
||||
Node getABarrierNode(int indirectionIndex) {
|
||||
Node getABarrierNode(int indirectionIndex, P p) {
|
||||
// Only get the SynthNodes from the shared implementation, as the ExprNodes cannot
|
||||
// be matched on SourceVariable.
|
||||
result.(SsaSynthNode).getSynthNode() =
|
||||
DataFlowIntegrationImpl::BarrierGuardDefWithState<int, guardChecksWithWrappers/4>::getABarrierNode(indirectionIndex)
|
||||
DataFlowIntegrationImpl::BarrierGuardDefWithState<ParamIntPair<P>::MkPair, guardChecksWithWrappers/4>::getABarrierNode(ParamIntPair<P>::MkPair(p,
|
||||
indirectionIndex))
|
||||
or
|
||||
// Calculate the guarded UseImpls corresponding to ExprNodes directly.
|
||||
exists(
|
||||
DataFlowIntegrationInput::Guard g, IRGuards::GuardValue branch, Definition def, IRBlock bb
|
||||
|
|
||||
guardChecksWithWrappers(g, def, branch, indirectionIndex) and
|
||||
exists(UseImpl use |
|
||||
guardChecksWithWrappers(g, def, branch, ParamIntPair<P>::MkPair(p, indirectionIndex)) and
|
||||
ssaDefReachesCertainUse(def, use) and
|
||||
use.getBlock() = bb and
|
||||
DataFlowIntegrationInput::guardControlsBlock(g, bb, branch) and
|
||||
@@ -1096,15 +1119,16 @@ module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
|
||||
}
|
||||
}
|
||||
|
||||
module BarrierGuard<guardChecksNodeSig/3 guardChecksNode> {
|
||||
module BarrierGuard<ParamSig P, WithParam<P>::guardChecksNodeSig/4 guardChecksNode> {
|
||||
private predicate guardChecksNode(
|
||||
IRGuards::IRGuardCondition g, Node e, boolean branch, int indirectionIndex
|
||||
IRGuards::IRGuardCondition g, Node e, boolean gv, int indirectionIndex, P p
|
||||
) {
|
||||
guardChecksNode(g, e, branch) and indirectionIndex = 0
|
||||
indirectionIndex = 0 and
|
||||
guardChecksNode(g, e, gv, p)
|
||||
}
|
||||
|
||||
Node getABarrierNode() {
|
||||
result = BarrierGuardWithIntParam<guardChecksNode/4>::getABarrierNode(0)
|
||||
Node getABarrierNode(P p) {
|
||||
result = BarrierGuardWithIntParam<P, guardChecksNode/5>::getABarrierNode(0, p)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1159,9 +1183,17 @@ class Definition extends SsaImpl::Definition {
|
||||
private Definition getAPhiInputOrPriorDefinition() {
|
||||
result = this.(PhiNode).getAnInput()
|
||||
or
|
||||
SsaImpl::uncertainWriteDefinitionInput(this, result)
|
||||
uncertainWriteDefinitionInput(this, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this SSA definition is live at the end of basic block `bb`.
|
||||
* That is, this definition reaches the end of basic block `bb`, at which
|
||||
* point it is still live, without crossing another SSA definition of the
|
||||
* same source variable.
|
||||
*/
|
||||
predicate isLiveAtEndOfBlock(IRBlock bb) { ssaDefReachesEndOfBlock(bb, this) }
|
||||
|
||||
/**
|
||||
* Gets a definition that ultimately defines this SSA definition and is
|
||||
* not itself a phi node.
|
||||
|
||||
@@ -104,7 +104,11 @@ newtype TInstructionTag =
|
||||
} or
|
||||
SizeofVlaDimensionTag(int index) {
|
||||
exists(VlaDeclStmt v | exists(v.getTransitiveVlaDimensionStmt(index)))
|
||||
}
|
||||
} or
|
||||
AssertionVarAddressTag() or
|
||||
AssertionVarLoadTag() or
|
||||
AssertionOpTag() or
|
||||
AssertionBranchTag()
|
||||
|
||||
class InstructionTag extends TInstructionTag {
|
||||
final string toString() { result = getInstructionTagId(this) }
|
||||
@@ -296,4 +300,12 @@ string getInstructionTagId(TInstructionTag tag) {
|
||||
tag = CoAwaitBranchTag() and result = "CoAwaitBranch"
|
||||
or
|
||||
tag = BoolToIntConversionTag() and result = "BoolToIntConversion"
|
||||
or
|
||||
tag = AssertionVarAddressTag() and result = "AssertionVarAddress"
|
||||
or
|
||||
tag = AssertionVarLoadTag() and result = "AssertionVarLoad"
|
||||
or
|
||||
tag = AssertionOpTag() and result = "AssertionOp"
|
||||
or
|
||||
tag = AssertionBranchTag() and result = "AssertionBranch"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,387 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.internal.IRUtilities
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.CppType
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedStmt
|
||||
private import TranslatedFunction
|
||||
|
||||
/**
|
||||
* Holds if `s` is a statement that may be an expanded assertion in a
|
||||
* release build.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate stmtCandidate(Stmt s) {
|
||||
not s.isFromUninstantiatedTemplate(_) and
|
||||
(
|
||||
// The expansion of `__analysis_assume(x != 0);` when `__analysis_assume` is
|
||||
// empty is the empty statement.
|
||||
s instanceof EmptyStmt
|
||||
or
|
||||
// The expansion of `assert(x != 0)` when `assert` is `((void)0)` is a zero literal
|
||||
// with a void type.
|
||||
exists(Expr e |
|
||||
e = s.(ExprStmt).getExpr() and
|
||||
e.getValue() = "0" and
|
||||
e.getActualType() instanceof VoidType
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate macroInvocationLocation(int startline, Function f, MacroInvocation mi) {
|
||||
mi.getMacroName() = ["assert", "__analysis_assume"] and
|
||||
mi.getNumberOfArguments() = 1 and
|
||||
mi.getLocation().hasLocationInfo(_, startline, _, _, _) and
|
||||
f.getEntryPoint().isAffectedByMacro(mi)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate stmtParentLocation(int startline, Function f, StmtParent p) {
|
||||
p.getEnclosingFunction() = f and
|
||||
p.getLocation().hasLocationInfo(_, startline, _, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `mi` is a macro invocation with a name that is known
|
||||
* to correspond to an assertion macro, and the macro invocation
|
||||
* is the only thing on the line.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate assertion0(MacroInvocation mi, Stmt s, string arg) {
|
||||
stmtCandidate(s) and
|
||||
s =
|
||||
unique(StmtParent p, int startline, Function f |
|
||||
macroInvocationLocation(startline, f, mi) and
|
||||
stmtParentLocation(startline, f, p) and
|
||||
// Also do not count the elements from the expanded macro, i.e., when checking
|
||||
// if `assert(x)` is the only thing on the line we do not count the
|
||||
// generated `((void)0)` expression.
|
||||
not p = mi.getAnExpandedElement()
|
||||
|
|
||||
p
|
||||
) and
|
||||
arg = mi.getUnexpandedArgument(0)
|
||||
}
|
||||
|
||||
private Function getEnclosingFunctionForMacroInvocation(MacroInvocation mi) {
|
||||
exists(Stmt s |
|
||||
assertion0(mi, s, _) and
|
||||
result = s.getEnclosingFunction()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `arg` has two components and the `i`'th component of the string
|
||||
* `arg` is `s`, and the components are separated by an operation with
|
||||
* opcode `opcode`.
|
||||
*/
|
||||
bindingset[arg]
|
||||
pragma[inline_late]
|
||||
private predicate parseArgument(string arg, string s, int i, Opcode opcode) {
|
||||
s =
|
||||
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?<=\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
|
||||
i + 1) and
|
||||
opcode instanceof Opcode::CompareLE
|
||||
or
|
||||
s =
|
||||
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?>=\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
|
||||
i + 1) and
|
||||
opcode instanceof Opcode::CompareGE
|
||||
or
|
||||
s =
|
||||
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?<\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
|
||||
i + 1) and
|
||||
opcode instanceof Opcode::CompareLT
|
||||
or
|
||||
s =
|
||||
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?>\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
|
||||
i + 1) and
|
||||
opcode instanceof Opcode::CompareGT
|
||||
or
|
||||
s =
|
||||
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?!=\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
|
||||
i + 1) and
|
||||
opcode instanceof Opcode::CompareNE
|
||||
or
|
||||
s =
|
||||
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?==\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
|
||||
i + 1) and
|
||||
opcode instanceof Opcode::CompareEQ
|
||||
}
|
||||
|
||||
private Element getAChildScope(Element scope) { result.getParentScope() = scope }
|
||||
|
||||
private predicate hasAVariable(MacroInvocation mi, Stmt s, Element scope) {
|
||||
assertion0(mi, s, _) and
|
||||
s.getParent() = scope
|
||||
or
|
||||
hasAVariable(mi, s, getAChildScope(scope))
|
||||
}
|
||||
|
||||
private LocalScopeVariable getVariable(MacroInvocation mi, int i) {
|
||||
exists(string operand, string arg, Stmt s |
|
||||
assertion0(mi, s, arg) and
|
||||
parseArgument(arg, operand, i, _) and
|
||||
result =
|
||||
unique(Variable v |
|
||||
v.getLocation().getStartLine() < s.getLocation().getStartLine() and
|
||||
hasAVariable(mi, s, v.getParentScope()) and
|
||||
v.hasName(operand)
|
||||
|
|
||||
v
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`'th component of the macro invocation `mi` with opcode
|
||||
* `opcode` is a reference to `var`.
|
||||
*/
|
||||
private predicate hasVarAccessMacroArgument(MacroInvocation mi, Variable var, int i, Opcode opcode) {
|
||||
exists(string arg, string s, Function f |
|
||||
arg = mi.getUnexpandedArgument(0) and
|
||||
f = getEnclosingFunctionForMacroInvocation(mi) and
|
||||
parseArgument(arg, s, i, opcode) and
|
||||
var = getVariable(mi, i)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`'th component of the macro invocation `mi` with opcode
|
||||
* `opcode` is a constant with the value `k`.
|
||||
*/
|
||||
private predicate hasConstMacroArgument(MacroInvocation mi, int k, int i, Opcode opcode) {
|
||||
exists(string arg, string s |
|
||||
assertion0(mi, _, arg) and
|
||||
s.toInt() = k and
|
||||
parseArgument(arg, s, i, opcode)
|
||||
)
|
||||
}
|
||||
|
||||
predicate hasAssertionOperand(MacroInvocation mi, int i) {
|
||||
hasVarAccessMacroArgument(mi, _, i, _)
|
||||
or
|
||||
hasConstMacroArgument(mi, _, i, _)
|
||||
}
|
||||
|
||||
private predicate hasAssertionOpcode(MacroInvocation mi, Opcode opcode) {
|
||||
hasVarAccessMacroArgument(mi, _, _, opcode)
|
||||
or
|
||||
hasConstMacroArgument(mi, _, _, opcode)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `mi` is a macro invocation that is an assertion that should be generated
|
||||
* in the control-flow graph at `s`.
|
||||
*/
|
||||
predicate assertion(MacroInvocation mi, Stmt s) {
|
||||
assertion0(mi, s, _) and
|
||||
hasAssertionOperand(mi, 0) and
|
||||
hasAssertionOperand(mi, 1)
|
||||
}
|
||||
|
||||
/** The translation of an operand of an assertion. */
|
||||
abstract private class TranslatedAssertionOperand extends TranslatedElement,
|
||||
TTranslatedAssertionOperand
|
||||
{
|
||||
MacroInvocation mi;
|
||||
int index;
|
||||
|
||||
TranslatedAssertionOperand() { this = TTranslatedAssertionOperand(mi, index) }
|
||||
|
||||
MacroInvocation getMacroInvocation() { result = mi }
|
||||
|
||||
/**
|
||||
* Gets the statement that is being replaced by the assertion that uses this
|
||||
* operand.
|
||||
*/
|
||||
Stmt getStmt() { assertion(mi, result) }
|
||||
|
||||
final override Locatable getAst() { result = this.getStmt() }
|
||||
|
||||
final override TranslatedElement getChild(int id) { none() }
|
||||
|
||||
final override Declaration getFunction() { result = this.getStmt().getEnclosingFunction() }
|
||||
|
||||
/** Gets the instruction which holds the result of this operand. */
|
||||
abstract Instruction getResult();
|
||||
|
||||
final override string toString() { result = "Operand of assertion: " + mi }
|
||||
|
||||
/** Gets the index of this operand (i.e., `0` or `1`). */
|
||||
final int getIndex() { result = index }
|
||||
}
|
||||
|
||||
/** An operand of an assertion that is a variable access. */
|
||||
class TranslatedAssertionVarAccess extends TranslatedAssertionOperand {
|
||||
TranslatedAssertionVarAccess() { hasVarAccessMacroArgument(mi, _, index, _) }
|
||||
|
||||
Variable getVariable() { hasVarAccessMacroArgument(mi, result, index, _) }
|
||||
|
||||
final override IRUserVariable getInstructionVariable(InstructionTag tag) {
|
||||
tag = AssertionVarAddressTag() and
|
||||
result.getVariable() = this.getVariable()
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
result = this.getInstruction(AssertionVarAddressTag()) and kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
|
||||
tag = AssertionVarAddressTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = this.getInstruction(AssertionVarLoadTag())
|
||||
or
|
||||
tag = AssertionVarLoadTag() and
|
||||
result = getTranslatedAssertionMacroInvocation(mi).getChildSuccessor(this, kind)
|
||||
}
|
||||
|
||||
final override Instruction getALastInstructionInternal() {
|
||||
result = this.getInstruction(AssertionVarLoadTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
exists(Variable v | v = this.getVariable() |
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
tag = AssertionVarAddressTag() and
|
||||
resultType = getTypeForGLValue(v.getType())
|
||||
or
|
||||
opcode instanceof Opcode::Load and
|
||||
tag = AssertionVarLoadTag() and
|
||||
resultType = getTypeForPRValue(v.getType())
|
||||
)
|
||||
}
|
||||
|
||||
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = AssertionVarLoadTag() and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = this.getInstruction(AssertionVarAddressTag())
|
||||
}
|
||||
|
||||
final override Instruction getResult() { result = this.getInstruction(AssertionVarLoadTag()) }
|
||||
}
|
||||
|
||||
/** An operand of an assertion that is a constant access. */
|
||||
private class TranslatedAssertionConst extends TranslatedAssertionOperand {
|
||||
TranslatedAssertionConst() { hasConstMacroArgument(mi, _, index, _) }
|
||||
|
||||
int getConst() { hasConstMacroArgument(mi, result, index, _) }
|
||||
|
||||
final override string getInstructionConstantValue(InstructionTag tag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = this.getConst().toString()
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
result = this.getInstruction(OnlyInstructionTag()) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = getTranslatedAssertionMacroInvocation(mi).getChildSuccessor(this, kind)
|
||||
}
|
||||
|
||||
final override Instruction getALastInstructionInternal() {
|
||||
result = this.getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
opcode instanceof Opcode::Constant and
|
||||
tag = OnlyInstructionTag() and
|
||||
resultType = getIntType()
|
||||
}
|
||||
|
||||
final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `TranslatedAssertionMacroInvocation` corresponding to the macro
|
||||
* invocation `mi`.
|
||||
*/
|
||||
TranslatedAssertionMacroInvocation getTranslatedAssertionMacroInvocation(MacroInvocation mi) {
|
||||
result.getMacroInvocation() = mi
|
||||
}
|
||||
|
||||
/**
|
||||
* A synthesized assertion which would have otherwise been invisible because the
|
||||
* database represents a release build where assertions are disabled.
|
||||
*/
|
||||
private class TranslatedAssertionMacroInvocation extends TranslatedStmt {
|
||||
MacroInvocation mi;
|
||||
|
||||
TranslatedAssertionMacroInvocation() { assertion(mi, stmt) }
|
||||
|
||||
final override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
result = this.getLeft().getFirstInstruction(kind)
|
||||
}
|
||||
|
||||
TranslatedAssertionOperand getLeft() {
|
||||
result.getMacroInvocation() = mi and
|
||||
result.getIndex() = 0
|
||||
}
|
||||
|
||||
TranslatedAssertionOperand getRight() {
|
||||
result.getMacroInvocation() = mi and
|
||||
result.getIndex() = 1
|
||||
}
|
||||
|
||||
final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
|
||||
tag = AssertionOpTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = this.getInstruction(AssertionBranchTag())
|
||||
or
|
||||
tag = AssertionBranchTag() and
|
||||
kind instanceof TrueEdge and
|
||||
result = this.getParent().getChildSuccessor(this, _)
|
||||
}
|
||||
|
||||
final override TranslatedElement getChildInternal(int id) {
|
||||
id = 0 and result = this.getLeft()
|
||||
or
|
||||
id = 1 and result = this.getRight()
|
||||
}
|
||||
|
||||
final override Instruction getALastInstructionInternal() {
|
||||
result = this.getInstruction(AssertionBranchTag())
|
||||
}
|
||||
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = AssertionOpTag() and
|
||||
resultType = getBoolType() and
|
||||
hasAssertionOpcode(mi, opcode)
|
||||
or
|
||||
tag = AssertionBranchTag() and
|
||||
resultType = getVoidType() and
|
||||
opcode instanceof Opcode::ConditionalBranch
|
||||
}
|
||||
|
||||
final override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
|
||||
child = this.getLeft() and
|
||||
result = this.getRight().getFirstInstruction(kind)
|
||||
or
|
||||
child = this.getRight() and
|
||||
kind instanceof GotoEdge and
|
||||
result = this.getInstruction(AssertionOpTag())
|
||||
}
|
||||
|
||||
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = AssertionOpTag() and
|
||||
(
|
||||
operandTag instanceof LeftOperandTag and
|
||||
result = this.getLeft().getResult()
|
||||
or
|
||||
operandTag instanceof RightOperandTag and
|
||||
result = this.getRight().getResult()
|
||||
)
|
||||
or
|
||||
tag = AssertionBranchTag() and
|
||||
operandTag instanceof ConditionOperandTag and
|
||||
result = this.getInstruction(AssertionOpTag())
|
||||
}
|
||||
|
||||
MacroInvocation getMacroInvocation() { result = mi }
|
||||
}
|
||||
@@ -12,6 +12,7 @@ private import TranslatedFunction
|
||||
private import TranslatedStmt
|
||||
private import TranslatedExpr
|
||||
private import IRConstruction
|
||||
private import TranslatedAssertion
|
||||
private import semmle.code.cpp.models.interfaces.SideEffect
|
||||
private import SideEffects
|
||||
|
||||
@@ -138,6 +139,14 @@ private predicate ignoreExprAndDescendants(Expr expr) {
|
||||
// conditionally constructed (until we have a mechanism for calling these only when the
|
||||
// temporary's constructor was run)
|
||||
isConditionalTemporaryDestructorCall(expr)
|
||||
or
|
||||
// An assertion in a release build is often defined as `#define assert(x) ((void)0)`.
|
||||
// We generate a synthetic assertion in release builds, and when we do that the
|
||||
// expression `((void)0)` should not be translated.
|
||||
exists(MacroInvocation mi |
|
||||
assertion(mi, _) and
|
||||
expr = mi.getExpr().getFullyConverted()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -909,7 +918,8 @@ newtype TTranslatedElement =
|
||||
} or
|
||||
// The side effect that initializes newly-allocated memory.
|
||||
TTranslatedAllocationSideEffect(AllocationExpr expr) { not ignoreSideEffects(expr) } or
|
||||
TTranslatedStaticStorageDurationVarInit(Variable var) { Raw::varHasIRFunc(var) }
|
||||
TTranslatedStaticStorageDurationVarInit(Variable var) { Raw::varHasIRFunc(var) } or
|
||||
TTranslatedAssertionOperand(MacroInvocation mi, int index) { hasAssertionOperand(mi, index) }
|
||||
|
||||
/**
|
||||
* Gets the index of the first explicitly initialized element in `initList`
|
||||
|
||||
@@ -10,6 +10,7 @@ private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
private import TranslatedFunction
|
||||
private import TranslatedInitialization
|
||||
private import TranslatedAssertion
|
||||
|
||||
TranslatedStmt getTranslatedStmt(Stmt stmt) { result.getAst() = stmt }
|
||||
|
||||
@@ -324,8 +325,16 @@ abstract class TranslatedStmt extends TranslatedElement, TTranslatedStmt {
|
||||
|
||||
class TranslatedEmptyStmt extends TranslatedStmt {
|
||||
TranslatedEmptyStmt() {
|
||||
stmt instanceof EmptyStmt or
|
||||
stmt instanceof LabelStmt or
|
||||
// An assertion macro invocation can expand to
|
||||
// an empty statement in release builds. In that case
|
||||
// we synthesize the check that would have occurred.
|
||||
// This is handled by `TranslatedAssertion.qll` and so
|
||||
// we exclude these statements here.
|
||||
not assertion(_, stmt) and
|
||||
stmt instanceof EmptyStmt
|
||||
or
|
||||
stmt instanceof LabelStmt
|
||||
or
|
||||
stmt instanceof SwitchCase
|
||||
}
|
||||
|
||||
@@ -420,6 +429,15 @@ class TranslatedDeclStmt extends TranslatedStmt {
|
||||
class TranslatedExprStmt extends TranslatedStmt {
|
||||
override ExprStmt stmt;
|
||||
|
||||
TranslatedExprStmt() {
|
||||
// An assertion macro invocation typically expand to the
|
||||
// expression `((void)0)` in release builds. In that case
|
||||
// we synthesize the check that would have occurred.
|
||||
// This is handled by `TranslatedAssertion.qll` and so
|
||||
// we exclude these statements here.
|
||||
not assertion(_, stmt)
|
||||
}
|
||||
|
||||
TranslatedExpr getExpr() { result = getTranslatedExpr(stmt.getExpr().getFullyConverted()) }
|
||||
|
||||
override TranslatedElement getChildInternal(int id) { id = 0 and result = this.getExpr() }
|
||||
|
||||
@@ -16,17 +16,3 @@ private class MySqlExecutionFunction extends SqlExecutionFunction {
|
||||
|
||||
override predicate hasSqlArgument(FunctionInput input) { input.isParameterDeref(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `mysql_real_escape_string` family of functions from the MySQL C API.
|
||||
*/
|
||||
private class MySqlBarrierFunction extends SqlBarrierFunction {
|
||||
MySqlBarrierFunction() {
|
||||
this.hasName(["mysql_real_escape_string", "mysql_real_escape_string_quote"])
|
||||
}
|
||||
|
||||
override predicate barrierSqlArgument(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameterDeref(2) and
|
||||
output.isParameterDeref(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ class Stmt extends StmtParent, @stmt {
|
||||
predicate hasChild(Element e, int n) { this.getChild(n) = e }
|
||||
|
||||
/** Gets the enclosing function of this statement, if any. */
|
||||
Function getEnclosingFunction() { result = stmtEnclosingElement(this) }
|
||||
override Function getEnclosingFunction() { result = stmtEnclosingElement(this) }
|
||||
|
||||
/**
|
||||
* Gets the nearest enclosing block of this statement in the source, if any.
|
||||
@@ -159,7 +159,10 @@ private class TStmtParent = @stmt or @expr;
|
||||
*
|
||||
* This is normally a statement, but may be a `StmtExpr`.
|
||||
*/
|
||||
class StmtParent extends ControlFlowNode, TStmtParent { }
|
||||
class StmtParent extends ControlFlowNode, TStmtParent {
|
||||
/** Gets the enclosing function of this element, if any. */
|
||||
Function getEnclosingFunction() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ 'expression' statement.
|
||||
|
||||
@@ -2353,6 +2353,7 @@ case @preprocdirect.kind of
|
||||
| 14 = @ppd_ms_import
|
||||
| 15 = @ppd_elifdef
|
||||
| 16 = @ppd_elifndef
|
||||
| 17 = @ppd_embed
|
||||
| 18 = @ppd_warning
|
||||
;
|
||||
|
||||
@@ -2379,6 +2380,11 @@ includes(
|
||||
int included: @file ref
|
||||
);
|
||||
|
||||
embeds(
|
||||
unique int id: @ppd_embed ref,
|
||||
int included: @file ref
|
||||
);
|
||||
|
||||
link_targets(
|
||||
int id: @link_target,
|
||||
int binary: @file ref
|
||||
@@ -2389,6 +2395,8 @@ link_parent(
|
||||
int link_target : @link_target ref
|
||||
);
|
||||
|
||||
/*- Database metadata -*/
|
||||
|
||||
/**
|
||||
* The CLI will automatically emit applicable tuples for this table,
|
||||
* such as `databaseMetadata("isOverlay", "true")` when building an
|
||||
@@ -2399,6 +2407,8 @@ databaseMetadata(
|
||||
string value: string ref
|
||||
);
|
||||
|
||||
/*- Overlay support -*/
|
||||
|
||||
/**
|
||||
* The CLI will automatically emit tuples for each new/modified/deleted file
|
||||
* when building an overlay database.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Sections for databaseMetadata and overlayChangedFiles
|
||||
compatibility: full
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Support embed preprocessor directive
|
||||
compatibility: partial
|
||||
@@ -45,14 +45,15 @@ module SqlTaintedConfig implements DataFlow::ConfigSig {
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.asExpr().getUnspecifiedType() instanceof IntegralType
|
||||
}
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) {
|
||||
or
|
||||
exists(SqlBarrierFunction sql, int arg, FunctionInput input |
|
||||
node.asIndirectArgument() = sql.getACallToThisFunction().getArgument(arg) and
|
||||
input.isParameterDeref(arg) and
|
||||
sql.barrierSqlArgument(input, _)
|
||||
)
|
||||
or
|
||||
// barrier defined using models-as-data
|
||||
barrierNode(node, "sql-injection")
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 1.5.9
|
||||
version: 1.5.10-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -310,7 +310,7 @@ private module SummaryModelGeneratorInput implements SummaryModelGeneratorInputS
|
||||
}
|
||||
|
||||
private predicate hasManualSummaryModel(Callable api) {
|
||||
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()) or
|
||||
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.hasManualModel()) or
|
||||
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel())
|
||||
}
|
||||
|
||||
|
||||
18
cpp/ql/test/library-tests/dataflow/asDefinition/test.cpp
Normal file
18
cpp/ql/test/library-tests/dataflow/asDefinition/test.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
struct S {
|
||||
int x;
|
||||
};
|
||||
|
||||
void use(int);
|
||||
|
||||
void test() {
|
||||
int y = 43; // $ asDefinition=43
|
||||
use(y);
|
||||
y = 44; // $ asDefinition="... = ..."
|
||||
use(y);
|
||||
|
||||
int x = 43; // $ asDefinition=43
|
||||
x = 44; // $ asDefinition="... = ..."
|
||||
|
||||
S s;
|
||||
s.x = 42; // $ asDefinition="... = ..."
|
||||
}
|
||||
22
cpp/ql/test/library-tests/dataflow/asDefinition/test.ql
Normal file
22
cpp/ql/test/library-tests/dataflow/asDefinition/test.ql
Normal file
@@ -0,0 +1,22 @@
|
||||
import cpp
|
||||
import utils.test.InlineExpectationsTest
|
||||
import semmle.code.cpp.dataflow.new.DataFlow::DataFlow
|
||||
|
||||
bindingset[s]
|
||||
string quote(string s) { if s.matches("% %") then result = "\"" + s + "\"" else result = s }
|
||||
|
||||
module AsDefinitionTest implements TestSig {
|
||||
string getARelevantTag() { result = "asDefinition" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Node n, Expr e |
|
||||
e = n.asDefinition() and
|
||||
location = e.getLocation() and
|
||||
element = n.toString() and
|
||||
tag = "asDefinition" and
|
||||
value = quote(e.toString())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<AsDefinitionTest>
|
||||
@@ -3,6 +3,4 @@
|
||||
| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated |
|
||||
| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body |
|
||||
| test.cpp:28:35:28:35 | 0 | test.cpp:28:11:28:33 | call to ymlStepManual_with_body |
|
||||
| test.cpp:32:38:32:38 | 0 | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body |
|
||||
| test.cpp:35:38:35:38 | x | test.cpp:35:11:35:36 | call to ymlStepGenerated_with_body |
|
||||
| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA |
|
||||
|
||||
@@ -12,4 +12,38 @@ void testCheckArgument(int p) {
|
||||
if (checkArgument(&p)) {
|
||||
sink(p); // $ barrier=glval<int> indirect_barrier=int
|
||||
}
|
||||
}
|
||||
|
||||
int* get_clean_value(int* x) { return x; }
|
||||
bool is_clean_value(int*);
|
||||
|
||||
int* get_clean_pointer(int* x) { return x; }
|
||||
bool is_clean_pointer(int*);
|
||||
|
||||
void sink(int*);
|
||||
|
||||
void test_mad(int x, int* p) {
|
||||
{
|
||||
if(is_clean_value(&x)) {
|
||||
sink(x); // $ external=int
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if(is_clean_value(p)) {
|
||||
sink(*p); // $ external=int
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if(is_clean_pointer(p)) {
|
||||
sink(p); // $ external=int*
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if(is_clean_pointer(&x)) {
|
||||
sink(x); // $ external=glval<int>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: barrierModel
|
||||
data:
|
||||
- ["", "", False, "get_clean_pointer", "", "", "ReturnValue", "test-barrier", "manual"]
|
||||
- ["", "", False, "get_clean_data", "", "", "ReturnValue[*]", "test-barrier", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: barrierGuardModel
|
||||
data:
|
||||
- ["", "", False, "is_clean_value", "", "", "Argument[*0]", "true", "test-barrier", "manual"]
|
||||
- ["", "", False, "is_clean_pointer", "", "", "Argument[0]", "true", "test-barrier", "manual"]
|
||||
@@ -2,6 +2,7 @@ import cpp
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import semmle.code.cpp.controlflow.IRGuards
|
||||
import utils.test.InlineExpectationsTest
|
||||
import semmle.code.cpp.dataflow.ExternalFlow
|
||||
|
||||
predicate instructionGuardChecks(IRGuardCondition gc, Instruction checked, boolean branch) {
|
||||
exists(CallInstruction call |
|
||||
@@ -27,18 +28,26 @@ predicate barrierGuard(DataFlow::Node node, string s) {
|
||||
else s = node.getType().toString().replaceAll(" ", "")
|
||||
}
|
||||
|
||||
predicate externalBarrierGuard(DataFlow::Node node, string s) {
|
||||
barrierNode(node, "test-barrier") and
|
||||
if node.isGLValue()
|
||||
then s = "glval<" + node.getType().toString().replaceAll(" ", "") + ">"
|
||||
else s = node.getType().toString().replaceAll(" ", "")
|
||||
}
|
||||
|
||||
module Test implements TestSig {
|
||||
string getARelevantTag() { result = ["barrier", "indirect_barrier"] }
|
||||
string getARelevantTag() { result = ["barrier", "indirect_barrier", "external"] }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Node node, string s |
|
||||
indirectBarrierGuard(node, s) and
|
||||
value = s and
|
||||
exists(DataFlow::Node node |
|
||||
indirectBarrierGuard(node, value) and
|
||||
tag = "indirect_barrier"
|
||||
or
|
||||
barrierGuard(node, s) and
|
||||
value = s and
|
||||
barrierGuard(node, value) and
|
||||
tag = "barrier"
|
||||
or
|
||||
externalBarrierGuard(node, value) and
|
||||
tag = "external"
|
||||
|
|
||||
element = node.toString() and
|
||||
location = node.getLocation()
|
||||
|
||||
@@ -25131,6 +25131,517 @@ ir.cpp:
|
||||
# 2823| Type = [ArrayType] int[]
|
||||
# 2823| ValueCategory = lvalue
|
||||
# 2824| getStmt(5): [ReturnStmt] return ...
|
||||
# 2830| [TopLevelFunction] void test_assert_simple(int, int, unsigned int, int)
|
||||
# 2830| <params>:
|
||||
# 2830| getParameter(0): [Parameter] x
|
||||
# 2830| Type = [IntType] int
|
||||
# 2830| getParameter(1): [Parameter] y
|
||||
# 2830| Type = [IntType] int
|
||||
# 2830| getParameter(2): [Parameter] u
|
||||
# 2830| Type = [IntType] unsigned int
|
||||
# 2830| getParameter(3): [Parameter] shadowed
|
||||
# 2830| Type = [IntType] int
|
||||
# 2830| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2831| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 2831| getExpr(): [Literal] 0
|
||||
# 2831| Type = [IntType] int
|
||||
# 2831| Value = [Literal] 0
|
||||
# 2831| ValueCategory = prvalue
|
||||
# 2831| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2831| Type = [VoidType] void
|
||||
# 2831| ValueCategory = prvalue
|
||||
# 2831| getExpr(): [CStyleCast] (void)...
|
||||
# 2831| Conversion = [VoidConversion] conversion to void
|
||||
# 2831| Type = [VoidType] void
|
||||
# 2831| ValueCategory = prvalue
|
||||
# 2832| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 2832| getExpr(): [Literal] 0
|
||||
# 2832| Type = [IntType] int
|
||||
# 2832| Value = [Literal] 0
|
||||
# 2832| ValueCategory = prvalue
|
||||
# 2832| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2832| Type = [VoidType] void
|
||||
# 2832| ValueCategory = prvalue
|
||||
# 2832| getExpr(): [CStyleCast] (void)...
|
||||
# 2832| Conversion = [VoidConversion] conversion to void
|
||||
# 2832| Type = [VoidType] void
|
||||
# 2832| ValueCategory = prvalue
|
||||
# 2833| getStmt(2): [ExprStmt] ExprStmt
|
||||
# 2833| getExpr(): [Literal] 0
|
||||
# 2833| Type = [IntType] int
|
||||
# 2833| Value = [Literal] 0
|
||||
# 2833| ValueCategory = prvalue
|
||||
# 2833| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2833| Type = [VoidType] void
|
||||
# 2833| ValueCategory = prvalue
|
||||
# 2833| getExpr(): [CStyleCast] (void)...
|
||||
# 2833| Conversion = [VoidConversion] conversion to void
|
||||
# 2833| Type = [VoidType] void
|
||||
# 2833| ValueCategory = prvalue
|
||||
# 2835| getStmt(3): [EmptyStmt] ;
|
||||
# 2837| getStmt(4): [ExprStmt] ExprStmt
|
||||
# 2837| getExpr(): [Literal] 0
|
||||
# 2837| Type = [IntType] int
|
||||
# 2837| Value = [Literal] 0
|
||||
# 2837| ValueCategory = prvalue
|
||||
# 2837| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2837| Type = [VoidType] void
|
||||
# 2837| ValueCategory = prvalue
|
||||
# 2837| getExpr(): [CStyleCast] (void)...
|
||||
# 2837| Conversion = [VoidConversion] conversion to void
|
||||
# 2837| Type = [VoidType] void
|
||||
# 2837| ValueCategory = prvalue
|
||||
# 2839| getStmt(5): [BlockStmt] { ... }
|
||||
# 2840| getStmt(0): [DeclStmt] declaration
|
||||
# 2840| getDeclarationEntry(0): [VariableDeclarationEntry] definition of shadowed
|
||||
# 2840| Type = [IntType] int
|
||||
# 2840| getVariable().getInitializer(): [Initializer] initializer for shadowed
|
||||
# 2840| getExpr(): [VariableAccess] x
|
||||
# 2840| Type = [IntType] int
|
||||
# 2840| ValueCategory = prvalue(load)
|
||||
# 2841| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 2841| getExpr(): [Literal] 0
|
||||
# 2841| Type = [IntType] int
|
||||
# 2841| Value = [Literal] 0
|
||||
# 2841| ValueCategory = prvalue
|
||||
# 2841| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2841| Type = [VoidType] void
|
||||
# 2841| ValueCategory = prvalue
|
||||
# 2841| getExpr(): [CStyleCast] (void)...
|
||||
# 2841| Conversion = [VoidConversion] conversion to void
|
||||
# 2841| Type = [VoidType] void
|
||||
# 2841| ValueCategory = prvalue
|
||||
# 2843| getStmt(6): [ReturnStmt] return ...
|
||||
# 2846| [TemplateFunction,TopLevelFunction] void test_assert_in_template<T>(T, int, unsigned int)
|
||||
# 2846| <params>:
|
||||
# 2846| getParameter(0): [Parameter] x
|
||||
# 2846| Type = [TypeTemplateParameter] T
|
||||
# 2846| getParameter(1): [Parameter] y
|
||||
# 2846| Type = [IntType] int
|
||||
# 2846| getParameter(2): [Parameter] u
|
||||
# 2846| Type = [IntType] unsigned int
|
||||
# 2846| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2847| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 2847| getExpr(): [Literal] 0
|
||||
# 2847| Type = [IntType] int
|
||||
# 2847| Value = [Literal] 0
|
||||
# 2847| ValueCategory = prvalue
|
||||
# 2847| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2847| Type = [VoidType] void
|
||||
# 2847| ValueCategory = prvalue
|
||||
# 2847| getExpr(): [CStyleCast] (void)...
|
||||
# 2847| Conversion = [VoidConversion] conversion to void
|
||||
# 2847| Type = [VoidType] void
|
||||
# 2847| ValueCategory = prvalue
|
||||
# 2848| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 2848| getExpr(): [Literal] 0
|
||||
# 2848| Type = [IntType] int
|
||||
# 2848| Value = [Literal] 0
|
||||
# 2848| ValueCategory = prvalue
|
||||
# 2848| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2848| Type = [VoidType] void
|
||||
# 2848| ValueCategory = prvalue
|
||||
# 2848| getExpr(): [CStyleCast] (void)...
|
||||
# 2848| Conversion = [VoidConversion] conversion to void
|
||||
# 2848| Type = [VoidType] void
|
||||
# 2848| ValueCategory = prvalue
|
||||
# 2849| getStmt(2): [ExprStmt] ExprStmt
|
||||
# 2849| getExpr(): [Literal] 0
|
||||
# 2849| Type = [IntType] int
|
||||
# 2849| Value = [Literal] 0
|
||||
# 2849| ValueCategory = prvalue
|
||||
# 2849| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2849| Type = [VoidType] void
|
||||
# 2849| ValueCategory = prvalue
|
||||
# 2849| getExpr(): [CStyleCast] (void)...
|
||||
# 2849| Conversion = [VoidConversion] conversion to void
|
||||
# 2849| Type = [VoidType] void
|
||||
# 2849| ValueCategory = prvalue
|
||||
# 2851| getStmt(3): [EmptyStmt] ;
|
||||
# 2853| getStmt(4): [ExprStmt] ExprStmt
|
||||
# 2853| getExpr(): [Literal] 0
|
||||
# 2853| Type = [IntType] int
|
||||
# 2853| Value = [Literal] 0
|
||||
# 2853| ValueCategory = prvalue
|
||||
# 2853| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2853| Type = [VoidType] void
|
||||
# 2853| ValueCategory = prvalue
|
||||
# 2853| getExpr(): [CStyleCast] (void)...
|
||||
# 2853| Conversion = [VoidConversion] conversion to void
|
||||
# 2853| Type = [VoidType] void
|
||||
# 2853| ValueCategory = prvalue
|
||||
# 2855| getStmt(5): [BlockStmt] { ... }
|
||||
# 2856| getStmt(0): [DeclStmt] declaration
|
||||
# 2856| getDeclarationEntry(0): [VariableDeclarationEntry] definition of shadowed
|
||||
# 2856| Type = [IntType] int
|
||||
# 2856| getVariable().getInitializer(): [Initializer] initializer for shadowed
|
||||
# 2856| getExpr(): [VariableAccess] x
|
||||
# 2856| Type = [TypeTemplateParameter] T
|
||||
# 2856| ValueCategory = lvalue
|
||||
# 2856| getExpr().getFullyConverted(): [CStyleCast] (int)...
|
||||
# 2856| Type = [IntType] int
|
||||
# 2856| ValueCategory = prvalue
|
||||
# 2857| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 2857| getExpr(): [Literal] 0
|
||||
# 2857| Type = [IntType] int
|
||||
# 2857| Value = [Literal] 0
|
||||
# 2857| ValueCategory = prvalue
|
||||
# 2857| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2857| Type = [VoidType] void
|
||||
# 2857| ValueCategory = prvalue
|
||||
# 2857| getExpr(): [CStyleCast] (void)...
|
||||
# 2857| Conversion = [VoidConversion] conversion to void
|
||||
# 2857| Type = [VoidType] void
|
||||
# 2857| ValueCategory = prvalue
|
||||
# 2859| getStmt(6): [ExprStmt] ExprStmt
|
||||
# 2859| getExpr(): [Literal] 0
|
||||
# 2859| Type = [IntType] int
|
||||
# 2859| Value = [Literal] 0
|
||||
# 2859| ValueCategory = prvalue
|
||||
# 2859| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2859| Type = [VoidType] void
|
||||
# 2859| ValueCategory = prvalue
|
||||
# 2859| getExpr(): [CStyleCast] (void)...
|
||||
# 2859| Conversion = [VoidConversion] conversion to void
|
||||
# 2859| Type = [VoidType] void
|
||||
# 2859| ValueCategory = prvalue
|
||||
# 2860| getStmt(7): [ReturnStmt] return ...
|
||||
# 2846| [FunctionTemplateInstantiation,TopLevelFunction] void test_assert_in_template<int>(int, int, unsigned int)
|
||||
# 2846| <params>:
|
||||
# 2846| getParameter(0): [Parameter] x
|
||||
# 2846| Type = [IntType] int
|
||||
# 2846| getParameter(1): [Parameter] y
|
||||
# 2846| Type = [IntType] int
|
||||
# 2846| getParameter(2): [Parameter] u
|
||||
# 2846| Type = [IntType] unsigned int
|
||||
# 2846| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2847| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 2847| getExpr(): [Literal] 0
|
||||
# 2847| Type = [IntType] int
|
||||
# 2847| Value = [Literal] 0
|
||||
# 2847| ValueCategory = prvalue
|
||||
# 2847| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2847| Type = [VoidType] void
|
||||
# 2847| ValueCategory = prvalue
|
||||
# 2847| getExpr(): [CStyleCast] (void)...
|
||||
# 2847| Conversion = [VoidConversion] conversion to void
|
||||
# 2847| Type = [VoidType] void
|
||||
# 2847| ValueCategory = prvalue
|
||||
# 2848| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 2848| getExpr(): [Literal] 0
|
||||
# 2848| Type = [IntType] int
|
||||
# 2848| Value = [Literal] 0
|
||||
# 2848| ValueCategory = prvalue
|
||||
# 2848| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2848| Type = [VoidType] void
|
||||
# 2848| ValueCategory = prvalue
|
||||
# 2848| getExpr(): [CStyleCast] (void)...
|
||||
# 2848| Conversion = [VoidConversion] conversion to void
|
||||
# 2848| Type = [VoidType] void
|
||||
# 2848| ValueCategory = prvalue
|
||||
# 2849| getStmt(2): [ExprStmt] ExprStmt
|
||||
# 2849| getExpr(): [Literal] 0
|
||||
# 2849| Type = [IntType] int
|
||||
# 2849| Value = [Literal] 0
|
||||
# 2849| ValueCategory = prvalue
|
||||
# 2849| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2849| Type = [VoidType] void
|
||||
# 2849| ValueCategory = prvalue
|
||||
# 2849| getExpr(): [CStyleCast] (void)...
|
||||
# 2849| Conversion = [VoidConversion] conversion to void
|
||||
# 2849| Type = [VoidType] void
|
||||
# 2849| ValueCategory = prvalue
|
||||
# 2851| getStmt(3): [EmptyStmt] ;
|
||||
# 2853| getStmt(4): [ExprStmt] ExprStmt
|
||||
# 2853| getExpr(): [Literal] 0
|
||||
# 2853| Type = [IntType] int
|
||||
# 2853| Value = [Literal] 0
|
||||
# 2853| ValueCategory = prvalue
|
||||
# 2853| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2853| Type = [VoidType] void
|
||||
# 2853| ValueCategory = prvalue
|
||||
# 2853| getExpr(): [CStyleCast] (void)...
|
||||
# 2853| Conversion = [VoidConversion] conversion to void
|
||||
# 2853| Type = [VoidType] void
|
||||
# 2853| ValueCategory = prvalue
|
||||
# 2855| getStmt(5): [BlockStmt] { ... }
|
||||
# 2856| getStmt(0): [DeclStmt] declaration
|
||||
# 2856| getDeclarationEntry(0): [VariableDeclarationEntry] definition of shadowed
|
||||
# 2856| Type = [IntType] int
|
||||
# 2856| getVariable().getInitializer(): [Initializer] initializer for shadowed
|
||||
# 2856| getExpr(): [VariableAccess] x
|
||||
# 2856| Type = [IntType] int
|
||||
# 2856| ValueCategory = prvalue(load)
|
||||
# 2857| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 2857| getExpr(): [Literal] 0
|
||||
# 2857| Type = [IntType] int
|
||||
# 2857| Value = [Literal] 0
|
||||
# 2857| ValueCategory = prvalue
|
||||
# 2857| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2857| Type = [VoidType] void
|
||||
# 2857| ValueCategory = prvalue
|
||||
# 2857| getExpr(): [CStyleCast] (void)...
|
||||
# 2857| Conversion = [VoidConversion] conversion to void
|
||||
# 2857| Type = [VoidType] void
|
||||
# 2857| ValueCategory = prvalue
|
||||
# 2859| getStmt(6): [ExprStmt] ExprStmt
|
||||
# 2859| getExpr(): [Literal] 0
|
||||
# 2859| Type = [IntType] int
|
||||
# 2859| Value = [Literal] 0
|
||||
# 2859| ValueCategory = prvalue
|
||||
# 2859| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2859| Type = [VoidType] void
|
||||
# 2859| ValueCategory = prvalue
|
||||
# 2859| getExpr(): [CStyleCast] (void)...
|
||||
# 2859| Conversion = [VoidConversion] conversion to void
|
||||
# 2859| Type = [VoidType] void
|
||||
# 2859| ValueCategory = prvalue
|
||||
# 2860| getStmt(7): [ReturnStmt] return ...
|
||||
# 2846| [FunctionTemplateInstantiation,TopLevelFunction] void test_assert_in_template<short>(short, int, unsigned int)
|
||||
# 2846| <params>:
|
||||
# 2846| getParameter(0): [Parameter] x
|
||||
# 2846| Type = [ShortType] short
|
||||
# 2846| getParameter(1): [Parameter] y
|
||||
# 2846| Type = [IntType] int
|
||||
# 2846| getParameter(2): [Parameter] u
|
||||
# 2846| Type = [IntType] unsigned int
|
||||
# 2846| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2847| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 2847| getExpr(): [Literal] 0
|
||||
# 2847| Type = [IntType] int
|
||||
# 2847| Value = [Literal] 0
|
||||
# 2847| ValueCategory = prvalue
|
||||
# 2847| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2847| Type = [VoidType] void
|
||||
# 2847| ValueCategory = prvalue
|
||||
# 2847| getExpr(): [CStyleCast] (void)...
|
||||
# 2847| Conversion = [VoidConversion] conversion to void
|
||||
# 2847| Type = [VoidType] void
|
||||
# 2847| ValueCategory = prvalue
|
||||
# 2848| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 2848| getExpr(): [Literal] 0
|
||||
# 2848| Type = [IntType] int
|
||||
# 2848| Value = [Literal] 0
|
||||
# 2848| ValueCategory = prvalue
|
||||
# 2848| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2848| Type = [VoidType] void
|
||||
# 2848| ValueCategory = prvalue
|
||||
# 2848| getExpr(): [CStyleCast] (void)...
|
||||
# 2848| Conversion = [VoidConversion] conversion to void
|
||||
# 2848| Type = [VoidType] void
|
||||
# 2848| ValueCategory = prvalue
|
||||
# 2849| getStmt(2): [ExprStmt] ExprStmt
|
||||
# 2849| getExpr(): [Literal] 0
|
||||
# 2849| Type = [IntType] int
|
||||
# 2849| Value = [Literal] 0
|
||||
# 2849| ValueCategory = prvalue
|
||||
# 2849| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2849| Type = [VoidType] void
|
||||
# 2849| ValueCategory = prvalue
|
||||
# 2849| getExpr(): [CStyleCast] (void)...
|
||||
# 2849| Conversion = [VoidConversion] conversion to void
|
||||
# 2849| Type = [VoidType] void
|
||||
# 2849| ValueCategory = prvalue
|
||||
# 2851| getStmt(3): [EmptyStmt] ;
|
||||
# 2853| getStmt(4): [ExprStmt] ExprStmt
|
||||
# 2853| getExpr(): [Literal] 0
|
||||
# 2853| Type = [IntType] int
|
||||
# 2853| Value = [Literal] 0
|
||||
# 2853| ValueCategory = prvalue
|
||||
# 2853| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2853| Type = [VoidType] void
|
||||
# 2853| ValueCategory = prvalue
|
||||
# 2853| getExpr(): [CStyleCast] (void)...
|
||||
# 2853| Conversion = [VoidConversion] conversion to void
|
||||
# 2853| Type = [VoidType] void
|
||||
# 2853| ValueCategory = prvalue
|
||||
# 2855| getStmt(5): [BlockStmt] { ... }
|
||||
# 2856| getStmt(0): [DeclStmt] declaration
|
||||
# 2856| getDeclarationEntry(0): [VariableDeclarationEntry] definition of shadowed
|
||||
# 2856| Type = [IntType] int
|
||||
# 2856| getVariable().getInitializer(): [Initializer] initializer for shadowed
|
||||
# 2856| getExpr(): [VariableAccess] x
|
||||
# 2856| Type = [ShortType] short
|
||||
# 2856| ValueCategory = prvalue(load)
|
||||
# 2856| getExpr().getFullyConverted(): [CStyleCast] (int)...
|
||||
# 2856| Conversion = [IntegralConversion] integral conversion
|
||||
# 2856| Type = [IntType] int
|
||||
# 2856| ValueCategory = prvalue
|
||||
# 2857| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 2857| getExpr(): [Literal] 0
|
||||
# 2857| Type = [IntType] int
|
||||
# 2857| Value = [Literal] 0
|
||||
# 2857| ValueCategory = prvalue
|
||||
# 2857| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2857| Type = [VoidType] void
|
||||
# 2857| ValueCategory = prvalue
|
||||
# 2857| getExpr(): [CStyleCast] (void)...
|
||||
# 2857| Conversion = [VoidConversion] conversion to void
|
||||
# 2857| Type = [VoidType] void
|
||||
# 2857| ValueCategory = prvalue
|
||||
# 2859| getStmt(6): [ExprStmt] ExprStmt
|
||||
# 2859| getExpr(): [Literal] 0
|
||||
# 2859| Type = [IntType] int
|
||||
# 2859| Value = [Literal] 0
|
||||
# 2859| ValueCategory = prvalue
|
||||
# 2859| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2859| Type = [VoidType] void
|
||||
# 2859| ValueCategory = prvalue
|
||||
# 2859| getExpr(): [CStyleCast] (void)...
|
||||
# 2859| Conversion = [VoidConversion] conversion to void
|
||||
# 2859| Type = [VoidType] void
|
||||
# 2859| ValueCategory = prvalue
|
||||
# 2860| getStmt(7): [ReturnStmt] return ...
|
||||
# 2867| [TopLevelFunction] void (unnamed namespace)::complex_assertions(int, bool, int)
|
||||
# 2867| <params>:
|
||||
# 2867| getParameter(0): [Parameter] x
|
||||
# 2867| Type = [IntType] int
|
||||
# 2867| getParameter(1): [Parameter] b
|
||||
# 2867| Type = [BoolType] bool
|
||||
# 2867| getParameter(2): [Parameter] max
|
||||
# 2867| Type = [IntType] int
|
||||
# 2867| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2868| getStmt(0): [DeclStmt] declaration
|
||||
# 2868| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
|
||||
# 2868| Type = [IntType] int
|
||||
# 2868| getVariable().getInitializer(): [Initializer] initializer for y
|
||||
# 2868| getExpr(): [CommaExpr] ... , ...
|
||||
# 2868| Type = [IntType] int
|
||||
# 2868| ValueCategory = prvalue(load)
|
||||
# 2868| getLeftOperand(): [Literal] 0
|
||||
# 2868| Type = [IntType] int
|
||||
# 2868| Value = [Literal] 0
|
||||
# 2868| ValueCategory = prvalue
|
||||
# 2868| getRightOperand(): [VariableAccess] x
|
||||
# 2868| Type = [IntType] int
|
||||
# 2868| ValueCategory = prvalue(load)
|
||||
# 2868| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2868| Type = [VoidType] void
|
||||
# 2868| ValueCategory = prvalue
|
||||
# 2868| getExpr(): [CStyleCast] (void)...
|
||||
# 2868| Conversion = [VoidConversion] conversion to void
|
||||
# 2868| Type = [VoidType] void
|
||||
# 2868| ValueCategory = prvalue
|
||||
# 2868| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2868| Type = [IntType] int
|
||||
# 2868| ValueCategory = prvalue(load)
|
||||
# 2869| getStmt(1): [DeclStmt] declaration
|
||||
# 2869| getDeclarationEntry(0): [VariableDeclarationEntry] definition of z
|
||||
# 2869| Type = [IntType] int
|
||||
# 2869| getVariable().getInitializer(): [Initializer] initializer for z
|
||||
# 2869| getExpr(): [ConditionalExpr] ... ? ... : ...
|
||||
# 2869| Type = [IntType] int
|
||||
# 2869| ValueCategory = prvalue
|
||||
# 2869| getCondition(): [VariableAccess] b
|
||||
# 2869| Type = [BoolType] bool
|
||||
# 2869| ValueCategory = prvalue(load)
|
||||
# 2869| getThen(): [CommaExpr] ... , ...
|
||||
# 2869| Type = [IntType] int
|
||||
# 2869| Value = [CommaExpr] 0
|
||||
# 2869| ValueCategory = prvalue
|
||||
# 2869| getLeftOperand(): [Literal] 0
|
||||
# 2869| Type = [IntType] int
|
||||
# 2869| Value = [Literal] 0
|
||||
# 2869| ValueCategory = prvalue
|
||||
# 2869| getRightOperand(): [Literal] 0
|
||||
# 2869| Type = [IntType] int
|
||||
# 2869| Value = [Literal] 0
|
||||
# 2869| ValueCategory = prvalue
|
||||
# 2869| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2869| Type = [VoidType] void
|
||||
# 2869| ValueCategory = prvalue
|
||||
# 2869| getExpr(): [CStyleCast] (void)...
|
||||
# 2869| Conversion = [VoidConversion] conversion to void
|
||||
# 2869| Type = [VoidType] void
|
||||
# 2869| ValueCategory = prvalue
|
||||
# 2869| getElse(): [Literal] 1
|
||||
# 2869| Type = [IntType] int
|
||||
# 2869| Value = [Literal] 1
|
||||
# 2869| ValueCategory = prvalue
|
||||
# 2869| getThen().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2869| Type = [IntType] int
|
||||
# 2869| Value = [ParenthesisExpr] 0
|
||||
# 2869| ValueCategory = prvalue
|
||||
# 2871| getStmt(2): [TryStmt] try { ... }
|
||||
# 2871| getStmt(): [BlockStmt] { ... }
|
||||
# 2872| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 2872| getExpr(): [ThrowExpr] throw ...
|
||||
# 2872| Type = [IntType] int
|
||||
# 2872| ValueCategory = prvalue
|
||||
# 2872| getExpr(): [Literal] 41
|
||||
# 2872| Type = [IntType] int
|
||||
# 2872| Value = [Literal] 41
|
||||
# 2872| ValueCategory = prvalue
|
||||
# 2873| getChild(1): [Handler] <handler>
|
||||
# 2873| getParameter(): [Parameter] c
|
||||
# 2873| Type = [IntType] int
|
||||
# 2873| getBlock(): [CatchBlock] { ... }
|
||||
# 2874| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 2874| getExpr(): [Literal] 0
|
||||
# 2874| Type = [IntType] int
|
||||
# 2874| Value = [Literal] 0
|
||||
# 2874| ValueCategory = prvalue
|
||||
# 2874| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2874| Type = [VoidType] void
|
||||
# 2874| ValueCategory = prvalue
|
||||
# 2874| getExpr(): [CStyleCast] (void)...
|
||||
# 2874| Conversion = [VoidConversion] conversion to void
|
||||
# 2874| Type = [VoidType] void
|
||||
# 2874| ValueCategory = prvalue
|
||||
# 2875| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 2875| getExpr(): [Literal] 0
|
||||
# 2875| Type = [IntType] int
|
||||
# 2875| Value = [Literal] 0
|
||||
# 2875| ValueCategory = prvalue
|
||||
# 2875| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2875| Type = [VoidType] void
|
||||
# 2875| ValueCategory = prvalue
|
||||
# 2875| getExpr(): [CStyleCast] (void)...
|
||||
# 2875| Conversion = [VoidConversion] conversion to void
|
||||
# 2875| Type = [VoidType] void
|
||||
# 2875| ValueCategory = prvalue
|
||||
# 2878| getStmt(3): [ExprStmt] ExprStmt
|
||||
# 2878| getExpr(): [Literal] 0
|
||||
# 2878| Type = [IntType] int
|
||||
# 2878| Value = [Literal] 0
|
||||
# 2878| ValueCategory = prvalue
|
||||
# 2878| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2878| Type = [VoidType] void
|
||||
# 2878| ValueCategory = prvalue
|
||||
# 2878| getExpr(): [CStyleCast] (void)...
|
||||
# 2878| Conversion = [VoidConversion] conversion to void
|
||||
# 2878| Type = [VoidType] void
|
||||
# 2878| ValueCategory = prvalue
|
||||
# 2879| getStmt(4): [DeclStmt] declaration
|
||||
# 2879| getDeclarationEntry(0): [VariableDeclarationEntry] definition of shadowed
|
||||
# 2879| Type = [IntType] int
|
||||
# 2881| getStmt(5): [TryStmt] try { ... }
|
||||
# 2881| getStmt(): [BlockStmt] { ... }
|
||||
# 2882| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 2882| getExpr(): [ThrowExpr] throw ...
|
||||
# 2882| Type = [IntType] int
|
||||
# 2882| ValueCategory = prvalue
|
||||
# 2882| getExpr(): [Literal] 41
|
||||
# 2882| Type = [IntType] int
|
||||
# 2882| Value = [Literal] 41
|
||||
# 2882| ValueCategory = prvalue
|
||||
# 2883| getChild(1): [Handler] <handler>
|
||||
# 2883| getParameter(): [Parameter] shadowed
|
||||
# 2883| Type = [IntType] int
|
||||
# 2883| getBlock(): [CatchBlock] { ... }
|
||||
# 2884| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 2884| getExpr(): [Literal] 0
|
||||
# 2884| Type = [IntType] int
|
||||
# 2884| Value = [Literal] 0
|
||||
# 2884| ValueCategory = prvalue
|
||||
# 2884| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2884| Type = [VoidType] void
|
||||
# 2884| ValueCategory = prvalue
|
||||
# 2884| getExpr(): [CStyleCast] (void)...
|
||||
# 2884| Conversion = [VoidConversion] conversion to void
|
||||
# 2884| Type = [VoidType] void
|
||||
# 2884| ValueCategory = prvalue
|
||||
# 2886| getStmt(6): [ReturnStmt] return ...
|
||||
ir23.cpp:
|
||||
# 1| [TopLevelFunction] bool consteval_1()
|
||||
# 1| <params>:
|
||||
|
||||
@@ -20741,6 +20741,331 @@ ir.cpp:
|
||||
# 2821| v2821_10(void) = AliasedUse : m2821_3
|
||||
# 2821| v2821_11(void) = ExitFunction :
|
||||
|
||||
# 2830| void test_assert_simple(int, int, unsigned int, int)
|
||||
# 2830| Block 0
|
||||
# 2830| v2830_1(void) = EnterFunction :
|
||||
# 2830| m2830_2(unknown) = AliasedDefinition :
|
||||
# 2830| m2830_3(unknown) = InitializeNonLocal :
|
||||
# 2830| m2830_4(unknown) = Chi : total:m2830_2, partial:m2830_3
|
||||
# 2830| r2830_5(glval<int>) = VariableAddress[x] :
|
||||
# 2830| m2830_6(int) = InitializeParameter[x] : &:r2830_5
|
||||
# 2830| r2830_7(glval<int>) = VariableAddress[y] :
|
||||
# 2830| m2830_8(int) = InitializeParameter[y] : &:r2830_7
|
||||
# 2830| r2830_9(glval<unsigned int>) = VariableAddress[u] :
|
||||
# 2830| m2830_10(unsigned int) = InitializeParameter[u] : &:r2830_9
|
||||
# 2830| r2830_11(glval<int>) = VariableAddress[shadowed] :
|
||||
# 2830| m2830_12(int) = InitializeParameter[shadowed] : &:r2830_11
|
||||
# 2831| r2831_1(glval<int>) = VariableAddress[x] :
|
||||
# 2831| r2831_2(int) = Load[x] : &:r2831_1, m2830_6
|
||||
# 2831| r2831_3(int) = Constant[0] :
|
||||
# 2831| r2831_4(bool) = CompareGT : r2831_2, r2831_3
|
||||
# 2831| v2831_5(void) = ConditionalBranch : r2831_4
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 2832| Block 1
|
||||
# 2832| r2832_1(int) = Constant[0] :
|
||||
# 2832| r2832_2(glval<int>) = VariableAddress[x] :
|
||||
# 2832| r2832_3(int) = Load[x] : &:r2832_2, m2830_6
|
||||
# 2832| r2832_4(bool) = CompareLT : r2832_1, r2832_3
|
||||
# 2832| v2832_5(void) = ConditionalBranch : r2832_4
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 2833| Block 2
|
||||
# 2833| r2833_1(glval<int>) = VariableAddress[x] :
|
||||
# 2833| r2833_2(int) = Load[x] : &:r2833_1, m2830_6
|
||||
# 2833| r2833_3(glval<int>) = VariableAddress[y] :
|
||||
# 2833| r2833_4(int) = Load[y] : &:r2833_3, m2830_8
|
||||
# 2833| r2833_5(bool) = CompareLT : r2833_2, r2833_4
|
||||
# 2833| v2833_6(void) = ConditionalBranch : r2833_5
|
||||
#-----| True -> Block 3
|
||||
|
||||
# 2835| Block 3
|
||||
# 2835| r2835_1(glval<int>) = VariableAddress[x] :
|
||||
# 2835| r2835_2(int) = Load[x] : &:r2835_1, m2830_6
|
||||
# 2835| r2835_3(int) = Constant[2] :
|
||||
# 2835| r2835_4(bool) = CompareNE : r2835_2, r2835_3
|
||||
# 2835| v2835_5(void) = ConditionalBranch : r2835_4
|
||||
#-----| True -> Block 4
|
||||
|
||||
# 2837| Block 4
|
||||
# 2837| r2837_1(glval<unsigned int>) = VariableAddress[u] :
|
||||
# 2837| r2837_2(unsigned int) = Load[u] : &:r2837_1, m2830_10
|
||||
# 2837| r2837_3(glval<int>) = VariableAddress[x] :
|
||||
# 2837| r2837_4(int) = Load[x] : &:r2837_3, m2830_6
|
||||
# 2837| r2837_5(bool) = CompareLT : r2837_2, r2837_4
|
||||
# 2837| v2837_6(void) = ConditionalBranch : r2837_5
|
||||
#-----| True -> Block 5
|
||||
|
||||
# 2840| Block 5
|
||||
# 2840| r2840_1(glval<int>) = VariableAddress[shadowed] :
|
||||
# 2840| r2840_2(glval<int>) = VariableAddress[x] :
|
||||
# 2840| r2840_3(int) = Load[x] : &:r2840_2, m2830_6
|
||||
# 2840| m2840_4(int) = Store[shadowed] : &:r2840_1, r2840_3
|
||||
# 2841| r2841_1(int) = Constant[0] :
|
||||
# 2841| v2841_2(void) = Convert : r2841_1
|
||||
# 2843| v2843_1(void) = NoOp :
|
||||
# 2830| v2830_13(void) = ReturnVoid :
|
||||
# 2830| v2830_14(void) = AliasedUse : m2830_3
|
||||
# 2830| v2830_15(void) = ExitFunction :
|
||||
|
||||
# 2846| void test_assert_in_template<int>(int, int, unsigned int)
|
||||
# 2846| Block 0
|
||||
# 2846| v2846_1(void) = EnterFunction :
|
||||
# 2846| m2846_2(unknown) = AliasedDefinition :
|
||||
# 2846| m2846_3(unknown) = InitializeNonLocal :
|
||||
# 2846| m2846_4(unknown) = Chi : total:m2846_2, partial:m2846_3
|
||||
# 2846| r2846_5(glval<int>) = VariableAddress[x] :
|
||||
# 2846| m2846_6(int) = InitializeParameter[x] : &:r2846_5
|
||||
# 2846| r2846_7(glval<int>) = VariableAddress[y] :
|
||||
# 2846| m2846_8(int) = InitializeParameter[y] : &:r2846_7
|
||||
# 2846| r2846_9(glval<unsigned int>) = VariableAddress[u] :
|
||||
# 2846| m2846_10(unsigned int) = InitializeParameter[u] : &:r2846_9
|
||||
# 2847| r2847_1(glval<int>) = VariableAddress[x] :
|
||||
# 2847| r2847_2(int) = Load[x] : &:r2847_1, m2846_6
|
||||
# 2847| r2847_3(int) = Constant[0] :
|
||||
# 2847| r2847_4(bool) = CompareGT : r2847_2, r2847_3
|
||||
# 2847| v2847_5(void) = ConditionalBranch : r2847_4
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 2848| Block 1
|
||||
# 2848| r2848_1(int) = Constant[0] :
|
||||
# 2848| r2848_2(glval<int>) = VariableAddress[x] :
|
||||
# 2848| r2848_3(int) = Load[x] : &:r2848_2, m2846_6
|
||||
# 2848| r2848_4(bool) = CompareLT : r2848_1, r2848_3
|
||||
# 2848| v2848_5(void) = ConditionalBranch : r2848_4
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 2849| Block 2
|
||||
# 2849| r2849_1(glval<int>) = VariableAddress[x] :
|
||||
# 2849| r2849_2(int) = Load[x] : &:r2849_1, m2846_6
|
||||
# 2849| r2849_3(glval<int>) = VariableAddress[y] :
|
||||
# 2849| r2849_4(int) = Load[y] : &:r2849_3, m2846_8
|
||||
# 2849| r2849_5(bool) = CompareLT : r2849_2, r2849_4
|
||||
# 2849| v2849_6(void) = ConditionalBranch : r2849_5
|
||||
#-----| True -> Block 3
|
||||
|
||||
# 2851| Block 3
|
||||
# 2851| r2851_1(glval<int>) = VariableAddress[x] :
|
||||
# 2851| r2851_2(int) = Load[x] : &:r2851_1, m2846_6
|
||||
# 2851| r2851_3(int) = Constant[2] :
|
||||
# 2851| r2851_4(bool) = CompareNE : r2851_2, r2851_3
|
||||
# 2851| v2851_5(void) = ConditionalBranch : r2851_4
|
||||
#-----| True -> Block 4
|
||||
|
||||
# 2853| Block 4
|
||||
# 2853| r2853_1(glval<unsigned int>) = VariableAddress[u] :
|
||||
# 2853| r2853_2(unsigned int) = Load[u] : &:r2853_1, m2846_10
|
||||
# 2853| r2853_3(glval<int>) = VariableAddress[x] :
|
||||
# 2853| r2853_4(int) = Load[x] : &:r2853_3, m2846_6
|
||||
# 2853| r2853_5(bool) = CompareLT : r2853_2, r2853_4
|
||||
# 2853| v2853_6(void) = ConditionalBranch : r2853_5
|
||||
#-----| True -> Block 5
|
||||
|
||||
# 2856| Block 5
|
||||
# 2856| r2856_1(glval<int>) = VariableAddress[shadowed] :
|
||||
# 2856| r2856_2(glval<int>) = VariableAddress[x] :
|
||||
# 2856| r2856_3(int) = Load[x] : &:r2856_2, m2846_6
|
||||
# 2856| m2856_4(int) = Store[shadowed] : &:r2856_1, r2856_3
|
||||
# 2857| r2857_1(glval<int>) = VariableAddress[shadowed] :
|
||||
# 2857| r2857_2(int) = Load[shadowed] : &:r2857_1, m2856_4
|
||||
# 2857| r2857_3(int) = Constant[0] :
|
||||
# 2857| r2857_4(bool) = CompareGT : r2857_2, r2857_3
|
||||
# 2857| v2857_5(void) = ConditionalBranch : r2857_4
|
||||
#-----| True -> Block 6
|
||||
|
||||
# 2859| Block 6
|
||||
# 2859| r2859_1(glval<int>) = VariableAddress[x] :
|
||||
# 2859| r2859_2(int) = Load[x] : &:r2859_1, m2846_6
|
||||
# 2859| r2859_3(int) = Constant[0] :
|
||||
# 2859| r2859_4(bool) = CompareGT : r2859_2, r2859_3
|
||||
# 2859| v2859_5(void) = ConditionalBranch : r2859_4
|
||||
#-----| True -> Block 7
|
||||
|
||||
# 2860| Block 7
|
||||
# 2860| v2860_1(void) = NoOp :
|
||||
# 2846| v2846_11(void) = ReturnVoid :
|
||||
# 2846| v2846_12(void) = AliasedUse : m2846_3
|
||||
# 2846| v2846_13(void) = ExitFunction :
|
||||
|
||||
# 2846| void test_assert_in_template<short>(short, int, unsigned int)
|
||||
# 2846| Block 0
|
||||
# 2846| v2846_1(void) = EnterFunction :
|
||||
# 2846| m2846_2(unknown) = AliasedDefinition :
|
||||
# 2846| m2846_3(unknown) = InitializeNonLocal :
|
||||
# 2846| m2846_4(unknown) = Chi : total:m2846_2, partial:m2846_3
|
||||
# 2846| r2846_5(glval<short>) = VariableAddress[x] :
|
||||
# 2846| m2846_6(short) = InitializeParameter[x] : &:r2846_5
|
||||
# 2846| r2846_7(glval<int>) = VariableAddress[y] :
|
||||
# 2846| m2846_8(int) = InitializeParameter[y] : &:r2846_7
|
||||
# 2846| r2846_9(glval<unsigned int>) = VariableAddress[u] :
|
||||
# 2846| m2846_10(unsigned int) = InitializeParameter[u] : &:r2846_9
|
||||
# 2847| r2847_1(glval<short>) = VariableAddress[x] :
|
||||
# 2847| r2847_2(short) = Load[x] : &:r2847_1, m2846_6
|
||||
# 2847| r2847_3(int) = Constant[0] :
|
||||
# 2847| r2847_4(bool) = CompareGT : r2847_2, r2847_3
|
||||
# 2847| v2847_5(void) = ConditionalBranch : r2847_4
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 2848| Block 1
|
||||
# 2848| r2848_1(int) = Constant[0] :
|
||||
# 2848| r2848_2(glval<short>) = VariableAddress[x] :
|
||||
# 2848| r2848_3(short) = Load[x] : &:r2848_2, m2846_6
|
||||
# 2848| r2848_4(bool) = CompareLT : r2848_1, r2848_3
|
||||
# 2848| v2848_5(void) = ConditionalBranch : r2848_4
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 2849| Block 2
|
||||
# 2849| r2849_1(glval<short>) = VariableAddress[x] :
|
||||
# 2849| r2849_2(short) = Load[x] : &:r2849_1, m2846_6
|
||||
# 2849| r2849_3(glval<int>) = VariableAddress[y] :
|
||||
# 2849| r2849_4(int) = Load[y] : &:r2849_3, m2846_8
|
||||
# 2849| r2849_5(bool) = CompareLT : r2849_2, r2849_4
|
||||
# 2849| v2849_6(void) = ConditionalBranch : r2849_5
|
||||
#-----| True -> Block 3
|
||||
|
||||
# 2851| Block 3
|
||||
# 2851| r2851_1(glval<short>) = VariableAddress[x] :
|
||||
# 2851| r2851_2(short) = Load[x] : &:r2851_1, m2846_6
|
||||
# 2851| r2851_3(int) = Constant[2] :
|
||||
# 2851| r2851_4(bool) = CompareNE : r2851_2, r2851_3
|
||||
# 2851| v2851_5(void) = ConditionalBranch : r2851_4
|
||||
#-----| True -> Block 4
|
||||
|
||||
# 2853| Block 4
|
||||
# 2853| r2853_1(glval<unsigned int>) = VariableAddress[u] :
|
||||
# 2853| r2853_2(unsigned int) = Load[u] : &:r2853_1, m2846_10
|
||||
# 2853| r2853_3(glval<short>) = VariableAddress[x] :
|
||||
# 2853| r2853_4(short) = Load[x] : &:r2853_3, m2846_6
|
||||
# 2853| r2853_5(bool) = CompareLT : r2853_2, r2853_4
|
||||
# 2853| v2853_6(void) = ConditionalBranch : r2853_5
|
||||
#-----| True -> Block 5
|
||||
|
||||
# 2856| Block 5
|
||||
# 2856| r2856_1(glval<int>) = VariableAddress[shadowed] :
|
||||
# 2856| r2856_2(glval<short>) = VariableAddress[x] :
|
||||
# 2856| r2856_3(short) = Load[x] : &:r2856_2, m2846_6
|
||||
# 2856| r2856_4(int) = Convert : r2856_3
|
||||
# 2856| m2856_5(int) = Store[shadowed] : &:r2856_1, r2856_4
|
||||
# 2857| r2857_1(glval<int>) = VariableAddress[shadowed] :
|
||||
# 2857| r2857_2(int) = Load[shadowed] : &:r2857_1, m2856_5
|
||||
# 2857| r2857_3(int) = Constant[0] :
|
||||
# 2857| r2857_4(bool) = CompareGT : r2857_2, r2857_3
|
||||
# 2857| v2857_5(void) = ConditionalBranch : r2857_4
|
||||
#-----| True -> Block 6
|
||||
|
||||
# 2859| Block 6
|
||||
# 2859| r2859_1(glval<short>) = VariableAddress[x] :
|
||||
# 2859| r2859_2(short) = Load[x] : &:r2859_1, m2846_6
|
||||
# 2859| r2859_3(int) = Constant[0] :
|
||||
# 2859| r2859_4(bool) = CompareGT : r2859_2, r2859_3
|
||||
# 2859| v2859_5(void) = ConditionalBranch : r2859_4
|
||||
#-----| True -> Block 7
|
||||
|
||||
# 2860| Block 7
|
||||
# 2860| v2860_1(void) = NoOp :
|
||||
# 2846| v2846_11(void) = ReturnVoid :
|
||||
# 2846| v2846_12(void) = AliasedUse : m2846_3
|
||||
# 2846| v2846_13(void) = ExitFunction :
|
||||
|
||||
# 2867| void (unnamed namespace)::complex_assertions(int, bool, int)
|
||||
# 2867| Block 0
|
||||
# 2867| v2867_1(void) = EnterFunction :
|
||||
# 2867| m2867_2(unknown) = AliasedDefinition :
|
||||
# 2867| m2867_3(unknown) = InitializeNonLocal :
|
||||
# 2867| m2867_4(unknown) = Chi : total:m2867_2, partial:m2867_3
|
||||
# 2867| r2867_5(glval<int>) = VariableAddress[x] :
|
||||
# 2867| m2867_6(int) = InitializeParameter[x] : &:r2867_5
|
||||
# 2867| r2867_7(glval<bool>) = VariableAddress[b] :
|
||||
# 2867| m2867_8(bool) = InitializeParameter[b] : &:r2867_7
|
||||
# 2867| r2867_9(glval<int>) = VariableAddress[max] :
|
||||
# 2867| m2867_10(int) = InitializeParameter[max] : &:r2867_9
|
||||
# 2868| r2868_1(glval<int>) = VariableAddress[y] :
|
||||
# 2868| r2868_2(int) = Constant[0] :
|
||||
# 2868| v2868_3(void) = Convert : r2868_2
|
||||
# 2868| r2868_4(glval<int>) = VariableAddress[x] :
|
||||
# 2868| r2868_5(int) = Load[x] : &:r2868_4, m2867_6
|
||||
# 2868| r2868_6(int) = CopyValue : r2868_5
|
||||
# 2868| m2868_7(int) = Store[y] : &:r2868_1, r2868_6
|
||||
# 2869| r2869_1(glval<int>) = VariableAddress[z] :
|
||||
# 2869| r2869_2(glval<bool>) = VariableAddress[b] :
|
||||
# 2869| r2869_3(bool) = Load[b] : &:r2869_2, m2867_8
|
||||
# 2869| v2869_4(void) = ConditionalBranch : r2869_3
|
||||
#-----| False -> Block 5
|
||||
#-----| True -> Block 4
|
||||
|
||||
# 2867| Block 1
|
||||
# 2867| v2867_11(void) = AliasedUse : m2867_3
|
||||
# 2867| v2867_12(void) = ExitFunction :
|
||||
|
||||
# 2867| Block 2
|
||||
# 2867| v2867_13(void) = Unwind :
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 2869| Block 3
|
||||
# 2869| m2869_5(int) = Phi : from 4:m2869_11, from 5:m2869_14
|
||||
# 2869| r2869_6(glval<int>) = VariableAddress[#temp2869:17] :
|
||||
# 2869| r2869_7(int) = Load[#temp2869:17] : &:r2869_6, m2869_5
|
||||
# 2869| m2869_8(int) = Store[z] : &:r2869_1, r2869_7
|
||||
# 2872| r2872_1(glval<int>) = VariableAddress[#throw2872:13] :
|
||||
# 2872| r2872_2(int) = Constant[41] :
|
||||
# 2872| m2872_3(int) = Store[#throw2872:13] : &:r2872_1, r2872_2
|
||||
# 2872| v2872_4(void) = ThrowValue : &:r2872_1, m2872_3
|
||||
#-----| C++ Exception -> Block 6
|
||||
|
||||
# 2869| Block 4
|
||||
# 2869| r2869_9(int) = Constant[0] :
|
||||
# 2869| r2869_10(glval<int>) = VariableAddress[#temp2869:17] :
|
||||
# 2869| m2869_11(int) = Store[#temp2869:17] : &:r2869_10, r2869_9
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 2869| Block 5
|
||||
# 2869| r2869_12(int) = Constant[1] :
|
||||
# 2869| r2869_13(glval<int>) = VariableAddress[#temp2869:17] :
|
||||
# 2869| m2869_14(int) = Store[#temp2869:17] : &:r2869_13, r2869_12
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 2873| Block 6
|
||||
# 2873| v2873_1(void) = CatchByType[int] :
|
||||
#-----| C++ Exception -> Block 2
|
||||
#-----| Goto -> Block 7
|
||||
|
||||
# 2873| Block 7
|
||||
# 2873| r2873_2(glval<int>) = VariableAddress[c] :
|
||||
# 2873| m2873_3(int) = InitializeParameter[c] : &:r2873_2
|
||||
# 2874| r2874_1(glval<int>) = VariableAddress[c] :
|
||||
# 2874| r2874_2(int) = Load[c] : &:r2874_1, m2873_3
|
||||
# 2874| r2874_3(int) = Constant[42] :
|
||||
# 2874| r2874_4(bool) = CompareLT : r2874_2, r2874_3
|
||||
# 2874| v2874_5(void) = ConditionalBranch : r2874_4
|
||||
#-----| True -> Block 8
|
||||
|
||||
# 2875| Block 8
|
||||
# 2875| r2875_1(int) = Constant[0] :
|
||||
# 2875| v2875_2(void) = Convert : r2875_1
|
||||
# 2878| r2878_1(int) = Constant[0] :
|
||||
# 2878| v2878_2(void) = Convert : r2878_1
|
||||
# 2879| r2879_1(glval<int>) = VariableAddress[shadowed] :
|
||||
# 2879| m2879_2(int) = Uninitialized[shadowed] : &:r2879_1
|
||||
# 2882| r2882_1(glval<int>) = VariableAddress[#throw2882:13] :
|
||||
# 2882| r2882_2(int) = Constant[41] :
|
||||
# 2882| m2882_3(int) = Store[#throw2882:13] : &:r2882_1, r2882_2
|
||||
# 2882| v2882_4(void) = ThrowValue : &:r2882_1, m2882_3
|
||||
#-----| C++ Exception -> Block 9
|
||||
|
||||
# 2883| Block 9
|
||||
# 2883| v2883_1(void) = CatchByType[int] :
|
||||
#-----| C++ Exception -> Block 2
|
||||
#-----| Goto -> Block 10
|
||||
|
||||
# 2883| Block 10
|
||||
# 2883| r2883_2(glval<int>) = VariableAddress[shadowed] :
|
||||
# 2883| m2883_3(int) = InitializeParameter[shadowed] : &:r2883_2
|
||||
# 2884| r2884_1(int) = Constant[0] :
|
||||
# 2884| v2884_2(void) = Convert : r2884_1
|
||||
# 2886| v2886_1(void) = NoOp :
|
||||
# 2867| v2867_14(void) = ReturnVoid :
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
ir23.cpp:
|
||||
# 1| bool consteval_1()
|
||||
# 1| Block 0
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.TranslatedAssertion
|
||||
import utils.test.InlineExpectationsTest
|
||||
|
||||
module Test implements TestSig {
|
||||
string getARelevantTag() { result = "var" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(TranslatedAssertionVarAccess tava, Variable v |
|
||||
v = tava.getVariable() and
|
||||
location = tava.getLocation() and
|
||||
tava.toString() = element and
|
||||
tag = "var" and
|
||||
value = v.getLocation().getStartLine().toString() + ":" + v.getName()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<Test>
|
||||
@@ -2823,4 +2823,67 @@ void vla_sizeof_test5(int len1, size_t len2) {
|
||||
size_t z = sizeof((*&tmp1)[1]);
|
||||
}
|
||||
|
||||
// Common definitions for assertions in release builds
|
||||
#define assert(x) ((void)0)
|
||||
#define __analysis_assume(x)
|
||||
|
||||
void test_assert_simple(int x, int y, unsigned u, int shadowed) {
|
||||
assert(x > 0); // $ var=2830:x
|
||||
assert(0 < x); // $ var=2830:x
|
||||
assert(x < y); // $ var=2830:x var=2830:y
|
||||
|
||||
__analysis_assume(x != 2); // $ var=2830:x
|
||||
|
||||
assert(u < x); // $ var=2830:u var=2830:x
|
||||
|
||||
{
|
||||
int shadowed = x;
|
||||
assert(shadowed > 0); // no assertion generated since the variable is shadowed
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void test_assert_in_template(T x, int y, unsigned u) {
|
||||
assert(x > 0); // $ var=2846:x
|
||||
assert(0 < x); // $ var=2846:x
|
||||
assert(x < y); // $ var=2846:x var=2846:y
|
||||
|
||||
__analysis_assume(x != 2); // $ var=2846:x
|
||||
|
||||
assert(u < x); // $ var=2846:u var=2846:x
|
||||
|
||||
{
|
||||
int shadowed = x;
|
||||
assert(shadowed > 0); // $ var=2856:shadowed
|
||||
}
|
||||
assert(x> 0); // $ var=2846:x
|
||||
}
|
||||
|
||||
template void test_assert_in_template<int>(int, int, unsigned);
|
||||
template void test_assert_in_template<short>(short, int, unsigned);
|
||||
namespace {
|
||||
int shadowed;
|
||||
|
||||
void complex_assertions(int x, bool b, int max) {
|
||||
int y = (assert(x > 0), x); // no assertion generated
|
||||
int z = b ? (assert(x != 0), 0) : 1; // no assertion generated
|
||||
|
||||
try {
|
||||
throw 41;
|
||||
} catch (int c) {
|
||||
assert(c < 42); // $ var=2873:c
|
||||
assert(shadowed < 42); // no assertion generated
|
||||
}
|
||||
|
||||
assert(shadowed > 0); // no assertion generated
|
||||
int shadowed;
|
||||
|
||||
try {
|
||||
throw 41;
|
||||
} catch (int shadowed) {
|
||||
assert(shadowed < 42); // no assertion generated
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++20 --clang
|
||||
|
||||
@@ -18880,6 +18880,326 @@ ir.cpp:
|
||||
# 2821| v2821_9(void) = AliasedUse : ~m?
|
||||
# 2821| v2821_10(void) = ExitFunction :
|
||||
|
||||
# 2830| void test_assert_simple(int, int, unsigned int, int)
|
||||
# 2830| Block 0
|
||||
# 2830| v2830_1(void) = EnterFunction :
|
||||
# 2830| mu2830_2(unknown) = AliasedDefinition :
|
||||
# 2830| mu2830_3(unknown) = InitializeNonLocal :
|
||||
# 2830| r2830_4(glval<int>) = VariableAddress[x] :
|
||||
# 2830| mu2830_5(int) = InitializeParameter[x] : &:r2830_4
|
||||
# 2830| r2830_6(glval<int>) = VariableAddress[y] :
|
||||
# 2830| mu2830_7(int) = InitializeParameter[y] : &:r2830_6
|
||||
# 2830| r2830_8(glval<unsigned int>) = VariableAddress[u] :
|
||||
# 2830| mu2830_9(unsigned int) = InitializeParameter[u] : &:r2830_8
|
||||
# 2830| r2830_10(glval<int>) = VariableAddress[shadowed] :
|
||||
# 2830| mu2830_11(int) = InitializeParameter[shadowed] : &:r2830_10
|
||||
# 2831| r2831_1(glval<int>) = VariableAddress[x] :
|
||||
# 2831| r2831_2(int) = Load[x] : &:r2831_1, ~m?
|
||||
# 2831| r2831_3(int) = Constant[0] :
|
||||
# 2831| r2831_4(bool) = CompareGT : r2831_2, r2831_3
|
||||
# 2831| v2831_5(void) = ConditionalBranch : r2831_4
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 2832| Block 1
|
||||
# 2832| r2832_1(int) = Constant[0] :
|
||||
# 2832| r2832_2(glval<int>) = VariableAddress[x] :
|
||||
# 2832| r2832_3(int) = Load[x] : &:r2832_2, ~m?
|
||||
# 2832| r2832_4(bool) = CompareLT : r2832_1, r2832_3
|
||||
# 2832| v2832_5(void) = ConditionalBranch : r2832_4
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 2833| Block 2
|
||||
# 2833| r2833_1(glval<int>) = VariableAddress[x] :
|
||||
# 2833| r2833_2(int) = Load[x] : &:r2833_1, ~m?
|
||||
# 2833| r2833_3(glval<int>) = VariableAddress[y] :
|
||||
# 2833| r2833_4(int) = Load[y] : &:r2833_3, ~m?
|
||||
# 2833| r2833_5(bool) = CompareLT : r2833_2, r2833_4
|
||||
# 2833| v2833_6(void) = ConditionalBranch : r2833_5
|
||||
#-----| True -> Block 3
|
||||
|
||||
# 2835| Block 3
|
||||
# 2835| r2835_1(glval<int>) = VariableAddress[x] :
|
||||
# 2835| r2835_2(int) = Load[x] : &:r2835_1, ~m?
|
||||
# 2835| r2835_3(int) = Constant[2] :
|
||||
# 2835| r2835_4(bool) = CompareNE : r2835_2, r2835_3
|
||||
# 2835| v2835_5(void) = ConditionalBranch : r2835_4
|
||||
#-----| True -> Block 4
|
||||
|
||||
# 2837| Block 4
|
||||
# 2837| r2837_1(glval<unsigned int>) = VariableAddress[u] :
|
||||
# 2837| r2837_2(unsigned int) = Load[u] : &:r2837_1, ~m?
|
||||
# 2837| r2837_3(glval<int>) = VariableAddress[x] :
|
||||
# 2837| r2837_4(int) = Load[x] : &:r2837_3, ~m?
|
||||
# 2837| r2837_5(bool) = CompareLT : r2837_2, r2837_4
|
||||
# 2837| v2837_6(void) = ConditionalBranch : r2837_5
|
||||
#-----| True -> Block 5
|
||||
|
||||
# 2840| Block 5
|
||||
# 2840| r2840_1(glval<int>) = VariableAddress[shadowed] :
|
||||
# 2840| r2840_2(glval<int>) = VariableAddress[x] :
|
||||
# 2840| r2840_3(int) = Load[x] : &:r2840_2, ~m?
|
||||
# 2840| mu2840_4(int) = Store[shadowed] : &:r2840_1, r2840_3
|
||||
# 2841| r2841_1(int) = Constant[0] :
|
||||
# 2841| v2841_2(void) = Convert : r2841_1
|
||||
# 2843| v2843_1(void) = NoOp :
|
||||
# 2830| v2830_12(void) = ReturnVoid :
|
||||
# 2830| v2830_13(void) = AliasedUse : ~m?
|
||||
# 2830| v2830_14(void) = ExitFunction :
|
||||
|
||||
# 2846| void test_assert_in_template<int>(int, int, unsigned int)
|
||||
# 2846| Block 0
|
||||
# 2846| v2846_1(void) = EnterFunction :
|
||||
# 2846| mu2846_2(unknown) = AliasedDefinition :
|
||||
# 2846| mu2846_3(unknown) = InitializeNonLocal :
|
||||
# 2846| r2846_4(glval<int>) = VariableAddress[x] :
|
||||
# 2846| mu2846_5(int) = InitializeParameter[x] : &:r2846_4
|
||||
# 2846| r2846_6(glval<int>) = VariableAddress[y] :
|
||||
# 2846| mu2846_7(int) = InitializeParameter[y] : &:r2846_6
|
||||
# 2846| r2846_8(glval<unsigned int>) = VariableAddress[u] :
|
||||
# 2846| mu2846_9(unsigned int) = InitializeParameter[u] : &:r2846_8
|
||||
# 2847| r2847_1(glval<int>) = VariableAddress[x] :
|
||||
# 2847| r2847_2(int) = Load[x] : &:r2847_1, ~m?
|
||||
# 2847| r2847_3(int) = Constant[0] :
|
||||
# 2847| r2847_4(bool) = CompareGT : r2847_2, r2847_3
|
||||
# 2847| v2847_5(void) = ConditionalBranch : r2847_4
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 2848| Block 1
|
||||
# 2848| r2848_1(int) = Constant[0] :
|
||||
# 2848| r2848_2(glval<int>) = VariableAddress[x] :
|
||||
# 2848| r2848_3(int) = Load[x] : &:r2848_2, ~m?
|
||||
# 2848| r2848_4(bool) = CompareLT : r2848_1, r2848_3
|
||||
# 2848| v2848_5(void) = ConditionalBranch : r2848_4
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 2849| Block 2
|
||||
# 2849| r2849_1(glval<int>) = VariableAddress[x] :
|
||||
# 2849| r2849_2(int) = Load[x] : &:r2849_1, ~m?
|
||||
# 2849| r2849_3(glval<int>) = VariableAddress[y] :
|
||||
# 2849| r2849_4(int) = Load[y] : &:r2849_3, ~m?
|
||||
# 2849| r2849_5(bool) = CompareLT : r2849_2, r2849_4
|
||||
# 2849| v2849_6(void) = ConditionalBranch : r2849_5
|
||||
#-----| True -> Block 3
|
||||
|
||||
# 2851| Block 3
|
||||
# 2851| r2851_1(glval<int>) = VariableAddress[x] :
|
||||
# 2851| r2851_2(int) = Load[x] : &:r2851_1, ~m?
|
||||
# 2851| r2851_3(int) = Constant[2] :
|
||||
# 2851| r2851_4(bool) = CompareNE : r2851_2, r2851_3
|
||||
# 2851| v2851_5(void) = ConditionalBranch : r2851_4
|
||||
#-----| True -> Block 4
|
||||
|
||||
# 2853| Block 4
|
||||
# 2853| r2853_1(glval<unsigned int>) = VariableAddress[u] :
|
||||
# 2853| r2853_2(unsigned int) = Load[u] : &:r2853_1, ~m?
|
||||
# 2853| r2853_3(glval<int>) = VariableAddress[x] :
|
||||
# 2853| r2853_4(int) = Load[x] : &:r2853_3, ~m?
|
||||
# 2853| r2853_5(bool) = CompareLT : r2853_2, r2853_4
|
||||
# 2853| v2853_6(void) = ConditionalBranch : r2853_5
|
||||
#-----| True -> Block 5
|
||||
|
||||
# 2856| Block 5
|
||||
# 2856| r2856_1(glval<int>) = VariableAddress[shadowed] :
|
||||
# 2856| r2856_2(glval<int>) = VariableAddress[x] :
|
||||
# 2856| r2856_3(int) = Load[x] : &:r2856_2, ~m?
|
||||
# 2856| mu2856_4(int) = Store[shadowed] : &:r2856_1, r2856_3
|
||||
# 2857| r2857_1(glval<int>) = VariableAddress[shadowed] :
|
||||
# 2857| r2857_2(int) = Load[shadowed] : &:r2857_1, ~m?
|
||||
# 2857| r2857_3(int) = Constant[0] :
|
||||
# 2857| r2857_4(bool) = CompareGT : r2857_2, r2857_3
|
||||
# 2857| v2857_5(void) = ConditionalBranch : r2857_4
|
||||
#-----| True -> Block 6
|
||||
|
||||
# 2859| Block 6
|
||||
# 2859| r2859_1(glval<int>) = VariableAddress[x] :
|
||||
# 2859| r2859_2(int) = Load[x] : &:r2859_1, ~m?
|
||||
# 2859| r2859_3(int) = Constant[0] :
|
||||
# 2859| r2859_4(bool) = CompareGT : r2859_2, r2859_3
|
||||
# 2859| v2859_5(void) = ConditionalBranch : r2859_4
|
||||
#-----| True -> Block 7
|
||||
|
||||
# 2860| Block 7
|
||||
# 2860| v2860_1(void) = NoOp :
|
||||
# 2846| v2846_10(void) = ReturnVoid :
|
||||
# 2846| v2846_11(void) = AliasedUse : ~m?
|
||||
# 2846| v2846_12(void) = ExitFunction :
|
||||
|
||||
# 2846| void test_assert_in_template<short>(short, int, unsigned int)
|
||||
# 2846| Block 0
|
||||
# 2846| v2846_1(void) = EnterFunction :
|
||||
# 2846| mu2846_2(unknown) = AliasedDefinition :
|
||||
# 2846| mu2846_3(unknown) = InitializeNonLocal :
|
||||
# 2846| r2846_4(glval<short>) = VariableAddress[x] :
|
||||
# 2846| mu2846_5(short) = InitializeParameter[x] : &:r2846_4
|
||||
# 2846| r2846_6(glval<int>) = VariableAddress[y] :
|
||||
# 2846| mu2846_7(int) = InitializeParameter[y] : &:r2846_6
|
||||
# 2846| r2846_8(glval<unsigned int>) = VariableAddress[u] :
|
||||
# 2846| mu2846_9(unsigned int) = InitializeParameter[u] : &:r2846_8
|
||||
# 2847| r2847_1(glval<short>) = VariableAddress[x] :
|
||||
# 2847| r2847_2(short) = Load[x] : &:r2847_1, ~m?
|
||||
# 2847| r2847_3(int) = Constant[0] :
|
||||
# 2847| r2847_4(bool) = CompareGT : r2847_2, r2847_3
|
||||
# 2847| v2847_5(void) = ConditionalBranch : r2847_4
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 2848| Block 1
|
||||
# 2848| r2848_1(int) = Constant[0] :
|
||||
# 2848| r2848_2(glval<short>) = VariableAddress[x] :
|
||||
# 2848| r2848_3(short) = Load[x] : &:r2848_2, ~m?
|
||||
# 2848| r2848_4(bool) = CompareLT : r2848_1, r2848_3
|
||||
# 2848| v2848_5(void) = ConditionalBranch : r2848_4
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 2849| Block 2
|
||||
# 2849| r2849_1(glval<short>) = VariableAddress[x] :
|
||||
# 2849| r2849_2(short) = Load[x] : &:r2849_1, ~m?
|
||||
# 2849| r2849_3(glval<int>) = VariableAddress[y] :
|
||||
# 2849| r2849_4(int) = Load[y] : &:r2849_3, ~m?
|
||||
# 2849| r2849_5(bool) = CompareLT : r2849_2, r2849_4
|
||||
# 2849| v2849_6(void) = ConditionalBranch : r2849_5
|
||||
#-----| True -> Block 3
|
||||
|
||||
# 2851| Block 3
|
||||
# 2851| r2851_1(glval<short>) = VariableAddress[x] :
|
||||
# 2851| r2851_2(short) = Load[x] : &:r2851_1, ~m?
|
||||
# 2851| r2851_3(int) = Constant[2] :
|
||||
# 2851| r2851_4(bool) = CompareNE : r2851_2, r2851_3
|
||||
# 2851| v2851_5(void) = ConditionalBranch : r2851_4
|
||||
#-----| True -> Block 4
|
||||
|
||||
# 2853| Block 4
|
||||
# 2853| r2853_1(glval<unsigned int>) = VariableAddress[u] :
|
||||
# 2853| r2853_2(unsigned int) = Load[u] : &:r2853_1, ~m?
|
||||
# 2853| r2853_3(glval<short>) = VariableAddress[x] :
|
||||
# 2853| r2853_4(short) = Load[x] : &:r2853_3, ~m?
|
||||
# 2853| r2853_5(bool) = CompareLT : r2853_2, r2853_4
|
||||
# 2853| v2853_6(void) = ConditionalBranch : r2853_5
|
||||
#-----| True -> Block 5
|
||||
|
||||
# 2856| Block 5
|
||||
# 2856| r2856_1(glval<int>) = VariableAddress[shadowed] :
|
||||
# 2856| r2856_2(glval<short>) = VariableAddress[x] :
|
||||
# 2856| r2856_3(short) = Load[x] : &:r2856_2, ~m?
|
||||
# 2856| r2856_4(int) = Convert : r2856_3
|
||||
# 2856| mu2856_5(int) = Store[shadowed] : &:r2856_1, r2856_4
|
||||
# 2857| r2857_1(glval<int>) = VariableAddress[shadowed] :
|
||||
# 2857| r2857_2(int) = Load[shadowed] : &:r2857_1, ~m?
|
||||
# 2857| r2857_3(int) = Constant[0] :
|
||||
# 2857| r2857_4(bool) = CompareGT : r2857_2, r2857_3
|
||||
# 2857| v2857_5(void) = ConditionalBranch : r2857_4
|
||||
#-----| True -> Block 6
|
||||
|
||||
# 2859| Block 6
|
||||
# 2859| r2859_1(glval<short>) = VariableAddress[x] :
|
||||
# 2859| r2859_2(short) = Load[x] : &:r2859_1, ~m?
|
||||
# 2859| r2859_3(int) = Constant[0] :
|
||||
# 2859| r2859_4(bool) = CompareGT : r2859_2, r2859_3
|
||||
# 2859| v2859_5(void) = ConditionalBranch : r2859_4
|
||||
#-----| True -> Block 7
|
||||
|
||||
# 2860| Block 7
|
||||
# 2860| v2860_1(void) = NoOp :
|
||||
# 2846| v2846_10(void) = ReturnVoid :
|
||||
# 2846| v2846_11(void) = AliasedUse : ~m?
|
||||
# 2846| v2846_12(void) = ExitFunction :
|
||||
|
||||
# 2867| void (unnamed namespace)::complex_assertions(int, bool, int)
|
||||
# 2867| Block 0
|
||||
# 2867| v2867_1(void) = EnterFunction :
|
||||
# 2867| mu2867_2(unknown) = AliasedDefinition :
|
||||
# 2867| mu2867_3(unknown) = InitializeNonLocal :
|
||||
# 2867| r2867_4(glval<int>) = VariableAddress[x] :
|
||||
# 2867| mu2867_5(int) = InitializeParameter[x] : &:r2867_4
|
||||
# 2867| r2867_6(glval<bool>) = VariableAddress[b] :
|
||||
# 2867| mu2867_7(bool) = InitializeParameter[b] : &:r2867_6
|
||||
# 2867| r2867_8(glval<int>) = VariableAddress[max] :
|
||||
# 2867| mu2867_9(int) = InitializeParameter[max] : &:r2867_8
|
||||
# 2868| r2868_1(glval<int>) = VariableAddress[y] :
|
||||
# 2868| r2868_2(int) = Constant[0] :
|
||||
# 2868| v2868_3(void) = Convert : r2868_2
|
||||
# 2868| r2868_4(glval<int>) = VariableAddress[x] :
|
||||
# 2868| r2868_5(int) = Load[x] : &:r2868_4, ~m?
|
||||
# 2868| r2868_6(int) = CopyValue : r2868_5
|
||||
# 2868| mu2868_7(int) = Store[y] : &:r2868_1, r2868_6
|
||||
# 2869| r2869_1(glval<int>) = VariableAddress[z] :
|
||||
# 2869| r2869_2(glval<bool>) = VariableAddress[b] :
|
||||
# 2869| r2869_3(bool) = Load[b] : &:r2869_2, ~m?
|
||||
# 2869| v2869_4(void) = ConditionalBranch : r2869_3
|
||||
#-----| False -> Block 5
|
||||
#-----| True -> Block 4
|
||||
|
||||
# 2867| Block 1
|
||||
# 2867| v2867_10(void) = AliasedUse : ~m?
|
||||
# 2867| v2867_11(void) = ExitFunction :
|
||||
|
||||
# 2867| Block 2
|
||||
# 2867| v2867_12(void) = Unwind :
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 2869| Block 3
|
||||
# 2869| r2869_5(glval<int>) = VariableAddress[#temp2869:17] :
|
||||
# 2869| r2869_6(int) = Load[#temp2869:17] : &:r2869_5, ~m?
|
||||
# 2869| mu2869_7(int) = Store[z] : &:r2869_1, r2869_6
|
||||
# 2872| r2872_1(glval<int>) = VariableAddress[#throw2872:13] :
|
||||
# 2872| r2872_2(int) = Constant[41] :
|
||||
# 2872| mu2872_3(int) = Store[#throw2872:13] : &:r2872_1, r2872_2
|
||||
# 2872| v2872_4(void) = ThrowValue : &:r2872_1, ~m?
|
||||
#-----| C++ Exception -> Block 6
|
||||
|
||||
# 2869| Block 4
|
||||
# 2869| r2869_8(int) = Constant[0] :
|
||||
# 2869| r2869_9(glval<int>) = VariableAddress[#temp2869:17] :
|
||||
# 2869| mu2869_10(int) = Store[#temp2869:17] : &:r2869_9, r2869_8
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 2869| Block 5
|
||||
# 2869| r2869_11(int) = Constant[1] :
|
||||
# 2869| r2869_12(glval<int>) = VariableAddress[#temp2869:17] :
|
||||
# 2869| mu2869_13(int) = Store[#temp2869:17] : &:r2869_12, r2869_11
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 2873| Block 6
|
||||
# 2873| v2873_1(void) = CatchByType[int] :
|
||||
#-----| C++ Exception -> Block 2
|
||||
#-----| Goto -> Block 7
|
||||
|
||||
# 2873| Block 7
|
||||
# 2873| r2873_2(glval<int>) = VariableAddress[c] :
|
||||
# 2873| mu2873_3(int) = InitializeParameter[c] : &:r2873_2
|
||||
# 2874| r2874_1(glval<int>) = VariableAddress[c] :
|
||||
# 2874| r2874_2(int) = Load[c] : &:r2874_1, ~m?
|
||||
# 2874| r2874_3(int) = Constant[42] :
|
||||
# 2874| r2874_4(bool) = CompareLT : r2874_2, r2874_3
|
||||
# 2874| v2874_5(void) = ConditionalBranch : r2874_4
|
||||
#-----| True -> Block 8
|
||||
|
||||
# 2875| Block 8
|
||||
# 2875| r2875_1(int) = Constant[0] :
|
||||
# 2875| v2875_2(void) = Convert : r2875_1
|
||||
# 2878| r2878_1(int) = Constant[0] :
|
||||
# 2878| v2878_2(void) = Convert : r2878_1
|
||||
# 2879| r2879_1(glval<int>) = VariableAddress[shadowed] :
|
||||
# 2879| mu2879_2(int) = Uninitialized[shadowed] : &:r2879_1
|
||||
# 2882| r2882_1(glval<int>) = VariableAddress[#throw2882:13] :
|
||||
# 2882| r2882_2(int) = Constant[41] :
|
||||
# 2882| mu2882_3(int) = Store[#throw2882:13] : &:r2882_1, r2882_2
|
||||
# 2882| v2882_4(void) = ThrowValue : &:r2882_1, ~m?
|
||||
#-----| C++ Exception -> Block 9
|
||||
|
||||
# 2883| Block 9
|
||||
# 2883| v2883_1(void) = CatchByType[int] :
|
||||
#-----| C++ Exception -> Block 2
|
||||
#-----| Goto -> Block 10
|
||||
|
||||
# 2883| Block 10
|
||||
# 2883| r2883_2(glval<int>) = VariableAddress[shadowed] :
|
||||
# 2883| mu2883_3(int) = InitializeParameter[shadowed] : &:r2883_2
|
||||
# 2884| r2884_1(int) = Constant[0] :
|
||||
# 2884| v2884_2(void) = Convert : r2884_1
|
||||
# 2886| v2886_1(void) = NoOp :
|
||||
# 2867| v2867_13(void) = ReturnVoid :
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
ir23.cpp:
|
||||
# 1| bool consteval_1()
|
||||
# 1| Block 0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.7.57
|
||||
version: 1.7.58-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.7.57
|
||||
version: 1.7.58-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* C# 14: Support for null-conditional assignments (such as `c?.Prop = p`). Furthermore, the `MaybeNullExpr` class now takes null-conditional access (such as `?.`) into account when modeling potential null values.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The predicate `SummarizedCallable.propagatesFlow` has been extended with the columns `Provenance p` and `boolean isExact`, and as a consequence the predicates `SummarizedCallable.hasProvenance` and `SummarizedCallable.hasExactModel` have been removed.
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-all
|
||||
version: 5.4.5
|
||||
version: 5.4.6-dev
|
||||
groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
|
||||
@@ -429,7 +429,7 @@ module Expressions {
|
||||
not this instanceof ObjectCreation and
|
||||
not this instanceof ArrayCreation and
|
||||
not this instanceof QualifiedWriteAccess and
|
||||
not this instanceof AccessorWrite and
|
||||
not this instanceof QualifiedAccessorWrite and
|
||||
not this instanceof NoNodeExpr and
|
||||
not this instanceof SwitchExpr and
|
||||
not this instanceof SwitchCaseExpr and
|
||||
@@ -446,21 +446,29 @@ module Expressions {
|
||||
}
|
||||
|
||||
/**
|
||||
* A qualified write access. In a qualified write access, the access itself is
|
||||
* not evaluated, only the qualifier and the indexer arguments (if any).
|
||||
* A qualified write access.
|
||||
*
|
||||
* The successor declaration in `QualifiedAccessorWrite` ensures that the access itself
|
||||
* is evaluated after the qualifier and the indexer arguments (if any)
|
||||
* and the right hand side of the assignment.
|
||||
*
|
||||
* When a qualified write access is used as an `out/ref` argument, the access itself is evaluated immediately.
|
||||
*/
|
||||
private class QualifiedWriteAccess extends ControlFlowTree instanceof WriteAccess, QualifiableExpr
|
||||
{
|
||||
QualifiedWriteAccess() {
|
||||
this.hasQualifier()
|
||||
or
|
||||
// Member initializers like
|
||||
// ```csharp
|
||||
// new Dictionary<int, string>() { [0] = "Zero", [1] = "One", [2] = "Two" }
|
||||
// ```
|
||||
// need special treatment, because the accesses `[0]`, `[1]`, and `[2]`
|
||||
// have no qualifier.
|
||||
this = any(MemberInitializer mi).getLValue()
|
||||
(
|
||||
this.hasQualifier()
|
||||
or
|
||||
// Member initializers like
|
||||
// ```csharp
|
||||
// new Dictionary<int, string>() { [0] = "Zero", [1] = "One", [2] = "Two" }
|
||||
// ```
|
||||
// need special treatment, because the accesses `[0]`, `[1]`, and `[2]`
|
||||
// have no qualifier.
|
||||
this = any(MemberInitializer mi).getLValue()
|
||||
) and
|
||||
not exists(AssignableDefinitions::OutRefDefinition def | def.getTargetAccess() = this)
|
||||
}
|
||||
|
||||
final override predicate propagatesAbnormal(AstNode child) { child = getExprChild(this, _) }
|
||||
@@ -470,25 +478,25 @@ module Expressions {
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
// Skip the access in a qualified write access
|
||||
last(getLastExprChild(this), last, c)
|
||||
or
|
||||
// Qualifier exits with a null completion
|
||||
super.isConditional() and
|
||||
last(super.getQualifier(), last, c) and
|
||||
c.(NullnessCompletion).isNull()
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
exists(int i |
|
||||
last(getExprChild(this, i), pred, c) and
|
||||
c instanceof NormalCompletion and
|
||||
(if i = 0 then not c.(NullnessCompletion).isNull() else any()) and
|
||||
first(getExprChild(this, i + 1), succ)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class StatOrDynAccessorCall_ =
|
||||
@dynamic_member_access_expr or @dynamic_element_access_expr or @call_access_expr;
|
||||
|
||||
/** A normal or a (potential) dynamic call to an accessor. */
|
||||
private class StatOrDynAccessorCall extends Expr, StatOrDynAccessorCall_ { }
|
||||
|
||||
/**
|
||||
* An expression that writes via an accessor call, for example `x.Prop = 0`,
|
||||
* An expression that writes via a qualifiable expression, for example `x.Prop = 0`,
|
||||
* where `Prop` is a property.
|
||||
*
|
||||
* Accessor writes need special attention, because we need to model the fact
|
||||
@@ -498,13 +506,21 @@ module Expressions {
|
||||
* ```csharp
|
||||
* x -> 0 -> set_Prop -> x.Prop = 0
|
||||
* ```
|
||||
*
|
||||
* For consistency, control flow is implemented the same way for other qualified writes.
|
||||
* For example, `x.Field = 0`, where `Field` is a field, we want a CFG that looks like
|
||||
*
|
||||
* ```csharp
|
||||
* x -> 0 -> x.Field -> x.Field = 0
|
||||
* ```
|
||||
*/
|
||||
class AccessorWrite extends PostOrderTree instanceof Expr {
|
||||
private class QualifiedAccessorWrite extends PostOrderTree instanceof Expr {
|
||||
AssignableDefinition def;
|
||||
|
||||
AccessorWrite() {
|
||||
QualifiedAccessorWrite() {
|
||||
def.getExpr() = this and
|
||||
def.getTargetAccess().(WriteAccess) instanceof StatOrDynAccessorCall and
|
||||
def.getTargetAccess().(WriteAccess) instanceof QualifiableExpr and
|
||||
not def instanceof AssignableDefinitions::OutRefDefinition and
|
||||
not this instanceof AssignOperationWithExpandedAssignment
|
||||
}
|
||||
|
||||
@@ -512,10 +528,11 @@ module Expressions {
|
||||
* Gets the `i`th accessor being called in this write. More than one call
|
||||
* can happen in tuple assignments.
|
||||
*/
|
||||
StatOrDynAccessorCall getCall(int i) {
|
||||
QualifiableExpr getAccess(int i) {
|
||||
result =
|
||||
rank[i + 1](AssignableDefinitions::TupleAssignmentDefinition tdef |
|
||||
tdef.getExpr() = this and tdef.getTargetAccess() instanceof StatOrDynAccessorCall
|
||||
tdef.getExpr() = this and
|
||||
tdef.getTargetAccess() instanceof QualifiableExpr
|
||||
|
|
||||
tdef order by tdef.getEvaluationOrder()
|
||||
).getTargetAccess()
|
||||
@@ -528,7 +545,13 @@ module Expressions {
|
||||
final override predicate propagatesAbnormal(AstNode child) {
|
||||
child = getExprChild(this, _)
|
||||
or
|
||||
child = this.getCall(_)
|
||||
child = this.getAccess(_)
|
||||
}
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
PostOrderTree.super.last(last, c)
|
||||
or
|
||||
last(getExprChild(this, 0), last, c) and c.(NullnessCompletion).isNull()
|
||||
}
|
||||
|
||||
final override predicate first(AstNode first) { first(getExprChild(this, 0), first) }
|
||||
@@ -538,24 +561,25 @@ module Expressions {
|
||||
exists(int i |
|
||||
last(getExprChild(this, i), pred, c) and
|
||||
c instanceof NormalCompletion and
|
||||
(if i = 0 then not c.(NullnessCompletion).isNull() else any()) and
|
||||
first(getExprChild(this, i + 1), succ)
|
||||
)
|
||||
or
|
||||
// Flow from last element of last child to first accessor call
|
||||
last(getLastExprChild(this), pred, c) and
|
||||
succ = this.getCall(0) and
|
||||
succ = this.getAccess(0) and
|
||||
c instanceof NormalCompletion
|
||||
or
|
||||
// Flow from one call to the next
|
||||
exists(int i | pred = this.getCall(i) |
|
||||
succ = this.getCall(i + 1) and
|
||||
exists(int i | pred = this.getAccess(i) |
|
||||
succ = this.getAccess(i + 1) and
|
||||
c.isValidFor(pred) and
|
||||
c instanceof NormalCompletion
|
||||
)
|
||||
or
|
||||
// Post-order: flow from last call to element itself
|
||||
exists(int last | last = max(int i | exists(this.getCall(i))) |
|
||||
pred = this.getCall(last) and
|
||||
exists(int last | last = max(int i | exists(this.getAccess(i))) |
|
||||
pred = this.getAccess(last) and
|
||||
succ = this and
|
||||
c.isValidFor(pred) and
|
||||
c instanceof NormalCompletion
|
||||
@@ -704,7 +728,9 @@ module Expressions {
|
||||
private class ConditionallyQualifiedExpr extends PostOrderTree instanceof QualifiableExpr {
|
||||
private Expr qualifier;
|
||||
|
||||
ConditionallyQualifiedExpr() { this.isConditional() and qualifier = getExprChild(this, 0) }
|
||||
ConditionallyQualifiedExpr() {
|
||||
this.isConditional() and qualifier = getExprChild(this, 0) and not this instanceof WriteAccess
|
||||
}
|
||||
|
||||
final override predicate propagatesAbnormal(AstNode child) { child = qualifier }
|
||||
|
||||
|
||||
@@ -18,6 +18,11 @@ deprecated module SummaryComponentStack = Impl::Private::SummaryComponentStack;
|
||||
|
||||
deprecated class RequiredSummaryComponentStack = Impl::Private::RequiredSummaryComponentStack;
|
||||
|
||||
class SummarizedCallable = Impl::Public::SummarizedCallable;
|
||||
/** Provides the `Range` class used to define the extent of `SummarizedCallable`. */
|
||||
module SummarizedCallable {
|
||||
class Range = Impl::Public::SummarizedCallable;
|
||||
}
|
||||
|
||||
class SummarizedCallable = Impl::Public::RelevantSummarizedCallable;
|
||||
|
||||
class Provenance = Impl::Public::Provenance;
|
||||
|
||||
@@ -43,6 +43,13 @@ private Expr maybeNullExpr(Expr reason) {
|
||||
)
|
||||
or
|
||||
result.(NullCoalescingExpr).getRightOperand() = maybeNullExpr(reason)
|
||||
or
|
||||
result =
|
||||
any(QualifiableExpr qe |
|
||||
qe.isConditional() and
|
||||
reason = qe.getQualifier() and
|
||||
not qe instanceof AssignableWrite
|
||||
)
|
||||
}
|
||||
|
||||
/** An expression that may be `null`. */
|
||||
|
||||
@@ -380,10 +380,7 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
|
||||
// we are not able to dispatch to a source declaration.
|
||||
exists(boolean static |
|
||||
result = this.getATarget(static) and
|
||||
not (
|
||||
result.applyGeneratedModel() and
|
||||
this.hasSourceTarget()
|
||||
)
|
||||
if this.hasSourceTarget() then result.hasManualModel() else any()
|
||||
|
|
||||
static = false
|
||||
or
|
||||
|
||||
@@ -848,7 +848,7 @@ private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, b
|
||||
FlowSummaryImpl::Private::SummarizedCallableImpl sc,
|
||||
FlowSummaryImpl::Private::SummaryComponentStack input, ContentSet readSet
|
||||
|
|
||||
sc.propagatesFlow(input, _, _, _) and
|
||||
sc.propagatesFlow(input, _, _, _, _, _) and
|
||||
input.contains(FlowSummaryImpl::Private::SummaryComponent::content(readSet)) and
|
||||
c.getAStoreContent() = readSet.getAReadContent()
|
||||
)
|
||||
@@ -1021,7 +1021,6 @@ private class InstanceCallable extends Callable {
|
||||
private Location l;
|
||||
|
||||
InstanceCallable() {
|
||||
this = any(DataFlowCallable dfc).asCallable(l) and
|
||||
not this.(Modifiable).isStatic() and
|
||||
// local functions and delegate capture `this` and should therefore
|
||||
// not have a `this` parameter
|
||||
@@ -1119,6 +1118,7 @@ private module Cached {
|
||||
p = c.asCallable(_).(CallableUsedInSource).getAParameter()
|
||||
} or
|
||||
TInstanceParameterNode(InstanceCallable c, Location l) {
|
||||
c = any(DataFlowCallable dfc).asCallable(l) and
|
||||
c instanceof CallableUsedInSource and
|
||||
l = c.getARelevantLocation()
|
||||
} or
|
||||
|
||||
@@ -380,20 +380,23 @@ private Declaration interpretExt(Declaration d, ExtPath ext) {
|
||||
/** Gets the source/sink/summary/neutral element corresponding to the supplied parameters. */
|
||||
pragma[nomagic]
|
||||
Declaration interpretElement(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
boolean isExact
|
||||
) {
|
||||
elementSpec(namespace, type, subtypes, name, signature, ext) and
|
||||
exists(Declaration base, Declaration d |
|
||||
base = interpretBaseDeclaration(namespace, type, name, signature) and
|
||||
(
|
||||
d = base
|
||||
d = base and
|
||||
isExact = true
|
||||
or
|
||||
subtypes = true and
|
||||
(
|
||||
d.(UnboundCallable).overridesOrImplementsUnbound(base)
|
||||
or
|
||||
d = base.(UnboundValueOrRefType).getASubTypeUnbound+()
|
||||
)
|
||||
) and
|
||||
isExact = false
|
||||
)
|
||||
|
|
||||
result = interpretExt(d, ext)
|
||||
@@ -586,71 +589,47 @@ string getSignature(UnboundCallable c) {
|
||||
}
|
||||
|
||||
private predicate interpretSummary(
|
||||
UnboundCallable c, string input, string output, string kind, string provenance, string model
|
||||
UnboundCallable c, string input, string output, string kind, string provenance, boolean isExact,
|
||||
string model
|
||||
) {
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance,
|
||||
model) and
|
||||
c = interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
c = interpretElement(namespace, type, subtypes, name, signature, ext, isExact)
|
||||
)
|
||||
}
|
||||
|
||||
predicate interpretNeutral(UnboundCallable c, string kind, string provenance) {
|
||||
predicate interpretNeutral(UnboundCallable c, string kind, string provenance, boolean isExact) {
|
||||
exists(string namespace, string type, string name, string signature |
|
||||
Extensions::neutralModel(namespace, type, name, signature, kind, provenance) and
|
||||
c = interpretElement(namespace, type, true, name, signature, "")
|
||||
c = interpretElement(namespace, type, true, name, signature, "", isExact)
|
||||
)
|
||||
}
|
||||
|
||||
// adapter class for converting Mad summaries to `SummarizedCallable`s
|
||||
private class SummarizedCallableAdapter extends SummarizedCallable {
|
||||
string input_;
|
||||
string output_;
|
||||
string kind;
|
||||
Provenance p_;
|
||||
boolean isExact_;
|
||||
string model_;
|
||||
|
||||
SummarizedCallableAdapter() {
|
||||
exists(Provenance provenance | interpretSummary(this, _, _, _, provenance, _) |
|
||||
not this.fromSource()
|
||||
or
|
||||
this.fromSource() and provenance.isManual()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate relevantSummaryElementManual(
|
||||
string input, string output, string kind, string model
|
||||
) {
|
||||
exists(Provenance provenance |
|
||||
interpretSummary(this, input, output, kind, provenance, model) and
|
||||
provenance.isManual()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate relevantSummaryElementGenerated(
|
||||
string input, string output, string kind, string model
|
||||
) {
|
||||
exists(Provenance provenance |
|
||||
interpretSummary(this, input, output, kind, provenance, model) and
|
||||
provenance.isGenerated()
|
||||
) and
|
||||
not exists(Provenance provenance |
|
||||
interpretNeutral(this, "summary", provenance) and
|
||||
provenance.isManual()
|
||||
)
|
||||
interpretSummary(this, input_, output_, kind, p_, isExact_, model_)
|
||||
}
|
||||
|
||||
override predicate propagatesFlow(
|
||||
string input, string output, boolean preservesValue, string model
|
||||
string input, string output, boolean preservesValue, Provenance p, boolean isExact, string model
|
||||
) {
|
||||
exists(string kind |
|
||||
this.relevantSummaryElementManual(input, output, kind, model)
|
||||
or
|
||||
not this.relevantSummaryElementManual(_, _, _, _) and
|
||||
this.relevantSummaryElementGenerated(input, output, kind, model)
|
||||
|
|
||||
if kind = "value" then preservesValue = true else preservesValue = false
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasProvenance(Provenance provenance) {
|
||||
interpretSummary(this, _, _, _, provenance, _)
|
||||
input = input_ and
|
||||
output = output_ and
|
||||
(if kind = "value" then preservesValue = true else preservesValue = false) and
|
||||
p = p_ and
|
||||
isExact = isExact_ and
|
||||
model = model_
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,14 +18,24 @@ module Input implements InputSig<Location, DataFlowImplSpecific::CsharpDataFlow>
|
||||
|
||||
class SummarizedCallableBase = UnboundCallable;
|
||||
|
||||
predicate callableFromSource(SummarizedCallableBase c) {
|
||||
c.fromSource() and
|
||||
not c.getFile().isStub() and
|
||||
not (
|
||||
c.getFile().extractedQlTest() and
|
||||
(
|
||||
c.getBody() instanceof ThrowElement or
|
||||
c.getBody().(BlockStmt).getStmt(0) instanceof ThrowElement
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class SourceBase = Void;
|
||||
|
||||
class SinkBase = Void;
|
||||
|
||||
predicate neutralElement(SummarizedCallableBase c, string kind, string provenance, boolean isExact) {
|
||||
interpretNeutral(c, kind, provenance) and
|
||||
// isExact is not needed for C#.
|
||||
isExact = false
|
||||
interpretNeutral(c, kind, provenance, isExact)
|
||||
}
|
||||
|
||||
ArgumentPosition callbackSelfParameterPosition() { result.isDelegateSelf() }
|
||||
@@ -216,7 +226,7 @@ module SourceSinkInterpretationInput implements
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance, model) and
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -227,7 +237,7 @@ module SourceSinkInterpretationInput implements
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance, model) and
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -238,7 +248,7 @@ module SourceSinkInterpretationInput implements
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
barrierModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance, model) and
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -251,7 +261,7 @@ module SourceSinkInterpretationInput implements
|
||||
|
|
||||
barrierGuardModel(namespace, type, subtypes, name, signature, ext, input, acceptingvalue,
|
||||
kind, provenance, model) and
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -448,13 +458,14 @@ private class SummarizedCallableWithCallback extends Public::SummarizedCallable
|
||||
SummarizedCallableWithCallback() { mayInvokeCallback(this, pos) }
|
||||
|
||||
override predicate propagatesFlow(
|
||||
string input, string output, boolean preservesValue, string model
|
||||
string input, string output, boolean preservesValue, Public::Provenance provenance,
|
||||
boolean isExact, string model
|
||||
) {
|
||||
input = "Argument[" + pos + "]" and
|
||||
output = "Argument[" + pos + "].Parameter[delegate-self]" and
|
||||
preservesValue = true and
|
||||
provenance = "hq-generated" and
|
||||
isExact = true and
|
||||
model = "heuristic-callback"
|
||||
}
|
||||
|
||||
override predicate hasProvenance(Public::Provenance provenance) { provenance = "hq-generated" }
|
||||
}
|
||||
|
||||
@@ -92,22 +92,17 @@ module EntityFramework {
|
||||
abstract class EFSummarizedCallable extends SummarizedCallableImpl {
|
||||
bindingset[this]
|
||||
EFSummarizedCallable() { any() }
|
||||
|
||||
override predicate hasProvenance(Provenance provenance) { provenance = "manual" }
|
||||
}
|
||||
|
||||
// see `SummarizedCallableImpl` qldoc
|
||||
private class EFSummarizedCallableAdapter extends SummarizedCallable instanceof EFSummarizedCallable
|
||||
{
|
||||
override predicate propagatesFlow(
|
||||
string input, string output, boolean preservesValue, string model
|
||||
string input, string output, boolean preservesValue, Provenance provenance, boolean isExact,
|
||||
string model
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasProvenance(Provenance provenance) {
|
||||
EFSummarizedCallable.super.hasProvenance(provenance)
|
||||
}
|
||||
}
|
||||
|
||||
/** The class ``Microsoft.EntityFrameworkCore.DbQuery`1`` or ``System.Data.Entity.DbQuery`1``. */
|
||||
@@ -177,11 +172,13 @@ module EntityFramework {
|
||||
|
||||
override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue,
|
||||
string model
|
||||
Provenance p, boolean isExact, string model
|
||||
) {
|
||||
input = SummaryComponentStack::argument(0) and
|
||||
output = SummaryComponentStack::return() and
|
||||
preservesValue = false and
|
||||
p = "manual" and
|
||||
isExact = true and
|
||||
model = "RawSqlStringConstructorSummarizedCallable"
|
||||
}
|
||||
}
|
||||
@@ -193,11 +190,13 @@ module EntityFramework {
|
||||
|
||||
override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue,
|
||||
string model
|
||||
Provenance p, boolean isExact, string model
|
||||
) {
|
||||
input = SummaryComponentStack::argument(0) and
|
||||
output = SummaryComponentStack::return() and
|
||||
preservesValue = false and
|
||||
p = "manual" and
|
||||
isExact = true and
|
||||
model = "RawSqlStringConversionSummarizedCallable"
|
||||
}
|
||||
}
|
||||
@@ -459,18 +458,20 @@ module EntityFramework {
|
||||
}
|
||||
|
||||
private class DbContextClassSetPropertySynthetic extends EFSummarizedCallable {
|
||||
private DbContextClassSetProperty p;
|
||||
private DbContextClassSetProperty prop;
|
||||
|
||||
DbContextClassSetPropertySynthetic() { this = p.getGetter() }
|
||||
DbContextClassSetPropertySynthetic() { this = prop.getGetter() }
|
||||
|
||||
override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue,
|
||||
string model
|
||||
Provenance p, boolean isExact, string model
|
||||
) {
|
||||
exists(string name, DbContextClass c |
|
||||
preservesValue = true and
|
||||
name = c.getSyntheticName(output, _, p) and
|
||||
name = c.getSyntheticName(output, _, prop) and
|
||||
input = SummaryComponentStack::syntheticGlobal(name) and
|
||||
p = "manual" and
|
||||
isExact = true and
|
||||
model = "DbContextClassSetPropertySynthetic"
|
||||
)
|
||||
}
|
||||
@@ -483,13 +484,15 @@ module EntityFramework {
|
||||
|
||||
override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue,
|
||||
string model
|
||||
Provenance p, boolean isExact, string model
|
||||
) {
|
||||
exists(string name, Property mapped |
|
||||
preservesValue = true and
|
||||
c.input(input, mapped) and
|
||||
name = c.getSyntheticNameProj(mapped) and
|
||||
output = SummaryComponentStack::syntheticGlobal(name) and
|
||||
p = "manual" and
|
||||
isExact = true and
|
||||
model = "DbContextSaveChanges"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-queries
|
||||
version: 1.6.0
|
||||
version: 1.6.1-dev
|
||||
groups:
|
||||
- csharp
|
||||
- queries
|
||||
|
||||
@@ -230,7 +230,7 @@ module SummaryModelGeneratorInput implements SummaryModelGeneratorInputSig {
|
||||
}
|
||||
|
||||
private predicate hasManualSummaryModel(Callable api) {
|
||||
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()) or
|
||||
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.hasManualModel()) or
|
||||
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel())
|
||||
}
|
||||
|
||||
|
||||
@@ -21,4 +21,26 @@ class Assignments
|
||||
|
||||
delegate void EventHandler(object sender, object e);
|
||||
event EventHandler Event;
|
||||
int IntField;
|
||||
string StringField;
|
||||
|
||||
void SetParamSingle(out int x)
|
||||
{
|
||||
x = 42;
|
||||
}
|
||||
|
||||
void SetParamMulti(out int x, object o, out string y)
|
||||
{
|
||||
x = 42;
|
||||
y = "Hello";
|
||||
}
|
||||
|
||||
void M2()
|
||||
{
|
||||
int x1;
|
||||
SetParamSingle(out x1);
|
||||
SetParamSingle(out IntField);
|
||||
SetParamMulti(out var y, null, out StringField);
|
||||
SetParamMulti(out IntField, null, out StringField);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
| AccessorCalls.cs:5:33:5:35 | enter set_Item | AccessorCalls.cs:5:33:5:35 | exit set_Item | 4 |
|
||||
| AccessorCalls.cs:7:32:7:34 | enter add_Event | AccessorCalls.cs:7:32:7:34 | exit add_Event | 4 |
|
||||
| AccessorCalls.cs:7:40:7:45 | enter remove_Event | AccessorCalls.cs:7:40:7:45 | exit remove_Event | 4 |
|
||||
| AccessorCalls.cs:10:10:10:11 | enter M1 | AccessorCalls.cs:10:10:10:11 | exit M1 | 33 |
|
||||
| AccessorCalls.cs:19:10:19:11 | enter M2 | AccessorCalls.cs:19:10:19:11 | exit M2 | 41 |
|
||||
| AccessorCalls.cs:10:10:10:11 | enter M1 | AccessorCalls.cs:10:10:10:11 | exit M1 | 34 |
|
||||
| AccessorCalls.cs:19:10:19:11 | enter M2 | AccessorCalls.cs:19:10:19:11 | exit M2 | 42 |
|
||||
| AccessorCalls.cs:28:10:28:11 | enter M3 | AccessorCalls.cs:28:10:28:11 | exit M3 | 17 |
|
||||
| AccessorCalls.cs:35:10:35:11 | enter M4 | AccessorCalls.cs:35:10:35:11 | exit M4 | 20 |
|
||||
| AccessorCalls.cs:42:10:42:11 | enter M5 | AccessorCalls.cs:42:10:42:11 | exit M5 | 33 |
|
||||
| AccessorCalls.cs:49:10:49:11 | enter M6 | AccessorCalls.cs:49:10:49:11 | exit M6 | 42 |
|
||||
| AccessorCalls.cs:56:10:56:11 | enter M7 | AccessorCalls.cs:56:10:56:11 | exit M7 | 24 |
|
||||
| AccessorCalls.cs:61:10:61:11 | enter M8 | AccessorCalls.cs:61:10:61:11 | exit M8 | 30 |
|
||||
| AccessorCalls.cs:42:10:42:11 | enter M5 | AccessorCalls.cs:42:10:42:11 | exit M5 | 34 |
|
||||
| AccessorCalls.cs:49:10:49:11 | enter M6 | AccessorCalls.cs:49:10:49:11 | exit M6 | 43 |
|
||||
| AccessorCalls.cs:56:10:56:11 | enter M7 | AccessorCalls.cs:56:10:56:11 | exit M7 | 25 |
|
||||
| AccessorCalls.cs:61:10:61:11 | enter M8 | AccessorCalls.cs:61:10:61:11 | exit M8 | 31 |
|
||||
| AccessorCalls.cs:66:10:66:11 | enter M9 | AccessorCalls.cs:66:10:66:11 | exit M9 | 58 |
|
||||
| ArrayCreation.cs:1:7:1:19 | enter ArrayCreation | ArrayCreation.cs:1:7:1:19 | exit ArrayCreation | 7 |
|
||||
| ArrayCreation.cs:3:11:3:12 | enter M1 | ArrayCreation.cs:3:11:3:12 | exit M1 | 5 |
|
||||
@@ -167,6 +167,9 @@
|
||||
| Assignments.cs:3:10:3:10 | enter M | Assignments.cs:3:10:3:10 | exit M | 34 |
|
||||
| Assignments.cs:14:18:14:35 | enter (...) => ... | Assignments.cs:14:18:14:35 | exit (...) => ... | 4 |
|
||||
| Assignments.cs:17:40:17:40 | enter + | Assignments.cs:17:40:17:40 | exit + | 6 |
|
||||
| Assignments.cs:27:10:27:23 | enter SetParamSingle | Assignments.cs:27:10:27:23 | exit SetParamSingle | 7 |
|
||||
| Assignments.cs:32:10:32:22 | enter SetParamMulti | Assignments.cs:32:10:32:22 | exit SetParamMulti | 10 |
|
||||
| Assignments.cs:38:10:38:11 | enter M2 | Assignments.cs:38:10:38:11 | exit M2 | 28 |
|
||||
| BreakInTry.cs:1:7:1:16 | enter BreakInTry | BreakInTry.cs:1:7:1:16 | exit BreakInTry | 7 |
|
||||
| BreakInTry.cs:3:10:3:11 | enter M1 | BreakInTry.cs:7:33:7:36 | access to parameter args | 5 |
|
||||
| BreakInTry.cs:3:10:3:11 | exit M1 (normal) | BreakInTry.cs:3:10:3:11 | exit M1 | 2 |
|
||||
@@ -244,7 +247,30 @@
|
||||
| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:35:9:35:12 | access to property Prop | 8 |
|
||||
| ConditionalAccess.cs:32:10:32:11 | exit M8 (normal) | ConditionalAccess.cs:32:10:32:11 | exit M8 | 2 |
|
||||
| ConditionalAccess.cs:35:9:35:24 | call to method Out | ConditionalAccess.cs:35:9:35:24 | call to method Out | 1 |
|
||||
| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | 8 |
|
||||
| ConditionalAccess.cs:42:9:42:11 | enter get_Item | ConditionalAccess.cs:42:9:42:11 | exit get_Item | 6 |
|
||||
| ConditionalAccess.cs:43:9:43:11 | enter set_Item | ConditionalAccess.cs:43:9:43:11 | exit set_Item | 4 |
|
||||
| ConditionalAccess.cs:46:10:46:11 | enter M9 | ConditionalAccess.cs:48:9:48:10 | access to parameter ca | 4 |
|
||||
| ConditionalAccess.cs:46:10:46:11 | exit M9 (normal) | ConditionalAccess.cs:46:10:46:11 | exit M9 | 2 |
|
||||
| ConditionalAccess.cs:48:24:48:25 | 42 | ConditionalAccess.cs:48:12:48:25 | ... = ... | 3 |
|
||||
| ConditionalAccess.cs:49:9:49:33 | ...; | ConditionalAccess.cs:49:9:49:10 | access to parameter ca | 2 |
|
||||
| ConditionalAccess.cs:49:26:49:32 | "Hello" | ConditionalAccess.cs:49:12:49:32 | ... = ... | 3 |
|
||||
| ConditionalAccess.cs:50:9:50:24 | ...; | ConditionalAccess.cs:50:9:50:10 | access to parameter ca | 2 |
|
||||
| ConditionalAccess.cs:50:13:50:13 | 0 | ConditionalAccess.cs:50:12:50:23 | ... = ... | 4 |
|
||||
| ConditionalAccess.cs:51:9:51:16 | access to property Prop | ConditionalAccess.cs:51:9:51:16 | access to property Prop | 1 |
|
||||
| ConditionalAccess.cs:51:9:51:32 | ...; | ConditionalAccess.cs:51:9:51:10 | access to parameter ca | 2 |
|
||||
| ConditionalAccess.cs:51:30:51:31 | 84 | ConditionalAccess.cs:51:18:51:31 | ... = ... | 3 |
|
||||
| ConditionalAccess.cs:52:9:52:16 | access to property Prop | ConditionalAccess.cs:52:9:52:16 | access to property Prop | 1 |
|
||||
| ConditionalAccess.cs:52:9:52:39 | ...; | ConditionalAccess.cs:52:9:52:10 | access to parameter ca | 2 |
|
||||
| ConditionalAccess.cs:52:32:52:38 | "World" | ConditionalAccess.cs:52:18:52:38 | ... = ... | 3 |
|
||||
| ConditionalAccess.cs:53:9:53:10 | access to parameter ca | ConditionalAccess.cs:53:9:53:10 | access to parameter ca | 1 |
|
||||
| ConditionalAccess.cs:53:9:53:20 | access to field IntField | ConditionalAccess.cs:53:9:53:20 | access to field IntField | 1 |
|
||||
| ConditionalAccess.cs:53:9:53:26 | ...; | ConditionalAccess.cs:53:9:53:10 | access to parameter ca | 2 |
|
||||
| ConditionalAccess.cs:53:25:53:25 | 1 | ConditionalAccess.cs:53:12:53:25 | ... = ... | 4 |
|
||||
| ConditionalAccess.cs:54:9:54:10 | access to parameter ca | ConditionalAccess.cs:54:9:54:10 | access to parameter ca | 1 |
|
||||
| ConditionalAccess.cs:54:9:54:22 | access to property StringProp | ConditionalAccess.cs:54:9:54:22 | access to property StringProp | 1 |
|
||||
| ConditionalAccess.cs:54:9:54:30 | ...; | ConditionalAccess.cs:54:9:54:10 | access to parameter ca | 2 |
|
||||
| ConditionalAccess.cs:54:27:54:29 | "!" | ConditionalAccess.cs:54:12:54:29 | ... = ... | 4 |
|
||||
| ConditionalAccess.cs:60:26:60:38 | enter CommaJoinWith | ConditionalAccess.cs:60:26:60:38 | exit CommaJoinWith | 8 |
|
||||
| Conditions.cs:1:7:1:16 | enter Conditions | Conditions.cs:1:7:1:16 | exit Conditions | 7 |
|
||||
| Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:5:13:5:15 | access to parameter inc | 4 |
|
||||
| Conditions.cs:3:10:3:19 | exit IncrOrDecr (normal) | Conditions.cs:3:10:3:19 | exit IncrOrDecr | 2 |
|
||||
@@ -490,8 +516,8 @@
|
||||
| Finally.cs:205:31:205:46 | object creation of type ExceptionB | Finally.cs:205:31:205:46 | object creation of type ExceptionB | 1 |
|
||||
| Finally.cs:208:13:210:13 | {...} | Finally.cs:209:21:209:22 | access to parameter b3 | 3 |
|
||||
| Finally.cs:209:31:209:46 | object creation of type ExceptionC | Finally.cs:209:25:209:47 | throw ...; | 2 |
|
||||
| Finally.cs:211:13:211:29 | ...; | Finally.cs:211:13:211:28 | ... = ... | 4 |
|
||||
| Finally.cs:213:9:213:25 | ...; | Finally.cs:195:10:195:12 | exit M10 (normal) | 5 |
|
||||
| Finally.cs:211:13:211:29 | ...; | Finally.cs:211:13:211:28 | ... = ... | 5 |
|
||||
| Finally.cs:213:9:213:25 | ...; | Finally.cs:195:10:195:12 | exit M10 (normal) | 6 |
|
||||
| Finally.cs:216:10:216:12 | enter M11 | Finally.cs:220:13:220:36 | call to method WriteLine | 7 |
|
||||
| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:224:13:224:38 | call to method WriteLine | 5 |
|
||||
| Finally.cs:227:9:229:9 | {...} | Finally.cs:216:10:216:12 | exit M11 | 9 |
|
||||
@@ -539,21 +565,21 @@
|
||||
| Foreach.cs:36:10:36:11 | exit M6 (normal) | Foreach.cs:36:10:36:11 | exit M6 | 2 |
|
||||
| Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | 1 |
|
||||
| Foreach.cs:38:26:38:26 | String x | Foreach.cs:39:11:39:11 | ; | 4 |
|
||||
| Initializers.cs:3:7:3:18 | enter <object initializer> | Initializers.cs:3:7:3:18 | exit <object initializer> | 14 |
|
||||
| Initializers.cs:3:7:3:18 | enter <object initializer> | Initializers.cs:3:7:3:18 | exit <object initializer> | 15 |
|
||||
| Initializers.cs:3:7:3:18 | enter Initializers | Initializers.cs:3:7:3:18 | exit Initializers | 4 |
|
||||
| Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:8:5:8:16 | exit Initializers | 7 |
|
||||
| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:10:5:10:16 | exit Initializers | 7 |
|
||||
| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:12:10:12:10 | exit M | 22 |
|
||||
| Initializers.cs:18:16:18:16 | enter H | Initializers.cs:18:16:18:16 | exit H | 5 |
|
||||
| Initializers.cs:20:11:20:23 | enter <object initializer> | Initializers.cs:20:11:20:23 | exit <object initializer> | 9 |
|
||||
| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:12:10:12:10 | exit M | 23 |
|
||||
| Initializers.cs:18:16:18:16 | enter H | Initializers.cs:18:16:18:16 | exit H | 6 |
|
||||
| Initializers.cs:20:11:20:23 | enter <object initializer> | Initializers.cs:20:11:20:23 | exit <object initializer> | 11 |
|
||||
| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:20:11:20:23 | exit NoConstructor | 7 |
|
||||
| Initializers.cs:26:11:26:13 | enter <object initializer> | Initializers.cs:26:11:26:13 | exit <object initializer> | 6 |
|
||||
| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | exit Sub | 11 |
|
||||
| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | exit Sub | 9 |
|
||||
| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:35:9:35:11 | exit Sub | 13 |
|
||||
| Initializers.cs:26:11:26:13 | enter <object initializer> | Initializers.cs:26:11:26:13 | exit <object initializer> | 7 |
|
||||
| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | exit Sub | 12 |
|
||||
| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | exit Sub | 10 |
|
||||
| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:35:9:35:11 | exit Sub | 14 |
|
||||
| Initializers.cs:39:7:39:23 | enter IndexInitializers | Initializers.cs:39:7:39:23 | exit IndexInitializers | 7 |
|
||||
| Initializers.cs:41:11:41:18 | enter Compound | Initializers.cs:41:11:41:18 | exit Compound | 7 |
|
||||
| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:51:10:51:13 | exit Test | 105 |
|
||||
| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:51:10:51:13 | exit Test | 116 |
|
||||
| LoopUnrolling.cs:5:7:5:19 | enter LoopUnrolling | LoopUnrolling.cs:5:7:5:19 | exit LoopUnrolling | 7 |
|
||||
| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:9:13:9:28 | ... == ... | 7 |
|
||||
| LoopUnrolling.cs:7:10:7:11 | exit M1 (normal) | LoopUnrolling.cs:7:10:7:11 | exit M1 | 2 |
|
||||
@@ -629,7 +655,7 @@
|
||||
| MultiImplementationA.cs:8:29:8:32 | null | MultiImplementationA.cs:8:16:8:16 | exit M (abnormal) | 3 |
|
||||
| MultiImplementationA.cs:11:7:11:8 | enter <object initializer> | MultiImplementationA.cs:11:7:11:8 | enter <object initializer> | 1 |
|
||||
| MultiImplementationA.cs:11:7:11:8 | exit <object initializer> (normal) | MultiImplementationA.cs:11:7:11:8 | exit <object initializer> | 2 |
|
||||
| MultiImplementationA.cs:13:16:13:16 | this access | MultiImplementationA.cs:24:32:24:34 | ... = ... | 7 |
|
||||
| MultiImplementationA.cs:13:16:13:16 | this access | MultiImplementationA.cs:24:32:24:34 | ... = ... | 8 |
|
||||
| MultiImplementationA.cs:14:31:14:31 | access to parameter i | MultiImplementationA.cs:14:31:14:31 | exit get_Item (normal) | 2 |
|
||||
| MultiImplementationA.cs:14:31:14:31 | enter get_Item | MultiImplementationA.cs:14:31:14:31 | enter get_Item | 1 |
|
||||
| MultiImplementationA.cs:14:31:14:31 | exit get_Item | MultiImplementationA.cs:14:31:14:31 | exit get_Item | 1 |
|
||||
@@ -645,7 +671,7 @@
|
||||
| MultiImplementationA.cs:18:9:18:22 | enter M2 | MultiImplementationA.cs:18:9:18:22 | exit M2 | 4 |
|
||||
| MultiImplementationA.cs:20:12:20:13 | enter C2 | MultiImplementationA.cs:20:12:20:13 | enter C2 | 1 |
|
||||
| MultiImplementationA.cs:20:12:20:13 | exit C2 | MultiImplementationA.cs:20:12:20:13 | exit C2 | 1 |
|
||||
| MultiImplementationA.cs:20:12:20:13 | this access | MultiImplementationA.cs:20:12:20:13 | exit C2 (normal) | 9 |
|
||||
| MultiImplementationA.cs:20:12:20:13 | this access | MultiImplementationA.cs:20:12:20:13 | exit C2 (normal) | 10 |
|
||||
| MultiImplementationA.cs:21:12:21:13 | enter C2 | MultiImplementationA.cs:21:12:21:13 | enter C2 | 1 |
|
||||
| MultiImplementationA.cs:21:12:21:13 | exit C2 (normal) | MultiImplementationA.cs:21:12:21:13 | exit C2 | 2 |
|
||||
| MultiImplementationA.cs:21:24:21:24 | 0 | MultiImplementationA.cs:21:27:21:29 | {...} | 3 |
|
||||
@@ -671,7 +697,7 @@
|
||||
| MultiImplementationB.cs:4:25:4:37 | {...} | MultiImplementationA.cs:7:21:7:23 | exit get_P2 (normal) | 4 |
|
||||
| MultiImplementationB.cs:4:43:4:45 | {...} | MultiImplementationA.cs:7:41:7:43 | exit set_P2 (normal) | 2 |
|
||||
| MultiImplementationB.cs:5:23:5:23 | 2 | MultiImplementationA.cs:8:16:8:16 | exit M (normal) | 2 |
|
||||
| MultiImplementationB.cs:11:16:11:16 | this access | MultiImplementationB.cs:22:32:22:34 | ... = ... | 7 |
|
||||
| MultiImplementationB.cs:11:16:11:16 | this access | MultiImplementationB.cs:22:32:22:34 | ... = ... | 8 |
|
||||
| MultiImplementationB.cs:12:37:12:40 | null | MultiImplementationA.cs:14:31:14:31 | exit get_Item (abnormal) | 3 |
|
||||
| MultiImplementationB.cs:13:40:13:54 | {...} | MultiImplementationA.cs:15:36:15:38 | exit get_Item (abnormal) | 4 |
|
||||
| MultiImplementationB.cs:13:60:13:62 | {...} | MultiImplementationB.cs:13:60:13:62 | {...} | 1 |
|
||||
@@ -722,7 +748,7 @@
|
||||
| NullCoalescing.cs:15:31:15:31 | 0 | NullCoalescing.cs:16:17:16:18 | "" | 5 |
|
||||
| NullCoalescing.cs:16:17:16:25 | ... ?? ... | NullCoalescing.cs:17:13:17:19 | (...) ... | 5 |
|
||||
| NullCoalescing.cs:17:13:17:24 | ... ?? ... | NullCoalescing.cs:13:10:13:11 | exit M6 | 4 |
|
||||
| PartialImplementationA.cs:1:15:1:21 | enter <object initializer> | PartialImplementationA.cs:1:15:1:21 | exit <object initializer> | 10 |
|
||||
| PartialImplementationA.cs:1:15:1:21 | enter <object initializer> | PartialImplementationA.cs:1:15:1:21 | exit <object initializer> | 11 |
|
||||
| PartialImplementationA.cs:3:12:3:18 | enter Partial | PartialImplementationA.cs:3:12:3:18 | exit Partial | 7 |
|
||||
| PartialImplementationB.cs:4:12:4:18 | enter Partial | PartialImplementationB.cs:4:12:4:18 | exit Partial | 7 |
|
||||
| Patterns.cs:3:7:3:14 | enter Patterns | Patterns.cs:3:7:3:14 | exit Patterns | 7 |
|
||||
@@ -1041,8 +1067,8 @@
|
||||
| cflow.cs:127:32:127:57 | ... ? ... : ... | cflow.cs:127:19:127:21 | exit get_Prop | 4 |
|
||||
| cflow.cs:127:48:127:49 | "" | cflow.cs:127:48:127:49 | "" | 1 |
|
||||
| cflow.cs:127:53:127:57 | this access | cflow.cs:127:53:127:57 | access to field Field | 2 |
|
||||
| cflow.cs:127:62:127:64 | enter set_Prop | cflow.cs:127:62:127:64 | exit set_Prop | 8 |
|
||||
| cflow.cs:129:5:129:15 | enter ControlFlow | cflow.cs:129:5:129:15 | exit ControlFlow | 11 |
|
||||
| cflow.cs:127:62:127:64 | enter set_Prop | cflow.cs:127:62:127:64 | exit set_Prop | 9 |
|
||||
| cflow.cs:129:5:129:15 | enter ControlFlow | cflow.cs:129:5:129:15 | exit ControlFlow | 12 |
|
||||
| cflow.cs:134:5:134:15 | enter ControlFlow | cflow.cs:134:5:134:15 | exit ControlFlow | 9 |
|
||||
| cflow.cs:136:12:136:22 | enter ControlFlow | cflow.cs:136:12:136:22 | exit ControlFlow | 8 |
|
||||
| cflow.cs:138:40:138:40 | enter + | cflow.cs:138:40:138:40 | exit + | 9 |
|
||||
@@ -1104,7 +1130,7 @@
|
||||
| cflow.cs:201:9:205:9 | {...} | cflow.cs:193:10:193:17 | exit Booleans (abnormal) | 5 |
|
||||
| cflow.cs:208:10:208:11 | enter Do | cflow.cs:210:9:221:36 | do ... while (...); | 3 |
|
||||
| cflow.cs:208:10:208:11 | exit Do (normal) | cflow.cs:208:10:208:11 | exit Do | 2 |
|
||||
| cflow.cs:211:9:221:9 | {...} | cflow.cs:213:17:213:32 | ... > ... | 14 |
|
||||
| cflow.cs:211:9:221:9 | {...} | cflow.cs:213:17:213:32 | ... > ... | 15 |
|
||||
| cflow.cs:214:13:216:13 | {...} | cflow.cs:215:17:215:25 | continue; | 2 |
|
||||
| cflow.cs:217:13:220:13 | if (...) ... | cflow.cs:217:17:217:32 | ... < ... | 6 |
|
||||
| cflow.cs:218:13:220:13 | {...} | cflow.cs:219:17:219:22 | break; | 2 |
|
||||
@@ -1112,7 +1138,7 @@
|
||||
| cflow.cs:224:10:224:16 | enter Foreach | cflow.cs:226:27:226:64 | call to method Repeat<String> | 5 |
|
||||
| cflow.cs:224:10:224:16 | exit Foreach (normal) | cflow.cs:224:10:224:16 | exit Foreach | 2 |
|
||||
| cflow.cs:226:9:237:9 | foreach (... ... in ...) ... | cflow.cs:226:9:237:9 | foreach (... ... in ...) ... | 1 |
|
||||
| cflow.cs:226:22:226:22 | String x | cflow.cs:229:17:229:32 | ... > ... | 15 |
|
||||
| cflow.cs:226:22:226:22 | String x | cflow.cs:229:17:229:32 | ... > ... | 16 |
|
||||
| cflow.cs:230:13:232:13 | {...} | cflow.cs:231:17:231:25 | continue; | 2 |
|
||||
| cflow.cs:233:13:236:13 | if (...) ... | cflow.cs:233:17:233:32 | ... < ... | 6 |
|
||||
| cflow.cs:234:13:236:13 | {...} | cflow.cs:235:17:235:22 | break; | 2 |
|
||||
|
||||
@@ -91,6 +91,23 @@ conditionBlock
|
||||
| ConditionalAccess.cs:23:13:23:38 | Nullable<Int32> j = ... | ConditionalAccess.cs:25:31:25:31 | access to local variable s | false |
|
||||
| ConditionalAccess.cs:24:17:24:37 | call to method ToString | ConditionalAccess.cs:25:31:25:31 | access to local variable s | false |
|
||||
| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:35:9:35:24 | call to method Out | false |
|
||||
| ConditionalAccess.cs:46:10:46:11 | enter M9 | ConditionalAccess.cs:48:24:48:25 | 42 | false |
|
||||
| ConditionalAccess.cs:49:9:49:33 | ...; | ConditionalAccess.cs:49:26:49:32 | "Hello" | false |
|
||||
| ConditionalAccess.cs:50:9:50:24 | ...; | ConditionalAccess.cs:50:13:50:13 | 0 | false |
|
||||
| ConditionalAccess.cs:51:9:51:16 | access to property Prop | ConditionalAccess.cs:51:30:51:31 | 84 | false |
|
||||
| ConditionalAccess.cs:51:9:51:32 | ...; | ConditionalAccess.cs:51:9:51:16 | access to property Prop | false |
|
||||
| ConditionalAccess.cs:51:9:51:32 | ...; | ConditionalAccess.cs:51:30:51:31 | 84 | false |
|
||||
| ConditionalAccess.cs:52:9:52:16 | access to property Prop | ConditionalAccess.cs:52:32:52:38 | "World" | false |
|
||||
| ConditionalAccess.cs:52:9:52:39 | ...; | ConditionalAccess.cs:52:9:52:16 | access to property Prop | false |
|
||||
| ConditionalAccess.cs:52:9:52:39 | ...; | ConditionalAccess.cs:52:32:52:38 | "World" | false |
|
||||
| ConditionalAccess.cs:53:9:53:10 | access to parameter ca | ConditionalAccess.cs:53:9:53:20 | access to field IntField | false |
|
||||
| ConditionalAccess.cs:53:9:53:26 | ...; | ConditionalAccess.cs:53:9:53:10 | access to parameter ca | false |
|
||||
| ConditionalAccess.cs:53:9:53:26 | ...; | ConditionalAccess.cs:53:9:53:20 | access to field IntField | false |
|
||||
| ConditionalAccess.cs:53:9:53:26 | ...; | ConditionalAccess.cs:53:25:53:25 | 1 | false |
|
||||
| ConditionalAccess.cs:54:9:54:10 | access to parameter ca | ConditionalAccess.cs:54:9:54:22 | access to property StringProp | false |
|
||||
| ConditionalAccess.cs:54:9:54:30 | ...; | ConditionalAccess.cs:54:9:54:10 | access to parameter ca | false |
|
||||
| ConditionalAccess.cs:54:9:54:30 | ...; | ConditionalAccess.cs:54:9:54:22 | access to property StringProp | false |
|
||||
| ConditionalAccess.cs:54:9:54:30 | ...; | ConditionalAccess.cs:54:27:54:29 | "!" | false |
|
||||
| Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:6:13:6:16 | ...; | true |
|
||||
| Conditions.cs:7:9:8:16 | if (...) ... | Conditions.cs:7:13:7:16 | [false] !... | true |
|
||||
| Conditions.cs:7:9:8:16 | if (...) ... | Conditions.cs:7:13:7:16 | [true] !... | false |
|
||||
|
||||
@@ -34,6 +34,25 @@ class ConditionalAccess
|
||||
i = 0;
|
||||
Prop?.Out(out i);
|
||||
}
|
||||
|
||||
string StringProp { get; set; }
|
||||
int IntField;
|
||||
string this[int index]
|
||||
{
|
||||
get { return null; }
|
||||
set { }
|
||||
}
|
||||
|
||||
void M9(ConditionalAccess ca)
|
||||
{
|
||||
ca?.IntField = 42;
|
||||
ca?.StringProp = "Hello";
|
||||
ca?[0] = "Set0";
|
||||
ca?.Prop?.IntField = 84;
|
||||
ca?.Prop?.StringProp = "World";
|
||||
ca?.IntField -= 1;
|
||||
ca?.StringProp += "!";
|
||||
}
|
||||
}
|
||||
|
||||
static class Ext
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user