Merge branch 'main' into redsun82/kotlin

This commit is contained in:
Paolo Tranquilli
2024-05-06 17:24:53 +02:00
357 changed files with 4622 additions and 4212 deletions

View File

@@ -14,6 +14,10 @@ build:linux --cxxopt=-std=c++20
build:macos --cxxopt=-std=c++20 --cpu=darwin_x86_64
build:windows --cxxopt=/std:c++20 --cxxopt=/Zc:preprocessor
# this requires developer mode, but is required to have pack installer functioning
startup --windows_enable_symlinks
common --enable_runfiles
common --registry=file:///%workspace%/misc/bazel/registry
common --registry=https://bcr.bazel.build

View File

@@ -24,5 +24,5 @@ jobs:
extra_args: >
buildifier --all-files 2>&1 ||
(
echo -e "In order to format all bazel files, please run:\n bazel run //:buildifier"; exit 1
echo -e "In order to format all bazel files, please run:\n bazel run //misc/bazel:buildifier"; exit 1
)

5
.lfsconfig Normal file
View File

@@ -0,0 +1,5 @@
[lfs]
# codeql is publicly forked by many users, and we don't want any LFS file polluting their working
# copies. We therefore exclude everything by default.
# For files required by bazel builds, use rules in `misc/bazel/lfs.bzl` to download them on demand.
fetchinclude = /nothing

View File

@@ -26,7 +26,14 @@ repos:
name: Format bazel files
files: \.(bazel|bzl)
language: system
entry: bazel run //:buildifier
entry: bazel run //misc/bazel:buildifier
pass_filenames: false
- id: go-gen
name: Check checked in generated files in go
files: ^go/.*
language: system
entry: bazel run //go:gen
pass_filenames: false
- id: codeql-format

View File

@@ -1,9 +0,0 @@
load("@buildifier_prebuilt//:rules.bzl", "buildifier")
buildifier(
name = "buildifier",
exclude_patterns = [
"./.git/*",
],
lint_mode = "fix",
)

View File

@@ -13,7 +13,8 @@ local_path_override(
# see https://registry.bazel.build/ for a list of available packages
bazel_dep(name = "platforms", version = "0.0.8")
bazel_dep(name = "platforms", version = "0.0.9")
bazel_dep(name = "rules_go", version = "0.47.0")
bazel_dep(name = "rules_pkg", version = "0.10.1")
bazel_dep(name = "rules_nodejs", version = "6.0.3")
bazel_dep(name = "rules_python", version = "0.31.0")
@@ -22,6 +23,7 @@ bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl")
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
bazel_dep(name = "fmt", version = "10.0.0")
bazel_dep(name = "rules_kotlin", version = "1.9.4-codeql.1")
bazel_dep(name = "gazelle", version = "0.36.0")
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
@@ -98,6 +100,9 @@ use_repo(
"kotlin-stdlib-2.0.0-RC1",
)
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
go_sdk.download(version = "1.22.2")
register_toolchains(
"@nodejs_toolchains//:all",
)

View File

@@ -1,3 +1,20 @@
## 0.13.0
### Breaking Changes
* Deleted the deprecated `GlobalValueNumberingImpl.qll` implementation.
### New Features
* Models-as-Data support has been added for C/C++. This feature allows flow sources, sinks and summaries to be expressed in compact strings as an alternative to modelling each source / sink / summary with explicit QL. See `dataflow/ExternalFlow.qll` for documentation and specification of the model format, and `models/implementations/ZMQ.qll` for a simple example of models. Importing models from `.yml` is not yet supported.
### Minor Analysis Improvements
* Source models have been added for the standard library function `getc` (and variations).
* Source, sink and flow models for the ZeroMQ (ZMQ) networking library have been added.
* Parameters of functions without definitions now have `ParameterNode`s.
* The alias analysis used internally by various libraries has been improved to answer alias questions more conservatively. As a result, some queries may report fewer false positives.
## 0.12.11
No user-facing changes.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The alias analysis used internally by various libraries has been improved to answer alias questions more conservatively. As a result, some queries may report fewer false positives.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Parameters of functions without definitions now have `ParameterNode`s.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Source models have been added for the standard library function `getc` (and variations).

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* Models-as-Data support has been added for C/C++. This feature allows flow sources, sinks and summaries to be expressed in compact strings as an alternative to modelling each source / sink / summary with explicit QL. See `dataflow/ExternalFlow.qll` for documentation and specification of the model format, and `models/implementations/ZMQ.qll` for a simple example of models. Importing models from `.yml` is not yet supported.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Source, sink and flow models for the ZeroMQ (ZMQ) networking library have been added.

View File

@@ -0,0 +1,16 @@
## 0.13.0
### Breaking Changes
* Deleted the deprecated `GlobalValueNumberingImpl.qll` implementation.
### New Features
* Models-as-Data support has been added for C/C++. This feature allows flow sources, sinks and summaries to be expressed in compact strings as an alternative to modelling each source / sink / summary with explicit QL. See `dataflow/ExternalFlow.qll` for documentation and specification of the model format, and `models/implementations/ZMQ.qll` for a simple example of models. Importing models from `.yml` is not yet supported.
### Minor Analysis Improvements
* Source models have been added for the standard library function `getc` (and variations).
* Source, sink and flow models for the ZeroMQ (ZMQ) networking library have been added.
* Parameters of functions without definitions now have `ParameterNode`s.
* The alias analysis used internally by various libraries has been improved to answer alias questions more conservatively. As a result, some queries may report fewer false positives.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.12.11
lastReleaseVersion: 0.13.0

View File

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

View File

@@ -790,6 +790,27 @@ private predicate simple_comparison_eq(Instruction test, Operand op, int k, Abst
exists(switch.getSuccessor(case)) and
case.getValue().toInt() = k
)
or
// There's no implicit CompareInstruction in files compiled as C since C
// doesn't have implicit boolean conversions. So instead we check whether
// there's a branch on a value of pointer or integer type.
exists(ConditionalBranchInstruction branch, IRType type |
not test instanceof CompareInstruction and
type = test.getResultIRType() and
(type instanceof IRAddressType or type instanceof IRIntegerType) and
test = branch.getCondition() and
op.getDef() = test
|
// We'd like to also include a case such as:
// ```
// k = 1 and
// value.(BooleanValue).getValue() = true
// ```
// but all we know is that the value is non-zero in the true branch.
// So we can only conclude something in the false branch.
k = 0 and
value.(BooleanValue).getValue() = false
)
}
private predicate complex_eq(

View File

@@ -1665,3 +1665,311 @@ class DataFlowSecondLevelScope extends TDataFlowSecondLevelScope {
/** Gets the second-level scope containing the node `n`, if any. */
DataFlowSecondLevelScope getSecondLevelScope(Node n) { result.getANode() = n }
/**
* Module that defines flow through iterators.
* For example,
* ```cpp
* auto it = v.begin();
* *it = source();
* ...
* sink(v[0]);
* ```
*/
module IteratorFlow {
private import codeql.ssa.Ssa as SsaImpl
private import semmle.code.cpp.models.interfaces.Iterator as Interface
private import semmle.code.cpp.models.implementations.Iterator as Impl
/**
* A variable of some type that can produce an iterator.
*/
class SourceVariable extends Ssa::SourceVariable {
SourceVariable() {
exists(Interface::GetIteratorFunction gets, Cpp::FunctionInput input, int i |
input.isParameterDerefOrQualifierObject(i) and
gets.getsIterator(input, _)
|
this.getType().stripType() = gets.getParameter(i).getType().stripType()
or
i = -1 and
this.getType().stripType() = gets.getDeclaringType()
)
}
}
private module SsaInput implements SsaImpl::InputSig<Location> {
import Ssa::InputSigCommon
class SourceVariable = IteratorFlow::SourceVariable;
/** A call to function that dereferences an iterator. */
private class IteratorPointerDereferenceCall extends CallInstruction {
IteratorPointerDereferenceCall() {
this.getStaticCallTarget() instanceof Impl::IteratorPointerDereferenceOperator
}
}
/** A call to a function that obtains an iterator. */
private class GetsIteratorCall extends CallInstruction {
GetsIteratorCall() { this.getStaticCallTarget() instanceof Impl::GetIteratorFunction }
}
/** A call to `operator++` or `operator--` on an iterator. */
private class IteratorCrementCall extends CallInstruction {
IteratorCrementCall() { this.getStaticCallTarget() instanceof Impl::IteratorCrementOperator }
}
/**
* Gets an ultimate definition of `def`.
*
* Note: Unlike `def.getAnUltimateDefinition()` this predicate also
* traverses back through iterator increment and decrement operations.
*/
private Ssa::Def getAnUltimateDefinition(Ssa::Def def) {
result = def.getAnUltimateDefinition()
or
exists(IRBlock bb, int i, IteratorCrementCall crementCall, Ssa::SourceVariable sv |
crementCall = def.getValue().asInstruction().(StoreInstruction).getSourceValue() and
sv = def.getSourceVariable() and
bb.getInstruction(i) = crementCall and
Ssa::ssaDefReachesRead(sv, result.asDef(), bb, i)
)
}
/**
* Holds if `write` is an instruction that writes to address `address`
*/
private predicate isIteratorWrite(Instruction write, Operand address) {
exists(Ssa::DefImpl writeDef, IRBlock bb, int i |
writeDef.hasIndexInBlock(bb, i, _) and
bb.getInstruction(i) = write and
address = writeDef.getAddressOperand()
)
}
/**
* Holds if `writeToDeref` is a write to an iterator that was obtained
* by `beginCall`. That is, the following instruction sequence holds:
* ```cpp
* it = container.begin(); // or a similar iterator-obtaining function call
* ...
* *it = value;
* ```
*/
private predicate isIteratorStoreInstruction(
GetsIteratorCall beginCall, Instruction writeToDeref
) {
exists(
StoreInstruction beginStore, IRBlock bbStar, int iStar, Ssa::Def def,
IteratorPointerDereferenceCall starCall, Ssa::Def ultimate, Operand address
|
isIteratorWrite(writeToDeref, address) and
operandForFullyConvertedCall(address, starCall) and
bbStar.getInstruction(iStar) = starCall and
Ssa::ssaDefReachesRead(_, def.asDef(), bbStar, iStar) and
ultimate = getAnUltimateDefinition*(def) and
beginStore = ultimate.getValue().asInstruction() and
operandForFullyConvertedCall(beginStore.getSourceValueOperand(), beginCall)
)
}
/**
* Holds if `(bb, i)` contains a write to an iterator that may have been obtained
* by calling `begin` (or related functions) on the variable `v`.
*/
predicate variableWrite(IRBlock bb, int i, SourceVariable v, boolean certain) {
certain = false and
exists(GetsIteratorCall beginCall, Instruction writeToDeref, IRBlock bbQual, int iQual |
isIteratorStoreInstruction(beginCall, writeToDeref) and
bb.getInstruction(i) = writeToDeref and
bbQual.getInstruction(iQual) = beginCall and
Ssa::variableRead(bbQual, iQual, v, _)
)
}
/** Holds if `(bb, i)` reads the container variable `v`. */
predicate variableRead(IRBlock bb, int i, SourceVariable v, boolean certain) {
Ssa::variableRead(bb, i, v, certain)
}
}
private module IteratorSsa = SsaImpl::Make<Location, SsaInput>;
cached
private newtype TSsaDef =
TDef(IteratorSsa::DefinitionExt def) or
TPhi(PhiNode phi)
abstract private class SsaDef extends TSsaDef {
/** Gets a textual representation of this element. */
string toString() { none() }
/** Gets the underlying non-phi definition or use. */
IteratorSsa::DefinitionExt asDef() { none() }
/** Gets the underlying phi node. */
PhiNode asPhi() { none() }
/** Gets the location of this element. */
abstract Location getLocation();
}
private class Def extends TDef, SsaDef {
IteratorSsa::DefinitionExt def;
Def() { this = TDef(def) }
final override IteratorSsa::DefinitionExt asDef() { result = def }
final override Location getLocation() { result = this.getImpl().getLocation() }
/** Gets the variable written to by this definition. */
final SourceVariable getSourceVariable() { result = def.getSourceVariable() }
override string toString() { result = def.toString() }
/**
* Holds if this definition (or use) has index `index` in block `block`,
* and is a definition (or use) of the variable `sv`.
*/
predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) {
def.definesAt(sv, block, index, _)
}
private Ssa::DefImpl getImpl() {
exists(IRBlock bb, int i |
this.hasIndexInBlock(bb, i, _) and
result.hasIndexInBlock(bb, i)
)
}
/** Gets the value written by this definition (i.e., the "right-hand side"). */
Node0Impl getValue() { result = this.getImpl().getValue() }
/** Gets the indirection index of this definition. */
int getIndirectionIndex() { result = this.getImpl().getIndirectionIndex() }
}
private class Phi extends TPhi, SsaDef {
PhiNode phi;
Phi() { this = TPhi(phi) }
final override PhiNode asPhi() { result = phi }
final override Location getLocation() { result = phi.getBasicBlock().getLocation() }
override string toString() { result = phi.toString() }
SsaIteratorNode getNode() { result.getIteratorFlowNode() = phi }
}
private class PhiNode extends IteratorSsa::DefinitionExt {
PhiNode() {
this instanceof IteratorSsa::PhiNode or
this instanceof IteratorSsa::PhiReadNode
}
SsaIteratorNode getNode() { result.getIteratorFlowNode() = this }
}
cached
private module IteratorSsaCached {
cached
predicate adjacentDefRead(IRBlock bb1, int i1, SourceVariable sv, IRBlock bb2, int i2) {
IteratorSsa::adjacentDefReadExt(_, sv, bb1, i1, bb2, i2)
or
exists(PhiNode phi |
IteratorSsa::lastRefRedefExt(_, sv, bb1, i1, phi) and
phi.definesAt(sv, bb2, i2, _)
)
}
cached
Node getAPriorDefinition(IteratorSsa::DefinitionExt next) {
exists(IRBlock bb, int i, SourceVariable sv, IteratorSsa::DefinitionExt def |
IteratorSsa::lastRefRedefExt(pragma[only_bind_into](def), pragma[only_bind_into](sv),
pragma[only_bind_into](bb), pragma[only_bind_into](i), next) and
nodeToDefOrUse(result, sv, bb, i, _)
)
}
}
/** The set of nodes necessary for iterator flow. */
class IteratorFlowNode instanceof PhiNode {
/** Gets a textual representation of this node. */
string toString() { result = super.toString() }
/** Gets the type of this node. */
DataFlowType getType() {
exists(Ssa::SourceVariable sv |
super.definesAt(sv, _, _, _) and
result = sv.getType()
)
}
/** Gets the `Declaration` that contains this block. */
Declaration getFunction() { result = super.getBasicBlock().getEnclosingFunction() }
/** Gets the locatino of this node. */
Location getLocation() { result = super.getBasicBlock().getLocation() }
}
private import IteratorSsaCached
private predicate defToNode(Node node, Def def, boolean uncertain) {
(
nodeHasOperand(node, def.getValue().asOperand(), def.getIndirectionIndex())
or
nodeHasInstruction(node, def.getValue().asInstruction(), def.getIndirectionIndex())
) and
uncertain = false
}
private predicate nodeToDefOrUse(
Node node, SourceVariable sv, IRBlock bb, int i, boolean uncertain
) {
exists(Def def |
def.hasIndexInBlock(bb, i, sv) and
defToNode(node, def, uncertain)
)
or
useToNode(bb, i, sv, node) and
uncertain = false
}
private predicate useToNode(IRBlock bb, int i, SourceVariable sv, Node nodeTo) {
exists(PhiNode phi |
phi.definesAt(sv, bb, i, _) and
nodeTo = phi.getNode()
)
or
exists(Ssa::UseImpl use |
use.hasIndexInBlock(bb, i, sv) and
nodeTo = use.getNode()
)
}
/**
* Holds if `nodeFrom` flows to `nodeTo` in a single step.
*/
predicate localFlowStep(Node nodeFrom, Node nodeTo) {
exists(
Node nFrom, SourceVariable sv, IRBlock bb1, int i1, IRBlock bb2, int i2, boolean uncertain
|
adjacentDefRead(bb1, i1, sv, bb2, i2) and
nodeToDefOrUse(nFrom, sv, bb1, i1, uncertain) and
useToNode(bb2, i2, sv, nodeTo)
|
if uncertain = true
then
nodeFrom =
[
nFrom,
getAPriorDefinition(any(IteratorSsa::DefinitionExt next | next.definesAt(sv, bb1, i1, _)))
]
else nFrom = nodeFrom
)
}
}

View File

@@ -46,6 +46,7 @@ private newtype TIRDataFlowNode =
Ssa::isModifiableByCall(operand, indirectionIndex)
} or
TSsaPhiNode(Ssa::PhiNode phi) or
TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
Ssa::hasRawIndirectOperand(node.asOperand(), indirectionIndex)
} or
@@ -653,6 +654,30 @@ class SsaPhiNode extends Node, TSsaPhiNode {
predicate isPhiRead() { phi.isPhiRead() }
}
/**
* INTERNAL: do not use.
*
* Dataflow nodes necessary for iterator flow
*/
class SsaIteratorNode extends Node, TSsaIteratorNode {
IteratorFlow::IteratorFlowNode node;
SsaIteratorNode() { this = TSsaIteratorNode(node) }
/** Gets the phi node associated with this node. */
IteratorFlow::IteratorFlowNode getIteratorFlowNode() { result = node }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Declaration getFunction() { result = node.getFunction() }
override DataFlowType getType() { result = node.getType() }
final override Location getLocationImpl() { result = node.getLocation() }
override string toStringImpl() { result = node.toString() }
}
/**
* INTERNAL: do not use.
*
@@ -1190,11 +1215,11 @@ class UninitializedNode extends Node {
LocalVariable v;
UninitializedNode() {
exists(Ssa::Def def |
exists(Ssa::Def def, Ssa::SourceVariable sv |
def.getIndirectionIndex() = 0 and
def.getValue().asInstruction() instanceof UninitializedInstruction and
Ssa::nodeToDefOrUse(this, def, _) and
v = def.getSourceVariable().getBaseVariable().(Ssa::BaseIRVariable).getIRVariable().getAst()
Ssa::defToNode(this, def, sv, _, _, _) and
v = sv.getBaseVariable().(Ssa::BaseIRVariable).getIRVariable().getAst()
)
}
@@ -2151,6 +2176,8 @@ private module Cached {
// Def-use/Use-use flow
Ssa::ssaFlow(nodeFrom, nodeTo)
or
IteratorFlow::localFlowStep(nodeFrom, nodeTo)
or
// Operand -> Instruction flow
simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction())
or

View File

@@ -102,12 +102,20 @@ predicate hasRawIndirectInstruction(Instruction instr, int indirectionIndex) {
}
cached
private newtype TDefOrUseImpl =
private newtype TDefImpl =
TDefAddressImpl(BaseIRVariable v) or
TDefImpl(BaseSourceVariableInstruction base, Operand address, int indirectionIndex) {
TDirectDefImpl(BaseSourceVariableInstruction base, Operand address, int indirectionIndex) {
isDef(_, _, address, base, _, indirectionIndex)
} or
TUseImpl(BaseSourceVariableInstruction base, Operand operand, int indirectionIndex) {
TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
// Represents the initial "definition" of a global variable when entering
// a function body.
isGlobalDefImpl(v, f, _, indirectionIndex)
}
cached
private newtype TUseImpl =
TDirectUseImpl(BaseSourceVariableInstruction base, Operand operand, int indirectionIndex) {
isUse(_, operand, base, _, indirectionIndex) and
not isDef(true, _, operand, _, _, _)
} or
@@ -116,21 +124,6 @@ private newtype TDefOrUseImpl =
// the assignment to a global variable isn't ruled out as dead.
isGlobalUse(v, f, _, indirectionIndex)
} or
TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
// Represents the initial "definition" of a global variable when entering
// a function body.
isGlobalDefImpl(v, f, _, indirectionIndex)
} or
TIteratorDef(
Operand iteratorDerefAddress, BaseSourceVariableInstruction container, int indirectionIndex
) {
isIteratorDef(container, iteratorDerefAddress, _, _, indirectionIndex)
} or
TIteratorUse(
Operand iteratorAddress, BaseSourceVariableInstruction container, int indirectionIndex
) {
isIteratorUse(container, iteratorAddress, _, indirectionIndex)
} or
TFinalParameterUse(Parameter p, int indirectionIndex) {
underlyingTypeIsModifiableAt(p.getUnderlyingType(), indirectionIndex) and
// Only create an SSA read for the final use of a parameter if there's
@@ -177,7 +170,84 @@ private predicate underlyingTypeIsModifiableAt(Type underlying, int indirectionI
private Indirection getIndirectionForUnspecifiedType(Type t) { result.getType() = t }
abstract private class DefOrUseImpl extends TDefOrUseImpl {
abstract class DefImpl extends TDefImpl {
int indirectionIndex;
bindingset[indirectionIndex]
DefImpl() { any() }
/** Gets a textual representation of this element. */
abstract string toString();
/** Gets the block of this definition or use. */
final IRBlock getBlock() { this.hasIndexInBlock(result, _) }
/** Holds if this definition or use has index `index` in block `block`. */
abstract predicate hasIndexInBlock(IRBlock block, int index);
/**
* Holds if this definition (or use) has index `index` in block `block`,
* and is a definition (or use) of the variable `sv`
*/
final predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) {
this.hasIndexInBlock(block, index) and
sv = this.getSourceVariable()
}
/** Gets the location of this element. */
abstract Cpp::Location getLocation();
/** Gets the indirection index of this definition. */
final int getIndirectionIndex() { result = indirectionIndex }
/**
* Gets the index (i.e., the number of loads required) of this
* definition or use.
*
* Note that this is _not_ the definition's (or use's) index in
* the enclosing basic block. To obtain this index, use
* `DefOrUseImpl::hasIndexInBlock/2` or `DefOrUseImpl::hasIndexInBlock/3`.
*/
abstract int getIndirection();
/**
* Gets the instruction that computes the base of this definition or use.
* This is always a `VariableAddressInstruction` or an `CallInstruction`.
*/
abstract BaseSourceVariableInstruction getBase();
/**
* Gets the base source variable (i.e., the variable without
* any indirection) of this definition or use.
*/
final BaseSourceVariable getBaseSourceVariable() {
this.getBase().getBaseSourceVariable() = result
}
/** Gets the variable that is defined or used. */
SourceVariable getSourceVariable() {
exists(BaseSourceVariable v, int indirection |
sourceVariableHasBaseAndIndex(result, v, indirection) and
defHasSourceVariable(this, v, indirection)
)
}
abstract predicate isCertain();
abstract Node0Impl getValue();
Operand getAddressOperand() { none() }
}
abstract class UseImpl extends TUseImpl {
int indirectionIndex;
bindingset[indirectionIndex]
UseImpl() { any() }
/** Gets the node associated with this use. */
abstract Node getNode();
/** Gets a textual representation of this element. */
abstract string toString();
@@ -207,7 +277,10 @@ abstract private class DefOrUseImpl extends TDefOrUseImpl {
* the enclosing basic block. To obtain this index, use
* `DefOrUseImpl::hasIndexInBlock/2` or `DefOrUseImpl::hasIndexInBlock/3`.
*/
abstract int getIndirectionIndex();
abstract int getIndirection();
/** Gets the indirection index of this use. */
final int getIndirectionIndex() { result = indirectionIndex }
/**
* Gets the instruction that computes the base of this definition or use.
@@ -225,17 +298,17 @@ abstract private class DefOrUseImpl extends TDefOrUseImpl {
/** Gets the variable that is defined or used. */
SourceVariable getSourceVariable() {
exists(BaseSourceVariable v, int ind |
sourceVariableHasBaseAndIndex(result, v, ind) and
defOrUseHasSourceVariable(this, v, ind)
exists(BaseSourceVariable v, int indirection |
sourceVariableHasBaseAndIndex(result, v, indirection) and
useHasSourceVariable(this, v, indirection)
)
}
}
private predicate defOrUseHasSourceVariable(DefOrUseImpl defOrUse, BaseSourceVariable bv, int ind) {
defHasSourceVariable(defOrUse, bv, ind)
or
useHasSourceVariable(defOrUse, bv, ind)
/**
* Holds if this use is guaranteed to read the
* associated variable.
*/
abstract predicate isCertain();
}
pragma[noinline]
@@ -256,32 +329,17 @@ private predicate sourceVariableHasBaseAndIndex(SourceVariable v, BaseSourceVari
v.getIndirection() = ind
}
abstract class DefImpl extends DefOrUseImpl {
int ind;
bindingset[ind]
DefImpl() { any() }
override int getIndirectionIndex() { result = ind }
override string toString() { result = "Def of " + this.getSourceVariable() }
abstract int getIndirection();
abstract predicate isCertain();
abstract Node0Impl getValue();
}
/** An initial definition of an `IRVariable`'s address. */
private class DefAddressImpl extends DefImpl, TDefAddressImpl {
BaseIRVariable v;
DefAddressImpl() {
this = TDefAddressImpl(v) and
ind = 0
indirectionIndex = 0
}
override string toString() { result = "Def of &" + v.toString() }
final override int getIndirection() { result = 0 }
final override predicate isCertain() { any() }
@@ -303,91 +361,45 @@ private class DefAddressImpl extends DefImpl, TDefAddressImpl {
final override BaseSourceVariableInstruction getBase() { none() }
}
/**
* An SSA definition that has an associated `Operand` representing the address
* that is being written to.
*/
abstract private class OperandBasedDef extends DefImpl {
private class DirectDef extends DefImpl, TDirectDefImpl {
Operand address;
BaseSourceVariableInstruction base;
bindingset[ind]
OperandBasedDef() { any() }
Operand getAddressOperand() { result = address }
DirectDef() { this = TDirectDefImpl(base, address, indirectionIndex) }
override Cpp::Location getLocation() { result = this.getAddressOperand().getUse().getLocation() }
final override predicate hasIndexInBlock(IRBlock block, int index) {
this.getAddressOperand().getUse() = block.getInstruction(index)
}
}
private class DirectDef extends OperandBasedDef, TDefImpl {
BaseSourceVariableInstruction base;
override string toString() { result = "Def of " + this.getSourceVariable() }
DirectDef() { this = TDefImpl(base, address, ind) }
override Operand getAddressOperand() { result = address }
override BaseSourceVariableInstruction getBase() { result = base }
override int getIndirection() { isDef(_, _, address, base, result, ind) }
override int getIndirection() { isDef(_, _, address, base, result, indirectionIndex) }
override Node0Impl getValue() { isDef(_, result, address, base, _, _) }
override predicate isCertain() { isDef(true, _, address, base, _, ind) }
override predicate isCertain() { isDef(true, _, address, base, _, indirectionIndex) }
}
private class IteratorDef extends OperandBasedDef, TIteratorDef {
BaseSourceVariableInstruction container;
IteratorDef() { this = TIteratorDef(address, container, ind) }
override BaseSourceVariableInstruction getBase() { result = container }
override int getIndirection() { isIteratorDef(container, address, _, result, ind) }
override Node0Impl getValue() { isIteratorDef(container, address, result, _, _) }
override predicate isCertain() { none() }
}
abstract class UseImpl extends DefOrUseImpl {
int ind;
bindingset[ind]
UseImpl() { any() }
/** Gets the node associated with this use. */
abstract Node getNode();
override string toString() { result = "Use of " + this.getSourceVariable() }
/** Gets the indirection index of this use. */
final override int getIndirectionIndex() { result = ind }
/** Gets the number of loads that precedence this use. */
abstract int getIndirection();
/**
* Holds if this use is guaranteed to read the
* associated variable.
*/
abstract predicate isCertain();
}
abstract private class OperandBasedUse extends UseImpl {
private class DirectUseImpl extends UseImpl, TDirectUseImpl {
Operand operand;
BaseSourceVariableInstruction base;
bindingset[ind]
OperandBasedUse() { any() }
DirectUseImpl() { this = TDirectUseImpl(base, operand, indirectionIndex) }
override string toString() { result = "Use of " + this.getSourceVariable() }
final override predicate hasIndexInBlock(IRBlock block, int index) {
// See the comment in `ssa0`'s `OperandBasedUse` for an explanation of this
// predicate's implementation.
if base.getAst() = any(Cpp::PostfixCrementOperation c).getOperand()
then
exists(Operand op, int indirectionIndex, int indirection |
indirectionIndex = this.getIndirectionIndex() and
exists(Operand op, int indirection |
indirection = this.getIndirection() and
op =
min(Operand cand, int i |
@@ -406,26 +418,12 @@ abstract private class OperandBasedUse extends UseImpl {
final Operand getOperand() { result = operand }
final override Cpp::Location getLocation() { result = operand.getLocation() }
}
private class DirectUse extends OperandBasedUse, TUseImpl {
DirectUse() { this = TUseImpl(base, operand, ind) }
override int getIndirection() { isUse(_, operand, base, result, indirectionIndex) }
override int getIndirection() { isUse(_, operand, base, result, ind) }
override predicate isCertain() { isUse(true, operand, base, _, indirectionIndex) }
override predicate isCertain() { isUse(true, operand, base, _, ind) }
override Node getNode() { nodeHasOperand(result, operand, ind) }
}
private class IteratorUse extends OperandBasedUse, TIteratorUse {
IteratorUse() { this = TIteratorUse(operand, base, ind) }
override int getIndirection() { isIteratorUse(base, operand, result, ind) }
override predicate isCertain() { none() }
override Node getNode() { nodeHasOperand(result, operand, ind) }
override Node getNode() { nodeHasOperand(result, operand, indirectionIndex) }
}
pragma[nomagic]
@@ -439,15 +437,17 @@ private predicate finalParameterNodeHasParameterAndIndex(
class FinalParameterUse extends UseImpl, TFinalParameterUse {
Parameter p;
FinalParameterUse() { this = TFinalParameterUse(p, ind) }
FinalParameterUse() { this = TFinalParameterUse(p, indirectionIndex) }
override string toString() { result = "Use of " + p.toString() }
Parameter getParameter() { result = p }
int getArgumentIndex() { result = p.getIndex() }
override Node getNode() { finalParameterNodeHasParameterAndIndex(result, p, ind) }
override Node getNode() { finalParameterNodeHasParameterAndIndex(result, p, indirectionIndex) }
override int getIndirection() { result = ind + 1 }
override int getIndirection() { result = indirectionIndex + 1 }
override predicate isCertain() { any() }
@@ -544,11 +544,13 @@ class GlobalUse extends UseImpl, TGlobalUse {
GlobalLikeVariable global;
IRFunction f;
GlobalUse() { this = TGlobalUse(global, f, ind) }
GlobalUse() { this = TGlobalUse(global, f, indirectionIndex) }
override string toString() { result = "Use of " + global }
override FinalGlobalValue getNode() { result.getGlobalUse() = this }
override int getIndirection() { isGlobalUse(global, f, result, ind) }
override int getIndirection() { isGlobalUse(global, f, result, indirectionIndex) }
/** Gets the global variable associated with this use. */
GlobalLikeVariable getVariable() { result = global }
@@ -598,10 +600,9 @@ class GlobalUse extends UseImpl, TGlobalUse {
*
* See the QLDoc for `GlobalUse` for how this is used.
*/
class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
class GlobalDefImpl extends DefImpl, TGlobalDefImpl {
GlobalLikeVariable global;
IRFunction f;
int indirectionIndex;
GlobalDefImpl() { this = TGlobalDefImpl(global, f, indirectionIndex) }
@@ -611,9 +612,6 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
/** Gets the `IRFunction` whose body is evaluated after this definition. */
IRFunction getIRFunction() { result = f }
/** Gets the global variable associated with this definition. */
override int getIndirectionIndex() { result = indirectionIndex }
/** Holds if this definition or use has index `index` in block `block`. */
final override predicate hasIndexInBlock(IRBlock block, int index) {
exists(EnterFunctionInstruction enter |
@@ -627,7 +625,11 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
sourceVariableIsGlobal(result, global, f, this.getIndirection())
}
int getIndirection() { result = indirectionIndex }
override int getIndirection() { result = indirectionIndex }
override Node0Impl getValue() { none() }
override predicate isCertain() { any() }
/**
* Gets the type of this definition after specifiers have been deeply
@@ -648,60 +650,30 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
}
/**
* Holds if `defOrUse1` is a definition which is first read by `use`,
* or if `defOrUse1` is a use and `use` is a next subsequent use.
*
* In both cases, `use` can either be an explicit use written in the
* source file, or it can be a phi node as computed by the SSA library.
* Holds if there is a definition or access at index `i1` in basic block `bb1`
* and the next subsequent read is at index `i2` in basic block `bb2`.
*/
predicate adjacentDefRead(DefOrUse defOrUse1, UseOrPhi use) {
exists(IRBlock bb1, int i1, SourceVariable v |
defOrUse1
.asDefOrUse()
.hasIndexInBlock(pragma[only_bind_out](bb1), pragma[only_bind_out](i1),
pragma[only_bind_out](v))
|
exists(IRBlock bb2, int i2, DefinitionExt def |
adjacentDefReadExt(pragma[only_bind_into](def), pragma[only_bind_into](bb1),
pragma[only_bind_into](i1), pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) and
def.getSourceVariable() = v and
use.asDefOrUse().(UseImpl).hasIndexInBlock(bb2, i2, v)
)
or
exists(PhiNode phi |
lastRefRedefExt(_, bb1, i1, phi) and
use.asPhi() = phi and
phi.getSourceVariable() = pragma[only_bind_into](v)
)
predicate adjacentDefRead(IRBlock bb1, int i1, SourceVariable sv, IRBlock bb2, int i2) {
adjacentDefReadExt(_, sv, bb1, i1, bb2, i2)
or
exists(PhiNode phi |
lastRefRedefExt(_, sv, bb1, i1, phi) and
phi.definesAt(sv, bb2, i2, _)
)
}
/**
* Holds if `globalDef` represents the initial definition of a global variable that
* flows to `useOrPhi`.
*/
private predicate globalDefToUse(GlobalDef globalDef, UseOrPhi useOrPhi) {
exists(IRBlock bb1, int i1, SourceVariable v |
globalDef
.hasIndexInBlock(pragma[only_bind_out](bb1), pragma[only_bind_out](i1),
pragma[only_bind_out](v))
|
exists(IRBlock bb2, int i2 |
adjacentDefReadExt(_, pragma[only_bind_into](bb1), pragma[only_bind_into](i1),
pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) and
useOrPhi.asDefOrUse().hasIndexInBlock(bb2, i2, v)
)
or
exists(PhiNode phi |
lastRefRedefExt(_, bb1, i1, phi) and
useOrPhi.asPhi() = phi and
phi.getSourceVariable() = pragma[only_bind_into](v)
)
predicate useToNode(IRBlock bb, int i, SourceVariable sv, Node nodeTo) {
exists(Phi phi |
phi.asPhi().definesAt(sv, bb, i, _) and
nodeTo = phi.getNode()
)
or
exists(UseImpl use |
use.hasIndexInBlock(bb, i, sv) and
nodeTo = use.getNode()
)
}
private predicate useToNode(UseOrPhi use, Node nodeTo) { use.getNode() = nodeTo }
pragma[noinline]
predicate outNodeHasAddressAndIndex(
IndirectArgumentOutNode out, Operand address, int indirectionIndex
@@ -710,11 +682,19 @@ predicate outNodeHasAddressAndIndex(
out.getIndirectionIndex() = indirectionIndex
}
private predicate defToNode(Node nodeFrom, Def def, boolean uncertain) {
/**
* INTERNAL: Do not use.
*
* Holds if `node` is the node that corresponds to the definition of `def`.
*/
predicate defToNode(Node node, Def def, SourceVariable sv, IRBlock bb, int i, boolean uncertain) {
def.hasIndexInBlock(bb, i, sv) and
(
nodeHasOperand(nodeFrom, def.getValue().asOperand(), def.getIndirectionIndex())
nodeHasOperand(node, def.getValue().asOperand(), def.getIndirectionIndex())
or
nodeHasInstruction(nodeFrom, def.getValue().asInstruction(), def.getIndirectionIndex())
nodeHasInstruction(node, def.getValue().asInstruction(), def.getIndirectionIndex())
or
node.(InitialGlobalValue).getGlobalDef() = def
) and
if def.isCertain() then uncertain = false else uncertain = true
}
@@ -722,14 +702,16 @@ private predicate defToNode(Node nodeFrom, Def def, boolean uncertain) {
/**
* INTERNAL: Do not use.
*
* Holds if `nodeFrom` is the node that correspond to the definition or use `defOrUse`.
* Holds if `node` is the node that corresponds to the definition or use at
* index `i` in block `bb` of `sv`.
*
* `uncertain` is `true` if this is an uncertain definition.
*/
predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse, boolean uncertain) {
// Node -> Def
defToNode(nodeFrom, defOrUse, uncertain)
predicate nodeToDefOrUse(Node node, SourceVariable sv, IRBlock bb, int i, boolean uncertain) {
defToNode(node, _, sv, bb, i, uncertain)
or
// Node -> Use
useToNode(defOrUse, nodeFrom) and
useToNode(bb, i, sv, node) and
uncertain = false
}
@@ -738,9 +720,9 @@ predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse, boolean uncertain)
* only holds when there is no use-use relation out of `nTo`.
*/
private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
not exists(UseOrPhi defOrUse |
nodeToDefOrUse(nTo, defOrUse, _) and
adjacentDefRead(defOrUse, _)
not exists(SourceVariable sv, IRBlock bb2, int i2 |
nodeToDefOrUse(nTo, sv, bb2, i2, _) and
adjacentDefRead(bb2, i2, sv, _, _)
) and
(
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
@@ -774,60 +756,39 @@ private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
* So this predicate recurses back along conversions and `PointerArithmeticInstruction`s to find the
* first use that has provides use-use flow, and uses that target as the target of the `nodeFrom`.
*/
private predicate adjustForPointerArith(PostUpdateNode pun, UseOrPhi use) {
exists(DefOrUse defOrUse, Node adjusted |
private predicate adjustForPointerArith(PostUpdateNode pun, SourceVariable sv, IRBlock bb2, int i2) {
exists(IRBlock bb1, int i1, Node adjusted |
indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
nodeToDefOrUse(adjusted, defOrUse, _) and
adjacentDefRead(defOrUse, use)
nodeToDefOrUse(adjusted, sv, bb1, i1, _) and
adjacentDefRead(bb1, i1, sv, bb2, i2)
)
}
/**
* Holds if `nodeFrom` flows to `nodeTo` because there is `def-use` or
* `use-use` flow from `defOrUse` to `use`.
* Holds if there should be flow from `nodeFrom` to `nodeTo` because
* `nodeFrom` is a definition or use of `sv` at index `i1` at basic
* block `bb1`.
*
* `uncertain` is `true` if the `defOrUse` is an uncertain definition.
* `uncertain` is `true` if `(bb1, i1)` is a definition, and that definition
* is _not_ guaranteed to overwrite the entire allocation.
*/
private predicate localSsaFlow(
SsaDefOrUse defOrUse, Node nodeFrom, UseOrPhi use, Node nodeTo, boolean uncertain
private predicate ssaFlowImpl(
IRBlock bb1, int i1, SourceVariable sv, Node nodeFrom, Node nodeTo, boolean uncertain
) {
nodeToDefOrUse(nodeFrom, defOrUse, uncertain) and
adjacentDefRead(defOrUse, use) and
useToNode(use, nodeTo) and
exists(IRBlock bb2, int i2 |
nodeToDefOrUse(nodeFrom, sv, bb1, i1, uncertain) and
adjacentDefRead(bb1, i1, sv, bb2, i2) and
useToNode(bb2, i2, sv, nodeTo)
) and
nodeFrom != nodeTo
}
private predicate ssaFlowImpl(SsaDefOrUse defOrUse, Node nodeFrom, Node nodeTo, boolean uncertain) {
exists(UseOrPhi use |
localSsaFlow(defOrUse, nodeFrom, use, nodeTo, uncertain)
or
// Initial global variable value to a first use
nodeFrom.(InitialGlobalValue).getGlobalDef() = defOrUse and
globalDefToUse(defOrUse, use) and
useToNode(use, nodeTo) and
uncertain = false
)
}
/**
* Holds if `def` is the corresponding definition of
* the SSA library's `definition`.
*/
private DefinitionExt ssaDefinition(Def def) {
exists(IRBlock block, int i, SourceVariable sv |
def.hasIndexInBlock(block, i, sv) and
result.definesAt(sv, block, i, _)
)
}
/** Gets a node that represents the prior definition of `node`. */
private Node getAPriorDefinition(SsaDefOrUse defOrUse) {
exists(IRBlock bb, int i, SourceVariable sv, DefinitionExt def, DefOrUse defOrUse0 |
lastRefRedefExt(pragma[only_bind_into](def), pragma[only_bind_into](bb),
pragma[only_bind_into](i), ssaDefinition(defOrUse)) and
def.getSourceVariable() = sv and
defOrUse0.hasIndexInBlock(bb, i, sv) and
nodeToDefOrUse(result, defOrUse0, _)
private Node getAPriorDefinition(DefinitionExt next) {
exists(IRBlock bb, int i, SourceVariable sv |
lastRefRedefExt(_, pragma[only_bind_into](sv), pragma[only_bind_into](bb),
pragma[only_bind_into](i), next) and
nodeToDefOrUse(result, sv, bb, i, _)
)
}
@@ -879,12 +840,16 @@ private predicate modeledFlowBarrier(Node n) {
/** Holds if there is def-use or use-use flow from `nodeFrom` to `nodeTo`. */
predicate ssaFlow(Node nodeFrom, Node nodeTo) {
exists(Node nFrom, boolean uncertain, SsaDefOrUse defOrUse |
ssaFlowImpl(defOrUse, nFrom, nodeTo, uncertain) and
exists(Node nFrom, boolean uncertain, IRBlock bb, int i, SourceVariable sv |
ssaFlowImpl(bb, i, sv, nFrom, nodeTo, uncertain) and
not modeledFlowBarrier(nFrom) and
nodeFrom != nodeTo
|
if uncertain = true then nodeFrom = [nFrom, getAPriorDefinition(defOrUse)] else nodeFrom = nFrom
if uncertain = true
then
nodeFrom =
[nFrom, getAPriorDefinition(any(DefinitionExt next | next.definesAt(sv, bb, i, _)))]
else nodeFrom = nFrom
)
}
@@ -929,15 +894,15 @@ private predicate isArgumentOfCallable(DataFlowCall call, Node n) {
* Holds if there is use-use flow from `pun`'s pre-update node to `n`.
*/
private predicate postUpdateNodeToFirstUse(PostUpdateNode pun, Node n) {
exists(UseOrPhi use |
adjustForPointerArith(pun, use) and
useToNode(use, n)
exists(SourceVariable sv, IRBlock bb2, int i2 |
adjustForPointerArith(pun, sv, bb2, i2) and
useToNode(bb2, i2, sv, n)
)
}
private predicate stepUntilNotInCall(DataFlowCall call, Node n1, Node n2) {
isArgumentOfCallable(call, n1) and
exists(Node mid | localSsaFlow(_, n1, _, mid, _) |
exists(Node mid | ssaFlowImpl(_, _, _, n1, mid, _) |
isArgumentOfCallable(call, mid) and
stepUntilNotInCall(call, mid, n2)
or
@@ -984,35 +949,13 @@ predicate postUpdateFlow(PostUpdateNode pun, Node nodeTo) {
)
}
/**
* Holds if `use` is a use of `sv` and is a next adjacent use of `phi` in
* index `i1` in basic block `bb1`.
*
* This predicate exists to prevent an early join of `adjacentDefRead` with `definesAt`.
*/
pragma[nomagic]
private predicate fromPhiNodeToUse(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, UseOrPhi use) {
exists(IRBlock bb2, int i2 |
use.asDefOrUse().hasIndexInBlock(bb2, i2, sv) and
adjacentDefReadExt(pragma[only_bind_into](phi), pragma[only_bind_into](bb1),
pragma[only_bind_into](i1), pragma[only_bind_into](bb2), pragma[only_bind_into](i2))
)
}
/** Holds if `nodeTo` receives flow from the phi node `nodeFrom`. */
predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) {
exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, UseOrPhi use |
exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, IRBlock bb2, int i2 |
phi = nodeFrom.getPhiNode() and
phi.definesAt(sv, bb1, i1, _) and
useToNode(use, nodeTo)
|
fromPhiNodeToUse(phi, sv, bb1, i1, use)
or
exists(PhiNode phiTo |
phi != phiTo and
lastRefRedefExt(phi, bb1, i1, phiTo) and
nodeTo.(SsaPhiNode).getPhiNode() = phiTo
)
adjacentDefRead(bb1, i1, sv, bb2, i2) and
useToNode(bb2, i2, sv, nodeTo)
)
}
@@ -1077,8 +1020,10 @@ module SsaCached {
* path between them without any read of `def`.
*/
cached
predicate adjacentDefReadExt(DefinitionExt def, IRBlock bb1, int i1, IRBlock bb2, int i2) {
SsaImpl::adjacentDefReadExt(def, _, bb1, i1, bb2, i2)
predicate adjacentDefReadExt(
DefinitionExt def, SourceVariable sv, IRBlock bb1, int i1, IRBlock bb2, int i2
) {
SsaImpl::adjacentDefReadExt(def, sv, bb1, i1, bb2, i2)
}
/**
@@ -1087,32 +1032,38 @@ module SsaCached {
* without passing through another read or write.
*/
cached
predicate lastRefRedefExt(DefinitionExt def, IRBlock bb, int i, DefinitionExt next) {
SsaImpl::lastRefRedefExt(def, _, bb, i, next)
predicate lastRefRedefExt(
DefinitionExt def, SourceVariable sv, IRBlock bb, int i, DefinitionExt next
) {
SsaImpl::lastRefRedefExt(def, sv, bb, i, next)
}
cached
Definition phiHasInputFromBlock(PhiNode phi, IRBlock bb) {
SsaImpl::phiHasInputFromBlock(phi, result, bb)
}
cached
predicate ssaDefReachesRead(SourceVariable v, Definition def, IRBlock bb, int i) {
SsaImpl::ssaDefReachesRead(v, def, bb, i)
}
predicate variableRead = SsaInput::variableRead/4;
predicate variableWrite = SsaInput::variableWrite/4;
}
cached
private newtype TSsaDefOrUse =
TDefOrUse(DefOrUseImpl defOrUse) {
defOrUse instanceof UseImpl
or
// Like in the pruning stage, we only include definition that's live after the
// write as the final definitions computed by SSA.
exists(DefinitionExt def, SourceVariable sv, IRBlock bb, int i |
def.definesAt(sv, bb, i, _) and
defOrUse.(DefImpl).hasIndexInBlock(bb, i, sv)
)
} or
TPhi(PhiNode phi) or
TGlobalDef(GlobalDefImpl global)
private newtype TSsaDef =
TDef(DefinitionExt def) or
TPhi(PhiNode phi)
abstract private class SsaDefOrUse extends TSsaDefOrUse {
abstract private class SsaDef extends TSsaDef {
/** Gets a textual representation of this element. */
string toString() { none() }
/** Gets the underlying non-phi definition or use. */
DefOrUseImpl asDefOrUse() { none() }
DefinitionExt asDef() { none() }
/** Gets the underlying phi node. */
PhiNode asPhi() { none() }
@@ -1121,52 +1072,97 @@ abstract private class SsaDefOrUse extends TSsaDefOrUse {
abstract Location getLocation();
}
class DefOrUse extends TDefOrUse, SsaDefOrUse {
DefOrUseImpl defOrUse;
abstract class Def extends SsaDef, TDef {
DefinitionExt def;
DefOrUse() { this = TDefOrUse(defOrUse) }
Def() { this = TDef(def) }
final override DefOrUseImpl asDefOrUse() { result = defOrUse }
final override DefinitionExt asDef() { result = def }
final override Location getLocation() { result = defOrUse.getLocation() }
/** Gets the source variable underlying this SSA definition. */
final SourceVariable getSourceVariable() { result = def.getSourceVariable() }
final SourceVariable getSourceVariable() { result = defOrUse.getSourceVariable() }
override string toString() { result = defOrUse.toString() }
override string toString() { result = def.toString() }
/**
* Holds if this definition (or use) has index `index` in block `block`,
* and is a definition (or use) of the variable `sv`.
*/
predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) {
defOrUse.hasIndexInBlock(block, index, sv)
def.definesAt(sv, block, index, _)
}
/** Gets the value written by this definition, if any. */
Node0Impl getValue() { none() }
/**
* Holds if this definition is guaranteed to overwrite the entire
* destination's allocation.
*/
abstract predicate isCertain();
/** Gets the address operand written to by this definition. */
Operand getAddressOperand() { none() }
/** Gets the address written to by this definition. */
final Instruction getAddress() { result = this.getAddressOperand().getDef() }
/** Gets the indirection index of this definition. */
abstract int getIndirectionIndex();
/**
* Gets the indirection level that this definition is writing to.
* For instance, `x = y` is a definition of `x` at indirection level 1 and
* `*x = y` is a definition of `x` at indirection level 2.
*/
abstract int getIndirection();
/**
* Gets a definition that ultimately defines this SSA definition and is not
* itself a phi node.
*/
Def getAnUltimateDefinition() { result.asDef() = def.getAnUltimateDefinition() }
}
class GlobalDef extends TGlobalDef, SsaDefOrUse {
private predicate isGlobal(DefinitionExt def, GlobalDefImpl global) {
exists(SourceVariable sv, IRBlock bb, int i |
def.definesAt(sv, bb, i, _) and
global.hasIndexInBlock(bb, i, sv)
)
}
private class NonGlobalDef extends Def {
NonGlobalDef() { not isGlobal(def, _) }
final override Location getLocation() { result = this.getImpl().getLocation() }
private DefImpl getImpl() {
exists(SourceVariable sv, IRBlock bb, int i |
this.hasIndexInBlock(bb, i, sv) and
result.hasIndexInBlock(bb, i, sv)
)
}
override Node0Impl getValue() { result = this.getImpl().getValue() }
override predicate isCertain() { this.getImpl().isCertain() }
override Operand getAddressOperand() { result = this.getImpl().getAddressOperand() }
override int getIndirectionIndex() { result = this.getImpl().getIndirectionIndex() }
override int getIndirection() { result = this.getImpl().getIndirection() }
}
class GlobalDef extends Def {
GlobalDefImpl global;
GlobalDef() { this = TGlobalDef(global) }
/** Gets the location of this definition. */
final override Location getLocation() { result = global.getLocation() }
GlobalDef() { isGlobal(def, global) }
/** Gets a textual representation of this definition. */
override string toString() { result = global.toString() }
/**
* Holds if this definition has index `index` in block `block`, and
* is a definition of the variable `sv`.
*/
predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) {
global.hasIndexInBlock(block, index, sv)
}
/** Gets the indirection index of this definition. */
int getIndirection() { result = global.getIndirection() }
/** Gets the indirection index of this definition. */
int getIndirectionIndex() { result = global.getIndirectionIndex() }
final override Location getLocation() { result = global.getLocation() }
/**
* Gets the type of this definition after specifiers have been deeply stripped
@@ -1184,9 +1180,15 @@ class GlobalDef extends TGlobalDef, SsaDefOrUse {
/** Gets the global variable associated with this definition. */
GlobalLikeVariable getVariable() { result = global.getVariable() }
override predicate isCertain() { any() }
final override int getIndirectionIndex() { result = global.getIndirectionIndex() }
final override int getIndirection() { result = global.getIndirection() }
}
class Phi extends TPhi, SsaDefOrUse {
class Phi extends TPhi, SsaDef {
PhiNode phi;
Phi() { this = TPhi(phi) }
@@ -1198,64 +1200,19 @@ class Phi extends TPhi, SsaDefOrUse {
override string toString() { result = "Phi" }
SsaPhiNode getNode() { result.getPhiNode() = phi }
}
class UseOrPhi extends SsaDefOrUse {
UseOrPhi() {
this.asDefOrUse() instanceof UseImpl
or
this instanceof Phi
}
predicate hasInputFromBlock(Definition inp, IRBlock bb) { inp = phiHasInputFromBlock(phi, bb) }
final override Location getLocation() {
result = this.asDefOrUse().getLocation() or result = this.(Phi).getLocation()
}
final Node getNode() {
result = this.(Phi).getNode()
or
result = this.asDefOrUse().(UseImpl).getNode()
}
}
class Def extends DefOrUse {
override DefImpl defOrUse;
Operand getAddressOperand() { result = defOrUse.(OperandBasedDef).getAddressOperand() }
Instruction getAddress() { result = this.getAddressOperand().getDef() }
/**
* Gets the indirection index of this definition.
*
* This predicate ensures that joins go from `defOrUse` to the result
* instead of the other way around.
*/
pragma[inline]
int getIndirectionIndex() {
pragma[only_bind_into](result) = pragma[only_bind_out](defOrUse).getIndirectionIndex()
}
/**
* Gets the indirection level that this definition is writing to.
* For instance, `x = y` is a definition of `x` at indirection level 1 and
* `*x = y` is a definition of `x` at indirection level 2.
*
* This predicate ensures that joins go from `defOrUse` to the result
* instead of the other way around.
*/
pragma[inline]
int getIndirection() {
pragma[only_bind_into](result) = pragma[only_bind_out](defOrUse).getIndirection()
}
Node0Impl getValue() { result = defOrUse.getValue() }
predicate isCertain() { defOrUse.isCertain() }
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
}
private module SsaImpl = SsaImplCommon::Make<Location, SsaInput>;
/**
* An static single assignment (SSA) phi node.
*
* This is either a normal phi node or a phi-read node.
*/
class PhiNode extends SsaImpl::DefinitionExt {
PhiNode() {
this instanceof SsaImpl::PhiNode or
@@ -1269,10 +1226,30 @@ class PhiNode extends SsaImpl::DefinitionExt {
* on reads instead of writes.
*/
predicate isPhiRead() { this instanceof SsaImpl::PhiReadNode }
/** Holds if `inp` is an input to this phi node along the edge originating in `bb`. */
predicate hasInputFromBlock(Definition inp, IRBlock bb) {
inp = SsaCached::phiHasInputFromBlock(this, bb)
}
/** Gets a definition that is an input to this phi node. */
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
}
class DefinitionExt = SsaImpl::DefinitionExt;
/** An static single assignment (SSA) definition. */
class DefinitionExt extends SsaImpl::DefinitionExt {
private Definition getAPhiInputOrPriorDefinition() { result = this.(PhiNode).getAnInput() }
class UncertainWriteDefinition = SsaImpl::UncertainWriteDefinition;
/**
* Gets a definition that ultimately defines this SSA definition and is
* not itself a phi node.
*/
final DefinitionExt getAnUltimateDefinition() {
result = this.getAPhiInputOrPriorDefinition*() and
not result instanceof PhiNode
}
}
class Definition = SsaImpl::Definition;
import SsaCached

View File

@@ -246,14 +246,6 @@ private module IteratorIndirections {
baseType = super.getValueType()
}
override predicate isAdditionalDereference(Instruction deref, Operand address) {
exists(CallInstruction call |
operandForFullyConvertedCall(getAUse(deref), call) and
this = call.getStaticCallTarget().getClassAndName("operator*") and
address = call.getThisArgumentOperand()
)
}
override predicate isAdditionalWrite(Node0Impl value, Operand address, boolean certain) {
exists(CallInstruction call | call.getArgumentOperand(0) = value.asOperand() |
this = call.getStaticCallTarget().getClassAndName("operator=") and
@@ -262,16 +254,6 @@ private module IteratorIndirections {
)
}
override predicate isAdditionalTaintStep(Node node1, Node node2) {
exists(CallInstruction call |
// Taint through `operator+=` and `operator-=` on iterators.
call.getStaticCallTarget() instanceof Iterator::IteratorAssignArithmeticOperator and
node2.(IndirectArgumentOutNode).getPreUpdateNode() = node1 and
node1.(IndirectOperand).hasOperandAndIndirectionIndex(call.getArgumentOperand(0), _) and
node1.getType().getUnspecifiedType() = this
)
}
override predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
// This is a bit annoying: Consider the following snippet:
// ```
@@ -589,230 +571,6 @@ private class BaseCallInstruction extends BaseSourceVariableInstruction, CallIns
cached
private module Cached {
private import semmle.code.cpp.models.interfaces.Iterator as Interfaces
private import semmle.code.cpp.models.implementations.Iterator as Iterator
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as IO
/**
* Holds if `next` is a instruction with a memory result that potentially
* updates the memory produced by `prev`.
*/
private predicate memorySucc(Instruction prev, Instruction next) {
prev = next.(ChiInstruction).getTotal()
or
// Phi inputs can be inexact.
prev = next.(PhiInstruction).getAnInputOperand().getAnyDef()
or
prev = next.(CopyInstruction).getSourceValue()
or
exists(ReadSideEffectInstruction read |
next = read.getPrimaryInstruction() and
isAdditionalConversionFlow(_, next) and
prev = read.getSideEffectOperand().getAnyDef()
)
}
/**
* Holds if `iteratorDerefAddress` is an address of an iterator dereference (i.e., `*it`)
* that is used for a write operation that writes the value `value`. The `memory` instruction
* represents the memory that the IR's SSA analysis determined was read by the call to `operator*`.
*
* The `numberOfLoads` integer represents the number of dereferences this write corresponds to
* on the underlying container that produced the iterator.
*/
private predicate isChiAfterIteratorDef(
Instruction memory, Operand iteratorDerefAddress, Node0Impl value, int numberOfLoads
) {
exists(
BaseSourceVariableInstruction iteratorBase, ReadSideEffectInstruction read,
Operand iteratorAddress
|
numberOfLoads >= 0 and
isDef(_, value, iteratorDerefAddress, iteratorBase, numberOfLoads + 2, 0) and
isUse(_, iteratorAddress, iteratorBase, numberOfLoads + 1, 0) and
iteratorBase.getResultType() instanceof Interfaces::Iterator and
isDereference(iteratorAddress.getDef(), read.getArgumentDef().getAUse(), _) and
memory = read.getSideEffectOperand().getAnyDef()
)
}
private predicate isSource(Instruction instr, Operand iteratorAddress, int numberOfLoads) {
getAUse(instr) = iteratorAddress and
exists(BaseSourceVariableInstruction iteratorBase |
iteratorBase.getResultType() instanceof Interfaces::Iterator and
not iteratorBase.getResultType() instanceof Cpp::PointerType and
isUse(_, iteratorAddress, iteratorBase, numberOfLoads - 1, 0)
)
}
private predicate isSink(Instruction instr, CallInstruction call) {
getAUse(instr).(ArgumentOperand).getCall() = call and
// Only include operations that may modify the object that the iterator points to.
// The following is a non-exhaustive list of things that may modify the value of the
// iterator, but never the value of what the iterator points to.
// The more things we can exclude here, the faster the small dataflow-like analysis
// done by `convertsIntoArgument` will converge.
not exists(Function f | f = call.getStaticCallTarget() |
f instanceof Iterator::IteratorCrementOperator or
f instanceof Iterator::IteratorBinaryArithmeticOperator or
f instanceof Iterator::IteratorAssignArithmeticOperator or
f instanceof Iterator::IteratorCrementMemberOperator or
f instanceof Iterator::IteratorBinaryArithmeticMemberOperator or
f instanceof Iterator::IteratorAssignArithmeticMemberOperator or
f instanceof Iterator::IteratorAssignmentMemberOperator
)
}
private predicate convertsIntoArgumentFwd(Instruction instr) {
isSource(instr, _, _)
or
exists(Instruction prev | convertsIntoArgumentFwd(prev) |
conversionFlow(unique( | | getAUse(prev)), instr, false, _)
)
}
private predicate convertsIntoArgumentRev(Instruction instr) {
convertsIntoArgumentFwd(instr) and
(
isSink(instr, _)
or
exists(Instruction next | convertsIntoArgumentRev(next) |
conversionFlow(unique( | | getAUse(instr)), next, false, _)
)
)
}
private predicate convertsIntoArgument(
Operand iteratorAddress, CallInstruction call, int numberOfLoads
) {
exists(Instruction iteratorAddressDef |
isSource(iteratorAddressDef, iteratorAddress, numberOfLoads) and
isSink(iteratorAddressDef, call) and
convertsIntoArgumentRev(pragma[only_bind_into](iteratorAddressDef))
)
}
private predicate isChiAfterIteratorArgument(
Instruction memory, Operand iteratorAddress, int numberOfLoads
) {
// Ideally, `iteratorAddress` would be an `ArgumentOperand`, but there might be
// various conversions applied to it before it becomes an argument.
// So we do a small amount of flow to find the call that the iterator is passed to.
exists(CallInstruction call | convertsIntoArgument(iteratorAddress, call, numberOfLoads) |
exists(ReadSideEffectInstruction read |
read.getPrimaryInstruction() = call and
read.getSideEffectOperand().getAnyDef() = memory
)
or
exists(LoadInstruction load |
iteratorAddress.getDef() = load and
memory = load.getSourceValueOperand().getAnyDef()
)
)
}
/**
* Holds if `iterator` is a `StoreInstruction` that stores the result of some function
* returning an iterator into an address computed started at `containerBase`.
*
* For example, given a declaration like `std::vector<int>::iterator it = v.begin()`,
* the `iterator` will be the `StoreInstruction` generated by the write to `it`, and
* `containerBase` will be the address of `v`.
*/
private predicate isChiAfterBegin(
BaseSourceVariableInstruction containerBase, StoreInstruction iterator
) {
exists(
CallInstruction getIterator, Iterator::GetIteratorFunction getIteratorFunction,
IO::FunctionInput input, int i
|
getIterator = iterator.getSourceValue() and
getIteratorFunction = getIterator.getStaticCallTarget() and
getIteratorFunction.getsIterator(input, _) and
isDef(_, any(Node0Impl n | n.asInstruction() = iterator), _, _, 1, 0) and
input.isParameterDerefOrQualifierObject(i) and
isUse(_, getIterator.getArgumentOperand(i), containerBase, 0, 0)
)
}
/**
* Holds if `iteratorAddress` is an address of an iterator that is used for
* a read operation. The `memory` instruction represents the memory that
* the IR's SSA analysis determined was read by the call to `operator*`.
*
* Finally, the `numberOfLoads` integer represents the number of dereferences
* this read corresponds to on the underlying container that produced the iterator.
*/
private predicate isChiBeforeIteratorUse(
Operand iteratorAddress, Instruction memory, int numberOfLoads
) {
exists(
BaseSourceVariableInstruction iteratorBase, LoadInstruction load,
ReadSideEffectInstruction read, Operand iteratorDerefAddress
|
numberOfLoads >= 0 and
isUse(_, iteratorAddress, iteratorBase, numberOfLoads + 1, 0) and
isUse(_, iteratorDerefAddress, iteratorBase, numberOfLoads + 2, 0) and
iteratorBase.getResultType() instanceof Interfaces::Iterator and
load.getSourceAddressOperand() = iteratorDerefAddress and
read.getPrimaryInstruction() = load.getSourceAddress() and
memory = read.getSideEffectOperand().getAnyDef()
)
}
/**
* Holds if `iteratorDerefAddress` is an address of an iterator dereference (i.e., `*it`)
* that is used for a write operation that writes the value `value` to a container that
* created the iterator. `container` represents the base of the address of the container
* that was used to create the iterator.
*/
cached
predicate isIteratorDef(
BaseSourceVariableInstruction container, Operand iteratorDerefAddress, Node0Impl value,
int numberOfLoads, int indirectionIndex
) {
exists(Instruction memory, Instruction begin, int upper, int ind |
isChiAfterIteratorDef(memory, iteratorDerefAddress, value, numberOfLoads) and
memorySucc*(begin, memory) and
isChiAfterBegin(container, begin) and
upper = countIndirectionsForCppType(getResultLanguageType(container)) and
ind = numberOfLoads + [1 .. upper] and
indirectionIndex = ind - (numberOfLoads + 1)
)
}
/**
* Holds if `iteratorAddress` is an address of an iterator that is used for a
* read operation to read a value from a container that created the iterator.
* `container` represents the base of the address of the container that was used
* to create the iterator.
*/
cached
predicate isIteratorUse(
BaseSourceVariableInstruction container, Operand iteratorAddress, int numberOfLoads,
int indirectionIndex
) {
// Direct use
exists(Instruction begin, Instruction memory, int upper, int ind |
isChiBeforeIteratorUse(iteratorAddress, memory, numberOfLoads) and
memorySucc*(begin, memory) and
isChiAfterBegin(container, begin) and
upper = countIndirectionsForCppType(getResultLanguageType(container)) and
ind = numberOfLoads + [1 .. upper] and
indirectionIndex = ind - (numberOfLoads + 1)
)
or
// Use through function output
exists(Instruction memory, Instruction begin, int upper, int ind |
isChiAfterIteratorArgument(memory, iteratorAddress, numberOfLoads) and
memorySucc*(begin, memory) and
isChiAfterBegin(container, begin) and
upper = countIndirectionsForCppType(getResultLanguageType(container)) and
ind = numberOfLoads + [1 .. upper] and
indirectionIndex = ind - (numberOfLoads - 1)
)
}
/** Holds if `op` is the only use of its defining instruction, and that op is used in a conversation */
private predicate isConversion(Operand op) {
exists(Instruction def, Operand use |

View File

@@ -17,18 +17,11 @@ private import Imports::IRType
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
* by the AST-to-IR translation (`IRTempVariable`).
*/
class IRVariable extends TIRVariable {
abstract private class AbstractIRVariable extends TIRVariable {
Language::Declaration func;
IRVariable() {
this = TIRUserVariable(_, _, func) or
this = TIRTempVariable(func, _, _, _) or
this = TIRStringLiteral(func, _, _, _) or
this = TIRDynamicInitializationFlag(func, _, _)
}
/** Gets a textual representation of this element. */
string toString() { none() }
abstract string toString();
/**
* Holds if this variable's value cannot be changed within a function. Currently used for string
@@ -49,13 +42,13 @@ class IRVariable extends TIRVariable {
/**
* Gets the type of the variable.
*/
Language::LanguageType getLanguageType() { none() }
abstract Language::LanguageType getLanguageType();
/**
* Gets the AST node that declared this variable, or that introduced this
* variable as part of the AST-to-IR translation.
*/
Language::AST getAst() { none() }
abstract Language::AST getAst();
/** DEPRECATED: Alias for getAst */
deprecated Language::AST getAST() { result = this.getAst() }
@@ -64,7 +57,7 @@ class IRVariable extends TIRVariable {
* Gets an identifier string for the variable. This identifier is unique
* within the function.
*/
string getUniqueId() { none() }
abstract string getUniqueId();
/**
* Gets the source location of this variable.
@@ -74,7 +67,7 @@ class IRVariable extends TIRVariable {
/**
* Gets the IR for the function that references this variable.
*/
final IRFunction getEnclosingIRFunction() { result.getFunction() = func }
final IRFunction getEnclosingIRFunction() { result.getFunction() = this.getEnclosingFunction() }
/**
* Gets the function that references this variable.
@@ -82,10 +75,18 @@ class IRVariable extends TIRVariable {
final Language::Declaration getEnclosingFunction() { result = func }
}
/**
* A variable referenced by the IR for a function.
*
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
* by the AST-to-IR translation (`IRTempVariable`).
*/
final class IRVariable = AbstractIRVariable;
/**
* A user-declared variable referenced by the IR for a function.
*/
class IRUserVariable extends IRVariable, TIRUserVariable {
class IRUserVariable extends AbstractIRVariable, TIRUserVariable {
Language::Variable var;
Language::LanguageType type;
@@ -114,26 +115,29 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
* parameters, non-static local variables, and temporary variables.
*/
class IRAutomaticVariable extends IRVariable {
IRAutomaticVariable() {
exists(Language::Variable var |
this = TIRUserVariable(var, _, func) and
Language::isVariableAutomatic(var)
)
or
this = TIRTempVariable(func, _, _, _)
}
abstract private class AbstractIRAutomaticVariable extends AbstractIRVariable { }
/**
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
* parameters, non-static local variables, and temporary variables.
*/
final class IRAutomaticVariable = AbstractIRAutomaticVariable;
/**
* A user-declared variable that is allocated on the stack. This includes all parameters and
* non-static local variables.
*/
private class AbstractIRAutomaticUserVariable extends IRUserVariable, AbstractIRAutomaticVariable {
override Language::AutomaticVariable var;
final override Language::AutomaticVariable getVariable() { result = var }
}
/**
* A user-declared variable that is allocated on the stack. This includes all parameters and
* non-static local variables.
*/
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
override Language::AutomaticVariable var;
final override Language::AutomaticVariable getVariable() { result = var }
}
final class IRAutomaticUserVariable = AbstractIRAutomaticUserVariable;
/**
* A user-declared variable that is not allocated on the stack. This includes all global variables,
@@ -151,16 +155,10 @@ class IRStaticUserVariable extends IRUserVariable {
* A variable that is not user-declared. This includes temporary variables generated as part of IR
* construction, as well as string literals.
*/
class IRGeneratedVariable extends IRVariable {
abstract private class AbstractIRGeneratedVariable extends AbstractIRVariable {
Language::AST ast;
Language::LanguageType type;
IRGeneratedVariable() {
this = TIRTempVariable(func, ast, _, type) or
this = TIRStringLiteral(func, ast, type, _) or
this = TIRDynamicInitializationFlag(func, ast, type)
}
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAst() { result = ast }
@@ -196,12 +194,20 @@ class IRGeneratedVariable extends IRVariable {
string getBaseString() { none() }
}
/**
* A variable that is not user-declared. This includes temporary variables generated as part of IR
* construction, as well as string literals.
*/
final class IRGeneratedVariable = AbstractIRGeneratedVariable;
/**
* A temporary variable introduced by IR construction. The most common examples are the variable
* generated to hold the return value of a function, or the variable generated to hold the result of
* a condition operator (`a ? b : c`).
*/
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
class IRTempVariable extends AbstractIRGeneratedVariable, AbstractIRAutomaticVariable,
TIRTempVariable
{
TempVariableTag tag;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
@@ -241,7 +247,7 @@ class IRThrowVariable extends IRTempVariable {
* A temporary variable generated to hold the contents of all arguments passed to the `...` of a
* function that accepts a variable number of arguments.
*/
class IREllipsisVariable extends IRTempVariable, IRParameter {
class IREllipsisVariable extends IRTempVariable, AbstractIRParameter {
IREllipsisVariable() { tag = EllipsisTempVar() }
final override string toString() { result = "#ellipsis" }
@@ -252,7 +258,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
/**
* A temporary variable generated to hold the `this` pointer.
*/
class IRThisVariable extends IRTempVariable, IRParameter {
class IRThisVariable extends IRTempVariable, AbstractIRParameter {
IRThisVariable() { tag = ThisTempVar() }
final override string toString() { result = "#this" }
@@ -264,7 +270,7 @@ class IRThisVariable extends IRTempVariable, IRParameter {
* A variable generated to represent the contents of a string literal. This variable acts much like
* a read-only global variable.
*/
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
class IRStringLiteral extends AbstractIRGeneratedVariable, TIRStringLiteral {
Language::StringLiteral literal;
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
@@ -288,7 +294,7 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
* used to model the runtime initialization of static local variables in C++, as well as static
* fields in C#.
*/
class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitializationFlag {
class IRDynamicInitializationFlag extends AbstractIRGeneratedVariable, TIRDynamicInitializationFlag {
Language::Variable var;
IRDynamicInitializationFlag() {
@@ -314,24 +320,24 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial
* An IR variable which acts like a function parameter, including positional parameters and the
* temporary variables generated for `this` and ellipsis parameters.
*/
class IRParameter extends IRAutomaticVariable {
IRParameter() {
this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter
or
this = TIRTempVariable(_, _, ThisTempVar(), _)
or
this = TIRTempVariable(_, _, EllipsisTempVar(), _)
}
abstract private class AbstractIRParameter extends AbstractIRAutomaticVariable {
/**
* Gets the zero-based index of this parameter. The `this` parameter has index -1.
*/
int getIndex() { none() }
}
/**
* An IR variable which acts like a function parameter, including positional parameters and the
* temporary variables generated for `this` and ellipsis parameters.
*/
final class IRParameter = AbstractIRParameter;
/**
* An IR variable representing a positional parameter.
*/
class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable {
class IRPositionalParameter extends AbstractIRParameter, AbstractIRAutomaticUserVariable {
IRPositionalParameter() { this.getVariable() instanceof Language::Parameter }
final override int getIndex() { result = this.getVariable().(Language::Parameter).getIndex() }
}

View File

@@ -17,18 +17,11 @@ private import Imports::IRType
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
* by the AST-to-IR translation (`IRTempVariable`).
*/
class IRVariable extends TIRVariable {
abstract private class AbstractIRVariable extends TIRVariable {
Language::Declaration func;
IRVariable() {
this = TIRUserVariable(_, _, func) or
this = TIRTempVariable(func, _, _, _) or
this = TIRStringLiteral(func, _, _, _) or
this = TIRDynamicInitializationFlag(func, _, _)
}
/** Gets a textual representation of this element. */
string toString() { none() }
abstract string toString();
/**
* Holds if this variable's value cannot be changed within a function. Currently used for string
@@ -49,13 +42,13 @@ class IRVariable extends TIRVariable {
/**
* Gets the type of the variable.
*/
Language::LanguageType getLanguageType() { none() }
abstract Language::LanguageType getLanguageType();
/**
* Gets the AST node that declared this variable, or that introduced this
* variable as part of the AST-to-IR translation.
*/
Language::AST getAst() { none() }
abstract Language::AST getAst();
/** DEPRECATED: Alias for getAst */
deprecated Language::AST getAST() { result = this.getAst() }
@@ -64,7 +57,7 @@ class IRVariable extends TIRVariable {
* Gets an identifier string for the variable. This identifier is unique
* within the function.
*/
string getUniqueId() { none() }
abstract string getUniqueId();
/**
* Gets the source location of this variable.
@@ -74,7 +67,7 @@ class IRVariable extends TIRVariable {
/**
* Gets the IR for the function that references this variable.
*/
final IRFunction getEnclosingIRFunction() { result.getFunction() = func }
final IRFunction getEnclosingIRFunction() { result.getFunction() = this.getEnclosingFunction() }
/**
* Gets the function that references this variable.
@@ -82,10 +75,18 @@ class IRVariable extends TIRVariable {
final Language::Declaration getEnclosingFunction() { result = func }
}
/**
* A variable referenced by the IR for a function.
*
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
* by the AST-to-IR translation (`IRTempVariable`).
*/
final class IRVariable = AbstractIRVariable;
/**
* A user-declared variable referenced by the IR for a function.
*/
class IRUserVariable extends IRVariable, TIRUserVariable {
class IRUserVariable extends AbstractIRVariable, TIRUserVariable {
Language::Variable var;
Language::LanguageType type;
@@ -114,26 +115,29 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
* parameters, non-static local variables, and temporary variables.
*/
class IRAutomaticVariable extends IRVariable {
IRAutomaticVariable() {
exists(Language::Variable var |
this = TIRUserVariable(var, _, func) and
Language::isVariableAutomatic(var)
)
or
this = TIRTempVariable(func, _, _, _)
}
abstract private class AbstractIRAutomaticVariable extends AbstractIRVariable { }
/**
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
* parameters, non-static local variables, and temporary variables.
*/
final class IRAutomaticVariable = AbstractIRAutomaticVariable;
/**
* A user-declared variable that is allocated on the stack. This includes all parameters and
* non-static local variables.
*/
private class AbstractIRAutomaticUserVariable extends IRUserVariable, AbstractIRAutomaticVariable {
override Language::AutomaticVariable var;
final override Language::AutomaticVariable getVariable() { result = var }
}
/**
* A user-declared variable that is allocated on the stack. This includes all parameters and
* non-static local variables.
*/
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
override Language::AutomaticVariable var;
final override Language::AutomaticVariable getVariable() { result = var }
}
final class IRAutomaticUserVariable = AbstractIRAutomaticUserVariable;
/**
* A user-declared variable that is not allocated on the stack. This includes all global variables,
@@ -151,16 +155,10 @@ class IRStaticUserVariable extends IRUserVariable {
* A variable that is not user-declared. This includes temporary variables generated as part of IR
* construction, as well as string literals.
*/
class IRGeneratedVariable extends IRVariable {
abstract private class AbstractIRGeneratedVariable extends AbstractIRVariable {
Language::AST ast;
Language::LanguageType type;
IRGeneratedVariable() {
this = TIRTempVariable(func, ast, _, type) or
this = TIRStringLiteral(func, ast, type, _) or
this = TIRDynamicInitializationFlag(func, ast, type)
}
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAst() { result = ast }
@@ -196,12 +194,20 @@ class IRGeneratedVariable extends IRVariable {
string getBaseString() { none() }
}
/**
* A variable that is not user-declared. This includes temporary variables generated as part of IR
* construction, as well as string literals.
*/
final class IRGeneratedVariable = AbstractIRGeneratedVariable;
/**
* A temporary variable introduced by IR construction. The most common examples are the variable
* generated to hold the return value of a function, or the variable generated to hold the result of
* a condition operator (`a ? b : c`).
*/
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
class IRTempVariable extends AbstractIRGeneratedVariable, AbstractIRAutomaticVariable,
TIRTempVariable
{
TempVariableTag tag;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
@@ -241,7 +247,7 @@ class IRThrowVariable extends IRTempVariable {
* A temporary variable generated to hold the contents of all arguments passed to the `...` of a
* function that accepts a variable number of arguments.
*/
class IREllipsisVariable extends IRTempVariable, IRParameter {
class IREllipsisVariable extends IRTempVariable, AbstractIRParameter {
IREllipsisVariable() { tag = EllipsisTempVar() }
final override string toString() { result = "#ellipsis" }
@@ -252,7 +258,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
/**
* A temporary variable generated to hold the `this` pointer.
*/
class IRThisVariable extends IRTempVariable, IRParameter {
class IRThisVariable extends IRTempVariable, AbstractIRParameter {
IRThisVariable() { tag = ThisTempVar() }
final override string toString() { result = "#this" }
@@ -264,7 +270,7 @@ class IRThisVariable extends IRTempVariable, IRParameter {
* A variable generated to represent the contents of a string literal. This variable acts much like
* a read-only global variable.
*/
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
class IRStringLiteral extends AbstractIRGeneratedVariable, TIRStringLiteral {
Language::StringLiteral literal;
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
@@ -288,7 +294,7 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
* used to model the runtime initialization of static local variables in C++, as well as static
* fields in C#.
*/
class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitializationFlag {
class IRDynamicInitializationFlag extends AbstractIRGeneratedVariable, TIRDynamicInitializationFlag {
Language::Variable var;
IRDynamicInitializationFlag() {
@@ -314,24 +320,24 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial
* An IR variable which acts like a function parameter, including positional parameters and the
* temporary variables generated for `this` and ellipsis parameters.
*/
class IRParameter extends IRAutomaticVariable {
IRParameter() {
this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter
or
this = TIRTempVariable(_, _, ThisTempVar(), _)
or
this = TIRTempVariable(_, _, EllipsisTempVar(), _)
}
abstract private class AbstractIRParameter extends AbstractIRAutomaticVariable {
/**
* Gets the zero-based index of this parameter. The `this` parameter has index -1.
*/
int getIndex() { none() }
}
/**
* An IR variable which acts like a function parameter, including positional parameters and the
* temporary variables generated for `this` and ellipsis parameters.
*/
final class IRParameter = AbstractIRParameter;
/**
* An IR variable representing a positional parameter.
*/
class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable {
class IRPositionalParameter extends AbstractIRParameter, AbstractIRAutomaticUserVariable {
IRPositionalParameter() { this.getVariable() instanceof Language::Parameter }
final override int getIndex() { result = this.getVariable().(Language::Parameter).getIndex() }
}

View File

@@ -1163,6 +1163,8 @@ class TranslatedForStmt extends TranslatedLoop {
class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
override RangeBasedForStmt stmt;
override predicate handlesDestructorsExplicitly() { any() }
override TranslatedElement getChildInternal(int id) {
id = 0 and result = this.getInitialization()
or
@@ -1216,6 +1218,19 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
or
child = this.getUpdate() and
result = this.getCondition().getFirstInstruction(kind)
or
exists(int destructorId |
destructorId >= this.getFirstDestructorCallIndex() and
child = this.getChild(destructorId) and
result = this.getChild(destructorId + 1).getFirstInstruction(kind)
)
or
exists(int lastDestructorIndex |
lastDestructorIndex =
max(int n | exists(this.getChild(n)) and n >= this.getFirstDestructorCallIndex()) and
child = this.getChild(lastDestructorIndex) and
result = this.getParent().getChildSuccessor(this, kind)
)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -1231,7 +1246,9 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
override Instruction getChildFalseSuccessor(TranslatedCondition child, EdgeKind kind) {
child = this.getCondition() and
result = this.getParent().getChildSuccessor(this, kind)
if this.hasAnImplicitDestructorCall()
then result = this.getChild(this.getFirstDestructorCallIndex()).getFirstInstruction(kind)
else result = this.getParent().getChildSuccessor(this, kind)
}
private TranslatedDeclStmt getRangeVariableDeclStmt() {
@@ -1276,6 +1293,11 @@ class TranslatedJumpStmt extends TranslatedStmt {
override JumpStmt stmt;
override Instruction getFirstInstruction(EdgeKind kind) {
// The first instruction is a destructor call, if any.
result = this.getChildInternal(0).getFirstInstruction(kind)
or
// Otherwise, the first (and only) instruction is a `NoOp`
not exists(this.getChildInternal(0)) and
result = this.getInstruction(OnlyInstructionTag()) and
kind instanceof GotoEdge
}
@@ -1284,7 +1306,20 @@ class TranslatedJumpStmt extends TranslatedStmt {
result = this.getInstruction(OnlyInstructionTag())
}
override TranslatedElement getChildInternal(int id) { none() }
private TranslatedCall getTranslatedImplicitDestructorCall(int id) {
result.getExpr() = stmt.getImplicitDestructorCall(id)
}
override TranslatedElement getLastChild() {
result =
this.getTranslatedImplicitDestructorCall(max(int id |
exists(stmt.getImplicitDestructorCall(id))
))
}
override TranslatedElement getChildInternal(int id) {
result = this.getTranslatedImplicitDestructorCall(id)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = OnlyInstructionTag() and
@@ -1297,7 +1332,19 @@ class TranslatedJumpStmt extends TranslatedStmt {
result = getTranslatedStmt(stmt.getTarget()).getFirstInstruction(kind)
}
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { none() }
final override predicate handlesDestructorsExplicitly() { any() }
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
exists(int id | child = this.getChildInternal(id) |
// Transition to the next destructor call, if any.
result = this.getChildInternal(id + 1).getFirstInstruction(kind)
or
// And otherwise, exit this element by flowing to the target of the jump.
not exists(this.getChildInternal(id + 1)) and
kind instanceof GotoEdge and
result = this.getInstruction(OnlyInstructionTag())
)
}
}
private EdgeKind getCaseEdge(SwitchCase switchCase) {

View File

@@ -17,18 +17,11 @@ private import Imports::IRType
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
* by the AST-to-IR translation (`IRTempVariable`).
*/
class IRVariable extends TIRVariable {
abstract private class AbstractIRVariable extends TIRVariable {
Language::Declaration func;
IRVariable() {
this = TIRUserVariable(_, _, func) or
this = TIRTempVariable(func, _, _, _) or
this = TIRStringLiteral(func, _, _, _) or
this = TIRDynamicInitializationFlag(func, _, _)
}
/** Gets a textual representation of this element. */
string toString() { none() }
abstract string toString();
/**
* Holds if this variable's value cannot be changed within a function. Currently used for string
@@ -49,13 +42,13 @@ class IRVariable extends TIRVariable {
/**
* Gets the type of the variable.
*/
Language::LanguageType getLanguageType() { none() }
abstract Language::LanguageType getLanguageType();
/**
* Gets the AST node that declared this variable, or that introduced this
* variable as part of the AST-to-IR translation.
*/
Language::AST getAst() { none() }
abstract Language::AST getAst();
/** DEPRECATED: Alias for getAst */
deprecated Language::AST getAST() { result = this.getAst() }
@@ -64,7 +57,7 @@ class IRVariable extends TIRVariable {
* Gets an identifier string for the variable. This identifier is unique
* within the function.
*/
string getUniqueId() { none() }
abstract string getUniqueId();
/**
* Gets the source location of this variable.
@@ -74,7 +67,7 @@ class IRVariable extends TIRVariable {
/**
* Gets the IR for the function that references this variable.
*/
final IRFunction getEnclosingIRFunction() { result.getFunction() = func }
final IRFunction getEnclosingIRFunction() { result.getFunction() = this.getEnclosingFunction() }
/**
* Gets the function that references this variable.
@@ -82,10 +75,18 @@ class IRVariable extends TIRVariable {
final Language::Declaration getEnclosingFunction() { result = func }
}
/**
* A variable referenced by the IR for a function.
*
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
* by the AST-to-IR translation (`IRTempVariable`).
*/
final class IRVariable = AbstractIRVariable;
/**
* A user-declared variable referenced by the IR for a function.
*/
class IRUserVariable extends IRVariable, TIRUserVariable {
class IRUserVariable extends AbstractIRVariable, TIRUserVariable {
Language::Variable var;
Language::LanguageType type;
@@ -114,26 +115,29 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
* parameters, non-static local variables, and temporary variables.
*/
class IRAutomaticVariable extends IRVariable {
IRAutomaticVariable() {
exists(Language::Variable var |
this = TIRUserVariable(var, _, func) and
Language::isVariableAutomatic(var)
)
or
this = TIRTempVariable(func, _, _, _)
}
abstract private class AbstractIRAutomaticVariable extends AbstractIRVariable { }
/**
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
* parameters, non-static local variables, and temporary variables.
*/
final class IRAutomaticVariable = AbstractIRAutomaticVariable;
/**
* A user-declared variable that is allocated on the stack. This includes all parameters and
* non-static local variables.
*/
private class AbstractIRAutomaticUserVariable extends IRUserVariable, AbstractIRAutomaticVariable {
override Language::AutomaticVariable var;
final override Language::AutomaticVariable getVariable() { result = var }
}
/**
* A user-declared variable that is allocated on the stack. This includes all parameters and
* non-static local variables.
*/
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
override Language::AutomaticVariable var;
final override Language::AutomaticVariable getVariable() { result = var }
}
final class IRAutomaticUserVariable = AbstractIRAutomaticUserVariable;
/**
* A user-declared variable that is not allocated on the stack. This includes all global variables,
@@ -151,16 +155,10 @@ class IRStaticUserVariable extends IRUserVariable {
* A variable that is not user-declared. This includes temporary variables generated as part of IR
* construction, as well as string literals.
*/
class IRGeneratedVariable extends IRVariable {
abstract private class AbstractIRGeneratedVariable extends AbstractIRVariable {
Language::AST ast;
Language::LanguageType type;
IRGeneratedVariable() {
this = TIRTempVariable(func, ast, _, type) or
this = TIRStringLiteral(func, ast, type, _) or
this = TIRDynamicInitializationFlag(func, ast, type)
}
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAst() { result = ast }
@@ -196,12 +194,20 @@ class IRGeneratedVariable extends IRVariable {
string getBaseString() { none() }
}
/**
* A variable that is not user-declared. This includes temporary variables generated as part of IR
* construction, as well as string literals.
*/
final class IRGeneratedVariable = AbstractIRGeneratedVariable;
/**
* A temporary variable introduced by IR construction. The most common examples are the variable
* generated to hold the return value of a function, or the variable generated to hold the result of
* a condition operator (`a ? b : c`).
*/
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
class IRTempVariable extends AbstractIRGeneratedVariable, AbstractIRAutomaticVariable,
TIRTempVariable
{
TempVariableTag tag;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
@@ -241,7 +247,7 @@ class IRThrowVariable extends IRTempVariable {
* A temporary variable generated to hold the contents of all arguments passed to the `...` of a
* function that accepts a variable number of arguments.
*/
class IREllipsisVariable extends IRTempVariable, IRParameter {
class IREllipsisVariable extends IRTempVariable, AbstractIRParameter {
IREllipsisVariable() { tag = EllipsisTempVar() }
final override string toString() { result = "#ellipsis" }
@@ -252,7 +258,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
/**
* A temporary variable generated to hold the `this` pointer.
*/
class IRThisVariable extends IRTempVariable, IRParameter {
class IRThisVariable extends IRTempVariable, AbstractIRParameter {
IRThisVariable() { tag = ThisTempVar() }
final override string toString() { result = "#this" }
@@ -264,7 +270,7 @@ class IRThisVariable extends IRTempVariable, IRParameter {
* A variable generated to represent the contents of a string literal. This variable acts much like
* a read-only global variable.
*/
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
class IRStringLiteral extends AbstractIRGeneratedVariable, TIRStringLiteral {
Language::StringLiteral literal;
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
@@ -288,7 +294,7 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
* used to model the runtime initialization of static local variables in C++, as well as static
* fields in C#.
*/
class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitializationFlag {
class IRDynamicInitializationFlag extends AbstractIRGeneratedVariable, TIRDynamicInitializationFlag {
Language::Variable var;
IRDynamicInitializationFlag() {
@@ -314,24 +320,24 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial
* An IR variable which acts like a function parameter, including positional parameters and the
* temporary variables generated for `this` and ellipsis parameters.
*/
class IRParameter extends IRAutomaticVariable {
IRParameter() {
this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter
or
this = TIRTempVariable(_, _, ThisTempVar(), _)
or
this = TIRTempVariable(_, _, EllipsisTempVar(), _)
}
abstract private class AbstractIRParameter extends AbstractIRAutomaticVariable {
/**
* Gets the zero-based index of this parameter. The `this` parameter has index -1.
*/
int getIndex() { none() }
}
/**
* An IR variable which acts like a function parameter, including positional parameters and the
* temporary variables generated for `this` and ellipsis parameters.
*/
final class IRParameter = AbstractIRParameter;
/**
* An IR variable representing a positional parameter.
*/
class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable {
class IRPositionalParameter extends AbstractIRParameter, AbstractIRAutomaticUserVariable {
IRPositionalParameter() { this.getVariable() instanceof Language::Parameter }
final override int getIndex() { result = this.getVariable().(Language::Parameter).getIndex() }
}

View File

@@ -560,7 +560,7 @@ private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMe
TaintFunction, SideEffectFunction, AliasFunction
{
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isParameterDeref(0) and
(input.isParameterDeref(0) or input.isParameter(0)) and
output.isQualifierObject()
}
@@ -579,17 +579,34 @@ private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMe
override predicate parameterEscapesOnlyViaReturn(int index) { index = -1 }
}
/**
* A `begin` member function, or a related function, that returns an iterator.
*/
class BeginFunction extends MemberFunction {
BeginFunction() {
this.hasName(["begin", "cbegin", "rbegin", "crbegin", "before_begin", "cbefore_begin"]) and
this.getType().getUnspecifiedType() instanceof Iterator
}
}
/**
* An `end` member function, or a related function, that returns an iterator.
*/
class EndFunction extends MemberFunction {
EndFunction() {
this.hasName(["end", "cend", "rend", "crend"]) and
this.getType().getUnspecifiedType() instanceof Iterator
}
}
/**
* A `begin` or `end` member function, or a related member function, that
* returns an iterator.
*/
class BeginOrEndFunction extends MemberFunction {
BeginOrEndFunction() {
this.hasName([
"begin", "cbegin", "rbegin", "crbegin", "end", "cend", "rend", "crend", "before_begin",
"cbefore_begin"
]) and
this.getType().getUnspecifiedType() instanceof Iterator
this instanceof BeginFunction or
this instanceof EndFunction
}
}

View File

@@ -1,616 +0,0 @@
/**
* DEPRECATED: This library has been replaced with a newer version which
* provides better performance and precision. Use
* `semmle.code.cpp.valuenumbering.GlobalValueNumbering` instead.
*
* Provides an implementation of Global Value Numbering.
* See https://en.wikipedia.org/wiki/Global_value_numbering
*
* The predicate `globalValueNumber` converts an expression into a `GVN`,
* which is an abstract type representing the value of the expression. If
* two expressions have the same `GVN` then they compute the same value.
* For example:
*
* ```
* void f(int x, int y) {
* g(x+y, x+y);
* }
* ```
*
* In this example, both arguments in the call to `g` compute the same value,
* so both arguments have the same `GVN`. In other words, we can find
* this call with the following query:
*
* ```
* from FunctionCall call, GVN v
* where v = globalValueNumber(call.getArgument(0))
* and v = globalValueNumber(call.getArgument(1))
* select call
* ```
*
* The analysis is conservative, so two expressions might have different
* `GVN`s even though the actually always compute the same value. The most
* common reason for this is that the analysis cannot prove that there
* are no side-effects that might cause the computed value to change.
*/
/*
* Note to developers: the correctness of this module depends on the
* definitions of GVN, globalValueNumber, and analyzableExpr being kept in
* sync with each other. If you change this module then make sure that the
* change is symmetric across all three.
*/
import cpp
private import semmle.code.cpp.controlflow.SSA
/**
* Holds if the result is a control flow node that might change the
* value of any global variable. This is used in the implementation
* of `GVN_OtherVariable`, because we need to be quite conservative when
* we assign a value number to a global variable. For example:
*
* ```
* x = g+1;
* dosomething();
* y = g+1;
* ```
*
* It is not safe to assign the same value number to both instances
* of `g+1` in this example, because the call to `dosomething` might
* change the value of `g`.
*/
private ControlFlowNode nodeWithPossibleSideEffect() {
result instanceof Call
or
// If the lhs of an assignment is not analyzable by SSA, then
// we need to treat the assignment as having a possible side-effect.
result instanceof Assignment and not result instanceof SsaDefinition
or
result instanceof CrementOperation and not result instanceof SsaDefinition
or
exists(LocalVariable v |
result = v.getInitializer().getExpr() and not result instanceof SsaDefinition
)
or
result instanceof AsmStmt
}
/**
* Gets the entry node of the control flow graph of which `node` is a
* member.
*/
cached
private ControlFlowNode getControlFlowEntry(ControlFlowNode node) {
result = node.getControlFlowScope().getEntryPoint() and
result.getASuccessor*() = node
}
/**
* Holds if there is a control flow edge from `src` to `dst` or
* if `dst` is an expression with a possible side-effect. The idea
* is to treat side effects as entry points in the control flow
* graph so that we can use the dominator tree to find the most recent
* side-effect.
*/
private predicate sideEffectCfg(ControlFlowNode src, ControlFlowNode dst) {
src.getASuccessor() = dst
or
// Add an edge from the entry point to any node that might have a side
// effect.
dst = nodeWithPossibleSideEffect() and
src = getControlFlowEntry(dst)
}
/**
* Holds if `dominator` is the immediate dominator of `node` in
* the side-effect CFG.
*/
private predicate iDomEffect(ControlFlowNode dominator, ControlFlowNode node) =
idominance(functionEntry/1, sideEffectCfg/2)(_, dominator, node)
/**
* Gets the most recent side effect. To be more precise, `result` is a
* dominator of `node` and no side-effects can occur between `result` and
* `node`.
*
* `sideEffectCFG` has an edge from the function entry to every node with a
* side-effect. This means that every node with a side-effect has the
* function entry as its immediate dominator. So if node `x` dominates node
* `y` then there can be no side effects between `x` and `y` unless `x` is
* the function entry. So the optimal choice for `result` has the function
* entry as its immediate dominator.
*
* Example:
*
* ```
* 000: int f(int a, int b, int *p) {
* 001: int r = 0;
* 002: if (a) {
* 003: if (b) {
* 004: sideEffect1();
* 005: }
* 006: } else {
* 007: sideEffect2();
* 008: }
* 009: if (a) {
* 010: r++; // Not a side-effect, because r is an SSA variable.
* 011: }
* 012: if (b) {
* 013: r++; // Not a side-effect, because r is an SSA variable.
* 014: }
* 015: return *p;
* 016: }
* ```
*
* Suppose we want to find the most recent side-effect for the dereference
* of `p` on line 015. The `sideEffectCFG` has an edge from the function
* entry (line 000) to the side effects at lines 004 and 007. Therefore,
* the immediate dominator tree looks like this:
*
* 000 - 001 - 002 - 003
* - 004
* - 007
* - 009 - 010
* - 012 - 013
* - 015
*
* The immediate dominator path to line 015 is 000 - 009 - 012 - 015.
* Therefore, the most recent side effect for line 015 is line 009.
*/
cached
private ControlFlowNode mostRecentSideEffect(ControlFlowNode node) {
exists(ControlFlowNode entry |
functionEntry(entry) and
iDomEffect(entry, result) and
iDomEffect*(result, node)
)
}
/** Used to represent the "global value number" of an expression. */
cached
private newtype GvnBase =
GVN_IntConst(int val, Type t) { mk_IntConst(val, t, _) } or
GVN_FloatConst(float val, Type t) { mk_FloatConst(val, t, _) } or
// If the local variable does not have a defining value, then
// we use the SsaDefinition as its global value number.
GVN_UndefinedStackVariable(StackVariable x, SsaDefinition def) {
mk_UndefinedStackVariable(x, def, _)
} or
// Variables with no SSA information. As a crude (but safe)
// approximation, we use `mostRecentSideEffect` to compute a definition
// location for the variable. This ensures that two instances of the same
// global variable will only get the same value number if they are
// guaranteed to have the same value.
GVN_OtherVariable(Variable x, ControlFlowNode dominator) { mk_OtherVariable(x, dominator, _) } or
deprecated GVN_FieldAccess(GVN s, Field f) {
mk_DotFieldAccess(s, f, _) or
mk_PointerFieldAccess_with_deref(s, f, _) or
mk_ImplicitThisFieldAccess_with_deref(s, f, _)
} or
// Dereference a pointer. The value might have changed since the last
// time the pointer was dereferenced, so we need to include a definition
// location. As a crude (but safe) approximation, we use
// `mostRecentSideEffect` to compute a definition location.
deprecated GVN_Deref(GVN p, ControlFlowNode dominator) {
mk_Deref(p, dominator, _) or
mk_PointerFieldAccess(p, _, dominator, _) or
mk_ImplicitThisFieldAccess_with_qualifier(p, _, dominator, _)
} or
GVN_ThisExpr(Function fcn) {
mk_ThisExpr(fcn, _) or
mk_ImplicitThisFieldAccess(fcn, _, _, _)
} or
deprecated GVN_Conversion(Type t, GVN child) { mk_Conversion(t, child, _) } or
deprecated GVN_BinaryOp(GVN lhs, GVN rhs, string opname) { mk_BinaryOp(lhs, rhs, opname, _) } or
deprecated GVN_UnaryOp(GVN child, string opname) { mk_UnaryOp(child, opname, _) } or
deprecated GVN_ArrayAccess(GVN x, GVN i, ControlFlowNode dominator) {
mk_ArrayAccess(x, i, dominator, _)
} or
// Any expression that is not handled by the cases above is
// given a unique number based on the expression itself.
GVN_Unanalyzable(Expr e) { not analyzableExpr(e) }
/**
* A Global Value Number. A GVN is an abstract representation of the value
* computed by an expression. The relationship between `Expr` and `GVN` is
* many-to-one: every `Expr` has exactly one `GVN`, but multiple
* expressions can have the same `GVN`. If two expressions have the same
* `GVN`, it means that they compute the same value at run time. The `GVN`
* is an opaque value, so you cannot deduce what the run-time value of an
* expression will be from its `GVN`. The only use for the `GVN` of an
* expression is to find other expressions that compute the same value.
* Use the predicate `globalValueNumber` to get the `GVN` for an `Expr`.
*
* Note: `GVN` has `toString` and `getLocation` methods, so that it can be
* displayed in a results list. These work by picking an arbitrary
* expression with this `GVN` and using its `toString` and `getLocation`
* methods.
*/
deprecated class GVN extends GvnBase {
GVN() { this instanceof GvnBase }
/** Gets an expression that has this GVN. */
Expr getAnExpr() { this = globalValueNumber(result) }
/** Gets the kind of the GVN. This can be useful for debugging. */
string getKind() {
if this instanceof GVN_IntConst
then result = "IntConst"
else
if this instanceof GVN_FloatConst
then result = "FloatConst"
else
if this instanceof GVN_UndefinedStackVariable
then result = "UndefinedStackVariable"
else
if this instanceof GVN_OtherVariable
then result = "OtherVariable"
else
if this instanceof GVN_FieldAccess
then result = "FieldAccess"
else
if this instanceof GVN_Deref
then result = "Deref"
else
if this instanceof GVN_ThisExpr
then result = "ThisExpr"
else
if this instanceof GVN_Conversion
then result = "Conversion"
else
if this instanceof GVN_BinaryOp
then result = "BinaryOp"
else
if this instanceof GVN_UnaryOp
then result = "UnaryOp"
else
if this instanceof GVN_ArrayAccess
then result = "ArrayAccess"
else
if this instanceof GVN_Unanalyzable
then result = "Unanalyzable"
else result = "error"
}
/**
* Gets an example of an expression with this GVN.
* This is useful for things like implementing toString().
*/
private Expr exampleExpr() {
// Pick the expression with the minimum source location string. This is
// just an arbitrary way to pick an expression with this `GVN`.
result = min(Expr e | this = globalValueNumber(e) | e order by e.getLocation().toString())
}
/** Gets a textual representation of this element. */
string toString() { result = this.exampleExpr().toString() }
/** Gets the primary location of this element. */
Location getLocation() { result = this.exampleExpr().getLocation() }
}
private predicate analyzableIntConst(Expr e) {
strictcount(e.getValue().toInt()) = 1 and
strictcount(e.getUnspecifiedType()) = 1
}
private predicate mk_IntConst(int val, Type t, Expr e) {
analyzableIntConst(e) and
val = e.getValue().toInt() and
t = e.getUnspecifiedType()
}
private predicate analyzableFloatConst(Expr e) {
strictcount(e.getValue().toFloat()) = 1 and
strictcount(e.getUnspecifiedType()) = 1 and
not analyzableIntConst(e)
}
private predicate mk_FloatConst(float val, Type t, Expr e) {
analyzableFloatConst(e) and
val = e.getValue().toFloat() and
t = e.getUnspecifiedType()
}
private predicate analyzableStackVariable(VariableAccess access) {
strictcount(SsaDefinition def | def.getAUse(_) = access | def) = 1 and
strictcount(SsaDefinition def, Variable v | def.getAUse(v) = access | v) = 1 and
count(SsaDefinition def, Variable v |
def.getAUse(v) = access
|
def.getDefiningValue(v).getFullyConverted()
) <= 1 and
not analyzableConst(access)
}
// Note: this predicate only has a result if the access has no
// defining value. If there is a defining value, then there is no
// need to generate a fresh `GVN` for the access because `globalValueNumber`
// will follow the chain and use the GVN of the defining value.
private predicate mk_UndefinedStackVariable(
StackVariable x, SsaDefinition def, VariableAccess access
) {
analyzableStackVariable(access) and
access = def.getAUse(x) and
not exists(def.getDefiningValue(x))
}
private predicate analyzableDotFieldAccess(DotFieldAccess access) {
strictcount(access.getTarget()) = 1 and
strictcount(access.getQualifier().getFullyConverted()) = 1 and
not analyzableConst(access)
}
deprecated private predicate mk_DotFieldAccess(GVN qualifier, Field target, DotFieldAccess access) {
analyzableDotFieldAccess(access) and
target = access.getTarget() and
qualifier = globalValueNumber(access.getQualifier().getFullyConverted())
}
private predicate analyzablePointerFieldAccess(PointerFieldAccess access) {
strictcount(mostRecentSideEffect(access)) = 1 and
strictcount(access.getTarget()) = 1 and
strictcount(access.getQualifier().getFullyConverted()) = 1 and
not analyzableConst(access)
}
deprecated private predicate mk_PointerFieldAccess(
GVN qualifier, Field target, ControlFlowNode dominator, PointerFieldAccess access
) {
analyzablePointerFieldAccess(access) and
dominator = mostRecentSideEffect(access) and
target = access.getTarget() and
qualifier = globalValueNumber(access.getQualifier().getFullyConverted())
}
/**
* `obj->field` is equivalent to `(*obj).field`, so we need to wrap an
* extra `GVN_Deref` around the qualifier.
*/
deprecated private predicate mk_PointerFieldAccess_with_deref(
GVN new_qualifier, Field target, PointerFieldAccess access
) {
exists(GVN qualifier, ControlFlowNode dominator |
mk_PointerFieldAccess(qualifier, target, dominator, access) and
new_qualifier = GVN_Deref(qualifier, dominator)
)
}
private predicate analyzableImplicitThisFieldAccess(ImplicitThisFieldAccess access) {
strictcount(mostRecentSideEffect(access)) = 1 and
strictcount(access.getTarget()) = 1 and
strictcount(access.getEnclosingFunction()) = 1 and
not analyzableConst(access)
}
private predicate mk_ImplicitThisFieldAccess(
Function fcn, Field target, ControlFlowNode dominator, ImplicitThisFieldAccess access
) {
analyzableImplicitThisFieldAccess(access) and
dominator = mostRecentSideEffect(access) and
target = access.getTarget() and
fcn = access.getEnclosingFunction()
}
deprecated private predicate mk_ImplicitThisFieldAccess_with_qualifier(
GVN qualifier, Field target, ControlFlowNode dominator, ImplicitThisFieldAccess access
) {
exists(Function fcn |
mk_ImplicitThisFieldAccess(fcn, target, dominator, access) and
qualifier = GVN_ThisExpr(fcn)
)
}
deprecated private predicate mk_ImplicitThisFieldAccess_with_deref(
GVN new_qualifier, Field target, ImplicitThisFieldAccess access
) {
exists(GVN qualifier, ControlFlowNode dominator |
mk_ImplicitThisFieldAccess_with_qualifier(qualifier, target, dominator, access) and
new_qualifier = GVN_Deref(qualifier, dominator)
)
}
/**
* Holds if `access` is an access of a variable that does
* not have SSA information. (For example, because the variable
* is global.)
*/
private predicate analyzableOtherVariable(VariableAccess access) {
not access instanceof FieldAccess and
not exists(SsaDefinition def | access = def.getAUse(_)) and
strictcount(access.getTarget()) = 1 and
strictcount(mostRecentSideEffect(access)) = 1 and
not analyzableConst(access)
}
private predicate mk_OtherVariable(Variable x, ControlFlowNode dominator, VariableAccess access) {
analyzableOtherVariable(access) and
x = access.getTarget() and
dominator = mostRecentSideEffect(access)
}
private predicate analyzableConversion(Conversion conv) {
strictcount(conv.getUnspecifiedType()) = 1 and
strictcount(conv.getExpr()) = 1 and
not analyzableConst(conv)
}
deprecated private predicate mk_Conversion(Type t, GVN child, Conversion conv) {
analyzableConversion(conv) and
t = conv.getUnspecifiedType() and
child = globalValueNumber(conv.getExpr())
}
private predicate analyzableBinaryOp(BinaryOperation op) {
op.isPure() and
strictcount(op.getLeftOperand().getFullyConverted()) = 1 and
strictcount(op.getRightOperand().getFullyConverted()) = 1 and
strictcount(op.getOperator()) = 1 and
not analyzableConst(op)
}
deprecated private predicate mk_BinaryOp(GVN lhs, GVN rhs, string opname, BinaryOperation op) {
analyzableBinaryOp(op) and
lhs = globalValueNumber(op.getLeftOperand().getFullyConverted()) and
rhs = globalValueNumber(op.getRightOperand().getFullyConverted()) and
opname = op.getOperator()
}
private predicate analyzableUnaryOp(UnaryOperation op) {
not op instanceof PointerDereferenceExpr and
op.isPure() and
strictcount(op.getOperand().getFullyConverted()) = 1 and
strictcount(op.getOperator()) = 1 and
not analyzableConst(op)
}
deprecated private predicate mk_UnaryOp(GVN child, string opname, UnaryOperation op) {
analyzableUnaryOp(op) and
child = globalValueNumber(op.getOperand().getFullyConverted()) and
opname = op.getOperator()
}
private predicate analyzableThisExpr(ThisExpr thisExpr) {
strictcount(thisExpr.getEnclosingFunction()) = 1 and
not analyzableConst(thisExpr)
}
private predicate mk_ThisExpr(Function fcn, ThisExpr thisExpr) {
analyzableThisExpr(thisExpr) and
fcn = thisExpr.getEnclosingFunction()
}
private predicate analyzableArrayAccess(ArrayExpr ae) {
strictcount(ae.getArrayBase().getFullyConverted()) = 1 and
strictcount(ae.getArrayOffset().getFullyConverted()) = 1 and
strictcount(mostRecentSideEffect(ae)) = 1 and
not analyzableConst(ae)
}
deprecated private predicate mk_ArrayAccess(
GVN base, GVN offset, ControlFlowNode dominator, ArrayExpr ae
) {
analyzableArrayAccess(ae) and
base = globalValueNumber(ae.getArrayBase().getFullyConverted()) and
offset = globalValueNumber(ae.getArrayOffset().getFullyConverted()) and
dominator = mostRecentSideEffect(ae)
}
private predicate analyzablePointerDereferenceExpr(PointerDereferenceExpr deref) {
strictcount(deref.getOperand().getFullyConverted()) = 1 and
strictcount(mostRecentSideEffect(deref)) = 1 and
not analyzableConst(deref)
}
deprecated private predicate mk_Deref(GVN p, ControlFlowNode dominator, PointerDereferenceExpr deref) {
analyzablePointerDereferenceExpr(deref) and
p = globalValueNumber(deref.getOperand().getFullyConverted()) and
dominator = mostRecentSideEffect(deref)
}
/** Gets the global value number of expression `e`. */
cached
deprecated GVN globalValueNumber(Expr e) {
exists(int val, Type t |
mk_IntConst(val, t, e) and
result = GVN_IntConst(val, t)
)
or
exists(float val, Type t |
mk_FloatConst(val, t, e) and
result = GVN_FloatConst(val, t)
)
or
// Local variable with a defining value.
exists(StackVariable x, SsaDefinition def |
analyzableStackVariable(e) and
e = def.getAUse(x) and
result = globalValueNumber(def.getDefiningValue(x).getFullyConverted())
)
or
// Local variable without a defining value.
exists(StackVariable x, SsaDefinition def |
mk_UndefinedStackVariable(x, def, e) and
result = GVN_UndefinedStackVariable(x, def)
)
or
// Variable with no SSA information.
exists(Variable x, ControlFlowNode dominator |
mk_OtherVariable(x, dominator, e) and
result = GVN_OtherVariable(x, dominator)
)
or
exists(GVN qualifier, Field target |
mk_DotFieldAccess(qualifier, target, e) and
result = GVN_FieldAccess(qualifier, target)
)
or
exists(GVN qualifier, Field target |
mk_PointerFieldAccess_with_deref(qualifier, target, e) and
result = GVN_FieldAccess(qualifier, target)
)
or
exists(GVN qualifier, Field target |
mk_ImplicitThisFieldAccess_with_deref(qualifier, target, e) and
result = GVN_FieldAccess(qualifier, target)
)
or
exists(Function fcn |
mk_ThisExpr(fcn, e) and
result = GVN_ThisExpr(fcn)
)
or
exists(Type t, GVN child |
mk_Conversion(t, child, e) and
result = GVN_Conversion(t, child)
)
or
exists(GVN lhs, GVN rhs, string opname |
mk_BinaryOp(lhs, rhs, opname, e) and
result = GVN_BinaryOp(lhs, rhs, opname)
)
or
exists(GVN child, string opname |
mk_UnaryOp(child, opname, e) and
result = GVN_UnaryOp(child, opname)
)
or
exists(GVN x, GVN i, ControlFlowNode dominator |
mk_ArrayAccess(x, i, dominator, e) and
result = GVN_ArrayAccess(x, i, dominator)
)
or
exists(GVN p, ControlFlowNode dominator |
mk_Deref(p, dominator, e) and
result = GVN_Deref(p, dominator)
)
or
not analyzableExpr(e) and result = GVN_Unanalyzable(e)
}
private predicate analyzableConst(Expr e) {
analyzableIntConst(e) or
analyzableFloatConst(e)
}
/**
* Holds if the expression is explicitly handled by `globalValueNumber`.
* Unanalyzable expressions still need to be given a global value number,
* but it will be a unique number that is not shared with any other
* expression.
*/
private predicate analyzableExpr(Expr e) {
analyzableConst(e) or
analyzableStackVariable(e) or
analyzableDotFieldAccess(e) or
analyzablePointerFieldAccess(e) or
analyzableImplicitThisFieldAccess(e) or
analyzableOtherVariable(e) or
analyzableConversion(e) or
analyzableBinaryOp(e) or
analyzableUnaryOp(e) or
analyzableThisExpr(e) or
analyzableArrayAccess(e) or
analyzablePointerDereferenceExpr(e)
}

View File

@@ -1,3 +1,11 @@
## 0.9.11
### Minor Analysis Improvements
* The "Uncontrolled data used in path expression" query (`cpp/path-injection`) query produces fewer near-duplicate results.
* The "Global variable may be used before initialization" query (`cpp/global-use-before-init`) no longer raises an alert on global variables that are initialized when they are declared.
* The "Inconsistent null check of pointer" query (`cpp/inconsistent-nullness-testing`) query no longer raises an alert when the guarded check is in a macro expansion.
## 0.9.10
No user-facing changes.

View File

@@ -88,6 +88,11 @@ module TaintedPathConfig implements DataFlow::ConfigSig {
hasUpperBoundsCheck(checkedVar)
)
}
predicate isBarrierOut(DataFlow::Node node) {
// make sinks barriers so that we only report the closest instance
isSink(node)
}
}
module TaintedPath = TaintTracking::Global<TaintedPathConfig>;

View File

@@ -30,6 +30,12 @@ This is because the temporary container is not bound to a rvalue reference.
</p>
<sample src="IteratorToExpiredContainerExtendedLifetime.cpp" />
<p>
To fix <code>lifetime_of_temp_not_extended</code>, consider rewriting the code so that the lifetime of the temporary object is extended.
In <code>fixed_lifetime_of_temp_not_extended</code>, the lifetime of the temporary object has been extended by storing it in an rvalue reference.
</p>
<sample src="IteratorToExpiredContainerExtendedLifetime-fixed.cpp" />
</example>
<references>

View File

@@ -2,9 +2,10 @@
* @name Iterator to expired container
* @description Using an iterator owned by a container whose lifetime has expired may lead to unexpected behavior.
* @kind problem
* @precision high
* @precision medium
* @id cpp/iterator-to-expired-container
* @problem.severity warning
* @security-severity 8.8
* @tags reliability
* security
* external/cwe/cwe-416
@@ -61,14 +62,38 @@ DataFlow::Node getADestroyedNode(DataFlow::Node n) {
)
}
predicate destroyedToBeginSink(DataFlow::Node sink, FunctionCall fc) {
predicate destroyedToBeginSink(DataFlow::Node sink) {
exists(CallInstruction call |
call = sink.asOperand().(ThisArgumentOperand).getCall() and
fc = call.getUnconvertedResultExpression() and
call.getStaticCallTarget() instanceof BeginOrEndFunction
)
}
/**
* Holds if `node1` is the node corresponding to a qualifier of a destructor
* call and `node2` is a node that is destroyed as a result of `node1` being
* destroyed.
*/
private predicate qualifierToDestroyed(DataFlow::Node node1, DataFlow::Node node2) {
tempToDestructorSink(node1, _) and
node2 = getADestroyedNode(node1)
}
/**
* A configuration to track flow from a destroyed node to a qualifier of
* a `begin` or `end` function call.
*
* This configuration exists to prevent a cartesian product between all sinks and
* all states in `Config::isSink`.
*/
module Config0 implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { qualifierToDestroyed(_, source) }
predicate isSink(DataFlow::Node sink) { destroyedToBeginSink(sink) }
}
module Flow0 = DataFlow::Global<Config0>;
/**
* A configuration to track flow from a temporary variable to the qualifier of
* a destructor call, and subsequently to a qualifier of a call to `begin` or
@@ -78,12 +103,15 @@ module Config implements DataFlow::StateConfigSig {
newtype FlowState =
additional TempToDestructor() or
additional DestroyedToBegin(DataFlow::Node n) {
exists(DataFlow::Node thisOperand |
tempToDestructorSink(thisOperand, _) and
n = getADestroyedNode(thisOperand)
)
any(Flow0::PathNode pn | pn.isSource()).getNode() = n
}
/**
* Holds if `sink` is a qualifier to a call to `begin`, and `mid` is an
* object that is destroyed.
*/
private predicate relevant(DataFlow::Node mid, DataFlow::Node sink) { Flow0::flow(mid, sink) }
predicate isSource(DataFlow::Node source, FlowState state) {
source.asInstruction().(VariableAddressInstruction).getIRVariable() instanceof IRTempVariable and
state = TempToDestructor()
@@ -92,16 +120,16 @@ module Config implements DataFlow::StateConfigSig {
predicate isAdditionalFlowStep(
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
) {
tempToDestructorSink(node1, _) and
state1 = TempToDestructor() and
state2 = DestroyedToBegin(node2) and
node2 = getADestroyedNode(node1)
qualifierToDestroyed(node1, node2)
}
predicate isSink(DataFlow::Node sink, FlowState state) {
// Note: This is a non-trivial cartesian product!
// Hopefully, both of these sets are quite small in practice
destroyedToBeginSink(sink, _) and state instanceof DestroyedToBegin
exists(DataFlow::Node mid |
relevant(mid, sink) and
state = DestroyedToBegin(mid)
)
}
DataFlow::FlowFeature getAFeature() {
@@ -121,9 +149,9 @@ module Config implements DataFlow::StateConfigSig {
module Flow = DataFlow::GlobalWithState<Config>;
from Flow::PathNode source, Flow::PathNode sink, FunctionCall beginOrEnd, DataFlow::Node mid
from Flow::PathNode source, Flow::PathNode sink, DataFlow::Node mid
where
Flow::flowPath(source, sink) and
destroyedToBeginSink(sink.getNode(), beginOrEnd) and
destroyedToBeginSink(sink.getNode()) and
sink.getState() = Config::DestroyedToBegin(mid)
select mid, "This object is destroyed before $@ is called.", beginOrEnd, beginOrEnd.toString()
select mid, "This object is destroyed at the end of the full-expression."

View File

@@ -0,0 +1,6 @@
void fixed_lifetime_of_temp_not_extended() {
auto&& v = get_vector();
for(auto x : log_and_return_argument(v)) {
use(x); // GOOD: The lifetime of the container returned by `get_vector()` has been extended to the lifetime of `v`.
}
}

View File

@@ -8,6 +8,12 @@
When the <code>std::string</code> object is destroyed, the pointer returned by <code>c_str</code> is no
longer valid. If the pointer is used after the <code>std::string</code> object is destroyed, then the behavior is undefined.
</p>
<p>Typically, this problem occurs when a <code>std::string</code> is returned by a function call (or overloaded operator)
by value, and the result is not immediately stored in a variable by value or reference in a way that extends the lifetime of
the temporary object. The resulting temporary <code>std::string</code> object is destroyed at the end of the containing expression
statement, along with any memory returned by a call to <code>c_str</code>.
</p>
</overview>
<recommendation>
@@ -39,6 +45,8 @@ points to valid memory.
<references>
<li><a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM50-CPP.+Do+not+access+freed+memory">MEM50-CPP. Do not access freed memory</a>.</li>
<li>Microsoft Learn: <a href="https://learn.microsoft.com/en-us/cpp/cpp/temporary-objects?view=msvc-170">Temporary objects</a>.</li>
<li>cppreference.com: <a href="https://en.cppreference.com/w/cpp/language/reference_initialization#Lifetime_of_a_temporary">Lifetime of a temporary</a>.</li>
</references>
</qhelp>

View File

@@ -23,4 +23,5 @@ where
(c.getTarget() instanceof StdStringCStr or c.getTarget() instanceof StdStringData) and
isTemporary(c.getQualifier().getFullyConverted())
select c,
"The underlying string object is destroyed after the call to '" + c.getTarget() + "' returns."
"The underlying temporary string object is destroyed after the call to '" + c.getTarget() +
"' returns."

View File

@@ -0,0 +1,4 @@
---
category: newQuery
---
* Added a new query, `cpp/iterator-to-expired-container`, to detect the creation of iterators owned by a temporary objects that are about to be destroyed.

View File

@@ -1,5 +1,7 @@
---
category: minorAnalysis
---
## 0.9.11
### Minor Analysis Improvements
* The "Uncontrolled data used in path expression" query (`cpp/path-injection`) query produces fewer near-duplicate results.
* The "Global variable may be used before initialization" query (`cpp/global-use-before-init`) no longer raises an alert on global variables that are initialized when they are declared.
* The "Inconsistent null check of pointer" query (`cpp/inconsistent-nullness-testing`) query no longer raises an alert when the guarded check is in a macro expansion.
* The "Inconsistent null check of pointer" query (`cpp/inconsistent-nullness-testing`) query no longer raises an alert when the guarded check is in a macro expansion.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.9.10
lastReleaseVersion: 0.9.11

View File

@@ -0,0 +1,11 @@
void test()
{
char *foo = malloc(100);
// BAD
if (foo)
free(foo);
// GOOD
free(foo);
}

View File

@@ -0,0 +1,18 @@
<!DOCTYPE qhelp SYSTEM "qhelp.dtd">
<qhelp>
<overview>
<p>The <code>free</code> function, which deallocates heap memory, may accept a NULL pointer and take no action. Therefore, it is unnecessary to check its argument for the value of NULL before a function call to <code>free</code>. As such, these guards may hinder performance and readability.</p>
</overview>
<recommendation>
<p>A function call to <code>free</code> should not depend upon the value of its argument. Delete the <code>if</code> condition preceeding a function call to <code>free</code> when its only purpose is to check the value of the pointer to be freed.</p>
</recommendation>
<example>
<sample src = "GuardedFree.cpp" />
</example>
<references>
<li>
The Open Group Base Specifications Issue 7, 2018 Edition:
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html">free - free allocated memory</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,26 @@
/**
* @name Guarded Free
* @description NULL-condition guards before function calls to the memory-deallocation
* function free(3) are unnecessary, because passing NULL to free(3) is a no-op.
* @kind problem
* @problem.severity recommendation
* @precision very-high
* @id cpp/guarded-free
* @tags maintainability
* readability
* experimental
*/
import cpp
import semmle.code.cpp.controlflow.Guards
class FreeCall extends FunctionCall {
FreeCall() { this.getTarget().hasGlobalName("free") }
}
from GuardCondition gc, FreeCall fc, Variable v, BasicBlock bb
where
gc.ensuresEq(v.getAnAccess(), 0, bb, false) and
fc.getArgument(0) = v.getAnAccess() and
bb = fc.getEnclosingStmt()
select gc, "unnecessary NULL check before call to $@", fc, "free"

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 0.9.11-dev
version: 0.9.12-dev
groups:
- cpp
- queries

View File

@@ -1,11 +0,0 @@
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:680:17:680:17 | call to begin | call to begin |
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:680:17:680:17 | call to end | call to end |
| test.cpp:683:31:683:32 | call to at | This object is destroyed before $@ is called. | test.cpp:683:17:683:17 | call to begin | call to begin |
| test.cpp:683:31:683:32 | call to at | This object is destroyed before $@ is called. | test.cpp:683:17:683:17 | call to end | call to end |
| test.cpp:689:46:689:58 | pointer to ~vector output argument | This object is destroyed before $@ is called. | test.cpp:689:60:689:62 | call to end | call to end |
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:703:19:703:23 | call to begin | call to begin |
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:703:36:703:38 | call to end | call to end |
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:750:17:750:17 | call to begin | call to begin |
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:750:17:750:17 | call to end | call to end |
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:759:17:759:17 | call to begin | call to begin |
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:759:17:759:17 | call to end | call to end |

View File

@@ -1 +0,0 @@
experimental/Security/CWE/CWE-416/IteratorToExpiredContainer.ql

View File

@@ -148,6 +148,24 @@ astGuardsCompare
| 109 | y < 0+0 when ... < ... is true |
| 109 | y >= 0+0 when ... < ... is false |
| 109 | y >= 0+0 when ... \|\| ... is false |
| 126 | 1 != 0 when 1 is true |
| 126 | 1 != 0 when ... && ... is true |
| 126 | 1 == 0 when 1 is false |
| 126 | call to test3_condition != 0 when ... && ... is true |
| 126 | call to test3_condition != 0 when call to test3_condition is true |
| 126 | call to test3_condition == 0 when call to test3_condition is false |
| 131 | b != 0 when b is true |
| 131 | b == 0 when b is false |
| 137 | 0 != 0 when 0 is true |
| 137 | 0 == 0 when 0 is false |
| 146 | ! ... != 0 when ! ... is true |
| 146 | ! ... == 0 when ! ... is false |
| 152 | x != 0 when ... && ... is true |
| 152 | x != 0 when x is true |
| 152 | x == 0 when x is false |
| 152 | y != 0 when ... && ... is true |
| 152 | y != 0 when y is true |
| 152 | y == 0 when y is false |
| 156 | ... + ... != x+0 when ... == ... is false |
| 156 | ... + ... == x+0 when ... == ... is true |
| 156 | x != ... + ...+0 when ... == ... is false |
@@ -186,6 +204,8 @@ astGuardsCompare
| 175 | call to foo != 0+0 when ... == ... is false |
| 175 | call to foo == 0 when ... == ... is true |
| 175 | call to foo == 0+0 when ... == ... is true |
| 181 | x != 0 when x is true |
| 181 | x == 0 when x is false |
astGuardsControl
| test.c:7:9:7:13 | ... > ... | false | 10 | 11 |
| test.c:7:9:7:13 | ... > ... | true | 7 | 9 |
@@ -487,8 +507,27 @@ astGuardsEnsure_const
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 109 | 109 |
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 126 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 131 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 132 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 134 | 123 |
| test.c:126:7:126:28 | ... && ... | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
| test.c:126:7:126:28 | ... && ... | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
| test.c:126:12:126:26 | call to test3_condition | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
| test.c:131:7:131:7 | b | test.c:131:7:131:7 | b | != | 0 | 131 | 132 |
| test.c:137:7:137:7 | 0 | test.c:137:7:137:7 | 0 | == | 0 | 142 | 136 |
| test.c:146:7:146:8 | ! ... | test.c:146:7:146:8 | ! ... | != | 0 | 146 | 147 |
| test.c:152:10:152:10 | x | test.c:152:10:152:10 | x | != | 0 | 151 | 152 |
| test.c:152:10:152:10 | x | test.c:152:10:152:10 | x | != | 0 | 152 | 152 |
| test.c:152:10:152:15 | ... && ... | test.c:152:10:152:10 | x | != | 0 | 151 | 152 |
| test.c:152:10:152:15 | ... && ... | test.c:152:15:152:15 | y | != | 0 | 151 | 152 |
| test.c:152:15:152:15 | y | test.c:152:15:152:15 | y | != | 0 | 151 | 152 |
| test.c:175:13:175:32 | ... == ... | test.c:175:13:175:15 | call to foo | != | 0 | 175 | 175 |
| test.c:175:13:175:32 | ... == ... | test.c:175:13:175:15 | call to foo | == | 0 | 175 | 175 |
| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | != | 0 | 181 | 182 |
| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | != | 0 | 186 | 180 |
| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | == | 0 | 183 | 184 |
| test.cpp:18:8:18:10 | call to get | test.cpp:18:8:18:10 | call to get | != | 0 | 19 | 19 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
@@ -640,6 +679,20 @@ irGuardsCompare
| 109 | y < 0+0 when CompareLT: ... < ... is true |
| 109 | y >= 0 when CompareLT: ... < ... is false |
| 109 | y >= 0+0 when CompareLT: ... < ... is false |
| 126 | 1 != 0 when Constant: 1 is true |
| 126 | 1 == 0 when Constant: 1 is false |
| 126 | call to test3_condition != 0 when Call: call to test3_condition is true |
| 126 | call to test3_condition == 0 when Call: call to test3_condition is false |
| 131 | b != 0 when Load: b is true |
| 131 | b == 0 when Load: b is false |
| 137 | 0 != 0 when Constant: 0 is true |
| 137 | 0 == 0 when Constant: 0 is false |
| 146 | ! ... != 0 when LogicalNot: ! ... is true |
| 146 | ! ... == 0 when LogicalNot: ! ... is false |
| 152 | x != 0 when Load: x is true |
| 152 | x == 0 when Load: x is false |
| 152 | y != 0 when Load: y is true |
| 152 | y == 0 when Load: y is false |
| 156 | ... + ... != x+0 when CompareEQ: ... == ... is false |
| 156 | ... + ... == x+0 when CompareEQ: ... == ... is true |
| 156 | x != ... + ...+0 when CompareEQ: ... == ... is false |
@@ -678,6 +731,8 @@ irGuardsCompare
| 175 | call to foo != 0+0 when CompareEQ: ... == ... is false |
| 175 | call to foo == 0 when CompareEQ: ... == ... is true |
| 175 | call to foo == 0+0 when CompareEQ: ... == ... is true |
| 181 | x != 0 when Load: x is true |
| 181 | x == 0 when Load: x is false |
irGuardsControl
| test.c:7:9:7:13 | CompareGT: ... > ... | false | 11 | 11 |
| test.c:7:9:7:13 | CompareGT: ... > ... | true | 8 | 8 |
@@ -999,8 +1054,21 @@ irGuardsEnsure_const
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:9 | Load: x | != | 0 | 109 | 109 |
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:9 | Load: x | != | 0 | 113 | 113 |
| test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:19:109:19 | Load: y | >= | 0 | 113 | 113 |
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 126 | 126 |
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 127 | 127 |
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 131 | 131 |
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 132 | 132 |
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 134 | 134 |
| test.c:126:12:126:26 | Call: call to test3_condition | test.c:126:12:126:26 | Call: call to test3_condition | != | 0 | 127 | 127 |
| test.c:131:7:131:7 | Load: b | test.c:131:7:131:7 | Load: b | != | 0 | 132 | 132 |
| test.c:137:7:137:7 | Constant: 0 | test.c:137:7:137:7 | Constant: 0 | == | 0 | 142 | 142 |
| test.c:146:7:146:8 | LogicalNot: ! ... | test.c:146:7:146:8 | LogicalNot: ! ... | != | 0 | 147 | 147 |
| test.c:152:10:152:10 | Load: x | test.c:152:10:152:10 | Load: x | != | 0 | 152 | 152 |
| test.c:152:15:152:15 | Load: y | test.c:152:15:152:15 | Load: y | != | 0 | 152 | 152 |
| test.c:175:13:175:32 | CompareEQ: ... == ... | test.c:175:13:175:15 | Call: call to foo | != | 0 | 175 | 175 |
| test.c:175:13:175:32 | CompareEQ: ... == ... | test.c:175:13:175:15 | Call: call to foo | == | 0 | 175 | 175 |
| test.c:181:9:181:9 | Load: x | test.c:181:9:181:9 | Load: x | != | 0 | 182 | 182 |
| test.c:181:9:181:9 | Load: x | test.c:181:9:181:9 | Load: x | == | 0 | 184 | 184 |
| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:10 | Call: call to get | != | 0 | 19 | 19 |
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | != | -1 | 34 | 34 |
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 30 | 30 |

View File

@@ -26,6 +26,12 @@
| test.c:137:7:137:7 | 0 |
| test.c:146:7:146:8 | ! ... |
| test.c:146:8:146:8 | x |
| test.c:152:8:152:8 | p |
| test.c:158:8:158:9 | ! ... |
| test.c:158:9:158:9 | p |
| test.c:164:8:164:8 | s |
| test.c:170:8:170:9 | ! ... |
| test.c:170:9:170:9 | s |
| test.cpp:18:8:18:10 | call to get |
| test.cpp:31:7:31:13 | ... == ... |
| test.cpp:42:13:42:20 | call to getABool |

View File

@@ -149,3 +149,23 @@
| 111 | 0.0 == i+0 when ... != ... is false |
| 111 | i != 0.0+0 when ... != ... is true |
| 111 | i == 0.0+0 when ... != ... is false |
| 126 | 1 != 0 when 1 is true |
| 126 | 1 != 0 when ... && ... is true |
| 126 | 1 == 0 when 1 is false |
| 126 | call to test3_condition != 0 when ... && ... is true |
| 126 | call to test3_condition != 0 when call to test3_condition is true |
| 126 | call to test3_condition == 0 when call to test3_condition is false |
| 131 | b != 0 when b is true |
| 131 | b == 0 when b is false |
| 137 | 0 != 0 when 0 is true |
| 137 | 0 == 0 when 0 is false |
| 146 | ! ... != 0 when ! ... is true |
| 146 | ! ... == 0 when ! ... is false |
| 152 | p != 0 when p is true |
| 152 | p == 0 when p is false |
| 158 | ! ... != 0 when ! ... is true |
| 158 | ! ... == 0 when ! ... is false |
| 164 | s != 0 when s is true |
| 164 | s == 0 when s is false |
| 170 | ! ... != 0 when ! ... is true |
| 170 | ! ... == 0 when ! ... is false |

View File

@@ -79,6 +79,12 @@
| test.c:137:7:137:7 | 0 | false | 142 | 136 |
| test.c:146:7:146:8 | ! ... | true | 146 | 147 |
| test.c:146:8:146:8 | x | false | 146 | 147 |
| test.c:152:8:152:8 | p | true | 152 | 154 |
| test.c:158:8:158:9 | ! ... | true | 158 | 160 |
| test.c:158:9:158:9 | p | false | 158 | 160 |
| test.c:164:8:164:8 | s | true | 164 | 166 |
| test.c:170:8:170:9 | ! ... | true | 170 | 172 |
| test.c:170:9:170:9 | s | false | 170 | 172 |
| test.cpp:18:8:18:10 | call to get | true | 19 | 19 |
| test.cpp:31:7:31:13 | ... == ... | false | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | false | 34 | 34 |

View File

@@ -234,6 +234,21 @@ unary
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:19:109:19 | y | >= | 0 | 113 | 113 |
| test.c:109:19:109:23 | ... < ... | test.c:109:19:109:19 | y | >= | 0 | 113 | 113 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 126 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 131 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 132 |
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 134 | 123 |
| test.c:126:7:126:28 | ... && ... | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
| test.c:126:7:126:28 | ... && ... | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
| test.c:126:12:126:26 | call to test3_condition | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
| test.c:131:7:131:7 | b | test.c:131:7:131:7 | b | != | 0 | 131 | 132 |
| test.c:137:7:137:7 | 0 | test.c:137:7:137:7 | 0 | == | 0 | 142 | 136 |
| test.c:146:7:146:8 | ! ... | test.c:146:7:146:8 | ! ... | != | 0 | 146 | 147 |
| test.c:152:8:152:8 | p | test.c:152:8:152:8 | p | != | 0 | 152 | 154 |
| test.c:158:8:158:9 | ! ... | test.c:158:8:158:9 | ! ... | != | 0 | 158 | 160 |
| test.c:164:8:164:8 | s | test.c:164:8:164:8 | s | != | 0 | 164 | 166 |
| test.c:170:8:170:9 | ! ... | test.c:170:8:170:9 | ! ... | != | 0 | 170 | 172 |
| test.cpp:18:8:18:10 | call to get | test.cpp:18:8:18:10 | call to get | != | 0 | 19 | 19 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |

View File

@@ -147,3 +147,27 @@ void test5(int x) {
test3();
}
}
void test6(char* p) {
if(p) {
}
}
void test7(char* p) {
if(!p) {
}
}
void test8(short s) {
if(s) {
}
}
void test9(short s) {
if(!s) {
}
}

View File

@@ -228,7 +228,6 @@ irFlow
| test.cpp:333:17:333:22 | call to source | test.cpp:337:10:337:18 | globalVar |
| test.cpp:333:17:333:22 | call to source | test.cpp:339:10:339:18 | globalVar |
| test.cpp:333:17:333:22 | call to source | test.cpp:343:10:343:18 | globalVar |
| test.cpp:333:17:333:22 | call to source | test.cpp:349:10:349:18 | globalVar |
| test.cpp:347:17:347:22 | call to source | test.cpp:337:10:337:18 | globalVar |
| test.cpp:347:17:347:22 | call to source | test.cpp:339:10:339:18 | globalVar |
| test.cpp:347:17:347:22 | call to source | test.cpp:343:10:343:18 | globalVar |
@@ -260,7 +259,6 @@ irFlow
| test.cpp:562:17:562:31 | *call to indirect_source | test.cpp:566:10:566:19 | * ... |
| test.cpp:562:17:562:31 | *call to indirect_source | test.cpp:568:10:568:19 | * ... |
| test.cpp:562:17:562:31 | *call to indirect_source | test.cpp:572:10:572:19 | * ... |
| test.cpp:562:17:562:31 | *call to indirect_source | test.cpp:578:10:578:19 | * ... |
| test.cpp:576:17:576:31 | *call to indirect_source | test.cpp:566:10:566:19 | * ... |
| test.cpp:576:17:576:31 | *call to indirect_source | test.cpp:568:10:568:19 | * ... |
| test.cpp:576:17:576:31 | *call to indirect_source | test.cpp:572:10:572:19 | * ... |

View File

@@ -346,7 +346,7 @@ namespace FlowThroughGlobals {
void taintAndCall() {
globalVar = source();
calledAfterTaint();
sink(globalVar); // $ ast ir=333:17 ir=347:17
sink(globalVar); // $ ast ir
}
}
@@ -575,7 +575,7 @@ namespace IndirectFlowThroughGlobals {
void taintAndCall() {
globalInt = indirect_source();
calledAfterTaint();
sink(*globalInt); // $ ir=562:17 ir=576:17 MISSING: ast=562:17 ast=576:17
sink(*globalInt); // $ ir MISSING: ast=562:17 ast=576:17
}
}

View File

@@ -66,8 +66,8 @@ public:
insert_iterator_by_trait operator++(int);
insert_iterator_by_trait &operator--();
insert_iterator_by_trait operator--(int);
insert_iterator_by_trait operator*();
insert_iterator_by_trait operator=(int x);
insert_iterator_by_trait& operator*();
insert_iterator_by_trait& operator=(int x);
};
template<>

View File

@@ -389,7 +389,7 @@ void test_vector_output_iterator(int b) {
*i9 = source();
taint_vector_output_iterator(i9);
sink(v9); // $ ast=330:10 MISSING: ir SPURIOUS: ast=389:8
sink(v9); // $ ast=330:10 ir SPURIOUS: ast=389:8
std::vector<int>::iterator i10 = v10.begin();
vector_iterator_assign_wrapper(i10, 10);
@@ -440,14 +440,14 @@ void test_vector_inserter(char *source_string) {
std::vector<std::string> out;
auto it = std::back_inserter(out);
*++it = std::string(source_string);
sink(out); // $ ast MISSING: ir
sink(out); // $ ast,ir
}
{
std::vector<int> out;
auto it = std::back_inserter(out);
*++it = source();
sink(out); // $ ast MISSING: ir
sink(out); // $ ast,ir
}
}

View File

@@ -19411,6 +19411,12 @@ ir.cpp:
# 2207| Value = [CharLiteral] 97
# 2207| ValueCategory = prvalue
# 2208| getStmt(2): [BreakStmt] break;
# 2212| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
# 2212| Type = [VoidType] void
# 2212| ValueCategory = prvalue
# 2212| getQualifier(): [VariableAccess] x
# 2212| Type = [Class] ClassWithDestructor
# 2212| ValueCategory = lvalue
# 2209| getStmt(3): [SwitchCase] default:
# 2210| getStmt(4): [ExprStmt] ExprStmt
# 2210| getExpr(): [FunctionCall] call to set_x
@@ -19424,6 +19430,12 @@ ir.cpp:
# 2210| Value = [CharLiteral] 98
# 2210| ValueCategory = prvalue
# 2211| getStmt(5): [BreakStmt] break;
# 2212| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
# 2212| Type = [VoidType] void
# 2212| ValueCategory = prvalue
# 2212| getQualifier(): [VariableAccess] x
# 2212| Type = [Class] ClassWithDestructor
# 2212| ValueCategory = lvalue
# 2212| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
# 2212| Type = [VoidType] void
# 2212| ValueCategory = prvalue
@@ -22442,6 +22454,157 @@ ir.cpp:
#-----| Type = [Class] ClassWithDestructor
#-----| ValueCategory = lvalue
# 2499| getStmt(4): [ReturnStmt] return ...
# 2501| [TopLevelFunction] void destruction_in_switch_1(int)
# 2501| <params>:
# 2501| getParameter(0): [Parameter] c
# 2501| Type = [IntType] int
# 2501| getEntryPoint(): [BlockStmt] { ... }
# 2502| getStmt(0): [SwitchStmt] switch (...) ...
# 2502| getExpr(): [VariableAccess] c
# 2502| Type = [IntType] int
# 2502| ValueCategory = prvalue(load)
# 2502| getStmt(): [BlockStmt] { ... }
# 2503| getStmt(0): [SwitchCase] case ...:
# 2503| getExpr(): [Literal] 0
# 2503| Type = [IntType] int
# 2503| Value = [Literal] 0
# 2503| ValueCategory = prvalue
# 2503| getStmt(1): [BlockStmt] { ... }
# 2504| getStmt(0): [DeclStmt] declaration
# 2504| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
# 2504| Type = [Class] ClassWithDestructor
# 2504| getVariable().getInitializer(): [Initializer] initializer for x
# 2504| getExpr(): [ConstructorCall] call to ClassWithDestructor
# 2504| Type = [VoidType] void
# 2504| ValueCategory = prvalue
# 2505| getStmt(1): [BreakStmt] break;
# 2506| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
# 2506| Type = [VoidType] void
# 2506| ValueCategory = prvalue
# 2506| getQualifier(): [VariableAccess] x
# 2506| Type = [Class] ClassWithDestructor
# 2506| ValueCategory = lvalue
# 2506| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
# 2506| Type = [VoidType] void
# 2506| ValueCategory = prvalue
# 2506| getQualifier(): [VariableAccess] x
# 2506| Type = [Class] ClassWithDestructor
# 2506| ValueCategory = lvalue
# 2507| getStmt(1): [LabelStmt] label ...:
# 2508| getStmt(2): [ReturnStmt] return ...
# 2510| [TopLevelFunction] void destruction_in_switch_2(int)
# 2510| <params>:
# 2510| getParameter(0): [Parameter] c
# 2510| Type = [IntType] int
# 2510| getEntryPoint(): [BlockStmt] { ... }
# 2511| getStmt(0): [SwitchStmt] switch (...) ...
# 2511| getInitialization(): [DeclStmt] declaration
# 2511| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
# 2511| Type = [Class] ClassWithDestructor
# 2511| getVariable().getInitializer(): [Initializer] initializer for y
# 2511| getExpr(): [ConstructorCall] call to ClassWithDestructor
# 2511| Type = [VoidType] void
# 2511| ValueCategory = prvalue
# 2511| getExpr(): [VariableAccess] c
# 2511| Type = [IntType] int
# 2511| ValueCategory = prvalue(load)
# 2511| getStmt(): [BlockStmt] { ... }
# 2512| getStmt(0): [SwitchCase] case ...:
# 2512| getExpr(): [Literal] 0
# 2512| Type = [IntType] int
# 2512| Value = [Literal] 0
# 2512| ValueCategory = prvalue
# 2512| getStmt(1): [BlockStmt] { ... }
# 2513| getStmt(0): [BreakStmt] break;
# 2518| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
# 2518| Type = [VoidType] void
# 2518| ValueCategory = prvalue
# 2518| getQualifier(): [VariableAccess] y
# 2518| Type = [Class] ClassWithDestructor
# 2518| ValueCategory = lvalue
# 2515| getStmt(2): [SwitchCase] default:
# 2515| getStmt(3): [BlockStmt] { ... }
# 2516| getStmt(0): [BreakStmt] break;
# 2518| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
# 2518| Type = [VoidType] void
# 2518| ValueCategory = prvalue
# 2518| getQualifier(): [VariableAccess] y
# 2518| Type = [Class] ClassWithDestructor
# 2518| ValueCategory = lvalue
# 2518| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
# 2518| Type = [VoidType] void
# 2518| ValueCategory = prvalue
# 2518| getQualifier(): [VariableAccess] y
# 2518| Type = [Class] ClassWithDestructor
# 2518| ValueCategory = lvalue
# 2518| getStmt(1): [LabelStmt] label ...:
# 2519| getStmt(2): [ReturnStmt] return ...
# 2521| [TopLevelFunction] void destruction_in_switch_3(int)
# 2521| <params>:
# 2521| getParameter(0): [Parameter] c
# 2521| Type = [IntType] int
# 2521| getEntryPoint(): [BlockStmt] { ... }
# 2522| getStmt(0): [SwitchStmt] switch (...) ...
# 2522| getInitialization(): [DeclStmt] declaration
# 2522| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
# 2522| Type = [Class] ClassWithDestructor
# 2522| getVariable().getInitializer(): [Initializer] initializer for y
# 2522| getExpr(): [ConstructorCall] call to ClassWithDestructor
# 2522| Type = [VoidType] void
# 2522| ValueCategory = prvalue
# 2522| getExpr(): [VariableAccess] c
# 2522| Type = [IntType] int
# 2522| ValueCategory = prvalue(load)
# 2522| getStmt(): [BlockStmt] { ... }
# 2523| getStmt(0): [SwitchCase] case ...:
# 2523| getExpr(): [Literal] 0
# 2523| Type = [IntType] int
# 2523| Value = [Literal] 0
# 2523| ValueCategory = prvalue
# 2523| getStmt(1): [BlockStmt] { ... }
# 2524| getStmt(0): [DeclStmt] declaration
# 2524| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
# 2524| Type = [Class] ClassWithDestructor
# 2524| getVariable().getInitializer(): [Initializer] initializer for x
# 2524| getExpr(): [ConstructorCall] call to ClassWithDestructor
# 2524| Type = [VoidType] void
# 2524| ValueCategory = prvalue
# 2525| getStmt(1): [BreakStmt] break;
# 2526| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
# 2526| Type = [VoidType] void
# 2526| ValueCategory = prvalue
# 2526| getQualifier(): [VariableAccess] x
# 2526| Type = [Class] ClassWithDestructor
# 2526| ValueCategory = lvalue
# 2530| getImplicitDestructorCall(1): [DestructorCall] call to ~ClassWithDestructor
# 2530| Type = [VoidType] void
# 2530| ValueCategory = prvalue
# 2530| getQualifier(): [VariableAccess] y
# 2530| Type = [Class] ClassWithDestructor
# 2530| ValueCategory = lvalue
# 2526| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
# 2526| Type = [VoidType] void
# 2526| ValueCategory = prvalue
# 2526| getQualifier(): [VariableAccess] x
# 2526| Type = [Class] ClassWithDestructor
# 2526| ValueCategory = lvalue
# 2527| getStmt(2): [SwitchCase] default:
# 2527| getStmt(3): [BlockStmt] { ... }
# 2528| getStmt(0): [BreakStmt] break;
# 2530| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
# 2530| Type = [VoidType] void
# 2530| ValueCategory = prvalue
# 2530| getQualifier(): [VariableAccess] y
# 2530| Type = [Class] ClassWithDestructor
# 2530| ValueCategory = lvalue
# 2530| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
# 2530| Type = [VoidType] void
# 2530| ValueCategory = prvalue
# 2530| getQualifier(): [VariableAccess] y
# 2530| Type = [Class] ClassWithDestructor
# 2530| ValueCategory = lvalue
# 2530| getStmt(1): [LabelStmt] label ...:
# 2531| getStmt(2): [ReturnStmt] return ...
perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| <params>:

View File

@@ -15438,42 +15438,58 @@ ir.cpp:
#-----| Default -> Block 6
# 2206| Block 5
# 2206| v2206_1(void) = NoOp :
# 2207| r2207_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2207| r2207_2(glval<unknown>) = FunctionAddress[set_x] :
# 2207| r2207_3(char) = Constant[97] :
# 2207| v2207_4(void) = Call[set_x] : func:r2207_2, this:r2207_1, 0:r2207_3
# 2207| m2207_5(unknown) = ^CallSideEffect : ~m2205_6
# 2207| m2207_6(unknown) = Chi : total:m2205_6, partial:m2207_5
# 2207| v2207_7(void) = ^IndirectReadSideEffect[-1] : &:r2207_1, m2205_8
# 2207| m2207_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2207_1
# 2207| m2207_9(ClassWithDestructor) = Chi : total:m2205_8, partial:m2207_8
# 2208| v2208_1(void) = NoOp :
# 2206| v2206_1(void) = NoOp :
# 2207| r2207_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2207| r2207_2(glval<unknown>) = FunctionAddress[set_x] :
# 2207| r2207_3(char) = Constant[97] :
# 2207| v2207_4(void) = Call[set_x] : func:r2207_2, this:r2207_1, 0:r2207_3
# 2207| m2207_5(unknown) = ^CallSideEffect : ~m2205_6
# 2207| m2207_6(unknown) = Chi : total:m2205_6, partial:m2207_5
# 2207| v2207_7(void) = ^IndirectReadSideEffect[-1] : &:r2207_1, m2205_8
# 2207| m2207_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2207_1
# 2207| m2207_9(ClassWithDestructor) = Chi : total:m2205_8, partial:m2207_8
# 2212| r2212_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2212| r2212_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2212| v2212_3(void) = Call[~ClassWithDestructor] : func:r2212_2, this:r2212_1
# 2212| m2212_4(unknown) = ^CallSideEffect : ~m2207_6
# 2212| m2212_5(unknown) = Chi : total:m2207_6, partial:m2212_4
# 2212| v2212_6(void) = ^IndirectReadSideEffect[-1] : &:r2212_1, m2207_9
# 2212| m2212_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2212_1
# 2212| m2212_8(ClassWithDestructor) = Chi : total:m2207_9, partial:m2212_7
# 2208| v2208_1(void) = NoOp :
#-----| Goto -> Block 7
# 2209| Block 6
# 2209| v2209_1(void) = NoOp :
# 2210| r2210_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2210| r2210_2(glval<unknown>) = FunctionAddress[set_x] :
# 2210| r2210_3(char) = Constant[98] :
# 2210| v2210_4(void) = Call[set_x] : func:r2210_2, this:r2210_1, 0:r2210_3
# 2210| m2210_5(unknown) = ^CallSideEffect : ~m2205_6
# 2210| m2210_6(unknown) = Chi : total:m2205_6, partial:m2210_5
# 2210| v2210_7(void) = ^IndirectReadSideEffect[-1] : &:r2210_1, m2205_8
# 2210| m2210_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2210_1
# 2210| m2210_9(ClassWithDestructor) = Chi : total:m2205_8, partial:m2210_8
# 2211| v2211_1(void) = NoOp :
# 2209| v2209_1(void) = NoOp :
# 2210| r2210_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2210| r2210_2(glval<unknown>) = FunctionAddress[set_x] :
# 2210| r2210_3(char) = Constant[98] :
# 2210| v2210_4(void) = Call[set_x] : func:r2210_2, this:r2210_1, 0:r2210_3
# 2210| m2210_5(unknown) = ^CallSideEffect : ~m2205_6
# 2210| m2210_6(unknown) = Chi : total:m2205_6, partial:m2210_5
# 2210| v2210_7(void) = ^IndirectReadSideEffect[-1] : &:r2210_1, m2205_8
# 2210| m2210_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2210_1
# 2210| m2210_9(ClassWithDestructor) = Chi : total:m2205_8, partial:m2210_8
# 2212| r2212_9(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2212| r2212_10(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2212| v2212_11(void) = Call[~ClassWithDestructor] : func:r2212_10, this:r2212_9
# 2212| m2212_12(unknown) = ^CallSideEffect : ~m2210_6
# 2212| m2212_13(unknown) = Chi : total:m2210_6, partial:m2212_12
# 2212| v2212_14(void) = ^IndirectReadSideEffect[-1] : &:r2212_9, m2210_9
# 2212| m2212_15(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2212_9
# 2212| m2212_16(ClassWithDestructor) = Chi : total:m2210_9, partial:m2212_15
# 2211| v2211_1(void) = NoOp :
#-----| Goto -> Block 7
# 2212| Block 7
# 2212| m2212_1(unknown) = Phi : from 5:~m2207_6, from 6:~m2210_6
# 2212| v2212_2(void) = NoOp :
# 2212| m2212_17(unknown) = Phi : from 5:~m2212_5, from 6:~m2212_13
# 2212| v2212_18(void) = NoOp :
# 2214| r2214_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2214| m2214_2(ClassWithDestructor) = Uninitialized[x] : &:r2214_1
# 2214| r2214_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
# 2214| v2214_4(void) = Call[ClassWithDestructor] : func:r2214_3, this:r2214_1
# 2214| m2214_5(unknown) = ^CallSideEffect : ~m2212_1
# 2214| m2214_6(unknown) = Chi : total:m2212_1, partial:m2214_5
# 2214| m2214_5(unknown) = ^CallSideEffect : ~m2212_17
# 2214| m2214_6(unknown) = Chi : total:m2212_17, partial:m2214_5
# 2214| m2214_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2214_1
# 2214| m2214_8(ClassWithDestructor) = Chi : total:m2214_2, partial:m2214_7
# 2215| r2215_1(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
@@ -15584,10 +15600,18 @@ ir.cpp:
# 2215| r2215_73(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2215_61
#-----| Goto (back edge) -> Block 8
# 2218| Block 10
# 2215| Block 10
# 2215| r2215_74(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2215| r2215_75(glval<unknown>) = FunctionAddress[~vector] :
# 2215| v2215_76(void) = Call[~vector] : func:r2215_75, this:r2215_74
# 2215| m2215_77(unknown) = ^CallSideEffect : ~m2215_50
# 2215| m2215_78(unknown) = Chi : total:m2215_50, partial:m2215_77
# 2215| v2215_79(void) = ^IndirectReadSideEffect[-1] : &:r2215_74, ~m2215_78
# 2215| m2215_80(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2215_74
# 2215| m2215_81(unknown) = Chi : total:m2215_78, partial:m2215_80
# 2218| r2218_1(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2218| m2218_2(vector<ClassWithDestructor>) = Uninitialized[ys] : &:r2218_1
# 2218| m2218_3(unknown) = Chi : total:m2215_50, partial:m2218_2
# 2218| m2218_3(unknown) = Chi : total:m2215_81, partial:m2218_2
# 2218| r2218_4(glval<unknown>) = FunctionAddress[vector] :
# 2218| r2218_5(glval<ClassWithDestructor>) = VariableAddress[#temp2218:45] :
# 2218| r2218_6(glval<ClassWithDestructor>) = VariableAddress[x] :
@@ -15737,10 +15761,18 @@ ir.cpp:
# 2233| m2233_8(ClassWithDestructor) = Chi : total:m2214_8, partial:m2233_7
#-----| Goto -> Block 1
# 2224| Block 15
# 2218| Block 15
# 2218| r2218_90(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2218| r2218_91(glval<unknown>) = FunctionAddress[~vector] :
# 2218| v2218_92(void) = Call[~vector] : func:r2218_91, this:r2218_90
# 2218| m2218_93(unknown) = ^CallSideEffect : ~m2218_50
# 2218| m2218_94(unknown) = Chi : total:m2218_50, partial:m2218_93
# 2218| v2218_95(void) = ^IndirectReadSideEffect[-1] : &:r2218_90, ~m2218_94
# 2218| m2218_96(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_90
# 2218| m2218_97(unknown) = Chi : total:m2218_94, partial:m2218_96
# 2224| r2224_1(glval<vector<int>>) = VariableAddress[ys] :
# 2224| m2224_2(vector<int>) = Uninitialized[ys] : &:r2224_1
# 2224| m2224_3(unknown) = Chi : total:m2218_50, partial:m2224_2
# 2224| m2224_3(unknown) = Chi : total:m2218_97, partial:m2224_2
# 2224| r2224_4(glval<unknown>) = FunctionAddress[vector] :
# 2224| r2224_5(int) = Constant[1] :
# 2224| v2224_6(void) = Call[vector] : func:r2224_4, this:r2224_1, 0:r2224_5
@@ -15846,10 +15878,18 @@ ir.cpp:
# 2233| m2233_16(ClassWithDestructor) = Chi : total:m2214_8, partial:m2233_15
#-----| Goto -> Block 1
# 2229| Block 20
# 2224| Block 20
# 2224| r2224_62(glval<vector<int>>) = VariableAddress[ys] :
# 2224| r2224_63(glval<unknown>) = FunctionAddress[~vector] :
# 2224| v2224_64(void) = Call[~vector] : func:r2224_63, this:r2224_62
# 2224| m2224_65(unknown) = ^CallSideEffect : ~m2224_38
# 2224| m2224_66(unknown) = Chi : total:m2224_38, partial:m2224_65
# 2224| v2224_67(void) = ^IndirectReadSideEffect[-1] : &:r2224_62, ~m2224_66
# 2224| m2224_68(vector<int>) = ^IndirectMayWriteSideEffect[-1] : &:r2224_62
# 2224| m2224_69(unknown) = Chi : total:m2224_66, partial:m2224_68
# 2229| r2229_1(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2229| m2229_2(vector<ClassWithDestructor>) = Uninitialized[ys] : &:r2229_1
# 2229| m2229_3(unknown) = Chi : total:m2224_38, partial:m2229_2
# 2229| m2229_3(unknown) = Chi : total:m2224_69, partial:m2229_2
# 2229| r2229_4(glval<unknown>) = FunctionAddress[vector] :
# 2229| r2229_5(glval<ClassWithDestructor>) = VariableAddress[#temp2229:45] :
# 2229| r2229_6(glval<ClassWithDestructor>) = VariableAddress[x] :
@@ -15978,16 +16018,24 @@ ir.cpp:
# 2229| r2229_73(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2229_61
#-----| Goto (back edge) -> Block 21
# 2233| Block 23
# 2233| v2233_17(void) = NoOp :
# 2233| r2233_18(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2233| r2233_19(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2233| v2233_20(void) = Call[~ClassWithDestructor] : func:r2233_19, this:r2233_18
# 2233| m2233_21(unknown) = ^CallSideEffect : ~m2229_50
# 2233| m2233_22(unknown) = Chi : total:m2229_50, partial:m2233_21
# 2233| v2233_23(void) = ^IndirectReadSideEffect[-1] : &:r2233_18, m2214_8
# 2233| m2233_24(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2233_18
# 2233| m2233_25(ClassWithDestructor) = Chi : total:m2214_8, partial:m2233_24
# 2229| Block 23
# 2229| r2229_74(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2229| r2229_75(glval<unknown>) = FunctionAddress[~vector] :
# 2229| v2229_76(void) = Call[~vector] : func:r2229_75, this:r2229_74
# 2229| m2229_77(unknown) = ^CallSideEffect : ~m2229_50
# 2229| m2229_78(unknown) = Chi : total:m2229_50, partial:m2229_77
# 2229| v2229_79(void) = ^IndirectReadSideEffect[-1] : &:r2229_74, ~m2229_78
# 2229| m2229_80(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2229_74
# 2229| m2229_81(unknown) = Chi : total:m2229_78, partial:m2229_80
# 2233| v2233_17(void) = NoOp :
# 2233| r2233_18(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2233| r2233_19(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2233| v2233_20(void) = Call[~ClassWithDestructor] : func:r2233_19, this:r2233_18
# 2233| m2233_21(unknown) = ^CallSideEffect : ~m2229_81
# 2233| m2233_22(unknown) = Chi : total:m2229_81, partial:m2233_21
# 2233| v2233_23(void) = ^IndirectReadSideEffect[-1] : &:r2233_18, m2214_8
# 2233| m2233_24(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2233_18
# 2233| m2233_25(ClassWithDestructor) = Chi : total:m2214_8, partial:m2233_24
#-----| Goto -> Block 1
# 2198| Block 24
@@ -17958,6 +18006,177 @@ ir.cpp:
# 2484| v2484_8(void) = AliasedUse : ~m2497_4
# 2484| v2484_9(void) = ExitFunction :
# 2501| void destruction_in_switch_1(int)
# 2501| Block 0
# 2501| v2501_1(void) = EnterFunction :
# 2501| m2501_2(unknown) = AliasedDefinition :
# 2501| m2501_3(unknown) = InitializeNonLocal :
# 2501| m2501_4(unknown) = Chi : total:m2501_2, partial:m2501_3
# 2501| r2501_5(glval<int>) = VariableAddress[c] :
# 2501| m2501_6(int) = InitializeParameter[c] : &:r2501_5
# 2502| r2502_1(glval<int>) = VariableAddress[c] :
# 2502| r2502_2(int) = Load[c] : &:r2502_1, m2501_6
# 2502| v2502_3(void) = Switch : r2502_2
#-----| Case[0] -> Block 1
#-----| Default -> Block 2
# 2503| Block 1
# 2503| v2503_1(void) = NoOp :
# 2504| r2504_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2504| m2504_2(ClassWithDestructor) = Uninitialized[x] : &:r2504_1
# 2504| r2504_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
# 2504| v2504_4(void) = Call[ClassWithDestructor] : func:r2504_3, this:r2504_1
# 2504| m2504_5(unknown) = ^CallSideEffect : ~m2501_4
# 2504| m2504_6(unknown) = Chi : total:m2501_4, partial:m2504_5
# 2504| m2504_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2504_1
# 2504| m2504_8(ClassWithDestructor) = Chi : total:m2504_2, partial:m2504_7
# 2506| r2506_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2506| r2506_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2506| v2506_3(void) = Call[~ClassWithDestructor] : func:r2506_2, this:r2506_1
# 2506| m2506_4(unknown) = ^CallSideEffect : ~m2504_6
# 2506| m2506_5(unknown) = Chi : total:m2504_6, partial:m2506_4
# 2506| v2506_6(void) = ^IndirectReadSideEffect[-1] : &:r2506_1, m2504_8
# 2506| m2506_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2506_1
# 2506| m2506_8(ClassWithDestructor) = Chi : total:m2504_8, partial:m2506_7
# 2505| v2505_1(void) = NoOp :
#-----| Goto -> Block 2
# 2507| Block 2
# 2507| m2507_1(unknown) = Phi : from 0:~m2501_4, from 1:~m2506_5
# 2507| v2507_2(void) = NoOp :
# 2508| v2508_1(void) = NoOp :
# 2501| v2501_7(void) = ReturnVoid :
# 2501| v2501_8(void) = AliasedUse : ~m2507_1
# 2501| v2501_9(void) = ExitFunction :
# 2510| void destruction_in_switch_2(int)
# 2510| Block 0
# 2510| v2510_1(void) = EnterFunction :
# 2510| m2510_2(unknown) = AliasedDefinition :
# 2510| m2510_3(unknown) = InitializeNonLocal :
# 2510| m2510_4(unknown) = Chi : total:m2510_2, partial:m2510_3
# 2510| r2510_5(glval<int>) = VariableAddress[c] :
# 2510| m2510_6(int) = InitializeParameter[c] : &:r2510_5
# 2511| r2511_1(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2511| m2511_2(ClassWithDestructor) = Uninitialized[y] : &:r2511_1
# 2511| r2511_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
# 2511| v2511_4(void) = Call[ClassWithDestructor] : func:r2511_3, this:r2511_1
# 2511| m2511_5(unknown) = ^CallSideEffect : ~m2510_4
# 2511| m2511_6(unknown) = Chi : total:m2510_4, partial:m2511_5
# 2511| m2511_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2511_1
# 2511| m2511_8(ClassWithDestructor) = Chi : total:m2511_2, partial:m2511_7
# 2511| r2511_9(glval<int>) = VariableAddress[c] :
# 2511| r2511_10(int) = Load[c] : &:r2511_9, m2510_6
# 2511| v2511_11(void) = Switch : r2511_10
#-----| Case[0] -> Block 1
#-----| Default -> Block 2
# 2512| Block 1
# 2512| v2512_1(void) = NoOp :
# 2518| r2518_1(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2518| r2518_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2518| v2518_3(void) = Call[~ClassWithDestructor] : func:r2518_2, this:r2518_1
# 2518| m2518_4(unknown) = ^CallSideEffect : ~m2511_6
# 2518| m2518_5(unknown) = Chi : total:m2511_6, partial:m2518_4
# 2518| v2518_6(void) = ^IndirectReadSideEffect[-1] : &:r2518_1, m2511_8
# 2518| m2518_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2518_1
# 2518| m2518_8(ClassWithDestructor) = Chi : total:m2511_8, partial:m2518_7
# 2513| v2513_1(void) = NoOp :
#-----| Goto -> Block 3
# 2515| Block 2
# 2515| v2515_1(void) = NoOp :
# 2518| r2518_9(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2518| r2518_10(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2518| v2518_11(void) = Call[~ClassWithDestructor] : func:r2518_10, this:r2518_9
# 2518| m2518_12(unknown) = ^CallSideEffect : ~m2511_6
# 2518| m2518_13(unknown) = Chi : total:m2511_6, partial:m2518_12
# 2518| v2518_14(void) = ^IndirectReadSideEffect[-1] : &:r2518_9, m2511_8
# 2518| m2518_15(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2518_9
# 2518| m2518_16(ClassWithDestructor) = Chi : total:m2511_8, partial:m2518_15
# 2516| v2516_1(void) = NoOp :
#-----| Goto -> Block 3
# 2518| Block 3
# 2518| m2518_17(unknown) = Phi : from 1:~m2518_5, from 2:~m2518_13
# 2518| v2518_18(void) = NoOp :
# 2519| v2519_1(void) = NoOp :
# 2510| v2510_7(void) = ReturnVoid :
# 2510| v2510_8(void) = AliasedUse : ~m2518_17
# 2510| v2510_9(void) = ExitFunction :
# 2521| void destruction_in_switch_3(int)
# 2521| Block 0
# 2521| v2521_1(void) = EnterFunction :
# 2521| m2521_2(unknown) = AliasedDefinition :
# 2521| m2521_3(unknown) = InitializeNonLocal :
# 2521| m2521_4(unknown) = Chi : total:m2521_2, partial:m2521_3
# 2521| r2521_5(glval<int>) = VariableAddress[c] :
# 2521| m2521_6(int) = InitializeParameter[c] : &:r2521_5
# 2522| r2522_1(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2522| m2522_2(ClassWithDestructor) = Uninitialized[y] : &:r2522_1
# 2522| r2522_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
# 2522| v2522_4(void) = Call[ClassWithDestructor] : func:r2522_3, this:r2522_1
# 2522| m2522_5(unknown) = ^CallSideEffect : ~m2521_4
# 2522| m2522_6(unknown) = Chi : total:m2521_4, partial:m2522_5
# 2522| m2522_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2522_1
# 2522| m2522_8(ClassWithDestructor) = Chi : total:m2522_2, partial:m2522_7
# 2522| r2522_9(glval<int>) = VariableAddress[c] :
# 2522| r2522_10(int) = Load[c] : &:r2522_9, m2521_6
# 2522| v2522_11(void) = Switch : r2522_10
#-----| Case[0] -> Block 1
#-----| Default -> Block 2
# 2523| Block 1
# 2523| v2523_1(void) = NoOp :
# 2524| r2524_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2524| m2524_2(ClassWithDestructor) = Uninitialized[x] : &:r2524_1
# 2524| r2524_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
# 2524| v2524_4(void) = Call[ClassWithDestructor] : func:r2524_3, this:r2524_1
# 2524| m2524_5(unknown) = ^CallSideEffect : ~m2522_6
# 2524| m2524_6(unknown) = Chi : total:m2522_6, partial:m2524_5
# 2524| m2524_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2524_1
# 2524| m2524_8(ClassWithDestructor) = Chi : total:m2524_2, partial:m2524_7
# 2526| r2526_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2526| r2526_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2526| v2526_3(void) = Call[~ClassWithDestructor] : func:r2526_2, this:r2526_1
# 2526| m2526_4(unknown) = ^CallSideEffect : ~m2524_6
# 2526| m2526_5(unknown) = Chi : total:m2524_6, partial:m2526_4
# 2526| v2526_6(void) = ^IndirectReadSideEffect[-1] : &:r2526_1, m2524_8
# 2526| m2526_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2526_1
# 2526| m2526_8(ClassWithDestructor) = Chi : total:m2524_8, partial:m2526_7
# 2530| r2530_1(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2530| r2530_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2530| v2530_3(void) = Call[~ClassWithDestructor] : func:r2530_2, this:r2530_1
# 2530| m2530_4(unknown) = ^CallSideEffect : ~m2526_5
# 2530| m2530_5(unknown) = Chi : total:m2526_5, partial:m2530_4
# 2530| v2530_6(void) = ^IndirectReadSideEffect[-1] : &:r2530_1, m2522_8
# 2530| m2530_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2530_1
# 2530| m2530_8(ClassWithDestructor) = Chi : total:m2522_8, partial:m2530_7
# 2525| v2525_1(void) = NoOp :
#-----| Goto -> Block 3
# 2527| Block 2
# 2527| v2527_1(void) = NoOp :
# 2530| r2530_9(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2530| r2530_10(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2530| v2530_11(void) = Call[~ClassWithDestructor] : func:r2530_10, this:r2530_9
# 2530| m2530_12(unknown) = ^CallSideEffect : ~m2522_6
# 2530| m2530_13(unknown) = Chi : total:m2522_6, partial:m2530_12
# 2530| v2530_14(void) = ^IndirectReadSideEffect[-1] : &:r2530_9, m2522_8
# 2530| m2530_15(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2530_9
# 2530| m2530_16(ClassWithDestructor) = Chi : total:m2522_8, partial:m2530_15
# 2528| v2528_1(void) = NoOp :
#-----| Goto -> Block 3
# 2530| Block 3
# 2530| m2530_17(unknown) = Phi : from 1:~m2530_5, from 2:~m2530_13
# 2530| v2530_18(void) = NoOp :
# 2531| v2531_1(void) = NoOp :
# 2521| v2521_7(void) = ReturnVoid :
# 2521| v2521_8(void) = AliasedUse : ~m2530_17
# 2521| v2521_9(void) = ExitFunction :
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0

View File

@@ -2498,4 +2498,36 @@ void destructor_without_block(bool b)
ClassWithDestructor g;
}
void destruction_in_switch_1(int c) {
switch (c) {
case 0: {
ClassWithDestructor x;
break;
}
}
}
void destruction_in_switch_2(int c) {
switch (ClassWithDestructor y; c) {
case 0: {
break;
}
default: {
break;
}
}
}
void destruction_in_switch_3(int c) {
switch (ClassWithDestructor y; c) {
case 0: {
ClassWithDestructor x;
break;
}
default: {
break;
}
}
}
// semmle-extractor-options: -std=c++20 --clang

View File

@@ -14207,40 +14207,52 @@ ir.cpp:
#-----| Default -> Block 8
# 2206| Block 7
# 2206| v2206_1(void) = NoOp :
# 2207| r2207_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2207| r2207_2(glval<unknown>) = FunctionAddress[set_x] :
# 2207| r2207_3(char) = Constant[97] :
# 2207| v2207_4(void) = Call[set_x] : func:r2207_2, this:r2207_1, 0:r2207_3
# 2207| mu2207_5(unknown) = ^CallSideEffect : ~m?
# 2207| v2207_6(void) = ^IndirectReadSideEffect[-1] : &:r2207_1, ~m?
# 2207| mu2207_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2207_1
# 2208| v2208_1(void) = NoOp :
#-----| Goto -> Block 10
# 2209| Block 8
# 2209| v2209_1(void) = NoOp :
# 2210| r2210_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2210| r2210_2(glval<unknown>) = FunctionAddress[set_x] :
# 2210| r2210_3(char) = Constant[98] :
# 2210| v2210_4(void) = Call[set_x] : func:r2210_2, this:r2210_1, 0:r2210_3
# 2210| mu2210_5(unknown) = ^CallSideEffect : ~m?
# 2210| v2210_6(void) = ^IndirectReadSideEffect[-1] : &:r2210_1, ~m?
# 2210| mu2210_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2210_1
# 2211| v2211_1(void) = NoOp :
#-----| Goto -> Block 10
# 2212| Block 9
# 2206| v2206_1(void) = NoOp :
# 2207| r2207_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2207| r2207_2(glval<unknown>) = FunctionAddress[set_x] :
# 2207| r2207_3(char) = Constant[97] :
# 2207| v2207_4(void) = Call[set_x] : func:r2207_2, this:r2207_1, 0:r2207_3
# 2207| mu2207_5(unknown) = ^CallSideEffect : ~m?
# 2207| v2207_6(void) = ^IndirectReadSideEffect[-1] : &:r2207_1, ~m?
# 2207| mu2207_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2207_1
# 2212| r2212_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2212| r2212_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2212| v2212_3(void) = Call[~ClassWithDestructor] : func:r2212_2, this:r2212_1
# 2212| mu2212_4(unknown) = ^CallSideEffect : ~m?
# 2212| v2212_5(void) = ^IndirectReadSideEffect[-1] : &:r2212_1, ~m?
# 2212| mu2212_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2212_1
# 2208| v2208_1(void) = NoOp :
#-----| Goto -> Block 10
# 2209| Block 8
# 2209| v2209_1(void) = NoOp :
# 2210| r2210_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2210| r2210_2(glval<unknown>) = FunctionAddress[set_x] :
# 2210| r2210_3(char) = Constant[98] :
# 2210| v2210_4(void) = Call[set_x] : func:r2210_2, this:r2210_1, 0:r2210_3
# 2210| mu2210_5(unknown) = ^CallSideEffect : ~m?
# 2210| v2210_6(void) = ^IndirectReadSideEffect[-1] : &:r2210_1, ~m?
# 2210| mu2210_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2210_1
# 2212| r2212_7(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2212| r2212_8(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2212| v2212_9(void) = Call[~ClassWithDestructor] : func:r2212_8, this:r2212_7
# 2212| mu2212_10(unknown) = ^CallSideEffect : ~m?
# 2212| v2212_11(void) = ^IndirectReadSideEffect[-1] : &:r2212_7, ~m?
# 2212| mu2212_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2212_7
# 2211| v2211_1(void) = NoOp :
#-----| Goto -> Block 10
# 2212| Block 9
# 2212| r2212_13(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2212| r2212_14(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2212| v2212_15(void) = Call[~ClassWithDestructor] : func:r2212_14, this:r2212_13
# 2212| mu2212_16(unknown) = ^CallSideEffect : ~m?
# 2212| v2212_17(void) = ^IndirectReadSideEffect[-1] : &:r2212_13, ~m?
# 2212| mu2212_18(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2212_13
#-----| Goto -> Block 10
# 2212| Block 10
# 2212| v2212_7(void) = NoOp :
# 2212| v2212_19(void) = NoOp :
# 2214| r2214_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2214| mu2214_2(ClassWithDestructor) = Uninitialized[x] : &:r2214_1
# 2214| r2214_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
@@ -14306,7 +14318,7 @@ ir.cpp:
# 2215| r2215_41(bool) = Call[operator!=] : func:r2215_35, this:r0_7, 0:r0_13
#-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~m?
# 2215| v2215_42(void) = ConditionalBranch : r2215_41
#-----| False -> Block 14
#-----| False -> Block 13
#-----| True -> Block 12
# 2215| Block 12
@@ -14340,15 +14352,12 @@ ir.cpp:
#-----| Goto (back edge) -> Block 11
# 2215| Block 13
# 2215| r2215_61(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2215| r2215_62(glval<unknown>) = FunctionAddress[~vector] :
# 2215| v2215_63(void) = Call[~vector] : func:r2215_62, this:r2215_61
# 2215| mu2215_64(unknown) = ^CallSideEffect : ~m?
# 2215| v2215_65(void) = ^IndirectReadSideEffect[-1] : &:r2215_61, ~m?
# 2215| mu2215_66(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2215_61
#-----| Goto -> Block 14
# 2218| Block 14
# 2215| r2215_61(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2215| r2215_62(glval<unknown>) = FunctionAddress[~vector] :
# 2215| v2215_63(void) = Call[~vector] : func:r2215_62, this:r2215_61
# 2215| mu2215_64(unknown) = ^CallSideEffect : ~m?
# 2215| v2215_65(void) = ^IndirectReadSideEffect[-1] : &:r2215_61, ~m?
# 2215| mu2215_66(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2215_61
# 2218| r2218_1(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2218| mu2218_2(vector<ClassWithDestructor>) = Uninitialized[ys] : &:r2218_1
# 2218| r2218_3(glval<unknown>) = FunctionAddress[vector] :
@@ -14388,9 +14397,9 @@ ir.cpp:
# 2218| r2218_32(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Call[end] : func:r2218_31, this:r0_21
#-----| v0_22(void) = ^IndirectReadSideEffect[-1] : &:r0_21, ~m?
# 2218| mu2218_33(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Store[(__end)] : &:r2218_28, r2218_32
#-----| Goto -> Block 15
#-----| Goto -> Block 14
# 2218| Block 15
# 2218| Block 14
# 2218| r2218_34(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
#-----| r0_23(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2218_34
# 2218| r2218_35(glval<unknown>) = FunctionAddress[operator!=] :
@@ -14408,10 +14417,10 @@ ir.cpp:
# 2218| r2218_41(bool) = Call[operator!=] : func:r2218_35, this:r0_23, 0:r0_29
#-----| v0_30(void) = ^IndirectReadSideEffect[-1] : &:r0_23, ~m?
# 2218| v2218_42(void) = ConditionalBranch : r2218_41
#-----| False -> Block 20
#-----| True -> Block 17
#-----| False -> Block 18
#-----| True -> Block 16
# 2218| Block 16
# 2218| Block 15
# 2218| r2218_43(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
# 2218| r2218_44(glval<unknown>) = FunctionAddress[operator++] :
# 2218| r2218_45(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2218_44, this:r2218_43
@@ -14424,9 +14433,9 @@ ir.cpp:
# 2218| v2218_52(void) = ^IndirectReadSideEffect[-1] : &:r2218_48, ~m?
# 2218| mu2218_53(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2218_48
# 2218| r2218_54(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2218_45
#-----| Goto (back edge) -> Block 15
#-----| Goto (back edge) -> Block 14
# 2218| Block 17
# 2218| Block 16
# 2218| r2218_55(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2218| r2218_56(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
#-----| r0_31(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2218_56
@@ -14452,10 +14461,10 @@ ir.cpp:
# 2220| r2220_8(int) = Constant[98] :
# 2220| r2220_9(bool) = CompareEQ : r2220_7, r2220_8
# 2220| v2220_10(void) = ConditionalBranch : r2220_9
#-----| False -> Block 16
#-----| True -> Block 18
#-----| False -> Block 15
#-----| True -> Block 17
# 2221| Block 18
# 2221| Block 17
# 2221| v2221_1(void) = NoOp :
# 2218| r2218_61(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2218| r2218_62(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
@@ -14477,16 +14486,13 @@ ir.cpp:
# 2233| mu2233_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2233_1
#-----| Goto -> Block 1
# 2218| Block 19
# 2218| r2218_73(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2218| r2218_74(glval<unknown>) = FunctionAddress[~vector] :
# 2218| v2218_75(void) = Call[~vector] : func:r2218_74, this:r2218_73
# 2218| mu2218_76(unknown) = ^CallSideEffect : ~m?
# 2218| v2218_77(void) = ^IndirectReadSideEffect[-1] : &:r2218_73, ~m?
# 2218| mu2218_78(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_73
#-----| Goto -> Block 20
# 2224| Block 20
# 2218| Block 18
# 2218| r2218_73(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2218| r2218_74(glval<unknown>) = FunctionAddress[~vector] :
# 2218| v2218_75(void) = Call[~vector] : func:r2218_74, this:r2218_73
# 2218| mu2218_76(unknown) = ^CallSideEffect : ~m?
# 2218| v2218_77(void) = ^IndirectReadSideEffect[-1] : &:r2218_73, ~m?
# 2218| mu2218_78(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_73
# 2224| r2224_1(glval<vector<int>>) = VariableAddress[ys] :
# 2224| mu2224_2(vector<int>) = Uninitialized[ys] : &:r2224_1
# 2224| r2224_3(glval<unknown>) = FunctionAddress[vector] :
@@ -14516,9 +14522,9 @@ ir.cpp:
# 2224| r2224_22(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = Call[end] : func:r2224_21, this:r0_37
#-----| v0_38(void) = ^IndirectReadSideEffect[-1] : &:r0_37, ~m?
# 2224| mu2224_23(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = Store[(__end)] : &:r2224_18, r2224_22
#-----| Goto -> Block 21
#-----| Goto -> Block 19
# 2224| Block 21
# 2224| Block 19
# 2224| r2224_24(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
#-----| r0_39(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = Convert : r2224_24
# 2224| r2224_25(glval<unknown>) = FunctionAddress[operator!=] :
@@ -14536,19 +14542,19 @@ ir.cpp:
# 2224| r2224_31(bool) = Call[operator!=] : func:r2224_25, this:r0_39, 0:r0_45
#-----| v0_46(void) = ^IndirectReadSideEffect[-1] : &:r0_39, ~m?
# 2224| v2224_32(void) = ConditionalBranch : r2224_31
#-----| False -> Block 26
#-----| True -> Block 23
#-----| False -> Block 23
#-----| True -> Block 21
# 2224| Block 22
# 2224| Block 20
# 2224| r2224_33(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
# 2224| r2224_34(glval<unknown>) = FunctionAddress[operator++] :
# 2224| r2224_35(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &> &) = Call[operator++] : func:r2224_34, this:r2224_33
# 2224| v2224_36(void) = ^IndirectReadSideEffect[-1] : &:r2224_33, ~m?
# 2224| mu2224_37(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = ^IndirectMayWriteSideEffect[-1] : &:r2224_33
# 2224| r2224_38(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = CopyValue : r2224_35
#-----| Goto (back edge) -> Block 21
#-----| Goto (back edge) -> Block 19
# 2224| Block 23
# 2224| Block 21
# 2224| r2224_39(glval<int>) = VariableAddress[y] :
# 2224| r2224_40(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
#-----| r0_47(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = Convert : r2224_40
@@ -14562,10 +14568,10 @@ ir.cpp:
# 2225| r2225_3(int) = Constant[1] :
# 2225| r2225_4(bool) = CompareEQ : r2225_2, r2225_3
# 2225| v2225_5(void) = ConditionalBranch : r2225_4
#-----| False -> Block 22
#-----| True -> Block 24
#-----| False -> Block 20
#-----| True -> Block 22
# 2226| Block 24
# 2226| Block 22
# 2226| v2226_1(void) = NoOp :
# 2224| r2224_45(glval<vector<int>>) = VariableAddress[ys] :
# 2224| r2224_46(glval<unknown>) = FunctionAddress[~vector] :
@@ -14581,16 +14587,13 @@ ir.cpp:
# 2233| mu2233_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2233_7
#-----| Goto -> Block 1
# 2224| Block 25
# 2224| r2224_51(glval<vector<int>>) = VariableAddress[ys] :
# 2224| r2224_52(glval<unknown>) = FunctionAddress[~vector] :
# 2224| v2224_53(void) = Call[~vector] : func:r2224_52, this:r2224_51
# 2224| mu2224_54(unknown) = ^CallSideEffect : ~m?
# 2224| v2224_55(void) = ^IndirectReadSideEffect[-1] : &:r2224_51, ~m?
# 2224| mu2224_56(vector<int>) = ^IndirectMayWriteSideEffect[-1] : &:r2224_51
#-----| Goto -> Block 26
# 2229| Block 26
# 2224| Block 23
# 2224| r2224_51(glval<vector<int>>) = VariableAddress[ys] :
# 2224| r2224_52(glval<unknown>) = FunctionAddress[~vector] :
# 2224| v2224_53(void) = Call[~vector] : func:r2224_52, this:r2224_51
# 2224| mu2224_54(unknown) = ^CallSideEffect : ~m?
# 2224| v2224_55(void) = ^IndirectReadSideEffect[-1] : &:r2224_51, ~m?
# 2224| mu2224_56(vector<int>) = ^IndirectMayWriteSideEffect[-1] : &:r2224_51
# 2229| r2229_1(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2229| mu2229_2(vector<ClassWithDestructor>) = Uninitialized[ys] : &:r2229_1
# 2229| r2229_3(glval<unknown>) = FunctionAddress[vector] :
@@ -14630,9 +14633,9 @@ ir.cpp:
# 2229| r2229_32(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Call[end] : func:r2229_31, this:r0_53
#-----| v0_54(void) = ^IndirectReadSideEffect[-1] : &:r0_53, ~m?
# 2229| mu2229_33(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Store[(__end)] : &:r2229_28, r2229_32
#-----| Goto -> Block 27
#-----| Goto -> Block 24
# 2229| Block 27
# 2229| Block 24
# 2229| r2229_34(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
#-----| r0_55(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2229_34
# 2229| r2229_35(glval<unknown>) = FunctionAddress[operator!=] :
@@ -14650,10 +14653,10 @@ ir.cpp:
# 2229| r2229_41(bool) = Call[operator!=] : func:r2229_35, this:r0_55, 0:r0_61
#-----| v0_62(void) = ^IndirectReadSideEffect[-1] : &:r0_55, ~m?
# 2229| v2229_42(void) = ConditionalBranch : r2229_41
#-----| False -> Block 30
#-----| True -> Block 28
#-----| False -> Block 26
#-----| True -> Block 25
# 2229| Block 28
# 2229| Block 25
# 2229| r2229_43(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2229| r2229_44(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
#-----| r0_63(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2229_44
@@ -14698,25 +14701,22 @@ ir.cpp:
# 2229| v2229_58(void) = ^IndirectReadSideEffect[-1] : &:r2229_54, ~m?
# 2229| mu2229_59(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2229_54
# 2229| r2229_60(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2229_51
#-----| Goto (back edge) -> Block 27
#-----| Goto (back edge) -> Block 24
# 2229| Block 29
# 2229| r2229_61(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2229| r2229_62(glval<unknown>) = FunctionAddress[~vector] :
# 2229| v2229_63(void) = Call[~vector] : func:r2229_62, this:r2229_61
# 2229| mu2229_64(unknown) = ^CallSideEffect : ~m?
# 2229| v2229_65(void) = ^IndirectReadSideEffect[-1] : &:r2229_61, ~m?
# 2229| mu2229_66(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2229_61
#-----| Goto -> Block 30
# 2233| Block 30
# 2233| v2233_13(void) = NoOp :
# 2233| r2233_14(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2233| r2233_15(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2233| v2233_16(void) = Call[~ClassWithDestructor] : func:r2233_15, this:r2233_14
# 2233| mu2233_17(unknown) = ^CallSideEffect : ~m?
# 2233| v2233_18(void) = ^IndirectReadSideEffect[-1] : &:r2233_14, ~m?
# 2233| mu2233_19(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2233_14
# 2229| Block 26
# 2229| r2229_61(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2229| r2229_62(glval<unknown>) = FunctionAddress[~vector] :
# 2229| v2229_63(void) = Call[~vector] : func:r2229_62, this:r2229_61
# 2229| mu2229_64(unknown) = ^CallSideEffect : ~m?
# 2229| v2229_65(void) = ^IndirectReadSideEffect[-1] : &:r2229_61, ~m?
# 2229| mu2229_66(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2229_61
# 2233| v2233_13(void) = NoOp :
# 2233| r2233_14(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2233| r2233_15(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2233| v2233_16(void) = Call[~ClassWithDestructor] : func:r2233_15, this:r2233_14
# 2233| mu2233_17(unknown) = ^CallSideEffect : ~m?
# 2233| v2233_18(void) = ^IndirectReadSideEffect[-1] : &:r2233_14, ~m?
# 2233| mu2233_19(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2233_14
#-----| Goto -> Block 1
# 2235| void static_variable_with_destructor_1()
@@ -16372,6 +16372,187 @@ ir.cpp:
# 2484| v2484_7(void) = AliasedUse : ~m?
# 2484| v2484_8(void) = ExitFunction :
# 2501| void destruction_in_switch_1(int)
# 2501| Block 0
# 2501| v2501_1(void) = EnterFunction :
# 2501| mu2501_2(unknown) = AliasedDefinition :
# 2501| mu2501_3(unknown) = InitializeNonLocal :
# 2501| r2501_4(glval<int>) = VariableAddress[c] :
# 2501| mu2501_5(int) = InitializeParameter[c] : &:r2501_4
# 2502| r2502_1(glval<int>) = VariableAddress[c] :
# 2502| r2502_2(int) = Load[c] : &:r2502_1, ~m?
# 2502| v2502_3(void) = Switch : r2502_2
#-----| Case[0] -> Block 1
#-----| Default -> Block 3
# 2503| Block 1
# 2503| v2503_1(void) = NoOp :
# 2504| r2504_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2504| mu2504_2(ClassWithDestructor) = Uninitialized[x] : &:r2504_1
# 2504| r2504_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
# 2504| v2504_4(void) = Call[ClassWithDestructor] : func:r2504_3, this:r2504_1
# 2504| mu2504_5(unknown) = ^CallSideEffect : ~m?
# 2504| mu2504_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2504_1
# 2506| r2506_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2506| r2506_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2506| v2506_3(void) = Call[~ClassWithDestructor] : func:r2506_2, this:r2506_1
# 2506| mu2506_4(unknown) = ^CallSideEffect : ~m?
# 2506| v2506_5(void) = ^IndirectReadSideEffect[-1] : &:r2506_1, ~m?
# 2506| mu2506_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2506_1
# 2505| v2505_1(void) = NoOp :
#-----| Goto -> Block 3
# 2506| Block 2
# 2506| r2506_7(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2506| r2506_8(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2506| v2506_9(void) = Call[~ClassWithDestructor] : func:r2506_8, this:r2506_7
# 2506| mu2506_10(unknown) = ^CallSideEffect : ~m?
# 2506| v2506_11(void) = ^IndirectReadSideEffect[-1] : &:r2506_7, ~m?
# 2506| mu2506_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2506_7
#-----| Goto -> Block 3
# 2507| Block 3
# 2507| v2507_1(void) = NoOp :
# 2508| v2508_1(void) = NoOp :
# 2501| v2501_6(void) = ReturnVoid :
# 2501| v2501_7(void) = AliasedUse : ~m?
# 2501| v2501_8(void) = ExitFunction :
# 2510| void destruction_in_switch_2(int)
# 2510| Block 0
# 2510| v2510_1(void) = EnterFunction :
# 2510| mu2510_2(unknown) = AliasedDefinition :
# 2510| mu2510_3(unknown) = InitializeNonLocal :
# 2510| r2510_4(glval<int>) = VariableAddress[c] :
# 2510| mu2510_5(int) = InitializeParameter[c] : &:r2510_4
# 2511| r2511_1(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2511| mu2511_2(ClassWithDestructor) = Uninitialized[y] : &:r2511_1
# 2511| r2511_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
# 2511| v2511_4(void) = Call[ClassWithDestructor] : func:r2511_3, this:r2511_1
# 2511| mu2511_5(unknown) = ^CallSideEffect : ~m?
# 2511| mu2511_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2511_1
# 2511| r2511_7(glval<int>) = VariableAddress[c] :
# 2511| r2511_8(int) = Load[c] : &:r2511_7, ~m?
# 2511| v2511_9(void) = Switch : r2511_8
#-----| Case[0] -> Block 1
#-----| Default -> Block 2
# 2512| Block 1
# 2512| v2512_1(void) = NoOp :
# 2518| r2518_1(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2518| r2518_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2518| v2518_3(void) = Call[~ClassWithDestructor] : func:r2518_2, this:r2518_1
# 2518| mu2518_4(unknown) = ^CallSideEffect : ~m?
# 2518| v2518_5(void) = ^IndirectReadSideEffect[-1] : &:r2518_1, ~m?
# 2518| mu2518_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2518_1
# 2513| v2513_1(void) = NoOp :
#-----| Goto -> Block 4
# 2515| Block 2
# 2515| v2515_1(void) = NoOp :
# 2518| r2518_7(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2518| r2518_8(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2518| v2518_9(void) = Call[~ClassWithDestructor] : func:r2518_8, this:r2518_7
# 2518| mu2518_10(unknown) = ^CallSideEffect : ~m?
# 2518| v2518_11(void) = ^IndirectReadSideEffect[-1] : &:r2518_7, ~m?
# 2518| mu2518_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2518_7
# 2516| v2516_1(void) = NoOp :
#-----| Goto -> Block 4
# 2518| Block 3
# 2518| r2518_13(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2518| r2518_14(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2518| v2518_15(void) = Call[~ClassWithDestructor] : func:r2518_14, this:r2518_13
# 2518| mu2518_16(unknown) = ^CallSideEffect : ~m?
# 2518| v2518_17(void) = ^IndirectReadSideEffect[-1] : &:r2518_13, ~m?
# 2518| mu2518_18(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2518_13
#-----| Goto -> Block 4
# 2518| Block 4
# 2518| v2518_19(void) = NoOp :
# 2519| v2519_1(void) = NoOp :
# 2510| v2510_6(void) = ReturnVoid :
# 2510| v2510_7(void) = AliasedUse : ~m?
# 2510| v2510_8(void) = ExitFunction :
# 2521| void destruction_in_switch_3(int)
# 2521| Block 0
# 2521| v2521_1(void) = EnterFunction :
# 2521| mu2521_2(unknown) = AliasedDefinition :
# 2521| mu2521_3(unknown) = InitializeNonLocal :
# 2521| r2521_4(glval<int>) = VariableAddress[c] :
# 2521| mu2521_5(int) = InitializeParameter[c] : &:r2521_4
# 2522| r2522_1(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2522| mu2522_2(ClassWithDestructor) = Uninitialized[y] : &:r2522_1
# 2522| r2522_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
# 2522| v2522_4(void) = Call[ClassWithDestructor] : func:r2522_3, this:r2522_1
# 2522| mu2522_5(unknown) = ^CallSideEffect : ~m?
# 2522| mu2522_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2522_1
# 2522| r2522_7(glval<int>) = VariableAddress[c] :
# 2522| r2522_8(int) = Load[c] : &:r2522_7, ~m?
# 2522| v2522_9(void) = Switch : r2522_8
#-----| Case[0] -> Block 1
#-----| Default -> Block 3
# 2523| Block 1
# 2523| v2523_1(void) = NoOp :
# 2524| r2524_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2524| mu2524_2(ClassWithDestructor) = Uninitialized[x] : &:r2524_1
# 2524| r2524_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
# 2524| v2524_4(void) = Call[ClassWithDestructor] : func:r2524_3, this:r2524_1
# 2524| mu2524_5(unknown) = ^CallSideEffect : ~m?
# 2524| mu2524_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2524_1
# 2526| r2526_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2526| r2526_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2526| v2526_3(void) = Call[~ClassWithDestructor] : func:r2526_2, this:r2526_1
# 2526| mu2526_4(unknown) = ^CallSideEffect : ~m?
# 2526| v2526_5(void) = ^IndirectReadSideEffect[-1] : &:r2526_1, ~m?
# 2526| mu2526_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2526_1
# 2530| r2530_1(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2530| r2530_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2530| v2530_3(void) = Call[~ClassWithDestructor] : func:r2530_2, this:r2530_1
# 2530| mu2530_4(unknown) = ^CallSideEffect : ~m?
# 2530| v2530_5(void) = ^IndirectReadSideEffect[-1] : &:r2530_1, ~m?
# 2530| mu2530_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2530_1
# 2525| v2525_1(void) = NoOp :
#-----| Goto -> Block 5
# 2526| Block 2
# 2526| r2526_7(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2526| r2526_8(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2526| v2526_9(void) = Call[~ClassWithDestructor] : func:r2526_8, this:r2526_7
# 2526| mu2526_10(unknown) = ^CallSideEffect : ~m?
# 2526| v2526_11(void) = ^IndirectReadSideEffect[-1] : &:r2526_7, ~m?
# 2526| mu2526_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2526_7
#-----| Goto -> Block 3
# 2527| Block 3
# 2527| v2527_1(void) = NoOp :
# 2530| r2530_7(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2530| r2530_8(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2530| v2530_9(void) = Call[~ClassWithDestructor] : func:r2530_8, this:r2530_7
# 2530| mu2530_10(unknown) = ^CallSideEffect : ~m?
# 2530| v2530_11(void) = ^IndirectReadSideEffect[-1] : &:r2530_7, ~m?
# 2530| mu2530_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2530_7
# 2528| v2528_1(void) = NoOp :
#-----| Goto -> Block 5
# 2530| Block 4
# 2530| r2530_13(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2530| r2530_14(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2530| v2530_15(void) = Call[~ClassWithDestructor] : func:r2530_14, this:r2530_13
# 2530| mu2530_16(unknown) = ^CallSideEffect : ~m?
# 2530| v2530_17(void) = ^IndirectReadSideEffect[-1] : &:r2530_13, ~m?
# 2530| mu2530_18(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2530_13
#-----| Goto -> Block 5
# 2530| Block 5
# 2530| v2530_19(void) = NoOp :
# 2531| v2531_1(void) = NoOp :
# 2521| v2521_6(void) = ReturnVoid :
# 2521| v2521_7(void) = AliasedUse : ~m?
# 2521| v2521_8(void) = ExitFunction :
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0

View File

@@ -4,12 +4,6 @@ uniqueType
uniqueNodeLocation
missingLocation
uniqueNodeToString
| builtin.c:5:5:5:11 | (no string representation) | Node should have one toString but has 0. |
| misc.c:227:7:227:28 | (no string representation) | Node should have one toString but has 0. |
| static_init_templates.cpp:80:18:80:23 | (no string representation) | Node should have one toString but has 0. |
| static_init_templates.cpp:80:18:80:23 | (no string representation) | Node should have one toString but has 0. |
| static_init_templates.cpp:89:18:89:23 | (no string representation) | Node should have one toString but has 0. |
| static_init_templates.cpp:89:18:89:23 | (no string representation) | Node should have one toString but has 0. |
parameterCallable
localFlowIsLocal
readStepIsLocal

View File

@@ -1,41 +0,0 @@
WARNING: Type GVN has been deprecated and may be removed in future (ast_gvn.ql:4,6-9)
| test.cpp:5:3:5:3 | x | 5:c3-c3 6:c3-c3 |
| test.cpp:5:7:5:8 | p0 | 5:c7-c8 6:c7-c8 |
| test.cpp:5:7:5:13 | ... + ... | 5:c7-c13 6:c7-c13 7:c7-c7 |
| test.cpp:5:12:5:13 | p1 | 5:c12-c13 6:c12-c13 |
| test.cpp:16:3:16:3 | x | 16:c3-c3 17:c3-c3 |
| test.cpp:16:7:16:8 | p0 | 16:c7-c8 17:c7-c8 |
| test.cpp:16:7:16:13 | ... + ... | 16:c7-c13 17:c7-c13 |
| test.cpp:16:7:16:24 | ... + ... | 16:c7-c24 17:c7-c24 18:c7-c7 |
| test.cpp:16:12:16:13 | p1 | 16:c12-c13 17:c12-c13 |
| test.cpp:16:17:16:24 | global01 | 16:c17-c24 17:c17-c24 |
| test.cpp:29:7:29:8 | p0 | 29:c7-c8 31:c7-c8 |
| test.cpp:29:7:29:13 | ... + ... | 29:c7-c13 31:c7-c13 |
| test.cpp:29:12:29:13 | p1 | 29:c12-c13 31:c12-c13 |
| test.cpp:31:7:31:24 | ... + ... | 31:c7-c24 32:c7-c7 |
| test.cpp:43:7:43:8 | p0 | 43:c7-c8 45:c7-c8 |
| test.cpp:43:7:43:13 | ... + ... | 43:c7-c13 45:c7-c13 |
| test.cpp:43:12:43:13 | p1 | 43:c12-c13 45:c12-c13 |
| test.cpp:44:9:44:9 | 0 | 44:c9-c9 51:c25-c25 53:c18-c21 56:c39-c42 59:c17-c20 88:c12-c12 |
| test.cpp:45:7:45:24 | ... + ... | 45:c7-c24 46:c7-c7 |
| test.cpp:53:10:53:13 | (int)... | 53:c10-c13 56:c21-c24 |
| test.cpp:53:10:53:13 | * ... | 53:c10-c13 56:c21-c24 |
| test.cpp:53:11:53:13 | str | 53:c11-c13 56:c22-c24 |
| test.cpp:53:18:53:21 | 0 | 53:c18-c21 56:c39-c42 59:c17-c20 |
| test.cpp:56:13:56:16 | (int)... | 56:c13-c16 56:c31-c34 59:c9-c12 |
| test.cpp:56:13:56:16 | * ... | 56:c13-c16 56:c31-c34 59:c9-c12 |
| test.cpp:56:14:56:16 | ptr | 56:c14-c16 56:c32-c34 56:c47-c49 59:c10-c12 |
| test.cpp:62:5:62:10 | result | 62:c5-c10 65:c10-c15 |
| test.cpp:77:20:77:30 | (signed short)... | 77:c20-c30 79:c7-c7 |
| test.cpp:79:11:79:14 | vals | 79:c11-c14 79:c24-c27 |
| test.cpp:105:11:105:12 | (Base *)... | 105:c11-c12 106:c14-c35 107:c11-c12 |
| test.cpp:105:11:105:12 | pd | 105:c11-c12 106:c33-c34 |
| test.cpp:105:15:105:15 | b | 105:c15-c15 107:c15-c15 109:c10-c10 |
| test.cpp:125:11:125:12 | pa | 125:c11-c12 126:c11-c12 128:c3-c4 129:c11-c12 |
| test.cpp:125:15:125:15 | x | 125:c15-c15 126:c15-c15 128:c7-c7 |
| test.cpp:136:11:136:18 | global_a | 136:c11-c18 137:c11-c18 139:c3-c10 |
| test.cpp:136:21:136:21 | x | 136:c21-c21 137:c21-c21 139:c13-c13 |
| test.cpp:144:11:144:12 | pa | 144:c11-c12 145:c11-c12 147:c3-c4 149:c11-c12 |
| test.cpp:145:15:145:15 | y | 145:c15-c15 147:c7-c7 |
| test.cpp:153:11:153:18 | global_a | 153:c11-c18 154:c11-c18 156:c3-c10 |
| test.cpp:153:21:153:21 | x | 153:c21-c21 154:c21-c21 |

View File

@@ -1,11 +0,0 @@
import cpp
import semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl
from GVN g
where strictcount(g.getAnExpr()) > 1
select g,
strictconcat(Location loc |
loc = g.getAnExpr().getLocation()
|
loc.getStartLine() + ":c" + loc.getStartColumn() + "-c" + loc.getEndColumn(), " "
)

View File

@@ -1,3 +0,0 @@
WARNING: Predicate globalValueNumber has been deprecated and may be removed in future (ast_uniqueness.ql:7,13-30)
WARNING: Predicate globalValueNumber has been deprecated and may be removed in future (ast_uniqueness.ql:8,30-47)
WARNING: Type GVN has been deprecated and may be removed in future (ast_uniqueness.ql:8,18-21)

View File

@@ -1,8 +0,0 @@
import cpp
import semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl
// Every expression should have exactly one GVN.
// So this query should have zero results.
from Expr e
where count(globalValueNumber(e)) != 1
select e, concat(GVN g | g = globalValueNumber(e) | g.getKind(), ", ")

View File

@@ -1,130 +0,0 @@
WARNING: Predicate globalValueNumber has been deprecated and may be removed in future (diff_ir_expr.ql:8,29-51)
| test.cpp:5:3:5:13 | ... = ... | test.cpp:5:3:5:13 | ... = ... | AST only |
| test.cpp:6:3:6:13 | ... = ... | test.cpp:6:3:6:13 | ... = ... | AST only |
| test.cpp:7:3:7:7 | ... = ... | test.cpp:7:3:7:7 | ... = ... | AST only |
| test.cpp:16:3:16:24 | ... = ... | test.cpp:16:3:16:24 | ... = ... | AST only |
| test.cpp:17:3:17:24 | ... = ... | test.cpp:17:3:17:24 | ... = ... | AST only |
| test.cpp:18:3:18:7 | ... = ... | test.cpp:18:3:18:7 | ... = ... | AST only |
| test.cpp:29:3:29:3 | x | test.cpp:31:3:31:3 | x | IR only |
| test.cpp:29:3:29:24 | ... = ... | test.cpp:29:3:29:24 | ... = ... | AST only |
| test.cpp:30:3:30:17 | call to change_global02 | test.cpp:30:3:30:17 | call to change_global02 | AST only |
| test.cpp:31:3:31:3 | x | test.cpp:29:3:29:3 | x | IR only |
| test.cpp:31:3:31:24 | ... = ... | test.cpp:31:3:31:24 | ... = ... | AST only |
| test.cpp:32:3:32:7 | ... = ... | test.cpp:32:3:32:7 | ... = ... | AST only |
| test.cpp:43:3:43:3 | x | test.cpp:45:3:45:3 | x | IR only |
| test.cpp:43:3:43:24 | ... = ... | test.cpp:43:3:43:24 | ... = ... | AST only |
| test.cpp:43:7:43:24 | ... + ... | test.cpp:45:7:45:24 | ... + ... | IR only |
| test.cpp:43:7:43:24 | ... + ... | test.cpp:46:7:46:7 | x | IR only |
| test.cpp:43:17:43:24 | global03 | test.cpp:45:17:45:24 | global03 | IR only |
| test.cpp:44:3:44:5 | * ... | test.cpp:44:4:44:5 | p2 | IR only |
| test.cpp:44:3:44:9 | ... = ... | test.cpp:44:3:44:9 | ... = ... | AST only |
| test.cpp:44:4:44:5 | p2 | test.cpp:44:3:44:5 | * ... | IR only |
| test.cpp:44:9:44:9 | 0 | test.cpp:51:25:51:25 | 0 | AST only |
| test.cpp:44:9:44:9 | 0 | test.cpp:53:18:53:21 | (int)... | AST only |
| test.cpp:44:9:44:9 | 0 | test.cpp:56:39:56:42 | (int)... | AST only |
| test.cpp:44:9:44:9 | 0 | test.cpp:59:17:59:20 | (int)... | AST only |
| test.cpp:44:9:44:9 | 0 | test.cpp:88:12:88:12 | 0 | AST only |
| test.cpp:45:3:45:3 | x | test.cpp:43:3:43:3 | x | IR only |
| test.cpp:45:3:45:24 | ... = ... | test.cpp:45:3:45:24 | ... = ... | AST only |
| test.cpp:45:7:45:24 | ... + ... | test.cpp:43:7:43:24 | ... + ... | IR only |
| test.cpp:45:17:45:24 | global03 | test.cpp:43:17:43:24 | global03 | IR only |
| test.cpp:46:3:46:7 | ... = ... | test.cpp:46:3:46:7 | ... = ... | AST only |
| test.cpp:46:7:46:7 | x | test.cpp:43:7:43:24 | ... + ... | IR only |
| test.cpp:51:25:51:25 | 0 | test.cpp:44:9:44:9 | 0 | AST only |
| test.cpp:51:25:51:25 | 0 | test.cpp:53:18:53:21 | (int)... | AST only |
| test.cpp:51:25:51:25 | 0 | test.cpp:56:39:56:42 | (int)... | AST only |
| test.cpp:51:25:51:25 | 0 | test.cpp:59:17:59:20 | (int)... | AST only |
| test.cpp:51:25:51:25 | 0 | test.cpp:88:12:88:12 | 0 | AST only |
| test.cpp:51:25:51:25 | (unsigned int)... | test.cpp:51:25:51:25 | (unsigned int)... | AST only |
| test.cpp:53:10:53:13 | (int)... | test.cpp:53:10:53:13 | (int)... | AST only |
| test.cpp:53:10:53:13 | (int)... | test.cpp:56:21:56:24 | (int)... | AST only |
| test.cpp:53:18:53:21 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
| test.cpp:53:18:53:21 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
| test.cpp:53:18:53:21 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
| test.cpp:53:18:53:21 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only |
| test.cpp:53:18:53:21 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only |
| test.cpp:53:18:53:21 | (int)... | test.cpp:88:12:88:12 | 0 | AST only |
| test.cpp:55:5:55:15 | ... = ... | test.cpp:55:5:55:15 | ... = ... | AST only |
| test.cpp:56:12:56:25 | (...) | test.cpp:56:12:56:25 | (...) | AST only |
| test.cpp:56:12:56:43 | ... && ... | test.cpp:56:12:56:43 | ... && ... | AST only |
| test.cpp:56:13:56:16 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
| test.cpp:56:13:56:16 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
| test.cpp:56:13:56:16 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
| test.cpp:56:21:56:24 | (int)... | test.cpp:53:10:53:13 | (int)... | AST only |
| test.cpp:56:21:56:24 | (int)... | test.cpp:56:21:56:24 | (int)... | AST only |
| test.cpp:56:30:56:43 | (...) | test.cpp:56:30:56:43 | (...) | AST only |
| test.cpp:56:31:56:34 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
| test.cpp:56:31:56:34 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
| test.cpp:56:31:56:34 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
| test.cpp:56:39:56:42 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
| test.cpp:56:39:56:42 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
| test.cpp:56:39:56:42 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
| test.cpp:56:39:56:42 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only |
| test.cpp:56:39:56:42 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only |
| test.cpp:56:39:56:42 | (int)... | test.cpp:88:12:88:12 | 0 | AST only |
| test.cpp:56:47:56:51 | ... ++ | test.cpp:56:47:56:51 | ... ++ | AST only |
| test.cpp:59:9:59:12 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
| test.cpp:59:9:59:12 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
| test.cpp:59:9:59:12 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
| test.cpp:59:17:59:20 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
| test.cpp:59:17:59:20 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
| test.cpp:59:17:59:20 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
| test.cpp:59:17:59:20 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only |
| test.cpp:59:17:59:20 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only |
| test.cpp:59:17:59:20 | (int)... | test.cpp:88:12:88:12 | 0 | AST only |
| test.cpp:62:5:62:12 | ... ++ | test.cpp:62:5:62:12 | ... ++ | AST only |
| test.cpp:77:20:77:28 | call to getAValue | test.cpp:79:7:79:7 | v | IR only |
| test.cpp:77:20:77:30 | (signed short)... | test.cpp:77:20:77:30 | (signed short)... | AST only |
| test.cpp:77:20:77:30 | (signed short)... | test.cpp:79:7:79:7 | v | AST only |
| test.cpp:79:7:79:7 | (int)... | test.cpp:79:7:79:7 | (int)... | AST only |
| test.cpp:79:7:79:7 | v | test.cpp:77:20:77:28 | call to getAValue | IR only |
| test.cpp:79:7:79:7 | v | test.cpp:77:20:77:30 | (signed short)... | AST only |
| test.cpp:79:11:79:20 | (int)... | test.cpp:79:11:79:20 | (int)... | AST only |
| test.cpp:79:24:79:33 | (int)... | test.cpp:79:24:79:33 | (int)... | AST only |
| test.cpp:80:5:80:19 | ... = ... | test.cpp:80:5:80:19 | ... = ... | AST only |
| test.cpp:80:9:80:19 | (signed short)... | test.cpp:80:9:80:19 | (signed short)... | AST only |
| test.cpp:88:3:88:20 | ... = ... | test.cpp:88:3:88:20 | ... = ... | AST only |
| test.cpp:88:12:88:12 | 0 | test.cpp:44:9:44:9 | 0 | AST only |
| test.cpp:88:12:88:12 | 0 | test.cpp:51:25:51:25 | 0 | AST only |
| test.cpp:88:12:88:12 | 0 | test.cpp:53:18:53:21 | (int)... | AST only |
| test.cpp:88:12:88:12 | 0 | test.cpp:56:39:56:42 | (int)... | AST only |
| test.cpp:88:12:88:12 | 0 | test.cpp:59:17:59:20 | (int)... | AST only |
| test.cpp:88:12:88:12 | (void *)... | test.cpp:88:12:88:12 | (void *)... | AST only |
| test.cpp:92:11:92:16 | ... = ... | test.cpp:92:15:92:16 | 10 | IR only |
| test.cpp:92:11:92:16 | ... = ... | test.cpp:93:10:93:10 | x | IR only |
| test.cpp:92:15:92:16 | 10 | test.cpp:92:11:92:16 | ... = ... | IR only |
| test.cpp:92:15:92:16 | 10 | test.cpp:93:10:93:10 | x | IR only |
| test.cpp:93:10:93:10 | x | test.cpp:92:11:92:16 | ... = ... | IR only |
| test.cpp:93:10:93:10 | x | test.cpp:92:15:92:16 | 10 | IR only |
| test.cpp:105:11:105:12 | (Base *)... | test.cpp:105:11:105:12 | (Base *)... | AST only |
| test.cpp:105:11:105:12 | (Base *)... | test.cpp:106:14:106:35 | static_cast<Base *>... | AST only |
| test.cpp:105:11:105:12 | (Base *)... | test.cpp:107:11:107:12 | pb | AST only |
| test.cpp:105:11:105:12 | pd | test.cpp:107:11:107:12 | pb | IR only |
| test.cpp:106:14:106:35 | static_cast<Base *>... | test.cpp:105:11:105:12 | (Base *)... | AST only |
| test.cpp:106:14:106:35 | static_cast<Base *>... | test.cpp:106:14:106:35 | static_cast<Base *>... | AST only |
| test.cpp:106:14:106:35 | static_cast<Base *>... | test.cpp:107:11:107:12 | pb | AST only |
| test.cpp:106:33:106:34 | pd | test.cpp:107:11:107:12 | pb | IR only |
| test.cpp:107:11:107:12 | pb | test.cpp:105:11:105:12 | (Base *)... | AST only |
| test.cpp:107:11:107:12 | pb | test.cpp:105:11:105:12 | pd | IR only |
| test.cpp:107:11:107:12 | pb | test.cpp:106:14:106:35 | static_cast<Base *>... | AST only |
| test.cpp:107:11:107:12 | pb | test.cpp:106:33:106:34 | pd | IR only |
| test.cpp:113:3:113:5 | a | test.cpp:115:3:115:5 | a | IR only |
| test.cpp:115:3:115:5 | a | test.cpp:113:3:113:5 | a | IR only |
| test.cpp:125:15:125:15 | x | test.cpp:128:7:128:7 | x | AST only |
| test.cpp:126:15:126:15 | x | test.cpp:128:7:128:7 | x | AST only |
| test.cpp:128:3:128:11 | ... = ... | test.cpp:128:3:128:11 | ... = ... | AST only |
| test.cpp:128:7:128:7 | x | test.cpp:125:15:125:15 | x | AST only |
| test.cpp:128:7:128:7 | x | test.cpp:126:15:126:15 | x | AST only |
| test.cpp:128:11:128:11 | n | test.cpp:129:15:129:15 | x | IR only |
| test.cpp:129:15:129:15 | x | test.cpp:128:11:128:11 | n | IR only |
| test.cpp:136:21:136:21 | x | test.cpp:139:13:139:13 | x | AST only |
| test.cpp:137:21:137:21 | x | test.cpp:139:13:139:13 | x | AST only |
| test.cpp:139:3:139:24 | ... = ... | test.cpp:139:3:139:24 | ... = ... | AST only |
| test.cpp:139:13:139:13 | x | test.cpp:136:21:136:21 | x | AST only |
| test.cpp:139:13:139:13 | x | test.cpp:137:21:137:21 | x | AST only |
| test.cpp:144:15:144:15 | x | test.cpp:149:15:149:15 | x | IR only |
| test.cpp:145:15:145:15 | y | test.cpp:147:7:147:7 | y | AST only |
| test.cpp:147:3:147:18 | ... = ... | test.cpp:147:3:147:18 | ... = ... | AST only |
| test.cpp:147:7:147:7 | y | test.cpp:145:15:145:15 | y | AST only |
| test.cpp:149:15:149:15 | x | test.cpp:144:15:144:15 | x | IR only |
| test.cpp:156:3:156:17 | ... = ... | test.cpp:156:3:156:17 | ... = ... | AST only |

View File

@@ -1,15 +0,0 @@
import cpp
import semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl as AST
import semmle.code.cpp.ir.internal.ASTValueNumbering as IR
import semmle.code.cpp.ir.IR
Expr ir(Expr e) { result = IR::globalValueNumber(e).getAnExpr() }
Expr ast(Expr e) { result = AST::globalValueNumber(e).getAnExpr() }
from Expr e, Expr evn, string note
where
evn = ast(e) and not evn = ir(e) and note = "AST only"
or
evn = ir(e) and not evn = ast(e) and note = "IR only"
select e, evn, note

View File

@@ -26,6 +26,8 @@
| test.cpp:128:15:128:16 | v4 |
| test.cpp:185:10:185:12 | cpy |
| test.cpp:199:10:199:12 | cpy |
| test.cpp:208:7:208:7 | a |
| test.cpp:214:7:214:7 | a |
| test_free.cpp:11:10:11:10 | a |
| test_free.cpp:14:10:14:10 | a |
| test_free.cpp:16:10:16:10 | a |

View File

@@ -1,4 +1,6 @@
edges
| test.cpp:208:7:208:7 | pointer to free output argument | test.cpp:209:2:209:2 | a | provenance | |
| test.cpp:214:7:214:7 | pointer to free output argument | test.cpp:215:2:215:2 | a | provenance | |
| test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:12:5:12:5 | a | provenance | |
| test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:13:5:13:6 | * ... | provenance | |
| test_free.cpp:42:27:42:27 | pointer to free output argument | test_free.cpp:45:5:45:5 | a | provenance | |
@@ -31,6 +33,10 @@ edges
| test_free.cpp:322:12:322:12 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | provenance | |
| test_free.cpp:331:12:331:12 | pointer to operator delete output argument | test_free.cpp:332:5:332:6 | * ... | provenance | |
nodes
| test.cpp:208:7:208:7 | pointer to free output argument | semmle.label | pointer to free output argument |
| test.cpp:209:2:209:2 | a | semmle.label | a |
| test.cpp:214:7:214:7 | pointer to free output argument | semmle.label | pointer to free output argument |
| test.cpp:215:2:215:2 | a | semmle.label | a |
| test_free.cpp:11:10:11:10 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:12:5:12:5 | a | semmle.label | a |
| test_free.cpp:13:5:13:6 | * ... | semmle.label | * ... |
@@ -82,6 +88,8 @@ nodes
| test_free.cpp:332:5:332:6 | * ... | semmle.label | * ... |
subpaths
#select
| test.cpp:209:2:209:2 | a | test.cpp:208:7:208:7 | pointer to free output argument | test.cpp:209:2:209:2 | a | Memory may have been previously freed by $@. | test.cpp:208:2:208:5 | call to free | call to free |
| test.cpp:215:2:215:2 | a | test.cpp:214:7:214:7 | pointer to free output argument | test.cpp:215:2:215:2 | a | Memory may have been previously freed by $@. | test.cpp:214:2:214:5 | call to free | call to free |
| test_free.cpp:12:5:12:5 | a | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:12:5:12:5 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
| test_free.cpp:13:5:13:6 | * ... | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:13:5:13:6 | * ... | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
| test_free.cpp:45:5:45:5 | a | test_free.cpp:42:27:42:27 | pointer to free output argument | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |

View File

@@ -114,7 +114,7 @@ int main()
mc2->method2();
delete mc2;
}
{
void *v1 = malloc(100);
int *i2 = (int *)malloc(100);
@@ -198,3 +198,19 @@ void test_strndupa_dealloc() {
char *cpy = strndupa(msg, 4);
free(cpy); // BAD [NOT DETECTED]
}
// ---
void test_reassignment() {
char *a = (char *)malloc(128);
char *b = (char *)malloc(128);
free(a);
a[0] = 0; // BAD
a = b;
a[0] = 0; // GOOD
free(a);
a[0] = 0; // BAD
}

View File

@@ -1,11 +1,16 @@
edges
| test.c:8:27:8:30 | **argv | test.c:9:23:9:29 | *access to array | provenance | |
| test.c:8:27:8:30 | **argv | test.c:31:22:31:28 | *access to array | provenance | |
| test.c:8:27:8:30 | **argv | test.c:57:10:57:16 | *access to array | provenance | |
| test.c:8:27:8:30 | **argv | test.c:69:14:69:20 | *access to array | provenance | |
| test.c:9:23:9:29 | *access to array | test.c:17:11:17:18 | *fileName | provenance | TaintFunction |
| test.c:31:22:31:28 | *access to array | test.c:32:11:32:18 | *fileName | provenance | |
| test.c:37:17:37:24 | scanf output argument | test.c:38:11:38:18 | *fileName | provenance | |
| test.c:43:17:43:24 | scanf output argument | test.c:44:11:44:18 | *fileName | provenance | |
| test.c:48:21:48:26 | *call to getenv | test.c:48:21:48:26 | *call to getenv | provenance | |
| test.c:48:21:48:26 | *call to getenv | test.c:49:11:49:17 | *tainted | provenance | |
| test.c:54:21:54:26 | *call to getenv | test.c:55:11:55:16 | *buffer | provenance | TaintFunction |
| test.c:74:13:74:18 | read output argument | test.c:76:11:76:16 | *buffer | provenance | |
| test.c:75:13:75:18 | read output argument | test.c:76:11:76:16 | *buffer | provenance | |
nodes
| test.c:8:27:8:30 | **argv | semmle.label | **argv |
| test.c:9:23:9:29 | *access to array | semmle.label | *access to array |
@@ -16,11 +21,23 @@ nodes
| test.c:38:11:38:18 | *fileName | semmle.label | *fileName |
| test.c:43:17:43:24 | scanf output argument | semmle.label | scanf output argument |
| test.c:44:11:44:18 | *fileName | semmle.label | *fileName |
| test.c:57:10:57:16 | *access to array | semmle.label | *access to array |
| test.c:48:21:48:26 | *call to getenv | semmle.label | *call to getenv |
| test.c:48:21:48:26 | *call to getenv | semmle.label | *call to getenv |
| test.c:49:11:49:17 | *tainted | semmle.label | *tainted |
| test.c:54:21:54:26 | *call to getenv | semmle.label | *call to getenv |
| test.c:55:11:55:16 | *buffer | semmle.label | *buffer |
| test.c:69:14:69:20 | *access to array | semmle.label | *access to array |
| test.c:74:13:74:18 | read output argument | semmle.label | read output argument |
| test.c:75:13:75:18 | read output argument | semmle.label | read output argument |
| test.c:76:11:76:16 | *buffer | semmle.label | *buffer |
subpaths
#select
| test.c:17:11:17:18 | fileName | test.c:8:27:8:30 | **argv | test.c:17:11:17:18 | *fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:8:27:8:30 | **argv | user input (a command-line argument) |
| test.c:32:11:32:18 | fileName | test.c:8:27:8:30 | **argv | test.c:32:11:32:18 | *fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:8:27:8:30 | **argv | user input (a command-line argument) |
| test.c:38:11:38:18 | fileName | test.c:37:17:37:24 | scanf output argument | test.c:38:11:38:18 | *fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:37:17:37:24 | scanf output argument | user input (value read by scanf) |
| test.c:44:11:44:18 | fileName | test.c:43:17:43:24 | scanf output argument | test.c:44:11:44:18 | *fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:43:17:43:24 | scanf output argument | user input (value read by scanf) |
| test.c:57:10:57:16 | access to array | test.c:8:27:8:30 | **argv | test.c:57:10:57:16 | *access to array | This argument to a file access function is derived from $@ and then passed to read(fileName), which calls fopen(filename). | test.c:8:27:8:30 | **argv | user input (a command-line argument) |
| test.c:49:11:49:17 | tainted | test.c:48:21:48:26 | *call to getenv | test.c:49:11:49:17 | *tainted | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:48:21:48:26 | *call to getenv | user input (an environment variable) |
| test.c:55:11:55:16 | buffer | test.c:54:21:54:26 | *call to getenv | test.c:55:11:55:16 | *buffer | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:54:21:54:26 | *call to getenv | user input (an environment variable) |
| test.c:69:14:69:20 | access to array | test.c:8:27:8:30 | **argv | test.c:69:14:69:20 | *access to array | This argument to a file access function is derived from $@ and then passed to readFile(fileName), which calls fopen(filename). | test.c:8:27:8:30 | **argv | user input (a command-line argument) |
| test.c:76:11:76:16 | buffer | test.c:74:13:74:18 | read output argument | test.c:76:11:76:16 | *buffer | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:74:13:74:18 | read output argument | user input (buffer read by read) |
| test.c:76:11:76:16 | buffer | test.c:75:13:75:18 | read output argument | test.c:76:11:76:16 | *buffer | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:75:13:75:18 | read output argument | user input (buffer read by read) |

View File

@@ -6,6 +6,7 @@
typedef struct {} FILE;
#define FILENAME_MAX 1000
typedef unsigned long size_t;
typedef signed long ssize_t;
FILE *fopen(const char *filename, const char *mode);
int sprintf(char *s, const char *format, ...);
@@ -15,3 +16,4 @@ int scanf(const char *format, ...);
void *malloc(size_t size);
double strtod(const char *ptr, char **endptr);
char *getenv(const char *name);
ssize_t read(int fd, void *buffer, size_t count);

View File

@@ -7,7 +7,7 @@
int main(int argc, char** argv) {
char *userAndFile = argv[2];
{
char fileBuffer[FILENAME_MAX] = "/home/";
char *fileName = fileBuffer;
@@ -44,6 +44,18 @@ int main(int argc, char** argv) {
fopen(fileName, "wb+"); // BAD
}
{
char *tainted = getenv("A_STRING");
fopen(tainted, "wb+"); // BAD
}
{
char buffer[1024];
strncpy(buffer, getenv("A_STRING"), 1024);
fopen(buffer, "wb+"); // BAD
fopen(buffer, "wb+"); // (we don't want a duplicate result here)
}
{
char *aNumber = getenv("A_NUMBER");
double number = strtod(aNumber, 0);
@@ -53,11 +65,18 @@ int main(int argc, char** argv) {
}
{
void read(const char *fileName);
read(argv[1]); // BAD
void readFile(const char *fileName);
readFile(argv[1]); // BAD
}
{
char buffer[1024];
read(0, buffer, 1024);
read(0, buffer, 1024);
fopen(buffer, "wb+"); // BAD [duplicated with both sources]
}
}
void read(char *fileName) {
void readFile(char *fileName) {
fopen(fileName, "wb+");
}

View File

@@ -0,0 +1,6 @@
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed at the end of the full-expression. |
| test.cpp:683:31:683:32 | call to at | This object is destroyed at the end of the full-expression. |
| test.cpp:689:46:689:58 | pointer to ~vector output argument | This object is destroyed at the end of the full-expression. |
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed at the end of the full-expression. |
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed at the end of the full-expression. |
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed at the end of the full-expression. |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-416/IteratorToExpiredContainer.ql

View File

@@ -1,13 +1,13 @@
| test.cpp:165:34:165:38 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
| test.cpp:166:39:166:43 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
| test.cpp:167:44:167:48 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
| test.cpp:169:29:169:33 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
| test.cpp:178:37:178:41 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
| test.cpp:181:39:181:43 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
| test.cpp:183:37:183:41 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
| test.cpp:187:34:187:37 | call to data | The underlying string object is destroyed after the call to 'data' returns. |
| test.cpp:188:39:188:42 | call to data | The underlying string object is destroyed after the call to 'data' returns. |
| test.cpp:189:44:189:47 | call to data | The underlying string object is destroyed after the call to 'data' returns. |
| test.cpp:191:29:191:32 | call to data | The underlying string object is destroyed after the call to 'data' returns. |
| test.cpp:193:47:193:51 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
| test.cpp:195:31:195:35 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
| test.cpp:165:34:165:38 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
| test.cpp:166:39:166:43 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
| test.cpp:167:44:167:48 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
| test.cpp:169:29:169:33 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
| test.cpp:178:37:178:41 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
| test.cpp:181:39:181:43 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
| test.cpp:183:37:183:41 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
| test.cpp:187:34:187:37 | call to data | The underlying temporary string object is destroyed after the call to 'data' returns. |
| test.cpp:188:39:188:42 | call to data | The underlying temporary string object is destroyed after the call to 'data' returns. |
| test.cpp:189:44:189:47 | call to data | The underlying temporary string object is destroyed after the call to 'data' returns. |
| test.cpp:191:29:191:32 | call to data | The underlying temporary string object is destroyed after the call to 'data' returns. |
| test.cpp:193:47:193:51 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
| test.cpp:195:31:195:35 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |

View File

@@ -41,99 +41,99 @@
| BoxedInt::~BoxedInt | true | 481 | 483 | |
| BoxedInt::~BoxedInt | true | 483 | 222 | |
| BoxedInt::~BoxedInt | true | 485 | 474 | |
| NonTrivial::NonTrivial | false | 543 | 543 | NonTrivial |
| NonTrivial::operator= | false | 549 | 549 | operator= |
| NonTrivial::~NonTrivial | false | 557 | 557 | ~NonTrivial |
| NonTrivial::~NonTrivial | false | 563 | 563 | return ... |
| NonTrivial::~NonTrivial | false | 565 | 565 | { ... } |
| NonTrivial::~NonTrivial | true | 563 | 557 | |
| NonTrivial::~NonTrivial | true | 565 | 563 | |
| NonTrivial::NonTrivial | false | 544 | 544 | NonTrivial |
| NonTrivial::operator= | false | 550 | 550 | operator= |
| NonTrivial::~NonTrivial | false | 558 | 558 | ~NonTrivial |
| NonTrivial::~NonTrivial | false | 564 | 564 | return ... |
| NonTrivial::~NonTrivial | false | 566 | 566 | { ... } |
| NonTrivial::~NonTrivial | true | 564 | 558 | |
| NonTrivial::~NonTrivial | true | 566 | 564 | |
| __va_list_tag::operator= | false | 66 | 66 | operator= |
| __va_list_tag::operator= | false | 72 | 72 | operator= |
| early_return | false | 799 | 799 | early_return |
| early_return | false | 807 | 807 | declaration |
| early_return | false | 812 | 812 | if (...) ... |
| early_return | false | 814 | 814 | x |
| early_return | false | 816 | 816 | (bool)... |
| early_return | false | 820 | 820 | declaration |
| early_return | false | 822 | 822 | return ... |
| early_return | false | 824 | 824 | { ... } |
| early_return | false | 826 | 826 | declaration |
| early_return | false | 831 | 831 | return ... |
| early_return | false | 833 | 833 | { ... } |
| early_return | false | 835 | 835 | inner |
| early_return | false | 837 | 837 | call to inner.~NonTrivial |
| early_return | false | 838 | 838 | before |
| early_return | false | 840 | 840 | call to before.~NonTrivial |
| early_return | false | 841 | 841 | inner |
| early_return | false | 842 | 842 | call to inner.~NonTrivial |
| early_return | false | 843 | 843 | before |
| early_return | false | 844 | 844 | call to before.~NonTrivial |
| early_return | false | 845 | 845 | after |
| early_return | false | 846 | 846 | call to after.~NonTrivial |
| early_return | true | 807 | 812 | |
| early_return | true | 812 | 814 | |
| early_return | true | 814 | 824 | T |
| early_return | true | 814 | 826 | F |
| early_return | true | 820 | 822 | |
| early_return | true | 822 | 841 | |
| early_return | true | 824 | 820 | |
| early_return | true | 826 | 831 | |
| early_return | true | 831 | 845 | |
| early_return | true | 833 | 807 | |
| early_return | true | 835 | 837 | |
| early_return | true | 837 | 826 | |
| early_return | true | 838 | 840 | |
| early_return | true | 840 | 799 | |
| early_return | true | 841 | 842 | |
| early_return | true | 842 | 838 | |
| early_return | true | 843 | 844 | |
| early_return | true | 844 | 799 | |
| early_return | true | 845 | 846 | |
| early_return | true | 846 | 843 | |
| early_throw | false | 749 | 749 | early_throw |
| early_throw | false | 757 | 757 | declaration |
| early_throw | false | 762 | 762 | if (...) ... |
| early_throw | false | 764 | 764 | x |
| early_throw | false | 766 | 766 | (bool)... |
| early_throw | false | 770 | 770 | declaration |
| early_throw | false | 772 | 772 | ExprStmt |
| early_throw | false | 774 | 774 | re-throw exception |
| early_throw | false | 776 | 776 | { ... } |
| early_throw | false | 778 | 778 | declaration |
| early_throw | false | 783 | 783 | return ... |
| early_throw | false | 785 | 785 | { ... } |
| early_throw | false | 787 | 787 | inner |
| early_throw | false | 789 | 789 | call to inner.~NonTrivial |
| early_throw | false | 790 | 790 | before |
| early_throw | false | 792 | 792 | call to before.~NonTrivial |
| early_throw | false | 793 | 793 | inner |
| early_throw | false | 794 | 794 | call to inner.~NonTrivial |
| early_throw | false | 795 | 795 | before |
| early_throw | false | 796 | 796 | call to before.~NonTrivial |
| early_throw | false | 797 | 797 | after |
| early_throw | false | 798 | 798 | call to after.~NonTrivial |
| early_throw | true | 757 | 762 | |
| early_throw | true | 762 | 764 | |
| early_throw | true | 764 | 776 | T |
| early_throw | true | 764 | 778 | F |
| early_throw | true | 770 | 772 | |
| early_throw | true | 772 | 774 | |
| early_throw | true | 774 | 793 | |
| early_throw | true | 776 | 770 | |
| early_throw | true | 778 | 783 | |
| early_throw | true | 783 | 797 | |
| early_throw | true | 785 | 757 | |
| early_throw | true | 787 | 789 | |
| early_throw | true | 789 | 778 | |
| early_throw | true | 790 | 792 | |
| early_throw | true | 792 | 749 | |
| early_throw | true | 793 | 794 | |
| early_throw | true | 794 | 790 | |
| early_throw | true | 795 | 796 | |
| early_throw | true | 796 | 749 | |
| early_throw | true | 797 | 798 | |
| early_throw | true | 798 | 795 | |
| early_return | false | 800 | 800 | early_return |
| early_return | false | 808 | 808 | declaration |
| early_return | false | 813 | 813 | if (...) ... |
| early_return | false | 815 | 815 | x |
| early_return | false | 817 | 817 | (bool)... |
| early_return | false | 821 | 821 | declaration |
| early_return | false | 823 | 823 | return ... |
| early_return | false | 825 | 825 | { ... } |
| early_return | false | 827 | 827 | declaration |
| early_return | false | 832 | 832 | return ... |
| early_return | false | 834 | 834 | { ... } |
| early_return | false | 836 | 836 | before |
| early_return | false | 838 | 838 | call to before.~NonTrivial |
| early_return | false | 839 | 839 | inner |
| early_return | false | 841 | 841 | call to inner.~NonTrivial |
| early_return | false | 842 | 842 | inner |
| early_return | false | 843 | 843 | call to inner.~NonTrivial |
| early_return | false | 844 | 844 | before |
| early_return | false | 845 | 845 | call to before.~NonTrivial |
| early_return | false | 846 | 846 | after |
| early_return | false | 847 | 847 | call to after.~NonTrivial |
| early_return | true | 808 | 813 | |
| early_return | true | 813 | 815 | |
| early_return | true | 815 | 825 | T |
| early_return | true | 815 | 827 | F |
| early_return | true | 821 | 823 | |
| early_return | true | 823 | 839 | |
| early_return | true | 825 | 821 | |
| early_return | true | 827 | 832 | |
| early_return | true | 832 | 846 | |
| early_return | true | 834 | 808 | |
| early_return | true | 836 | 838 | |
| early_return | true | 838 | 800 | |
| early_return | true | 839 | 841 | |
| early_return | true | 841 | 836 | |
| early_return | true | 842 | 843 | |
| early_return | true | 843 | 827 | |
| early_return | true | 844 | 845 | |
| early_return | true | 845 | 800 | |
| early_return | true | 846 | 847 | |
| early_return | true | 847 | 844 | |
| early_throw | false | 750 | 750 | early_throw |
| early_throw | false | 758 | 758 | declaration |
| early_throw | false | 763 | 763 | if (...) ... |
| early_throw | false | 765 | 765 | x |
| early_throw | false | 767 | 767 | (bool)... |
| early_throw | false | 771 | 771 | declaration |
| early_throw | false | 773 | 773 | ExprStmt |
| early_throw | false | 775 | 775 | re-throw exception |
| early_throw | false | 777 | 777 | { ... } |
| early_throw | false | 779 | 779 | declaration |
| early_throw | false | 784 | 784 | return ... |
| early_throw | false | 786 | 786 | { ... } |
| early_throw | false | 788 | 788 | before |
| early_throw | false | 790 | 790 | call to before.~NonTrivial |
| early_throw | false | 791 | 791 | inner |
| early_throw | false | 793 | 793 | call to inner.~NonTrivial |
| early_throw | false | 794 | 794 | inner |
| early_throw | false | 795 | 795 | call to inner.~NonTrivial |
| early_throw | false | 796 | 796 | before |
| early_throw | false | 797 | 797 | call to before.~NonTrivial |
| early_throw | false | 798 | 798 | after |
| early_throw | false | 799 | 799 | call to after.~NonTrivial |
| early_throw | true | 758 | 763 | |
| early_throw | true | 763 | 765 | |
| early_throw | true | 765 | 777 | T |
| early_throw | true | 765 | 779 | F |
| early_throw | true | 771 | 773 | |
| early_throw | true | 773 | 775 | |
| early_throw | true | 775 | 791 | |
| early_throw | true | 777 | 771 | |
| early_throw | true | 779 | 784 | |
| early_throw | true | 784 | 798 | |
| early_throw | true | 786 | 758 | |
| early_throw | true | 788 | 790 | |
| early_throw | true | 790 | 750 | |
| early_throw | true | 791 | 793 | |
| early_throw | true | 793 | 788 | |
| early_throw | true | 794 | 795 | |
| early_throw | true | 795 | 779 | |
| early_throw | true | 796 | 797 | |
| early_throw | true | 797 | 750 | |
| early_throw | true | 798 | 799 | |
| early_throw | true | 799 | 796 | |
| for_decl_bind | false | 153 | 153 | for_decl_bind |
| for_decl_bind | false | 161 | 161 | for(...;...;...) ... |
| for_decl_bind | false | 164 | 164 | call to BoxedInt |
@@ -194,108 +194,108 @@
| for_decl_bind | true | 225 | 219 | |
| for_decl_bind | true | 226 | 227 | |
| for_decl_bind | true | 227 | 182 | |
| for_loop_scope | false | 698 | 698 | for_loop_scope |
| for_loop_scope | false | 706 | 706 | declaration |
| for_loop_scope | false | 711 | 711 | for(...;...;...) ... |
| for_loop_scope | false | 716 | 716 | x |
| for_loop_scope | false | 720 | 720 | 10 |
| for_loop_scope | false | 721 | 721 | ... < ... |
| for_loop_scope | false | 726 | 726 | declaration |
| for_loop_scope | false | 728 | 728 | { ... } |
| for_loop_scope | false | 730 | 730 | declaration |
| for_loop_scope | false | 732 | 732 | x |
| for_loop_scope | false | 734 | 734 | ++ ... |
| for_loop_scope | false | 736 | 736 | return ... |
| for_loop_scope | false | 738 | 738 | { ... } |
| for_loop_scope | false | 740 | 740 | for_scope |
| for_loop_scope | false | 742 | 742 | call to for_scope.~NonTrivial |
| for_loop_scope | false | 743 | 743 | inner_scope |
| for_loop_scope | false | 745 | 745 | call to inner_scope.~NonTrivial |
| for_loop_scope | false | 746 | 746 | outer_scope |
| for_loop_scope | false | 748 | 748 | call to outer_scope.~NonTrivial |
| for_loop_scope | true | 706 | 711 | |
| for_loop_scope | true | 711 | 730 | |
| for_loop_scope | true | 716 | 720 | |
| for_loop_scope | true | 720 | 721 | |
| for_loop_scope | true | 721 | 728 | T |
| for_loop_scope | true | 721 | 740 | F |
| for_loop_scope | true | 726 | 743 | |
| for_loop_scope | true | 728 | 726 | |
| for_loop_scope | true | 730 | 716 | |
| for_loop_scope | true | 732 | 734 | |
| for_loop_scope | true | 734 | 716 | |
| for_loop_scope | true | 736 | 746 | |
| for_loop_scope | true | 738 | 706 | |
| for_loop_scope | true | 740 | 742 | |
| for_loop_scope | true | 742 | 736 | |
| for_loop_scope | true | 743 | 745 | |
| for_loop_scope | true | 745 | 732 | |
| for_loop_scope | true | 746 | 748 | |
| for_loop_scope | true | 748 | 698 | |
| gotos | false | 608 | 608 | gotos |
| gotos | false | 616 | 616 | declaration |
| gotos | false | 621 | 621 | if (...) ... |
| gotos | false | 623 | 623 | x |
| gotos | false | 625 | 625 | (bool)... |
| gotos | false | 626 | 626 | goto ... |
| gotos | false | 628 | 628 | x |
| gotos | false | 630 | 630 | ++ ... |
| gotos | false | 632 | 632 | initializer for y |
| gotos | false | 643 | 643 | declaration |
| gotos | false | 645 | 645 | label ...: |
| gotos | false | 647 | 647 | declaration |
| gotos | false | 649 | 649 | if (...) ... |
| gotos | false | 651 | 651 | y |
| gotos | false | 653 | 653 | (bool)... |
| gotos | false | 654 | 654 | goto ... |
| gotos | false | 656 | 656 | declaration |
| gotos | false | 658 | 658 | { ... } |
| gotos | false | 660 | 660 | label ...: |
| gotos | false | 662 | 662 | ExprStmt |
| gotos | false | 664 | 664 | x |
| gotos | false | 666 | 666 | -- ... |
| gotos | false | 668 | 668 | return ... |
| gotos | false | 670 | 670 | { ... } |
| gotos | false | 672 | 672 | nt2 |
| gotos | false | 674 | 674 | call to nt2.~NonTrivial |
| gotos | false | 675 | 675 | nt3 |
| gotos | false | 676 | 676 | call to nt3.~NonTrivial |
| gotos | false | 677 | 677 | nt2 |
| gotos | false | 678 | 678 | call to nt2.~NonTrivial |
| gotos | false | 679 | 679 | nt1 |
| gotos | false | 681 | 681 | call to nt1.~NonTrivial |
| gotos | true | 616 | 621 | |
| gotos | true | 621 | 623 | |
| gotos | true | 623 | 626 | T |
| gotos | true | 623 | 658 | F |
| gotos | true | 626 | 645 | |
| gotos | true | 628 | 630 | |
| gotos | true | 630 | 645 | |
| gotos | true | 632 | 628 | |
| gotos | true | 643 | 632 | |
| gotos | true | 643 | 645 | |
| gotos | true | 645 | 647 | |
| gotos | true | 647 | 649 | |
| gotos | true | 649 | 651 | |
| gotos | true | 651 | 654 | T |
| gotos | true | 651 | 656 | F |
| gotos | true | 654 | 677 | |
| gotos | true | 656 | 675 | |
| gotos | true | 658 | 643 | |
| gotos | true | 660 | 662 | |
| gotos | true | 662 | 664 | |
| gotos | true | 664 | 666 | |
| gotos | true | 666 | 668 | |
| gotos | true | 668 | 679 | |
| gotos | true | 670 | 616 | |
| gotos | true | 672 | 674 | |
| gotos | true | 674 | 660 | |
| gotos | true | 675 | 676 | |
| gotos | true | 676 | 672 | |
| gotos | true | 677 | 678 | |
| gotos | true | 678 | 660 | |
| gotos | true | 679 | 681 | |
| gotos | true | 681 | 608 | |
| for_loop_scope | false | 699 | 699 | for_loop_scope |
| for_loop_scope | false | 707 | 707 | declaration |
| for_loop_scope | false | 712 | 712 | for(...;...;...) ... |
| for_loop_scope | false | 717 | 717 | x |
| for_loop_scope | false | 721 | 721 | 10 |
| for_loop_scope | false | 722 | 722 | ... < ... |
| for_loop_scope | false | 727 | 727 | declaration |
| for_loop_scope | false | 729 | 729 | { ... } |
| for_loop_scope | false | 731 | 731 | declaration |
| for_loop_scope | false | 733 | 733 | x |
| for_loop_scope | false | 735 | 735 | ++ ... |
| for_loop_scope | false | 737 | 737 | return ... |
| for_loop_scope | false | 739 | 739 | { ... } |
| for_loop_scope | false | 741 | 741 | for_scope |
| for_loop_scope | false | 743 | 743 | call to for_scope.~NonTrivial |
| for_loop_scope | false | 744 | 744 | inner_scope |
| for_loop_scope | false | 746 | 746 | call to inner_scope.~NonTrivial |
| for_loop_scope | false | 747 | 747 | outer_scope |
| for_loop_scope | false | 749 | 749 | call to outer_scope.~NonTrivial |
| for_loop_scope | true | 707 | 712 | |
| for_loop_scope | true | 712 | 731 | |
| for_loop_scope | true | 717 | 721 | |
| for_loop_scope | true | 721 | 722 | |
| for_loop_scope | true | 722 | 729 | T |
| for_loop_scope | true | 722 | 741 | F |
| for_loop_scope | true | 727 | 744 | |
| for_loop_scope | true | 729 | 727 | |
| for_loop_scope | true | 731 | 717 | |
| for_loop_scope | true | 733 | 735 | |
| for_loop_scope | true | 735 | 717 | |
| for_loop_scope | true | 737 | 747 | |
| for_loop_scope | true | 739 | 707 | |
| for_loop_scope | true | 741 | 743 | |
| for_loop_scope | true | 743 | 737 | |
| for_loop_scope | true | 744 | 746 | |
| for_loop_scope | true | 746 | 733 | |
| for_loop_scope | true | 747 | 749 | |
| for_loop_scope | true | 749 | 699 | |
| gotos | false | 609 | 609 | gotos |
| gotos | false | 617 | 617 | declaration |
| gotos | false | 622 | 622 | if (...) ... |
| gotos | false | 624 | 624 | x |
| gotos | false | 626 | 626 | (bool)... |
| gotos | false | 627 | 627 | goto ... |
| gotos | false | 629 | 629 | x |
| gotos | false | 631 | 631 | ++ ... |
| gotos | false | 633 | 633 | initializer for y |
| gotos | false | 644 | 644 | declaration |
| gotos | false | 646 | 646 | label ...: |
| gotos | false | 648 | 648 | declaration |
| gotos | false | 650 | 650 | if (...) ... |
| gotos | false | 652 | 652 | y |
| gotos | false | 654 | 654 | (bool)... |
| gotos | false | 655 | 655 | goto ... |
| gotos | false | 657 | 657 | declaration |
| gotos | false | 659 | 659 | { ... } |
| gotos | false | 661 | 661 | label ...: |
| gotos | false | 663 | 663 | ExprStmt |
| gotos | false | 665 | 665 | x |
| gotos | false | 667 | 667 | -- ... |
| gotos | false | 669 | 669 | return ... |
| gotos | false | 671 | 671 | { ... } |
| gotos | false | 673 | 673 | nt2 |
| gotos | false | 675 | 675 | call to nt2.~NonTrivial |
| gotos | false | 676 | 676 | nt2 |
| gotos | false | 677 | 677 | call to nt2.~NonTrivial |
| gotos | false | 678 | 678 | nt3 |
| gotos | false | 679 | 679 | call to nt3.~NonTrivial |
| gotos | false | 680 | 680 | nt1 |
| gotos | false | 682 | 682 | call to nt1.~NonTrivial |
| gotos | true | 617 | 622 | |
| gotos | true | 622 | 624 | |
| gotos | true | 624 | 627 | T |
| gotos | true | 624 | 659 | F |
| gotos | true | 627 | 646 | |
| gotos | true | 629 | 631 | |
| gotos | true | 631 | 646 | |
| gotos | true | 633 | 629 | |
| gotos | true | 644 | 633 | |
| gotos | true | 644 | 646 | |
| gotos | true | 646 | 648 | |
| gotos | true | 648 | 650 | |
| gotos | true | 650 | 652 | |
| gotos | true | 652 | 655 | T |
| gotos | true | 652 | 657 | F |
| gotos | true | 655 | 673 | |
| gotos | true | 657 | 678 | |
| gotos | true | 659 | 644 | |
| gotos | true | 661 | 663 | |
| gotos | true | 663 | 665 | |
| gotos | true | 665 | 667 | |
| gotos | true | 667 | 669 | |
| gotos | true | 669 | 680 | |
| gotos | true | 671 | 617 | |
| gotos | true | 673 | 675 | |
| gotos | true | 675 | 661 | |
| gotos | true | 676 | 677 | |
| gotos | true | 677 | 661 | |
| gotos | true | 678 | 679 | |
| gotos | true | 679 | 676 | |
| gotos | true | 680 | 682 | |
| gotos | true | 682 | 609 | |
| if_decl_bind | false | 375 | 375 | if_decl_bind |
| if_decl_bind | false | 383 | 383 | if (...) ... |
| if_decl_bind | false | 386 | 386 | call to operator int |
@@ -350,45 +350,45 @@
| if_decl_bind | true | 435 | 383 | |
| if_decl_bind | true | 437 | 439 | |
| if_decl_bind | true | 439 | 424 | |
| never_destructs | false | 682 | 682 | never_destructs |
| never_destructs | false | 687 | 687 | declaration |
| never_destructs | false | 692 | 692 | label ...: |
| never_destructs | false | 694 | 694 | goto ... |
| never_destructs | false | 696 | 696 | { ... } |
| never_destructs | true | 687 | 692 | |
| never_destructs | true | 692 | 694 | |
| never_destructs | true | 694 | 692 | |
| never_destructs | true | 696 | 687 | |
| never_destructs | false | 683 | 683 | never_destructs |
| never_destructs | false | 688 | 688 | declaration |
| never_destructs | false | 693 | 693 | label ...: |
| never_destructs | false | 695 | 695 | goto ... |
| never_destructs | false | 697 | 697 | { ... } |
| never_destructs | true | 688 | 693 | |
| never_destructs | true | 693 | 695 | |
| never_destructs | true | 695 | 693 | |
| never_destructs | true | 697 | 688 | |
| operator delete | false | 476 | 476 | operator delete |
| operator new | false | 499 | 499 | operator new |
| simple | false | 871 | 871 | simple |
| simple | false | 876 | 876 | declaration |
| simple | false | 881 | 881 | return ... |
| simple | false | 883 | 883 | { ... } |
| simple | false | 885 | 885 | nt |
| simple | false | 887 | 887 | call to nt.~NonTrivial |
| simple | true | 876 | 881 | |
| simple | true | 881 | 885 | |
| simple | true | 883 | 876 | |
| simple | true | 885 | 887 | |
| simple | true | 887 | 871 | |
| simple2 | false | 847 | 847 | simple2 |
| simple2 | false | 852 | 852 | declaration |
| simple2 | false | 857 | 857 | declaration |
| simple2 | false | 862 | 862 | return ... |
| simple2 | false | 864 | 864 | { ... } |
| simple2 | false | 866 | 866 | one |
| simple2 | false | 868 | 868 | call to one.~NonTrivial |
| simple2 | false | 869 | 869 | two |
| simple2 | false | 870 | 870 | call to two.~NonTrivial |
| simple2 | true | 852 | 857 | |
| simple2 | true | 857 | 862 | |
| simple2 | true | 862 | 869 | |
| simple2 | true | 864 | 852 | |
| simple2 | true | 866 | 868 | |
| simple2 | true | 868 | 847 | |
| simple2 | true | 869 | 870 | |
| simple2 | true | 870 | 866 | |
| simple | false | 872 | 872 | simple |
| simple | false | 877 | 877 | declaration |
| simple | false | 882 | 882 | return ... |
| simple | false | 884 | 884 | { ... } |
| simple | false | 886 | 886 | nt |
| simple | false | 888 | 888 | call to nt.~NonTrivial |
| simple | true | 877 | 882 | |
| simple | true | 882 | 886 | |
| simple | true | 884 | 877 | |
| simple | true | 886 | 888 | |
| simple | true | 888 | 872 | |
| simple2 | false | 848 | 848 | simple2 |
| simple2 | false | 853 | 853 | declaration |
| simple2 | false | 858 | 858 | declaration |
| simple2 | false | 863 | 863 | return ... |
| simple2 | false | 865 | 865 | { ... } |
| simple2 | false | 867 | 867 | one |
| simple2 | false | 869 | 869 | call to one.~NonTrivial |
| simple2 | false | 870 | 870 | two |
| simple2 | false | 871 | 871 | call to two.~NonTrivial |
| simple2 | true | 853 | 858 | |
| simple2 | true | 858 | 863 | |
| simple2 | true | 863 | 870 | |
| simple2 | true | 865 | 853 | |
| simple2 | true | 867 | 869 | |
| simple2 | true | 869 | 848 | |
| simple2 | true | 870 | 871 | |
| simple2 | true | 871 | 867 | |
| switch_decl_bind | false | 276 | 276 | switch_decl_bind |
| switch_decl_bind | false | 284 | 284 | switch (...) ... |
| switch_decl_bind | false | 287 | 287 | call to operator int |
@@ -444,21 +444,21 @@
| switch_decl_bind | true | 310 | 313 | |
| switch_decl_bind | true | 313 | 315 | |
| switch_decl_bind | true | 315 | 317 | |
| switch_decl_bind | true | 317 | 371 | |
| switch_decl_bind | true | 317 | 368 | |
| switch_decl_bind | true | 319 | 324 | |
| switch_decl_bind | true | 324 | 326 | |
| switch_decl_bind | true | 326 | 328 | |
| switch_decl_bind | true | 328 | 330 | |
| switch_decl_bind | true | 330 | 332 | |
| switch_decl_bind | true | 332 | 334 | |
| switch_decl_bind | true | 334 | 373 | |
| switch_decl_bind | true | 334 | 371 | |
| switch_decl_bind | true | 336 | 338 | |
| switch_decl_bind | true | 338 | 340 | |
| switch_decl_bind | true | 340 | 342 | |
| switch_decl_bind | true | 342 | 344 | |
| switch_decl_bind | true | 344 | 348 | |
| switch_decl_bind | true | 348 | 349 | |
| switch_decl_bind | true | 349 | 368 | |
| switch_decl_bind | true | 349 | 373 | |
| switch_decl_bind | true | 351 | 300 | |
| switch_decl_bind | true | 351 | 319 | |
| switch_decl_bind | true | 351 | 336 | |
@@ -501,10 +501,11 @@
| while_decl_bind | true | 241 | 251 | |
| while_decl_bind | true | 243 | 241 | |
| while_decl_bind | true | 251 | 259 | T |
| while_decl_bind | true | 251 | 271 | F |
| while_decl_bind | true | 251 | 274 | F |
| while_decl_bind | true | 253 | 255 | |
| while_decl_bind | true | 255 | 257 | |
| while_decl_bind | true | 257 | 274 | |
| while_decl_bind | true | 257 | 243 | |
| while_decl_bind | true | 257 | 271 | |
| while_decl_bind | true | 259 | 253 | |
| while_decl_bind | true | 261 | 263 | |
| while_decl_bind | true | 263 | 265 | |
@@ -512,6 +513,5 @@
| while_decl_bind | true | 267 | 228 | |
| while_decl_bind | true | 269 | 236 | |
| while_decl_bind | true | 271 | 273 | |
| while_decl_bind | true | 273 | 261 | |
| while_decl_bind | true | 274 | 275 | |
| while_decl_bind | true | 275 | 243 | |
| while_decl_bind | true | 275 | 261 | |

View File

@@ -77,7 +77,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
/// "json.net"
/// }
/// </summary>
private void AddPackageDependencies(JObject json)
private void AddPackageDependencies(JObject json, string jsonPath)
{
// If there is more than one framework we need to pick just one.
// To ensure stability we pick one based on the lexicographic order of
@@ -91,7 +91,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
if (references is null)
{
logger.LogDebug("No references found in the targets section in the assets file.");
logger.LogDebug($"No references found in the targets section in '{jsonPath}'");
return;
}
@@ -154,7 +154,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
/// "microsoft.netcore.app.ref"
/// }
/// </summary>
private void AddFrameworkDependencies(JObject json)
private void AddFrameworkDependencies(JObject json, string jsonPath)
{
var frameworks = json
@@ -163,7 +163,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
if (frameworks is null)
{
logger.LogDebug("No framework section in assets.json.");
logger.LogDebug($"No framework section in '{jsonPath}'.");
return;
}
@@ -177,7 +177,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
if (references is null)
{
logger.LogDebug("No framework references in assets.json.");
logger.LogDebug($"No framework references in '{jsonPath}'.");
return;
}
@@ -196,8 +196,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
try
{
var obj = JObject.Parse(json);
AddPackageDependencies(obj);
AddFrameworkDependencies(obj);
AddPackageDependencies(obj, json);
AddFrameworkDependencies(obj, json);
return true;
}
catch (Exception e)

View File

@@ -94,7 +94,10 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
public HashSet<AssemblyLookupLocation> Restore()
{
var assemblyLookupLocations = new HashSet<AssemblyLookupLocation>();
var checkNugetFeedResponsiveness = EnvironmentVariables.GetBoolean(EnvironmentVariableNames.CheckNugetFeedResponsiveness);
var checkNugetFeedResponsiveness = EnvironmentVariables.GetBooleanOptOut(EnvironmentVariableNames.CheckNugetFeedResponsiveness);
logger.LogInfo($"Checking NuGet feed responsiveness: {checkNugetFeedResponsiveness}");
compilationInfoContainer.CompilationInfos.Add(("NuGet feed responsiveness checked", checkNugetFeedResponsiveness ? "1" : "0"));
try
{
if (checkNugetFeedResponsiveness && !CheckFeeds())

View File

@@ -20,17 +20,9 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
protected override bool IsEnabled()
{
var webViewExtractionOption = Environment.GetEnvironmentVariable(EnvironmentVariableNames.WebViewGeneration);
if (webViewExtractionOption == null ||
bool.TryParse(webViewExtractionOption, out var shouldExtractWebViews) &&
shouldExtractWebViews)
{
compilationInfoContainer.CompilationInfos.Add(("WebView extraction enabled", "1"));
return true;
}
compilationInfoContainer.CompilationInfos.Add(("WebView extraction enabled", "0"));
return false;
var webViewExtractionOption = EnvironmentVariables.GetBooleanOptOut(EnvironmentVariableNames.WebViewGeneration);
compilationInfoContainer.CompilationInfos.Add(("WebView extraction enabled", webViewExtractionOption ? "1" : "0"));
return webViewExtractionOption;
}
protected override ICollection<string> AdditionalFiles => fileProvider.RazorViews;

View File

@@ -29,6 +29,19 @@ namespace Semmle.Util
return threads;
}
public static bool GetBooleanOptOut(string name)
{
var env = Environment.GetEnvironmentVariable(name);
if (env == null ||
bool.TryParse(env, out var value) &&
value)
{
return true;
}
return false;
}
public static bool GetBoolean(string name)
{
var env = Environment.GetEnvironmentVariable(name);

View File

@@ -1,3 +1,7 @@
## 1.7.15
No user-facing changes.
## 1.7.14
No user-facing changes.

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.7.14
lastReleaseVersion: 1.7.15

View File

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

View File

@@ -1,3 +1,7 @@
## 1.7.15
No user-facing changes.
## 1.7.14
No user-facing changes.

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.7.14
lastReleaseVersion: 1.7.15

View File

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

View File

@@ -1,5 +1,7 @@
| All Nuget feeds reachable | 1.0 |
| Failed project restore with package source error | 0.0 |
| Failed solution restore with package source error | 0.0 |
| NuGet feed responsiveness checked | 1.0 |
| Project files on filesystem | 1.0 |
| Resource extraction enabled | 1.0 |
| Restored .NET framework variants | 1.0 |

View File

@@ -1,6 +1,8 @@
| All Nuget feeds reachable | 1.0 |
| Failed project restore with package source error | 1.0 |
| Failed solution restore with package source error | 0.0 |
| Fallback nuget restore | 1.0 |
| NuGet feed responsiveness checked | 1.0 |
| Project files on filesystem | 1.0 |
| Resolved assembly conflicts | 7.0 |
| Resource extraction enabled | 0.0 |

View File

@@ -1,6 +1,7 @@
| All Nuget feeds reachable | 0.0 |
| Fallback nuget restore | 1.0 |
| Inherited Nuget feed count | 1.0 |
| NuGet feed responsiveness checked | 1.0 |
| Project files on filesystem | 1.0 |
| Resolved assembly conflicts | 7.0 |
| Resource extraction enabled | 0.0 |

View File

@@ -2,7 +2,7 @@ from create_database_utils import *
from diagnostics_test_utils import *
import os
os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK"] = "true" # Enable NuGet feed check
# os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK"] = "true" # Nuget feed check is enabled by default
os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_TIMEOUT"] = "1" # 1ms, the GET request should fail with such short timeout
os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_LIMIT"] = "1" # Limit the count of checks to 1
os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_EXCLUDED"] = "https://abc.de:8000/packages/" # Exclude this feed from check

View File

@@ -1,3 +1,15 @@
## 0.10.0
### Breaking Changes
* Deleted the deprecated `getAssemblyName` predicate from the `Operator` class. Use `getFunctionName` instead.
* Deleted the deprecated `LShiftOperator`, `RShiftOperator`, `AssignLShiftExpr`, `AssignRShiftExpr`, `LShiftExpr`, and `RShiftExpr` aliases.
* Deleted the deprecated `getCallableDescription` predicate from the `ExternalApiDataNode` class. Use `hasQualifiedName` instead.
### Minor Analysis Improvements
* Generated .NET Runtime models for properties with both getters and setters have been removed as this is now handled by the data flow library.
## 0.9.1
### Minor Analysis Improvements

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Generated .NET Runtime models for properties with both getters and setters have been removed as this is now handled by the data flow library.

View File

@@ -0,0 +1,11 @@
## 0.10.0
### Breaking Changes
* Deleted the deprecated `getAssemblyName` predicate from the `Operator` class. Use `getFunctionName` instead.
* Deleted the deprecated `LShiftOperator`, `RShiftOperator`, `AssignLShiftExpr`, `AssignRShiftExpr`, `LShiftExpr`, and `RShiftExpr` aliases.
* Deleted the deprecated `getCallableDescription` predicate from the `ExternalApiDataNode` class. Use `hasQualifiedName` instead.
### Minor Analysis Improvements
* Generated .NET Runtime models for properties with both getters and setters have been removed as this is now handled by the data flow library.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.9.1
lastReleaseVersion: 0.10.0

View File

@@ -1,4 +1,6 @@
extensions:
# Make sure that the extensible model predicates have at least one definition
# to avoid errors about undefined extensionals.
- addsTo:
pack: codeql/csharp-all
extensible: sourceModel

View File

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

View File

@@ -527,13 +527,6 @@ class Destructor extends Callable, Member, Attributable, @destructor {
* (`BinaryOperator`), or a conversion operator (`ConversionOperator`).
*/
class Operator extends Callable, Member, Attributable, Overridable, @operator {
/**
* DEPRECATED: use `getFunctionName()` instead.
*
* Gets the assembly name of this operator.
*/
deprecated string getAssemblyName() { result = this.getFunctionName() }
override string getName() { operators(this, _, result, _, _, _) }
override string getUndecoratedName() { operators(this, _, result, _, _, _) }
@@ -989,9 +982,6 @@ class LeftShiftOperator extends BinaryOperator {
override string getAPrimaryQlClass() { result = "LeftShiftOperator" }
}
/** DEPRECATED: Alias for LeftShiftOperator. */
deprecated class LShiftOperator = LeftShiftOperator;
/**
* A user-defined right shift operator (`>>`), for example
*
@@ -1007,9 +997,6 @@ class RightShiftOperator extends BinaryOperator {
override string getAPrimaryQlClass() { result = "RightShiftOperator" }
}
/** DEPRECATED: Alias for RightShiftOperator. */
deprecated class RShiftOperator = RightShiftOperator;
/**
* A user-defined unsigned right shift operator (`>>>`), for example
*

View File

@@ -51,8 +51,6 @@ class TopLevelExprParent extends Element, @top_level_expr_parent {
final Expr getAChildExpr() { result = this.getChildExpr(_) }
}
private predicate hasNoSourceLocation(Element e) { not e.getALocation() instanceof SourceLocation }
/** INTERNAL: Do not use. */
Expr getExpressionBody(Callable c) {
result = c.getAChildExpr() and
@@ -67,17 +65,46 @@ private ControlFlowElement getBody(Callable c) {
result = getStatementBody(c)
}
pragma[nomagic]
private SourceLocation getASourceLocation(Element e) {
result = e.getALocation().(SourceLocation) and
not exists(e.getALocation().(SourceLocation).getMappedLocation())
or
result = e.getALocation().(SourceLocation).getMappedLocation()
}
pragma[nomagic]
private predicate hasNoSourceLocation(Element e) { not exists(getASourceLocation(e)) }
pragma[nomagic]
private Location getFirstSourceLocation(Element e) {
result =
min(Location l, string filepath, int startline, int startcolumn, int endline, int endcolumn |
l = getASourceLocation(e) and
l.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
l order by filepath, startline, startcolumn, endline, endcolumn
)
}
cached
private module Cached {
cached
Location bestLocation(Element e) {
result = e.getALocation().(SourceLocation) and
not exists(e.getALocation().(SourceLocation).getMappedLocation())
or
result = e.getALocation().(SourceLocation).getMappedLocation()
(
if e.(Modifiable).isPartial() or e instanceof Namespace
then result = getASourceLocation(e)
else result = getFirstSourceLocation(e)
)
or
hasNoSourceLocation(e) and
result = min(Location l | l = e.getALocation() | l order by l.getFile().toString())
result =
min(Location l, string filepath |
l = e.getALocation() and
l.hasLocationInfo(filepath, _, _, _, _)
|
l order by filepath
)
or
not exists(e.getALocation()) and
result instanceof EmptyLocation

View File

@@ -63,7 +63,7 @@ class EmptyLocation extends Location {
*/
class SourceLocation extends Location, @location_default {
/** Gets the location that takes into account `#line` directives, if any. */
Location getMappedLocation() {
SourceLocation getMappedLocation() {
locations_mapped(this, result) and
not exists(LineDirective l | l.getALocation() = this)
}

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