mirror of
https://github.com/github/codeql.git
synced 2026-07-07 20:45:28 +02:00
Compare commits
111 Commits
codeql-cli
...
criemen/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
205209c324 | ||
|
|
5d5e31378b | ||
|
|
5cde3fa697 | ||
|
|
eb0621ab7a | ||
|
|
c0cf1c7c8c | ||
|
|
d5475c4a89 | ||
|
|
7ca54a6f94 | ||
|
|
e8cb8b4f81 | ||
|
|
ba64cf3016 | ||
|
|
807e6795a7 | ||
|
|
880262d462 | ||
|
|
95ff5bae65 | ||
|
|
6cbe16e0c2 | ||
|
|
75615f2817 | ||
|
|
c07bf65eb6 | ||
|
|
8def1c2c13 | ||
|
|
1b90f22e84 | ||
|
|
ecdf62376d | ||
|
|
96d69ca49c | ||
|
|
daea674095 | ||
|
|
315f439135 | ||
|
|
e4cf7df38f | ||
|
|
b8b3689251 | ||
|
|
0693bf9e75 | ||
|
|
ccad70897d | ||
|
|
3239af9973 | ||
|
|
f7113e0105 | ||
|
|
2cff081f2b | ||
|
|
f99cb3f649 | ||
|
|
dfdd79d8cf | ||
|
|
b912918d8b | ||
|
|
ef88f3ed09 | ||
|
|
d909f2bc4f | ||
|
|
9bfb189fa7 | ||
|
|
322fa36359 | ||
|
|
4a47e11a16 | ||
|
|
83249cd9c2 | ||
|
|
c6185b30ba | ||
|
|
9ce08c586c | ||
|
|
7d92ec5ddf | ||
|
|
9157dee0db | ||
|
|
677520aa8e | ||
|
|
16dcc0969b | ||
|
|
09e59ccf44 | ||
|
|
a8f2cbc2b1 | ||
|
|
c00d0d302d | ||
|
|
5a7a1dc92e | ||
|
|
c480431ec0 | ||
|
|
f7fc2e0b00 | ||
|
|
397e641f2f | ||
|
|
00cbfaf40e | ||
|
|
dc4604f5a5 | ||
|
|
40b6e1624f | ||
|
|
22e843abc6 | ||
|
|
3c70a2d7df | ||
|
|
541effb8cb | ||
|
|
248ffa15a2 | ||
|
|
5843326b5c | ||
|
|
3a2b0a2feb | ||
|
|
07dd6d5c8d | ||
|
|
708d12624f | ||
|
|
3eddd3114f | ||
|
|
61ce7252e6 | ||
|
|
b86aeb68ae | ||
|
|
cf025e1924 | ||
|
|
a200ced2d6 | ||
|
|
c04e59611b | ||
|
|
c5a87c95d8 | ||
|
|
797f675285 | ||
|
|
c32c810ae7 | ||
|
|
32fe084630 | ||
|
|
0715c4ac5a | ||
|
|
99928b82ed | ||
|
|
377c6b4cc8 | ||
|
|
2939c89f7a | ||
|
|
bb6cc92728 | ||
|
|
d736426529 | ||
|
|
806d42852c | ||
|
|
676bcf39a5 | ||
|
|
94364f724e | ||
|
|
0fa5a1f274 | ||
|
|
5c454bdd8c | ||
|
|
f194c70e8a | ||
|
|
179270ffc1 | ||
|
|
401717d739 | ||
|
|
527409d05f | ||
|
|
d3d2e2188d | ||
|
|
141af7cc87 | ||
|
|
6e3dddede0 | ||
|
|
683fe26034 | ||
|
|
ea1b8a3999 | ||
|
|
5f0efc19fa | ||
|
|
50775d0c53 | ||
|
|
9874d40d29 | ||
|
|
044ee9b08a | ||
|
|
3195f0c828 | ||
|
|
f95b33049e | ||
|
|
b754706e44 | ||
|
|
9db32f4d26 | ||
|
|
acb2bbb2a3 | ||
|
|
06f987ad58 | ||
|
|
d7c784ef2f | ||
|
|
830b83f653 | ||
|
|
f77f91ef49 | ||
|
|
78ddb998a2 | ||
|
|
b12f4d97f8 | ||
|
|
ee3085e15e | ||
|
|
53e96e5adf | ||
|
|
6f60eb9e1a | ||
|
|
845f384df6 | ||
|
|
39c52c9ecf |
5
.lfsconfig
Normal file
5
.lfsconfig
Normal 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
|
||||
@@ -21,8 +21,7 @@ bazel_dep(name = "bazel_skylib", version = "1.5.0")
|
||||
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 = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
|
||||
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0")
|
||||
|
||||
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
|
||||
pip.parse(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.13.0
|
||||
version: 0.13.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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."
|
||||
@@ -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`.
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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.
|
||||
11
cpp/ql/src/experimental/Best Practices/GuardedFree.cpp
Normal file
11
cpp/ql/src/experimental/Best Practices/GuardedFree.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
void test()
|
||||
{
|
||||
char *foo = malloc(100);
|
||||
|
||||
// BAD
|
||||
if (foo)
|
||||
free(foo);
|
||||
|
||||
// GOOD
|
||||
free(foo);
|
||||
}
|
||||
18
cpp/ql/src/experimental/Best Practices/GuardedFree.qhelp
Normal file
18
cpp/ql/src/experimental/Best Practices/GuardedFree.qhelp
Normal 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>
|
||||
26
cpp/ql/src/experimental/Best Practices/GuardedFree.ql
Normal file
26
cpp/ql/src/experimental/Best Practices/GuardedFree.ql
Normal 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"
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.9.11
|
||||
version: 0.9.12-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -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 |
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security/CWE/CWE-416/IteratorToExpiredContainer.ql
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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 | * ... |
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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. |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-416/IteratorToExpiredContainer.ql
|
||||
@@ -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. |
|
||||
|
||||
@@ -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 | |
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.7.15
|
||||
version: 1.7.16-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.7.15
|
||||
version: 1.7.16-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-all
|
||||
version: 0.10.0
|
||||
version: 0.10.1-dev
|
||||
groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-queries
|
||||
version: 0.8.15
|
||||
version: 0.8.16-dev
|
||||
groups:
|
||||
- csharp
|
||||
- queries
|
||||
|
||||
@@ -575,7 +575,7 @@ func getModMode(depMode DependencyInstallerMode, baseDir string) ModMode {
|
||||
// Tries to open `go.mod` and read a go directive, returning the version and whether it was found.
|
||||
// The version string is returned in the "1.2.3" format.
|
||||
func tryReadGoDirective(path string) GoVersionInfo {
|
||||
versionRe := regexp.MustCompile(`(?m)^go[ \t\r]+([0-9]+\.[0-9]+(\.[0-9]+)?)$`)
|
||||
versionRe := regexp.MustCompile(`(?m)^go[ \t\r]+([0-9]+\.[0-9]+(\.[0-9]+)?)`)
|
||||
goMod, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Println("Failed to read go.mod to check for missing Go version")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql-go-consistency-queries
|
||||
version: 0.0.14
|
||||
version: 0.0.15-dev
|
||||
groups:
|
||||
- go
|
||||
- queries
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
extensions:
|
||||
# Make sure that the extensible model predicates are at least defined as empty.
|
||||
# Make sure that the extensible model predicates have at least one definition
|
||||
# to avoid errors about undefined extensionals.
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sourceModel
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/go-all
|
||||
version: 0.8.0
|
||||
version: 0.8.1-dev
|
||||
groups: go
|
||||
dbscheme: go.dbscheme
|
||||
extractor: go
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/go-queries
|
||||
version: 0.7.15
|
||||
version: 0.7.16-dev
|
||||
groups:
|
||||
- go
|
||||
- queries
|
||||
|
||||
@@ -276,7 +276,6 @@ public class Env {
|
||||
*/
|
||||
ODASA_SRC,
|
||||
ODASA_DB,
|
||||
ODASA_BUILD_ERROR_DIR,
|
||||
TRAP_FOLDER,
|
||||
SOURCE_ARCHIVE,
|
||||
ODASA_OUTPUT,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/java-automodel-queries
|
||||
version: 0.0.22
|
||||
version: 0.0.23-dev
|
||||
groups:
|
||||
- java
|
||||
- automodel
|
||||
|
||||
4
java/ql/lib/change-notes/2024-04-26-env-vars.md
Normal file
4
java/ql/lib/change-notes/2024-04-26-env-vars.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
* The Java extractor no longer supports the `ODASA_BUILD_ERROR_DIR` legacy environment variable.
|
||||
@@ -1,5 +1,6 @@
|
||||
extensions:
|
||||
# Make sure that the extensible model predicates are at least defined as empty.
|
||||
# Make sure that the extensible model predicates have at least one definition
|
||||
# to avoid errors about undefined extensionals.
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: sourceModel
|
||||
@@ -15,4 +16,4 @@ extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: neutralModel
|
||||
data: []
|
||||
data: []
|
||||
@@ -1,6 +1,6 @@
|
||||
# Define the extensible prediactes related to experimental queries
|
||||
# to at least be empty.
|
||||
extensions:
|
||||
# Make sure that the extensible model predicates have at least one definition
|
||||
# to avoid errors about undefined extensionals.
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: experimentalSourceModel
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/java-all
|
||||
version: 0.10.0
|
||||
version: 0.10.1-dev
|
||||
groups: java
|
||||
dbscheme: config/semmlecode.dbscheme
|
||||
extractor: java
|
||||
|
||||
39
java/ql/lib/semmle/code/java/dataflow/ApiSinks.qll
Normal file
39
java/ql/lib/semmle/code/java/dataflow/ApiSinks.qll
Normal file
@@ -0,0 +1,39 @@
|
||||
/** Provides classes representing various flow sinks for data flow / taint tracking. */
|
||||
|
||||
private import semmle.code.java.dataflow.FlowSinks as FlowSinks
|
||||
|
||||
final class SinkNode = FlowSinks::ApiSinkNode;
|
||||
|
||||
/**
|
||||
* Module that adds all API like sinks to `SinkNode`, excluding sinks for cryptography based
|
||||
* queries, and queries where sinks are not succifiently defined (eg. using broad method name matching).
|
||||
*/
|
||||
private module AllApiSinks {
|
||||
private import semmle.code.java.security.AndroidSensitiveCommunicationQuery
|
||||
private import semmle.code.java.security.ArbitraryApkInstallation
|
||||
private import semmle.code.java.security.CleartextStorageAndroidDatabaseQuery
|
||||
private import semmle.code.java.security.CleartextStorageAndroidFilesystemQuery
|
||||
private import semmle.code.java.security.CleartextStorageCookieQuery
|
||||
private import semmle.code.java.security.CleartextStorageSharedPrefsQuery
|
||||
private import semmle.code.java.security.ExternallyControlledFormatStringQuery
|
||||
private import semmle.code.java.security.InsecureBasicAuth
|
||||
private import semmle.code.java.security.IntentUriPermissionManipulation
|
||||
private import semmle.code.java.security.InsecureLdapAuth
|
||||
private import semmle.code.java.security.InsecureTrustManager
|
||||
private import semmle.code.java.security.JndiInjection
|
||||
private import semmle.code.java.security.JWT
|
||||
private import semmle.code.java.security.OgnlInjection
|
||||
private import semmle.code.java.security.SensitiveResultReceiverQuery
|
||||
private import semmle.code.java.security.SensitiveUiQuery
|
||||
private import semmle.code.java.security.SpelInjection
|
||||
private import semmle.code.java.security.SpelInjectionQuery
|
||||
private import semmle.code.java.security.QueryInjection
|
||||
private import semmle.code.java.security.TempDirLocalInformationDisclosureQuery
|
||||
private import semmle.code.java.security.UnsafeAndroidAccess
|
||||
private import semmle.code.java.security.UnsafeContentUriResolution
|
||||
private import semmle.code.java.security.UnsafeDeserializationQuery
|
||||
private import semmle.code.java.security.UrlRedirect
|
||||
private import semmle.code.java.security.WebviewDebuggingEnabledQuery
|
||||
private import semmle.code.java.security.XPath
|
||||
private import semmle.code.java.security.XSS
|
||||
}
|
||||
23
java/ql/lib/semmle/code/java/dataflow/ApiSources.qll
Normal file
23
java/ql/lib/semmle/code/java/dataflow/ApiSources.qll
Normal file
@@ -0,0 +1,23 @@
|
||||
/** Provides classes representing various flow sources for data flow / taint tracking. */
|
||||
|
||||
private import semmle.code.java.dataflow.FlowSources as FlowSources
|
||||
|
||||
final class SourceNode = FlowSources::ApiSourceNode;
|
||||
|
||||
/**
|
||||
* Module that adds all API like sources to `SourceNode`, excluding some sources for cryptography based
|
||||
* queries, and queries where sources are not succifiently defined (eg. using broad method name matching).
|
||||
*/
|
||||
private module AllApiSources {
|
||||
private import semmle.code.java.security.ArbitraryApkInstallation
|
||||
private import semmle.code.java.security.CleartextStorageAndroidDatabaseQuery
|
||||
private import semmle.code.java.security.CleartextStorageAndroidFilesystemQuery
|
||||
private import semmle.code.java.security.CleartextStorageCookieQuery
|
||||
private import semmle.code.java.security.CleartextStorageSharedPrefsQuery
|
||||
private import semmle.code.java.security.ImplicitPendingIntentsQuery
|
||||
private import semmle.code.java.security.ImproperIntentVerificationQuery
|
||||
private import semmle.code.java.security.InsecureTrustManager
|
||||
private import semmle.code.java.security.JWT
|
||||
private import semmle.code.java.security.StackTraceExposureQuery
|
||||
private import semmle.code.java.security.ZipSlipQuery
|
||||
}
|
||||
18
java/ql/lib/semmle/code/java/dataflow/FlowSinks.qll
Normal file
18
java/ql/lib/semmle/code/java/dataflow/FlowSinks.qll
Normal file
@@ -0,0 +1,18 @@
|
||||
/** Provides classes representing various flow sinks for data flow / taint tracking. */
|
||||
|
||||
private import java
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
|
||||
/**
|
||||
* A data flow sink node for an API, which should be considered
|
||||
* supported for a modeling perspective.
|
||||
*/
|
||||
abstract class ApiSinkNode extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* Add all sink models as data sinks.
|
||||
*/
|
||||
private class ApiSinkNodeExternal extends ApiSinkNode {
|
||||
ApiSinkNodeExternal() { sinkNode(this, _) }
|
||||
}
|
||||
@@ -194,15 +194,17 @@ private class AndroidExternalStorageSource extends RemoteFlowSource {
|
||||
}
|
||||
|
||||
/** Class for `tainted` user input. */
|
||||
abstract class UserInput extends DataFlow::Node { }
|
||||
abstract class UserInput extends SourceNode { }
|
||||
|
||||
/**
|
||||
* Input that may be controlled by a remote user.
|
||||
*/
|
||||
private class RemoteUserInput extends UserInput instanceof RemoteFlowSource { }
|
||||
private class RemoteUserInput extends UserInput instanceof RemoteFlowSource {
|
||||
override string getThreatModel() { result = RemoteFlowSource.super.getThreatModel() }
|
||||
}
|
||||
|
||||
/** A node with input that may be controlled by a local user. */
|
||||
abstract class LocalUserInput extends UserInput, SourceNode {
|
||||
abstract class LocalUserInput extends UserInput {
|
||||
override string getThreatModel() { result = "local" }
|
||||
}
|
||||
|
||||
@@ -385,3 +387,18 @@ class AndroidJavascriptInterfaceMethodParameter extends RemoteFlowSource {
|
||||
result = "Parameter of method with JavascriptInterface annotation"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow source node for an API, which should be considered
|
||||
* supported for a modeling perspective.
|
||||
*/
|
||||
abstract class ApiSourceNode extends DataFlow::Node { }
|
||||
|
||||
private class AddSourceNodes extends ApiSourceNode instanceof SourceNode { }
|
||||
|
||||
/**
|
||||
* Add all source models as data sources.
|
||||
*/
|
||||
private class ApiSourceNodeExternal extends ApiSourceNode {
|
||||
ApiSourceNodeExternal() { sourceNode(this, _) }
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.frameworks.android.Intent
|
||||
import semmle.code.java.security.SensitiveActions
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
|
||||
/**
|
||||
* Gets regular expression for matching names of Android variables that indicate the value being held contains sensitive information.
|
||||
@@ -151,17 +152,24 @@ deprecated class SensitiveCommunicationConfig extends TaintTracking::Configurati
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensitive communication sink node.
|
||||
*/
|
||||
private class SensitiveCommunicationSink extends ApiSinkNode {
|
||||
SensitiveCommunicationSink() {
|
||||
isSensitiveBroadcastSink(this)
|
||||
or
|
||||
isStartActivityOrServiceSink(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint configuration tracking flow from variables containing sensitive information to broadcast Intents.
|
||||
*/
|
||||
module SensitiveCommunicationConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof SensitiveInfoExpr }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
isSensitiveBroadcastSink(sink)
|
||||
or
|
||||
isStartActivityOrServiceSink(sink)
|
||||
}
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof SensitiveCommunicationSink }
|
||||
|
||||
/**
|
||||
* Holds if broadcast doesn't specify receiving package name of the 3rd party app
|
||||
|
||||
@@ -4,6 +4,7 @@ import java
|
||||
import semmle.code.java.frameworks.android.Intent
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
/** A string literal that represents the MIME type for Android APKs. */
|
||||
@@ -48,7 +49,7 @@ class SetDataMethod extends Method {
|
||||
}
|
||||
|
||||
/** A dataflow sink for the URI of an intent. */
|
||||
class SetDataSink extends DataFlow::ExprNode {
|
||||
class SetDataSink extends ApiSinkNode, DataFlow::ExprNode {
|
||||
SetDataSink() {
|
||||
exists(MethodCall ma |
|
||||
this.getExpr() = ma.getQualifier() and
|
||||
@@ -69,7 +70,7 @@ class UriConstructorMethod extends Method {
|
||||
* A dataflow source representing the URIs which an APK not controlled by the
|
||||
* application may come from. Including external storage and web URLs.
|
||||
*/
|
||||
class ExternalApkSource extends DataFlow::Node {
|
||||
class ExternalApkSource extends ApiSourceNode {
|
||||
ExternalApkSource() {
|
||||
sourceNode(this, "android-external-storage-dir") or
|
||||
this.asExpr().(MethodCall).getMethod() instanceof UriConstructorMethod or
|
||||
|
||||
@@ -6,6 +6,8 @@ import semmle.code.java.frameworks.android.ContentProviders
|
||||
import semmle.code.java.frameworks.android.Intent
|
||||
import semmle.code.java.frameworks.android.SQLite
|
||||
import semmle.code.java.security.CleartextStorageQuery
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
private class LocalDatabaseCleartextStorageSink extends CleartextStorageSink {
|
||||
LocalDatabaseCleartextStorageSink() { localDatabaseInput(_, this.asExpr()) }
|
||||
@@ -96,15 +98,24 @@ private predicate localDatabaseStore(DataFlow::Node database, MethodCall store)
|
||||
)
|
||||
}
|
||||
|
||||
private module LocalDatabaseFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof LocalDatabaseOpenMethodCall
|
||||
}
|
||||
/**
|
||||
* A local database open method call source node.
|
||||
*/
|
||||
private class LocalDatabaseOpenMethodCallSource extends ApiSourceNode {
|
||||
LocalDatabaseOpenMethodCallSource() { this.asExpr() instanceof LocalDatabaseOpenMethodCall }
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
localDatabaseInput(sink, _) or
|
||||
localDatabaseStore(sink, _)
|
||||
}
|
||||
/**
|
||||
* A local database sink node.
|
||||
*/
|
||||
private class LocalDatabaseSink extends ApiSinkNode {
|
||||
LocalDatabaseSink() { localDatabaseInput(this, _) or localDatabaseStore(this, _) }
|
||||
}
|
||||
|
||||
private module LocalDatabaseFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalDatabaseOpenMethodCallSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof LocalDatabaseSink }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
// Adds a step for tracking databases through field flow, that is, a database is opened and
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
import semmle.code.java.security.CleartextStorageQuery
|
||||
import semmle.code.xml.AndroidManifest
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
private class AndroidFilesystemCleartextStorageSink extends CleartextStorageSink {
|
||||
AndroidFilesystemCleartextStorageSink() {
|
||||
@@ -79,13 +81,27 @@ private class CloseFileMethod extends Method {
|
||||
}
|
||||
}
|
||||
|
||||
private module FilesystemFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof LocalFileOpenCall }
|
||||
/**
|
||||
* A local file open call source node.
|
||||
*/
|
||||
private class LocalFileOpenCallSource extends ApiSourceNode {
|
||||
LocalFileOpenCallSource() { this.asExpr() instanceof LocalFileOpenCall }
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
filesystemInput(sink, _) or
|
||||
closesFile(sink, _)
|
||||
/**
|
||||
* A local file sink node.
|
||||
*/
|
||||
private class LocalFileSink extends ApiSinkNode {
|
||||
LocalFileSink() {
|
||||
filesystemInput(this, _) or
|
||||
closesFile(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
private module FilesystemFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof LocalFileOpenCallSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof LocalFileSink }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
// Add nested Writer constructors as extra data flow steps
|
||||
|
||||
@@ -4,6 +4,8 @@ import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
deprecated import semmle.code.java.dataflow.DataFlow3
|
||||
import semmle.code.java.security.CleartextStorageQuery
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
private class CookieCleartextStorageSink extends CleartextStorageSink {
|
||||
CookieCleartextStorageSink() { this.asExpr() = cookieInput(_) }
|
||||
@@ -37,10 +39,24 @@ private predicate cookieStore(DataFlow::Node cookie, Expr store) {
|
||||
)
|
||||
}
|
||||
|
||||
private module CookieToStoreFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof Cookie }
|
||||
/**
|
||||
* A cookie source node.
|
||||
*/
|
||||
private class CookieSource extends ApiSourceNode {
|
||||
CookieSource() { this.asExpr() instanceof Cookie }
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { cookieStore(sink, _) }
|
||||
/**
|
||||
* A cookie store sink node.
|
||||
*/
|
||||
private class CookieStoreSink extends ApiSinkNode {
|
||||
CookieStoreSink() { cookieStore(this, _) }
|
||||
}
|
||||
|
||||
private module CookieToStoreFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof CookieSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof CookieStoreSink }
|
||||
}
|
||||
|
||||
private module CookieToStoreFlow = DataFlow::Global<CookieToStoreFlowConfig>;
|
||||
|
||||
@@ -4,6 +4,8 @@ import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.frameworks.android.SharedPreferences
|
||||
import semmle.code.java.security.CleartextStorageQuery
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
private class SharedPrefsCleartextStorageSink extends CleartextStorageSink {
|
||||
SharedPrefsCleartextStorageSink() {
|
||||
@@ -67,16 +69,30 @@ private predicate sharedPreferencesStore(DataFlow::Node editor, MethodCall m) {
|
||||
editor.asExpr() = m.getQualifier().getUnderlyingExpr()
|
||||
}
|
||||
|
||||
/** Flow from `SharedPreferences.Editor` to either a setter or a store method. */
|
||||
private module SharedPreferencesFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) {
|
||||
src.asExpr() instanceof SharedPreferencesEditorMethodCall
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sharedPreferencesInput(sink, _) or
|
||||
sharedPreferencesStore(sink, _)
|
||||
/**
|
||||
* A shared preferences editor method call source node.
|
||||
*/
|
||||
private class SharedPreferencesEditorMethodCallSource extends ApiSourceNode {
|
||||
SharedPreferencesEditorMethodCallSource() {
|
||||
this.asExpr() instanceof SharedPreferencesEditorMethodCall
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A shared preferences sink node.
|
||||
*/
|
||||
private class SharedPreferencesSink extends ApiSinkNode {
|
||||
SharedPreferencesSink() {
|
||||
sharedPreferencesInput(this, _) or
|
||||
sharedPreferencesStore(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
/** Flow from `SharedPreferences.Editor` to either a setter or a store method. */
|
||||
private module SharedPreferencesFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof SharedPreferencesEditorMethodCallSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof SharedPreferencesSink }
|
||||
}
|
||||
|
||||
private module SharedPreferencesFlow = DataFlow::Global<SharedPreferencesFlowConfig>;
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
/** Provides a taint-tracking configuration to reason about externally controlled format string vulnerabilities. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.StringFormat
|
||||
|
||||
/**
|
||||
* A string format sink node.
|
||||
*/
|
||||
private class StringFormatSink extends ApiSinkNode {
|
||||
StringFormatSink() { this.asExpr() = any(StringFormat formatCall).getFormatArgument() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for externally controlled format string vulnerabilities.
|
||||
*/
|
||||
module ExternallyControlledFormatStringConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ThreatModelFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(StringFormat formatCall).getFormatArgument()
|
||||
}
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof StringFormatSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof NumericType or node.getType() instanceof BooleanType
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.frameworks.android.Intent
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.frameworks.android.PendingIntent
|
||||
|
||||
private newtype TPendingIntentState =
|
||||
@@ -27,7 +26,7 @@ class NoState extends PendingIntentState, TNoState {
|
||||
}
|
||||
|
||||
/** A source for an implicit `PendingIntent` flow. */
|
||||
abstract class ImplicitPendingIntentSource extends DataFlow::Node {
|
||||
abstract class ImplicitPendingIntentSource extends ApiSourceNode {
|
||||
/**
|
||||
* DEPRECATED: Open-ended flow state is not intended to be part of the extension points.
|
||||
*
|
||||
|
||||
@@ -4,6 +4,7 @@ import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.security.HttpsUrls
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
|
||||
/**
|
||||
* A source that represents HTTP URLs.
|
||||
@@ -20,7 +21,7 @@ private class DefaultInsecureBasicAuthSource extends InsecureBasicAuthSource {
|
||||
* A sink that represents a method that sets Basic Authentication.
|
||||
* Extend this class to add your own Insecure Basic Authentication sinks.
|
||||
*/
|
||||
abstract class InsecureBasicAuthSink extends DataFlow::Node { }
|
||||
abstract class InsecureBasicAuthSink extends ApiSinkNode { }
|
||||
|
||||
/** A default sink representing methods that set an Authorization header. */
|
||||
private class DefaultInsecureBasicAuthSink extends InsecureBasicAuthSink {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.frameworks.Networking
|
||||
private import semmle.code.java.frameworks.Jndi
|
||||
|
||||
@@ -32,7 +33,7 @@ class InsecureLdapUrl extends Expr {
|
||||
/**
|
||||
* A sink representing the construction of a `DirContextEnvironment`.
|
||||
*/
|
||||
class InsecureLdapUrlSink extends DataFlow::Node {
|
||||
class InsecureLdapUrlSink extends ApiSinkNode {
|
||||
InsecureLdapUrlSink() {
|
||||
exists(ConstructorCall cc |
|
||||
cc.getConstructedType().getAnAncestor() instanceof TypeDirContext and
|
||||
|
||||
@@ -4,6 +4,7 @@ import java
|
||||
private import semmle.code.java.frameworks.OpenSaml
|
||||
private import semmle.code.java.frameworks.Servlets
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.security.Cookies
|
||||
private import semmle.code.java.security.RandomQuery
|
||||
@@ -49,7 +50,7 @@ abstract class InsecureRandomnessSink extends DataFlow::Node { }
|
||||
/**
|
||||
* A node which sets the value of a cookie.
|
||||
*/
|
||||
private class CookieSink extends InsecureRandomnessSink {
|
||||
private class CookieSink extends InsecureRandomnessSink, ApiSinkNode {
|
||||
CookieSink() { this.asExpr() instanceof SetCookieValue }
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
import java
|
||||
private import semmle.code.java.controlflow.Guards
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.security.Encryption
|
||||
private import semmle.code.java.security.SecurityFlag
|
||||
|
||||
/** The creation of an insecure `TrustManager`. */
|
||||
abstract class InsecureTrustManagerSource extends DataFlow::Node { }
|
||||
abstract class InsecureTrustManagerSource extends ApiSourceNode { }
|
||||
|
||||
private class DefaultInsecureTrustManagerSource extends InsecureTrustManagerSource {
|
||||
DefaultInsecureTrustManagerSource() {
|
||||
@@ -18,7 +19,7 @@ private class DefaultInsecureTrustManagerSource extends InsecureTrustManagerSour
|
||||
* The use of a `TrustManager` in an SSL context.
|
||||
* Intentionally insecure connections are not considered sinks.
|
||||
*/
|
||||
abstract class InsecureTrustManagerSink extends DataFlow::Node {
|
||||
abstract class InsecureTrustManagerSink extends ApiSinkNode {
|
||||
InsecureTrustManagerSink() { not isGuardedByInsecureFlag(this) }
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import java
|
||||
private import semmle.code.java.controlflow.Guards
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.frameworks.android.Android
|
||||
private import semmle.code.java.frameworks.android.Intent
|
||||
@@ -14,7 +15,7 @@ private import semmle.code.java.frameworks.android.Intent
|
||||
* A sink for Intent URI permission manipulation vulnerabilities in Android,
|
||||
* that is, method calls that return an Intent as the result of an Activity.
|
||||
*/
|
||||
abstract class IntentUriPermissionManipulationSink extends DataFlow::Node { }
|
||||
abstract class IntentUriPermissionManipulationSink extends ApiSinkNode { }
|
||||
|
||||
/**
|
||||
* A sanitizer that makes sure that an Intent is safe to be returned to another Activity.
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/** Provides classes for working with JSON Web Token (JWT) libraries. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
/** A method access that assigns signing keys to a JWT parser. */
|
||||
class JwtParserWithInsecureParseSource extends DataFlow::Node {
|
||||
class JwtParserWithInsecureParseSource extends ApiSourceNode {
|
||||
JwtParserWithInsecureParseSource() {
|
||||
exists(MethodCall ma, Method m |
|
||||
m.getDeclaringType().getAnAncestor() instanceof TypeJwtParser or
|
||||
@@ -24,7 +25,7 @@ class JwtParserWithInsecureParseSource extends DataFlow::Node {
|
||||
* the qualifier of a call to a `parse(token, handler)` method
|
||||
* where the `handler` is considered insecure.
|
||||
*/
|
||||
class JwtParserWithInsecureParseSink extends DataFlow::Node {
|
||||
class JwtParserWithInsecureParseSink extends ApiSinkNode {
|
||||
MethodCall insecureParseMa;
|
||||
|
||||
JwtParserWithInsecureParseSink() {
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.frameworks.Jndi
|
||||
private import semmle.code.java.frameworks.SpringLdap
|
||||
|
||||
/** A data flow sink for unvalidated user input that is used in JNDI lookup. */
|
||||
abstract class JndiInjectionSink extends DataFlow::Node { }
|
||||
abstract class JndiInjectionSink extends ApiSinkNode { }
|
||||
|
||||
/** A sanitizer for JNDI injection vulnerabilities. */
|
||||
abstract class JndiInjectionSanitizer extends DataFlow::Node { }
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
private import semmle.code.java.frameworks.MyBatis
|
||||
|
||||
@@ -10,7 +11,7 @@ private import semmle.code.java.frameworks.MyBatis
|
||||
*
|
||||
* Extend this class to add your own OGNL injection sinks.
|
||||
*/
|
||||
abstract class OgnlInjectionSink extends DataFlow::Node { }
|
||||
abstract class OgnlInjectionSink extends ApiSinkNode { }
|
||||
|
||||
/**
|
||||
* A unit class for adding additional taint steps.
|
||||
|
||||
@@ -5,9 +5,10 @@ import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.frameworks.javaee.Persistence
|
||||
private import semmle.code.java.frameworks.MyBatis
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
|
||||
/** A sink for database query language injection vulnerabilities. */
|
||||
abstract class QueryInjectionSink extends DataFlow::Node { }
|
||||
abstract class QueryInjectionSink extends ApiSinkNode { }
|
||||
|
||||
/**
|
||||
* A unit class for adding additional taint steps.
|
||||
|
||||
@@ -4,6 +4,7 @@ import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.SensitiveActions
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
|
||||
private class ResultReceiverSendCall extends MethodCall {
|
||||
ResultReceiverSendCall() {
|
||||
@@ -50,15 +51,22 @@ deprecated private class SensitiveResultReceiverConf extends TaintTracking::Conf
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensitive result receiver sink node.
|
||||
*/
|
||||
private class SensitiveResultReceiverSink extends ApiSinkNode {
|
||||
SensitiveResultReceiverSink() {
|
||||
exists(ResultReceiverSendCall call |
|
||||
untrustedResultReceiverSend(_, call) and
|
||||
this.asExpr() = call.getSentData()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private module SensitiveResultReceiverConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof SensitiveExpr }
|
||||
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
exists(ResultReceiverSendCall call |
|
||||
untrustedResultReceiverSend(_, call) and
|
||||
node.asExpr() = call.getSentData()
|
||||
)
|
||||
}
|
||||
predicate isSink(DataFlow::Node node) { node instanceof SensitiveResultReceiverSink }
|
||||
|
||||
predicate allowImplicitRead(DataFlow::Node n, DataFlow::ContentSet c) { isSink(n) and exists(c) }
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.security.SensitiveActions
|
||||
private import semmle.code.java.frameworks.android.Layout
|
||||
@@ -53,16 +54,23 @@ private class MaskCall extends MethodCall {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A text field sink node.
|
||||
*/
|
||||
private class TextFieldSink extends ApiSinkNode {
|
||||
TextFieldSink() {
|
||||
exists(SetTextCall call |
|
||||
this.asExpr() = call.getStringArgument() and
|
||||
not setTextCallIsMasked(call)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A configuration for tracking sensitive information to text fields. */
|
||||
private module TextFieldTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SensitiveExpr }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(SetTextCall call |
|
||||
sink.asExpr() = call.getStringArgument() and
|
||||
not setTextCallIsMasked(call)
|
||||
)
|
||||
}
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof TextFieldSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof SimpleTypeSanitizer }
|
||||
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.frameworks.spring.SpringExpression
|
||||
|
||||
/** A data flow sink for unvalidated user input that is used to construct SpEL expressions. */
|
||||
abstract class SpelExpressionEvaluationSink extends DataFlow::ExprNode { }
|
||||
abstract class SpelExpressionEvaluationSink extends ApiSinkNode, DataFlow::ExprNode { }
|
||||
|
||||
/**
|
||||
* A unit class for adding additional taint steps.
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/** Provides predicates to reason about exposure of stack-traces. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.security.InformationLeak
|
||||
|
||||
/**
|
||||
@@ -19,7 +18,7 @@ private class PrintStackTraceMethod extends Method {
|
||||
}
|
||||
|
||||
private module ServletWriterSourceToPrintStackTraceMethodFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof XssVulnerableWriterSource }
|
||||
predicate isSource(DataFlow::Node src) { src instanceof XssVulnerableWriterSourceNode }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodCall ma |
|
||||
@@ -95,7 +94,10 @@ predicate stringifiedStackFlowsExternally(DataFlow::Node externalExpr, Expr stac
|
||||
)
|
||||
}
|
||||
|
||||
private class GetMessageFlowSource extends DataFlow::Node {
|
||||
/**
|
||||
* A get message source node.
|
||||
*/
|
||||
private class GetMessageFlowSource extends ApiSourceNode {
|
||||
GetMessageFlowSource() {
|
||||
exists(Method method | this.asExpr().(MethodCall).getMethod() = method |
|
||||
method.hasName("getMessage") and
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/** Provides classes to reason about local information disclosure in a temporary directory. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.os.OSCheck
|
||||
private import semmle.code.java.security.TempDirUtils
|
||||
@@ -29,7 +30,7 @@ private class MethodFileFileCreation extends MethodFileSystemFileCreation {
|
||||
/**
|
||||
* A dataflow node that creates a file or directory in the file system.
|
||||
*/
|
||||
abstract private class FileCreationSink extends DataFlow::Node { }
|
||||
abstract private class FileCreationSink extends ApiSinkNode { }
|
||||
|
||||
/**
|
||||
* The qualifier of a call to one of `File`'s file-creating or directory-creating methods,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.FlowSinks
|
||||
private import semmle.code.java.frameworks.android.WebView
|
||||
private import semmle.code.java.frameworks.kotlin.Kotlin
|
||||
|
||||
@@ -12,7 +13,7 @@ private import semmle.code.java.frameworks.kotlin.Kotlin
|
||||
*
|
||||
* Extend this class to add your own Unsafe Resource Fetching sinks.
|
||||
*/
|
||||
abstract class UrlResourceSink extends DataFlow::Node {
|
||||
abstract class UrlResourceSink extends ApiSinkNode {
|
||||
/**
|
||||
* Gets a description of this vulnerability.
|
||||
*/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user