mirror of
https://github.com/github/codeql.git
synced 2026-04-22 07:15:15 +02:00
Merge branch 'main' into bring-back-type-barriers-in-non-constant-format
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
class Expr extends @expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from Expr expr, int kind, int kind_new, Location loc
|
||||
where
|
||||
exprs(expr, kind, loc) and
|
||||
if kind = 363 then kind_new = 1 else kind_new = kind
|
||||
select expr, kind_new, loc
|
||||
2250
cpp/downgrades/aa7ff0ab32cd4674f6ab731d32fea64116997b05/old.dbscheme
Normal file
2250
cpp/downgrades/aa7ff0ab32cd4674f6ab731d32fea64116997b05/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
description: Introduce re-use expressions
|
||||
compatibility: partial
|
||||
expr_reuse.rel: delete
|
||||
exprs.rel: run exprs.qlo
|
||||
@@ -285,6 +285,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
|
||||
@@ -285,6 +285,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
|
||||
@@ -285,6 +285,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
|
||||
@@ -285,6 +285,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
|
||||
@@ -285,6 +285,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
|
||||
@@ -1322,3 +1322,23 @@ class CoYieldExpr extends UnaryOperation, @co_yield {
|
||||
|
||||
override int getPrecedence() { result = 2 }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression representing the re-use of another expression.
|
||||
*
|
||||
* In some specific cases an expression may be referred to outside its
|
||||
* original context. A re-use expression wraps any such reference. A
|
||||
* re-use expression can for example occur as the qualifier of an implicit
|
||||
* destructor called on a temporary object, where the original use of the
|
||||
* expression is in the definition of the temporary.
|
||||
*/
|
||||
class ReuseExpr extends Expr, @reuseexpr {
|
||||
override string getAPrimaryQlClass() { result = "ReuseExpr" }
|
||||
|
||||
override string toString() { result = "reuse of " + this.getReusedExpr().toString() }
|
||||
|
||||
/**
|
||||
* Gets the expression that is being re-used.
|
||||
*/
|
||||
Expr getReusedExpr() { expr_reuse(underlyingElement(this), unresolveElement(result)) }
|
||||
}
|
||||
|
||||
@@ -285,6 +285,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
|
||||
@@ -285,6 +285,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
|
||||
@@ -285,6 +285,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
|
||||
@@ -285,6 +285,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
|
||||
@@ -36,7 +36,9 @@ private class MallocAllocationFunction extends AllocationFunction {
|
||||
"CRYPTO_malloc", // CRYPTO_malloc(size_t num, const char *file, int line)
|
||||
"CRYPTO_zalloc", // CRYPTO_zalloc(size_t num, const char *file, int line)
|
||||
"CRYPTO_secure_malloc", // CRYPTO_secure_malloc(size_t num, const char *file, int line)
|
||||
"CRYPTO_secure_zalloc" // CRYPTO_secure_zalloc(size_t num, const char *file, int line)
|
||||
"CRYPTO_secure_zalloc", // CRYPTO_secure_zalloc(size_t num, const char *file, int line)
|
||||
"g_malloc", // g_malloc (n_bytes);
|
||||
"g_try_malloc" // g_try_malloc(n_bytes);
|
||||
]) and
|
||||
sizeArg = 0
|
||||
or
|
||||
@@ -139,7 +141,9 @@ private class ReallocAllocationFunction extends AllocationFunction, TaintFunctio
|
||||
// --- Windows COM allocation
|
||||
"CoTaskMemRealloc", // CoTaskMemRealloc(ptr, size)
|
||||
// --- OpenSSL memory allocation
|
||||
"CRYPTO_realloc" // CRYPTO_realloc(void *addr, size_t num, const char *file, int line)
|
||||
"CRYPTO_realloc", // CRYPTO_realloc(void *addr, size_t num, const char *file, int line)
|
||||
"g_realloc", // g_realloc(mem, n_bytes);
|
||||
"g_try_realloc" // g_try_realloc(mem, n_bytes);
|
||||
]) and
|
||||
sizeArg = 1 and
|
||||
reallocArg = 0
|
||||
|
||||
@@ -20,8 +20,10 @@ private class StandardDeallocationFunction extends DeallocationFunction {
|
||||
freedArg = 0
|
||||
or
|
||||
this.hasGlobalName([
|
||||
// --- OpenSSL memory allocation
|
||||
"CRYPTO_free", "CRYPTO_secure_free"
|
||||
// --- OpenSSL memory deallocation
|
||||
"CRYPTO_free", "CRYPTO_secure_free",
|
||||
// --- glib memory deallocation
|
||||
"g_free"
|
||||
]) and
|
||||
freedArg = 0
|
||||
or
|
||||
|
||||
@@ -1513,6 +1513,11 @@ exprs(
|
||||
int location: @location_expr ref
|
||||
);
|
||||
|
||||
expr_reuse(
|
||||
int reuse: @expr ref,
|
||||
int original: @expr ref
|
||||
)
|
||||
|
||||
/*
|
||||
case @value.category of
|
||||
1 = prval
|
||||
@@ -1741,6 +1746,7 @@ case @expr.kind of
|
||||
| 360 = @isunsigned
|
||||
| 361 = @isvoid
|
||||
| 362 = @isvolatile
|
||||
| 363 = @reuseexpr
|
||||
;
|
||||
|
||||
@var_args_expr = @vastartexpr
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Introduce re-use expressions
|
||||
compatibility: backwards
|
||||
50
cpp/ql/src/Security/CWE/CWE-843/TypeConfusion.qhelp
Normal file
50
cpp/ql/src/Security/CWE/CWE-843/TypeConfusion.qhelp
Normal file
@@ -0,0 +1,50 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Certain casts in C and C++ place no restrictions on the target type. For
|
||||
example, C style casts such as <code>(MyClass*)p</code> allows the programmer
|
||||
to cast any pointer <code>p</code> to an expression of type <code>MyClass*</code>.
|
||||
If the runtime type of <code>p</code> turns out to be a type that's incompatible
|
||||
with <code>MyClass</code>, this results in undefined behavior.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
If possible, use <code>dynamic_cast</code> to safely cast between polymorphic types.
|
||||
If <code>dynamic_cast</code> is not an option, use <code>static_cast</code> to restrict
|
||||
the kinds of conversions that the compiler is allowed to perform. If C++ style casts is
|
||||
not an option, carefully check that all casts are safe.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
Consider the following class hierachy where we define a base class <code>Shape</code> and two
|
||||
derived classes <code>Circle</code> and <code>Square</code> that are mutually incompatible:
|
||||
</p>
|
||||
<sample src="TypeConfusionCommon.cpp"/>
|
||||
|
||||
<p>
|
||||
The following code demonstrates a type confusion vulnerability where the programmer
|
||||
assumes that the runtime type of <code>p</code> is always a <code>Square</code>.
|
||||
However, if <code>p</code> is a <code>Circle</code>, the cast will result in undefined behavior.
|
||||
</p>
|
||||
<sample src="TypeConfusionBad.cpp"/>
|
||||
|
||||
<p>
|
||||
The following code fixes the vulnerability by using <code>dynamic_cast</code> to
|
||||
safely cast between polymorphic types. If the cast fails, <code>dynamic_cast</code>
|
||||
returns a null pointer, which can be checked for and handled appropriately.
|
||||
</p>
|
||||
<sample src="TypeConfusionGood.cpp"/>
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
Microsoft Learn: <a href="https://learn.microsoft.com/en-us/cpp/cpp/type-conversions-and-type-safety-modern-cpp">Type conversions and type safety</a>.
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
263
cpp/ql/src/Security/CWE/CWE-843/TypeConfusion.ql
Normal file
263
cpp/ql/src/Security/CWE/CWE-843/TypeConfusion.ql
Normal file
@@ -0,0 +1,263 @@
|
||||
/**
|
||||
* @name Type confusion
|
||||
* @description Casting a value to an incompatible type can lead to undefined behavior.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 9.3
|
||||
* @precision medium
|
||||
* @id cpp/type-confusion
|
||||
* @tags security
|
||||
* external/cwe/cwe-843
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import Flow::PathGraph
|
||||
|
||||
/**
|
||||
* Holds if `f` is a field located at byte offset `offset` in `c`.
|
||||
*
|
||||
* Note that predicate is recursive, so that given the following:
|
||||
* ```cpp
|
||||
* struct S1 {
|
||||
* int a;
|
||||
* void* b;
|
||||
* };
|
||||
*
|
||||
* struct S2 {
|
||||
* S1 s1;
|
||||
* char c;
|
||||
* };
|
||||
* ```
|
||||
* both `hasAFieldWithOffset(S2, s1, 0)` and `hasAFieldWithOffset(S2, a, 0)`
|
||||
* holds.
|
||||
*/
|
||||
predicate hasAFieldWithOffset(Class c, Field f, int offset) {
|
||||
// Base case: `f` is a field in `c`.
|
||||
f = c.getAField() and
|
||||
offset = f.getByteOffset() and
|
||||
not f.getUnspecifiedType().(Class).hasDefinition()
|
||||
or
|
||||
// Otherwise, we find the struct that is a field of `c` which then has
|
||||
// the field `f` as a member.
|
||||
exists(Field g |
|
||||
g = c.getAField() and
|
||||
// Find the field with the largest offset that's less than or equal to
|
||||
// offset. That's the struct we need to search recursively.
|
||||
g =
|
||||
max(Field cand, int candOffset |
|
||||
cand = c.getAField() and
|
||||
candOffset = cand.getByteOffset() and
|
||||
offset >= candOffset
|
||||
|
|
||||
cand order by candOffset
|
||||
) and
|
||||
hasAFieldWithOffset(g.getUnspecifiedType(), f, offset - g.getByteOffset())
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `f` is the last field of its declaring class. */
|
||||
predicate lastField(Field f) {
|
||||
exists(Class c | c = f.getDeclaringType() |
|
||||
f =
|
||||
max(Field cand, int byteOffset |
|
||||
cand.getDeclaringType() = c and byteOffset = f.getByteOffset()
|
||||
|
|
||||
cand order by byteOffset
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there exists a field in `c2` at offset `offset` that's compatible
|
||||
* with `f1`.
|
||||
*/
|
||||
bindingset[f1, offset, c2]
|
||||
pragma[inline_late]
|
||||
predicate hasCompatibleFieldAtOffset(Field f1, int offset, Class c2) {
|
||||
exists(Field f2 | hasAFieldWithOffset(c2, f2, offset) |
|
||||
// Let's not deal with bit-fields for now.
|
||||
f2 instanceof BitField
|
||||
or
|
||||
f1.getUnspecifiedType().getSize() = f2.getUnspecifiedType().getSize()
|
||||
or
|
||||
lastField(f1) and
|
||||
f1.getUnspecifiedType().getSize() <= f2.getUnspecifiedType().getSize()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `c1` is a prefix of `c2`.
|
||||
*/
|
||||
bindingset[c1, c2]
|
||||
pragma[inline_late]
|
||||
predicate prefix(Class c1, Class c2) {
|
||||
not c1.isPolymorphic() and
|
||||
not c2.isPolymorphic() and
|
||||
if c1 instanceof Union
|
||||
then
|
||||
// If it's a union we just verify that one of it's variants is compatible with the other class
|
||||
exists(Field f1, int offset |
|
||||
// Let's not deal with bit-fields for now.
|
||||
not f1 instanceof BitField and
|
||||
hasAFieldWithOffset(c1, f1, offset)
|
||||
|
|
||||
hasCompatibleFieldAtOffset(f1, offset, c2)
|
||||
)
|
||||
else
|
||||
forall(Field f1, int offset |
|
||||
// Let's not deal with bit-fields for now.
|
||||
not f1 instanceof BitField and
|
||||
hasAFieldWithOffset(c1, f1, offset)
|
||||
|
|
||||
hasCompatibleFieldAtOffset(f1, offset, c2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* An unsafe cast is any explicit cast that is not
|
||||
* a `dynamic_cast`.
|
||||
*/
|
||||
class UnsafeCast extends Cast {
|
||||
private Class toType;
|
||||
|
||||
UnsafeCast() {
|
||||
(
|
||||
this instanceof CStyleCast
|
||||
or
|
||||
this instanceof StaticCast
|
||||
or
|
||||
this instanceof ReinterpretCast
|
||||
) and
|
||||
toType = this.getExplicitlyConverted().getUnspecifiedType().stripType() and
|
||||
not this.isImplicit() and
|
||||
exists(TypeDeclarationEntry tde |
|
||||
tde = toType.getDefinition() and
|
||||
not tde.isFromUninstantiatedTemplate(_)
|
||||
)
|
||||
}
|
||||
|
||||
Class getConvertedType() { result = toType }
|
||||
|
||||
/**
|
||||
* Holds if the result of this cast can safely be interpreted as a value of
|
||||
* type `t`.
|
||||
*
|
||||
* The compatibility rules are as follows:
|
||||
*
|
||||
* 1. the result of `(T)x` is compatible with the type `T` for any `T`
|
||||
* 2. the result of `(T)x` is compatible with the type `U` for any `U` such
|
||||
* that `U` is a subtype of `T`, or `T` is a subtype of `U`.
|
||||
* 3. the result of `(T)x` is compatible with the type `U` if the list
|
||||
* of fields of `T` is a prefix of the list of fields of `U`.
|
||||
* For example, if `U` is `struct { unsigned char x; int y; };`
|
||||
* and `T` is `struct { unsigned char uc; };`.
|
||||
* 4. the result of `(T)x` is compatible with the type `U` if the list
|
||||
* of fields of `U` is a prefix of the list of fields of `T`.
|
||||
*
|
||||
* Condition 4 is a bit controversial, since it assumes that the additional
|
||||
* fields in `T` won't be accessed. This may result in some FNs.
|
||||
*/
|
||||
bindingset[this, t]
|
||||
pragma[inline_late]
|
||||
predicate compatibleWith(Type t) {
|
||||
// Conition 1
|
||||
t.stripType() = this.getConvertedType()
|
||||
or
|
||||
// Condition 3
|
||||
prefix(this.getConvertedType(), t.stripType())
|
||||
or
|
||||
// Condition 4
|
||||
prefix(t.stripType(), this.getConvertedType())
|
||||
or
|
||||
// Condition 2 (a)
|
||||
t.stripType().(Class).getABaseClass+() = this.getConvertedType()
|
||||
or
|
||||
// Condition 2 (b)
|
||||
t.stripType() = this.getConvertedType().getABaseClass+()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `source` is an allocation that allocates a value of type `type`.
|
||||
*/
|
||||
predicate isSourceImpl(DataFlow::Node source, Class type) {
|
||||
exists(AllocationExpr alloc |
|
||||
alloc = source.asExpr() and
|
||||
type = alloc.getAllocatedElementType().stripType() and
|
||||
not exists(
|
||||
alloc
|
||||
.(NewOrNewArrayExpr)
|
||||
.getAllocator()
|
||||
.(OperatorNewAllocationFunction)
|
||||
.getPlacementArgument()
|
||||
)
|
||||
) and
|
||||
exists(TypeDeclarationEntry tde |
|
||||
tde = type.getDefinition() and
|
||||
not tde.isFromUninstantiatedTemplate(_)
|
||||
)
|
||||
}
|
||||
|
||||
/** A configuration describing flow from an allocation to a potentially unsafe cast. */
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isSourceImpl(source, _) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
// We disable flow through global variables to reduce FPs from infeasible paths
|
||||
node instanceof DataFlow::VariableNode
|
||||
or
|
||||
exists(Class c | c = node.getType().stripType() |
|
||||
not c.hasDefinition()
|
||||
or
|
||||
exists(TypeDeclarationEntry tde |
|
||||
tde = c.getDefinition() and
|
||||
tde.isFromUninstantiatedTemplate(_)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(UnsafeCast cast).getUnconverted() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = 0 }
|
||||
}
|
||||
|
||||
module Flow = DataFlow::Global<Config>;
|
||||
|
||||
predicate relevantType(DataFlow::Node sink, Class allocatedType) {
|
||||
exists(DataFlow::Node source |
|
||||
Flow::flow(source, sink) and
|
||||
isSourceImpl(source, allocatedType)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSinkImpl(
|
||||
DataFlow::Node sink, Class allocatedType, Type convertedType, boolean compatible
|
||||
) {
|
||||
exists(UnsafeCast cast |
|
||||
relevantType(sink, allocatedType) and
|
||||
sink.asExpr() = cast.getUnconverted() and
|
||||
convertedType = cast.getConvertedType()
|
||||
|
|
||||
if cast.compatibleWith(allocatedType) then compatible = true else compatible = false
|
||||
)
|
||||
}
|
||||
|
||||
from
|
||||
Flow::PathNode source, Flow::PathNode sink, Type badSourceType, Type sinkType,
|
||||
DataFlow::Node sinkNode
|
||||
where
|
||||
Flow::flowPath(source, sink) and
|
||||
sinkNode = sink.getNode() and
|
||||
isSourceImpl(source.getNode(), badSourceType) and
|
||||
isSinkImpl(sinkNode, badSourceType, sinkType, false) and
|
||||
// If there is any flow that would result in a valid cast then we don't
|
||||
// report an alert here. This reduces the number of FPs from infeasible paths
|
||||
// significantly.
|
||||
not exists(DataFlow::Node goodSource, Type goodSourceType |
|
||||
isSourceImpl(goodSource, goodSourceType) and
|
||||
isSinkImpl(sinkNode, goodSourceType, sinkType, true) and
|
||||
Flow::flow(goodSource, sinkNode)
|
||||
)
|
||||
select sinkNode, source, sink, "Conversion from $@ to $@ is invalid.", badSourceType,
|
||||
badSourceType.toString(), sinkType, sinkType.toString()
|
||||
7
cpp/ql/src/Security/CWE/CWE-843/TypeConfusionBad.cpp
Normal file
7
cpp/ql/src/Security/CWE/CWE-843/TypeConfusionBad.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
void allocate_and_draw_bad() {
|
||||
Shape* shape = new Circle;
|
||||
// ...
|
||||
// BAD: Assumes that shape is always a Square
|
||||
Square* square = static_cast<Square*>(shape);
|
||||
int length = square->getLength();
|
||||
}
|
||||
25
cpp/ql/src/Security/CWE/CWE-843/TypeConfusionCommon.cpp
Normal file
25
cpp/ql/src/Security/CWE/CWE-843/TypeConfusionCommon.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
struct Shape {
|
||||
virtual ~Shape();
|
||||
|
||||
virtual void draw() = 0;
|
||||
};
|
||||
|
||||
struct Circle : public Shape {
|
||||
Circle();
|
||||
|
||||
void draw() override {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
int getRadius();
|
||||
};
|
||||
|
||||
struct Square : public Shape {
|
||||
Square();
|
||||
|
||||
void draw() override {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
int getLength();
|
||||
};
|
||||
11
cpp/ql/src/Security/CWE/CWE-843/TypeConfusionGood.cpp
Normal file
11
cpp/ql/src/Security/CWE/CWE-843/TypeConfusionGood.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
void allocate_and_draw_good() {
|
||||
Shape* shape = new Circle;
|
||||
// ...
|
||||
// GOOD: Dynamically checks if shape is a Square
|
||||
Square* square = dynamic_cast<Square*>(shape);
|
||||
if(square) {
|
||||
int length = square->getLength();
|
||||
} else {
|
||||
// handle error
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* Added a new query, `cpp/type-confusion`, to detect casts to invalid types.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added models for `GLib` allocation and deallocation functions.
|
||||
@@ -1728,6 +1728,374 @@ complex.c:
|
||||
# 144| Type = [LongDoubleType] long double
|
||||
# 144| ValueCategory = prvalue
|
||||
# 145| getStmt(72): [ReturnStmt] return ...
|
||||
destructors_for_temps.cpp:
|
||||
# 1| [CopyAssignmentOperator] ClassWithDestructor2& ClassWithDestructor2::operator=(ClassWithDestructor2 const&)
|
||||
# 1| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const ClassWithDestructor2 &
|
||||
# 1| [CopyConstructor] void ClassWithDestructor2::ClassWithDestructor2(ClassWithDestructor2 const&)
|
||||
# 1| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const ClassWithDestructor2 &
|
||||
# 3| [Constructor] void ClassWithDestructor2::ClassWithDestructor2()
|
||||
# 3| <params>:
|
||||
# 4| [Destructor] void ClassWithDestructor2::~ClassWithDestructor2()
|
||||
# 4| <params>:
|
||||
# 6| [MemberFunction] char ClassWithDestructor2::get_x()
|
||||
# 6| <params>:
|
||||
# 9| [CopyAssignmentOperator] ClassWithConstructor& ClassWithConstructor::operator=(ClassWithConstructor const&)
|
||||
# 9| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const ClassWithConstructor &
|
||||
# 9| [MoveAssignmentOperator] ClassWithConstructor& ClassWithConstructor::operator=(ClassWithConstructor&&)
|
||||
# 9| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] ClassWithConstructor &&
|
||||
# 9| [CopyConstructor] void ClassWithConstructor::ClassWithConstructor(ClassWithConstructor const&)
|
||||
# 9| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const ClassWithConstructor &
|
||||
# 9| [MoveConstructor] void ClassWithConstructor::ClassWithConstructor(ClassWithConstructor&&)
|
||||
# 9| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] ClassWithConstructor &&
|
||||
# 9| <initializations>:
|
||||
# 9| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 9| getStmt(0): [ReturnStmt] return ...
|
||||
# 11| [Constructor] void ClassWithConstructor::ClassWithConstructor(char, char)
|
||||
# 11| <params>:
|
||||
# 11| getParameter(0): [Parameter] x
|
||||
# 11| Type = [PlainCharType] char
|
||||
# 11| getParameter(1): [Parameter] y
|
||||
# 11| Type = [PlainCharType] char
|
||||
# 14| [TopLevelFunction] char temp_test()
|
||||
# 14| <params>:
|
||||
# 14| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 15| getStmt(0): [DeclStmt] declaration
|
||||
# 15| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
|
||||
# 15| Type = [PlainCharType] char
|
||||
# 15| getVariable().getInitializer(): [Initializer] initializer for x
|
||||
# 15| getExpr(): [FunctionCall] call to get_x
|
||||
# 15| Type = [PlainCharType] char
|
||||
# 15| ValueCategory = prvalue
|
||||
# 15| getQualifier(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 15| Type = [VoidType] void
|
||||
# 15| ValueCategory = prvalue
|
||||
# 15| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 15| Type = [Class] ClassWithDestructor2
|
||||
# 15| ValueCategory = prvalue(load)
|
||||
# 16| getStmt(1): [DeclStmt] declaration
|
||||
# 16| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
|
||||
# 16| Type = [Class] ClassWithConstructor
|
||||
# 16| getVariable().getInitializer(): [Initializer] initializer for y
|
||||
# 16| getExpr(): [ConstructorCall] call to ClassWithConstructor
|
||||
# 16| Type = [VoidType] void
|
||||
# 16| ValueCategory = prvalue
|
||||
# 16| getArgument(0): [CharLiteral] 97
|
||||
# 16| Type = [PlainCharType] char
|
||||
# 16| Value = [CharLiteral] 97
|
||||
# 16| ValueCategory = prvalue
|
||||
# 16| getArgument(1): [FunctionCall] call to get_x
|
||||
# 16| Type = [PlainCharType] char
|
||||
# 16| ValueCategory = prvalue
|
||||
# 16| getQualifier(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 16| Type = [VoidType] void
|
||||
# 16| ValueCategory = prvalue
|
||||
# 16| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 16| Type = [Class] ClassWithDestructor2
|
||||
# 16| ValueCategory = prvalue(load)
|
||||
# 17| getStmt(2): [ReturnStmt] return ...
|
||||
# 17| getExpr(): [FunctionCall] call to get_x
|
||||
# 17| Type = [PlainCharType] char
|
||||
# 17| ValueCategory = prvalue
|
||||
# 17| getQualifier(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 17| Type = [VoidType] void
|
||||
# 17| ValueCategory = prvalue
|
||||
# 17| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 17| Type = [Class] ClassWithDestructor2
|
||||
# 17| ValueCategory = prvalue(load)
|
||||
# 21| [TopLevelFunction] char temp_test2()
|
||||
# 21| <params>:
|
||||
# 21| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 22| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 22| getExpr(): [NewExpr] new
|
||||
# 22| Type = [PointerType] ClassWithDestructor2 *
|
||||
# 22| ValueCategory = prvalue
|
||||
# 22| getInitializer(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 22| Type = [VoidType] void
|
||||
# 22| ValueCategory = prvalue
|
||||
# 23| getStmt(1): [ReturnStmt] return ...
|
||||
# 23| getExpr(): [AddExpr] ... + ...
|
||||
# 23| Type = [IntType] int
|
||||
# 23| ValueCategory = prvalue
|
||||
# 23| getLeftOperand(): [FunctionCall] call to get_x
|
||||
# 23| Type = [PlainCharType] char
|
||||
# 23| ValueCategory = prvalue
|
||||
# 23| getQualifier(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 23| Type = [VoidType] void
|
||||
# 23| ValueCategory = prvalue
|
||||
# 23| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 23| Type = [Class] ClassWithDestructor2
|
||||
# 23| ValueCategory = prvalue(load)
|
||||
# 23| getRightOperand(): [FunctionCall] call to get_x
|
||||
# 23| Type = [PlainCharType] char
|
||||
# 23| ValueCategory = prvalue
|
||||
# 23| getQualifier(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 23| Type = [VoidType] void
|
||||
# 23| ValueCategory = prvalue
|
||||
# 23| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 23| Type = [Class] ClassWithDestructor2
|
||||
# 23| ValueCategory = prvalue(load)
|
||||
# 23| getLeftOperand().getFullyConverted(): [CStyleCast] (int)...
|
||||
# 23| Conversion = [IntegralConversion] integral conversion
|
||||
# 23| Type = [IntType] int
|
||||
# 23| ValueCategory = prvalue
|
||||
# 23| getRightOperand().getFullyConverted(): [CStyleCast] (int)...
|
||||
# 23| Conversion = [IntegralConversion] integral conversion
|
||||
# 23| Type = [IntType] int
|
||||
# 23| ValueCategory = prvalue
|
||||
# 23| getExpr().getFullyConverted(): [CStyleCast] (char)...
|
||||
# 23| Conversion = [IntegralConversion] integral conversion
|
||||
# 23| Type = [PlainCharType] char
|
||||
# 23| ValueCategory = prvalue
|
||||
# 27| [FunctionTemplateInstantiation,TopLevelFunction] ClassWithDestructor2 returnValue<ClassWithDestructor2>()
|
||||
# 27| <params>:
|
||||
# 27| [TemplateFunction,TopLevelFunction] T returnValue<T>()
|
||||
# 27| <params>:
|
||||
# 29| [TopLevelFunction] void temp_test3()
|
||||
# 29| <params>:
|
||||
# 29| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 30| getStmt(0): [DeclStmt] declaration
|
||||
# 30| getDeclarationEntry(0): [VariableDeclarationEntry] definition of rs
|
||||
# 30| Type = [LValueReferenceType] const ClassWithDestructor2 &
|
||||
# 30| getVariable().getInitializer(): [Initializer] initializer for rs
|
||||
# 30| getExpr(): [FunctionCall] call to returnValue
|
||||
# 30| Type = [Class] ClassWithDestructor2
|
||||
# 30| ValueCategory = prvalue
|
||||
# 30| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 30| Type = [LValueReferenceType] const ClassWithDestructor2 &
|
||||
# 30| ValueCategory = prvalue
|
||||
# 30| getExpr(): [CStyleCast] (const ClassWithDestructor2)...
|
||||
# 30| Conversion = [GlvalueConversion] glvalue conversion
|
||||
# 30| Type = [SpecifiedType] const ClassWithDestructor2
|
||||
# 30| ValueCategory = lvalue
|
||||
# 30| getExpr(): [TemporaryObjectExpr] temporary object
|
||||
# 30| Type = [Class] ClassWithDestructor2
|
||||
# 30| ValueCategory = lvalue
|
||||
# 31| getStmt(1): [ReturnStmt] return ...
|
||||
# 33| [TopLevelFunction] void temp_test4()
|
||||
# 33| <params>:
|
||||
# 33| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 34| getStmt(0): [DeclStmt] declaration
|
||||
# 34| getDeclarationEntry(0): [VariableDeclarationEntry] definition of c
|
||||
# 34| Type = [Class] ClassWithDestructor2
|
||||
# 34| getVariable().getInitializer(): [Initializer] initializer for c
|
||||
# 34| getExpr(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 34| Type = [VoidType] void
|
||||
# 34| ValueCategory = prvalue
|
||||
# 35| getStmt(1): [DeclStmt] declaration
|
||||
# 35| getDeclarationEntry(0): [VariableDeclarationEntry] definition of rs2
|
||||
# 35| Type = [LValueReferenceType] const ClassWithDestructor2 &
|
||||
# 35| getVariable().getInitializer(): [Initializer] initializer for rs2
|
||||
# 35| getExpr(): [FunctionCall] call to returnValue
|
||||
# 35| Type = [Class] ClassWithDestructor2
|
||||
# 35| ValueCategory = prvalue
|
||||
# 35| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 35| Type = [LValueReferenceType] const ClassWithDestructor2 &
|
||||
# 35| ValueCategory = prvalue
|
||||
# 35| getExpr(): [CStyleCast] (const ClassWithDestructor2)...
|
||||
# 35| Conversion = [GlvalueConversion] glvalue conversion
|
||||
# 35| Type = [SpecifiedType] const ClassWithDestructor2
|
||||
# 35| ValueCategory = lvalue
|
||||
# 35| getExpr(): [TemporaryObjectExpr] temporary object
|
||||
# 35| Type = [Class] ClassWithDestructor2
|
||||
# 35| ValueCategory = lvalue
|
||||
# 36| getStmt(2): [ReturnStmt] return ...
|
||||
# 36| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor2
|
||||
# 36| Type = [VoidType] void
|
||||
# 36| ValueCategory = prvalue
|
||||
# 36| getQualifier(): [VariableAccess] c
|
||||
# 36| Type = [Class] ClassWithDestructor2
|
||||
# 36| ValueCategory = lvalue
|
||||
# 38| [TopLevelFunction] void temp_test5(bool)
|
||||
# 38| <params>:
|
||||
# 38| getParameter(0): [Parameter] b
|
||||
# 38| Type = [BoolType] bool
|
||||
# 38| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 39| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 39| getExpr(): [ConditionalExpr] ... ? ... : ...
|
||||
# 39| Type = [Class] ClassWithDestructor2
|
||||
# 39| ValueCategory = prvalue
|
||||
# 39| getCondition(): [VariableAccess] b
|
||||
# 39| Type = [BoolType] bool
|
||||
# 39| ValueCategory = prvalue(load)
|
||||
# 39| getThen(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 39| Type = [VoidType] void
|
||||
# 39| ValueCategory = prvalue
|
||||
# 39| getElse(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 39| Type = [VoidType] void
|
||||
# 39| ValueCategory = prvalue
|
||||
# 39| getThen().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 39| Type = [Class] ClassWithDestructor2
|
||||
# 39| ValueCategory = prvalue(load)
|
||||
# 39| getElse().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 39| Type = [Class] ClassWithDestructor2
|
||||
# 39| ValueCategory = prvalue(load)
|
||||
# 39| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 39| Type = [Class] ClassWithDestructor2
|
||||
# 39| ValueCategory = prvalue
|
||||
# 40| getStmt(1): [ReturnStmt] return ...
|
||||
# 42| [TopLevelFunction] void temp_test6(bool)
|
||||
# 42| <params>:
|
||||
# 42| getParameter(0): [Parameter] b
|
||||
# 42| Type = [BoolType] bool
|
||||
# 42| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 43| getStmt(0): [DeclStmt] declaration
|
||||
# 43| getDeclarationEntry(0): [VariableDeclarationEntry] definition of c
|
||||
# 43| Type = [Class] ClassWithDestructor2
|
||||
# 43| getVariable().getInitializer(): [Initializer] initializer for c
|
||||
# 43| getExpr(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 43| Type = [VoidType] void
|
||||
# 43| ValueCategory = prvalue
|
||||
# 44| getStmt(1): [IfStmt] if (...) ...
|
||||
# 44| getCondition(): [VariableAccess] b
|
||||
# 44| Type = [BoolType] bool
|
||||
# 44| ValueCategory = prvalue(load)
|
||||
# 44| getThen(): [BlockStmt] { ... }
|
||||
# 45| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 45| getExpr(): [ThrowExpr] throw ...
|
||||
# 45| Type = [Class] ClassWithConstructor
|
||||
# 45| ValueCategory = prvalue
|
||||
# 45| getExpr(): [ConstructorCall] call to ClassWithConstructor
|
||||
# 45| Type = [VoidType] void
|
||||
# 45| ValueCategory = prvalue
|
||||
# 45| getArgument(0): [CharLiteral] 120
|
||||
# 45| Type = [PlainCharType] char
|
||||
# 45| Value = [CharLiteral] 120
|
||||
# 45| ValueCategory = prvalue
|
||||
# 45| getArgument(1): [FunctionCall] call to get_x
|
||||
# 45| Type = [PlainCharType] char
|
||||
# 45| ValueCategory = prvalue
|
||||
# 45| getQualifier(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 45| Type = [VoidType] void
|
||||
# 45| ValueCategory = prvalue
|
||||
# 45| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 45| Type = [Class] ClassWithDestructor2
|
||||
# 45| ValueCategory = prvalue(load)
|
||||
# 47| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor2
|
||||
# 47| Type = [VoidType] void
|
||||
# 47| ValueCategory = prvalue
|
||||
# 47| getQualifier(): [VariableAccess] c
|
||||
# 47| Type = [Class] ClassWithDestructor2
|
||||
# 47| ValueCategory = lvalue
|
||||
# 47| getStmt(2): [ReturnStmt] return ...
|
||||
# 47| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor2
|
||||
# 47| Type = [VoidType] void
|
||||
# 47| ValueCategory = prvalue
|
||||
# 47| getQualifier(): [VariableAccess] c
|
||||
# 47| Type = [Class] ClassWithDestructor2
|
||||
# 47| ValueCategory = lvalue
|
||||
# 49| [TopLevelFunction] void temp_test7(bool)
|
||||
# 49| <params>:
|
||||
# 49| getParameter(0): [Parameter] b
|
||||
# 49| Type = [BoolType] bool
|
||||
# 49| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 50| getStmt(0): [DeclStmt] declaration
|
||||
# 50| getDeclarationEntry(0): [VariableDeclarationEntry] definition of c
|
||||
# 50| Type = [Class] ClassWithDestructor2
|
||||
# 50| getVariable().getInitializer(): [Initializer] initializer for c
|
||||
# 50| getExpr(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 50| Type = [VoidType] void
|
||||
# 50| ValueCategory = prvalue
|
||||
# 51| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 51| getExpr(): [ConditionalExpr] ... ? ... : ...
|
||||
# 51| Type = [Class] ClassWithDestructor2
|
||||
# 51| ValueCategory = prvalue(load)
|
||||
# 51| getCondition(): [VariableAccess] b
|
||||
# 51| Type = [BoolType] bool
|
||||
# 51| ValueCategory = prvalue(load)
|
||||
# 51| getThen(): [ThrowExpr] throw ...
|
||||
# 51| Type = [Class] ClassWithConstructor
|
||||
# 51| ValueCategory = prvalue
|
||||
# 51| getExpr(): [ConstructorCall] call to ClassWithConstructor
|
||||
# 51| Type = [VoidType] void
|
||||
# 51| ValueCategory = prvalue
|
||||
# 51| getArgument(0): [CharLiteral] 120
|
||||
# 51| Type = [PlainCharType] char
|
||||
# 51| Value = [CharLiteral] 120
|
||||
# 51| ValueCategory = prvalue
|
||||
# 51| getArgument(1): [FunctionCall] call to get_x
|
||||
# 51| Type = [PlainCharType] char
|
||||
# 51| ValueCategory = prvalue
|
||||
# 51| getQualifier(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 51| Type = [VoidType] void
|
||||
# 51| ValueCategory = prvalue
|
||||
# 51| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 51| Type = [Class] ClassWithDestructor2
|
||||
# 51| ValueCategory = prvalue(load)
|
||||
# 52| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor2
|
||||
# 52| Type = [VoidType] void
|
||||
# 52| ValueCategory = prvalue
|
||||
# 52| getQualifier(): [VariableAccess] c
|
||||
# 52| Type = [Class] ClassWithDestructor2
|
||||
# 52| ValueCategory = lvalue
|
||||
# 51| getElse(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 51| Type = [VoidType] void
|
||||
# 51| ValueCategory = prvalue
|
||||
# 51| getElse().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 51| Type = [Class] ClassWithDestructor2
|
||||
# 51| ValueCategory = prvalue(load)
|
||||
# 51| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 51| Type = [Class] ClassWithDestructor2
|
||||
# 51| ValueCategory = prvalue
|
||||
# 52| getStmt(2): [ReturnStmt] return ...
|
||||
# 52| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor2
|
||||
# 52| Type = [VoidType] void
|
||||
# 52| ValueCategory = prvalue
|
||||
# 52| getQualifier(): [VariableAccess] c
|
||||
# 52| Type = [Class] ClassWithDestructor2
|
||||
# 52| ValueCategory = lvalue
|
||||
# 54| [TopLevelFunction] void temp_test8(bool)
|
||||
# 54| <params>:
|
||||
# 54| getParameter(0): [Parameter] b
|
||||
# 54| Type = [BoolType] bool
|
||||
# 54| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 55| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 55| getExpr(): [ConditionalExpr] ... ? ... : ...
|
||||
# 55| Type = [Class] ClassWithDestructor2
|
||||
# 55| ValueCategory = prvalue(load)
|
||||
# 55| getCondition(): [VariableAccess] b
|
||||
# 55| Type = [BoolType] bool
|
||||
# 55| ValueCategory = prvalue(load)
|
||||
# 55| getThen(): [ThrowExpr] throw ...
|
||||
# 55| Type = [Class] ClassWithConstructor
|
||||
# 55| ValueCategory = prvalue
|
||||
# 55| getExpr(): [ConstructorCall] call to ClassWithConstructor
|
||||
# 55| Type = [VoidType] void
|
||||
# 55| ValueCategory = prvalue
|
||||
# 55| getArgument(0): [CharLiteral] 120
|
||||
# 55| Type = [PlainCharType] char
|
||||
# 55| Value = [CharLiteral] 120
|
||||
# 55| ValueCategory = prvalue
|
||||
# 55| getArgument(1): [FunctionCall] call to get_x
|
||||
# 55| Type = [PlainCharType] char
|
||||
# 55| ValueCategory = prvalue
|
||||
# 55| getQualifier(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 55| Type = [VoidType] void
|
||||
# 55| ValueCategory = prvalue
|
||||
# 55| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 55| Type = [Class] ClassWithDestructor2
|
||||
# 55| ValueCategory = prvalue(load)
|
||||
# 55| getElse(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 55| Type = [VoidType] void
|
||||
# 55| ValueCategory = prvalue
|
||||
# 55| getElse().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 55| Type = [Class] ClassWithDestructor2
|
||||
# 55| ValueCategory = prvalue(load)
|
||||
# 55| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 55| Type = [Class] ClassWithDestructor2
|
||||
# 55| ValueCategory = prvalue
|
||||
# 56| getStmt(1): [ReturnStmt] return ...
|
||||
ir.c:
|
||||
# 5| [TopLevelFunction] int getX(MyCoords*)
|
||||
# 5| <params>:
|
||||
|
||||
@@ -738,6 +738,499 @@ complex.c:
|
||||
# 58| v58_6(void) = AliasedUse : m58_3
|
||||
# 58| v58_7(void) = ExitFunction :
|
||||
|
||||
destructors_for_temps.cpp:
|
||||
# 9| void ClassWithConstructor::ClassWithConstructor(ClassWithConstructor&&)
|
||||
# 9| Block 0
|
||||
# 9| v9_1(void) = EnterFunction :
|
||||
# 9| m9_2(unknown) = AliasedDefinition :
|
||||
# 9| m9_3(unknown) = InitializeNonLocal :
|
||||
# 9| m9_4(unknown) = Chi : total:m9_2, partial:m9_3
|
||||
# 9| r9_5(glval<unknown>) = VariableAddress[#this] :
|
||||
# 9| m9_6(glval<ClassWithConstructor>) = InitializeParameter[#this] : &:r9_5
|
||||
# 9| r9_7(glval<ClassWithConstructor>) = Load[#this] : &:r9_5, m9_6
|
||||
# 9| m9_8(ClassWithConstructor) = InitializeIndirection[#this] : &:r9_7
|
||||
#-----| r0_1(glval<ClassWithConstructor &&>) = VariableAddress[(unnamed parameter 0)] :
|
||||
#-----| m0_2(ClassWithConstructor &&) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
|
||||
#-----| r0_3(ClassWithConstructor &&) = Load[(unnamed parameter 0)] : &:r0_1, m0_2
|
||||
#-----| m0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
|
||||
# 9| v9_9(void) = NoOp :
|
||||
# 9| v9_10(void) = ReturnIndirection[#this] : &:r9_7, m9_8
|
||||
#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, m0_4
|
||||
# 9| v9_11(void) = ReturnVoid :
|
||||
# 9| v9_12(void) = AliasedUse : m9_3
|
||||
# 9| v9_13(void) = ExitFunction :
|
||||
|
||||
# 14| char temp_test()
|
||||
# 14| Block 0
|
||||
# 14| v14_1(void) = EnterFunction :
|
||||
# 14| m14_2(unknown) = AliasedDefinition :
|
||||
# 14| m14_3(unknown) = InitializeNonLocal :
|
||||
# 14| m14_4(unknown) = Chi : total:m14_2, partial:m14_3
|
||||
# 15| r15_1(glval<char>) = VariableAddress[x] :
|
||||
# 15| r15_2(glval<ClassWithDestructor2>) = VariableAddress[#temp15:14] :
|
||||
# 15| m15_3(ClassWithDestructor2) = Uninitialized[#temp15:14] : &:r15_2
|
||||
# 15| r15_4(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 15| v15_5(void) = Call[ClassWithDestructor2] : func:r15_4, this:r15_2
|
||||
# 15| m15_6(unknown) = ^CallSideEffect : ~m14_4
|
||||
# 15| m15_7(unknown) = Chi : total:m14_4, partial:m15_6
|
||||
# 15| m15_8(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r15_2
|
||||
# 15| m15_9(ClassWithDestructor2) = Chi : total:m15_3, partial:m15_8
|
||||
# 15| r15_10(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 15| r15_11(char) = Call[get_x] : func:r15_10, this:r15_2
|
||||
# 15| m15_12(unknown) = ^CallSideEffect : ~m15_7
|
||||
# 15| m15_13(unknown) = Chi : total:m15_7, partial:m15_12
|
||||
# 15| v15_14(void) = ^IndirectReadSideEffect[-1] : &:r15_2, m15_9
|
||||
# 15| m15_15(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r15_2
|
||||
# 15| m15_16(ClassWithDestructor2) = Chi : total:m15_9, partial:m15_15
|
||||
# 15| m15_17(char) = Store[x] : &:r15_1, r15_11
|
||||
# 16| r16_1(glval<ClassWithConstructor>) = VariableAddress[y] :
|
||||
# 16| m16_2(ClassWithConstructor) = Uninitialized[y] : &:r16_1
|
||||
# 16| r16_3(glval<unknown>) = FunctionAddress[ClassWithConstructor] :
|
||||
# 16| r16_4(char) = Constant[97] :
|
||||
# 16| r16_5(glval<ClassWithDestructor2>) = VariableAddress[#temp16:33] :
|
||||
# 16| m16_6(ClassWithDestructor2) = Uninitialized[#temp16:33] : &:r16_5
|
||||
# 16| r16_7(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 16| v16_8(void) = Call[ClassWithDestructor2] : func:r16_7, this:r16_5
|
||||
# 16| m16_9(unknown) = ^CallSideEffect : ~m15_13
|
||||
# 16| m16_10(unknown) = Chi : total:m15_13, partial:m16_9
|
||||
# 16| m16_11(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r16_5
|
||||
# 16| m16_12(ClassWithDestructor2) = Chi : total:m16_6, partial:m16_11
|
||||
# 16| r16_13(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 16| r16_14(char) = Call[get_x] : func:r16_13, this:r16_5
|
||||
# 16| m16_15(unknown) = ^CallSideEffect : ~m16_10
|
||||
# 16| m16_16(unknown) = Chi : total:m16_10, partial:m16_15
|
||||
# 16| v16_17(void) = ^IndirectReadSideEffect[-1] : &:r16_5, m16_12
|
||||
# 16| m16_18(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r16_5
|
||||
# 16| m16_19(ClassWithDestructor2) = Chi : total:m16_12, partial:m16_18
|
||||
# 16| v16_20(void) = Call[ClassWithConstructor] : func:r16_3, this:r16_1, 0:r16_4, 1:r16_14
|
||||
# 16| m16_21(unknown) = ^CallSideEffect : ~m16_16
|
||||
# 16| m16_22(unknown) = Chi : total:m16_16, partial:m16_21
|
||||
# 16| m16_23(ClassWithConstructor) = ^IndirectMayWriteSideEffect[-1] : &:r16_1
|
||||
# 16| m16_24(ClassWithConstructor) = Chi : total:m16_2, partial:m16_23
|
||||
# 17| r17_1(glval<char>) = VariableAddress[#return] :
|
||||
# 17| r17_2(glval<ClassWithDestructor2>) = VariableAddress[#temp17:12] :
|
||||
# 17| m17_3(ClassWithDestructor2) = Uninitialized[#temp17:12] : &:r17_2
|
||||
# 17| r17_4(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 17| v17_5(void) = Call[ClassWithDestructor2] : func:r17_4, this:r17_2
|
||||
# 17| m17_6(unknown) = ^CallSideEffect : ~m16_22
|
||||
# 17| m17_7(unknown) = Chi : total:m16_22, partial:m17_6
|
||||
# 17| m17_8(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r17_2
|
||||
# 17| m17_9(ClassWithDestructor2) = Chi : total:m17_3, partial:m17_8
|
||||
# 17| r17_10(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 17| r17_11(char) = Call[get_x] : func:r17_10, this:r17_2
|
||||
# 17| m17_12(unknown) = ^CallSideEffect : ~m17_7
|
||||
# 17| m17_13(unknown) = Chi : total:m17_7, partial:m17_12
|
||||
# 17| v17_14(void) = ^IndirectReadSideEffect[-1] : &:r17_2, m17_9
|
||||
# 17| m17_15(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r17_2
|
||||
# 17| m17_16(ClassWithDestructor2) = Chi : total:m17_9, partial:m17_15
|
||||
# 17| m17_17(char) = Store[#return] : &:r17_1, r17_11
|
||||
# 14| r14_5(glval<char>) = VariableAddress[#return] :
|
||||
# 14| v14_6(void) = ReturnValue : &:r14_5, m17_17
|
||||
# 14| v14_7(void) = AliasedUse : ~m17_13
|
||||
# 14| v14_8(void) = ExitFunction :
|
||||
|
||||
# 21| char temp_test2()
|
||||
# 21| Block 0
|
||||
# 21| v21_1(void) = EnterFunction :
|
||||
# 21| m21_2(unknown) = AliasedDefinition :
|
||||
# 21| m21_3(unknown) = InitializeNonLocal :
|
||||
# 21| m21_4(unknown) = Chi : total:m21_2, partial:m21_3
|
||||
# 22| r22_1(glval<unknown>) = FunctionAddress[operator new] :
|
||||
# 22| r22_2(unsigned long) = Constant[1] :
|
||||
# 22| r22_3(void *) = Call[operator new] : func:r22_1, 0:r22_2
|
||||
# 22| m22_4(unknown) = ^CallSideEffect : ~m21_4
|
||||
# 22| m22_5(unknown) = Chi : total:m21_4, partial:m22_4
|
||||
# 22| m22_6(unknown) = ^InitializeDynamicAllocation : &:r22_3
|
||||
# 22| r22_7(ClassWithDestructor2 *) = Convert : r22_3
|
||||
# 22| r22_8(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 22| v22_9(void) = Call[ClassWithDestructor2] : func:r22_8, this:r22_7
|
||||
# 22| m22_10(unknown) = ^CallSideEffect : ~m22_5
|
||||
# 22| m22_11(unknown) = Chi : total:m22_5, partial:m22_10
|
||||
# 22| m22_12(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r22_7
|
||||
# 22| m22_13(unknown) = Chi : total:m22_6, partial:m22_12
|
||||
# 23| r23_1(glval<char>) = VariableAddress[#return] :
|
||||
# 23| r23_2(glval<ClassWithDestructor2>) = VariableAddress[#temp23:12] :
|
||||
# 23| m23_3(ClassWithDestructor2) = Uninitialized[#temp23:12] : &:r23_2
|
||||
# 23| r23_4(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 23| v23_5(void) = Call[ClassWithDestructor2] : func:r23_4, this:r23_2
|
||||
# 23| m23_6(unknown) = ^CallSideEffect : ~m22_11
|
||||
# 23| m23_7(unknown) = Chi : total:m22_11, partial:m23_6
|
||||
# 23| m23_8(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r23_2
|
||||
# 23| m23_9(ClassWithDestructor2) = Chi : total:m23_3, partial:m23_8
|
||||
# 23| r23_10(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 23| r23_11(char) = Call[get_x] : func:r23_10, this:r23_2
|
||||
# 23| m23_12(unknown) = ^CallSideEffect : ~m23_7
|
||||
# 23| m23_13(unknown) = Chi : total:m23_7, partial:m23_12
|
||||
# 23| v23_14(void) = ^IndirectReadSideEffect[-1] : &:r23_2, m23_9
|
||||
# 23| m23_15(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r23_2
|
||||
# 23| m23_16(ClassWithDestructor2) = Chi : total:m23_9, partial:m23_15
|
||||
# 23| r23_17(int) = Convert : r23_11
|
||||
# 23| r23_18(glval<ClassWithDestructor2>) = VariableAddress[#temp23:45] :
|
||||
# 23| m23_19(ClassWithDestructor2) = Uninitialized[#temp23:45] : &:r23_18
|
||||
# 23| r23_20(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 23| v23_21(void) = Call[ClassWithDestructor2] : func:r23_20, this:r23_18
|
||||
# 23| m23_22(unknown) = ^CallSideEffect : ~m23_13
|
||||
# 23| m23_23(unknown) = Chi : total:m23_13, partial:m23_22
|
||||
# 23| m23_24(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r23_18
|
||||
# 23| m23_25(ClassWithDestructor2) = Chi : total:m23_19, partial:m23_24
|
||||
# 23| r23_26(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 23| r23_27(char) = Call[get_x] : func:r23_26, this:r23_18
|
||||
# 23| m23_28(unknown) = ^CallSideEffect : ~m23_23
|
||||
# 23| m23_29(unknown) = Chi : total:m23_23, partial:m23_28
|
||||
# 23| v23_30(void) = ^IndirectReadSideEffect[-1] : &:r23_18, m23_25
|
||||
# 23| m23_31(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r23_18
|
||||
# 23| m23_32(ClassWithDestructor2) = Chi : total:m23_25, partial:m23_31
|
||||
# 23| r23_33(int) = Convert : r23_27
|
||||
# 23| r23_34(int) = Add : r23_17, r23_33
|
||||
# 23| r23_35(char) = Convert : r23_34
|
||||
# 23| m23_36(char) = Store[#return] : &:r23_1, r23_35
|
||||
# 21| r21_5(glval<char>) = VariableAddress[#return] :
|
||||
# 21| v21_6(void) = ReturnValue : &:r21_5, m23_36
|
||||
# 21| v21_7(void) = AliasedUse : ~m23_29
|
||||
# 21| v21_8(void) = ExitFunction :
|
||||
|
||||
# 29| void temp_test3()
|
||||
# 29| Block 0
|
||||
# 29| v29_1(void) = EnterFunction :
|
||||
# 29| m29_2(unknown) = AliasedDefinition :
|
||||
# 29| m29_3(unknown) = InitializeNonLocal :
|
||||
# 29| m29_4(unknown) = Chi : total:m29_2, partial:m29_3
|
||||
# 30| r30_1(glval<ClassWithDestructor2 &>) = VariableAddress[rs] :
|
||||
# 30| r30_2(glval<ClassWithDestructor2>) = VariableAddress[#temp30:38] :
|
||||
# 30| r30_3(glval<unknown>) = FunctionAddress[returnValue] :
|
||||
# 30| r30_4(ClassWithDestructor2) = Call[returnValue] : func:r30_3
|
||||
# 30| m30_5(unknown) = ^CallSideEffect : ~m29_4
|
||||
# 30| m30_6(unknown) = Chi : total:m29_4, partial:m30_5
|
||||
# 30| m30_7(ClassWithDestructor2) = Store[#temp30:38] : &:r30_2, r30_4
|
||||
# 30| r30_8(glval<ClassWithDestructor2>) = Convert : r30_2
|
||||
# 30| r30_9(ClassWithDestructor2 &) = CopyValue : r30_8
|
||||
# 30| m30_10(ClassWithDestructor2 &) = Store[rs] : &:r30_1, r30_9
|
||||
# 31| v31_1(void) = NoOp :
|
||||
# 29| v29_5(void) = ReturnVoid :
|
||||
# 29| v29_6(void) = AliasedUse : ~m30_6
|
||||
# 29| v29_7(void) = ExitFunction :
|
||||
|
||||
# 33| void temp_test4()
|
||||
# 33| Block 0
|
||||
# 33| v33_1(void) = EnterFunction :
|
||||
# 33| m33_2(unknown) = AliasedDefinition :
|
||||
# 33| m33_3(unknown) = InitializeNonLocal :
|
||||
# 33| m33_4(unknown) = Chi : total:m33_2, partial:m33_3
|
||||
# 34| r34_1(glval<ClassWithDestructor2>) = VariableAddress[c] :
|
||||
# 34| m34_2(ClassWithDestructor2) = Uninitialized[c] : &:r34_1
|
||||
# 34| r34_3(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 34| v34_4(void) = Call[ClassWithDestructor2] : func:r34_3, this:r34_1
|
||||
# 34| m34_5(unknown) = ^CallSideEffect : ~m33_4
|
||||
# 34| m34_6(unknown) = Chi : total:m33_4, partial:m34_5
|
||||
# 34| m34_7(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r34_1
|
||||
# 34| m34_8(ClassWithDestructor2) = Chi : total:m34_2, partial:m34_7
|
||||
# 35| r35_1(glval<ClassWithDestructor2 &>) = VariableAddress[rs2] :
|
||||
# 35| r35_2(glval<ClassWithDestructor2>) = VariableAddress[#temp35:39] :
|
||||
# 35| r35_3(glval<unknown>) = FunctionAddress[returnValue] :
|
||||
# 35| r35_4(ClassWithDestructor2) = Call[returnValue] : func:r35_3
|
||||
# 35| m35_5(unknown) = ^CallSideEffect : ~m34_6
|
||||
# 35| m35_6(unknown) = Chi : total:m34_6, partial:m35_5
|
||||
# 35| m35_7(ClassWithDestructor2) = Store[#temp35:39] : &:r35_2, r35_4
|
||||
# 35| r35_8(glval<ClassWithDestructor2>) = Convert : r35_2
|
||||
# 35| r35_9(ClassWithDestructor2 &) = CopyValue : r35_8
|
||||
# 35| m35_10(ClassWithDestructor2 &) = Store[rs2] : &:r35_1, r35_9
|
||||
# 36| v36_1(void) = NoOp :
|
||||
# 36| r36_2(glval<ClassWithDestructor2>) = VariableAddress[c] :
|
||||
# 36| r36_3(glval<unknown>) = FunctionAddress[~ClassWithDestructor2] :
|
||||
# 36| v36_4(void) = Call[~ClassWithDestructor2] : func:r36_3, this:r36_2
|
||||
# 36| m36_5(unknown) = ^CallSideEffect : ~m35_6
|
||||
# 36| m36_6(unknown) = Chi : total:m35_6, partial:m36_5
|
||||
# 36| v36_7(void) = ^IndirectReadSideEffect[-1] : &:r36_2, m34_8
|
||||
# 36| m36_8(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r36_2
|
||||
# 36| m36_9(ClassWithDestructor2) = Chi : total:m34_8, partial:m36_8
|
||||
# 33| v33_5(void) = ReturnVoid :
|
||||
# 33| v33_6(void) = AliasedUse : ~m36_6
|
||||
# 33| v33_7(void) = ExitFunction :
|
||||
|
||||
# 38| void temp_test5(bool)
|
||||
# 38| Block 0
|
||||
# 38| v38_1(void) = EnterFunction :
|
||||
# 38| m38_2(unknown) = AliasedDefinition :
|
||||
# 38| m38_3(unknown) = InitializeNonLocal :
|
||||
# 38| m38_4(unknown) = Chi : total:m38_2, partial:m38_3
|
||||
# 38| r38_5(glval<bool>) = VariableAddress[b] :
|
||||
# 38| m38_6(bool) = InitializeParameter[b] : &:r38_5
|
||||
# 39| r39_1(glval<ClassWithDestructor2>) = VariableAddress[#temp39:3] :
|
||||
# 39| r39_2(glval<bool>) = VariableAddress[b] :
|
||||
# 39| r39_3(bool) = Load[b] : &:r39_2, m38_6
|
||||
# 39| v39_4(void) = ConditionalBranch : r39_3
|
||||
#-----| False -> Block 3
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 39| Block 1
|
||||
# 39| m39_5(unknown) = Phi : from 2:~m39_15, from 3:~m39_26
|
||||
# 39| m39_6(ClassWithDestructor2) = Phi : from 2:m39_20, from 3:m39_31
|
||||
# 39| r39_7(glval<ClassWithDestructor2>) = VariableAddress[#temp39:3] :
|
||||
# 39| r39_8(ClassWithDestructor2) = Load[#temp39:3] : &:r39_7, m39_6
|
||||
# 39| m39_9(ClassWithDestructor2) = Store[#temp39:3] : &:r39_1, r39_8
|
||||
# 40| v40_1(void) = NoOp :
|
||||
# 38| v38_7(void) = ReturnVoid :
|
||||
# 38| v38_8(void) = AliasedUse : ~m39_5
|
||||
# 38| v38_9(void) = ExitFunction :
|
||||
|
||||
# 39| Block 2
|
||||
# 39| r39_10(glval<ClassWithDestructor2>) = VariableAddress[#temp39:7] :
|
||||
# 39| m39_11(ClassWithDestructor2) = Uninitialized[#temp39:7] : &:r39_10
|
||||
# 39| r39_12(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 39| v39_13(void) = Call[ClassWithDestructor2] : func:r39_12, this:r39_10
|
||||
# 39| m39_14(unknown) = ^CallSideEffect : ~m38_4
|
||||
# 39| m39_15(unknown) = Chi : total:m38_4, partial:m39_14
|
||||
# 39| m39_16(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r39_10
|
||||
# 39| m39_17(ClassWithDestructor2) = Chi : total:m39_11, partial:m39_16
|
||||
# 39| r39_18(ClassWithDestructor2) = Load[#temp39:7] : &:r39_10, m39_17
|
||||
# 39| r39_19(glval<ClassWithDestructor2>) = VariableAddress[#temp39:3] :
|
||||
# 39| m39_20(ClassWithDestructor2) = Store[#temp39:3] : &:r39_19, r39_18
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 39| Block 3
|
||||
# 39| r39_21(glval<ClassWithDestructor2>) = VariableAddress[#temp39:32] :
|
||||
# 39| m39_22(ClassWithDestructor2) = Uninitialized[#temp39:32] : &:r39_21
|
||||
# 39| r39_23(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 39| v39_24(void) = Call[ClassWithDestructor2] : func:r39_23, this:r39_21
|
||||
# 39| m39_25(unknown) = ^CallSideEffect : ~m38_4
|
||||
# 39| m39_26(unknown) = Chi : total:m38_4, partial:m39_25
|
||||
# 39| m39_27(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r39_21
|
||||
# 39| m39_28(ClassWithDestructor2) = Chi : total:m39_22, partial:m39_27
|
||||
# 39| r39_29(ClassWithDestructor2) = Load[#temp39:32] : &:r39_21, m39_28
|
||||
# 39| r39_30(glval<ClassWithDestructor2>) = VariableAddress[#temp39:3] :
|
||||
# 39| m39_31(ClassWithDestructor2) = Store[#temp39:3] : &:r39_30, r39_29
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 42| void temp_test6(bool)
|
||||
# 42| Block 0
|
||||
# 42| v42_1(void) = EnterFunction :
|
||||
# 42| m42_2(unknown) = AliasedDefinition :
|
||||
# 42| m42_3(unknown) = InitializeNonLocal :
|
||||
# 42| m42_4(unknown) = Chi : total:m42_2, partial:m42_3
|
||||
# 42| r42_5(glval<bool>) = VariableAddress[b] :
|
||||
# 42| m42_6(bool) = InitializeParameter[b] : &:r42_5
|
||||
# 43| r43_1(glval<ClassWithDestructor2>) = VariableAddress[c] :
|
||||
# 43| m43_2(ClassWithDestructor2) = Uninitialized[c] : &:r43_1
|
||||
# 43| r43_3(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 43| v43_4(void) = Call[ClassWithDestructor2] : func:r43_3, this:r43_1
|
||||
# 43| m43_5(unknown) = ^CallSideEffect : ~m42_4
|
||||
# 43| m43_6(unknown) = Chi : total:m42_4, partial:m43_5
|
||||
# 43| m43_7(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r43_1
|
||||
# 43| m43_8(ClassWithDestructor2) = Chi : total:m43_2, partial:m43_7
|
||||
# 44| r44_1(glval<bool>) = VariableAddress[b] :
|
||||
# 44| r44_2(bool) = Load[b] : &:r44_1, m42_6
|
||||
# 44| v44_3(void) = ConditionalBranch : r44_2
|
||||
#-----| False -> Block 4
|
||||
#-----| True -> Block 3
|
||||
|
||||
# 42| Block 1
|
||||
# 42| m42_7(unknown) = Phi : from 2:~m45_22, from 4:~m47_6
|
||||
# 42| v42_8(void) = AliasedUse : ~m42_7
|
||||
# 42| v42_9(void) = ExitFunction :
|
||||
|
||||
# 42| Block 2
|
||||
# 42| v42_10(void) = Unwind :
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 45| Block 3
|
||||
# 45| r45_1(glval<ClassWithConstructor>) = VariableAddress[#throw45:7] :
|
||||
# 45| m45_2(ClassWithConstructor) = Uninitialized[#throw45:7] : &:r45_1
|
||||
# 45| r45_3(glval<unknown>) = FunctionAddress[ClassWithConstructor] :
|
||||
# 45| r45_4(char) = Constant[120] :
|
||||
# 45| r45_5(glval<ClassWithDestructor2>) = VariableAddress[#temp45:39] :
|
||||
# 45| m45_6(ClassWithDestructor2) = Uninitialized[#temp45:39] : &:r45_5
|
||||
# 45| r45_7(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 45| v45_8(void) = Call[ClassWithDestructor2] : func:r45_7, this:r45_5
|
||||
# 45| m45_9(unknown) = ^CallSideEffect : ~m43_6
|
||||
# 45| m45_10(unknown) = Chi : total:m43_6, partial:m45_9
|
||||
# 45| m45_11(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r45_5
|
||||
# 45| m45_12(ClassWithDestructor2) = Chi : total:m45_6, partial:m45_11
|
||||
# 45| r45_13(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 45| r45_14(char) = Call[get_x] : func:r45_13, this:r45_5
|
||||
# 45| m45_15(unknown) = ^CallSideEffect : ~m45_10
|
||||
# 45| m45_16(unknown) = Chi : total:m45_10, partial:m45_15
|
||||
# 45| v45_17(void) = ^IndirectReadSideEffect[-1] : &:r45_5, m45_12
|
||||
# 45| m45_18(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r45_5
|
||||
# 45| m45_19(ClassWithDestructor2) = Chi : total:m45_12, partial:m45_18
|
||||
# 45| v45_20(void) = Call[ClassWithConstructor] : func:r45_3, this:r45_1, 0:r45_4, 1:r45_14
|
||||
# 45| m45_21(unknown) = ^CallSideEffect : ~m45_16
|
||||
# 45| m45_22(unknown) = Chi : total:m45_16, partial:m45_21
|
||||
# 45| m45_23(ClassWithConstructor) = ^IndirectMayWriteSideEffect[-1] : &:r45_1
|
||||
# 45| m45_24(ClassWithConstructor) = Chi : total:m45_2, partial:m45_23
|
||||
# 45| v45_25(void) = ThrowValue : &:r45_1, m45_24
|
||||
#-----| Exception -> Block 2
|
||||
|
||||
# 47| Block 4
|
||||
# 47| v47_1(void) = NoOp :
|
||||
# 47| r47_2(glval<ClassWithDestructor2>) = VariableAddress[c] :
|
||||
# 47| r47_3(glval<unknown>) = FunctionAddress[~ClassWithDestructor2] :
|
||||
# 47| v47_4(void) = Call[~ClassWithDestructor2] : func:r47_3, this:r47_2
|
||||
# 47| m47_5(unknown) = ^CallSideEffect : ~m43_6
|
||||
# 47| m47_6(unknown) = Chi : total:m43_6, partial:m47_5
|
||||
# 47| v47_7(void) = ^IndirectReadSideEffect[-1] : &:r47_2, m43_8
|
||||
# 47| m47_8(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r47_2
|
||||
# 47| m47_9(ClassWithDestructor2) = Chi : total:m43_8, partial:m47_8
|
||||
# 42| v42_11(void) = ReturnVoid :
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 49| void temp_test7(bool)
|
||||
# 49| Block 0
|
||||
# 49| v49_1(void) = EnterFunction :
|
||||
# 49| m49_2(unknown) = AliasedDefinition :
|
||||
# 49| m49_3(unknown) = InitializeNonLocal :
|
||||
# 49| m49_4(unknown) = Chi : total:m49_2, partial:m49_3
|
||||
# 49| r49_5(glval<bool>) = VariableAddress[b] :
|
||||
# 49| m49_6(bool) = InitializeParameter[b] : &:r49_5
|
||||
# 50| r50_1(glval<ClassWithDestructor2>) = VariableAddress[c] :
|
||||
# 50| m50_2(ClassWithDestructor2) = Uninitialized[c] : &:r50_1
|
||||
# 50| r50_3(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 50| v50_4(void) = Call[ClassWithDestructor2] : func:r50_3, this:r50_1
|
||||
# 50| m50_5(unknown) = ^CallSideEffect : ~m49_4
|
||||
# 50| m50_6(unknown) = Chi : total:m49_4, partial:m50_5
|
||||
# 50| m50_7(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r50_1
|
||||
# 50| m50_8(ClassWithDestructor2) = Chi : total:m50_2, partial:m50_7
|
||||
# 51| r51_1(glval<ClassWithDestructor2>) = VariableAddress[#temp51:5] :
|
||||
# 51| r51_2(glval<bool>) = VariableAddress[b] :
|
||||
# 51| r51_3(bool) = Load[b] : &:r51_2, m49_6
|
||||
# 51| v51_4(void) = ConditionalBranch : r51_3
|
||||
#-----| False -> Block 4
|
||||
#-----| True -> Block 3
|
||||
|
||||
# 49| Block 1
|
||||
# 49| m49_7(unknown) = Phi : from 2:~m51_26, from 4:~m52_6
|
||||
# 49| v49_8(void) = AliasedUse : ~m49_7
|
||||
# 49| v49_9(void) = ExitFunction :
|
||||
|
||||
# 49| Block 2
|
||||
# 49| v49_10(void) = Unwind :
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 51| Block 3
|
||||
# 51| r51_5(glval<ClassWithConstructor>) = VariableAddress[#throw51:9] :
|
||||
# 51| m51_6(ClassWithConstructor) = Uninitialized[#throw51:9] : &:r51_5
|
||||
# 51| r51_7(glval<unknown>) = FunctionAddress[ClassWithConstructor] :
|
||||
# 51| r51_8(char) = Constant[120] :
|
||||
# 51| r51_9(glval<ClassWithDestructor2>) = VariableAddress[#temp51:41] :
|
||||
# 51| m51_10(ClassWithDestructor2) = Uninitialized[#temp51:41] : &:r51_9
|
||||
# 51| r51_11(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 51| v51_12(void) = Call[ClassWithDestructor2] : func:r51_11, this:r51_9
|
||||
# 51| m51_13(unknown) = ^CallSideEffect : ~m50_6
|
||||
# 51| m51_14(unknown) = Chi : total:m50_6, partial:m51_13
|
||||
# 51| m51_15(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r51_9
|
||||
# 51| m51_16(ClassWithDestructor2) = Chi : total:m51_10, partial:m51_15
|
||||
# 51| r51_17(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 51| r51_18(char) = Call[get_x] : func:r51_17, this:r51_9
|
||||
# 51| m51_19(unknown) = ^CallSideEffect : ~m51_14
|
||||
# 51| m51_20(unknown) = Chi : total:m51_14, partial:m51_19
|
||||
# 51| v51_21(void) = ^IndirectReadSideEffect[-1] : &:r51_9, m51_16
|
||||
# 51| m51_22(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r51_9
|
||||
# 51| m51_23(ClassWithDestructor2) = Chi : total:m51_16, partial:m51_22
|
||||
# 51| v51_24(void) = Call[ClassWithConstructor] : func:r51_7, this:r51_5, 0:r51_8, 1:r51_18
|
||||
# 51| m51_25(unknown) = ^CallSideEffect : ~m51_20
|
||||
# 51| m51_26(unknown) = Chi : total:m51_20, partial:m51_25
|
||||
# 51| m51_27(ClassWithConstructor) = ^IndirectMayWriteSideEffect[-1] : &:r51_5
|
||||
# 51| m51_28(ClassWithConstructor) = Chi : total:m51_6, partial:m51_27
|
||||
# 51| v51_29(void) = ThrowValue : &:r51_5, m51_28
|
||||
#-----| Exception -> Block 2
|
||||
|
||||
# 51| Block 4
|
||||
# 51| r51_30(glval<ClassWithDestructor2>) = VariableAddress[#temp51:75] :
|
||||
# 51| m51_31(ClassWithDestructor2) = Uninitialized[#temp51:75] : &:r51_30
|
||||
# 51| r51_32(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 51| v51_33(void) = Call[ClassWithDestructor2] : func:r51_32, this:r51_30
|
||||
# 51| m51_34(unknown) = ^CallSideEffect : ~m50_6
|
||||
# 51| m51_35(unknown) = Chi : total:m50_6, partial:m51_34
|
||||
# 51| m51_36(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r51_30
|
||||
# 51| m51_37(ClassWithDestructor2) = Chi : total:m51_31, partial:m51_36
|
||||
# 51| r51_38(ClassWithDestructor2) = Load[#temp51:75] : &:r51_30, m51_37
|
||||
# 51| r51_39(glval<ClassWithDestructor2>) = VariableAddress[#temp51:5] :
|
||||
# 51| m51_40(ClassWithDestructor2) = Store[#temp51:5] : &:r51_39, r51_38
|
||||
# 51| r51_41(glval<ClassWithDestructor2>) = VariableAddress[#temp51:5] :
|
||||
# 51| r51_42(ClassWithDestructor2) = Load[#temp51:5] : &:r51_41, m51_40
|
||||
# 51| m51_43(ClassWithDestructor2) = Store[#temp51:5] : &:r51_1, r51_42
|
||||
# 52| v52_1(void) = NoOp :
|
||||
# 52| r52_2(glval<ClassWithDestructor2>) = VariableAddress[c] :
|
||||
# 52| r52_3(glval<unknown>) = FunctionAddress[~ClassWithDestructor2] :
|
||||
# 52| v52_4(void) = Call[~ClassWithDestructor2] : func:r52_3, this:r52_2
|
||||
# 52| m52_5(unknown) = ^CallSideEffect : ~m51_35
|
||||
# 52| m52_6(unknown) = Chi : total:m51_35, partial:m52_5
|
||||
# 52| v52_7(void) = ^IndirectReadSideEffect[-1] : &:r52_2, m50_8
|
||||
# 52| m52_8(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r52_2
|
||||
# 52| m52_9(ClassWithDestructor2) = Chi : total:m50_8, partial:m52_8
|
||||
# 49| v49_11(void) = ReturnVoid :
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 54| void temp_test8(bool)
|
||||
# 54| Block 0
|
||||
# 54| v54_1(void) = EnterFunction :
|
||||
# 54| m54_2(unknown) = AliasedDefinition :
|
||||
# 54| m54_3(unknown) = InitializeNonLocal :
|
||||
# 54| m54_4(unknown) = Chi : total:m54_2, partial:m54_3
|
||||
# 54| r54_5(glval<bool>) = VariableAddress[b] :
|
||||
# 54| m54_6(bool) = InitializeParameter[b] : &:r54_5
|
||||
# 55| r55_1(glval<ClassWithDestructor2>) = VariableAddress[#temp55:5] :
|
||||
# 55| r55_2(glval<bool>) = VariableAddress[b] :
|
||||
# 55| r55_3(bool) = Load[b] : &:r55_2, m54_6
|
||||
# 55| v55_4(void) = ConditionalBranch : r55_3
|
||||
#-----| False -> Block 4
|
||||
#-----| True -> Block 3
|
||||
|
||||
# 54| Block 1
|
||||
# 54| m54_7(unknown) = Phi : from 2:~m55_26, from 4:~m55_35
|
||||
# 54| v54_8(void) = AliasedUse : ~m54_7
|
||||
# 54| v54_9(void) = ExitFunction :
|
||||
|
||||
# 54| Block 2
|
||||
# 54| v54_10(void) = Unwind :
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 55| Block 3
|
||||
# 55| r55_5(glval<ClassWithConstructor>) = VariableAddress[#throw55:9] :
|
||||
# 55| m55_6(ClassWithConstructor) = Uninitialized[#throw55:9] : &:r55_5
|
||||
# 55| r55_7(glval<unknown>) = FunctionAddress[ClassWithConstructor] :
|
||||
# 55| r55_8(char) = Constant[120] :
|
||||
# 55| r55_9(glval<ClassWithDestructor2>) = VariableAddress[#temp55:41] :
|
||||
# 55| m55_10(ClassWithDestructor2) = Uninitialized[#temp55:41] : &:r55_9
|
||||
# 55| r55_11(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 55| v55_12(void) = Call[ClassWithDestructor2] : func:r55_11, this:r55_9
|
||||
# 55| m55_13(unknown) = ^CallSideEffect : ~m54_4
|
||||
# 55| m55_14(unknown) = Chi : total:m54_4, partial:m55_13
|
||||
# 55| m55_15(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r55_9
|
||||
# 55| m55_16(ClassWithDestructor2) = Chi : total:m55_10, partial:m55_15
|
||||
# 55| r55_17(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 55| r55_18(char) = Call[get_x] : func:r55_17, this:r55_9
|
||||
# 55| m55_19(unknown) = ^CallSideEffect : ~m55_14
|
||||
# 55| m55_20(unknown) = Chi : total:m55_14, partial:m55_19
|
||||
# 55| v55_21(void) = ^IndirectReadSideEffect[-1] : &:r55_9, m55_16
|
||||
# 55| m55_22(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r55_9
|
||||
# 55| m55_23(ClassWithDestructor2) = Chi : total:m55_16, partial:m55_22
|
||||
# 55| v55_24(void) = Call[ClassWithConstructor] : func:r55_7, this:r55_5, 0:r55_8, 1:r55_18
|
||||
# 55| m55_25(unknown) = ^CallSideEffect : ~m55_20
|
||||
# 55| m55_26(unknown) = Chi : total:m55_20, partial:m55_25
|
||||
# 55| m55_27(ClassWithConstructor) = ^IndirectMayWriteSideEffect[-1] : &:r55_5
|
||||
# 55| m55_28(ClassWithConstructor) = Chi : total:m55_6, partial:m55_27
|
||||
# 55| v55_29(void) = ThrowValue : &:r55_5, m55_28
|
||||
#-----| Exception -> Block 2
|
||||
|
||||
# 55| Block 4
|
||||
# 55| r55_30(glval<ClassWithDestructor2>) = VariableAddress[#temp55:75] :
|
||||
# 55| m55_31(ClassWithDestructor2) = Uninitialized[#temp55:75] : &:r55_30
|
||||
# 55| r55_32(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 55| v55_33(void) = Call[ClassWithDestructor2] : func:r55_32, this:r55_30
|
||||
# 55| m55_34(unknown) = ^CallSideEffect : ~m54_4
|
||||
# 55| m55_35(unknown) = Chi : total:m54_4, partial:m55_34
|
||||
# 55| m55_36(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r55_30
|
||||
# 55| m55_37(ClassWithDestructor2) = Chi : total:m55_31, partial:m55_36
|
||||
# 55| r55_38(ClassWithDestructor2) = Load[#temp55:75] : &:r55_30, m55_37
|
||||
# 55| r55_39(glval<ClassWithDestructor2>) = VariableAddress[#temp55:5] :
|
||||
# 55| m55_40(ClassWithDestructor2) = Store[#temp55:5] : &:r55_39, r55_38
|
||||
# 55| r55_41(glval<ClassWithDestructor2>) = VariableAddress[#temp55:5] :
|
||||
# 55| r55_42(ClassWithDestructor2) = Load[#temp55:5] : &:r55_41, m55_40
|
||||
# 55| m55_43(ClassWithDestructor2) = Store[#temp55:5] : &:r55_1, r55_42
|
||||
# 56| v56_1(void) = NoOp :
|
||||
# 54| v54_11(void) = ReturnVoid :
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
ir.c:
|
||||
# 7| void MyCoordsTest(int)
|
||||
# 7| Block 0
|
||||
|
||||
56
cpp/ql/test/library-tests/ir/ir/destructors_for_temps.cpp
Normal file
56
cpp/ql/test/library-tests/ir/ir/destructors_for_temps.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
class ClassWithDestructor2 {
|
||||
public:
|
||||
ClassWithDestructor2();
|
||||
~ClassWithDestructor2();
|
||||
|
||||
char get_x();
|
||||
};
|
||||
|
||||
class ClassWithConstructor {
|
||||
public:
|
||||
ClassWithConstructor(char x, char y);
|
||||
};
|
||||
|
||||
char temp_test() {
|
||||
char x = ClassWithDestructor2().get_x();
|
||||
ClassWithConstructor y('a', ClassWithDestructor2().get_x());
|
||||
return ClassWithDestructor2().get_x();
|
||||
}
|
||||
|
||||
|
||||
char temp_test2() {
|
||||
new ClassWithDestructor2();
|
||||
return ClassWithDestructor2().get_x() + ClassWithDestructor2().get_x();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T returnValue();
|
||||
|
||||
void temp_test3() {
|
||||
const ClassWithDestructor2& rs = returnValue<ClassWithDestructor2>();
|
||||
}
|
||||
|
||||
void temp_test4() {
|
||||
ClassWithDestructor2 c;
|
||||
const ClassWithDestructor2& rs2 = returnValue<ClassWithDestructor2>();
|
||||
}
|
||||
|
||||
void temp_test5(bool b) {
|
||||
b ? ClassWithDestructor2() : ClassWithDestructor2();
|
||||
}
|
||||
|
||||
void temp_test6(bool b) {
|
||||
ClassWithDestructor2 c;
|
||||
if (b) {
|
||||
throw ClassWithConstructor('x', ClassWithDestructor2().get_x());
|
||||
}
|
||||
}
|
||||
|
||||
void temp_test7(bool b) {
|
||||
ClassWithDestructor2 c;
|
||||
b ? throw ClassWithConstructor('x', ClassWithDestructor2().get_x()) : ClassWithDestructor2();
|
||||
}
|
||||
|
||||
void temp_test8(bool b) {
|
||||
b ? throw ClassWithConstructor('x', ClassWithDestructor2().get_x()) : ClassWithDestructor2();
|
||||
}
|
||||
@@ -652,6 +652,440 @@
|
||||
| complex.c:144:8:144:10 | Load | m133_5 |
|
||||
| complex.c:144:8:144:10 | StoreValue | r144_3 |
|
||||
| complex.c:144:8:144:10 | Unary | r144_2 |
|
||||
| destructors_for_temps.cpp:9:7:9:7 | Address | &:r9_5 |
|
||||
| destructors_for_temps.cpp:9:7:9:7 | Address | &:r9_5 |
|
||||
| destructors_for_temps.cpp:9:7:9:7 | Address | &:r9_7 |
|
||||
| destructors_for_temps.cpp:9:7:9:7 | Address | &:r9_7 |
|
||||
| destructors_for_temps.cpp:9:7:9:7 | ChiPartial | partial:m9_3 |
|
||||
| destructors_for_temps.cpp:9:7:9:7 | ChiTotal | total:m9_2 |
|
||||
| destructors_for_temps.cpp:9:7:9:7 | Load | m9_6 |
|
||||
| destructors_for_temps.cpp:9:7:9:7 | SideEffect | m9_3 |
|
||||
| destructors_for_temps.cpp:9:7:9:7 | SideEffect | m9_8 |
|
||||
| destructors_for_temps.cpp:14:6:14:14 | Address | &:r14_5 |
|
||||
| destructors_for_temps.cpp:14:6:14:14 | ChiPartial | partial:m14_3 |
|
||||
| destructors_for_temps.cpp:14:6:14:14 | ChiTotal | total:m14_2 |
|
||||
| destructors_for_temps.cpp:14:6:14:14 | Load | m17_17 |
|
||||
| destructors_for_temps.cpp:14:6:14:14 | SideEffect | ~m17_13 |
|
||||
| destructors_for_temps.cpp:15:10:15:10 | Address | &:r15_1 |
|
||||
| destructors_for_temps.cpp:15:14:15:35 | Address | &:r15_2 |
|
||||
| destructors_for_temps.cpp:15:14:15:35 | Address | &:r15_2 |
|
||||
| destructors_for_temps.cpp:15:14:15:35 | Address | &:r15_2 |
|
||||
| destructors_for_temps.cpp:15:14:15:35 | Address | &:r15_2 |
|
||||
| destructors_for_temps.cpp:15:14:15:35 | Arg(this) | this:r15_2 |
|
||||
| destructors_for_temps.cpp:15:14:15:35 | Arg(this) | this:r15_2 |
|
||||
| destructors_for_temps.cpp:15:14:15:35 | CallTarget | func:r15_4 |
|
||||
| destructors_for_temps.cpp:15:14:15:35 | ChiPartial | partial:m15_6 |
|
||||
| destructors_for_temps.cpp:15:14:15:35 | ChiPartial | partial:m15_8 |
|
||||
| destructors_for_temps.cpp:15:14:15:35 | ChiPartial | partial:m15_15 |
|
||||
| destructors_for_temps.cpp:15:14:15:35 | ChiTotal | total:m14_4 |
|
||||
| destructors_for_temps.cpp:15:14:15:35 | ChiTotal | total:m15_3 |
|
||||
| destructors_for_temps.cpp:15:14:15:35 | ChiTotal | total:m15_9 |
|
||||
| destructors_for_temps.cpp:15:14:15:35 | SideEffect | m15_9 |
|
||||
| destructors_for_temps.cpp:15:14:15:35 | SideEffect | ~m14_4 |
|
||||
| destructors_for_temps.cpp:15:37:15:41 | CallTarget | func:r15_10 |
|
||||
| destructors_for_temps.cpp:15:37:15:41 | ChiPartial | partial:m15_12 |
|
||||
| destructors_for_temps.cpp:15:37:15:41 | ChiTotal | total:m15_7 |
|
||||
| destructors_for_temps.cpp:15:37:15:41 | SideEffect | ~m15_7 |
|
||||
| destructors_for_temps.cpp:15:37:15:41 | StoreValue | r15_11 |
|
||||
| destructors_for_temps.cpp:16:26:16:26 | Address | &:r16_1 |
|
||||
| destructors_for_temps.cpp:16:26:16:26 | Address | &:r16_1 |
|
||||
| destructors_for_temps.cpp:16:26:16:26 | Arg(this) | this:r16_1 |
|
||||
| destructors_for_temps.cpp:16:28:16:30 | Arg(0) | 0:r16_4 |
|
||||
| destructors_for_temps.cpp:16:28:16:63 | CallTarget | func:r16_3 |
|
||||
| destructors_for_temps.cpp:16:28:16:63 | ChiPartial | partial:m16_21 |
|
||||
| destructors_for_temps.cpp:16:28:16:63 | ChiPartial | partial:m16_23 |
|
||||
| destructors_for_temps.cpp:16:28:16:63 | ChiTotal | total:m16_2 |
|
||||
| destructors_for_temps.cpp:16:28:16:63 | ChiTotal | total:m16_16 |
|
||||
| destructors_for_temps.cpp:16:28:16:63 | SideEffect | ~m16_16 |
|
||||
| destructors_for_temps.cpp:16:33:16:54 | Address | &:r16_5 |
|
||||
| destructors_for_temps.cpp:16:33:16:54 | Address | &:r16_5 |
|
||||
| destructors_for_temps.cpp:16:33:16:54 | Address | &:r16_5 |
|
||||
| destructors_for_temps.cpp:16:33:16:54 | Address | &:r16_5 |
|
||||
| destructors_for_temps.cpp:16:33:16:54 | Arg(this) | this:r16_5 |
|
||||
| destructors_for_temps.cpp:16:33:16:54 | Arg(this) | this:r16_5 |
|
||||
| destructors_for_temps.cpp:16:33:16:54 | CallTarget | func:r16_7 |
|
||||
| destructors_for_temps.cpp:16:33:16:54 | ChiPartial | partial:m16_9 |
|
||||
| destructors_for_temps.cpp:16:33:16:54 | ChiPartial | partial:m16_11 |
|
||||
| destructors_for_temps.cpp:16:33:16:54 | ChiPartial | partial:m16_18 |
|
||||
| destructors_for_temps.cpp:16:33:16:54 | ChiTotal | total:m15_13 |
|
||||
| destructors_for_temps.cpp:16:33:16:54 | ChiTotal | total:m16_6 |
|
||||
| destructors_for_temps.cpp:16:33:16:54 | ChiTotal | total:m16_12 |
|
||||
| destructors_for_temps.cpp:16:33:16:54 | SideEffect | m16_12 |
|
||||
| destructors_for_temps.cpp:16:33:16:54 | SideEffect | ~m15_13 |
|
||||
| destructors_for_temps.cpp:16:56:16:60 | Arg(1) | 1:r16_14 |
|
||||
| destructors_for_temps.cpp:16:56:16:60 | CallTarget | func:r16_13 |
|
||||
| destructors_for_temps.cpp:16:56:16:60 | ChiPartial | partial:m16_15 |
|
||||
| destructors_for_temps.cpp:16:56:16:60 | ChiTotal | total:m16_10 |
|
||||
| destructors_for_temps.cpp:16:56:16:60 | SideEffect | ~m16_10 |
|
||||
| destructors_for_temps.cpp:17:5:17:42 | Address | &:r17_1 |
|
||||
| destructors_for_temps.cpp:17:12:17:33 | Address | &:r17_2 |
|
||||
| destructors_for_temps.cpp:17:12:17:33 | Address | &:r17_2 |
|
||||
| destructors_for_temps.cpp:17:12:17:33 | Address | &:r17_2 |
|
||||
| destructors_for_temps.cpp:17:12:17:33 | Address | &:r17_2 |
|
||||
| destructors_for_temps.cpp:17:12:17:33 | Arg(this) | this:r17_2 |
|
||||
| destructors_for_temps.cpp:17:12:17:33 | Arg(this) | this:r17_2 |
|
||||
| destructors_for_temps.cpp:17:12:17:33 | CallTarget | func:r17_4 |
|
||||
| destructors_for_temps.cpp:17:12:17:33 | ChiPartial | partial:m17_6 |
|
||||
| destructors_for_temps.cpp:17:12:17:33 | ChiPartial | partial:m17_8 |
|
||||
| destructors_for_temps.cpp:17:12:17:33 | ChiPartial | partial:m17_15 |
|
||||
| destructors_for_temps.cpp:17:12:17:33 | ChiTotal | total:m16_22 |
|
||||
| destructors_for_temps.cpp:17:12:17:33 | ChiTotal | total:m17_3 |
|
||||
| destructors_for_temps.cpp:17:12:17:33 | ChiTotal | total:m17_9 |
|
||||
| destructors_for_temps.cpp:17:12:17:33 | SideEffect | m17_9 |
|
||||
| destructors_for_temps.cpp:17:12:17:33 | SideEffect | ~m16_22 |
|
||||
| destructors_for_temps.cpp:17:35:17:39 | CallTarget | func:r17_10 |
|
||||
| destructors_for_temps.cpp:17:35:17:39 | ChiPartial | partial:m17_12 |
|
||||
| destructors_for_temps.cpp:17:35:17:39 | ChiTotal | total:m17_7 |
|
||||
| destructors_for_temps.cpp:17:35:17:39 | SideEffect | ~m17_7 |
|
||||
| destructors_for_temps.cpp:17:35:17:39 | StoreValue | r17_11 |
|
||||
| destructors_for_temps.cpp:21:6:21:15 | Address | &:r21_5 |
|
||||
| destructors_for_temps.cpp:21:6:21:15 | ChiPartial | partial:m21_3 |
|
||||
| destructors_for_temps.cpp:21:6:21:15 | ChiTotal | total:m21_2 |
|
||||
| destructors_for_temps.cpp:21:6:21:15 | Load | m23_36 |
|
||||
| destructors_for_temps.cpp:21:6:21:15 | SideEffect | ~m23_29 |
|
||||
| destructors_for_temps.cpp:22:5:22:30 | Address | &:r22_3 |
|
||||
| destructors_for_temps.cpp:22:5:22:30 | Address | &:r22_7 |
|
||||
| destructors_for_temps.cpp:22:5:22:30 | Arg(0) | 0:r22_2 |
|
||||
| destructors_for_temps.cpp:22:5:22:30 | Arg(this) | this:r22_7 |
|
||||
| destructors_for_temps.cpp:22:5:22:30 | CallTarget | func:r22_1 |
|
||||
| destructors_for_temps.cpp:22:5:22:30 | CallTarget | func:r22_8 |
|
||||
| destructors_for_temps.cpp:22:5:22:30 | ChiPartial | partial:m22_4 |
|
||||
| destructors_for_temps.cpp:22:5:22:30 | ChiPartial | partial:m22_10 |
|
||||
| destructors_for_temps.cpp:22:5:22:30 | ChiPartial | partial:m22_12 |
|
||||
| destructors_for_temps.cpp:22:5:22:30 | ChiTotal | total:m21_4 |
|
||||
| destructors_for_temps.cpp:22:5:22:30 | ChiTotal | total:m22_5 |
|
||||
| destructors_for_temps.cpp:22:5:22:30 | ChiTotal | total:m22_6 |
|
||||
| destructors_for_temps.cpp:22:5:22:30 | SideEffect | ~m21_4 |
|
||||
| destructors_for_temps.cpp:22:5:22:30 | SideEffect | ~m22_5 |
|
||||
| destructors_for_temps.cpp:22:5:22:30 | Unary | r22_3 |
|
||||
| destructors_for_temps.cpp:23:5:23:75 | Address | &:r23_1 |
|
||||
| destructors_for_temps.cpp:23:12:23:33 | Address | &:r23_2 |
|
||||
| destructors_for_temps.cpp:23:12:23:33 | Address | &:r23_2 |
|
||||
| destructors_for_temps.cpp:23:12:23:33 | Address | &:r23_2 |
|
||||
| destructors_for_temps.cpp:23:12:23:33 | Address | &:r23_2 |
|
||||
| destructors_for_temps.cpp:23:12:23:33 | Arg(this) | this:r23_2 |
|
||||
| destructors_for_temps.cpp:23:12:23:33 | Arg(this) | this:r23_2 |
|
||||
| destructors_for_temps.cpp:23:12:23:33 | CallTarget | func:r23_4 |
|
||||
| destructors_for_temps.cpp:23:12:23:33 | ChiPartial | partial:m23_6 |
|
||||
| destructors_for_temps.cpp:23:12:23:33 | ChiPartial | partial:m23_8 |
|
||||
| destructors_for_temps.cpp:23:12:23:33 | ChiPartial | partial:m23_15 |
|
||||
| destructors_for_temps.cpp:23:12:23:33 | ChiTotal | total:m22_11 |
|
||||
| destructors_for_temps.cpp:23:12:23:33 | ChiTotal | total:m23_3 |
|
||||
| destructors_for_temps.cpp:23:12:23:33 | ChiTotal | total:m23_9 |
|
||||
| destructors_for_temps.cpp:23:12:23:33 | SideEffect | m23_9 |
|
||||
| destructors_for_temps.cpp:23:12:23:33 | SideEffect | ~m22_11 |
|
||||
| destructors_for_temps.cpp:23:12:23:41 | Left | r23_17 |
|
||||
| destructors_for_temps.cpp:23:12:23:74 | StoreValue | r23_35 |
|
||||
| destructors_for_temps.cpp:23:12:23:74 | Unary | r23_34 |
|
||||
| destructors_for_temps.cpp:23:35:23:39 | CallTarget | func:r23_10 |
|
||||
| destructors_for_temps.cpp:23:35:23:39 | ChiPartial | partial:m23_12 |
|
||||
| destructors_for_temps.cpp:23:35:23:39 | ChiTotal | total:m23_7 |
|
||||
| destructors_for_temps.cpp:23:35:23:39 | SideEffect | ~m23_7 |
|
||||
| destructors_for_temps.cpp:23:35:23:39 | Unary | r23_11 |
|
||||
| destructors_for_temps.cpp:23:45:23:66 | Address | &:r23_18 |
|
||||
| destructors_for_temps.cpp:23:45:23:66 | Address | &:r23_18 |
|
||||
| destructors_for_temps.cpp:23:45:23:66 | Address | &:r23_18 |
|
||||
| destructors_for_temps.cpp:23:45:23:66 | Address | &:r23_18 |
|
||||
| destructors_for_temps.cpp:23:45:23:66 | Arg(this) | this:r23_18 |
|
||||
| destructors_for_temps.cpp:23:45:23:66 | Arg(this) | this:r23_18 |
|
||||
| destructors_for_temps.cpp:23:45:23:66 | CallTarget | func:r23_20 |
|
||||
| destructors_for_temps.cpp:23:45:23:66 | ChiPartial | partial:m23_22 |
|
||||
| destructors_for_temps.cpp:23:45:23:66 | ChiPartial | partial:m23_24 |
|
||||
| destructors_for_temps.cpp:23:45:23:66 | ChiPartial | partial:m23_31 |
|
||||
| destructors_for_temps.cpp:23:45:23:66 | ChiTotal | total:m23_13 |
|
||||
| destructors_for_temps.cpp:23:45:23:66 | ChiTotal | total:m23_19 |
|
||||
| destructors_for_temps.cpp:23:45:23:66 | ChiTotal | total:m23_25 |
|
||||
| destructors_for_temps.cpp:23:45:23:66 | SideEffect | m23_25 |
|
||||
| destructors_for_temps.cpp:23:45:23:66 | SideEffect | ~m23_13 |
|
||||
| destructors_for_temps.cpp:23:45:23:74 | Right | r23_33 |
|
||||
| destructors_for_temps.cpp:23:68:23:72 | CallTarget | func:r23_26 |
|
||||
| destructors_for_temps.cpp:23:68:23:72 | ChiPartial | partial:m23_28 |
|
||||
| destructors_for_temps.cpp:23:68:23:72 | ChiTotal | total:m23_23 |
|
||||
| destructors_for_temps.cpp:23:68:23:72 | SideEffect | ~m23_23 |
|
||||
| destructors_for_temps.cpp:23:68:23:72 | Unary | r23_27 |
|
||||
| destructors_for_temps.cpp:29:6:29:15 | ChiPartial | partial:m29_3 |
|
||||
| destructors_for_temps.cpp:29:6:29:15 | ChiTotal | total:m29_2 |
|
||||
| destructors_for_temps.cpp:29:6:29:15 | SideEffect | ~m30_6 |
|
||||
| destructors_for_temps.cpp:30:33:30:34 | Address | &:r30_1 |
|
||||
| destructors_for_temps.cpp:30:38:30:70 | CallTarget | func:r30_3 |
|
||||
| destructors_for_temps.cpp:30:38:30:70 | ChiPartial | partial:m30_5 |
|
||||
| destructors_for_temps.cpp:30:38:30:70 | ChiTotal | total:m29_4 |
|
||||
| destructors_for_temps.cpp:30:38:30:70 | SideEffect | ~m29_4 |
|
||||
| destructors_for_temps.cpp:30:38:30:70 | StoreValue | r30_4 |
|
||||
| destructors_for_temps.cpp:30:38:30:72 | Address | &:r30_2 |
|
||||
| destructors_for_temps.cpp:30:38:30:72 | StoreValue | r30_9 |
|
||||
| destructors_for_temps.cpp:30:38:30:72 | Unary | r30_2 |
|
||||
| destructors_for_temps.cpp:30:38:30:72 | Unary | r30_8 |
|
||||
| destructors_for_temps.cpp:33:6:33:15 | ChiPartial | partial:m33_3 |
|
||||
| destructors_for_temps.cpp:33:6:33:15 | ChiTotal | total:m33_2 |
|
||||
| destructors_for_temps.cpp:33:6:33:15 | SideEffect | ~m36_6 |
|
||||
| destructors_for_temps.cpp:34:26:34:26 | Address | &:r34_1 |
|
||||
| destructors_for_temps.cpp:34:26:34:26 | Address | &:r34_1 |
|
||||
| destructors_for_temps.cpp:34:26:34:26 | Arg(this) | this:r34_1 |
|
||||
| destructors_for_temps.cpp:34:26:34:26 | CallTarget | func:r34_3 |
|
||||
| destructors_for_temps.cpp:34:26:34:26 | ChiPartial | partial:m34_5 |
|
||||
| destructors_for_temps.cpp:34:26:34:26 | ChiPartial | partial:m34_7 |
|
||||
| destructors_for_temps.cpp:34:26:34:26 | ChiTotal | total:m33_4 |
|
||||
| destructors_for_temps.cpp:34:26:34:26 | ChiTotal | total:m34_2 |
|
||||
| destructors_for_temps.cpp:34:26:34:26 | SideEffect | ~m33_4 |
|
||||
| destructors_for_temps.cpp:35:33:35:35 | Address | &:r35_1 |
|
||||
| destructors_for_temps.cpp:35:39:35:71 | CallTarget | func:r35_3 |
|
||||
| destructors_for_temps.cpp:35:39:35:71 | ChiPartial | partial:m35_5 |
|
||||
| destructors_for_temps.cpp:35:39:35:71 | ChiTotal | total:m34_6 |
|
||||
| destructors_for_temps.cpp:35:39:35:71 | SideEffect | ~m34_6 |
|
||||
| destructors_for_temps.cpp:35:39:35:71 | StoreValue | r35_4 |
|
||||
| destructors_for_temps.cpp:35:39:35:73 | Address | &:r35_2 |
|
||||
| destructors_for_temps.cpp:35:39:35:73 | StoreValue | r35_9 |
|
||||
| destructors_for_temps.cpp:35:39:35:73 | Unary | r35_2 |
|
||||
| destructors_for_temps.cpp:35:39:35:73 | Unary | r35_8 |
|
||||
| destructors_for_temps.cpp:36:1:36:1 | Address | &:r36_2 |
|
||||
| destructors_for_temps.cpp:36:1:36:1 | Address | &:r36_2 |
|
||||
| destructors_for_temps.cpp:36:1:36:1 | Arg(this) | this:r36_2 |
|
||||
| destructors_for_temps.cpp:36:1:36:1 | CallTarget | func:r36_3 |
|
||||
| destructors_for_temps.cpp:36:1:36:1 | ChiPartial | partial:m36_5 |
|
||||
| destructors_for_temps.cpp:36:1:36:1 | ChiPartial | partial:m36_8 |
|
||||
| destructors_for_temps.cpp:36:1:36:1 | ChiTotal | total:m34_8 |
|
||||
| destructors_for_temps.cpp:36:1:36:1 | ChiTotal | total:m35_6 |
|
||||
| destructors_for_temps.cpp:36:1:36:1 | SideEffect | m34_8 |
|
||||
| destructors_for_temps.cpp:36:1:36:1 | SideEffect | ~m35_6 |
|
||||
| destructors_for_temps.cpp:38:6:38:15 | ChiPartial | partial:m38_3 |
|
||||
| destructors_for_temps.cpp:38:6:38:15 | ChiTotal | total:m38_2 |
|
||||
| destructors_for_temps.cpp:38:6:38:15 | SideEffect | ~m39_5 |
|
||||
| destructors_for_temps.cpp:38:22:38:22 | Address | &:r38_5 |
|
||||
| destructors_for_temps.cpp:39:3:39:3 | Address | &:r39_2 |
|
||||
| destructors_for_temps.cpp:39:3:39:3 | Address | &:r39_7 |
|
||||
| destructors_for_temps.cpp:39:3:39:3 | Address | &:r39_19 |
|
||||
| destructors_for_temps.cpp:39:3:39:3 | Address | &:r39_30 |
|
||||
| destructors_for_temps.cpp:39:3:39:3 | Condition | r39_3 |
|
||||
| destructors_for_temps.cpp:39:3:39:3 | Load | m38_6 |
|
||||
| destructors_for_temps.cpp:39:3:39:3 | Load | m39_6 |
|
||||
| destructors_for_temps.cpp:39:3:39:3 | Phi | from 2:m39_20 |
|
||||
| destructors_for_temps.cpp:39:3:39:3 | Phi | from 2:~m39_15 |
|
||||
| destructors_for_temps.cpp:39:3:39:3 | Phi | from 3:m39_31 |
|
||||
| destructors_for_temps.cpp:39:3:39:3 | Phi | from 3:~m39_26 |
|
||||
| destructors_for_temps.cpp:39:3:39:3 | StoreValue | r39_8 |
|
||||
| destructors_for_temps.cpp:39:3:39:53 | Address | &:r39_1 |
|
||||
| destructors_for_temps.cpp:39:7:39:28 | Address | &:r39_10 |
|
||||
| destructors_for_temps.cpp:39:7:39:28 | Address | &:r39_10 |
|
||||
| destructors_for_temps.cpp:39:7:39:28 | Address | &:r39_10 |
|
||||
| destructors_for_temps.cpp:39:7:39:28 | Arg(this) | this:r39_10 |
|
||||
| destructors_for_temps.cpp:39:7:39:28 | CallTarget | func:r39_12 |
|
||||
| destructors_for_temps.cpp:39:7:39:28 | ChiPartial | partial:m39_14 |
|
||||
| destructors_for_temps.cpp:39:7:39:28 | ChiPartial | partial:m39_16 |
|
||||
| destructors_for_temps.cpp:39:7:39:28 | ChiTotal | total:m38_4 |
|
||||
| destructors_for_temps.cpp:39:7:39:28 | ChiTotal | total:m39_11 |
|
||||
| destructors_for_temps.cpp:39:7:39:28 | Load | m39_17 |
|
||||
| destructors_for_temps.cpp:39:7:39:28 | SideEffect | ~m38_4 |
|
||||
| destructors_for_temps.cpp:39:7:39:28 | StoreValue | r39_18 |
|
||||
| destructors_for_temps.cpp:39:32:39:53 | Address | &:r39_21 |
|
||||
| destructors_for_temps.cpp:39:32:39:53 | Address | &:r39_21 |
|
||||
| destructors_for_temps.cpp:39:32:39:53 | Address | &:r39_21 |
|
||||
| destructors_for_temps.cpp:39:32:39:53 | Arg(this) | this:r39_21 |
|
||||
| destructors_for_temps.cpp:39:32:39:53 | CallTarget | func:r39_23 |
|
||||
| destructors_for_temps.cpp:39:32:39:53 | ChiPartial | partial:m39_25 |
|
||||
| destructors_for_temps.cpp:39:32:39:53 | ChiPartial | partial:m39_27 |
|
||||
| destructors_for_temps.cpp:39:32:39:53 | ChiTotal | total:m38_4 |
|
||||
| destructors_for_temps.cpp:39:32:39:53 | ChiTotal | total:m39_22 |
|
||||
| destructors_for_temps.cpp:39:32:39:53 | Load | m39_28 |
|
||||
| destructors_for_temps.cpp:39:32:39:53 | SideEffect | ~m38_4 |
|
||||
| destructors_for_temps.cpp:39:32:39:53 | StoreValue | r39_29 |
|
||||
| destructors_for_temps.cpp:42:6:42:15 | ChiPartial | partial:m42_3 |
|
||||
| destructors_for_temps.cpp:42:6:42:15 | ChiTotal | total:m42_2 |
|
||||
| destructors_for_temps.cpp:42:6:42:15 | Phi | from 2:~m45_22 |
|
||||
| destructors_for_temps.cpp:42:6:42:15 | Phi | from 4:~m47_6 |
|
||||
| destructors_for_temps.cpp:42:6:42:15 | SideEffect | ~m42_7 |
|
||||
| destructors_for_temps.cpp:42:22:42:22 | Address | &:r42_5 |
|
||||
| destructors_for_temps.cpp:43:26:43:26 | Address | &:r43_1 |
|
||||
| destructors_for_temps.cpp:43:26:43:26 | Address | &:r43_1 |
|
||||
| destructors_for_temps.cpp:43:26:43:26 | Arg(this) | this:r43_1 |
|
||||
| destructors_for_temps.cpp:43:26:43:26 | CallTarget | func:r43_3 |
|
||||
| destructors_for_temps.cpp:43:26:43:26 | ChiPartial | partial:m43_5 |
|
||||
| destructors_for_temps.cpp:43:26:43:26 | ChiPartial | partial:m43_7 |
|
||||
| destructors_for_temps.cpp:43:26:43:26 | ChiTotal | total:m42_4 |
|
||||
| destructors_for_temps.cpp:43:26:43:26 | ChiTotal | total:m43_2 |
|
||||
| destructors_for_temps.cpp:43:26:43:26 | SideEffect | ~m42_4 |
|
||||
| destructors_for_temps.cpp:44:9:44:9 | Address | &:r44_1 |
|
||||
| destructors_for_temps.cpp:44:9:44:9 | Condition | r44_2 |
|
||||
| destructors_for_temps.cpp:44:9:44:9 | Load | m42_6 |
|
||||
| destructors_for_temps.cpp:45:7:45:69 | Address | &:r45_1 |
|
||||
| destructors_for_temps.cpp:45:7:45:69 | Address | &:r45_1 |
|
||||
| destructors_for_temps.cpp:45:7:45:69 | Address | &:r45_1 |
|
||||
| destructors_for_temps.cpp:45:7:45:69 | Arg(this) | this:r45_1 |
|
||||
| destructors_for_temps.cpp:45:7:45:69 | CallTarget | func:r45_3 |
|
||||
| destructors_for_temps.cpp:45:7:45:69 | ChiPartial | partial:m45_21 |
|
||||
| destructors_for_temps.cpp:45:7:45:69 | ChiPartial | partial:m45_23 |
|
||||
| destructors_for_temps.cpp:45:7:45:69 | ChiTotal | total:m45_2 |
|
||||
| destructors_for_temps.cpp:45:7:45:69 | ChiTotal | total:m45_16 |
|
||||
| destructors_for_temps.cpp:45:7:45:69 | Load | m45_24 |
|
||||
| destructors_for_temps.cpp:45:7:45:69 | SideEffect | ~m45_16 |
|
||||
| destructors_for_temps.cpp:45:34:45:36 | Arg(0) | 0:r45_4 |
|
||||
| destructors_for_temps.cpp:45:39:45:60 | Address | &:r45_5 |
|
||||
| destructors_for_temps.cpp:45:39:45:60 | Address | &:r45_5 |
|
||||
| destructors_for_temps.cpp:45:39:45:60 | Address | &:r45_5 |
|
||||
| destructors_for_temps.cpp:45:39:45:60 | Address | &:r45_5 |
|
||||
| destructors_for_temps.cpp:45:39:45:60 | Arg(this) | this:r45_5 |
|
||||
| destructors_for_temps.cpp:45:39:45:60 | Arg(this) | this:r45_5 |
|
||||
| destructors_for_temps.cpp:45:39:45:60 | CallTarget | func:r45_7 |
|
||||
| destructors_for_temps.cpp:45:39:45:60 | ChiPartial | partial:m45_9 |
|
||||
| destructors_for_temps.cpp:45:39:45:60 | ChiPartial | partial:m45_11 |
|
||||
| destructors_for_temps.cpp:45:39:45:60 | ChiPartial | partial:m45_18 |
|
||||
| destructors_for_temps.cpp:45:39:45:60 | ChiTotal | total:m43_6 |
|
||||
| destructors_for_temps.cpp:45:39:45:60 | ChiTotal | total:m45_6 |
|
||||
| destructors_for_temps.cpp:45:39:45:60 | ChiTotal | total:m45_12 |
|
||||
| destructors_for_temps.cpp:45:39:45:60 | SideEffect | m45_12 |
|
||||
| destructors_for_temps.cpp:45:39:45:60 | SideEffect | ~m43_6 |
|
||||
| destructors_for_temps.cpp:45:62:45:66 | Arg(1) | 1:r45_14 |
|
||||
| destructors_for_temps.cpp:45:62:45:66 | CallTarget | func:r45_13 |
|
||||
| destructors_for_temps.cpp:45:62:45:66 | ChiPartial | partial:m45_15 |
|
||||
| destructors_for_temps.cpp:45:62:45:66 | ChiTotal | total:m45_10 |
|
||||
| destructors_for_temps.cpp:45:62:45:66 | SideEffect | ~m45_10 |
|
||||
| destructors_for_temps.cpp:47:1:47:1 | Address | &:r47_2 |
|
||||
| destructors_for_temps.cpp:47:1:47:1 | Address | &:r47_2 |
|
||||
| destructors_for_temps.cpp:47:1:47:1 | Arg(this) | this:r47_2 |
|
||||
| destructors_for_temps.cpp:47:1:47:1 | CallTarget | func:r47_3 |
|
||||
| destructors_for_temps.cpp:47:1:47:1 | ChiPartial | partial:m47_5 |
|
||||
| destructors_for_temps.cpp:47:1:47:1 | ChiPartial | partial:m47_8 |
|
||||
| destructors_for_temps.cpp:47:1:47:1 | ChiTotal | total:m43_6 |
|
||||
| destructors_for_temps.cpp:47:1:47:1 | ChiTotal | total:m43_8 |
|
||||
| destructors_for_temps.cpp:47:1:47:1 | SideEffect | m43_8 |
|
||||
| destructors_for_temps.cpp:47:1:47:1 | SideEffect | ~m43_6 |
|
||||
| destructors_for_temps.cpp:49:6:49:15 | ChiPartial | partial:m49_3 |
|
||||
| destructors_for_temps.cpp:49:6:49:15 | ChiTotal | total:m49_2 |
|
||||
| destructors_for_temps.cpp:49:6:49:15 | Phi | from 2:~m51_26 |
|
||||
| destructors_for_temps.cpp:49:6:49:15 | Phi | from 4:~m52_6 |
|
||||
| destructors_for_temps.cpp:49:6:49:15 | SideEffect | ~m49_7 |
|
||||
| destructors_for_temps.cpp:49:22:49:22 | Address | &:r49_5 |
|
||||
| destructors_for_temps.cpp:50:26:50:26 | Address | &:r50_1 |
|
||||
| destructors_for_temps.cpp:50:26:50:26 | Address | &:r50_1 |
|
||||
| destructors_for_temps.cpp:50:26:50:26 | Arg(this) | this:r50_1 |
|
||||
| destructors_for_temps.cpp:50:26:50:26 | CallTarget | func:r50_3 |
|
||||
| destructors_for_temps.cpp:50:26:50:26 | ChiPartial | partial:m50_5 |
|
||||
| destructors_for_temps.cpp:50:26:50:26 | ChiPartial | partial:m50_7 |
|
||||
| destructors_for_temps.cpp:50:26:50:26 | ChiTotal | total:m49_4 |
|
||||
| destructors_for_temps.cpp:50:26:50:26 | ChiTotal | total:m50_2 |
|
||||
| destructors_for_temps.cpp:50:26:50:26 | SideEffect | ~m49_4 |
|
||||
| destructors_for_temps.cpp:51:5:51:5 | Address | &:r51_2 |
|
||||
| destructors_for_temps.cpp:51:5:51:5 | Address | &:r51_39 |
|
||||
| destructors_for_temps.cpp:51:5:51:5 | Address | &:r51_41 |
|
||||
| destructors_for_temps.cpp:51:5:51:5 | Condition | r51_3 |
|
||||
| destructors_for_temps.cpp:51:5:51:5 | Load | m49_6 |
|
||||
| destructors_for_temps.cpp:51:5:51:5 | Load | m51_40 |
|
||||
| destructors_for_temps.cpp:51:5:51:5 | StoreValue | r51_42 |
|
||||
| destructors_for_temps.cpp:51:5:51:96 | Address | &:r51_1 |
|
||||
| destructors_for_temps.cpp:51:9:51:71 | Address | &:r51_5 |
|
||||
| destructors_for_temps.cpp:51:9:51:71 | Address | &:r51_5 |
|
||||
| destructors_for_temps.cpp:51:9:51:71 | Address | &:r51_5 |
|
||||
| destructors_for_temps.cpp:51:9:51:71 | Arg(this) | this:r51_5 |
|
||||
| destructors_for_temps.cpp:51:9:51:71 | CallTarget | func:r51_7 |
|
||||
| destructors_for_temps.cpp:51:9:51:71 | ChiPartial | partial:m51_25 |
|
||||
| destructors_for_temps.cpp:51:9:51:71 | ChiPartial | partial:m51_27 |
|
||||
| destructors_for_temps.cpp:51:9:51:71 | ChiTotal | total:m51_6 |
|
||||
| destructors_for_temps.cpp:51:9:51:71 | ChiTotal | total:m51_20 |
|
||||
| destructors_for_temps.cpp:51:9:51:71 | Load | m51_28 |
|
||||
| destructors_for_temps.cpp:51:9:51:71 | SideEffect | ~m51_20 |
|
||||
| destructors_for_temps.cpp:51:36:51:38 | Arg(0) | 0:r51_8 |
|
||||
| destructors_for_temps.cpp:51:41:51:62 | Address | &:r51_9 |
|
||||
| destructors_for_temps.cpp:51:41:51:62 | Address | &:r51_9 |
|
||||
| destructors_for_temps.cpp:51:41:51:62 | Address | &:r51_9 |
|
||||
| destructors_for_temps.cpp:51:41:51:62 | Address | &:r51_9 |
|
||||
| destructors_for_temps.cpp:51:41:51:62 | Arg(this) | this:r51_9 |
|
||||
| destructors_for_temps.cpp:51:41:51:62 | Arg(this) | this:r51_9 |
|
||||
| destructors_for_temps.cpp:51:41:51:62 | CallTarget | func:r51_11 |
|
||||
| destructors_for_temps.cpp:51:41:51:62 | ChiPartial | partial:m51_13 |
|
||||
| destructors_for_temps.cpp:51:41:51:62 | ChiPartial | partial:m51_15 |
|
||||
| destructors_for_temps.cpp:51:41:51:62 | ChiPartial | partial:m51_22 |
|
||||
| destructors_for_temps.cpp:51:41:51:62 | ChiTotal | total:m50_6 |
|
||||
| destructors_for_temps.cpp:51:41:51:62 | ChiTotal | total:m51_10 |
|
||||
| destructors_for_temps.cpp:51:41:51:62 | ChiTotal | total:m51_16 |
|
||||
| destructors_for_temps.cpp:51:41:51:62 | SideEffect | m51_16 |
|
||||
| destructors_for_temps.cpp:51:41:51:62 | SideEffect | ~m50_6 |
|
||||
| destructors_for_temps.cpp:51:64:51:68 | Arg(1) | 1:r51_18 |
|
||||
| destructors_for_temps.cpp:51:64:51:68 | CallTarget | func:r51_17 |
|
||||
| destructors_for_temps.cpp:51:64:51:68 | ChiPartial | partial:m51_19 |
|
||||
| destructors_for_temps.cpp:51:64:51:68 | ChiTotal | total:m51_14 |
|
||||
| destructors_for_temps.cpp:51:64:51:68 | SideEffect | ~m51_14 |
|
||||
| destructors_for_temps.cpp:51:75:51:96 | Address | &:r51_30 |
|
||||
| destructors_for_temps.cpp:51:75:51:96 | Address | &:r51_30 |
|
||||
| destructors_for_temps.cpp:51:75:51:96 | Address | &:r51_30 |
|
||||
| destructors_for_temps.cpp:51:75:51:96 | Arg(this) | this:r51_30 |
|
||||
| destructors_for_temps.cpp:51:75:51:96 | CallTarget | func:r51_32 |
|
||||
| destructors_for_temps.cpp:51:75:51:96 | ChiPartial | partial:m51_34 |
|
||||
| destructors_for_temps.cpp:51:75:51:96 | ChiPartial | partial:m51_36 |
|
||||
| destructors_for_temps.cpp:51:75:51:96 | ChiTotal | total:m50_6 |
|
||||
| destructors_for_temps.cpp:51:75:51:96 | ChiTotal | total:m51_31 |
|
||||
| destructors_for_temps.cpp:51:75:51:96 | Load | m51_37 |
|
||||
| destructors_for_temps.cpp:51:75:51:96 | SideEffect | ~m50_6 |
|
||||
| destructors_for_temps.cpp:51:75:51:96 | StoreValue | r51_38 |
|
||||
| destructors_for_temps.cpp:52:1:52:1 | Address | &:r52_2 |
|
||||
| destructors_for_temps.cpp:52:1:52:1 | Address | &:r52_2 |
|
||||
| destructors_for_temps.cpp:52:1:52:1 | Arg(this) | this:r52_2 |
|
||||
| destructors_for_temps.cpp:52:1:52:1 | CallTarget | func:r52_3 |
|
||||
| destructors_for_temps.cpp:52:1:52:1 | ChiPartial | partial:m52_5 |
|
||||
| destructors_for_temps.cpp:52:1:52:1 | ChiPartial | partial:m52_8 |
|
||||
| destructors_for_temps.cpp:52:1:52:1 | ChiTotal | total:m50_8 |
|
||||
| destructors_for_temps.cpp:52:1:52:1 | ChiTotal | total:m51_35 |
|
||||
| destructors_for_temps.cpp:52:1:52:1 | SideEffect | m50_8 |
|
||||
| destructors_for_temps.cpp:52:1:52:1 | SideEffect | ~m51_35 |
|
||||
| destructors_for_temps.cpp:54:6:54:15 | ChiPartial | partial:m54_3 |
|
||||
| destructors_for_temps.cpp:54:6:54:15 | ChiTotal | total:m54_2 |
|
||||
| destructors_for_temps.cpp:54:6:54:15 | Phi | from 2:~m55_26 |
|
||||
| destructors_for_temps.cpp:54:6:54:15 | Phi | from 4:~m55_35 |
|
||||
| destructors_for_temps.cpp:54:6:54:15 | SideEffect | ~m54_7 |
|
||||
| destructors_for_temps.cpp:54:22:54:22 | Address | &:r54_5 |
|
||||
| destructors_for_temps.cpp:55:5:55:5 | Address | &:r55_2 |
|
||||
| destructors_for_temps.cpp:55:5:55:5 | Address | &:r55_39 |
|
||||
| destructors_for_temps.cpp:55:5:55:5 | Address | &:r55_41 |
|
||||
| destructors_for_temps.cpp:55:5:55:5 | Condition | r55_3 |
|
||||
| destructors_for_temps.cpp:55:5:55:5 | Load | m54_6 |
|
||||
| destructors_for_temps.cpp:55:5:55:5 | Load | m55_40 |
|
||||
| destructors_for_temps.cpp:55:5:55:5 | StoreValue | r55_42 |
|
||||
| destructors_for_temps.cpp:55:5:55:96 | Address | &:r55_1 |
|
||||
| destructors_for_temps.cpp:55:9:55:71 | Address | &:r55_5 |
|
||||
| destructors_for_temps.cpp:55:9:55:71 | Address | &:r55_5 |
|
||||
| destructors_for_temps.cpp:55:9:55:71 | Address | &:r55_5 |
|
||||
| destructors_for_temps.cpp:55:9:55:71 | Arg(this) | this:r55_5 |
|
||||
| destructors_for_temps.cpp:55:9:55:71 | CallTarget | func:r55_7 |
|
||||
| destructors_for_temps.cpp:55:9:55:71 | ChiPartial | partial:m55_25 |
|
||||
| destructors_for_temps.cpp:55:9:55:71 | ChiPartial | partial:m55_27 |
|
||||
| destructors_for_temps.cpp:55:9:55:71 | ChiTotal | total:m55_6 |
|
||||
| destructors_for_temps.cpp:55:9:55:71 | ChiTotal | total:m55_20 |
|
||||
| destructors_for_temps.cpp:55:9:55:71 | Load | m55_28 |
|
||||
| destructors_for_temps.cpp:55:9:55:71 | SideEffect | ~m55_20 |
|
||||
| destructors_for_temps.cpp:55:36:55:38 | Arg(0) | 0:r55_8 |
|
||||
| destructors_for_temps.cpp:55:41:55:62 | Address | &:r55_9 |
|
||||
| destructors_for_temps.cpp:55:41:55:62 | Address | &:r55_9 |
|
||||
| destructors_for_temps.cpp:55:41:55:62 | Address | &:r55_9 |
|
||||
| destructors_for_temps.cpp:55:41:55:62 | Address | &:r55_9 |
|
||||
| destructors_for_temps.cpp:55:41:55:62 | Arg(this) | this:r55_9 |
|
||||
| destructors_for_temps.cpp:55:41:55:62 | Arg(this) | this:r55_9 |
|
||||
| destructors_for_temps.cpp:55:41:55:62 | CallTarget | func:r55_11 |
|
||||
| destructors_for_temps.cpp:55:41:55:62 | ChiPartial | partial:m55_13 |
|
||||
| destructors_for_temps.cpp:55:41:55:62 | ChiPartial | partial:m55_15 |
|
||||
| destructors_for_temps.cpp:55:41:55:62 | ChiPartial | partial:m55_22 |
|
||||
| destructors_for_temps.cpp:55:41:55:62 | ChiTotal | total:m54_4 |
|
||||
| destructors_for_temps.cpp:55:41:55:62 | ChiTotal | total:m55_10 |
|
||||
| destructors_for_temps.cpp:55:41:55:62 | ChiTotal | total:m55_16 |
|
||||
| destructors_for_temps.cpp:55:41:55:62 | SideEffect | m55_16 |
|
||||
| destructors_for_temps.cpp:55:41:55:62 | SideEffect | ~m54_4 |
|
||||
| destructors_for_temps.cpp:55:64:55:68 | Arg(1) | 1:r55_18 |
|
||||
| destructors_for_temps.cpp:55:64:55:68 | CallTarget | func:r55_17 |
|
||||
| destructors_for_temps.cpp:55:64:55:68 | ChiPartial | partial:m55_19 |
|
||||
| destructors_for_temps.cpp:55:64:55:68 | ChiTotal | total:m55_14 |
|
||||
| destructors_for_temps.cpp:55:64:55:68 | SideEffect | ~m55_14 |
|
||||
| destructors_for_temps.cpp:55:75:55:96 | Address | &:r55_30 |
|
||||
| destructors_for_temps.cpp:55:75:55:96 | Address | &:r55_30 |
|
||||
| destructors_for_temps.cpp:55:75:55:96 | Address | &:r55_30 |
|
||||
| destructors_for_temps.cpp:55:75:55:96 | Arg(this) | this:r55_30 |
|
||||
| destructors_for_temps.cpp:55:75:55:96 | CallTarget | func:r55_32 |
|
||||
| destructors_for_temps.cpp:55:75:55:96 | ChiPartial | partial:m55_34 |
|
||||
| destructors_for_temps.cpp:55:75:55:96 | ChiPartial | partial:m55_36 |
|
||||
| destructors_for_temps.cpp:55:75:55:96 | ChiTotal | total:m54_4 |
|
||||
| destructors_for_temps.cpp:55:75:55:96 | ChiTotal | total:m55_31 |
|
||||
| destructors_for_temps.cpp:55:75:55:96 | Load | m55_37 |
|
||||
| destructors_for_temps.cpp:55:75:55:96 | SideEffect | ~m54_4 |
|
||||
| destructors_for_temps.cpp:55:75:55:96 | StoreValue | r55_38 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
@@ -726,6 +1160,8 @@
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_4 |
|
||||
| file://:0:0:0:0 | Address | &:r0_4 |
|
||||
| file://:0:0:0:0 | Address | &:r0_5 |
|
||||
@@ -861,6 +1297,7 @@
|
||||
| file://:0:0:0:0 | Load | m0_2 |
|
||||
| file://:0:0:0:0 | Load | m0_2 |
|
||||
| file://:0:0:0:0 | Load | m0_2 |
|
||||
| file://:0:0:0:0 | Load | m0_2 |
|
||||
| file://:0:0:0:0 | Load | m0_5 |
|
||||
| file://:0:0:0:0 | Load | m0_8 |
|
||||
| file://:0:0:0:0 | Load | m0_11 |
|
||||
@@ -900,6 +1337,7 @@
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_14 |
|
||||
| file://:0:0:0:0 | SideEffect | m1080_23 |
|
||||
| file://:0:0:0:0 | SideEffect | m1080_23 |
|
||||
|
||||
@@ -724,6 +724,420 @@ complex.c:
|
||||
# 58| v58_5(void) = AliasedUse : ~m?
|
||||
# 58| v58_6(void) = ExitFunction :
|
||||
|
||||
destructors_for_temps.cpp:
|
||||
# 9| void ClassWithConstructor::ClassWithConstructor(ClassWithConstructor&&)
|
||||
# 9| Block 0
|
||||
# 9| v9_1(void) = EnterFunction :
|
||||
# 9| mu9_2(unknown) = AliasedDefinition :
|
||||
# 9| mu9_3(unknown) = InitializeNonLocal :
|
||||
# 9| r9_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 9| mu9_5(glval<ClassWithConstructor>) = InitializeParameter[#this] : &:r9_4
|
||||
# 9| r9_6(glval<ClassWithConstructor>) = Load[#this] : &:r9_4, ~m?
|
||||
# 9| mu9_7(ClassWithConstructor) = InitializeIndirection[#this] : &:r9_6
|
||||
#-----| r0_1(glval<ClassWithConstructor &&>) = VariableAddress[(unnamed parameter 0)] :
|
||||
#-----| mu0_2(ClassWithConstructor &&) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
|
||||
#-----| r0_3(ClassWithConstructor &&) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
|
||||
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
|
||||
# 9| v9_8(void) = NoOp :
|
||||
# 9| v9_9(void) = ReturnIndirection[#this] : &:r9_6, ~m?
|
||||
#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
|
||||
# 9| v9_10(void) = ReturnVoid :
|
||||
# 9| v9_11(void) = AliasedUse : ~m?
|
||||
# 9| v9_12(void) = ExitFunction :
|
||||
|
||||
# 14| char temp_test()
|
||||
# 14| Block 0
|
||||
# 14| v14_1(void) = EnterFunction :
|
||||
# 14| mu14_2(unknown) = AliasedDefinition :
|
||||
# 14| mu14_3(unknown) = InitializeNonLocal :
|
||||
# 15| r15_1(glval<char>) = VariableAddress[x] :
|
||||
# 15| r15_2(glval<ClassWithDestructor2>) = VariableAddress[#temp15:14] :
|
||||
# 15| mu15_3(ClassWithDestructor2) = Uninitialized[#temp15:14] : &:r15_2
|
||||
# 15| r15_4(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 15| v15_5(void) = Call[ClassWithDestructor2] : func:r15_4, this:r15_2
|
||||
# 15| mu15_6(unknown) = ^CallSideEffect : ~m?
|
||||
# 15| mu15_7(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r15_2
|
||||
# 15| r15_8(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 15| r15_9(char) = Call[get_x] : func:r15_8, this:r15_2
|
||||
# 15| mu15_10(unknown) = ^CallSideEffect : ~m?
|
||||
# 15| v15_11(void) = ^IndirectReadSideEffect[-1] : &:r15_2, ~m?
|
||||
# 15| mu15_12(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r15_2
|
||||
# 15| mu15_13(char) = Store[x] : &:r15_1, r15_9
|
||||
# 16| r16_1(glval<ClassWithConstructor>) = VariableAddress[y] :
|
||||
# 16| mu16_2(ClassWithConstructor) = Uninitialized[y] : &:r16_1
|
||||
# 16| r16_3(glval<unknown>) = FunctionAddress[ClassWithConstructor] :
|
||||
# 16| r16_4(char) = Constant[97] :
|
||||
# 16| r16_5(glval<ClassWithDestructor2>) = VariableAddress[#temp16:33] :
|
||||
# 16| mu16_6(ClassWithDestructor2) = Uninitialized[#temp16:33] : &:r16_5
|
||||
# 16| r16_7(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 16| v16_8(void) = Call[ClassWithDestructor2] : func:r16_7, this:r16_5
|
||||
# 16| mu16_9(unknown) = ^CallSideEffect : ~m?
|
||||
# 16| mu16_10(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r16_5
|
||||
# 16| r16_11(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 16| r16_12(char) = Call[get_x] : func:r16_11, this:r16_5
|
||||
# 16| mu16_13(unknown) = ^CallSideEffect : ~m?
|
||||
# 16| v16_14(void) = ^IndirectReadSideEffect[-1] : &:r16_5, ~m?
|
||||
# 16| mu16_15(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r16_5
|
||||
# 16| v16_16(void) = Call[ClassWithConstructor] : func:r16_3, this:r16_1, 0:r16_4, 1:r16_12
|
||||
# 16| mu16_17(unknown) = ^CallSideEffect : ~m?
|
||||
# 16| mu16_18(ClassWithConstructor) = ^IndirectMayWriteSideEffect[-1] : &:r16_1
|
||||
# 17| r17_1(glval<char>) = VariableAddress[#return] :
|
||||
# 17| r17_2(glval<ClassWithDestructor2>) = VariableAddress[#temp17:12] :
|
||||
# 17| mu17_3(ClassWithDestructor2) = Uninitialized[#temp17:12] : &:r17_2
|
||||
# 17| r17_4(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 17| v17_5(void) = Call[ClassWithDestructor2] : func:r17_4, this:r17_2
|
||||
# 17| mu17_6(unknown) = ^CallSideEffect : ~m?
|
||||
# 17| mu17_7(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r17_2
|
||||
# 17| r17_8(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 17| r17_9(char) = Call[get_x] : func:r17_8, this:r17_2
|
||||
# 17| mu17_10(unknown) = ^CallSideEffect : ~m?
|
||||
# 17| v17_11(void) = ^IndirectReadSideEffect[-1] : &:r17_2, ~m?
|
||||
# 17| mu17_12(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r17_2
|
||||
# 17| mu17_13(char) = Store[#return] : &:r17_1, r17_9
|
||||
# 14| r14_4(glval<char>) = VariableAddress[#return] :
|
||||
# 14| v14_5(void) = ReturnValue : &:r14_4, ~m?
|
||||
# 14| v14_6(void) = AliasedUse : ~m?
|
||||
# 14| v14_7(void) = ExitFunction :
|
||||
|
||||
# 21| char temp_test2()
|
||||
# 21| Block 0
|
||||
# 21| v21_1(void) = EnterFunction :
|
||||
# 21| mu21_2(unknown) = AliasedDefinition :
|
||||
# 21| mu21_3(unknown) = InitializeNonLocal :
|
||||
# 22| r22_1(glval<unknown>) = FunctionAddress[operator new] :
|
||||
# 22| r22_2(unsigned long) = Constant[1] :
|
||||
# 22| r22_3(void *) = Call[operator new] : func:r22_1, 0:r22_2
|
||||
# 22| mu22_4(unknown) = ^CallSideEffect : ~m?
|
||||
# 22| mu22_5(unknown) = ^InitializeDynamicAllocation : &:r22_3
|
||||
# 22| r22_6(ClassWithDestructor2 *) = Convert : r22_3
|
||||
# 22| r22_7(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 22| v22_8(void) = Call[ClassWithDestructor2] : func:r22_7, this:r22_6
|
||||
# 22| mu22_9(unknown) = ^CallSideEffect : ~m?
|
||||
# 22| mu22_10(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r22_6
|
||||
# 23| r23_1(glval<char>) = VariableAddress[#return] :
|
||||
# 23| r23_2(glval<ClassWithDestructor2>) = VariableAddress[#temp23:12] :
|
||||
# 23| mu23_3(ClassWithDestructor2) = Uninitialized[#temp23:12] : &:r23_2
|
||||
# 23| r23_4(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 23| v23_5(void) = Call[ClassWithDestructor2] : func:r23_4, this:r23_2
|
||||
# 23| mu23_6(unknown) = ^CallSideEffect : ~m?
|
||||
# 23| mu23_7(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r23_2
|
||||
# 23| r23_8(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 23| r23_9(char) = Call[get_x] : func:r23_8, this:r23_2
|
||||
# 23| mu23_10(unknown) = ^CallSideEffect : ~m?
|
||||
# 23| v23_11(void) = ^IndirectReadSideEffect[-1] : &:r23_2, ~m?
|
||||
# 23| mu23_12(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r23_2
|
||||
# 23| r23_13(int) = Convert : r23_9
|
||||
# 23| r23_14(glval<ClassWithDestructor2>) = VariableAddress[#temp23:45] :
|
||||
# 23| mu23_15(ClassWithDestructor2) = Uninitialized[#temp23:45] : &:r23_14
|
||||
# 23| r23_16(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 23| v23_17(void) = Call[ClassWithDestructor2] : func:r23_16, this:r23_14
|
||||
# 23| mu23_18(unknown) = ^CallSideEffect : ~m?
|
||||
# 23| mu23_19(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r23_14
|
||||
# 23| r23_20(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 23| r23_21(char) = Call[get_x] : func:r23_20, this:r23_14
|
||||
# 23| mu23_22(unknown) = ^CallSideEffect : ~m?
|
||||
# 23| v23_23(void) = ^IndirectReadSideEffect[-1] : &:r23_14, ~m?
|
||||
# 23| mu23_24(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r23_14
|
||||
# 23| r23_25(int) = Convert : r23_21
|
||||
# 23| r23_26(int) = Add : r23_13, r23_25
|
||||
# 23| r23_27(char) = Convert : r23_26
|
||||
# 23| mu23_28(char) = Store[#return] : &:r23_1, r23_27
|
||||
# 21| r21_4(glval<char>) = VariableAddress[#return] :
|
||||
# 21| v21_5(void) = ReturnValue : &:r21_4, ~m?
|
||||
# 21| v21_6(void) = AliasedUse : ~m?
|
||||
# 21| v21_7(void) = ExitFunction :
|
||||
|
||||
# 29| void temp_test3()
|
||||
# 29| Block 0
|
||||
# 29| v29_1(void) = EnterFunction :
|
||||
# 29| mu29_2(unknown) = AliasedDefinition :
|
||||
# 29| mu29_3(unknown) = InitializeNonLocal :
|
||||
# 30| r30_1(glval<ClassWithDestructor2 &>) = VariableAddress[rs] :
|
||||
# 30| r30_2(glval<ClassWithDestructor2>) = VariableAddress[#temp30:38] :
|
||||
# 30| r30_3(glval<unknown>) = FunctionAddress[returnValue] :
|
||||
# 30| r30_4(ClassWithDestructor2) = Call[returnValue] : func:r30_3
|
||||
# 30| mu30_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 30| mu30_6(ClassWithDestructor2) = Store[#temp30:38] : &:r30_2, r30_4
|
||||
# 30| r30_7(glval<ClassWithDestructor2>) = Convert : r30_2
|
||||
# 30| r30_8(ClassWithDestructor2 &) = CopyValue : r30_7
|
||||
# 30| mu30_9(ClassWithDestructor2 &) = Store[rs] : &:r30_1, r30_8
|
||||
# 31| v31_1(void) = NoOp :
|
||||
# 29| v29_4(void) = ReturnVoid :
|
||||
# 29| v29_5(void) = AliasedUse : ~m?
|
||||
# 29| v29_6(void) = ExitFunction :
|
||||
|
||||
# 33| void temp_test4()
|
||||
# 33| Block 0
|
||||
# 33| v33_1(void) = EnterFunction :
|
||||
# 33| mu33_2(unknown) = AliasedDefinition :
|
||||
# 33| mu33_3(unknown) = InitializeNonLocal :
|
||||
# 34| r34_1(glval<ClassWithDestructor2>) = VariableAddress[c] :
|
||||
# 34| mu34_2(ClassWithDestructor2) = Uninitialized[c] : &:r34_1
|
||||
# 34| r34_3(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 34| v34_4(void) = Call[ClassWithDestructor2] : func:r34_3, this:r34_1
|
||||
# 34| mu34_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 34| mu34_6(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r34_1
|
||||
# 35| r35_1(glval<ClassWithDestructor2 &>) = VariableAddress[rs2] :
|
||||
# 35| r35_2(glval<ClassWithDestructor2>) = VariableAddress[#temp35:39] :
|
||||
# 35| r35_3(glval<unknown>) = FunctionAddress[returnValue] :
|
||||
# 35| r35_4(ClassWithDestructor2) = Call[returnValue] : func:r35_3
|
||||
# 35| mu35_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 35| mu35_6(ClassWithDestructor2) = Store[#temp35:39] : &:r35_2, r35_4
|
||||
# 35| r35_7(glval<ClassWithDestructor2>) = Convert : r35_2
|
||||
# 35| r35_8(ClassWithDestructor2 &) = CopyValue : r35_7
|
||||
# 35| mu35_9(ClassWithDestructor2 &) = Store[rs2] : &:r35_1, r35_8
|
||||
# 36| v36_1(void) = NoOp :
|
||||
# 36| r36_2(glval<ClassWithDestructor2>) = VariableAddress[c] :
|
||||
# 36| r36_3(glval<unknown>) = FunctionAddress[~ClassWithDestructor2] :
|
||||
# 36| v36_4(void) = Call[~ClassWithDestructor2] : func:r36_3, this:r36_2
|
||||
# 36| mu36_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 36| v36_6(void) = ^IndirectReadSideEffect[-1] : &:r36_2, ~m?
|
||||
# 36| mu36_7(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r36_2
|
||||
# 33| v33_4(void) = ReturnVoid :
|
||||
# 33| v33_5(void) = AliasedUse : ~m?
|
||||
# 33| v33_6(void) = ExitFunction :
|
||||
|
||||
# 38| void temp_test5(bool)
|
||||
# 38| Block 0
|
||||
# 38| v38_1(void) = EnterFunction :
|
||||
# 38| mu38_2(unknown) = AliasedDefinition :
|
||||
# 38| mu38_3(unknown) = InitializeNonLocal :
|
||||
# 38| r38_4(glval<bool>) = VariableAddress[b] :
|
||||
# 38| mu38_5(bool) = InitializeParameter[b] : &:r38_4
|
||||
# 39| r39_1(glval<ClassWithDestructor2>) = VariableAddress[#temp39:3] :
|
||||
# 39| r39_2(glval<bool>) = VariableAddress[b] :
|
||||
# 39| r39_3(bool) = Load[b] : &:r39_2, ~m?
|
||||
# 39| v39_4(void) = ConditionalBranch : r39_3
|
||||
#-----| False -> Block 3
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 39| Block 1
|
||||
# 39| r39_5(glval<ClassWithDestructor2>) = VariableAddress[#temp39:3] :
|
||||
# 39| r39_6(ClassWithDestructor2) = Load[#temp39:3] : &:r39_5, ~m?
|
||||
# 39| mu39_7(ClassWithDestructor2) = Store[#temp39:3] : &:r39_1, r39_6
|
||||
# 40| v40_1(void) = NoOp :
|
||||
# 38| v38_6(void) = ReturnVoid :
|
||||
# 38| v38_7(void) = AliasedUse : ~m?
|
||||
# 38| v38_8(void) = ExitFunction :
|
||||
|
||||
# 39| Block 2
|
||||
# 39| r39_8(glval<ClassWithDestructor2>) = VariableAddress[#temp39:7] :
|
||||
# 39| mu39_9(ClassWithDestructor2) = Uninitialized[#temp39:7] : &:r39_8
|
||||
# 39| r39_10(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 39| v39_11(void) = Call[ClassWithDestructor2] : func:r39_10, this:r39_8
|
||||
# 39| mu39_12(unknown) = ^CallSideEffect : ~m?
|
||||
# 39| mu39_13(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r39_8
|
||||
# 39| r39_14(ClassWithDestructor2) = Load[#temp39:7] : &:r39_8, ~m?
|
||||
# 39| r39_15(glval<ClassWithDestructor2>) = VariableAddress[#temp39:3] :
|
||||
# 39| mu39_16(ClassWithDestructor2) = Store[#temp39:3] : &:r39_15, r39_14
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 39| Block 3
|
||||
# 39| r39_17(glval<ClassWithDestructor2>) = VariableAddress[#temp39:32] :
|
||||
# 39| mu39_18(ClassWithDestructor2) = Uninitialized[#temp39:32] : &:r39_17
|
||||
# 39| r39_19(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 39| v39_20(void) = Call[ClassWithDestructor2] : func:r39_19, this:r39_17
|
||||
# 39| mu39_21(unknown) = ^CallSideEffect : ~m?
|
||||
# 39| mu39_22(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r39_17
|
||||
# 39| r39_23(ClassWithDestructor2) = Load[#temp39:32] : &:r39_17, ~m?
|
||||
# 39| r39_24(glval<ClassWithDestructor2>) = VariableAddress[#temp39:3] :
|
||||
# 39| mu39_25(ClassWithDestructor2) = Store[#temp39:3] : &:r39_24, r39_23
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 42| void temp_test6(bool)
|
||||
# 42| Block 0
|
||||
# 42| v42_1(void) = EnterFunction :
|
||||
# 42| mu42_2(unknown) = AliasedDefinition :
|
||||
# 42| mu42_3(unknown) = InitializeNonLocal :
|
||||
# 42| r42_4(glval<bool>) = VariableAddress[b] :
|
||||
# 42| mu42_5(bool) = InitializeParameter[b] : &:r42_4
|
||||
# 43| r43_1(glval<ClassWithDestructor2>) = VariableAddress[c] :
|
||||
# 43| mu43_2(ClassWithDestructor2) = Uninitialized[c] : &:r43_1
|
||||
# 43| r43_3(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 43| v43_4(void) = Call[ClassWithDestructor2] : func:r43_3, this:r43_1
|
||||
# 43| mu43_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 43| mu43_6(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r43_1
|
||||
# 44| r44_1(glval<bool>) = VariableAddress[b] :
|
||||
# 44| r44_2(bool) = Load[b] : &:r44_1, ~m?
|
||||
# 44| v44_3(void) = ConditionalBranch : r44_2
|
||||
#-----| False -> Block 4
|
||||
#-----| True -> Block 3
|
||||
|
||||
# 42| Block 1
|
||||
# 42| v42_6(void) = AliasedUse : ~m?
|
||||
# 42| v42_7(void) = ExitFunction :
|
||||
|
||||
# 42| Block 2
|
||||
# 42| v42_8(void) = Unwind :
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 45| Block 3
|
||||
# 45| r45_1(glval<ClassWithConstructor>) = VariableAddress[#throw45:7] :
|
||||
# 45| mu45_2(ClassWithConstructor) = Uninitialized[#throw45:7] : &:r45_1
|
||||
# 45| r45_3(glval<unknown>) = FunctionAddress[ClassWithConstructor] :
|
||||
# 45| r45_4(char) = Constant[120] :
|
||||
# 45| r45_5(glval<ClassWithDestructor2>) = VariableAddress[#temp45:39] :
|
||||
# 45| mu45_6(ClassWithDestructor2) = Uninitialized[#temp45:39] : &:r45_5
|
||||
# 45| r45_7(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 45| v45_8(void) = Call[ClassWithDestructor2] : func:r45_7, this:r45_5
|
||||
# 45| mu45_9(unknown) = ^CallSideEffect : ~m?
|
||||
# 45| mu45_10(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r45_5
|
||||
# 45| r45_11(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 45| r45_12(char) = Call[get_x] : func:r45_11, this:r45_5
|
||||
# 45| mu45_13(unknown) = ^CallSideEffect : ~m?
|
||||
# 45| v45_14(void) = ^IndirectReadSideEffect[-1] : &:r45_5, ~m?
|
||||
# 45| mu45_15(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r45_5
|
||||
# 45| v45_16(void) = Call[ClassWithConstructor] : func:r45_3, this:r45_1, 0:r45_4, 1:r45_12
|
||||
# 45| mu45_17(unknown) = ^CallSideEffect : ~m?
|
||||
# 45| mu45_18(ClassWithConstructor) = ^IndirectMayWriteSideEffect[-1] : &:r45_1
|
||||
# 45| v45_19(void) = ThrowValue : &:r45_1, ~m?
|
||||
#-----| Exception -> Block 2
|
||||
|
||||
# 47| Block 4
|
||||
# 47| v47_1(void) = NoOp :
|
||||
# 47| r47_2(glval<ClassWithDestructor2>) = VariableAddress[c] :
|
||||
# 47| r47_3(glval<unknown>) = FunctionAddress[~ClassWithDestructor2] :
|
||||
# 47| v47_4(void) = Call[~ClassWithDestructor2] : func:r47_3, this:r47_2
|
||||
# 47| mu47_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 47| v47_6(void) = ^IndirectReadSideEffect[-1] : &:r47_2, ~m?
|
||||
# 47| mu47_7(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r47_2
|
||||
# 42| v42_9(void) = ReturnVoid :
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 49| void temp_test7(bool)
|
||||
# 49| Block 0
|
||||
# 49| v49_1(void) = EnterFunction :
|
||||
# 49| mu49_2(unknown) = AliasedDefinition :
|
||||
# 49| mu49_3(unknown) = InitializeNonLocal :
|
||||
# 49| r49_4(glval<bool>) = VariableAddress[b] :
|
||||
# 49| mu49_5(bool) = InitializeParameter[b] : &:r49_4
|
||||
# 50| r50_1(glval<ClassWithDestructor2>) = VariableAddress[c] :
|
||||
# 50| mu50_2(ClassWithDestructor2) = Uninitialized[c] : &:r50_1
|
||||
# 50| r50_3(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 50| v50_4(void) = Call[ClassWithDestructor2] : func:r50_3, this:r50_1
|
||||
# 50| mu50_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 50| mu50_6(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r50_1
|
||||
# 51| r51_1(glval<ClassWithDestructor2>) = VariableAddress[#temp51:5] :
|
||||
# 51| r51_2(glval<bool>) = VariableAddress[b] :
|
||||
# 51| r51_3(bool) = Load[b] : &:r51_2, ~m?
|
||||
# 51| v51_4(void) = ConditionalBranch : r51_3
|
||||
#-----| False -> Block 4
|
||||
#-----| True -> Block 3
|
||||
|
||||
# 49| Block 1
|
||||
# 49| v49_6(void) = AliasedUse : ~m?
|
||||
# 49| v49_7(void) = ExitFunction :
|
||||
|
||||
# 49| Block 2
|
||||
# 49| v49_8(void) = Unwind :
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 51| Block 3
|
||||
# 51| r51_5(glval<ClassWithConstructor>) = VariableAddress[#throw51:9] :
|
||||
# 51| mu51_6(ClassWithConstructor) = Uninitialized[#throw51:9] : &:r51_5
|
||||
# 51| r51_7(glval<unknown>) = FunctionAddress[ClassWithConstructor] :
|
||||
# 51| r51_8(char) = Constant[120] :
|
||||
# 51| r51_9(glval<ClassWithDestructor2>) = VariableAddress[#temp51:41] :
|
||||
# 51| mu51_10(ClassWithDestructor2) = Uninitialized[#temp51:41] : &:r51_9
|
||||
# 51| r51_11(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 51| v51_12(void) = Call[ClassWithDestructor2] : func:r51_11, this:r51_9
|
||||
# 51| mu51_13(unknown) = ^CallSideEffect : ~m?
|
||||
# 51| mu51_14(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r51_9
|
||||
# 51| r51_15(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 51| r51_16(char) = Call[get_x] : func:r51_15, this:r51_9
|
||||
# 51| mu51_17(unknown) = ^CallSideEffect : ~m?
|
||||
# 51| v51_18(void) = ^IndirectReadSideEffect[-1] : &:r51_9, ~m?
|
||||
# 51| mu51_19(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r51_9
|
||||
# 51| v51_20(void) = Call[ClassWithConstructor] : func:r51_7, this:r51_5, 0:r51_8, 1:r51_16
|
||||
# 51| mu51_21(unknown) = ^CallSideEffect : ~m?
|
||||
# 51| mu51_22(ClassWithConstructor) = ^IndirectMayWriteSideEffect[-1] : &:r51_5
|
||||
# 51| v51_23(void) = ThrowValue : &:r51_5, ~m?
|
||||
#-----| Exception -> Block 2
|
||||
|
||||
# 51| Block 4
|
||||
# 51| r51_24(glval<ClassWithDestructor2>) = VariableAddress[#temp51:75] :
|
||||
# 51| mu51_25(ClassWithDestructor2) = Uninitialized[#temp51:75] : &:r51_24
|
||||
# 51| r51_26(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 51| v51_27(void) = Call[ClassWithDestructor2] : func:r51_26, this:r51_24
|
||||
# 51| mu51_28(unknown) = ^CallSideEffect : ~m?
|
||||
# 51| mu51_29(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r51_24
|
||||
# 51| r51_30(ClassWithDestructor2) = Load[#temp51:75] : &:r51_24, ~m?
|
||||
# 51| r51_31(glval<ClassWithDestructor2>) = VariableAddress[#temp51:5] :
|
||||
# 51| mu51_32(ClassWithDestructor2) = Store[#temp51:5] : &:r51_31, r51_30
|
||||
# 51| r51_33(glval<ClassWithDestructor2>) = VariableAddress[#temp51:5] :
|
||||
# 51| r51_34(ClassWithDestructor2) = Load[#temp51:5] : &:r51_33, ~m?
|
||||
# 51| mu51_35(ClassWithDestructor2) = Store[#temp51:5] : &:r51_1, r51_34
|
||||
# 52| v52_1(void) = NoOp :
|
||||
# 52| r52_2(glval<ClassWithDestructor2>) = VariableAddress[c] :
|
||||
# 52| r52_3(glval<unknown>) = FunctionAddress[~ClassWithDestructor2] :
|
||||
# 52| v52_4(void) = Call[~ClassWithDestructor2] : func:r52_3, this:r52_2
|
||||
# 52| mu52_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 52| v52_6(void) = ^IndirectReadSideEffect[-1] : &:r52_2, ~m?
|
||||
# 52| mu52_7(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r52_2
|
||||
# 49| v49_9(void) = ReturnVoid :
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 54| void temp_test8(bool)
|
||||
# 54| Block 0
|
||||
# 54| v54_1(void) = EnterFunction :
|
||||
# 54| mu54_2(unknown) = AliasedDefinition :
|
||||
# 54| mu54_3(unknown) = InitializeNonLocal :
|
||||
# 54| r54_4(glval<bool>) = VariableAddress[b] :
|
||||
# 54| mu54_5(bool) = InitializeParameter[b] : &:r54_4
|
||||
# 55| r55_1(glval<ClassWithDestructor2>) = VariableAddress[#temp55:5] :
|
||||
# 55| r55_2(glval<bool>) = VariableAddress[b] :
|
||||
# 55| r55_3(bool) = Load[b] : &:r55_2, ~m?
|
||||
# 55| v55_4(void) = ConditionalBranch : r55_3
|
||||
#-----| False -> Block 4
|
||||
#-----| True -> Block 3
|
||||
|
||||
# 54| Block 1
|
||||
# 54| v54_6(void) = AliasedUse : ~m?
|
||||
# 54| v54_7(void) = ExitFunction :
|
||||
|
||||
# 54| Block 2
|
||||
# 54| v54_8(void) = Unwind :
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 55| Block 3
|
||||
# 55| r55_5(glval<ClassWithConstructor>) = VariableAddress[#throw55:9] :
|
||||
# 55| mu55_6(ClassWithConstructor) = Uninitialized[#throw55:9] : &:r55_5
|
||||
# 55| r55_7(glval<unknown>) = FunctionAddress[ClassWithConstructor] :
|
||||
# 55| r55_8(char) = Constant[120] :
|
||||
# 55| r55_9(glval<ClassWithDestructor2>) = VariableAddress[#temp55:41] :
|
||||
# 55| mu55_10(ClassWithDestructor2) = Uninitialized[#temp55:41] : &:r55_9
|
||||
# 55| r55_11(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 55| v55_12(void) = Call[ClassWithDestructor2] : func:r55_11, this:r55_9
|
||||
# 55| mu55_13(unknown) = ^CallSideEffect : ~m?
|
||||
# 55| mu55_14(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r55_9
|
||||
# 55| r55_15(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 55| r55_16(char) = Call[get_x] : func:r55_15, this:r55_9
|
||||
# 55| mu55_17(unknown) = ^CallSideEffect : ~m?
|
||||
# 55| v55_18(void) = ^IndirectReadSideEffect[-1] : &:r55_9, ~m?
|
||||
# 55| mu55_19(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r55_9
|
||||
# 55| v55_20(void) = Call[ClassWithConstructor] : func:r55_7, this:r55_5, 0:r55_8, 1:r55_16
|
||||
# 55| mu55_21(unknown) = ^CallSideEffect : ~m?
|
||||
# 55| mu55_22(ClassWithConstructor) = ^IndirectMayWriteSideEffect[-1] : &:r55_5
|
||||
# 55| v55_23(void) = ThrowValue : &:r55_5, ~m?
|
||||
#-----| Exception -> Block 2
|
||||
|
||||
# 55| Block 4
|
||||
# 55| r55_24(glval<ClassWithDestructor2>) = VariableAddress[#temp55:75] :
|
||||
# 55| mu55_25(ClassWithDestructor2) = Uninitialized[#temp55:75] : &:r55_24
|
||||
# 55| r55_26(glval<unknown>) = FunctionAddress[ClassWithDestructor2] :
|
||||
# 55| v55_27(void) = Call[ClassWithDestructor2] : func:r55_26, this:r55_24
|
||||
# 55| mu55_28(unknown) = ^CallSideEffect : ~m?
|
||||
# 55| mu55_29(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r55_24
|
||||
# 55| r55_30(ClassWithDestructor2) = Load[#temp55:75] : &:r55_24, ~m?
|
||||
# 55| r55_31(glval<ClassWithDestructor2>) = VariableAddress[#temp55:5] :
|
||||
# 55| mu55_32(ClassWithDestructor2) = Store[#temp55:5] : &:r55_31, r55_30
|
||||
# 55| r55_33(glval<ClassWithDestructor2>) = VariableAddress[#temp55:5] :
|
||||
# 55| r55_34(ClassWithDestructor2) = Load[#temp55:5] : &:r55_33, ~m?
|
||||
# 55| mu55_35(ClassWithDestructor2) = Store[#temp55:5] : &:r55_1, r55_34
|
||||
# 56| v56_1(void) = NoOp :
|
||||
# 54| v54_9(void) = ReturnVoid :
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
ir.c:
|
||||
# 7| void MyCoordsTest(int)
|
||||
# 7| Block 0
|
||||
|
||||
@@ -11,6 +11,7 @@ edges
|
||||
| test_free.cpp:128:10:128:11 | pointer to free output argument | test_free.cpp:129:10:129:11 | * ... | provenance | |
|
||||
| test_free.cpp:152:27:152:27 | pointer to free output argument | test_free.cpp:154:10:154:10 | a | provenance | |
|
||||
| test_free.cpp:207:10:207:10 | pointer to free output argument | test_free.cpp:209:10:209:10 | a | provenance | |
|
||||
| test_free.cpp:301:12:301:14 | pointer to g_free output argument | test_free.cpp:302:12:302:14 | buf | provenance | |
|
||||
nodes
|
||||
| test_free.cpp:11:10:11:10 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||
| test_free.cpp:14:10:14:10 | a | semmle.label | a |
|
||||
@@ -36,6 +37,8 @@ nodes
|
||||
| test_free.cpp:154:10:154:10 | a | semmle.label | a |
|
||||
| test_free.cpp:207:10:207:10 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||
| test_free.cpp:209:10:209:10 | a | semmle.label | a |
|
||||
| test_free.cpp:301:12:301:14 | pointer to g_free output argument | semmle.label | pointer to g_free output argument |
|
||||
| test_free.cpp:302:12:302:14 | buf | semmle.label | buf |
|
||||
subpaths
|
||||
#select
|
||||
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
@@ -50,3 +53,4 @@ subpaths
|
||||
| test_free.cpp:129:10:129:11 | * ... | test_free.cpp:128:10:128:11 | pointer to free output argument | test_free.cpp:129:10:129:11 | * ... | Memory pointed to by '* ...' may already have been freed by $@. | test_free.cpp:128:5:128:8 | call to free | call to free |
|
||||
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | pointer to free output argument | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | pointer to free output argument | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
|
||||
| test_free.cpp:302:12:302:14 | buf | test_free.cpp:301:12:301:14 | pointer to g_free output argument | test_free.cpp:302:12:302:14 | buf | Memory pointed to by 'buf' may already have been freed by $@. | test_free.cpp:301:5:301:10 | call to g_free | call to g_free |
|
||||
|
||||
@@ -102,6 +102,8 @@
|
||||
| test_free.cpp:282:10:282:12 | buf |
|
||||
| test_free.cpp:288:8:288:10 | buf |
|
||||
| test_free.cpp:293:8:293:10 | buf |
|
||||
| test_free.cpp:301:12:301:14 | buf |
|
||||
| test_free.cpp:302:12:302:14 | buf |
|
||||
| virtual.cpp:18:10:18:10 | a |
|
||||
| virtual.cpp:19:10:19:10 | c |
|
||||
| virtual.cpp:38:10:38:10 | b |
|
||||
|
||||
@@ -293,4 +293,11 @@ void test_free_struct4(char* buf, MyStruct s) {
|
||||
free(buf);
|
||||
s.buf = buf;
|
||||
char c = s.buf[0]; // BAD
|
||||
}
|
||||
|
||||
void g_free (void*);
|
||||
|
||||
void test_g_free(char* buf) {
|
||||
g_free(buf);
|
||||
g_free(buf); // BAD
|
||||
}
|
||||
@@ -101,6 +101,10 @@ edges
|
||||
| test.cpp:857:16:857:29 | ... + ... | test.cpp:857:16:857:29 | ... + ... | provenance | |
|
||||
| test.cpp:857:16:857:29 | ... + ... | test.cpp:860:5:860:11 | ... = ... | provenance | |
|
||||
| test.cpp:857:16:857:29 | ... + ... | test.cpp:860:5:860:11 | ... = ... | provenance | |
|
||||
| test.cpp:868:15:868:35 | call to g_malloc | test.cpp:869:15:869:22 | ... + ... | provenance | |
|
||||
| test.cpp:869:15:869:22 | ... + ... | test.cpp:869:15:869:22 | ... + ... | provenance | |
|
||||
| test.cpp:869:15:869:22 | ... + ... | test.cpp:870:14:870:15 | * ... | provenance | |
|
||||
| test.cpp:869:15:869:22 | ... + ... | test.cpp:870:14:870:15 | * ... | provenance | |
|
||||
nodes
|
||||
| test.cpp:4:15:4:33 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
|
||||
@@ -198,6 +202,10 @@ nodes
|
||||
| test.cpp:857:16:857:29 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:857:16:857:29 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:860:5:860:11 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:868:15:868:35 | call to g_malloc | semmle.label | call to g_malloc |
|
||||
| test.cpp:869:15:869:22 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:869:15:869:22 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:870:14:870:15 | * ... | semmle.label | * ... |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:6:14:6:15 | * ... | test.cpp:4:15:4:33 | call to malloc | test.cpp:6:14:6:15 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:33 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
|
||||
@@ -231,3 +239,4 @@ subpaths
|
||||
| test.cpp:842:3:842:20 | ... = ... | test.cpp:841:18:841:35 | call to malloc | test.cpp:842:3:842:20 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:841:18:841:35 | call to malloc | call to malloc | test.cpp:842:11:842:15 | index | index |
|
||||
| test.cpp:849:5:849:22 | ... = ... | test.cpp:848:20:848:37 | call to malloc | test.cpp:849:5:849:22 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:848:20:848:37 | call to malloc | call to malloc | test.cpp:849:13:849:17 | index | index |
|
||||
| test.cpp:860:5:860:11 | ... = ... | test.cpp:856:12:856:35 | call to malloc | test.cpp:860:5:860:11 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:856:12:856:35 | call to malloc | call to malloc | test.cpp:857:21:857:28 | ... + ... | ... + ... |
|
||||
| test.cpp:870:14:870:15 | * ... | test.cpp:868:15:868:35 | call to g_malloc | test.cpp:870:14:870:15 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:868:15:868:35 | call to g_malloc | call to g_malloc | test.cpp:869:19:869:22 | size | size |
|
||||
|
||||
@@ -859,4 +859,13 @@ void test_regression(size_t size) {
|
||||
if(p <= chend) {
|
||||
*p = 42; // $ deref=L857->L860 // BAD
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void* g_malloc(size_t size);
|
||||
|
||||
void test17(int size) {
|
||||
char* p = (char*)g_malloc(size);
|
||||
char* q = p + size; // $ alloc=L868
|
||||
char a = *q; // $ deref=L869->L870 // BAD
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
edges
|
||||
| test.cpp:17:13:17:18 | new | test.cpp:18:21:18:47 | p | provenance | |
|
||||
| test.cpp:22:13:22:26 | new | test.cpp:23:12:23:30 | p | provenance | |
|
||||
| test.cpp:27:13:27:18 | new | test.cpp:28:25:28:55 | p | provenance | |
|
||||
| test.cpp:32:13:32:30 | new | test.cpp:33:12:33:30 | p | provenance | |
|
||||
| test.cpp:47:21:47:36 | new | test.cpp:48:22:48:55 | p | provenance | |
|
||||
| test.cpp:66:15:66:21 | new | test.cpp:67:12:67:31 | a | provenance | |
|
||||
| test.cpp:76:15:76:21 | new | test.cpp:77:12:77:31 | a | provenance | |
|
||||
| test.cpp:83:9:83:15 | new | test.cpp:88:14:88:33 | a | provenance | |
|
||||
| test.cpp:85:9:85:15 | new | test.cpp:88:14:88:33 | a | provenance | |
|
||||
| test.cpp:115:12:115:17 | new | test.cpp:116:20:116:51 | s2 | provenance | |
|
||||
| test.cpp:127:12:127:17 | new | test.cpp:128:24:128:59 | s2 | provenance | |
|
||||
| test.cpp:140:12:140:17 | new | test.cpp:141:23:141:57 | s1 | provenance | |
|
||||
| test.cpp:143:14:143:19 | new | test.cpp:145:28:145:68 | s1_2 | provenance | |
|
||||
| test.cpp:153:9:153:15 | new | test.cpp:159:14:159:33 | a | provenance | |
|
||||
| test.cpp:166:9:166:15 | new | test.cpp:171:14:171:33 | a | provenance | |
|
||||
| test.cpp:168:9:168:15 | new | test.cpp:171:14:171:33 | a | provenance | |
|
||||
| test.cpp:179:15:179:24 | new | test.cpp:181:15:181:25 | u64 | provenance | |
|
||||
| test.cpp:187:15:187:24 | new | test.cpp:189:25:189:45 | u64 | provenance | |
|
||||
| test.cpp:207:14:207:26 | new | test.cpp:209:17:209:28 | si | provenance | |
|
||||
| test.cpp:217:13:217:18 | new | test.cpp:218:30:218:65 | p | provenance | |
|
||||
| test.cpp:226:13:226:18 | new | test.cpp:227:29:227:63 | p | provenance | |
|
||||
nodes
|
||||
| test.cpp:17:13:17:18 | new | semmle.label | new |
|
||||
| test.cpp:18:21:18:47 | p | semmle.label | p |
|
||||
| test.cpp:22:13:22:26 | new | semmle.label | new |
|
||||
| test.cpp:23:12:23:30 | p | semmle.label | p |
|
||||
| test.cpp:27:13:27:18 | new | semmle.label | new |
|
||||
| test.cpp:28:25:28:55 | p | semmle.label | p |
|
||||
| test.cpp:32:13:32:30 | new | semmle.label | new |
|
||||
| test.cpp:33:12:33:30 | p | semmle.label | p |
|
||||
| test.cpp:47:21:47:36 | new | semmle.label | new |
|
||||
| test.cpp:48:22:48:55 | p | semmle.label | p |
|
||||
| test.cpp:66:15:66:21 | new | semmle.label | new |
|
||||
| test.cpp:67:12:67:31 | a | semmle.label | a |
|
||||
| test.cpp:76:15:76:21 | new | semmle.label | new |
|
||||
| test.cpp:77:12:77:31 | a | semmle.label | a |
|
||||
| test.cpp:83:9:83:15 | new | semmle.label | new |
|
||||
| test.cpp:85:9:85:15 | new | semmle.label | new |
|
||||
| test.cpp:88:14:88:33 | a | semmle.label | a |
|
||||
| test.cpp:115:12:115:17 | new | semmle.label | new |
|
||||
| test.cpp:116:20:116:51 | s2 | semmle.label | s2 |
|
||||
| test.cpp:127:12:127:17 | new | semmle.label | new |
|
||||
| test.cpp:128:24:128:59 | s2 | semmle.label | s2 |
|
||||
| test.cpp:140:12:140:17 | new | semmle.label | new |
|
||||
| test.cpp:141:23:141:57 | s1 | semmle.label | s1 |
|
||||
| test.cpp:143:14:143:19 | new | semmle.label | new |
|
||||
| test.cpp:145:28:145:68 | s1_2 | semmle.label | s1_2 |
|
||||
| test.cpp:153:9:153:15 | new | semmle.label | new |
|
||||
| test.cpp:159:14:159:33 | a | semmle.label | a |
|
||||
| test.cpp:166:9:166:15 | new | semmle.label | new |
|
||||
| test.cpp:168:9:168:15 | new | semmle.label | new |
|
||||
| test.cpp:171:14:171:33 | a | semmle.label | a |
|
||||
| test.cpp:179:15:179:24 | new | semmle.label | new |
|
||||
| test.cpp:181:15:181:25 | u64 | semmle.label | u64 |
|
||||
| test.cpp:187:15:187:24 | new | semmle.label | new |
|
||||
| test.cpp:189:25:189:45 | u64 | semmle.label | u64 |
|
||||
| test.cpp:207:14:207:26 | new | semmle.label | new |
|
||||
| test.cpp:209:17:209:28 | si | semmle.label | si |
|
||||
| test.cpp:217:13:217:18 | new | semmle.label | new |
|
||||
| test.cpp:218:30:218:65 | p | semmle.label | p |
|
||||
| test.cpp:226:13:226:18 | new | semmle.label | new |
|
||||
| test.cpp:227:29:227:63 | p | semmle.label | p |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:28:25:28:55 | p | test.cpp:27:13:27:18 | new | test.cpp:28:25:28:55 | p | Conversion from $@ to $@ is invalid. | test.cpp:1:8:1:9 | S1 | S1 | test.cpp:11:8:11:21 | Not_S1_wrapper | Not_S1_wrapper |
|
||||
| test.cpp:33:12:33:30 | p | test.cpp:32:13:32:30 | new | test.cpp:33:12:33:30 | p | Conversion from $@ to $@ is invalid. | test.cpp:11:8:11:21 | Not_S1_wrapper | Not_S1_wrapper | test.cpp:1:8:1:9 | S1 | S1 |
|
||||
| test.cpp:67:12:67:31 | a | test.cpp:66:15:66:21 | new | test.cpp:67:12:67:31 | a | Conversion from $@ to $@ is invalid. | test.cpp:55:8:55:10 | Cat | Cat | test.cpp:60:8:60:10 | Dog | Dog |
|
||||
| test.cpp:128:24:128:59 | s2 | test.cpp:127:12:127:17 | new | test.cpp:128:24:128:59 | s2 | Conversion from $@ to $@ is invalid. | test.cpp:102:8:102:9 | S2 | S2 | test.cpp:119:8:119:20 | Not_S2_prefix | Not_S2_prefix |
|
||||
| test.cpp:145:28:145:68 | s1_2 | test.cpp:143:14:143:19 | new | test.cpp:145:28:145:68 | s1_2 | Conversion from $@ to $@ is invalid. | test.cpp:1:8:1:9 | S1 | S1 | test.cpp:131:8:131:23 | HasSomeBitFields | HasSomeBitFields |
|
||||
| test.cpp:159:14:159:33 | a | test.cpp:153:9:153:15 | new | test.cpp:159:14:159:33 | a | Conversion from $@ to $@ is invalid. | test.cpp:60:8:60:10 | Dog | Dog | test.cpp:55:8:55:10 | Cat | Cat |
|
||||
| test.cpp:189:25:189:45 | u64 | test.cpp:187:15:187:24 | new | test.cpp:189:25:189:45 | u64 | Conversion from $@ to $@ is invalid. | test.cpp:175:8:175:13 | UInt64 | UInt64 | test.cpp:184:8:184:22 | UInt8_with_more | UInt8_with_more |
|
||||
| test.cpp:218:30:218:65 | p | test.cpp:217:13:217:18 | new | test.cpp:218:30:218:65 | p | Conversion from $@ to $@ is invalid. | test.cpp:1:8:1:9 | S1 | S1 | test.cpp:212:8:212:26 | UnrelatedStructSize | UnrelatedStructSize |
|
||||
| test.cpp:227:29:227:63 | p | test.cpp:226:13:226:18 | new | test.cpp:227:29:227:63 | p | Conversion from $@ to $@ is invalid. | test.cpp:1:8:1:9 | S1 | S1 | test.cpp:221:8:221:25 | TooLargeBufferSize | TooLargeBufferSize |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-843/TypeConfusion.ql
|
||||
230
cpp/ql/test/query-tests/Security/CWE/CWE-843/test.cpp
Normal file
230
cpp/ql/test/query-tests/Security/CWE/CWE-843/test.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
struct S1 {
|
||||
int a;
|
||||
void* b;
|
||||
unsigned char c;
|
||||
};
|
||||
|
||||
struct S1_wrapper {
|
||||
S1 s1;
|
||||
};
|
||||
|
||||
struct Not_S1_wrapper {
|
||||
unsigned char x;
|
||||
S1 s1;
|
||||
};
|
||||
|
||||
void test1() {
|
||||
void* p = new S1;
|
||||
S1_wrapper* s1w = static_cast<S1_wrapper*>(p); // GOOD
|
||||
}
|
||||
|
||||
void test2() {
|
||||
void* p = new S1_wrapper;
|
||||
S1* s1 = static_cast<S1*>(p); // GOOD
|
||||
}
|
||||
|
||||
void test3() {
|
||||
void* p = new S1;
|
||||
Not_S1_wrapper* s1w = static_cast<Not_S1_wrapper*>(p); // BAD
|
||||
}
|
||||
|
||||
void test4() {
|
||||
void* p = new Not_S1_wrapper;
|
||||
S1* s1 = static_cast<S1*>(p); // BAD
|
||||
}
|
||||
|
||||
struct HasBitFields {
|
||||
int x : 16;
|
||||
int y : 16;
|
||||
int z : 32;
|
||||
};
|
||||
|
||||
struct BufferStruct {
|
||||
unsigned char buffer[sizeof(HasBitFields)];
|
||||
};
|
||||
|
||||
void test5() {
|
||||
HasBitFields* p = new HasBitFields;
|
||||
BufferStruct* bs = reinterpret_cast<BufferStruct*>(p); // GOOD
|
||||
}
|
||||
|
||||
struct Animal {
|
||||
virtual ~Animal();
|
||||
};
|
||||
|
||||
struct Cat : public Animal {
|
||||
Cat();
|
||||
~Cat();
|
||||
};
|
||||
|
||||
struct Dog : public Animal {
|
||||
Dog();
|
||||
~Dog();
|
||||
};
|
||||
|
||||
void test6() {
|
||||
Animal* a = new Cat;
|
||||
Dog* d = static_cast<Dog*>(a); // BAD
|
||||
}
|
||||
|
||||
void test7() {
|
||||
Animal* a = new Cat;
|
||||
Dog* d = dynamic_cast<Dog*>(a); // GOOD
|
||||
}
|
||||
|
||||
void test8() {
|
||||
Animal* a = new Cat;
|
||||
Cat* d = static_cast<Cat*>(a); // GOOD
|
||||
}
|
||||
|
||||
void test9(bool b) {
|
||||
Animal* a;
|
||||
if(b) {
|
||||
a = new Cat;
|
||||
} else {
|
||||
a = new Dog;
|
||||
}
|
||||
if(b) {
|
||||
Cat* d = static_cast<Cat*>(a); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The layout of S2 is:
|
||||
* 0: int
|
||||
* 8: void*
|
||||
* 16: unsigned char
|
||||
* 16 + pad: unsigned char
|
||||
* 32 + pad: int
|
||||
* 40 + pad: void*
|
||||
* 48 + pad: unsigned char
|
||||
*/
|
||||
struct S2 {
|
||||
S1 s1;
|
||||
unsigned char buffer[16];
|
||||
S1 s1_2;
|
||||
};
|
||||
|
||||
struct S2_prefix {
|
||||
int a;
|
||||
void* p;
|
||||
unsigned char c;
|
||||
};
|
||||
|
||||
void test10() {
|
||||
S2* s2 = new S2;
|
||||
S2_prefix* s2p = reinterpret_cast<S2_prefix*>(s2); // GOOD
|
||||
}
|
||||
|
||||
struct Not_S2_prefix {
|
||||
int a;
|
||||
void* p;
|
||||
void* p2;
|
||||
unsigned char c;
|
||||
};
|
||||
|
||||
void test11() {
|
||||
S2* s2 = new S2;
|
||||
Not_S2_prefix* s2p = reinterpret_cast<Not_S2_prefix*>(s2); // BAD
|
||||
}
|
||||
|
||||
struct HasSomeBitFields {
|
||||
int x : 16;
|
||||
int y;
|
||||
int z : 32;
|
||||
};
|
||||
|
||||
void test12() {
|
||||
// This has doesn't have any non-bitfield member, so we don't detect
|
||||
// the problem here since the query currently ignores bitfields.
|
||||
S1* s1 = new S1;
|
||||
HasBitFields* hbf = reinterpret_cast<HasBitFields*>(s1); // BAD [NOT DETECTED]
|
||||
|
||||
S1* s1_2 = new S1;
|
||||
// This one has a non-bitfield members. So we detect the problem
|
||||
HasSomeBitFields* hbf2 = reinterpret_cast<HasSomeBitFields*>(s1_2); // BAD
|
||||
}
|
||||
|
||||
void test13(bool b, Cat* c) {
|
||||
Animal* a;
|
||||
if(b) {
|
||||
a = c;
|
||||
} else {
|
||||
a = new Dog;
|
||||
}
|
||||
// This FP happens despite the `not GoodFlow::flowTo(sinkNode)` condition in the query
|
||||
// because we don't find a flow path from `a = c` to `static_cast<Cat*>(a)` because
|
||||
// the "source" (i.e., `a = c`) doesn't have an allocation.
|
||||
if(b) {
|
||||
Cat* d = static_cast<Cat*>(a); // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
void test14(bool b) {
|
||||
Animal* a;
|
||||
if(b) {
|
||||
a = new Cat;
|
||||
} else {
|
||||
a = new Dog;
|
||||
}
|
||||
if(!b) {
|
||||
Cat* d = static_cast<Cat*>(a); // BAD [NOT DETECTED]
|
||||
}
|
||||
}
|
||||
|
||||
struct UInt64 { unsigned long u64; };
|
||||
struct UInt8 { unsigned char u8; };
|
||||
|
||||
void test14() {
|
||||
void* u64 = new UInt64;
|
||||
// ...
|
||||
UInt8* u8 = (UInt8*)u64; // GOOD
|
||||
}
|
||||
|
||||
struct UInt8_with_more { UInt8 u8; void* p; };
|
||||
|
||||
void test15() {
|
||||
void* u64 = new UInt64;
|
||||
// ...
|
||||
UInt8_with_more* u8 = (UInt8_with_more*)u64; // BAD
|
||||
}
|
||||
|
||||
struct SingleInt {
|
||||
int i;
|
||||
} __attribute__((packed));;
|
||||
|
||||
struct PairInts {
|
||||
int x, y;
|
||||
} __attribute__((packed));;
|
||||
|
||||
union MyUnion
|
||||
{
|
||||
PairInts p;
|
||||
unsigned long long foo;
|
||||
} __attribute__((packed));
|
||||
|
||||
void test16() {
|
||||
void* si = new SingleInt;
|
||||
// ...
|
||||
MyUnion* mu = (MyUnion*)si; // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
struct UnrelatedStructSize {
|
||||
unsigned char buffer[1024];
|
||||
};
|
||||
|
||||
void test17() {
|
||||
void* p = new S1;
|
||||
UnrelatedStructSize* uss = static_cast<UnrelatedStructSize*>(p); // BAD
|
||||
}
|
||||
|
||||
struct TooLargeBufferSize {
|
||||
unsigned char buffer[sizeof(S1) + 1];
|
||||
};
|
||||
|
||||
void test18() {
|
||||
void* p = new S1;
|
||||
TooLargeBufferSize* uss = static_cast<TooLargeBufferSize*>(p); // BAD
|
||||
}
|
||||
|
||||
// semmle-extractor-options: --gcc -std=c++11
|
||||
@@ -268,6 +268,5 @@ csharp_style_var_elsewhere = true:suggestion
|
||||
#
|
||||
|
||||
[extractor/Semmle.Extraction/Tuples.cs,
|
||||
extractor/Semmle.Extraction.CSharp/Tuples.cs,
|
||||
extractor/Semmle.Extraction.CIL/Tuples.cs]
|
||||
dotnet_naming_rule.members_should_be_pascal_case.severity = none
|
||||
extractor/Semmle.Extraction.CSharp/Tuples.cs]
|
||||
dotnet_naming_rule.members_should_be_pascal_case.severity = none
|
||||
|
||||
@@ -8,8 +8,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction", "extrac
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp", "extractor\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj", "{C4D62DA0-B64B-440B-86DC-AB52318CB8BF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CIL", "extractor\Semmle.Extraction.CIL\Semmle.Extraction.CIL.csproj", "{399A1579-68F0-40F4-9A23-F241BA697F9C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp.DependencyFetching", "extractor\Semmle.Extraction.CSharp.DependencyFetching\Semmle.Extraction.CSharp.DependencyFetching.csproj", "{541D1AC5-E42C-4AB2-A1A4-C2355CE2A2EF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp.Standalone", "extractor\Semmle.Extraction.CSharp.Standalone\Semmle.Extraction.CSharp.Standalone.csproj", "{D00E7D25-0FA0-48EC-B048-CD60CE1B30D8}"
|
||||
@@ -18,8 +16,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp.St
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp.Util", "extractor\Semmle.Extraction.CSharp.Util\Semmle.Extraction.CSharp.Util.csproj", "{998A0D4C-8BFC-4513-A28D-4816AFB89882}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CIL.Driver", "extractor\Semmle.Extraction.CIL.Driver\Semmle.Extraction.CIL.Driver.csproj", "{EFA400B3-C1CE-446F-A4E2-8B44E61EF47C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp.Driver", "extractor\Semmle.Extraction.CSharp.Driver\Semmle.Extraction.CSharp.Driver.csproj", "{C36453BF-0C82-448A-B15D-26947503A2D3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.Tests", "extractor\Semmle.Extraction.Tests\Semmle.Extraction.Tests.csproj", "{CD8D3F90-AD2E-4BB5-8E82-B94AA293864A}"
|
||||
|
||||
@@ -47,13 +47,6 @@ options:
|
||||
the code (for example if it uses inaccessible dependencies).
|
||||
type: string
|
||||
pattern: "^(false|true)$"
|
||||
cil:
|
||||
title: Whether to enable CIL extraction.
|
||||
description: >
|
||||
A value indicating, whether CIL extraction should be enabled.
|
||||
The default is 'true'.
|
||||
type: string
|
||||
pattern: "^(false|true)$"
|
||||
logging:
|
||||
title: Options pertaining to logging.
|
||||
type: object
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
package,sink,source,summary,sink:code-injection,sink:encryption-decryptor,sink:encryption-encryptor,sink:encryption-keyprop,sink:encryption-symmetrickey,sink:file-content-store,sink:html-injection,sink:js-injection,sink:log-injection,sink:sql-injection,source:commandargs,source:environment,source:file,source:file-write,source:local,source:remote,summary:taint,summary:value
|
||||
Amazon.Lambda.APIGatewayEvents,,6,,,,,,,,,,,,,,,,,6,,
|
||||
Amazon.Lambda.Core,10,,,,,,,,,,,10,,,,,,,,,
|
||||
Dapper,55,,,,,,,,,,,,55,,,,,,,,
|
||||
ILCompiler,,,81,,,,,,,,,,,,,,,,,81,
|
||||
ILLink.RoslynAnalyzer,,,63,,,,,,,,,,,,,,,,,63,
|
||||
ILLink.Shared,,,32,,,,,,,,,,,,,,,,,29,3
|
||||
ILLink.Tasks,,,5,,,,,,,,,,,,,,,,,5,
|
||||
Internal.IL,,,69,,,,,,,,,,,,,,,,,67,2
|
||||
Internal.Pgo,,,9,,,,,,,,,,,,,,,,,8,1
|
||||
Internal.TypeSystem,,,367,,,,,,,,,,,,,,,,,331,36
|
||||
JsonToItemsTaskFactory,,,7,,,,,,,,,,,,,,,,,7,
|
||||
Microsoft.Android.Build,,,14,,,,,,,,,,,,,,,,,14,
|
||||
Microsoft.Apple.Build,,,7,,,,,,,,,,,,,,,,,7,
|
||||
Microsoft.ApplicationBlocks.Data,28,,,,,,,,,,,,28,,,,,,,,
|
||||
Microsoft.CSharp,,,24,,,,,,,,,,,,,,,,,24,
|
||||
Microsoft.Diagnostics.Tools.Pgo,,,13,,,,,,,,,,,,,,,,,13,
|
||||
Microsoft.EntityFrameworkCore,6,,12,,,,,,,,,,6,,,,,,,,12
|
||||
Microsoft.Extensions.Caching.Distributed,,,15,,,,,,,,,,,,,,,,,15,
|
||||
Microsoft.Extensions.Caching.Memory,,,38,,,,,,,,,,,,,,,,,37,1
|
||||
Microsoft.Extensions.Configuration,,2,89,,,,,,,,,,,,2,,,,,86,3
|
||||
Microsoft.Extensions.DependencyInjection,,,120,,,,,,,,,,,,,,,,,120,
|
||||
Microsoft.Extensions.DependencyModel,,,12,,,,,,,,,,,,,,,,,12,
|
||||
Microsoft.Extensions.Diagnostics.Metrics,,,13,,,,,,,,,,,,,,,,,13,
|
||||
Microsoft.Extensions.FileProviders,,,15,,,,,,,,,,,,,,,,,15,
|
||||
Microsoft.Extensions.FileSystemGlobbing,,,16,,,,,,,,,,,,,,,,,14,2
|
||||
Microsoft.Extensions.Hosting,,,23,,,,,,,,,,,,,,,,,22,1
|
||||
Microsoft.Extensions.Http,,,10,,,,,,,,,,,,,,,,,10,
|
||||
Microsoft.Extensions.Logging,,,60,,,,,,,,,,,,,,,,,59,1
|
||||
Microsoft.Extensions.Options,,,8,,,,,,,,,,,,,,,,,8,
|
||||
Microsoft.Extensions.Primitives,,,64,,,,,,,,,,,,,,,,,64,
|
||||
Microsoft.Interop,,,78,,,,,,,,,,,,,,,,,78,
|
||||
Microsoft.NET.Build.Tasks,,,1,,,,,,,,,,,,,,,,,1,
|
||||
Microsoft.NET.WebAssembly.Webcil,,,7,,,,,,,,,,,,,,,,,7,
|
||||
Microsoft.VisualBasic,,,10,,,,,,,,,,,,,,,,,5,5
|
||||
Microsoft.WebAssembly.Build.Tasks,,,3,,,,,,,,,,,,,,,,,3,
|
||||
Microsoft.Win32.SafeHandles,,,4,,,,,,,,,,,,,,,,,4,
|
||||
Mono.Linker,,,163,,,,,,,,,,,,,,,,,163,
|
||||
MySql.Data.MySqlClient,48,,,,,,,,,,,,48,,,,,,,,
|
||||
Newtonsoft.Json,,,91,,,,,,,,,,,,,,,,,73,18
|
||||
ServiceStack,194,,7,27,,,,,75,,,,92,,,,,,,7,
|
||||
SourceGenerators,,,4,,,,,,,,,,,,,,,,,4,
|
||||
System,67,30,11864,,8,8,9,,,4,5,,33,2,3,1,17,3,4,9898,1966
|
||||
Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,,,,,,
|
||||
package,sink,source,summary,sink:code-injection,sink:encryption-decryptor,sink:encryption-encryptor,sink:encryption-keyprop,sink:encryption-symmetrickey,sink:file-content-store,sink:html-injection,sink:js-injection,sink:log-injection,sink:sql-injection,source:commandargs,source:environment,source:file,source:file-write,source:local,source:remote,source:windows-registry,summary:taint,summary:value
|
||||
Amazon.Lambda.APIGatewayEvents,,6,,,,,,,,,,,,,,,,,6,,,
|
||||
Amazon.Lambda.Core,10,,,,,,,,,,,10,,,,,,,,,,
|
||||
Dapper,55,,,,,,,,,,,,55,,,,,,,,,
|
||||
ILCompiler,,,81,,,,,,,,,,,,,,,,,,81,
|
||||
ILLink.RoslynAnalyzer,,,63,,,,,,,,,,,,,,,,,,63,
|
||||
ILLink.Shared,,,32,,,,,,,,,,,,,,,,,,29,3
|
||||
ILLink.Tasks,,,5,,,,,,,,,,,,,,,,,,5,
|
||||
Internal.IL,,,69,,,,,,,,,,,,,,,,,,67,2
|
||||
Internal.Pgo,,,9,,,,,,,,,,,,,,,,,,8,1
|
||||
Internal.TypeSystem,,,367,,,,,,,,,,,,,,,,,,331,36
|
||||
JsonToItemsTaskFactory,,,7,,,,,,,,,,,,,,,,,,7,
|
||||
Microsoft.Android.Build,,,14,,,,,,,,,,,,,,,,,,14,
|
||||
Microsoft.Apple.Build,,,7,,,,,,,,,,,,,,,,,,7,
|
||||
Microsoft.ApplicationBlocks.Data,28,,,,,,,,,,,,28,,,,,,,,,
|
||||
Microsoft.CSharp,,,24,,,,,,,,,,,,,,,,,,24,
|
||||
Microsoft.Diagnostics.Tools.Pgo,,,13,,,,,,,,,,,,,,,,,,13,
|
||||
Microsoft.EntityFrameworkCore,6,,12,,,,,,,,,,6,,,,,,,,,12
|
||||
Microsoft.Extensions.Caching.Distributed,,,15,,,,,,,,,,,,,,,,,,15,
|
||||
Microsoft.Extensions.Caching.Memory,,,38,,,,,,,,,,,,,,,,,,37,1
|
||||
Microsoft.Extensions.Configuration,,2,89,,,,,,,,,,,,2,,,,,,86,3
|
||||
Microsoft.Extensions.DependencyInjection,,,120,,,,,,,,,,,,,,,,,,120,
|
||||
Microsoft.Extensions.DependencyModel,,,12,,,,,,,,,,,,,,,,,,12,
|
||||
Microsoft.Extensions.Diagnostics.Metrics,,,13,,,,,,,,,,,,,,,,,,13,
|
||||
Microsoft.Extensions.FileProviders,,,15,,,,,,,,,,,,,,,,,,15,
|
||||
Microsoft.Extensions.FileSystemGlobbing,,,16,,,,,,,,,,,,,,,,,,14,2
|
||||
Microsoft.Extensions.Hosting,,,23,,,,,,,,,,,,,,,,,,22,1
|
||||
Microsoft.Extensions.Http,,,10,,,,,,,,,,,,,,,,,,10,
|
||||
Microsoft.Extensions.Logging,,,60,,,,,,,,,,,,,,,,,,59,1
|
||||
Microsoft.Extensions.Options,,,8,,,,,,,,,,,,,,,,,,8,
|
||||
Microsoft.Extensions.Primitives,,,64,,,,,,,,,,,,,,,,,,64,
|
||||
Microsoft.Interop,,,78,,,,,,,,,,,,,,,,,,78,
|
||||
Microsoft.NET.Build.Tasks,,,1,,,,,,,,,,,,,,,,,,1,
|
||||
Microsoft.NET.WebAssembly.Webcil,,,7,,,,,,,,,,,,,,,,,,7,
|
||||
Microsoft.VisualBasic,,,10,,,,,,,,,,,,,,,,,,5,5
|
||||
Microsoft.WebAssembly.Build.Tasks,,,3,,,,,,,,,,,,,,,,,,3,
|
||||
Microsoft.Win32,,4,4,,,,,,,,,,,,,,,,,4,4,
|
||||
Mono.Linker,,,163,,,,,,,,,,,,,,,,,,163,
|
||||
MySql.Data.MySqlClient,48,,,,,,,,,,,,48,,,,,,,,,
|
||||
Newtonsoft.Json,,,91,,,,,,,,,,,,,,,,,,73,18
|
||||
ServiceStack,194,,7,27,,,,,75,,,,92,,,,,,,,7,
|
||||
SourceGenerators,,,4,,,,,,,,,,,,,,,,,,4,
|
||||
System,67,30,11864,,8,8,9,,,4,5,,33,2,3,1,17,3,4,,9898,1966
|
||||
Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,,,,,,,
|
||||
|
||||
|
@@ -9,6 +9,6 @@ C# framework & library support
|
||||
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
|
||||
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
|
||||
System,"``System.*``, ``System``",30,11864,67,9
|
||||
Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``JsonToItemsTaskFactory``, ``Microsoft.Android.Build``, ``Microsoft.Apple.Build``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NET.WebAssembly.Webcil``, ``Microsoft.VisualBasic``, ``Microsoft.WebAssembly.Build.Tasks``, ``Microsoft.Win32.SafeHandles``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",8,1547,148,
|
||||
Totals,,38,13418,409,9
|
||||
Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``JsonToItemsTaskFactory``, ``Microsoft.Android.Build``, ``Microsoft.Apple.Build``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NET.WebAssembly.Webcil``, ``Microsoft.VisualBasic``, ``Microsoft.WebAssembly.Build.Tasks``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",12,1547,148,
|
||||
Totals,,42,13418,409,9
|
||||
|
||||
|
||||
@@ -1,250 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using System.Runtime.InteropServices;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Driver
|
||||
{
|
||||
/// <summary>
|
||||
/// Information about a single assembly.
|
||||
/// In particular, provides references between assemblies.
|
||||
/// </summary>
|
||||
internal class AssemblyInfo
|
||||
{
|
||||
public override string ToString() => Filename;
|
||||
|
||||
private static AssemblyName CreateAssemblyName(MetadataReader mdReader, StringHandle name, System.Version version, StringHandle culture)
|
||||
{
|
||||
var cultureString = mdReader.GetString(culture);
|
||||
|
||||
var assemblyName = new AssemblyName()
|
||||
{
|
||||
Name = mdReader.GetString(name),
|
||||
Version = version
|
||||
};
|
||||
|
||||
if (cultureString != "neutral")
|
||||
assemblyName.CultureInfo = CultureInfo.GetCultureInfo(cultureString);
|
||||
|
||||
return assemblyName;
|
||||
}
|
||||
|
||||
private static AssemblyName CreateAssemblyName(MetadataReader mdReader, AssemblyReference ar)
|
||||
{
|
||||
var an = CreateAssemblyName(mdReader, ar.Name, ar.Version, ar.Culture);
|
||||
if (!ar.PublicKeyOrToken.IsNil)
|
||||
an.SetPublicKeyToken(mdReader.GetBlobBytes(ar.PublicKeyOrToken));
|
||||
return an;
|
||||
}
|
||||
|
||||
private static AssemblyName CreateAssemblyName(MetadataReader mdReader, AssemblyDefinition ad)
|
||||
{
|
||||
var an = CreateAssemblyName(mdReader, ad.Name, ad.Version, ad.Culture);
|
||||
if (!ad.PublicKey.IsNil)
|
||||
an.SetPublicKey(mdReader.GetBlobBytes(ad.PublicKey));
|
||||
return an;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AssemblyInfo"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">Path of the assembly.</param>
|
||||
/// <exception cref="Semmle.Extraction.CIL.Driver.InvalidAssemblyException">
|
||||
/// Thrown when the input file is not a valid assembly.
|
||||
/// </exception>
|
||||
public AssemblyInfo(string path)
|
||||
{
|
||||
Filename = path;
|
||||
|
||||
// Attempt to open the file and see if it's a valid assembly.
|
||||
using var stream = File.OpenRead(path);
|
||||
using var peReader = new PEReader(stream);
|
||||
try
|
||||
{
|
||||
if (!peReader.HasMetadata)
|
||||
throw new InvalidAssemblyException();
|
||||
|
||||
var mdReader = peReader.GetMetadataReader();
|
||||
|
||||
if (!mdReader.IsAssembly)
|
||||
throw new InvalidAssemblyException();
|
||||
|
||||
// Get our own assembly name
|
||||
Name = CreateAssemblyName(mdReader, mdReader.GetAssemblyDefinition());
|
||||
|
||||
References = mdReader.AssemblyReferences
|
||||
.Select(r => mdReader.GetAssemblyReference(r))
|
||||
.Select(ar => CreateAssemblyName(mdReader, ar))
|
||||
.ToArray();
|
||||
}
|
||||
catch (System.BadImageFormatException)
|
||||
{
|
||||
// This failed on one of the Roslyn tests that includes
|
||||
// a deliberately malformed assembly.
|
||||
// In this case, we just skip the extraction of this assembly.
|
||||
throw new InvalidAssemblyException();
|
||||
}
|
||||
}
|
||||
|
||||
public AssemblyName Name { get; }
|
||||
public string Filename { get; }
|
||||
public bool Extract { get; set; }
|
||||
public AssemblyName[] References { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper to manage a collection of assemblies.
|
||||
/// Resolves references between assemblies and determines which
|
||||
/// additional assemblies need to be extracted.
|
||||
/// </summary>
|
||||
internal class AssemblyList
|
||||
{
|
||||
private class AssemblyNameComparer : IEqualityComparer<AssemblyName>
|
||||
{
|
||||
bool IEqualityComparer<AssemblyName>.Equals(AssemblyName? x, AssemblyName? y) =>
|
||||
object.ReferenceEquals(x, y) ||
|
||||
x?.Name == y?.Name && x?.Version == y?.Version;
|
||||
|
||||
int IEqualityComparer<AssemblyName>.GetHashCode(AssemblyName obj) =>
|
||||
(obj.Name, obj.Version).GetHashCode();
|
||||
}
|
||||
|
||||
private readonly Dictionary<AssemblyName, AssemblyInfo> assembliesRead = new Dictionary<AssemblyName, AssemblyInfo>(new AssemblyNameComparer());
|
||||
|
||||
public void AddFile(string assemblyPath, bool extractAll)
|
||||
{
|
||||
if (!filesAnalyzed.Contains(assemblyPath))
|
||||
{
|
||||
filesAnalyzed.Add(assemblyPath);
|
||||
try
|
||||
{
|
||||
var info = new AssemblyInfo(assemblyPath)
|
||||
{
|
||||
Extract = extractAll
|
||||
};
|
||||
if (!assembliesRead.ContainsKey(info.Name))
|
||||
assembliesRead.Add(info.Name, info);
|
||||
}
|
||||
catch (InvalidAssemblyException)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<AssemblyInfo> AssembliesToExtract => assembliesRead.Values.Where(info => info.Extract);
|
||||
|
||||
private IEnumerable<AssemblyName> AssembliesToReference => AssembliesToExtract.SelectMany(info => info.References);
|
||||
|
||||
public void ResolveReferences()
|
||||
{
|
||||
var assembliesToReference = new Stack<AssemblyName>(AssembliesToReference);
|
||||
|
||||
while (assembliesToReference.Any())
|
||||
{
|
||||
var item = assembliesToReference.Pop();
|
||||
if (assembliesRead.TryGetValue(item, out var info))
|
||||
{
|
||||
if (!info.Extract)
|
||||
{
|
||||
info.Extract = true;
|
||||
foreach (var reference in info.References)
|
||||
assembliesToReference.Push(reference);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MissingReferences.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly HashSet<string> filesAnalyzed = new HashSet<string>();
|
||||
public HashSet<AssemblyName> MissingReferences { get; } = new HashSet<AssemblyName>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the command line and collates a list of DLLs/EXEs to extract.
|
||||
/// </summary>
|
||||
internal class ExtractorOptions : CommonOptions
|
||||
{
|
||||
private readonly AssemblyList assemblyList = new AssemblyList();
|
||||
|
||||
public ExtractorOptions(string[] args)
|
||||
{
|
||||
this.ParseArguments(args.Append("--pdb").ToArray());
|
||||
|
||||
AddFrameworkDirectories(false);
|
||||
|
||||
assemblyList.ResolveReferences();
|
||||
AssembliesToExtract = assemblyList.AssembliesToExtract.ToArray();
|
||||
}
|
||||
|
||||
public void AddDirectory(string directory, bool extractAll)
|
||||
{
|
||||
foreach (var file in
|
||||
Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories).
|
||||
Concat(Directory.EnumerateFiles(directory, "*.exe", SearchOption.AllDirectories)))
|
||||
{
|
||||
assemblyList.AddFile(file, extractAll);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddFrameworkDirectories(bool extractAll)
|
||||
{
|
||||
AddDirectory(RuntimeEnvironment.GetRuntimeDirectory(), extractAll);
|
||||
}
|
||||
|
||||
private void AddFileOrDirectory(string path)
|
||||
{
|
||||
path = Path.GetFullPath(path);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
assemblyList.AddFile(path, true);
|
||||
var directory = Path.GetDirectoryName(path);
|
||||
if (directory is null)
|
||||
{
|
||||
throw new InternalError($"Directory of path '{path}' is null");
|
||||
}
|
||||
AddDirectory(directory, false);
|
||||
}
|
||||
else if (Directory.Exists(path))
|
||||
{
|
||||
AddDirectory(path, true);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<AssemblyInfo> AssembliesToExtract { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the assemblies that were referenced but were not available to be
|
||||
/// extracted. This is not an error, it just means that the database is not
|
||||
/// as complete as it could be.
|
||||
/// </summary>
|
||||
public IEnumerable<AssemblyName> MissingReferences => assemblyList.MissingReferences;
|
||||
|
||||
public override bool HandleFlag(string flag, bool value)
|
||||
{
|
||||
switch (flag)
|
||||
{
|
||||
case "dotnet":
|
||||
if (value)
|
||||
AddFrameworkDirectories(true);
|
||||
return true;
|
||||
default:
|
||||
return base.HandleFlag(flag, value);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool HandleArgument(string argument)
|
||||
{
|
||||
AddFileOrDirectory(argument);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void InvalidArgument(string argument) { }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Driver
|
||||
{
|
||||
public class InvalidAssemblyException : Exception
|
||||
{ }
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Driver
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
private static void DisplayHelp()
|
||||
{
|
||||
Console.WriteLine("CIL command line extractor");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Usage: Semmle.Extraction.CIL.Driver.exe [options] path ...");
|
||||
Console.WriteLine(" --verbose Turn on verbose output");
|
||||
Console.WriteLine(" --dotnet Extract the .Net Framework");
|
||||
Console.WriteLine(" --nocache Overwrite existing trap files");
|
||||
Console.WriteLine(" --no-pdb Do not extract PDB files");
|
||||
Console.WriteLine(" path A directory/dll/exe to analyze");
|
||||
}
|
||||
|
||||
private static void ExtractAssembly(string assemblyPath, ILogger logger, CommonOptions options)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
Analyser.ExtractCIL(assemblyPath, logger, options, out _, out _);
|
||||
sw.Stop();
|
||||
logger.Log(Severity.Info, " {0} ({1})", assemblyPath, sw.Elapsed);
|
||||
}
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
if (args.Length == 0)
|
||||
{
|
||||
DisplayHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
var options = new ExtractorOptions(args);
|
||||
using ILogger logger = new ConsoleLogger(options.Verbosity, logThreadId: false);
|
||||
|
||||
var actions = options.AssembliesToExtract
|
||||
.Select(asm => asm.Filename)
|
||||
.Select<string, Action>(filename => () => ExtractAssembly(filename, logger, options))
|
||||
.ToArray();
|
||||
|
||||
foreach (var missingRef in options.MissingReferences)
|
||||
logger.LogInfo(" Missing assembly " + missingRef);
|
||||
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var piOptions = new ParallelOptions
|
||||
{
|
||||
MaxDegreeOfParallelism = options.Threads
|
||||
};
|
||||
|
||||
Parallel.Invoke(piOptions, actions);
|
||||
|
||||
sw.Stop();
|
||||
logger.Log(Severity.Info, "Extraction completed in {0}", sw.Elapsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Semmle.Extraction.CIL.Driver")]
|
||||
[assembly: AssemblyDescription("Semmle CIL extractor")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Semmle Ltd")]
|
||||
[assembly: AssemblyProduct("Semmle.Extraction.CIL.Driver")]
|
||||
[assembly: AssemblyCopyright("Copyright © Semmle 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("5642ae68-9c26-43c9-bd3c-49923dddf02d")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -1,23 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Extraction.CIL.Driver</AssemblyName>
|
||||
<RootNamespace>Semmle.Extraction.CIL.Driver</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CIL\Semmle.Extraction.CIL.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,52 +0,0 @@
|
||||
using System;
|
||||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
using Semmle.Extraction.CIL.Entities;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
public static class Analyser
|
||||
{
|
||||
private static void ExtractCIL(TracingExtractor extractor, TrapWriter trapWriter, bool extractPdbs)
|
||||
{
|
||||
using var cilContext = new Context(extractor, trapWriter, extractor.OutputPath, extractPdbs);
|
||||
cilContext.Populate(new Assembly(cilContext));
|
||||
cilContext.PopulateAll();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Main entry point to the CIL extractor.
|
||||
/// Call this to extract a given assembly.
|
||||
/// </summary>
|
||||
/// <param name="layout">The trap layout.</param>
|
||||
/// <param name="assemblyPath">The full path of the assembly to extract.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="nocache">True to overwrite existing trap file.</param>
|
||||
/// <param name="extractPdbs">Whether to extract PDBs.</param>
|
||||
/// <param name="trapFile">The path of the trap file.</param>
|
||||
/// <param name="extracted">Whether the file was extracted (false=cached).</param>
|
||||
public static void ExtractCIL(string assemblyPath, ILogger logger, CommonOptions options, out string trapFile, out bool extracted)
|
||||
{
|
||||
trapFile = "";
|
||||
extracted = false;
|
||||
try
|
||||
{
|
||||
var canonicalPathCache = CanonicalPathCache.Create(logger, 1000);
|
||||
var pathTransformer = new PathTransformer(canonicalPathCache);
|
||||
var extractor = new TracingExtractor(assemblyPath, logger, pathTransformer, options);
|
||||
var transformedAssemblyPath = pathTransformer.Transform(assemblyPath);
|
||||
using var trapWriter = transformedAssemblyPath.WithSuffix(".cil").CreateTrapWriter(logger, options.TrapCompression, discardDuplicates: true);
|
||||
trapFile = trapWriter.TrapFile;
|
||||
if (!options.Cache || !System.IO.File.Exists(trapFile))
|
||||
{
|
||||
ExtractCIL(extractor, trapWriter, options.PDB);
|
||||
extracted = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
logger.LogError(string.Format("Exception extracting {0}: {1}", assemblyPath, ex));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// A factory and a cache for mapping source entities to target entities.
|
||||
/// Could be considered as a memoizer.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSrc">The type of the source.</typeparam>
|
||||
/// <typeparam name="TTarget">The type of the generated object.</typeparam>
|
||||
public class CachedFunction<TSrc, TTarget> where TSrc : notnull
|
||||
{
|
||||
private readonly Func<TSrc, TTarget> generator;
|
||||
private readonly Dictionary<TSrc, TTarget> cache;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the factory with a given mapping.
|
||||
/// </summary>
|
||||
/// <param name="g">The mapping.</param>
|
||||
public CachedFunction(Func<TSrc, TTarget> g)
|
||||
{
|
||||
generator = g;
|
||||
cache = new Dictionary<TSrc, TTarget>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the target for a given source.
|
||||
/// Create it if it does not exist.
|
||||
/// </summary>
|
||||
/// <param name="src">The source object.</param>
|
||||
/// <returns>The created object.</returns>
|
||||
public TTarget this[TSrc src]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!cache.TryGetValue(src, out var result))
|
||||
{
|
||||
result = generator(src);
|
||||
cache[src] = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A factory for mapping a pair of source entities to a target entity.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSrcEntity1">Source entity type 1.</typeparam>
|
||||
/// <typeparam name="TSrcEntity2">Source entity type 2.</typeparam>
|
||||
/// <typeparam name="TTarget">The target type.</typeparam>
|
||||
public class CachedFunction<TSrcEntity1, TSrcEntity2, TTarget>
|
||||
{
|
||||
private readonly CachedFunction<(TSrcEntity1, TSrcEntity2), TTarget> factory;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the factory with a given mapping.
|
||||
/// </summary>
|
||||
/// <param name="g">The mapping.</param>
|
||||
public CachedFunction(Func<TSrcEntity1, TSrcEntity2, TTarget> g)
|
||||
{
|
||||
factory = new CachedFunction<(TSrcEntity1, TSrcEntity2), TTarget>(p => g(p.Item1, p.Item2));
|
||||
}
|
||||
|
||||
public TTarget this[TSrcEntity1 s1, TSrcEntity2 s2] => factory[(s1, s2)];
|
||||
}
|
||||
}
|
||||
@@ -1,253 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata;
|
||||
using Semmle.Extraction.CIL.Entities;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods for creating and caching various entities.
|
||||
/// </summary>
|
||||
internal sealed partial class Context
|
||||
{
|
||||
private readonly Dictionary<object, Label> ids = new Dictionary<object, Label>();
|
||||
|
||||
internal T Populate<T>(T e) where T : IExtractedEntity
|
||||
{
|
||||
if (e.Label.Valid)
|
||||
{
|
||||
return e; // Already populated
|
||||
}
|
||||
|
||||
if (ids.TryGetValue(e, out var existing))
|
||||
{
|
||||
// It exists already
|
||||
e.Label = existing;
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Label = GetNewLabel();
|
||||
DefineLabel(e);
|
||||
ids.Add(e, e.Label);
|
||||
PopulateLater(() =>
|
||||
{
|
||||
foreach (var c in e.Contents)
|
||||
c.Extract(this);
|
||||
});
|
||||
#if DEBUG_LABELS
|
||||
using var writer = new EscapingTextWriter();
|
||||
e.WriteId(writer);
|
||||
var id = writer.ToString();
|
||||
|
||||
if (debugLabels.TryGetValue(id, out var previousEntity))
|
||||
{
|
||||
Extractor.Message(new Message("Duplicate trap ID", id, null, severity: Util.Logging.Severity.Warning));
|
||||
}
|
||||
else
|
||||
{
|
||||
debugLabels.Add(id, e);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
#if DEBUG_LABELS
|
||||
private readonly Dictionary<string, IExtractedEntity> debugLabels = new Dictionary<string, IExtractedEntity>();
|
||||
#endif
|
||||
|
||||
public IExtractedEntity Create(Handle h)
|
||||
{
|
||||
var entity = CreateGeneric(defaultGenericContext, h);
|
||||
return entity;
|
||||
}
|
||||
|
||||
// Lazily cache primitive types.
|
||||
private readonly PrimitiveType[] primitiveTypes = new PrimitiveType[(int)PrimitiveTypeCode.Object + 1];
|
||||
|
||||
public PrimitiveType Create(PrimitiveTypeCode code)
|
||||
{
|
||||
var e = primitiveTypes[(int)code];
|
||||
|
||||
if (e is null)
|
||||
{
|
||||
e = new PrimitiveType(this, code)
|
||||
{
|
||||
Label = GetNewLabel()
|
||||
};
|
||||
DefineLabel(e);
|
||||
primitiveTypes[(int)code] = e;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an entity from a Handle in a GenericContext.
|
||||
/// The type of the returned entity depends on the type of the handle.
|
||||
/// The GenericContext is needed because some handles are generics which
|
||||
/// need to be expanded in terms of the current instantiation. If this sounds
|
||||
/// complex, you are right.
|
||||
///
|
||||
/// The pair (h,genericContext) is cached in case it is needed again.
|
||||
/// </summary>
|
||||
/// <param name="h">The handle of the entity.</param>
|
||||
/// <param name="genericContext">The generic context.</param>
|
||||
/// <returns></returns>
|
||||
public IExtractedEntity CreateGeneric(IGenericContext genericContext, Handle h) => genericHandleFactory[genericContext, h];
|
||||
|
||||
private readonly IGenericContext defaultGenericContext;
|
||||
|
||||
private IExtractedEntity CreateGenericHandle(IGenericContext gc, Handle handle)
|
||||
{
|
||||
IExtractedEntity entity;
|
||||
switch (handle.Kind)
|
||||
{
|
||||
case HandleKind.MethodDefinition:
|
||||
entity = new DefinitionMethod(gc, (MethodDefinitionHandle)handle);
|
||||
break;
|
||||
case HandleKind.MemberReference:
|
||||
entity = Create(gc, (MemberReferenceHandle)handle);
|
||||
break;
|
||||
case HandleKind.MethodSpecification:
|
||||
entity = new MethodSpecificationMethod(gc, (MethodSpecificationHandle)handle);
|
||||
break;
|
||||
case HandleKind.FieldDefinition:
|
||||
entity = new DefinitionField(gc.Context, (FieldDefinitionHandle)handle);
|
||||
break;
|
||||
case HandleKind.TypeReference:
|
||||
var tr = new TypeReferenceType(this, (TypeReferenceHandle)handle);
|
||||
if (tr.TryGetPrimitiveType(out var pt))
|
||||
// Map special names like `System.Int32` to `int`
|
||||
return pt;
|
||||
entity = tr;
|
||||
break;
|
||||
case HandleKind.TypeSpecification:
|
||||
return Entities.Type.DecodeType(gc, (TypeSpecificationHandle)handle);
|
||||
case HandleKind.TypeDefinition:
|
||||
entity = new TypeDefinitionType(this, (TypeDefinitionHandle)handle);
|
||||
break;
|
||||
case HandleKind.StandaloneSignature:
|
||||
var signature = MdReader.GetStandaloneSignature((StandaloneSignatureHandle)handle);
|
||||
var method = signature.DecodeMethodSignature(gc.Context.TypeSignatureDecoder, gc);
|
||||
entity = new FunctionPointerType(this, method);
|
||||
break;
|
||||
default:
|
||||
throw new InternalError("Unhandled handle kind " + handle.Kind);
|
||||
}
|
||||
|
||||
Populate(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
private IExtractedEntity Create(IGenericContext gc, MemberReferenceHandle handle)
|
||||
{
|
||||
var mr = MdReader.GetMemberReference(handle);
|
||||
switch (mr.GetKind())
|
||||
{
|
||||
case MemberReferenceKind.Method:
|
||||
return new MemberReferenceMethod(gc, handle);
|
||||
case MemberReferenceKind.Field:
|
||||
return new MemberReferenceField(gc, handle);
|
||||
default:
|
||||
throw new InternalError("Unhandled member reference handle");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the string for a string handle.
|
||||
/// </summary>
|
||||
/// <param name="h">The string handle.</param>
|
||||
/// <returns>The string.</returns>
|
||||
public string GetString(StringHandle h) => MdReader.GetString(h);
|
||||
|
||||
#region Namespaces
|
||||
|
||||
private readonly CachedFunction<StringHandle, Namespace> namespaceFactory;
|
||||
|
||||
public Namespace CreateNamespace(StringHandle fqn) => namespaceFactory[fqn];
|
||||
|
||||
private readonly Lazy<Namespace> globalNamespace, systemNamespace;
|
||||
|
||||
/// <summary>
|
||||
/// The entity representing the global namespace.
|
||||
/// </summary>
|
||||
public Namespace GlobalNamespace => globalNamespace.Value;
|
||||
|
||||
/// <summary>
|
||||
/// The entity representing the System namespace.
|
||||
/// </summary>
|
||||
public Namespace SystemNamespace => systemNamespace.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a namespace from a fully-qualified name.
|
||||
/// </summary>
|
||||
/// <param name="fqn">The fully-qualified namespace name.</param>
|
||||
/// <returns>The namespace entity.</returns>
|
||||
private Namespace CreateNamespace(string fqn) => Populate(new Namespace(this, fqn));
|
||||
|
||||
private readonly CachedFunction<NamespaceDefinitionHandle, Namespace> namespaceDefinitionFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a namespace from a namespace handle.
|
||||
/// </summary>
|
||||
/// <param name="handle">The handle of the namespace.</param>
|
||||
/// <returns>The namespace entity.</returns>
|
||||
public Namespace Create(NamespaceDefinitionHandle handle) => namespaceDefinitionFactory[handle];
|
||||
|
||||
private Namespace CreateNamespace(NamespaceDefinitionHandle handle)
|
||||
{
|
||||
if (handle.IsNil)
|
||||
return GlobalNamespace;
|
||||
var nd = MdReader.GetNamespaceDefinition(handle);
|
||||
return Populate(new Namespace(this, GetString(nd.Name), Create(nd.Parent)));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Locations
|
||||
private readonly CachedFunction<PDB.ISourceFile, PdbSourceFile> sourceFiles;
|
||||
private readonly CachedFunction<PathTransformer.ITransformedPath, Folder> folders;
|
||||
private readonly CachedFunction<PDB.Location, PdbSourceLocation> sourceLocations;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a source file entity from a PDB source file.
|
||||
/// </summary>
|
||||
/// <param name="file">The PDB source file.</param>
|
||||
/// <returns>A source file entity.</returns>
|
||||
public PdbSourceFile CreateSourceFile(PDB.ISourceFile file) => sourceFiles[file];
|
||||
|
||||
/// <summary>
|
||||
/// Creates a folder entity with the given path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the folder.</param>
|
||||
/// <returns>A folder entity.</returns>
|
||||
public Folder CreateFolder(PathTransformer.ITransformedPath path) => folders[path];
|
||||
|
||||
/// <summary>
|
||||
/// Creates a source location.
|
||||
/// </summary>
|
||||
/// <param name="loc">The source location from PDB.</param>
|
||||
/// <returns>A source location entity.</returns>
|
||||
public PdbSourceLocation CreateSourceLocation(PDB.Location loc) => sourceLocations[loc];
|
||||
|
||||
#endregion
|
||||
|
||||
private readonly CachedFunction<IGenericContext, Handle, IExtractedEntity> genericHandleFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the short name of a member, without the preceding interface qualifier.
|
||||
/// </summary>
|
||||
/// <param name="handle">The handle of the name.</param>
|
||||
/// <returns>The short name.</returns>
|
||||
public string ShortName(StringHandle handle)
|
||||
{
|
||||
var str = MdReader.GetString(handle);
|
||||
if (str.EndsWith(".ctor"))
|
||||
return ".ctor";
|
||||
if (str.EndsWith(".cctor"))
|
||||
return ".cctor";
|
||||
var dot = str.LastIndexOf('.');
|
||||
return dot == -1 ? str : str.Substring(dot + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.PortableExecutable;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// Extraction context for CIL extraction.
|
||||
/// Adds additional context that is specific for CIL extraction.
|
||||
/// One context = one DLL/EXE.
|
||||
/// </summary>
|
||||
internal sealed partial class Context : Extraction.Context, IDisposable
|
||||
{
|
||||
private readonly FileStream stream;
|
||||
private Entities.Assembly? assemblyNull;
|
||||
public MetadataReader MdReader { get; }
|
||||
public PEReader PeReader { get; }
|
||||
public string AssemblyPath { get; }
|
||||
public Entities.Assembly Assembly
|
||||
{
|
||||
get { return assemblyNull!; }
|
||||
set { assemblyNull = value; }
|
||||
}
|
||||
public PDB.IPdb? Pdb { get; }
|
||||
|
||||
public Context(Extractor extractor, TrapWriter trapWriter, string assemblyPath, bool extractPdbs)
|
||||
: base(extractor, trapWriter)
|
||||
{
|
||||
this.AssemblyPath = assemblyPath;
|
||||
stream = File.OpenRead(assemblyPath);
|
||||
PeReader = new PEReader(stream, PEStreamOptions.PrefetchEntireImage);
|
||||
MdReader = PeReader.GetMetadataReader();
|
||||
TypeSignatureDecoder = new Entities.TypeSignatureDecoder(this);
|
||||
|
||||
globalNamespace = new Lazy<Entities.Namespace>(() => Populate(new Entities.Namespace(this, "", null)));
|
||||
systemNamespace = new Lazy<Entities.Namespace>(() => Populate(new Entities.Namespace(this, "System")));
|
||||
genericHandleFactory = new CachedFunction<IGenericContext, Handle, IExtractedEntity>(CreateGenericHandle);
|
||||
namespaceFactory = new CachedFunction<StringHandle, Entities.Namespace>(n => CreateNamespace(MdReader.GetString(n)));
|
||||
namespaceDefinitionFactory = new CachedFunction<NamespaceDefinitionHandle, Entities.Namespace>(CreateNamespace);
|
||||
sourceFiles = new CachedFunction<PDB.ISourceFile, Entities.PdbSourceFile>(path => new Entities.PdbSourceFile(this, path));
|
||||
folders = new CachedFunction<PathTransformer.ITransformedPath, Entities.Folder>(path => new Entities.Folder(this, path));
|
||||
sourceLocations = new CachedFunction<PDB.Location, Entities.PdbSourceLocation>(location => new Entities.PdbSourceLocation(this, location));
|
||||
|
||||
defaultGenericContext = new EmptyContext(this);
|
||||
|
||||
if (extractPdbs)
|
||||
{
|
||||
Pdb = PDB.PdbReader.Create(assemblyPath, PeReader);
|
||||
if (Pdb is not null)
|
||||
{
|
||||
Extractor.Logger.Log(Util.Logging.Severity.Info, string.Format("Found PDB information for {0}", assemblyPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Pdb is not null)
|
||||
Pdb.Dispose();
|
||||
PeReader.Dispose();
|
||||
stream.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract the contents of a given entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity to extract.</param>
|
||||
public void Extract(IExtractedEntity entity)
|
||||
{
|
||||
foreach (var content in entity.Contents)
|
||||
{
|
||||
content.Extract(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteAssemblyPrefix(TextWriter trapFile)
|
||||
{
|
||||
var def = MdReader.GetAssemblyDefinition();
|
||||
trapFile.Write(GetString(def.Name));
|
||||
trapFile.Write('_');
|
||||
trapFile.Write(def.Version.ToString());
|
||||
trapFile.Write(Entities.Type.AssemblyTypeNameSeparator);
|
||||
}
|
||||
|
||||
public Entities.TypeSignatureDecoder TypeSignatureDecoder { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A type used to signify something we can't handle yet.
|
||||
/// Specifically, function pointers (used in C++).
|
||||
/// </summary>
|
||||
public Entities.Type ErrorType
|
||||
{
|
||||
get
|
||||
{
|
||||
var errorType = new Entities.ErrorType(this);
|
||||
Populate(errorType);
|
||||
return errorType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to locate debugging information for a particular method.
|
||||
///
|
||||
/// Returns null on failure, for example if there was no PDB information found for the
|
||||
/// DLL, or if the particular method is compiler generated or doesn't come from source code.
|
||||
/// </summary>
|
||||
/// <param name="handle">The handle of the method.</param>
|
||||
/// <returns>The debugging information, or null if the information could not be located.</returns>
|
||||
public PDB.Method? GetMethodDebugInformation(MethodDefinitionHandle handle)
|
||||
{
|
||||
return Pdb?.GetMethod(handle.ToDebugInformationHandle());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// A generic context which does not contain any type parameters.
|
||||
/// </summary>
|
||||
internal class EmptyContext : IGenericContext
|
||||
{
|
||||
public EmptyContext(Context cx)
|
||||
{
|
||||
Context = cx;
|
||||
}
|
||||
|
||||
public Context Context { get; }
|
||||
|
||||
public IEnumerable<Entities.Type> TypeParameters { get { yield break; } }
|
||||
|
||||
public IEnumerable<Entities.Type> MethodParameters { get { yield break; } }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An array type.
|
||||
/// </summary>
|
||||
internal sealed class ArrayType : Type
|
||||
{
|
||||
private readonly Type elementType;
|
||||
private readonly int rank;
|
||||
|
||||
public ArrayType(Context cx, Type elementType, int rank) : base(cx)
|
||||
{
|
||||
this.rank = rank;
|
||||
this.elementType = elementType;
|
||||
}
|
||||
|
||||
public ArrayType(Context cx, Type elementType) : this(cx, elementType, 1)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is ArrayType array && elementType.Equals(array.elementType) && rank == array.rank;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => HashCode.Combine(elementType, rank);
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
elementType.WriteId(trapFile, inContext);
|
||||
trapFile.Write('[');
|
||||
for (var i = 1; i < rank; ++i)
|
||||
{
|
||||
trapFile.Write(',');
|
||||
}
|
||||
trapFile.Write(']');
|
||||
}
|
||||
|
||||
public override string Name => elementType.Name + "[]";
|
||||
|
||||
public override Namespace ContainingNamespace => Context.SystemNamespace;
|
||||
|
||||
public override Type? ContainingType => null;
|
||||
|
||||
public override int ThisTypeParameterCount => elementType.ThisTypeParameterCount;
|
||||
|
||||
public override CilTypeKind Kind => CilTypeKind.Array;
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments) => Context.Populate(new ArrayType(Context, elementType.Construct(typeArguments)));
|
||||
|
||||
public override Type SourceDeclaration => Context.Populate(new ArrayType(Context, elementType.SourceDeclaration));
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var c in base.Contents)
|
||||
yield return c;
|
||||
|
||||
yield return Tuples.cil_array_type(this, elementType, rank);
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile) => elementType.WriteAssemblyPrefix(trapFile);
|
||||
|
||||
public override IEnumerable<Type> GenericArguments => elementType.GenericArguments;
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => elementType.TypeParameters;
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using Semmle.Extraction.Entities;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An assembly to extract.
|
||||
/// </summary>
|
||||
internal class Assembly : LabelledEntity, ILocation
|
||||
{
|
||||
private readonly File file;
|
||||
private readonly AssemblyName assemblyName;
|
||||
|
||||
public Assembly(Context cx) : base(cx)
|
||||
{
|
||||
cx.Assembly = this;
|
||||
var def = cx.MdReader.GetAssemblyDefinition();
|
||||
|
||||
assemblyName = new AssemblyName
|
||||
{
|
||||
Name = cx.MdReader.GetString(def.Name),
|
||||
Version = def.Version,
|
||||
CultureInfo = new CultureInfo(cx.MdReader.GetString(def.Culture))
|
||||
};
|
||||
|
||||
if (!def.PublicKey.IsNil)
|
||||
assemblyName.SetPublicKey(cx.MdReader.GetBlobBytes(def.PublicKey));
|
||||
|
||||
file = new File(cx, cx.AssemblyPath);
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(FullName);
|
||||
trapFile.Write("#file:///");
|
||||
trapFile.Write(Context.AssemblyPath.Replace("\\", "/"));
|
||||
trapFile.Write(";assembly");
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return GetType() == obj?.GetType() && Equals(file, ((Assembly)obj).file);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => 7 * file.GetHashCode();
|
||||
|
||||
private string FullName => assemblyName.GetPublicKey() is null ? assemblyName.FullName + ", PublicKeyToken=null" : assemblyName.FullName;
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return file;
|
||||
yield return Tuples.assemblies(this, file, FullName, assemblyName.Name ?? string.Empty, assemblyName.Version?.ToString() ?? string.Empty);
|
||||
|
||||
if (Context.Pdb is not null)
|
||||
{
|
||||
foreach (var f in Context.Pdb.SourceFiles)
|
||||
{
|
||||
yield return Context.CreateSourceFile(f);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var handle in Context.MdReader.TypeDefinitions)
|
||||
{
|
||||
IExtractionProduct? product = null;
|
||||
try
|
||||
{
|
||||
product = Context.Create(handle);
|
||||
}
|
||||
catch (InternalError e)
|
||||
{
|
||||
Context.ExtractionError("Error processing type definition", e.Message, GeneratedLocation.Create(Context), e.StackTrace);
|
||||
}
|
||||
|
||||
// Limitation of C#: Cannot yield return inside a try-catch.
|
||||
if (product is not null)
|
||||
yield return product;
|
||||
}
|
||||
|
||||
foreach (var handle in Context.MdReader.MethodDefinitions)
|
||||
{
|
||||
IExtractionProduct? product = null;
|
||||
try
|
||||
{
|
||||
product = Context.Create(handle);
|
||||
}
|
||||
catch (InternalError e)
|
||||
{
|
||||
Context.ExtractionError("Error processing bytecode", e.Message, GeneratedLocation.Create(Context), e.StackTrace);
|
||||
}
|
||||
|
||||
if (product is not null)
|
||||
yield return product;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity representing a CIL attribute.
|
||||
/// </summary>
|
||||
internal sealed class Attribute : UnlabelledEntity
|
||||
{
|
||||
private readonly CustomAttributeHandle handle;
|
||||
private readonly CustomAttribute attrib;
|
||||
private readonly IExtractedEntity @object;
|
||||
|
||||
public Attribute(Context cx, IExtractedEntity @object, CustomAttributeHandle handle) : base(cx)
|
||||
{
|
||||
attrib = cx.MdReader.GetCustomAttribute(handle);
|
||||
this.handle = handle;
|
||||
this.@object = @object;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Attribute attribute && handle.Equals(attribute.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
var constructor = (Method)Context.Create(attrib.Constructor);
|
||||
yield return constructor;
|
||||
|
||||
yield return Tuples.cil_attribute(this, @object, constructor);
|
||||
|
||||
CustomAttributeValue<Type> decoded;
|
||||
|
||||
try
|
||||
{
|
||||
decoded = attrib.DecodeValue(new CustomAttributeDecoder(Context));
|
||||
}
|
||||
catch
|
||||
{
|
||||
Context.Extractor.Logger.Log(Util.Logging.Severity.Info,
|
||||
$"Attribute decoding is partial. Decoding attribute {constructor.DeclaringType.GetQualifiedName()} failed on {@object}.");
|
||||
yield break;
|
||||
}
|
||||
|
||||
for (var index = 0; index < decoded.FixedArguments.Length; ++index)
|
||||
{
|
||||
var stringValue = GetStringValue(decoded.FixedArguments[index].Type, decoded.FixedArguments[index].Value);
|
||||
yield return Tuples.cil_attribute_positional_argument(this, index, stringValue);
|
||||
}
|
||||
|
||||
foreach (var p in decoded.NamedArguments)
|
||||
{
|
||||
var stringValue = GetStringValue(p.Type, p.Value);
|
||||
yield return Tuples.cil_attribute_named_argument(this, p.Name!, stringValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetStringValue(Type type, object? value)
|
||||
{
|
||||
if (value is System.Collections.Immutable.ImmutableArray<CustomAttributeTypedArgument<Type>> values)
|
||||
{
|
||||
return "[" + string.Join(",", values.Select(v => GetStringValue(v.Type, v.Value))) + "]";
|
||||
}
|
||||
|
||||
if (type.GetQualifiedName() == "System.Type" &&
|
||||
value is Type t)
|
||||
{
|
||||
return t.GetQualifiedName();
|
||||
}
|
||||
|
||||
return value?.ToString() ?? "null";
|
||||
}
|
||||
|
||||
public static IEnumerable<IExtractionProduct> Populate(Context cx, IExtractedEntity @object, CustomAttributeHandleCollection attributes)
|
||||
{
|
||||
foreach (var attrib in attributes)
|
||||
{
|
||||
yield return new Attribute(cx, @object, attrib);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// A CIL entity which has been extracted.
|
||||
/// </summary>
|
||||
internal interface IExtractedEntity : IExtractionProduct, IEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// The contents of the entity.
|
||||
/// </summary>
|
||||
|
||||
IEnumerable<IExtractionProduct> Contents { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// Something that is extracted from an entity.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// The extraction algorithm proceeds as follows:
|
||||
/// - Construct entity
|
||||
/// - Call Extract()
|
||||
/// - IExtractedEntity check if already extracted
|
||||
/// - Enumerate Contents to produce more extraction products
|
||||
/// - Extract these until there is nothing left to extract
|
||||
/// </remarks>
|
||||
internal interface IExtractionProduct
|
||||
{
|
||||
/// <summary>
|
||||
/// Perform further extraction/population of this item as necessary.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="cx">The extraction context.</param>
|
||||
void Extract(Context cx);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// When we decode a type/method signature, we need access to
|
||||
/// generic parameters.
|
||||
/// </summary>
|
||||
internal interface IGenericContext
|
||||
{
|
||||
Context Context { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of generic type parameters/arguments, including type parameters/arguments of
|
||||
/// containing types.
|
||||
/// </summary>
|
||||
IEnumerable<Entities.Type> TypeParameters { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of generic method parameters/arguments.
|
||||
/// </summary>
|
||||
IEnumerable<Entities.Type> MethodParameters { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// An entity that needs to be populated during extraction.
|
||||
/// This assigns a key and optionally extracts its contents.
|
||||
/// </summary>
|
||||
internal abstract class LabelledEntity : Extraction.LabelledEntity, IExtractedEntity
|
||||
{
|
||||
public override Context Context => (Context)base.Context;
|
||||
|
||||
protected LabelledEntity(Context cx) : base(cx)
|
||||
{
|
||||
}
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException();
|
||||
|
||||
public void Extract(Context cx2)
|
||||
{
|
||||
cx2.Populate(this);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
using var writer = new EscapingTextWriter();
|
||||
WriteQuotedId(writer);
|
||||
return writer.ToString();
|
||||
}
|
||||
|
||||
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
|
||||
|
||||
public abstract IEnumerable<IExtractionProduct> Contents { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// A tuple that is an extraction product.
|
||||
/// </summary>
|
||||
internal class Tuple : IExtractionProduct
|
||||
{
|
||||
private readonly Extraction.Tuple tuple;
|
||||
|
||||
public Tuple(string name, params object[] args)
|
||||
{
|
||||
tuple = new Extraction.Tuple(name, args);
|
||||
}
|
||||
|
||||
public void Extract(Context cx)
|
||||
{
|
||||
cx.TrapWriter.Emit(tuple);
|
||||
}
|
||||
|
||||
public override string ToString() => tuple.ToString();
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// An entity that has contents to extract. There is no need to populate
|
||||
/// a key as it's done in the constructor.
|
||||
/// </summary>
|
||||
internal abstract class UnlabelledEntity : Extraction.UnlabelledEntity, IExtractedEntity
|
||||
{
|
||||
public override Context Context => (Context)base.Context;
|
||||
|
||||
protected UnlabelledEntity(Context cx) : base(cx)
|
||||
{
|
||||
}
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException();
|
||||
|
||||
public void Extract(Context cx2)
|
||||
{
|
||||
cx2.Extract(this);
|
||||
}
|
||||
|
||||
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
|
||||
|
||||
public abstract IEnumerable<IExtractionProduct> Contents { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Types that are passed by reference are not written directly to trap files. Instead, the annotation is stored on
|
||||
/// the entity.
|
||||
/// </summary>
|
||||
internal sealed class ByRefType : Type
|
||||
{
|
||||
public ByRefType(Context cx, Type elementType) : base(cx)
|
||||
{
|
||||
ElementType = elementType;
|
||||
}
|
||||
|
||||
public override CilTypeKind Kind => throw new NotImplementedException();
|
||||
|
||||
public override Namespace? ContainingNamespace => throw new NotImplementedException();
|
||||
|
||||
public override Type? ContainingType => throw new NotImplementedException();
|
||||
|
||||
public override int ThisTypeParameterCount => throw new NotImplementedException();
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
|
||||
|
||||
public override string Name => $"{ElementType.Name}&";
|
||||
|
||||
public Type ElementType { get; }
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile) => throw new NotImplementedException();
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
ElementType.WriteId(trapFile, inContext);
|
||||
trapFile.Write('&');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// The CIL database type-kind.
|
||||
/// </summary>
|
||||
public enum CilTypeKind
|
||||
{
|
||||
ValueOrRefType,
|
||||
TypeParameter,
|
||||
Array,
|
||||
Pointer,
|
||||
FunctionPointer
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A constructed type.
|
||||
/// </summary>
|
||||
internal sealed class ConstructedType : Type
|
||||
{
|
||||
private readonly Type unboundGenericType;
|
||||
|
||||
// Either null or notEmpty
|
||||
private readonly Type[]? thisTypeArguments;
|
||||
|
||||
private readonly Type? containingType;
|
||||
private readonly NamedTypeIdWriter idWriter;
|
||||
|
||||
public ConstructedType(Context cx, Type unboundType, IEnumerable<Type> typeArguments) : base(cx)
|
||||
{
|
||||
idWriter = new NamedTypeIdWriter(this);
|
||||
var suppliedArgs = typeArguments.Count();
|
||||
if (suppliedArgs != unboundType.TotalTypeParametersCount)
|
||||
throw new InternalError("Unexpected number of type arguments in ConstructedType");
|
||||
|
||||
unboundGenericType = unboundType;
|
||||
var thisParams = unboundType.ThisTypeParameterCount;
|
||||
|
||||
if (typeArguments.Count() == thisParams)
|
||||
{
|
||||
containingType = unboundType.ContainingType;
|
||||
thisTypeArguments = typeArguments.ToArray();
|
||||
}
|
||||
else if (thisParams == 0)
|
||||
{
|
||||
// all type arguments belong to containing type
|
||||
containingType = unboundType.ContainingType!.Construct(typeArguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
// some type arguments belong to containing type
|
||||
var parentParams = suppliedArgs - thisParams;
|
||||
containingType = unboundType.ContainingType!.Construct(typeArguments.Take(parentParams));
|
||||
thisTypeArguments = typeArguments.Skip(parentParams).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is ConstructedType t && Equals(unboundGenericType, t.unboundGenericType) && Equals(containingType, t.containingType))
|
||||
{
|
||||
if (thisTypeArguments is null)
|
||||
return t.thisTypeArguments is null;
|
||||
if (!(t.thisTypeArguments is null))
|
||||
return thisTypeArguments.SequenceEqual(t.thisTypeArguments);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var h = unboundGenericType.GetHashCode();
|
||||
h = 13 * h + (containingType is null ? 0 : containingType.GetHashCode());
|
||||
if (!(thisTypeArguments is null))
|
||||
h = h * 13 + thisTypeArguments.SequenceHash();
|
||||
return h;
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var c in base.Contents)
|
||||
yield return c;
|
||||
|
||||
var i = 0;
|
||||
foreach (var type in ThisTypeArguments)
|
||||
{
|
||||
yield return type;
|
||||
yield return Tuples.cil_type_argument(this, i++, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override Type SourceDeclaration => unboundGenericType;
|
||||
|
||||
public override Type? ContainingType => containingType;
|
||||
|
||||
public override string Name => unboundGenericType.Name;
|
||||
|
||||
public override Namespace ContainingNamespace => unboundGenericType.ContainingNamespace!;
|
||||
|
||||
public override CilTypeKind Kind => unboundGenericType.Kind;
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
idWriter.WriteId(trapFile, inContext);
|
||||
}
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile) => unboundGenericType.WriteAssemblyPrefix(trapFile);
|
||||
|
||||
public override int ThisTypeParameterCount => thisTypeArguments?.Length ?? 0;
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => GenericArguments;
|
||||
|
||||
public override IEnumerable<Type> ThisTypeArguments => thisTypeArguments.EnumerateNull();
|
||||
|
||||
public override IEnumerable<Type> ThisGenericArguments => thisTypeArguments.EnumerateNull();
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to decode the attribute structure.
|
||||
/// Note that there are some unhandled cases that should be fixed in due course.
|
||||
/// </summary>
|
||||
internal class CustomAttributeDecoder : ICustomAttributeTypeProvider<Type>
|
||||
{
|
||||
private readonly Context cx;
|
||||
public CustomAttributeDecoder(Context cx) { this.cx = cx; }
|
||||
|
||||
public Type GetPrimitiveType(PrimitiveTypeCode typeCode) => cx.Create(typeCode);
|
||||
|
||||
public Type GetSystemType() => new NoMetadataHandleType(cx, "System.Type");
|
||||
|
||||
public Type GetSZArrayType(Type elementType) =>
|
||||
cx.Populate(new ArrayType(cx, elementType));
|
||||
|
||||
public Type GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) =>
|
||||
(Type)cx.Create(handle);
|
||||
|
||||
public Type GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) =>
|
||||
(Type)cx.Create(handle);
|
||||
|
||||
public Type GetTypeFromSerializedName(string name) => new NoMetadataHandleType(cx, name);
|
||||
|
||||
public PrimitiveTypeCode GetUnderlyingEnumType(Type type)
|
||||
{
|
||||
if (type is TypeDefinitionType tdt &&
|
||||
tdt.GetUnderlyingEnumType() is PrimitiveTypeCode underlying)
|
||||
{
|
||||
return underlying;
|
||||
}
|
||||
|
||||
var name = type.GetQualifiedName();
|
||||
|
||||
if (wellKnownEnums.TryGetValue(name, out var code))
|
||||
{
|
||||
cx.Extractor.Logger.Log(Util.Logging.Severity.Debug, $"Using hard coded underlying enum type for {name}");
|
||||
return code;
|
||||
}
|
||||
|
||||
cx.Extractor.Logger.Log(Util.Logging.Severity.Info, $"Couldn't get underlying enum type for {name}");
|
||||
|
||||
// We can't fall back to Int32, because the type returned here defines how many bytes are read from the
|
||||
// stream and how those bytes are interpreted.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsSystemType(Type type) => type.GetQualifiedName() == "System.Type";
|
||||
|
||||
private static readonly Dictionary<string, PrimitiveTypeCode> wellKnownEnums = new Dictionary<string, PrimitiveTypeCode>
|
||||
{
|
||||
{ "System.AttributeTargets", PrimitiveTypeCode.Int32 },
|
||||
{ "System.ComponentModel.EditorBrowsableState", PrimitiveTypeCode.Int32 },
|
||||
{ "System.Diagnostics.DebuggerBrowsableState", PrimitiveTypeCode.Int32 }
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class DefinitionField : Field
|
||||
{
|
||||
private readonly Handle handle;
|
||||
private readonly FieldDefinition fd;
|
||||
|
||||
public DefinitionField(Context cx, FieldDefinitionHandle handle) : base(cx)
|
||||
{
|
||||
this.handle = handle;
|
||||
fd = Context.MdReader.GetFieldDefinition(handle);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is DefinitionField field && handle.Equals(field.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return Tuples.metadata_handle(this, Context.Assembly, MetadataTokens.GetToken(handle));
|
||||
|
||||
foreach (var c in base.Contents)
|
||||
yield return c;
|
||||
|
||||
if (fd.Attributes.HasFlag(FieldAttributes.Private))
|
||||
yield return Tuples.cil_private(this);
|
||||
|
||||
if (fd.Attributes.HasFlag(FieldAttributes.Public))
|
||||
yield return Tuples.cil_public(this);
|
||||
|
||||
if (fd.Attributes.HasFlag(FieldAttributes.Family))
|
||||
yield return Tuples.cil_protected(this);
|
||||
|
||||
if (fd.Attributes.HasFlag(FieldAttributes.Static))
|
||||
yield return Tuples.cil_static(this);
|
||||
|
||||
if (fd.Attributes.HasFlag(FieldAttributes.Assembly))
|
||||
yield return Tuples.cil_internal(this);
|
||||
|
||||
foreach (var c in Attribute.Populate(Context, this, fd.GetCustomAttributes()))
|
||||
yield return c;
|
||||
}
|
||||
}
|
||||
|
||||
public override string Name => Context.GetString(fd.Name);
|
||||
|
||||
public override Type DeclaringType => (Type)Context.Create(fd.GetDeclaringType());
|
||||
|
||||
public override Type Type => fd.DecodeSignature(Context.TypeSignatureDecoder, DeclaringType);
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
|
||||
|
||||
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -1,299 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A definition method - a method defined in the current assembly.
|
||||
/// </summary>
|
||||
internal sealed class DefinitionMethod : Method
|
||||
{
|
||||
private readonly Handle handle;
|
||||
private readonly MethodDefinition md;
|
||||
private readonly PDB.Method? methodDebugInformation;
|
||||
private readonly Type declaringType;
|
||||
|
||||
private readonly string name;
|
||||
private LocalVariable[]? locals;
|
||||
|
||||
public MethodImplementation? Implementation { get; private set; }
|
||||
|
||||
public override IList<LocalVariable>? LocalVariables => locals;
|
||||
|
||||
public DefinitionMethod(IGenericContext gc, MethodDefinitionHandle handle) : base(gc)
|
||||
{
|
||||
md = Context.MdReader.GetMethodDefinition(handle);
|
||||
this.gc = gc;
|
||||
this.handle = handle;
|
||||
name = Context.GetString(md.Name);
|
||||
|
||||
declaringType = (Type)Context.CreateGeneric(this, md.GetDeclaringType());
|
||||
|
||||
signature = md.DecodeSignature(new SignatureDecoder(), this);
|
||||
|
||||
methodDebugInformation = Context.GetMethodDebugInformation(handle);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is DefinitionMethod method && handle.Equals(method.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode();
|
||||
|
||||
public override bool IsStatic => !signature.Header.IsInstance;
|
||||
|
||||
public override Type DeclaringType => declaringType;
|
||||
|
||||
public override string Name => Context.ShortName(md.Name);
|
||||
|
||||
public override string NameLabel => name;
|
||||
|
||||
/// <summary>
|
||||
/// Holds if this method has bytecode.
|
||||
/// </summary>
|
||||
public bool HasBytecode => md.ImplAttributes == MethodImplAttributes.IL && md.RelativeVirtualAddress != 0;
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
if (md.GetGenericParameters().Any())
|
||||
{
|
||||
// We need to perform a 2-phase population because some type parameters can
|
||||
// depend on other type parameters (as a constraint).
|
||||
genericParams = new MethodTypeParameter[md.GetGenericParameters().Count];
|
||||
for (var i = 0; i < genericParams.Length; ++i)
|
||||
genericParams[i] = Context.Populate(new MethodTypeParameter(this, this, i));
|
||||
for (var i = 0; i < genericParams.Length; ++i)
|
||||
genericParams[i].PopulateHandle(md.GetGenericParameters()[i]);
|
||||
foreach (var p in genericParams)
|
||||
yield return p;
|
||||
}
|
||||
|
||||
var typeSignature = md.DecodeSignature(Context.TypeSignatureDecoder, this);
|
||||
|
||||
var parameters = GetParameterExtractionProducts(typeSignature.ParameterTypes).ToArray();
|
||||
Parameters = parameters.OfType<Parameter>().ToArray();
|
||||
|
||||
foreach (var c in parameters)
|
||||
yield return c;
|
||||
|
||||
foreach (var c in PopulateFlags)
|
||||
yield return c;
|
||||
|
||||
foreach (var p in md.GetParameters().Select(h => Context.MdReader.GetParameter(h)).Where(p => p.SequenceNumber > 0))
|
||||
{
|
||||
var pe = Parameters[IsStatic ? p.SequenceNumber - 1 : p.SequenceNumber];
|
||||
if (p.Attributes.HasFlag(ParameterAttributes.Out))
|
||||
yield return Tuples.cil_parameter_out(pe);
|
||||
if (p.Attributes.HasFlag(ParameterAttributes.In))
|
||||
yield return Tuples.cil_parameter_in(pe);
|
||||
foreach (var c in Attribute.Populate(Context, pe, p.GetCustomAttributes()))
|
||||
yield return c;
|
||||
}
|
||||
|
||||
yield return Tuples.metadata_handle(this, Context.Assembly, MetadataTokens.GetToken(handle));
|
||||
|
||||
foreach (var m in GetMethodExtractionProducts(Name, declaringType, typeSignature.ReturnType))
|
||||
{
|
||||
yield return m;
|
||||
}
|
||||
|
||||
yield return Tuples.cil_method_source_declaration(this, this);
|
||||
yield return Tuples.cil_method_location(this, Context.Assembly);
|
||||
|
||||
if (HasBytecode)
|
||||
{
|
||||
Implementation = new MethodImplementation(this);
|
||||
yield return Implementation;
|
||||
|
||||
var body = Context.PeReader.GetMethodBody(md.RelativeVirtualAddress);
|
||||
|
||||
if (!body.LocalSignature.IsNil)
|
||||
{
|
||||
var localVariableTypes = System.Collections.Immutable.ImmutableArray<Type>.Empty;
|
||||
var hasError = false;
|
||||
try
|
||||
{
|
||||
var locals = Context.MdReader.GetStandaloneSignature(body.LocalSignature);
|
||||
localVariableTypes = locals.DecodeLocalSignature(Context.TypeSignatureDecoder, this);
|
||||
}
|
||||
catch (System.BadImageFormatException exc)
|
||||
{
|
||||
Context.Extractor.Logger.Log(Util.Logging.Severity.Info,
|
||||
$"Could not decode locals in method {declaringType.GetQualifiedName()}.{name}. {exc}");
|
||||
hasError = true;
|
||||
}
|
||||
|
||||
if (!hasError)
|
||||
{
|
||||
this.locals = new LocalVariable[localVariableTypes.Length];
|
||||
|
||||
for (var l = 0; l < this.locals.Length; ++l)
|
||||
{
|
||||
var t = localVariableTypes[l];
|
||||
if (t is ByRefType brt)
|
||||
{
|
||||
t = brt.ElementType;
|
||||
this.locals[l] = Context.Populate(new LocalVariable(Context, Implementation, l, t));
|
||||
yield return this.locals[l];
|
||||
yield return Tuples.cil_type_annotation(this.locals[l], TypeAnnotation.Ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.locals[l] = Context.Populate(new LocalVariable(Context, Implementation, l, t));
|
||||
yield return this.locals[l];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var jump_table = new Dictionary<int, Instruction>();
|
||||
|
||||
foreach (var c in Decode(body.GetILBytes(), jump_table))
|
||||
yield return c;
|
||||
|
||||
var filter_index = 0;
|
||||
foreach (var region in body.ExceptionRegions)
|
||||
{
|
||||
yield return new ExceptionRegion(this, Implementation, filter_index++, region, jump_table);
|
||||
}
|
||||
|
||||
yield return Tuples.cil_method_stack_size(Implementation, body.MaxStack);
|
||||
|
||||
if (methodDebugInformation is not null)
|
||||
{
|
||||
var sourceLocation = Context.CreateSourceLocation(methodDebugInformation.Location);
|
||||
yield return sourceLocation;
|
||||
yield return Tuples.cil_method_location(this, sourceLocation);
|
||||
}
|
||||
}
|
||||
|
||||
// Flags
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.Private))
|
||||
yield return Tuples.cil_private(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.Public))
|
||||
yield return Tuples.cil_public(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.Family))
|
||||
yield return Tuples.cil_protected(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.Final))
|
||||
yield return Tuples.cil_sealed(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.Virtual))
|
||||
yield return Tuples.cil_virtual(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.Abstract))
|
||||
yield return Tuples.cil_abstract(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.HasSecurity))
|
||||
yield return Tuples.cil_security(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.RequireSecObject))
|
||||
yield return Tuples.cil_requiresecobject(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.SpecialName))
|
||||
yield return Tuples.cil_specialname(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.NewSlot))
|
||||
yield return Tuples.cil_newslot(this);
|
||||
|
||||
// Populate attributes
|
||||
foreach (var c in Attribute.Populate(Context, this, md.GetCustomAttributes()))
|
||||
yield return c;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<IExtractionProduct> Decode(byte[]? ilbytes, Dictionary<int, Instruction> jump_table)
|
||||
{
|
||||
// Sequence points are stored in order of offset.
|
||||
// We use an enumerator to locate the correct sequence point for each instruction.
|
||||
// The sequence point gives the location of each instruction.
|
||||
// The location of an instruction is given by the sequence point *after* the
|
||||
// instruction.
|
||||
IEnumerator<PDB.SequencePoint>? nextSequencePoint = null;
|
||||
PdbSourceLocation? instructionLocation = null;
|
||||
|
||||
if (methodDebugInformation is not null)
|
||||
{
|
||||
nextSequencePoint = methodDebugInformation.SequencePoints.GetEnumerator();
|
||||
if (nextSequencePoint.MoveNext())
|
||||
{
|
||||
instructionLocation = Context.CreateSourceLocation(nextSequencePoint.Current.Location);
|
||||
yield return instructionLocation;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextSequencePoint = null;
|
||||
}
|
||||
}
|
||||
|
||||
var child = 0;
|
||||
for (var offset = 0; offset < (ilbytes?.Length ?? 0);)
|
||||
{
|
||||
var instruction = new Instruction(Context, this, ilbytes!, offset, child++);
|
||||
yield return instruction;
|
||||
|
||||
if (nextSequencePoint is not null && offset >= nextSequencePoint.Current.Offset)
|
||||
{
|
||||
instructionLocation = Context.CreateSourceLocation(nextSequencePoint.Current.Location);
|
||||
yield return instructionLocation;
|
||||
if (!nextSequencePoint.MoveNext())
|
||||
nextSequencePoint = null;
|
||||
}
|
||||
|
||||
if (instructionLocation is not null)
|
||||
yield return Tuples.cil_instruction_location(instruction, instructionLocation);
|
||||
|
||||
jump_table.Add(instruction.Offset, instruction);
|
||||
offset += instruction.Width;
|
||||
}
|
||||
|
||||
foreach (var i in jump_table)
|
||||
{
|
||||
foreach (var t in i.Value.JumpContents(jump_table))
|
||||
yield return t;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display the instructions in the method in the debugger.
|
||||
/// This is only used for debugging, not in the code itself.
|
||||
/// </summary>
|
||||
public IEnumerable<Instruction> DebugInstructions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (md.ImplAttributes == MethodImplAttributes.IL && md.RelativeVirtualAddress != 0)
|
||||
{
|
||||
var body = Context.PeReader.GetMethodBody(md.RelativeVirtualAddress);
|
||||
|
||||
var ilbytes = body.GetILBytes();
|
||||
|
||||
var child = 0;
|
||||
for (var offset = 0; offset < (ilbytes?.Length ?? 0);)
|
||||
{
|
||||
Instruction decoded;
|
||||
try
|
||||
{
|
||||
decoded = new Instruction(Context, this, ilbytes!, offset, child++);
|
||||
offset += decoded.Width;
|
||||
}
|
||||
catch // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
yield return decoded;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class ErrorType : Type
|
||||
{
|
||||
public ErrorType(Context cx) : base(cx)
|
||||
{
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext) => trapFile.Write("<ErrorType>");
|
||||
|
||||
public override CilTypeKind Kind => CilTypeKind.ValueOrRefType;
|
||||
|
||||
public override string Name => "!error";
|
||||
|
||||
public override Namespace ContainingNamespace => Context.GlobalNamespace;
|
||||
|
||||
public override Type? ContainingType => null;
|
||||
|
||||
public override int ThisTypeParameterCount => 0;
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile) => throw new NotImplementedException();
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An event entity.
|
||||
/// </summary>
|
||||
internal sealed class Event : LabelledEntity
|
||||
{
|
||||
private readonly EventDefinitionHandle handle;
|
||||
private readonly Type parent;
|
||||
private readonly EventDefinition ed;
|
||||
|
||||
public Event(Context cx, Type parent, EventDefinitionHandle handle) : base(cx)
|
||||
{
|
||||
this.handle = handle;
|
||||
this.parent = parent;
|
||||
ed = cx.MdReader.GetEventDefinition(handle);
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
parent.WriteId(trapFile);
|
||||
trapFile.Write('.');
|
||||
trapFile.Write(Context.ShortName(ed.Name));
|
||||
trapFile.Write(";cil-event");
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Event e && handle.Equals(e.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
var signature = (Type)Context.CreateGeneric(parent, ed.Type);
|
||||
yield return signature;
|
||||
|
||||
yield return Tuples.cil_event(this, parent, Context.ShortName(ed.Name), signature);
|
||||
|
||||
var accessors = ed.GetAccessors();
|
||||
if (!accessors.Adder.IsNil)
|
||||
{
|
||||
var adder = (Method)Context.CreateGeneric(parent, accessors.Adder);
|
||||
yield return adder;
|
||||
yield return Tuples.cil_adder(this, adder);
|
||||
}
|
||||
|
||||
if (!accessors.Remover.IsNil)
|
||||
{
|
||||
var remover = (Method)Context.CreateGeneric(parent, accessors.Remover);
|
||||
yield return remover;
|
||||
yield return Tuples.cil_remover(this, remover);
|
||||
}
|
||||
|
||||
if (!accessors.Raiser.IsNil)
|
||||
{
|
||||
var raiser = (Method)Context.CreateGeneric(parent, accessors.Raiser);
|
||||
yield return raiser;
|
||||
yield return Tuples.cil_raiser(this, raiser);
|
||||
}
|
||||
|
||||
foreach (var c in Attribute.Populate(Context, this, ed.GetCustomAttributes()))
|
||||
yield return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception region entity.
|
||||
/// </summary>
|
||||
internal class ExceptionRegion : UnlabelledEntity
|
||||
{
|
||||
private readonly IGenericContext gc;
|
||||
private readonly MethodImplementation method;
|
||||
private readonly int index;
|
||||
private readonly System.Reflection.Metadata.ExceptionRegion r;
|
||||
private readonly Dictionary<int, Instruction> jump_table;
|
||||
|
||||
public ExceptionRegion(IGenericContext gc, MethodImplementation method, int index, System.Reflection.Metadata.ExceptionRegion r, Dictionary<int, Instruction> jump_table) : base(gc.Context)
|
||||
{
|
||||
this.gc = gc;
|
||||
this.method = method;
|
||||
this.index = index;
|
||||
this.r = r;
|
||||
this.jump_table = jump_table;
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
if (!jump_table.TryGetValue(r.TryOffset, out var try_start))
|
||||
throw new InternalError("Failed to retrieve handler");
|
||||
if (!jump_table.TryGetValue(r.TryOffset + r.TryLength, out var try_end))
|
||||
throw new InternalError("Failed to retrieve handler");
|
||||
if (!jump_table.TryGetValue(r.HandlerOffset, out var handler_start))
|
||||
throw new InternalError("Failed to retrieve handler");
|
||||
|
||||
yield return Tuples.cil_handler(this, method, index, (int)r.Kind, try_start, try_end, handler_start);
|
||||
|
||||
if (r.FilterOffset != -1)
|
||||
{
|
||||
if (!jump_table.TryGetValue(r.FilterOffset, out var filter_start))
|
||||
throw new InternalError("ExceptionRegion filter clause");
|
||||
|
||||
yield return Tuples.cil_handler_filter(this, filter_start);
|
||||
}
|
||||
|
||||
if (!r.CatchType.IsNil)
|
||||
{
|
||||
var catchType = (Type)Context.CreateGeneric(gc, r.CatchType);
|
||||
yield return catchType;
|
||||
yield return Tuples.cil_handler_type(this, catchType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An entity representing a field.
|
||||
/// </summary>
|
||||
internal abstract class Field : LabelledEntity, IGenericContext, IMember, ICustomModifierReceiver
|
||||
{
|
||||
protected Field(Context cx) : base(cx)
|
||||
{
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteSubId(DeclaringType);
|
||||
trapFile.Write('.');
|
||||
trapFile.Write(Name);
|
||||
trapFile.Write(";cil-field");
|
||||
}
|
||||
|
||||
public abstract string Name { get; }
|
||||
|
||||
public abstract Type DeclaringType { get; }
|
||||
|
||||
public abstract Type Type { get; }
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
var t = Type;
|
||||
if (t is ModifiedType mt)
|
||||
{
|
||||
t = mt.Unmodified;
|
||||
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
|
||||
}
|
||||
if (t is ByRefType brt)
|
||||
{
|
||||
t = brt.ElementType;
|
||||
yield return Tuples.cil_type_annotation(this, TypeAnnotation.Ref);
|
||||
}
|
||||
yield return Tuples.cil_field(this, DeclaringType, Name, t);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract IEnumerable<Type> TypeParameters { get; }
|
||||
|
||||
public abstract IEnumerable<Type> MethodParameters { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal class File : LabelledEntity, IFileOrFolder
|
||||
{
|
||||
protected string OriginalPath { get; }
|
||||
protected PathTransformer.ITransformedPath TransformedPath { get; }
|
||||
|
||||
public File(Context cx, string path) : base(cx)
|
||||
{
|
||||
this.OriginalPath = path;
|
||||
TransformedPath = Context.Extractor.PathTransformer.Transform(OriginalPath);
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(TransformedPath.DatabaseId);
|
||||
trapFile.Write(";sourcefile");
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return GetType() == obj?.GetType() && OriginalPath == ((File)obj).OriginalPath;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => 11 * OriginalPath.GetHashCode();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
if (TransformedPath.ParentDirectory is PathTransformer.ITransformedPath dir)
|
||||
{
|
||||
var parent = Context.CreateFolder(dir);
|
||||
yield return parent;
|
||||
yield return Tuples.containerparent(parent, this);
|
||||
}
|
||||
yield return Tuples.files(this, TransformedPath.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class Folder : LabelledEntity, IFileOrFolder
|
||||
{
|
||||
private readonly PathTransformer.ITransformedPath transformedPath;
|
||||
|
||||
public Folder(Context cx, PathTransformer.ITransformedPath path) : base(cx)
|
||||
{
|
||||
this.transformedPath = path;
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(transformedPath.DatabaseId);
|
||||
trapFile.Write(";folder");
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
if (transformedPath.ParentDirectory is PathTransformer.ITransformedPath parent)
|
||||
{
|
||||
var parentFolder = Context.CreateFolder(parent);
|
||||
yield return parentFolder;
|
||||
yield return Tuples.containerparent(parentFolder, this);
|
||||
}
|
||||
yield return Tuples.folders(this, transformedPath.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Folder folder && transformedPath == folder.transformedPath;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => transformedPath.GetHashCode();
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class FunctionPointerType : Type, IParameterizable, ICustomModifierReceiver
|
||||
{
|
||||
private readonly MethodSignature<Type> signature;
|
||||
|
||||
public FunctionPointerType(Context cx, MethodSignature<Type> signature) : base(cx)
|
||||
{
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public override CilTypeKind Kind => CilTypeKind.FunctionPointer;
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
using var id = new StringWriter();
|
||||
WriteName(
|
||||
id.Write,
|
||||
t => id.Write(t.Name),
|
||||
signature
|
||||
);
|
||||
return id.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public override Namespace? ContainingNamespace => Context.GlobalNamespace;
|
||||
|
||||
public override Type? ContainingType => null;
|
||||
|
||||
public override int ThisTypeParameterCount => throw new System.NotImplementedException();
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new System.NotImplementedException();
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments) => throw new System.NotImplementedException();
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile) { }
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
WriteName(
|
||||
trapFile.Write,
|
||||
t => t.WriteId(trapFile, inContext),
|
||||
signature
|
||||
);
|
||||
}
|
||||
|
||||
internal static void WriteName<TType>(Action<string> write, Action<TType> writeType, MethodSignature<TType> signature)
|
||||
{
|
||||
write("delegate* ");
|
||||
write(GetCallingConvention(signature.Header.CallingConvention));
|
||||
write("<");
|
||||
foreach (var pt in signature.ParameterTypes)
|
||||
{
|
||||
writeType(pt);
|
||||
write(",");
|
||||
}
|
||||
writeType(signature.ReturnType);
|
||||
write(">");
|
||||
}
|
||||
|
||||
internal static string GetCallingConvention(SignatureCallingConvention callingConvention)
|
||||
{
|
||||
if (callingConvention == SignatureCallingConvention.Default)
|
||||
{
|
||||
return "managed";
|
||||
}
|
||||
|
||||
if (callingConvention == SignatureCallingConvention.Unmanaged)
|
||||
{
|
||||
return "unmanaged";
|
||||
}
|
||||
|
||||
return $"unmanaged[{callingConvention}]";
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var c in base.Contents)
|
||||
{
|
||||
yield return c;
|
||||
}
|
||||
|
||||
var retType = signature.ReturnType;
|
||||
if (retType is ModifiedType mt)
|
||||
{
|
||||
retType = mt.Unmodified;
|
||||
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
|
||||
}
|
||||
if (retType is ByRefType byRefType)
|
||||
{
|
||||
retType = byRefType.ElementType;
|
||||
yield return Tuples.cil_type_annotation(this, TypeAnnotation.Ref);
|
||||
}
|
||||
yield return Tuples.cil_function_pointer_return_type(this, retType);
|
||||
|
||||
yield return Tuples.cil_function_pointer_calling_conventions(this, signature.Header.CallingConvention);
|
||||
|
||||
foreach (var p in Method.GetParameterExtractionProducts(signature.ParameterTypes, this, this, Context, 0))
|
||||
{
|
||||
yield return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal static class GenericsHelper
|
||||
{
|
||||
public static TypeTypeParameter[] MakeTypeParameters(Type container, int count)
|
||||
{
|
||||
var newTypeParams = new TypeTypeParameter[count];
|
||||
for (var i = 0; i < newTypeParams.Length; ++i)
|
||||
{
|
||||
newTypeParams[i] = new TypeTypeParameter(container, i);
|
||||
}
|
||||
return newTypeParams;
|
||||
}
|
||||
|
||||
public static string GetNonGenericName(StringHandle name, MetadataReader reader)
|
||||
{
|
||||
var n = reader.GetString(name);
|
||||
return GetNonGenericName(n);
|
||||
}
|
||||
|
||||
public static string GetNonGenericName(string name)
|
||||
{
|
||||
var tick = name.LastIndexOf('`');
|
||||
return tick == -1
|
||||
? name
|
||||
: name.Substring(0, tick);
|
||||
}
|
||||
|
||||
public static int GetGenericTypeParameterCount(StringHandle name, MetadataReader reader)
|
||||
{
|
||||
var n = reader.GetString(name);
|
||||
return GetGenericTypeParameterCount(n);
|
||||
}
|
||||
|
||||
public static int GetGenericTypeParameterCount(string name)
|
||||
{
|
||||
var tick = name.LastIndexOf('`');
|
||||
return tick == -1
|
||||
? 0
|
||||
: int.Parse(name.Substring(tick + 1));
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> GetAllTypeParameters(Type? container, IEnumerable<TypeTypeParameter> thisTypeParameters)
|
||||
{
|
||||
if (container is not null)
|
||||
{
|
||||
foreach (var t in container.TypeParameters)
|
||||
yield return t;
|
||||
}
|
||||
|
||||
foreach (var t in thisTypeParameters)
|
||||
yield return t;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal interface IFileOrFolder : IEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
public interface ILocation : IEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An entity representing a member.
|
||||
/// Used to type tuples correctly.
|
||||
/// </summary>
|
||||
internal interface IMember : IExtractedEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal interface IParameterizable : IEntity
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal interface ITypeSignature
|
||||
{
|
||||
void WriteId(EscapingTextWriter trapFile, IGenericContext gc);
|
||||
}
|
||||
}
|
||||
@@ -1,508 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A CIL instruction.
|
||||
/// </summary>
|
||||
internal class Instruction : UnlabelledEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// The additional data following the opcode, if any.
|
||||
/// </summary>
|
||||
public enum Payload
|
||||
{
|
||||
None, TypeTok, Field, Target8, Class,
|
||||
Method, Arg8, Local8, Target32, Int8,
|
||||
Int16, Int32, Int64, Float32, Float64,
|
||||
CallSiteDesc, Switch, String, Constructor, ValueType,
|
||||
Type, Arg16, Ignore8, Token, Local16, MethodRef
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For each Payload, how many additional bytes in the bytestream need to be read.
|
||||
/// </summary>
|
||||
private static readonly int[] payloadSizes = {
|
||||
0, 4, 4, 1, 4,
|
||||
4, 1, 1, 4, 1,
|
||||
2, 4, 8, 4, 8,
|
||||
4, -1, 4, 4, 4,
|
||||
4, 2, 1, 4, 2, 4 };
|
||||
|
||||
// Maps opcodes to payloads for each instruction.
|
||||
private static readonly Dictionary<ILOpCode, Payload> opPayload = new Dictionary<ILOpCode, Payload>()
|
||||
{
|
||||
{ ILOpCode.Nop, Payload.None },
|
||||
{ ILOpCode.Break, Payload.None },
|
||||
{ ILOpCode.Ldarg_0, Payload.None },
|
||||
{ ILOpCode.Ldarg_1, Payload.None },
|
||||
{ ILOpCode.Ldarg_2, Payload.None },
|
||||
{ ILOpCode.Ldarg_3, Payload.None },
|
||||
{ ILOpCode.Ldloc_0, Payload.None },
|
||||
{ ILOpCode.Ldloc_1, Payload.None },
|
||||
{ ILOpCode.Ldloc_2, Payload.None },
|
||||
{ ILOpCode.Ldloc_3, Payload.None },
|
||||
{ ILOpCode.Stloc_0, Payload.None },
|
||||
{ ILOpCode.Stloc_1, Payload.None },
|
||||
{ ILOpCode.Stloc_2, Payload.None },
|
||||
{ ILOpCode.Stloc_3, Payload.None },
|
||||
{ ILOpCode.Ldarg_s, Payload.Arg8 },
|
||||
{ ILOpCode.Ldarga_s, Payload.Arg8 },
|
||||
{ ILOpCode.Starg_s, Payload.Arg8 },
|
||||
{ ILOpCode.Ldloc_s, Payload.Local8 },
|
||||
{ ILOpCode.Ldloca_s, Payload.Local8 },
|
||||
{ ILOpCode.Stloc_s, Payload.Local8 },
|
||||
{ ILOpCode.Ldnull, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_m1, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_0, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_1, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_2, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_3, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_4, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_5, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_6, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_7, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_8, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_s, Payload.Int8 },
|
||||
{ ILOpCode.Ldc_i4, Payload.Int32 },
|
||||
{ ILOpCode.Ldc_i8, Payload.Int64 },
|
||||
{ ILOpCode.Ldc_r4, Payload.Float32 },
|
||||
{ ILOpCode.Ldc_r8, Payload.Float64 },
|
||||
{ ILOpCode.Dup, Payload.None },
|
||||
{ ILOpCode.Pop, Payload.None },
|
||||
{ ILOpCode.Jmp, Payload.Method },
|
||||
{ ILOpCode.Call, Payload.Method },
|
||||
{ ILOpCode.Calli, Payload.CallSiteDesc },
|
||||
{ ILOpCode.Ret, Payload.None },
|
||||
{ ILOpCode.Br_s, Payload.Target8 },
|
||||
{ ILOpCode.Brfalse_s, Payload.Target8 },
|
||||
{ ILOpCode.Brtrue_s, Payload.Target8 },
|
||||
{ ILOpCode.Beq_s, Payload.Target8 },
|
||||
{ ILOpCode.Bge_s, Payload.Target8 },
|
||||
{ ILOpCode.Bgt_s, Payload.Target8 },
|
||||
{ ILOpCode.Ble_s, Payload.Target8 },
|
||||
{ ILOpCode.Blt_s, Payload.Target8 },
|
||||
{ ILOpCode.Bne_un_s, Payload.Target8 },
|
||||
{ ILOpCode.Bge_un_s, Payload.Target8 },
|
||||
{ ILOpCode.Bgt_un_s, Payload.Target8 },
|
||||
{ ILOpCode.Ble_un_s, Payload.Target8 },
|
||||
{ ILOpCode.Blt_un_s, Payload.Target8 },
|
||||
{ ILOpCode.Br, Payload.Target32 },
|
||||
{ ILOpCode.Brfalse, Payload.Target32 },
|
||||
{ ILOpCode.Brtrue, Payload.Target32 },
|
||||
{ ILOpCode.Beq, Payload.Target32 },
|
||||
{ ILOpCode.Bge, Payload.Target32 },
|
||||
{ ILOpCode.Bgt, Payload.Target32 },
|
||||
{ ILOpCode.Ble, Payload.Target32 },
|
||||
{ ILOpCode.Blt, Payload.Target32 },
|
||||
{ ILOpCode.Bne_un, Payload.Target32 },
|
||||
{ ILOpCode.Bge_un, Payload.Target32 },
|
||||
{ ILOpCode.Bgt_un, Payload.Target32 },
|
||||
{ ILOpCode.Ble_un, Payload.Target32 },
|
||||
{ ILOpCode.Blt_un, Payload.Target32 },
|
||||
{ ILOpCode.Switch, Payload.Switch },
|
||||
{ ILOpCode.Ldind_i1, Payload.None },
|
||||
{ ILOpCode.Ldind_u1, Payload.None },
|
||||
{ ILOpCode.Ldind_i2, Payload.None },
|
||||
{ ILOpCode.Ldind_u2, Payload.None },
|
||||
{ ILOpCode.Ldind_i4, Payload.None },
|
||||
{ ILOpCode.Ldind_u4, Payload.None },
|
||||
{ ILOpCode.Ldind_i8, Payload.None },
|
||||
{ ILOpCode.Ldind_i, Payload.None },
|
||||
{ ILOpCode.Ldind_r4, Payload.None },
|
||||
{ ILOpCode.Ldind_r8, Payload.None },
|
||||
{ ILOpCode.Ldind_ref, Payload.None },
|
||||
{ ILOpCode.Stind_ref, Payload.None },
|
||||
{ ILOpCode.Stind_i1, Payload.None },
|
||||
{ ILOpCode.Stind_i2, Payload.None },
|
||||
{ ILOpCode.Stind_i4, Payload.None },
|
||||
{ ILOpCode.Stind_i8, Payload.None },
|
||||
{ ILOpCode.Stind_r4, Payload.None },
|
||||
{ ILOpCode.Stind_r8, Payload.None },
|
||||
{ ILOpCode.Add, Payload.None },
|
||||
{ ILOpCode.Sub, Payload.None },
|
||||
{ ILOpCode.Mul, Payload.None },
|
||||
{ ILOpCode.Div, Payload.None },
|
||||
{ ILOpCode.Div_un, Payload.None },
|
||||
{ ILOpCode.Rem, Payload.None },
|
||||
{ ILOpCode.Rem_un, Payload.None },
|
||||
{ ILOpCode.And, Payload.None },
|
||||
{ ILOpCode.Or, Payload.None },
|
||||
{ ILOpCode.Xor, Payload.None },
|
||||
{ ILOpCode.Shl, Payload.None },
|
||||
{ ILOpCode.Shr, Payload.None },
|
||||
{ ILOpCode.Shr_un, Payload.None },
|
||||
{ ILOpCode.Neg, Payload.None },
|
||||
{ ILOpCode.Not, Payload.None },
|
||||
{ ILOpCode.Conv_i1, Payload.None },
|
||||
{ ILOpCode.Conv_i2, Payload.None },
|
||||
{ ILOpCode.Conv_i4, Payload.None },
|
||||
{ ILOpCode.Conv_i8, Payload.None },
|
||||
{ ILOpCode.Conv_r4, Payload.None },
|
||||
{ ILOpCode.Conv_r8, Payload.None },
|
||||
{ ILOpCode.Conv_u4, Payload.None },
|
||||
{ ILOpCode.Conv_u8, Payload.None },
|
||||
{ ILOpCode.Callvirt, Payload.MethodRef },
|
||||
{ ILOpCode.Cpobj, Payload.TypeTok },
|
||||
{ ILOpCode.Ldobj, Payload.TypeTok },
|
||||
{ ILOpCode.Ldstr, Payload.String },
|
||||
{ ILOpCode.Newobj, Payload.Constructor },
|
||||
{ ILOpCode.Castclass, Payload.Class },
|
||||
{ ILOpCode.Isinst, Payload.Class },
|
||||
{ ILOpCode.Conv_r_un, Payload.None },
|
||||
{ ILOpCode.Unbox, Payload.ValueType },
|
||||
{ ILOpCode.Throw, Payload.None },
|
||||
{ ILOpCode.Ldfld, Payload.Field },
|
||||
{ ILOpCode.Ldflda, Payload.Field },
|
||||
{ ILOpCode.Stfld, Payload.Field },
|
||||
{ ILOpCode.Ldsfld, Payload.Field },
|
||||
{ ILOpCode.Ldsflda, Payload.Field },
|
||||
{ ILOpCode.Stsfld, Payload.Field },
|
||||
{ ILOpCode.Stobj, Payload.Field },
|
||||
{ ILOpCode.Conv_ovf_i1_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_i2_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_i4_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_i8_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u1_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u2_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u4_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u8_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_i_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u_un, Payload.None },
|
||||
{ ILOpCode.Box, Payload.TypeTok },
|
||||
{ ILOpCode.Newarr, Payload.TypeTok },
|
||||
{ ILOpCode.Ldlen, Payload.None },
|
||||
{ ILOpCode.Ldelema, Payload.Class },
|
||||
{ ILOpCode.Ldelem_i1, Payload.None },
|
||||
{ ILOpCode.Ldelem_u1, Payload.None },
|
||||
{ ILOpCode.Ldelem_i2, Payload.None },
|
||||
{ ILOpCode.Ldelem_u2, Payload.None },
|
||||
{ ILOpCode.Ldelem_i4, Payload.None },
|
||||
{ ILOpCode.Ldelem_u4, Payload.None },
|
||||
{ ILOpCode.Ldelem_i8, Payload.None },
|
||||
{ ILOpCode.Ldelem_i, Payload.None },
|
||||
{ ILOpCode.Ldelem_r4, Payload.None },
|
||||
{ ILOpCode.Ldelem_r8, Payload.None },
|
||||
{ ILOpCode.Ldelem_ref, Payload.None },
|
||||
{ ILOpCode.Stelem_i, Payload.None },
|
||||
{ ILOpCode.Stelem_i1, Payload.None },
|
||||
{ ILOpCode.Stelem_i2, Payload.None },
|
||||
{ ILOpCode.Stelem_i4, Payload.None },
|
||||
{ ILOpCode.Stelem_i8, Payload.None },
|
||||
{ ILOpCode.Stelem_r4, Payload.None },
|
||||
{ ILOpCode.Stelem_r8, Payload.None },
|
||||
{ ILOpCode.Stelem_ref, Payload.None },
|
||||
{ ILOpCode.Ldelem, Payload.TypeTok },
|
||||
{ ILOpCode.Stelem, Payload.TypeTok },
|
||||
{ ILOpCode.Unbox_any, Payload.TypeTok },
|
||||
{ ILOpCode.Conv_ovf_i1, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u1, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_i2, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u2, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_i4, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u4, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_i8, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u8, Payload.None },
|
||||
{ ILOpCode.Refanyval, Payload.Type },
|
||||
{ ILOpCode.Ckfinite, Payload.None },
|
||||
{ ILOpCode.Mkrefany, Payload.Class },
|
||||
{ ILOpCode.Ldtoken, Payload.Token },
|
||||
{ ILOpCode.Conv_u2, Payload.None },
|
||||
{ ILOpCode.Conv_u1, Payload.None },
|
||||
{ ILOpCode.Conv_i, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_i, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u, Payload.None },
|
||||
{ ILOpCode.Add_ovf, Payload.None },
|
||||
{ ILOpCode.Add_ovf_un, Payload.None },
|
||||
{ ILOpCode.Mul_ovf, Payload.None },
|
||||
{ ILOpCode.Mul_ovf_un, Payload.None },
|
||||
{ ILOpCode.Sub_ovf, Payload.None },
|
||||
{ ILOpCode.Sub_ovf_un, Payload.None },
|
||||
{ ILOpCode.Endfinally, Payload.None },
|
||||
{ ILOpCode.Leave, Payload.Target32 },
|
||||
{ ILOpCode.Leave_s, Payload.Target8 },
|
||||
{ ILOpCode.Stind_i, Payload.None },
|
||||
{ ILOpCode.Conv_u, Payload.None },
|
||||
{ ILOpCode.Arglist, Payload.None },
|
||||
{ ILOpCode.Ceq, Payload.None },
|
||||
{ ILOpCode.Cgt, Payload.None },
|
||||
{ ILOpCode.Cgt_un, Payload.None },
|
||||
{ ILOpCode.Clt, Payload.None },
|
||||
{ ILOpCode.Clt_un, Payload.None },
|
||||
{ ILOpCode.Ldftn, Payload.Method },
|
||||
{ ILOpCode.Ldvirtftn, Payload.Method },
|
||||
{ ILOpCode.Ldarg, Payload.Arg16 },
|
||||
{ ILOpCode.Ldarga, Payload.Arg16 },
|
||||
{ ILOpCode.Starg, Payload.Arg16 },
|
||||
{ ILOpCode.Ldloc, Payload.Local16 },
|
||||
{ ILOpCode.Ldloca, Payload.Local16 },
|
||||
{ ILOpCode.Stloc, Payload.Local16 },
|
||||
{ ILOpCode.Localloc, Payload.None },
|
||||
{ ILOpCode.Endfilter, Payload.None },
|
||||
{ ILOpCode.Unaligned, Payload.Ignore8 },
|
||||
{ ILOpCode.Volatile, Payload.None },
|
||||
{ ILOpCode.Tail, Payload.None },
|
||||
{ ILOpCode.Initobj, Payload.TypeTok },
|
||||
{ ILOpCode.Constrained, Payload.Type },
|
||||
{ ILOpCode.Cpblk, Payload.None },
|
||||
{ ILOpCode.Initblk, Payload.None },
|
||||
{ ILOpCode.Rethrow, Payload.None },
|
||||
{ ILOpCode.Sizeof, Payload.TypeTok },
|
||||
{ ILOpCode.Refanytype, Payload.None },
|
||||
{ ILOpCode.Readonly, Payload.None }
|
||||
};
|
||||
|
||||
public DefinitionMethod Method { get; }
|
||||
public ILOpCode OpCode { get; }
|
||||
public int Offset { get; }
|
||||
public int Index { get; }
|
||||
private readonly int payloadValue;
|
||||
private readonly uint unsignedPayloadValue;
|
||||
|
||||
public Payload PayloadType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!opPayload.TryGetValue(OpCode, out var result))
|
||||
throw new InternalError("Unknown op code " + OpCode);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => Index + ": " + OpCode;
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes of this instruction,
|
||||
/// including the payload (if any).
|
||||
/// </summary>
|
||||
public int Width
|
||||
{
|
||||
get
|
||||
{
|
||||
if (OpCode == ILOpCode.Switch)
|
||||
return 5 + 4 * payloadValue;
|
||||
|
||||
return ((int)OpCode > 255 ? 2 : 1) + PayloadSize;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly byte[] data;
|
||||
|
||||
private int PayloadSize => payloadSizes[(int)PayloadType];
|
||||
|
||||
/// <summary>
|
||||
/// Reads the instruction from a byte stream.
|
||||
/// </summary>
|
||||
/// <param name="data">The byte stream.</param>
|
||||
/// <param name="offset">The offset of the instruction.</param>
|
||||
/// <param name="index">The index of this instruction in the callable.</param>
|
||||
public Instruction(Context cx, DefinitionMethod method, byte[] data, int offset, int index) : base(cx)
|
||||
{
|
||||
Method = method;
|
||||
Offset = offset;
|
||||
Index = index;
|
||||
this.data = data;
|
||||
int opcode = data[offset];
|
||||
++offset;
|
||||
|
||||
/*
|
||||
* An opcode is either 1 or 2 bytes, followed by an optional payload depending on the instruction.
|
||||
* Instructions where the first byte is 0xfe are 2-byte instructions.
|
||||
*/
|
||||
if (opcode == 0xfe)
|
||||
opcode = opcode << 8 | data[offset++];
|
||||
OpCode = (ILOpCode)opcode;
|
||||
|
||||
switch (PayloadSize)
|
||||
{
|
||||
case 0:
|
||||
payloadValue = 0;
|
||||
break;
|
||||
case 1:
|
||||
payloadValue = (sbyte)data[offset];
|
||||
unsignedPayloadValue = data[offset];
|
||||
break;
|
||||
case 2:
|
||||
payloadValue = BitConverter.ToInt16(data, offset);
|
||||
unsignedPayloadValue = BitConverter.ToUInt16(data, offset);
|
||||
break;
|
||||
case -1: // Switch
|
||||
case 4:
|
||||
payloadValue = BitConverter.ToInt32(data, offset);
|
||||
break;
|
||||
case 8: // Not handled here.
|
||||
break;
|
||||
default:
|
||||
throw new InternalError("Unhandled CIL instruction Payload");
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
var offset = Offset;
|
||||
|
||||
if (Method.Implementation is null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
yield return Tuples.cil_instruction(this, (int)OpCode, Index, Method.Implementation);
|
||||
|
||||
switch (PayloadType)
|
||||
{
|
||||
case Payload.String:
|
||||
yield return Tuples.cil_value(this, Context.MdReader.GetUserString(MetadataTokens.UserStringHandle(payloadValue)));
|
||||
break;
|
||||
case Payload.Float32:
|
||||
yield return Tuples.cil_value(this, BitConverter.ToSingle(data, offset).ToString());
|
||||
break;
|
||||
case Payload.Float64:
|
||||
yield return Tuples.cil_value(this, BitConverter.ToDouble(data, offset).ToString());
|
||||
break;
|
||||
case Payload.Int8:
|
||||
yield return Tuples.cil_value(this, data[offset].ToString());
|
||||
break;
|
||||
case Payload.Int16:
|
||||
yield return Tuples.cil_value(this, BitConverter.ToInt16(data, offset).ToString());
|
||||
break;
|
||||
case Payload.Int32:
|
||||
yield return Tuples.cil_value(this, BitConverter.ToInt32(data, offset).ToString());
|
||||
break;
|
||||
case Payload.Int64:
|
||||
yield return Tuples.cil_value(this, BitConverter.ToInt64(data, offset).ToString());
|
||||
break;
|
||||
case Payload.Constructor:
|
||||
case Payload.Method:
|
||||
case Payload.MethodRef:
|
||||
case Payload.Class:
|
||||
case Payload.TypeTok:
|
||||
case Payload.Token:
|
||||
case Payload.Type:
|
||||
case Payload.Field:
|
||||
case Payload.ValueType:
|
||||
{
|
||||
// A generic EntityHandle.
|
||||
var handle = MetadataTokens.EntityHandle(payloadValue);
|
||||
var target = Context.CreateGeneric(Method, handle);
|
||||
yield return target;
|
||||
if (target is not null)
|
||||
{
|
||||
yield return Tuples.cil_access(this, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InternalError($"Unable to create payload type {PayloadType} for opcode {OpCode}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Payload.Arg8:
|
||||
case Payload.Arg16:
|
||||
if (Method.Parameters is not null)
|
||||
{
|
||||
yield return Tuples.cil_access(this, Method.Parameters[(int)unsignedPayloadValue]);
|
||||
}
|
||||
break;
|
||||
case Payload.Local8:
|
||||
case Payload.Local16:
|
||||
if (Method.LocalVariables is not null)
|
||||
{
|
||||
yield return Tuples.cil_access(this, Method.LocalVariables[(int)unsignedPayloadValue]);
|
||||
}
|
||||
break;
|
||||
case Payload.None:
|
||||
case Payload.Target8:
|
||||
case Payload.Target32:
|
||||
case Payload.Switch:
|
||||
case Payload.Ignore8:
|
||||
// These are not handled here.
|
||||
// Some of these are handled by JumpContents().
|
||||
break;
|
||||
case Payload.CallSiteDesc:
|
||||
{
|
||||
var handle = MetadataTokens.EntityHandle(payloadValue);
|
||||
IExtractedEntity? target = null;
|
||||
try
|
||||
{
|
||||
target = Context.CreateGeneric(Method, handle);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
Context.Extractor.Logger.Log(Util.Logging.Severity.Warning, $"Couldn't interpret payload of payload type {PayloadType} as a function pointer type. {exc.Message} {exc.StackTrace}");
|
||||
}
|
||||
|
||||
if (target is not null)
|
||||
{
|
||||
yield return target;
|
||||
yield return Tuples.cil_access(this, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InternalError($"Unable to create payload type {PayloadType} for opcode {OpCode}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new InternalError($"Unhandled payload type {PayloadType}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called to populate the jumps in each instruction.
|
||||
public IEnumerable<IExtractionProduct> JumpContents(Dictionary<int, Instruction> jump_table)
|
||||
{
|
||||
int target;
|
||||
Instruction? inst;
|
||||
|
||||
switch (PayloadType)
|
||||
{
|
||||
case Payload.Target8:
|
||||
target = Offset + payloadValue + 2;
|
||||
break;
|
||||
case Payload.Target32:
|
||||
target = Offset + payloadValue + 5;
|
||||
break;
|
||||
case Payload.Switch:
|
||||
var end = Offset + Width;
|
||||
|
||||
var offset = Offset + 5;
|
||||
|
||||
for (var b = 0; b < payloadValue; ++b, offset += 4)
|
||||
{
|
||||
target = BitConverter.ToInt32(data, offset) + end;
|
||||
if (jump_table.TryGetValue(target, out inst))
|
||||
{
|
||||
yield return Tuples.cil_switch(this, b, inst);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InternalError("Invalid jump target");
|
||||
}
|
||||
}
|
||||
|
||||
yield break;
|
||||
default:
|
||||
// Not a jump
|
||||
yield break;
|
||||
}
|
||||
|
||||
|
||||
if (jump_table.TryGetValue(target, out inst))
|
||||
{
|
||||
yield return Tuples.cil_jump(this, inst);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sometimes instructions can jump outside the current method.
|
||||
// TODO: Find a solution to this.
|
||||
|
||||
// For now, just log the error
|
||||
Context.ExtractionError("A CIL instruction jumps outside the current method", null, Extraction.Entities.GeneratedLocation.Create(Context), "", Util.Logging.Severity.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal class LocalVariable : LabelledEntity
|
||||
{
|
||||
private readonly MethodImplementation method;
|
||||
private readonly int index;
|
||||
private readonly Type type;
|
||||
|
||||
public LocalVariable(Context cx, MethodImplementation m, int i, Type t) : base(cx)
|
||||
{
|
||||
method = m;
|
||||
index = i;
|
||||
type = t;
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteSubId(method);
|
||||
trapFile.Write('_');
|
||||
trapFile.Write(index);
|
||||
trapFile.Write(";cil-local");
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return type;
|
||||
yield return Tuples.cil_local_variable(this, method, index, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class MemberReferenceField : Field
|
||||
{
|
||||
private readonly MemberReferenceHandle handle;
|
||||
private readonly MemberReference mr;
|
||||
private readonly IGenericContext gc;
|
||||
private readonly Type declType;
|
||||
|
||||
public MemberReferenceField(IGenericContext gc, MemberReferenceHandle handle) : base(gc.Context)
|
||||
{
|
||||
this.handle = handle;
|
||||
this.gc = gc;
|
||||
mr = Context.MdReader.GetMemberReference(handle);
|
||||
declType = (Type)Context.CreateGeneric(gc, mr.Parent);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is MemberReferenceField field && handle.Equals(field.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return handle.GetHashCode();
|
||||
}
|
||||
|
||||
public override string Name => Context.GetString(mr.Name);
|
||||
|
||||
public override Type DeclaringType => declType;
|
||||
|
||||
public override Type Type => mr.DecodeFieldSignature(Context.TypeSignatureDecoder, this);
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => gc.TypeParameters.Concat(declType.TypeParameters);
|
||||
|
||||
public override IEnumerable<Type> MethodParameters => gc.MethodParameters.Concat(declType.MethodParameters);
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a late-bound reference to a method.
|
||||
/// </summary>
|
||||
internal sealed class MemberReferenceMethod : Method
|
||||
{
|
||||
private readonly MemberReferenceHandle handle;
|
||||
private readonly MemberReference mr;
|
||||
private readonly Type declaringType;
|
||||
private readonly IGenericContext parent;
|
||||
private readonly Method? sourceDeclaration;
|
||||
|
||||
public MemberReferenceMethod(IGenericContext gc, MemberReferenceHandle handle) : base(gc)
|
||||
{
|
||||
this.handle = handle;
|
||||
this.gc = gc;
|
||||
mr = Context.MdReader.GetMemberReference(handle);
|
||||
|
||||
signature = mr.DecodeMethodSignature(new SignatureDecoder(), gc);
|
||||
|
||||
parent = (IGenericContext)Context.CreateGeneric(gc, mr.Parent);
|
||||
|
||||
var declType = parent is Method parentMethod
|
||||
? parentMethod.DeclaringType
|
||||
: parent as Type;
|
||||
|
||||
if (declType is null)
|
||||
throw new InternalError("Parent context of method is not a type");
|
||||
|
||||
declaringType = declType;
|
||||
nameLabel = Context.GetString(mr.Name);
|
||||
|
||||
var typeSourceDeclaration = declaringType.SourceDeclaration;
|
||||
sourceDeclaration = typeSourceDeclaration == declaringType ? (Method)this : typeSourceDeclaration.LookupMethod(mr.Name, mr.Signature);
|
||||
}
|
||||
|
||||
private readonly string nameLabel;
|
||||
|
||||
public override string NameLabel => nameLabel;
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is MemberReferenceMethod method && handle.Equals(method.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return handle.GetHashCode();
|
||||
}
|
||||
|
||||
public override Method? SourceDeclaration => sourceDeclaration;
|
||||
|
||||
public override bool IsStatic => !signature.Header.IsInstance;
|
||||
|
||||
public override Type DeclaringType => declaringType;
|
||||
|
||||
public override string Name => Context.ShortName(mr.Name);
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => parent.TypeParameters.Concat(gc.TypeParameters);
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
genericParams = new MethodTypeParameter[signature.GenericParameterCount];
|
||||
for (var p = 0; p < genericParams.Length; ++p)
|
||||
genericParams[p] = Context.Populate(new MethodTypeParameter(this, this, p));
|
||||
|
||||
foreach (var p in genericParams)
|
||||
yield return p;
|
||||
|
||||
var typeSignature = mr.DecodeMethodSignature(Context.TypeSignatureDecoder, this);
|
||||
|
||||
var parameters = GetParameterExtractionProducts(typeSignature.ParameterTypes).ToArray();
|
||||
Parameters = parameters.OfType<Parameter>().ToArray();
|
||||
foreach (var p in parameters) yield return p;
|
||||
|
||||
foreach (var f in PopulateFlags) yield return f;
|
||||
|
||||
foreach (var m in GetMethodExtractionProducts(Name, DeclaringType, typeSignature.ReturnType))
|
||||
{
|
||||
yield return m;
|
||||
}
|
||||
|
||||
if (SourceDeclaration is not null)
|
||||
yield return Tuples.cil_method_source_declaration(this, SourceDeclaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A method entity.
|
||||
/// </summary>
|
||||
internal abstract class Method : TypeContainer, IMember, ICustomModifierReceiver, IParameterizable
|
||||
{
|
||||
protected MethodTypeParameter[]? genericParams;
|
||||
protected IGenericContext gc;
|
||||
protected MethodSignature<ITypeSignature> signature;
|
||||
|
||||
protected Method(IGenericContext gc) : base(gc.Context)
|
||||
{
|
||||
this.gc = gc;
|
||||
}
|
||||
|
||||
public ITypeSignature ReturnType => signature.ReturnType;
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => gc.TypeParameters.Concat(DeclaringType.TypeParameters);
|
||||
|
||||
public override IEnumerable<Type> MethodParameters =>
|
||||
genericParams is null ? gc.MethodParameters : gc.MethodParameters.Concat(genericParams);
|
||||
|
||||
public int GenericParameterCount => signature.GenericParameterCount;
|
||||
|
||||
public virtual Method? SourceDeclaration => this;
|
||||
|
||||
public abstract Type DeclaringType { get; }
|
||||
public abstract string Name { get; }
|
||||
|
||||
public virtual IList<LocalVariable>? LocalVariables => throw new NotImplementedException();
|
||||
public IList<Parameter>? Parameters { get; protected set; }
|
||||
|
||||
public abstract string NameLabel { get; }
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
signature.ReturnType.WriteId(trapFile, this);
|
||||
trapFile.Write(' ');
|
||||
DeclaringType.WriteId(trapFile);
|
||||
trapFile.Write('.');
|
||||
trapFile.Write(NameLabel);
|
||||
|
||||
if (signature.GenericParameterCount > 0)
|
||||
{
|
||||
trapFile.Write('`');
|
||||
trapFile.Write(signature.GenericParameterCount);
|
||||
}
|
||||
trapFile.Write('(');
|
||||
var index = 0;
|
||||
foreach (var param in signature.ParameterTypes)
|
||||
{
|
||||
trapFile.WriteSeparator(",", ref index);
|
||||
param.WriteId(trapFile, this);
|
||||
}
|
||||
trapFile.Write(");cil-method");
|
||||
}
|
||||
|
||||
protected IEnumerable<IExtractionProduct> PopulateFlags
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsStatic)
|
||||
yield return Tuples.cil_static(this);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract bool IsStatic { get; }
|
||||
|
||||
protected IEnumerable<IExtractionProduct> GetParameterExtractionProducts(IEnumerable<Type> parameterTypes)
|
||||
{
|
||||
var i = 0;
|
||||
|
||||
if (!IsStatic)
|
||||
{
|
||||
yield return Context.Populate(new Parameter(Context, this, i++, DeclaringType));
|
||||
}
|
||||
|
||||
foreach (var p in GetParameterExtractionProducts(parameterTypes, this, this, Context, i))
|
||||
{
|
||||
yield return p;
|
||||
}
|
||||
}
|
||||
|
||||
internal static IEnumerable<IExtractionProduct> GetParameterExtractionProducts(IEnumerable<Type> parameterTypes, IParameterizable parameterizable, ICustomModifierReceiver receiver, Context cx, int firstChildIndex)
|
||||
{
|
||||
var i = firstChildIndex;
|
||||
foreach (var p in parameterTypes)
|
||||
{
|
||||
var t = p;
|
||||
if (t is ModifiedType mt)
|
||||
{
|
||||
t = mt.Unmodified;
|
||||
yield return Tuples.cil_custom_modifiers(receiver, mt.Modifier, mt.IsRequired);
|
||||
}
|
||||
if (t is ByRefType brt)
|
||||
{
|
||||
t = brt.ElementType;
|
||||
var parameter = cx.Populate(new Parameter(cx, parameterizable, i++, t));
|
||||
yield return parameter;
|
||||
yield return Tuples.cil_type_annotation(parameter, TypeAnnotation.Ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return cx.Populate(new Parameter(cx, parameterizable, i++, t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected IEnumerable<IExtractionProduct> GetMethodExtractionProducts(string name, Type declaringType, Type returnType)
|
||||
{
|
||||
var t = returnType;
|
||||
if (t is ModifiedType mt)
|
||||
{
|
||||
t = mt.Unmodified;
|
||||
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
|
||||
}
|
||||
if (t is ByRefType brt)
|
||||
{
|
||||
t = brt.ElementType;
|
||||
yield return Tuples.cil_type_annotation(this, TypeAnnotation.Ref);
|
||||
}
|
||||
yield return Tuples.cil_method(this, name, declaringType, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A method implementation entity.
|
||||
/// In the database, the same method could in principle have multiple implementations.
|
||||
/// </summary>
|
||||
internal class MethodImplementation : UnlabelledEntity
|
||||
{
|
||||
private readonly Method m;
|
||||
|
||||
public MethodImplementation(Method m) : base(m.Context)
|
||||
{
|
||||
this.m = m;
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return Tuples.cil_method_implementation(this, m, Context.Assembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A constructed method.
|
||||
/// </summary>
|
||||
internal sealed class MethodSpecificationMethod : Method
|
||||
{
|
||||
private readonly MethodSpecificationHandle handle;
|
||||
private readonly MethodSpecification ms;
|
||||
private readonly Method unboundMethod;
|
||||
private readonly ImmutableArray<Type> typeParams;
|
||||
|
||||
public MethodSpecificationMethod(IGenericContext gc, MethodSpecificationHandle handle) : base(gc)
|
||||
{
|
||||
this.handle = handle;
|
||||
ms = Context.MdReader.GetMethodSpecification(handle);
|
||||
typeParams = ms.DecodeSignature(Context.TypeSignatureDecoder, gc);
|
||||
unboundMethod = (Method)Context.CreateGeneric(gc, ms.Method);
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
unboundMethod.WriteId(trapFile);
|
||||
trapFile.Write('<');
|
||||
var index = 0;
|
||||
foreach (var param in typeParams)
|
||||
{
|
||||
trapFile.WriteSeparator(",", ref index);
|
||||
trapFile.WriteSubId(param);
|
||||
}
|
||||
trapFile.Write('>');
|
||||
}
|
||||
|
||||
public override string NameLabel => throw new NotImplementedException();
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is MethodSpecificationMethod method && handle.Equals(method.handle) && typeParams.SequenceEqual(method.typeParams);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode() * 11 + typeParams.SequenceHash();
|
||||
|
||||
public override Method SourceDeclaration => unboundMethod;
|
||||
|
||||
public override Type DeclaringType => unboundMethod.DeclaringType;
|
||||
|
||||
public override string Name => unboundMethod.Name;
|
||||
|
||||
public override bool IsStatic => unboundMethod.IsStatic;
|
||||
|
||||
public override IEnumerable<Type> MethodParameters => typeParams;
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
MethodSignature<Type> constructedTypeSignature;
|
||||
switch (ms.Method.Kind)
|
||||
{
|
||||
case HandleKind.MemberReference:
|
||||
var mr = Context.MdReader.GetMemberReference((MemberReferenceHandle)ms.Method);
|
||||
constructedTypeSignature = mr.DecodeMethodSignature(Context.TypeSignatureDecoder, this);
|
||||
break;
|
||||
case HandleKind.MethodDefinition:
|
||||
var md = Context.MdReader.GetMethodDefinition((MethodDefinitionHandle)ms.Method);
|
||||
constructedTypeSignature = md.DecodeSignature(Context.TypeSignatureDecoder, this);
|
||||
break;
|
||||
default:
|
||||
throw new InternalError($"Unexpected constructed method handle kind {ms.Method.Kind}");
|
||||
}
|
||||
|
||||
var parameters = GetParameterExtractionProducts(constructedTypeSignature.ParameterTypes).ToArray();
|
||||
Parameters = parameters.OfType<Parameter>().ToArray();
|
||||
foreach (var p in parameters)
|
||||
yield return p;
|
||||
|
||||
foreach (var f in PopulateFlags)
|
||||
yield return f;
|
||||
|
||||
foreach (var m in GetMethodExtractionProducts(Name, DeclaringType, constructedTypeSignature.ReturnType))
|
||||
{
|
||||
yield return m;
|
||||
}
|
||||
|
||||
yield return Tuples.cil_method_source_declaration(this, SourceDeclaration);
|
||||
|
||||
if (typeParams.Length != unboundMethod.GenericParameterCount)
|
||||
throw new InternalError("Method type parameter mismatch");
|
||||
|
||||
for (var p = 0; p < typeParams.Length; ++p)
|
||||
{
|
||||
yield return Tuples.cil_type_argument(this, p, typeParams[p]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class MethodTypeParameter : TypeParameter
|
||||
{
|
||||
private readonly Method method;
|
||||
private readonly int index;
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
if (!(inContext && method == gc))
|
||||
{
|
||||
trapFile.WriteSubId(method);
|
||||
}
|
||||
trapFile.Write("!");
|
||||
trapFile.Write(index);
|
||||
}
|
||||
|
||||
public override string Name => "!" + index;
|
||||
|
||||
public MethodTypeParameter(IGenericContext gc, Method m, int index) : base(gc)
|
||||
{
|
||||
method = m;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is MethodTypeParameter tp && method.Equals(tp.method) && index == tp.index;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return method.GetHashCode() * 29 + index;
|
||||
}
|
||||
|
||||
public override TypeContainer Parent => method;
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return Tuples.cil_type(this, Name, Kind, method, SourceDeclaration);
|
||||
yield return Tuples.cil_type_parameter(method, index, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Modified types are not written directly to trap files. Instead, the modifiers are stored
|
||||
/// on the modifiable entity (field type, property/method/function pointer parameter or return types).
|
||||
/// </summary>
|
||||
internal sealed class ModifiedType : Type
|
||||
{
|
||||
public ModifiedType(Context cx, Type unmodified, Type modifier, bool isRequired) : base(cx)
|
||||
{
|
||||
Unmodified = unmodified;
|
||||
Modifier = modifier;
|
||||
IsRequired = isRequired;
|
||||
}
|
||||
|
||||
public Type Unmodified { get; }
|
||||
public Type Modifier { get; }
|
||||
public bool IsRequired { get; }
|
||||
|
||||
public override CilTypeKind Kind => throw new NotImplementedException();
|
||||
|
||||
public override Namespace? ContainingNamespace => throw new NotImplementedException();
|
||||
|
||||
public override Type? ContainingType => throw new NotImplementedException();
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
|
||||
|
||||
public override int ThisTypeParameterCount => throw new NotImplementedException();
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
|
||||
|
||||
public override string Name => $"{Unmodified.Name} {(IsRequired ? "modreq" : "modopt")}({Modifier.Name})";
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile) => throw new NotImplementedException();
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
Unmodified.WriteId(trapFile, inContext);
|
||||
trapFile.Write(IsRequired ? " modreq" : " modopt");
|
||||
trapFile.Write("(");
|
||||
Modifier.WriteId(trapFile, inContext);
|
||||
trapFile.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal class NamedTypeIdWriter
|
||||
{
|
||||
private readonly Type type;
|
||||
|
||||
public NamedTypeIdWriter(Type type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
if (type.IsPrimitiveType)
|
||||
{
|
||||
Type.WritePrimitiveTypeId(trapFile, type.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
var ct = type.ContainingType;
|
||||
if (ct is not null)
|
||||
{
|
||||
ct.WriteId(trapFile, inContext);
|
||||
trapFile.Write('.');
|
||||
}
|
||||
else
|
||||
{
|
||||
type.WriteAssemblyPrefix(trapFile);
|
||||
|
||||
var ns = type.ContainingNamespace!;
|
||||
if (!ns.IsGlobalNamespace)
|
||||
{
|
||||
ns.WriteId(trapFile);
|
||||
trapFile.Write('.');
|
||||
}
|
||||
}
|
||||
|
||||
trapFile.Write(type.Name);
|
||||
|
||||
var thisTypeArguments = type.ThisTypeArguments;
|
||||
if (thisTypeArguments is not null && thisTypeArguments.Any())
|
||||
{
|
||||
trapFile.Write('<');
|
||||
var index = 0;
|
||||
foreach (var t in thisTypeArguments)
|
||||
{
|
||||
trapFile.WriteSeparator(",", ref index);
|
||||
t.WriteId(trapFile);
|
||||
}
|
||||
trapFile.Write('>');
|
||||
}
|
||||
else if (type.ThisTypeParameterCount > 0)
|
||||
{
|
||||
trapFile.Write('`');
|
||||
trapFile.Write(type.ThisTypeParameterCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A namespace.
|
||||
/// </summary>
|
||||
internal sealed class Namespace : TypeContainer
|
||||
{
|
||||
public Namespace? ParentNamespace { get; }
|
||||
public string Name { get; }
|
||||
|
||||
public bool IsGlobalNamespace => ParentNamespace is null;
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
if (ParentNamespace is not null && !ParentNamespace.IsGlobalNamespace)
|
||||
{
|
||||
ParentNamespace.WriteId(trapFile);
|
||||
trapFile.Write('.');
|
||||
}
|
||||
trapFile.Write(Name);
|
||||
trapFile.Write(";namespace");
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is Namespace ns && Name == ns.Name)
|
||||
{
|
||||
if (ParentNamespace is null)
|
||||
return ns.ParentNamespace is null;
|
||||
if (!(ns.ParentNamespace is null))
|
||||
return ParentNamespace.Equals(ns.ParentNamespace);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var h = ParentNamespace is null ? 19 : ParentNamespace.GetHashCode();
|
||||
return 13 * h + Name.GetHashCode();
|
||||
}
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
|
||||
|
||||
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
|
||||
|
||||
private static string parseNamespaceName(string fqn)
|
||||
{
|
||||
var i = fqn.LastIndexOf('.');
|
||||
return i == -1 ? fqn : fqn.Substring(i + 1);
|
||||
}
|
||||
|
||||
private static Namespace? createParentNamespace(Context cx, string fqn)
|
||||
{
|
||||
if (fqn.Length == 0)
|
||||
return null;
|
||||
var i = fqn.LastIndexOf('.');
|
||||
return i == -1 ? cx.GlobalNamespace : cx.Populate(new Namespace(cx, fqn.Substring(0, i)));
|
||||
}
|
||||
|
||||
public Namespace(Context cx, string fqn) : this(cx, parseNamespaceName(fqn), createParentNamespace(cx, fqn))
|
||||
{
|
||||
}
|
||||
|
||||
public Namespace(Context cx, string name, Namespace? parent) : base(cx)
|
||||
{
|
||||
Name = name;
|
||||
ParentNamespace = parent;
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return Tuples.namespaces(this, Name);
|
||||
if (ParentNamespace is not null)
|
||||
yield return Tuples.parent_namespace(this, ParentNamespace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed partial class NoMetadataHandleType
|
||||
{
|
||||
/// <summary>
|
||||
/// Parser to split a fully qualified name into short name, namespace or declaring type name, assembly name, and
|
||||
/// type argument names. Names are in the following format:
|
||||
/// <c>N1.N2.T1`2+T2`2[T3,[T4, A1, Version=...],T5,T6], A2, Version=...</c>
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>typeof(System.Collections.Generic.List<int>.Enumerator)
|
||||
/// -> System.Collections.Generic.List`1+Enumerator[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
|
||||
/// typeof(System.Collections.Generic.List<>.Enumerator)
|
||||
/// -> System.Collections.Generic.List`1+Enumerator, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
|
||||
/// </code>
|
||||
/// </example>
|
||||
private class FullyQualifiedNameParser
|
||||
{
|
||||
public string ShortName { get; internal set; }
|
||||
public string? AssemblyName { get; private set; }
|
||||
public IEnumerable<string>? TypeArguments { get; internal set; }
|
||||
public string? UnboundGenericTypeName { get; internal set; }
|
||||
public string ContainerName { get; internal set; }
|
||||
public bool IsContainerNamespace { get; internal set; }
|
||||
|
||||
private string AssemblySuffix => string.IsNullOrWhiteSpace(AssemblyName) ? "" : $", {AssemblyName}";
|
||||
|
||||
public FullyQualifiedNameParser(string name)
|
||||
{
|
||||
ExtractAssemblyName(ref name, out var lastBracketIndex);
|
||||
ExtractTypeArguments(ref name, lastBracketIndex, out var containerTypeArguments);
|
||||
ContainerName = ExtractContainer(ref name, containerTypeArguments);
|
||||
|
||||
ShortName = name;
|
||||
}
|
||||
|
||||
private void ExtractTypeArguments(ref string name, int lastBracketIndex, out string containerTypeArguments)
|
||||
{
|
||||
var firstBracketIndex = name.IndexOf('[');
|
||||
if (firstBracketIndex < 0)
|
||||
{
|
||||
// not generic or non-constructed generic
|
||||
TypeArguments = null;
|
||||
containerTypeArguments = "";
|
||||
UnboundGenericTypeName = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// "T3,[T4, Assembly1, Version=...],T5,T6"
|
||||
string typeArgs;
|
||||
(name, _, typeArgs, _) = name.Split(firstBracketIndex, firstBracketIndex + 1, lastBracketIndex);
|
||||
|
||||
var thisTypeArgCount = GenericsHelper.GetGenericTypeParameterCount(name);
|
||||
if (thisTypeArgCount == 0)
|
||||
{
|
||||
// not generic or non-constructed generic; container is constructed
|
||||
TypeArguments = null;
|
||||
containerTypeArguments = $"[{typeArgs}]";
|
||||
UnboundGenericTypeName = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// constructed generic
|
||||
// "T3,[T4, Assembly1, Version=...]", ["T5", "T6"]
|
||||
var (containerTypeArgs, thisTypeArgs) = ParseTypeArgumentStrings(typeArgs, thisTypeArgCount);
|
||||
|
||||
TypeArguments = thisTypeArgs;
|
||||
|
||||
containerTypeArguments = string.IsNullOrWhiteSpace(containerTypeArgs)
|
||||
? "" // containing type is not constructed generics
|
||||
: $"[{containerTypeArgs}]"; // "T3,[T4, Assembly1, Version=...],,]"
|
||||
|
||||
UnboundGenericTypeName = $"{name}{AssemblySuffix}";
|
||||
}
|
||||
|
||||
private string ExtractContainer(ref string name, string containerTypeArguments)
|
||||
{
|
||||
var lastPlusIndex = name.LastIndexOf('+');
|
||||
IsContainerNamespace = lastPlusIndex < 0;
|
||||
if (IsContainerNamespace)
|
||||
{
|
||||
return ExtractContainerNamespace(ref name);
|
||||
}
|
||||
|
||||
return ExtractContainerType(ref name, containerTypeArguments, lastPlusIndex);
|
||||
}
|
||||
|
||||
private static string ExtractContainerNamespace(ref string name)
|
||||
{
|
||||
var lastDotIndex = name.LastIndexOf('.');
|
||||
if (lastDotIndex >= 0)
|
||||
{
|
||||
string containerName;
|
||||
(containerName, _, name) = name.Split(lastDotIndex, lastDotIndex + 1);
|
||||
return containerName;
|
||||
}
|
||||
|
||||
return ""; // global namespace name
|
||||
}
|
||||
|
||||
private string ExtractContainerType(ref string name, string containerTypeArguments, int lastPlusIndex)
|
||||
{
|
||||
string containerName;
|
||||
(containerName, _, name) = name.Split(lastPlusIndex, lastPlusIndex + 1);
|
||||
return $"{containerName}{containerTypeArguments}{AssemblySuffix}";
|
||||
}
|
||||
|
||||
private void ExtractAssemblyName(ref string name, out int lastBracketIndex)
|
||||
{
|
||||
lastBracketIndex = name.LastIndexOf(']');
|
||||
var assemblyCommaIndex = name.IndexOf(',', lastBracketIndex < 0 ? 0 : lastBracketIndex);
|
||||
if (assemblyCommaIndex >= 0)
|
||||
{
|
||||
// "Assembly2, Version=..."
|
||||
(name, _, AssemblyName) = name.Split(assemblyCommaIndex, assemblyCommaIndex + 2);
|
||||
}
|
||||
}
|
||||
|
||||
private static (string, IEnumerable<string>) ParseTypeArgumentStrings(string typeArgs, int thisTypeArgCount)
|
||||
{
|
||||
var thisTypeArgs = new Stack<string>(thisTypeArgCount);
|
||||
while (typeArgs.Length > 0 && thisTypeArgCount > 0)
|
||||
{
|
||||
int startCurrentType;
|
||||
if (typeArgs[^1] != ']')
|
||||
{
|
||||
startCurrentType = typeArgs.LastIndexOf(',') + 1;
|
||||
thisTypeArgs.Push(typeArgs.Substring(startCurrentType));
|
||||
}
|
||||
else
|
||||
{
|
||||
var bracketCount = 1;
|
||||
for (startCurrentType = typeArgs.Length - 2; startCurrentType >= 0 && bracketCount > 0; startCurrentType--)
|
||||
{
|
||||
if (typeArgs[startCurrentType] == ']')
|
||||
{
|
||||
bracketCount++;
|
||||
}
|
||||
else if (typeArgs[startCurrentType] == '[')
|
||||
{
|
||||
bracketCount--;
|
||||
}
|
||||
}
|
||||
startCurrentType++;
|
||||
thisTypeArgs.Push(typeArgs[(startCurrentType + 1)..^1]);
|
||||
}
|
||||
|
||||
typeArgs = startCurrentType != 0
|
||||
? typeArgs.Substring(0, startCurrentType - 1)
|
||||
: "";
|
||||
|
||||
thisTypeArgCount--;
|
||||
}
|
||||
return (typeArgs, thisTypeArgs.ToList());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed partial class NoMetadataHandleType : Type
|
||||
{
|
||||
private readonly string originalName;
|
||||
private readonly string name;
|
||||
private readonly string? assemblyName;
|
||||
private readonly string containerName;
|
||||
private readonly bool isContainerNamespace;
|
||||
|
||||
private readonly Lazy<TypeTypeParameter[]>? typeParams;
|
||||
|
||||
// Either null or notEmpty
|
||||
private readonly Type[]? thisTypeArguments;
|
||||
private readonly Type unboundGenericType;
|
||||
private readonly Type? containingType;
|
||||
private readonly Namespace? containingNamespace;
|
||||
|
||||
private readonly NamedTypeIdWriter idWriter;
|
||||
|
||||
public NoMetadataHandleType(Context cx, string originalName) : base(cx)
|
||||
{
|
||||
this.originalName = originalName;
|
||||
this.idWriter = new NamedTypeIdWriter(this);
|
||||
|
||||
var nameParser = new FullyQualifiedNameParser(originalName);
|
||||
|
||||
name = nameParser.ShortName;
|
||||
assemblyName = nameParser.AssemblyName;
|
||||
isContainerNamespace = nameParser.IsContainerNamespace;
|
||||
containerName = nameParser.ContainerName;
|
||||
|
||||
unboundGenericType = nameParser.UnboundGenericTypeName is null
|
||||
? this
|
||||
: new NoMetadataHandleType(Context, nameParser.UnboundGenericTypeName);
|
||||
|
||||
if (nameParser.TypeArguments is not null)
|
||||
{
|
||||
thisTypeArguments = nameParser.TypeArguments.Select(t => new NoMetadataHandleType(Context, t)).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
typeParams = new Lazy<TypeTypeParameter[]>(GenericsHelper.MakeTypeParameters(this, ThisTypeParameterCount));
|
||||
}
|
||||
|
||||
containingType = isContainerNamespace
|
||||
? null
|
||||
: new NoMetadataHandleType(Context, containerName);
|
||||
|
||||
containingNamespace = isContainerNamespace
|
||||
? containerName == Context.GlobalNamespace.Name
|
||||
? Context.GlobalNamespace
|
||||
: containerName == Context.SystemNamespace.Name
|
||||
? Context.SystemNamespace
|
||||
: new Namespace(Context, containerName)
|
||||
: null;
|
||||
|
||||
Populate();
|
||||
}
|
||||
|
||||
private void Populate()
|
||||
{
|
||||
if (ContainingNamespace is not null)
|
||||
{
|
||||
Context.Populate(ContainingNamespace);
|
||||
}
|
||||
|
||||
Context.Populate(this);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is NoMetadataHandleType t && originalName.Equals(t.originalName, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return originalName.GetHashCode(StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var tp in typeParams?.Value ?? Array.Empty<TypeTypeParameter>())
|
||||
yield return tp;
|
||||
|
||||
foreach (var c in base.Contents)
|
||||
yield return c;
|
||||
|
||||
var i = 0;
|
||||
foreach (var type in ThisTypeArguments)
|
||||
{
|
||||
yield return type;
|
||||
yield return Tuples.cil_type_argument(this, i++, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override CilTypeKind Kind => CilTypeKind.ValueOrRefType;
|
||||
|
||||
public override string Name => GenericsHelper.GetNonGenericName(name);
|
||||
|
||||
public override Namespace? ContainingNamespace => containingNamespace;
|
||||
|
||||
public override Type? ContainingType => containingType;
|
||||
|
||||
public override Type SourceDeclaration => unboundGenericType;
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments)
|
||||
{
|
||||
if (TotalTypeParametersCount != typeArguments.Count())
|
||||
throw new InternalError("Mismatched type arguments");
|
||||
|
||||
return Context.Populate(new ConstructedType(Context, this, typeArguments));
|
||||
}
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(assemblyName))
|
||||
{
|
||||
var an = new AssemblyName(assemblyName);
|
||||
trapFile.Write(an.Name);
|
||||
trapFile.Write('_');
|
||||
trapFile.Write((an.Version ?? new Version(0, 0, 0, 0)).ToString());
|
||||
trapFile.Write(Type.AssemblyTypeNameSeparator);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.WriteAssemblyPrefix(trapFile);
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
idWriter.WriteId(trapFile, inContext);
|
||||
}
|
||||
|
||||
public override int ThisTypeParameterCount => unboundGenericType == this
|
||||
? GenericsHelper.GetGenericTypeParameterCount(name)
|
||||
: thisTypeArguments!.Length;
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => unboundGenericType == this
|
||||
? GenericsHelper.GetAllTypeParameters(containingType, typeParams!.Value)
|
||||
: GenericArguments;
|
||||
|
||||
public override IEnumerable<Type> ThisTypeArguments => unboundGenericType == this
|
||||
? base.ThisTypeArguments
|
||||
: thisTypeArguments!;
|
||||
|
||||
public override IEnumerable<Type> ThisGenericArguments => unboundGenericType == this
|
||||
? typeParams!.Value
|
||||
: thisTypeArguments!;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A parameter entity.
|
||||
/// </summary>
|
||||
internal sealed class Parameter : LabelledEntity
|
||||
{
|
||||
private readonly IParameterizable parameterizable;
|
||||
private readonly int index;
|
||||
private readonly Type type;
|
||||
|
||||
public Parameter(Context cx, IParameterizable p, int i, Type t) : base(cx)
|
||||
{
|
||||
parameterizable = p;
|
||||
index = i;
|
||||
type = t;
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteSubId(parameterizable);
|
||||
trapFile.Write('_');
|
||||
trapFile.Write(index);
|
||||
trapFile.Write(";cil-parameter");
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Parameter param && parameterizable.Equals(param.parameterizable) && index == param.index;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return 23 * parameterizable.GetHashCode() + index;
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return Tuples.cil_parameter(this, parameterizable, index, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal class PdbSourceFile : File
|
||||
{
|
||||
private readonly PDB.ISourceFile file;
|
||||
|
||||
public PdbSourceFile(Context cx, PDB.ISourceFile file) : base(cx, file.Path)
|
||||
{
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var c in base.Contents)
|
||||
yield return c;
|
||||
|
||||
var text = file.Contents;
|
||||
|
||||
if (text is null)
|
||||
Context.Extractor.Logger.Log(Util.Logging.Severity.Warning, string.Format("PDB source file {0} could not be found", OriginalPath));
|
||||
else
|
||||
Context.TrapWriter.Archive(TransformedPath, text);
|
||||
|
||||
yield return Tuples.file_extraction_mode(this, Context.Extractor.Mode | ExtractorMode.Pdb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class PointerType : Type
|
||||
{
|
||||
private readonly Type pointee;
|
||||
|
||||
public PointerType(Context cx, Type pointee) : base(cx)
|
||||
{
|
||||
this.pointee = pointee;
|
||||
|
||||
if (pointee is ModifiedType mt)
|
||||
{
|
||||
cx.Extractor.Logger.Log(
|
||||
Util.Logging.Severity.Info,
|
||||
$"Pointer to modified type {pointee.GetQualifiedName()} is changed to {mt.Unmodified.GetQualifiedName()}");
|
||||
this.pointee = mt.Unmodified;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is PointerType pt && pointee.Equals(pt.pointee);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => HashCode.Combine(pointee, nameof(PointerType));
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
pointee.WriteId(trapFile, inContext);
|
||||
trapFile.Write('*');
|
||||
}
|
||||
|
||||
public override string Name => pointee.Name + "*";
|
||||
|
||||
public override Namespace? ContainingNamespace => pointee.ContainingNamespace;
|
||||
|
||||
public override Type? ContainingType => pointee.ContainingType;
|
||||
|
||||
public override TypeContainer Parent => pointee.Parent;
|
||||
|
||||
public override int ThisTypeParameterCount => 0;
|
||||
|
||||
public override CilTypeKind Kind => CilTypeKind.Pointer;
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile) => pointee.WriteAssemblyPrefix(trapFile);
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var c in base.Contents) yield return c;
|
||||
yield return Tuples.cil_pointer_type(this, pointee);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user