Merge branch 'main' into codeql-spark-run-21376405640

This commit is contained in:
Henry Mercer
2026-01-27 09:11:02 -08:00
committed by GitHub
423 changed files with 82959 additions and 31560 deletions

View File

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

View File

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

View File

@@ -0,0 +1,4 @@
---
category: fix
---
* Fixed a crash when analysing a `${{ ... }}` expression over around 300 characters in length.

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,5 @@
import codeql.actions.ast.internal.Ast
int getAnExpressionLength() { result = any(ExpressionImpl e).toString().length() }
select max(getAnExpressionLength())

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Sections for databaseMetadata and overlayChangedFiles
compatibility: full

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,4 @@
description: Support embed preprocessor directive
compatibility: partial
embeds.rel: delete
preprocdirects.rel: run preprocdirects.qlo

View File

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

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* Added a subclass `Embed` of `PreprocessorDirective` for C23 and C++26 `#embed` preprocessor directives.

View File

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

View File

@@ -0,0 +1,4 @@
---
category: fix
---
* Fixed a bug which caused `Node.asDefinition()` to not have a result for certain assignments.

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

View File

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

View 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"]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1144,7 +1144,7 @@ private newtype TDataFlowCall =
}
private predicate summarizedCallableIsManual(SummarizedCallable sc) {
sc.asSummarizedCallable().applyManualModel()
sc.asSummarizedCallable().hasManualModel()
}
/**

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,2 @@
description: Sections for databaseMetadata and overlayChangedFiles
compatibility: full

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Support embed preprocessor directive
compatibility: partial

View File

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

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 1.5.9
version: 1.5.10-dev
groups:
- cpp
- queries

View File

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

View 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="... = ..."
}

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-queries
version: 1.6.0
version: 1.6.1-dev
groups:
- csharp
- queries

View File

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

View File

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

View File

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

View File

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

View File

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