mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Merge remote-tracking branch 'upstream/master' into XssDom
This commit is contained in:
@@ -25,6 +25,7 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
|
||||
| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | | This query is no longer run on LGTM. |
|
||||
| No space for zero terminator (`cpp/no-space-for-terminator`) | Fewer false positive results | This query has been modified to be more conservative when identifying which pointers point to null-terminated strings. This approach produces fewer, more accurate results. |
|
||||
| Overflow in uncontrolled allocation size (`cpp/uncontrolled-allocation-size`) | Fewer false positive results | Cases where the tainted allocation size is range checked are now more reliably excluded. |
|
||||
| Overflow in uncontrolled allocation size (`cpp/uncontrolled-allocation-size`) | Fewer false positive results | The query now produces fewer, more accurate results. |
|
||||
| Overloaded assignment does not return 'this' (`cpp/assignment-does-not-return-this`) | Fewer false positive results | This query no longer reports incorrect results in template classes. |
|
||||
| Unsafe array for days of the year (`cpp/leap-year/unsafe-array-for-days-of-the-year`) | | This query is no longer run on LGTM. |
|
||||
| Unsigned comparison to zero (`cpp/unsigned-comparison-zero`) | More correct results | This query now also looks for comparisons of the form `0 <= x`. |
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
| Useless regular-expression character escape (`js/useless-regexp-character-escape`) | Fewer false positive results | This query now distinguishes escapes in strings and regular expression literals. |
|
||||
| Identical operands (`js/redundant-operation`) | Fewer results | This query now recognizes cases where the operands change a value using ++/-- expressions. |
|
||||
| Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer results | This query now recognizes cases where a function uses the `Function.arguments` value to process a variable number of parameters. |
|
||||
| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes more variations of URL scheme checks. |
|
||||
| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional variations of URL scheme checks. |
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
|
||||
22
change-notes/1.25/analysis-javascript.md
Normal file
22
change-notes/1.25/analysis-javascript.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Improvements to JavaScript analysis
|
||||
|
||||
## General improvements
|
||||
|
||||
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|--------------------------------|------------------------------|---------------------------------------------------------------------------|
|
||||
| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. |
|
||||
| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. |
|
||||
| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. |
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
* Added data flow for `Map` and `Set`, and added matching type-tracking steps that can accessed using the `CollectionsTypeTracking` module.
|
||||
@@ -15,31 +15,31 @@ import cpp
|
||||
import semmle.code.cpp.security.TaintTracking
|
||||
import TaintedWithPath
|
||||
|
||||
predicate taintedChild(Expr e, Expr tainted) {
|
||||
(
|
||||
isAllocationExpr(e)
|
||||
or
|
||||
any(MulExpr me | me.getAChild() instanceof SizeofOperator) = e
|
||||
) and
|
||||
tainted = e.getAChild() and
|
||||
/**
|
||||
* Holds if `alloc` is an allocation, and `tainted` is a child of it that is a
|
||||
* taint sink.
|
||||
*/
|
||||
predicate allocSink(Expr alloc, Expr tainted) {
|
||||
isAllocationExpr(alloc) and
|
||||
tainted = alloc.getAChild() and
|
||||
tainted.getUnspecifiedType() instanceof IntegralType
|
||||
}
|
||||
|
||||
class TaintedAllocationSizeConfiguration extends TaintTrackingConfiguration {
|
||||
override predicate isSink(Element tainted) { taintedChild(_, tainted) }
|
||||
override predicate isSink(Element tainted) { allocSink(_, tainted) }
|
||||
}
|
||||
|
||||
predicate taintedAllocSize(
|
||||
Expr e, Expr source, PathNode sourceNode, PathNode sinkNode, string taintCause
|
||||
Expr source, Expr alloc, PathNode sourceNode, PathNode sinkNode, string taintCause
|
||||
) {
|
||||
isUserInput(source, taintCause) and
|
||||
exists(Expr tainted |
|
||||
taintedChild(e, tainted) and
|
||||
allocSink(alloc, tainted) and
|
||||
taintedWithPath(source, tainted, sourceNode, sinkNode)
|
||||
)
|
||||
}
|
||||
|
||||
from Expr e, Expr source, PathNode sourceNode, PathNode sinkNode, string taintCause
|
||||
where taintedAllocSize(e, source, sourceNode, sinkNode, taintCause)
|
||||
select e, sourceNode, sinkNode, "This allocation size is derived from $@ and might overflow",
|
||||
from Expr source, Expr alloc, PathNode sourceNode, PathNode sinkNode, string taintCause
|
||||
where taintedAllocSize(source, alloc, sourceNode, sinkNode, taintCause)
|
||||
select alloc, sourceNode, sinkNode, "This allocation size is derived from $@ and might overflow",
|
||||
source, "user input (" + taintCause + ")"
|
||||
|
||||
@@ -697,28 +697,188 @@ class Int128Type extends IntegralType {
|
||||
override string getCanonicalQLClass() { result = "Int128Type" }
|
||||
}
|
||||
|
||||
private newtype TTypeDomain =
|
||||
TRealDomain() or
|
||||
TComplexDomain() or
|
||||
TImaginaryDomain()
|
||||
|
||||
/**
|
||||
* The C/C++ floating point types. See 4.5. This includes `float`,
|
||||
* `double` and `long double` types.
|
||||
* ```
|
||||
* float f;
|
||||
* double d;
|
||||
* long double ld;
|
||||
* ```
|
||||
* The type domain of a floating-point type. One of `RealDomain`, `ComplexDomain`, or
|
||||
* `ImaginaryDomain`.
|
||||
*/
|
||||
class TypeDomain extends TTypeDomain {
|
||||
/** Gets a textual representation of this type domain. */
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The type domain of a floating-point type that represents a real number.
|
||||
*/
|
||||
class RealDomain extends TypeDomain, TRealDomain {
|
||||
final override string toString() { result = "real" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The type domain of a floating-point type that represents a complex number.
|
||||
*/
|
||||
class ComplexDomain extends TypeDomain, TComplexDomain {
|
||||
final override string toString() { result = "complex" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The type domain of a floating-point type that represents an imaginary number.
|
||||
*/
|
||||
class ImaginaryDomain extends TypeDomain, TImaginaryDomain {
|
||||
final override string toString() { result = "imaginary" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Data for floating-point types.
|
||||
*
|
||||
* kind: The original type kind. Can be any floating-point type kind.
|
||||
* base: The numeric base of the number's representation. Can be 2 (binary) or 10 (decimal).
|
||||
* domain: The type domain of the type. Can be `RealDomain`, `ComplexDomain`, or `ImaginaryDomain`.
|
||||
* realKind: The type kind of the corresponding real type. For example, the corresponding real type
|
||||
* of `_Complex double` is `double`.
|
||||
* extended: `true` if the number is an extended-precision floating-point number, such as
|
||||
* `_Float32x`.
|
||||
*/
|
||||
private predicate floatingPointTypeMapping(
|
||||
int kind, int base, TTypeDomain domain, int realKind, boolean extended
|
||||
) {
|
||||
// float
|
||||
kind = 24 and base = 2 and domain = TRealDomain() and realKind = 24 and extended = false
|
||||
or
|
||||
// double
|
||||
kind = 25 and base = 2 and domain = TRealDomain() and realKind = 25 and extended = false
|
||||
or
|
||||
// long double
|
||||
kind = 26 and base = 2 and domain = TRealDomain() and realKind = 26 and extended = false
|
||||
or
|
||||
// _Complex float
|
||||
kind = 27 and base = 2 and domain = TComplexDomain() and realKind = 24 and extended = false
|
||||
or
|
||||
// _Complex double
|
||||
kind = 28 and base = 2 and domain = TComplexDomain() and realKind = 25 and extended = false
|
||||
or
|
||||
// _Complex long double
|
||||
kind = 29 and base = 2 and domain = TComplexDomain() and realKind = 26 and extended = false
|
||||
or
|
||||
// _Imaginary float
|
||||
kind = 30 and base = 2 and domain = TImaginaryDomain() and realKind = 24 and extended = false
|
||||
or
|
||||
// _Imaginary double
|
||||
kind = 31 and base = 2 and domain = TImaginaryDomain() and realKind = 25 and extended = false
|
||||
or
|
||||
// _Imaginary long double
|
||||
kind = 32 and base = 2 and domain = TImaginaryDomain() and realKind = 26 and extended = false
|
||||
or
|
||||
// __float128
|
||||
kind = 38 and base = 2 and domain = TRealDomain() and realKind = 38 and extended = false
|
||||
or
|
||||
// _Complex __float128
|
||||
kind = 39 and base = 2 and domain = TComplexDomain() and realKind = 38 and extended = false
|
||||
or
|
||||
// _Decimal32
|
||||
kind = 40 and base = 10 and domain = TRealDomain() and realKind = 40 and extended = false
|
||||
or
|
||||
// _Decimal64
|
||||
kind = 41 and base = 10 and domain = TRealDomain() and realKind = 41 and extended = false
|
||||
or
|
||||
// _Decimal128
|
||||
kind = 42 and base = 10 and domain = TRealDomain() and realKind = 42 and extended = false
|
||||
or
|
||||
// _Float32
|
||||
kind = 45 and base = 2 and domain = TRealDomain() and realKind = 45 and extended = false
|
||||
or
|
||||
// _Float32x
|
||||
kind = 46 and base = 2 and domain = TRealDomain() and realKind = 46 and extended = true
|
||||
or
|
||||
// _Float64
|
||||
kind = 47 and base = 2 and domain = TRealDomain() and realKind = 47 and extended = false
|
||||
or
|
||||
// _Float64x
|
||||
kind = 48 and base = 2 and domain = TRealDomain() and realKind = 48 and extended = true
|
||||
or
|
||||
// _Float128
|
||||
kind = 49 and base = 2 and domain = TRealDomain() and realKind = 49 and extended = false
|
||||
or
|
||||
// _Float128x
|
||||
kind = 50 and base = 2 and domain = TRealDomain() and realKind = 50 and extended = true
|
||||
}
|
||||
|
||||
/**
|
||||
* The C/C++ floating point types. See 4.5. This includes `float`, `double` and `long double`, the
|
||||
* fixed-size floating-point types like `_Float32`, the extended-precision floating-point types like
|
||||
* `_Float64x`, and the decimal floating-point types like `_Decimal32`. It also includes the complex
|
||||
* and imaginary versions of all of these types.
|
||||
*/
|
||||
class FloatingPointType extends ArithmeticType {
|
||||
final int base;
|
||||
final TypeDomain domain;
|
||||
final int realKind;
|
||||
final boolean extended;
|
||||
|
||||
FloatingPointType() {
|
||||
exists(int kind |
|
||||
builtintypes(underlyingElement(this), _, kind, _, _, _) and
|
||||
(
|
||||
kind >= 24 and kind <= 32
|
||||
or
|
||||
kind >= 38 and kind <= 42
|
||||
or
|
||||
kind >= 45 and kind <= 50
|
||||
)
|
||||
floatingPointTypeMapping(kind, base, domain, realKind, extended)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the numeric base of this type's representation: 2 (binary) or 10 (decimal). */
|
||||
final int getBase() { result = base }
|
||||
|
||||
/**
|
||||
* Gets the type domain of this type. Can be `RealDomain`, `ComplexDomain`, or `ImaginaryDomain`.
|
||||
*/
|
||||
final TypeDomain getDomain() { result = domain }
|
||||
|
||||
/**
|
||||
* Gets the corresponding real type of this type. For example, the corresponding real type of
|
||||
* `_Complex double` is `double`.
|
||||
*/
|
||||
final RealNumberType getRealType() {
|
||||
builtintypes(unresolveElement(result), _, realKind, _, _, _)
|
||||
}
|
||||
|
||||
/** Holds if this type is an extended precision floating-point type, such as `_Float32x`. */
|
||||
final predicate isExtendedPrecision() { extended = true }
|
||||
}
|
||||
|
||||
/**
|
||||
* A floating-point type representing a real number.
|
||||
*/
|
||||
class RealNumberType extends FloatingPointType {
|
||||
RealNumberType() { domain instanceof RealDomain }
|
||||
}
|
||||
|
||||
/**
|
||||
* A floating-point type representing a complex number.
|
||||
*/
|
||||
class ComplexNumberType extends FloatingPointType {
|
||||
ComplexNumberType() { domain instanceof ComplexDomain }
|
||||
}
|
||||
|
||||
/**
|
||||
* A floating-point type representing an imaginary number.
|
||||
*/
|
||||
class ImaginaryNumberType extends FloatingPointType {
|
||||
ImaginaryNumberType() { domain instanceof ImaginaryDomain }
|
||||
}
|
||||
|
||||
/**
|
||||
* A floating-point type whose representation is base 2.
|
||||
*/
|
||||
class BinaryFloatingPointType extends FloatingPointType {
|
||||
BinaryFloatingPointType() { base = 2 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A floating-point type whose representation is base 10.
|
||||
*/
|
||||
class DecimalFloatingPointType extends FloatingPointType {
|
||||
DecimalFloatingPointType() { base = 10 }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -727,7 +887,7 @@ class FloatingPointType extends ArithmeticType {
|
||||
* float f;
|
||||
* ```
|
||||
*/
|
||||
class FloatType extends FloatingPointType {
|
||||
class FloatType extends RealNumberType, BinaryFloatingPointType {
|
||||
FloatType() { builtintypes(underlyingElement(this), _, 24, _, _, _) }
|
||||
|
||||
override string getCanonicalQLClass() { result = "FloatType" }
|
||||
@@ -739,7 +899,7 @@ class FloatType extends FloatingPointType {
|
||||
* double d;
|
||||
* ```
|
||||
*/
|
||||
class DoubleType extends FloatingPointType {
|
||||
class DoubleType extends RealNumberType, BinaryFloatingPointType {
|
||||
DoubleType() { builtintypes(underlyingElement(this), _, 25, _, _, _) }
|
||||
|
||||
override string getCanonicalQLClass() { result = "DoubleType" }
|
||||
@@ -751,7 +911,7 @@ class DoubleType extends FloatingPointType {
|
||||
* long double ld;
|
||||
* ```
|
||||
*/
|
||||
class LongDoubleType extends FloatingPointType {
|
||||
class LongDoubleType extends RealNumberType, BinaryFloatingPointType {
|
||||
LongDoubleType() { builtintypes(underlyingElement(this), _, 26, _, _, _) }
|
||||
|
||||
override string getCanonicalQLClass() { result = "LongDoubleType" }
|
||||
@@ -763,7 +923,7 @@ class LongDoubleType extends FloatingPointType {
|
||||
* __float128 f128;
|
||||
* ```
|
||||
*/
|
||||
class Float128Type extends FloatingPointType {
|
||||
class Float128Type extends RealNumberType, BinaryFloatingPointType {
|
||||
Float128Type() { builtintypes(underlyingElement(this), _, 38, _, _, _) }
|
||||
|
||||
override string getCanonicalQLClass() { result = "Float128Type" }
|
||||
@@ -775,7 +935,7 @@ class Float128Type extends FloatingPointType {
|
||||
* _Decimal32 d32;
|
||||
* ```
|
||||
*/
|
||||
class Decimal32Type extends FloatingPointType {
|
||||
class Decimal32Type extends RealNumberType, DecimalFloatingPointType {
|
||||
Decimal32Type() { builtintypes(underlyingElement(this), _, 40, _, _, _) }
|
||||
|
||||
override string getCanonicalQLClass() { result = "Decimal32Type" }
|
||||
@@ -787,7 +947,7 @@ class Decimal32Type extends FloatingPointType {
|
||||
* _Decimal64 d64;
|
||||
* ```
|
||||
*/
|
||||
class Decimal64Type extends FloatingPointType {
|
||||
class Decimal64Type extends RealNumberType, DecimalFloatingPointType {
|
||||
Decimal64Type() { builtintypes(underlyingElement(this), _, 41, _, _, _) }
|
||||
|
||||
override string getCanonicalQLClass() { result = "Decimal64Type" }
|
||||
@@ -799,7 +959,7 @@ class Decimal64Type extends FloatingPointType {
|
||||
* _Decimal128 d128;
|
||||
* ```
|
||||
*/
|
||||
class Decimal128Type extends FloatingPointType {
|
||||
class Decimal128Type extends RealNumberType, DecimalFloatingPointType {
|
||||
Decimal128Type() { builtintypes(underlyingElement(this), _, 42, _, _, _) }
|
||||
|
||||
override string getCanonicalQLClass() { result = "Decimal128Type" }
|
||||
|
||||
@@ -186,7 +186,12 @@ private class ArrayContent extends Content, TArrayContent {
|
||||
* value of `node1`.
|
||||
*/
|
||||
predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
|
||||
none() // stub implementation
|
||||
exists(FieldAddressInstruction fa, StoreInstruction store |
|
||||
node1.asInstruction() = store and
|
||||
store.getDestinationAddress() = fa and
|
||||
node2.asInstruction().(ChiInstruction).getPartial() = store and
|
||||
f.(FieldContent).getField() = fa.getField()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,7 +200,12 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
|
||||
* `node2`.
|
||||
*/
|
||||
predicate readStep(Node node1, Content f, Node node2) {
|
||||
none() // stub implementation
|
||||
exists(FieldAddressInstruction fa, LoadInstruction load |
|
||||
load.getSourceAddress() = fa and
|
||||
node1.asInstruction() = load.getSourceValueOperand().getAnyDef() and
|
||||
fa.getField() = f.(FieldContent).getField() and
|
||||
load = node2.asInstruction()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -55,7 +55,7 @@ class Node extends TIRDataFlowNode {
|
||||
Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() }
|
||||
|
||||
/** Gets the parameter corresponding to this node, if any. */
|
||||
Parameter asParameter() { result = this.(ParameterNode).getParameter() }
|
||||
Parameter asParameter() { result = this.(ExplicitParameterNode).getParameter() }
|
||||
|
||||
/**
|
||||
* Gets the variable corresponding to this node, if any. This can be used for
|
||||
@@ -63,6 +63,18 @@ class Node extends TIRDataFlowNode {
|
||||
*/
|
||||
Variable asVariable() { result = this.(VariableNode).getVariable() }
|
||||
|
||||
/**
|
||||
* Gets the expression that is partially defined by this node, if any.
|
||||
*
|
||||
* Partial definitions are created for field stores (`x.y = taint();` is a partial
|
||||
* definition of `x`), and for calls that may change the value of an object (so
|
||||
* `x.set(taint())` is a partial definition of `x`, and `transfer(&x, taint())` is
|
||||
* a partial definition of `&x`).
|
||||
*/
|
||||
Expr asPartialDefinition() {
|
||||
result = this.(PartialDefinitionNode).getInstruction().getUnconvertedResultExpression()
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: See UninitializedNode.
|
||||
*
|
||||
@@ -96,6 +108,9 @@ class Node extends TIRDataFlowNode {
|
||||
string toString() { none() } // overridden by subclasses
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction, viewed as a node in a data flow graph.
|
||||
*/
|
||||
class InstructionNode extends Node, TInstructionNode {
|
||||
Instruction instr;
|
||||
|
||||
@@ -143,26 +158,45 @@ class ExprNode extends InstructionNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of a parameter at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
* A node representing a `Parameter`. This includes both explicit parameters such
|
||||
* as `x` in `f(x)` and implicit parameters such as `this` in `x.f()`
|
||||
*/
|
||||
class ParameterNode extends InstructionNode {
|
||||
override InitializeParameterInstruction instr;
|
||||
ParameterNode() {
|
||||
instr instanceof InitializeParameterInstruction
|
||||
or
|
||||
instr instanceof InitializeThisInstruction
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this node is the parameter of `c` at the specified (zero-based)
|
||||
* position. The implicit `this` parameter is considered to have index `-1`.
|
||||
*/
|
||||
predicate isParameterOf(Function f, int i) { f.getParameter(i) = instr.getParameter() }
|
||||
predicate isParameterOf(Function f, int i) { none() } // overriden by subclasses
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of a parameter at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
*/
|
||||
private class ExplicitParameterNode extends ParameterNode {
|
||||
override InitializeParameterInstruction instr;
|
||||
|
||||
override predicate isParameterOf(Function f, int i) { f.getParameter(i) = instr.getParameter() }
|
||||
|
||||
/** Gets the parameter corresponding to this node. */
|
||||
Parameter getParameter() { result = instr.getParameter() }
|
||||
|
||||
override string toString() { result = instr.getParameter().toString() }
|
||||
}
|
||||
|
||||
private class ThisParameterNode extends InstructionNode {
|
||||
private class ThisParameterNode extends ParameterNode {
|
||||
override InitializeThisInstruction instr;
|
||||
|
||||
override predicate isParameterOf(Function f, int i) {
|
||||
i = -1 and instr.getEnclosingFunction() = f
|
||||
}
|
||||
|
||||
override string toString() { result = "this" }
|
||||
}
|
||||
|
||||
@@ -204,6 +238,38 @@ abstract class PostUpdateNode extends InstructionNode {
|
||||
abstract Node getPreUpdateNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* The base class for nodes that perform "partial definitions".
|
||||
*
|
||||
* In contrast to a normal "definition", which provides a new value for
|
||||
* something, a partial definition is an expression that may affect a
|
||||
* value, but does not necessarily replace it entirely. For example:
|
||||
* ```
|
||||
* x.y = 1; // a partial definition of the object `x`.
|
||||
* x.y.z = 1; // a partial definition of the object `x.y`.
|
||||
* x.setY(1); // a partial definition of the object `x`.
|
||||
* setY(&x); // a partial definition of the object `x`.
|
||||
* ```
|
||||
*/
|
||||
abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { }
|
||||
|
||||
private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
|
||||
override ChiInstruction instr;
|
||||
|
||||
ExplicitFieldStoreQualifierNode() {
|
||||
not instr.isResultConflated() and
|
||||
exists(StoreInstruction store, FieldInstruction field |
|
||||
instr.getPartial() = store and field = store.getDestinationAddress()
|
||||
)
|
||||
}
|
||||
|
||||
// There might be multiple `ChiInstructions` that has a particular instruction as
|
||||
// the total operand - so this definition gives consistency errors in
|
||||
// DataFlowImplConsistency::Consistency. However, it's not clear what (if any) implications
|
||||
// this consistency failure has.
|
||||
override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that represents the value of a variable after a function call that
|
||||
* may have changed the variable because it's passed by reference.
|
||||
@@ -288,6 +354,10 @@ class VariableNode extends Node, TVariableNode {
|
||||
*/
|
||||
InstructionNode instructionNode(Instruction instr) { result.getInstruction() = instr }
|
||||
|
||||
/**
|
||||
* Gets the `Node` corresponding to a definition by reference of the variable
|
||||
* that is passed as `argument` of a call.
|
||||
*/
|
||||
DefinitionByReferenceNode definitionByReferenceNode(Expr e) { result.getArgument() = e }
|
||||
|
||||
/**
|
||||
@@ -305,7 +375,7 @@ ExprNode convertedExprNode(Expr e) { result.getConvertedExpr() = e }
|
||||
/**
|
||||
* Gets the `Node` corresponding to the value of `p` at function entry.
|
||||
*/
|
||||
ParameterNode parameterNode(Parameter p) { result.getParameter() = p }
|
||||
ExplicitParameterNode parameterNode(Parameter p) { result.getParameter() = p }
|
||||
|
||||
/** Gets the `VariableNode` corresponding to the variable `v`. */
|
||||
VariableNode variableNode(Variable v) { result.getVariable() = v }
|
||||
@@ -360,6 +430,28 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
|
||||
// for now.
|
||||
iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom
|
||||
or
|
||||
// The next two rules allow flow from partial definitions in setters to succeeding loads in the caller.
|
||||
// First, we add flow from write side-effects to non-conflated chi instructions through their
|
||||
// partial operands. Consider the following example:
|
||||
// ```
|
||||
// void setX(Point* p, int new_x) {
|
||||
// p->x = new_x;
|
||||
// }
|
||||
// ...
|
||||
// setX(&p, taint());
|
||||
// ```
|
||||
// Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to
|
||||
// `setX`, which will be melded into `p` through a chi instruction.
|
||||
iTo.getAnOperand().(ChiPartialOperand).getDef() = iFrom.(WriteSideEffectInstruction) and
|
||||
not iTo.isResultConflated()
|
||||
or
|
||||
// Next, we add flow from non-conflated chi instructions to loads (even when they are not precise).
|
||||
// This ensures that loads of `p->x` gets data flow from the `WriteSideEffectInstruction` above.
|
||||
exists(ChiInstruction chi | iFrom = chi |
|
||||
not chi.isResultConflated() and
|
||||
iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = chi
|
||||
)
|
||||
or
|
||||
// Flow through modeled functions
|
||||
modelFlow(iFrom, iTo)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,9 @@ private newtype TIRType =
|
||||
TIRBooleanType(int byteSize) { Language::hasBooleanType(byteSize) } or
|
||||
TIRSignedIntegerType(int byteSize) { Language::hasSignedIntegerType(byteSize) } or
|
||||
TIRUnsignedIntegerType(int byteSize) { Language::hasUnsignedIntegerType(byteSize) } or
|
||||
TIRFloatingPointType(int byteSize) { Language::hasFloatingPointType(byteSize) } or
|
||||
TIRFloatingPointType(int byteSize, int base, Language::TypeDomain domain) {
|
||||
Language::hasFloatingPointType(byteSize, base, domain)
|
||||
} or
|
||||
TIRAddressType(int byteSize) { Language::hasAddressType(byteSize) } or
|
||||
TIRFunctionAddressType(int byteSize) { Language::hasFunctionAddressType(byteSize) } or
|
||||
TIROpaqueType(Language::OpaqueTypeTag tag, int byteSize) {
|
||||
@@ -104,7 +106,7 @@ private class IRSizedType extends IRType {
|
||||
this = TIRBooleanType(byteSize) or
|
||||
this = TIRSignedIntegerType(byteSize) or
|
||||
this = TIRUnsignedIntegerType(byteSize) or
|
||||
this = TIRFloatingPointType(byteSize) or
|
||||
this = TIRFloatingPointType(byteSize, _, _) or
|
||||
this = TIRAddressType(byteSize) or
|
||||
this = TIRFunctionAddressType(byteSize) or
|
||||
this = TIROpaqueType(_, byteSize)
|
||||
@@ -133,7 +135,7 @@ class IRNumericType extends IRSizedType {
|
||||
IRNumericType() {
|
||||
this = TIRSignedIntegerType(byteSize) or
|
||||
this = TIRUnsignedIntegerType(byteSize) or
|
||||
this = TIRFloatingPointType(byteSize)
|
||||
this = TIRFloatingPointType(byteSize, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,14 +173,43 @@ class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType {
|
||||
* A floating-point type.
|
||||
*/
|
||||
class IRFloatingPointType extends IRNumericType, TIRFloatingPointType {
|
||||
final override string toString() { result = "float" + byteSize.toString() }
|
||||
final private int base;
|
||||
final private Language::TypeDomain domain;
|
||||
|
||||
IRFloatingPointType() { this = TIRFloatingPointType(_, base, domain) }
|
||||
|
||||
final override string toString() {
|
||||
result = getDomainPrefix() + getBaseString() + byteSize.toString()
|
||||
}
|
||||
|
||||
final override Language::LanguageType getCanonicalLanguageType() {
|
||||
result = Language::getCanonicalFloatingPointType(byteSize)
|
||||
result = Language::getCanonicalFloatingPointType(byteSize, base, domain)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final override int getByteSize() { result = byteSize }
|
||||
|
||||
/** Gets the numeric base of the type. Can be either 2 (binary) or 10 (decimal). */
|
||||
final int getBase() { result = base }
|
||||
|
||||
/**
|
||||
* Gets the type domain of the type. Can be `RealDomain`, `ComplexDomain`, or `ImaginaryDomain`.
|
||||
*/
|
||||
final Language::TypeDomain getDomain() { result = domain }
|
||||
|
||||
private string getBaseString() {
|
||||
base = 2 and result = "float"
|
||||
or
|
||||
base = 10 and result = "decimal"
|
||||
}
|
||||
|
||||
private string getDomainPrefix() {
|
||||
domain instanceof Language::RealDomain and result = ""
|
||||
or
|
||||
domain instanceof Language::ComplexDomain and result = "c"
|
||||
or
|
||||
domain instanceof Language::ImaginaryDomain and result = "i"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,11 +6,12 @@ private import DebugSSA
|
||||
|
||||
bindingset[offset]
|
||||
private string getKeySuffixForOffset(int offset) {
|
||||
offset >= 0 and
|
||||
if offset % 2 = 0 then result = "" else result = "_Chi"
|
||||
}
|
||||
|
||||
bindingset[offset]
|
||||
private int getIndexForOffset(int offset) { result = offset / 2 }
|
||||
private int getIndexForOffset(int offset) { offset >= 0 and result = offset / 2 }
|
||||
|
||||
/**
|
||||
* Property provide that dumps the memory access of each result. Useful for debugging SSA
|
||||
|
||||
@@ -1100,13 +1100,36 @@ private Opcode binaryBitwiseOpcode(BinaryBitwiseOperation expr) {
|
||||
}
|
||||
|
||||
private Opcode binaryArithmeticOpcode(BinaryArithmeticOperation expr) {
|
||||
expr instanceof AddExpr and result instanceof Opcode::Add
|
||||
(
|
||||
expr instanceof AddExpr
|
||||
or
|
||||
expr instanceof ImaginaryRealAddExpr
|
||||
or
|
||||
expr instanceof RealImaginaryAddExpr
|
||||
) and
|
||||
result instanceof Opcode::Add
|
||||
or
|
||||
expr instanceof SubExpr and result instanceof Opcode::Sub
|
||||
(
|
||||
expr instanceof SubExpr
|
||||
or
|
||||
expr instanceof ImaginaryRealSubExpr
|
||||
or
|
||||
expr instanceof RealImaginarySubExpr
|
||||
) and
|
||||
result instanceof Opcode::Sub
|
||||
or
|
||||
expr instanceof MulExpr and result instanceof Opcode::Mul
|
||||
(
|
||||
expr instanceof MulExpr
|
||||
or
|
||||
expr instanceof ImaginaryMulExpr
|
||||
) and
|
||||
result instanceof Opcode::Mul
|
||||
or
|
||||
expr instanceof DivExpr and result instanceof Opcode::Div
|
||||
(
|
||||
expr instanceof DivExpr or
|
||||
expr instanceof ImaginaryDivExpr
|
||||
) and
|
||||
result instanceof Opcode::Div
|
||||
or
|
||||
expr instanceof RemExpr and result instanceof Opcode::Rem
|
||||
or
|
||||
|
||||
@@ -6,11 +6,12 @@ private import DebugSSA
|
||||
|
||||
bindingset[offset]
|
||||
private string getKeySuffixForOffset(int offset) {
|
||||
offset >= 0 and
|
||||
if offset % 2 = 0 then result = "" else result = "_Chi"
|
||||
}
|
||||
|
||||
bindingset[offset]
|
||||
private int getIndexForOffset(int offset) { result = offset / 2 }
|
||||
private int getIndexForOffset(int offset) { offset >= 0 and result = offset / 2 }
|
||||
|
||||
/**
|
||||
* Property provide that dumps the memory access of each result. Useful for debugging SSA
|
||||
|
||||
@@ -86,9 +86,15 @@ predicate hasUnsignedIntegerType(int byteSize) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an `IRFloatingPointType` with the specified `byteSize` should exist.
|
||||
* Holds if an `IRFloatingPointType` with the specified size, base, and type domain should exist.
|
||||
*/
|
||||
predicate hasFloatingPointType(int byteSize) { byteSize = any(FloatingPointType type).getSize() }
|
||||
predicate hasFloatingPointType(int byteSize, int base, TypeDomain domain) {
|
||||
exists(FloatingPointType type |
|
||||
byteSize = type.getSize() and
|
||||
base = type.getBase() and
|
||||
domain = type.getDomain()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isPointerIshType(Type type) {
|
||||
type instanceof PointerType
|
||||
@@ -159,8 +165,13 @@ private IRType getIRTypeForPRValue(Type type) {
|
||||
isUnsignedIntegerType(unspecifiedType) and
|
||||
result.(IRUnsignedIntegerType).getByteSize() = type.getSize()
|
||||
or
|
||||
unspecifiedType instanceof FloatingPointType and
|
||||
result.(IRFloatingPointType).getByteSize() = type.getSize()
|
||||
exists(FloatingPointType floatType, IRFloatingPointType irFloatType |
|
||||
floatType = unspecifiedType and
|
||||
irFloatType = result and
|
||||
irFloatType.getByteSize() = floatType.getSize() and
|
||||
irFloatType.getBase() = floatType.getBase() and
|
||||
irFloatType.getDomain() = floatType.getDomain()
|
||||
)
|
||||
or
|
||||
isPointerIshType(unspecifiedType) and result.(IRAddressType).getByteSize() = getTypeSize(type)
|
||||
or
|
||||
@@ -438,15 +449,37 @@ CppPRValueType getCanonicalUnsignedIntegerType(int byteSize) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that is the canonical type for an `IRFloatingPointType` with the specified
|
||||
* `byteSize`.
|
||||
* Gets the sort priority of a `RealNumberType` base on its precision.
|
||||
*/
|
||||
CppPRValueType getCanonicalFloatingPointType(int byteSize) {
|
||||
private int getPrecisionPriority(RealNumberType type) {
|
||||
// Prefer `double`, `float`, `long double` in that order.
|
||||
if type instanceof DoubleType
|
||||
then result = 4
|
||||
else
|
||||
if type instanceof FloatType
|
||||
then result = 3
|
||||
else
|
||||
if type instanceof LongDoubleType
|
||||
then result = 2
|
||||
else
|
||||
// If we get this far, prefer non-extended-precision types.
|
||||
if not type.isExtendedPrecision()
|
||||
then result = 1
|
||||
else result = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `CppType` that is the canonical type for an `IRFloatingPointType` with the specified
|
||||
* size, base, and type domain.
|
||||
*/
|
||||
CppPRValueType getCanonicalFloatingPointType(int byteSize, int base, TypeDomain domain) {
|
||||
result =
|
||||
TPRValueType(max(FloatingPointType type |
|
||||
type.getSize() = byteSize
|
||||
type.getSize() = byteSize and
|
||||
type.getBase() = base and
|
||||
type.getDomain() = domain
|
||||
|
|
||||
type order by type.toString() desc
|
||||
type order by getPrecisionPriority(type.getRealType()), type.toString() desc
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,14 @@ class LanguageType = CppType;
|
||||
|
||||
class OpaqueTypeTag = Cpp::Type;
|
||||
|
||||
class TypeDomain = Cpp::TypeDomain;
|
||||
|
||||
class RealDomain = Cpp::RealDomain;
|
||||
|
||||
class ComplexDomain = Cpp::ComplexDomain;
|
||||
|
||||
class ImaginaryDomain = Cpp::ImaginaryDomain;
|
||||
|
||||
class Function = Cpp::Function;
|
||||
|
||||
class Location = Cpp::Location;
|
||||
|
||||
@@ -23,17 +23,20 @@ Type getVariableType(Variable v) {
|
||||
then
|
||||
result = getDecayedType(declaredType)
|
||||
or
|
||||
not exists(getDecayedType(declaredType)) and result = declaredType
|
||||
not exists(getDecayedType(declaredType)) and result = v.getType()
|
||||
else
|
||||
if declaredType instanceof ArrayType and not declaredType.(ArrayType).hasArraySize()
|
||||
then
|
||||
result = v.getInitializer().getExpr().getUnspecifiedType()
|
||||
result = v.getInitializer().getExpr().getType()
|
||||
or
|
||||
not exists(v.getInitializer()) and result = declaredType
|
||||
else result = declaredType
|
||||
not exists(v.getInitializer()) and result = v.getType()
|
||||
else result = v.getType()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the database contains a `case` label with the specified minimum and maximum value.
|
||||
*/
|
||||
predicate hasCaseEdge(SwitchCase switchCase, string minValue, string maxValue) {
|
||||
minValue = switchCase.getExpr().getFullyConverted().getValue() and
|
||||
if exists(switchCase.getEndExpr())
|
||||
|
||||
@@ -30,6 +30,8 @@ localCallNodes
|
||||
postIsNotPre
|
||||
postHasUniquePre
|
||||
uniquePostUpdate
|
||||
| ref.cpp:83:5:83:17 | Chi | Node has multiple PostUpdateNodes. |
|
||||
| ref.cpp:109:5:109:22 | Chi | Node has multiple PostUpdateNodes. |
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
|
||||
@@ -31,10 +31,6 @@
|
||||
| ref.cpp:53:17:53:18 | ref.cpp:62:10:62:11 | AST only |
|
||||
| ref.cpp:53:21:53:22 | ref.cpp:65:10:65:11 | AST only |
|
||||
| ref.cpp:55:23:55:28 | ref.cpp:56:10:56:11 | AST only |
|
||||
| ref.cpp:94:15:94:20 | ref.cpp:129:13:129:15 | AST only |
|
||||
| ref.cpp:109:15:109:20 | ref.cpp:132:13:132:15 | AST only |
|
||||
| ref.cpp:122:23:122:28 | ref.cpp:123:13:123:15 | AST only |
|
||||
| ref.cpp:125:19:125:24 | ref.cpp:126:13:126:15 | AST only |
|
||||
| test.cpp:75:7:75:8 | test.cpp:76:8:76:9 | AST only |
|
||||
| test.cpp:83:7:83:8 | test.cpp:84:8:84:18 | AST only |
|
||||
| test.cpp:83:7:83:8 | test.cpp:86:8:86:9 | AST only |
|
||||
@@ -45,9 +41,6 @@
|
||||
| test.cpp:359:13:359:18 | test.cpp:365:10:365:14 | AST only |
|
||||
| test.cpp:373:13:373:18 | test.cpp:369:10:369:14 | AST only |
|
||||
| test.cpp:373:13:373:18 | test.cpp:375:10:375:14 | AST only |
|
||||
| test.cpp:382:48:382:54 | test.cpp:385:8:385:10 | AST only |
|
||||
| test.cpp:388:53:388:59 | test.cpp:392:8:392:10 | AST only |
|
||||
| test.cpp:388:53:388:59 | test.cpp:394:10:394:12 | AST only |
|
||||
| test.cpp:399:7:399:9 | test.cpp:401:8:401:10 | AST only |
|
||||
| test.cpp:405:7:405:9 | test.cpp:408:8:408:10 | AST only |
|
||||
| test.cpp:416:7:416:11 | test.cpp:418:8:418:12 | AST only |
|
||||
|
||||
@@ -39,6 +39,10 @@
|
||||
| globals.cpp:12:10:12:24 | flowTestGlobal1 | globals.cpp:13:23:13:28 | call to source |
|
||||
| globals.cpp:19:10:19:24 | flowTestGlobal2 | globals.cpp:23:23:23:28 | call to source |
|
||||
| lambdas.cpp:35:8:35:8 | a | lambdas.cpp:8:10:8:15 | call to source |
|
||||
| ref.cpp:123:13:123:15 | val | ref.cpp:122:23:122:28 | call to source |
|
||||
| ref.cpp:126:13:126:15 | val | ref.cpp:125:19:125:24 | call to source |
|
||||
| ref.cpp:129:13:129:15 | val | ref.cpp:94:15:94:20 | call to source |
|
||||
| ref.cpp:132:13:132:15 | val | ref.cpp:109:15:109:20 | call to source |
|
||||
| test.cpp:7:8:7:9 | t1 | test.cpp:6:12:6:17 | call to source |
|
||||
| test.cpp:9:8:9:9 | t1 | test.cpp:6:12:6:17 | call to source |
|
||||
| test.cpp:10:8:10:9 | t2 | test.cpp:6:12:6:17 | call to source |
|
||||
@@ -61,6 +65,9 @@
|
||||
| test.cpp:266:12:266:12 | x | test.cpp:265:22:265:27 | call to source |
|
||||
| test.cpp:289:14:289:14 | x | test.cpp:305:17:305:22 | call to source |
|
||||
| test.cpp:318:7:318:7 | x | test.cpp:314:4:314:9 | call to source |
|
||||
| test.cpp:385:8:385:10 | tmp | test.cpp:382:48:382:54 | source1 |
|
||||
| test.cpp:392:8:392:10 | tmp | test.cpp:388:53:388:59 | source1 |
|
||||
| test.cpp:394:10:394:12 | tmp | test.cpp:388:53:388:59 | source1 |
|
||||
| test.cpp:450:9:450:22 | (statement expression) | test.cpp:449:26:449:32 | source1 |
|
||||
| test.cpp:461:8:461:12 | local | test.cpp:449:26:449:32 | source1 |
|
||||
| true_upon_entry.cpp:13:8:13:8 | x | true_upon_entry.cpp:9:11:9:16 | call to source |
|
||||
|
||||
82
cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
Normal file
82
cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected
Normal file
@@ -0,0 +1,82 @@
|
||||
edges
|
||||
| A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] |
|
||||
| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] |
|
||||
| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store |
|
||||
| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c |
|
||||
| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c |
|
||||
| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] |
|
||||
| A.cpp:154:13:154:13 | c | A.cpp:154:10:154:13 | (void *)... |
|
||||
| aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] |
|
||||
| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] |
|
||||
| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store |
|
||||
| aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] |
|
||||
| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | Chi [m1] |
|
||||
| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Store |
|
||||
| aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 |
|
||||
| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] |
|
||||
| aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 |
|
||||
| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] |
|
||||
| aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 |
|
||||
| aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 |
|
||||
| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] |
|
||||
| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | Chi [m1] |
|
||||
| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Store |
|
||||
| aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 |
|
||||
| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 |
|
||||
| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 |
|
||||
| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 |
|
||||
| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a |
|
||||
| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a |
|
||||
nodes
|
||||
| A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] |
|
||||
| A.cpp:142:7:142:20 | Store | semmle.label | Store |
|
||||
| A.cpp:142:14:142:20 | new | semmle.label | new |
|
||||
| A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] |
|
||||
| A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] |
|
||||
| A.cpp:154:10:154:13 | (void *)... | semmle.label | (void *)... |
|
||||
| A.cpp:154:13:154:13 | c | semmle.label | c |
|
||||
| A.cpp:154:13:154:13 | c | semmle.label | c |
|
||||
| aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] |
|
||||
| aliasing.cpp:9:3:9:22 | Store | semmle.label | Store |
|
||||
| aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] |
|
||||
| aliasing.cpp:13:3:13:21 | Store | semmle.label | Store |
|
||||
| aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] |
|
||||
| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] |
|
||||
| aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] |
|
||||
| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] |
|
||||
| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:37:13:37:22 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] |
|
||||
| aliasing.cpp:60:3:60:22 | Store | semmle.label | Store |
|
||||
| aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] |
|
||||
| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:86:10:86:19 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 |
|
||||
| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input |
|
||||
| struct_init.c:22:11:22:11 | a | semmle.label | a |
|
||||
| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input |
|
||||
| struct_init.c:31:23:31:23 | a | semmle.label | a |
|
||||
#select
|
||||
| A.cpp:154:10:154:13 | (void *)... | A.cpp:142:14:142:20 | new | A.cpp:154:10:154:13 | (void *)... | (void *)... flows from $@ | A.cpp:142:14:142:20 | new | new |
|
||||
| A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new |
|
||||
| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input | call to user_input |
|
||||
| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input |
|
||||
| aliasing.cpp:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input | call to user_input |
|
||||
| aliasing.cpp:43:13:43:14 | m1 | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | m1 flows from $@ | aliasing.cpp:42:11:42:20 | call to user_input | call to user_input |
|
||||
| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input |
|
||||
| aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input | call to user_input |
|
||||
| aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input | call to user_input |
|
||||
| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input |
|
||||
| struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
|
||||
| struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input |
|
||||
46
cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql
Normal file
46
cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon
|
||||
import semmle.code.cpp.ir.IR
|
||||
import DataFlow::PathGraph
|
||||
import cpp
|
||||
|
||||
class Conf extends DataFlow::Configuration {
|
||||
Conf() { this = "FieldFlowConf" }
|
||||
|
||||
override predicate isSource(Node src) {
|
||||
src.asExpr() instanceof NewExpr
|
||||
or
|
||||
src.asExpr().(Call).getTarget().hasName("user_input")
|
||||
or
|
||||
exists(FunctionCall fc |
|
||||
fc.getAnArgument() = src.asDefiningArgument() and
|
||||
fc.getTarget().hasName("argument_source")
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(Node sink) {
|
||||
exists(Call c |
|
||||
c.getTarget().hasName("sink") and
|
||||
c.getAnArgument() = sink.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(Node a, Node b) {
|
||||
b.asPartialDefinition() =
|
||||
any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr())
|
||||
.getQualifier()
|
||||
or
|
||||
b.asExpr().(AddressOfExpr).getOperand() = a.asExpr()
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode src, DataFlow::PathNode sink, Conf conf
|
||||
where conf.hasFlowPath(src, sink)
|
||||
select sink, src, sink, sink + " flows from $@", src, src.toString()
|
||||
@@ -28,7 +28,6 @@
|
||||
| taint.cpp:181:8:181:9 | taint.cpp:185:11:185:16 | AST only |
|
||||
| taint.cpp:195:7:195:7 | taint.cpp:192:23:192:28 | AST only |
|
||||
| taint.cpp:195:7:195:7 | taint.cpp:193:6:193:6 | AST only |
|
||||
| taint.cpp:216:7:216:7 | taint.cpp:207:6:207:11 | AST only |
|
||||
| taint.cpp:229:3:229:6 | taint.cpp:223:10:223:15 | AST only |
|
||||
| taint.cpp:233:8:233:8 | taint.cpp:223:10:223:15 | AST only |
|
||||
| taint.cpp:236:3:236:6 | taint.cpp:223:10:223:15 | AST only |
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
| taint.cpp:168:8:168:14 | tainted | taint.cpp:164:19:164:24 | call to source |
|
||||
| taint.cpp:210:7:210:7 | x | taint.cpp:207:6:207:11 | call to source |
|
||||
| taint.cpp:215:7:215:7 | x | taint.cpp:207:6:207:11 | call to source |
|
||||
| taint.cpp:216:7:216:7 | y | taint.cpp:207:6:207:11 | call to source |
|
||||
| taint.cpp:250:8:250:8 | a | taint.cpp:223:10:223:15 | call to source |
|
||||
| taint.cpp:280:7:280:7 | t | taint.cpp:275:6:275:11 | call to source |
|
||||
| taint.cpp:289:7:289:7 | t | taint.cpp:275:6:275:11 | call to source |
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
147
cpp/ql/test/library-tests/ir/ir/complex.c
Normal file
147
cpp/ql/test/library-tests/ir/ir/complex.c
Normal file
@@ -0,0 +1,147 @@
|
||||
void complex_literals(void) {
|
||||
_Complex float cf = 2.0;
|
||||
cf = __I__;
|
||||
_Complex double cd = 3.0;
|
||||
cd = __I__;
|
||||
_Complex long double cld = 5.0;
|
||||
cld = __I__;
|
||||
|
||||
_Imaginary float jf = __I__;
|
||||
_Imaginary double jd = __I__;
|
||||
_Imaginary long double jld = __I__;
|
||||
}
|
||||
|
||||
void complex_arithmetic(void) {
|
||||
float f1 = 5.0;
|
||||
float f2 = 7.0;
|
||||
float f3;
|
||||
_Complex float cf1 = 2.0;
|
||||
_Complex float cf2 = __I__;
|
||||
_Complex float cf3;
|
||||
_Imaginary float jf1 = __I__;
|
||||
_Imaginary float jf2 = __I__;
|
||||
_Imaginary float jf3;
|
||||
|
||||
// unaryop _Complex
|
||||
cf3 = +cf1;
|
||||
cf3 = -cf1;
|
||||
|
||||
// _Complex binaryop _Complex
|
||||
cf3 = cf1 + cf2;
|
||||
cf3 = cf1 - cf2;
|
||||
cf3 = cf1 * cf2;
|
||||
cf3 = cf1 / cf2;
|
||||
|
||||
// unaryop _Imaginary
|
||||
jf3 = +jf1;
|
||||
jf3 = -jf1;
|
||||
|
||||
// _Imaginary binaryop _Imaginary
|
||||
jf3 = jf1 + jf2;
|
||||
jf3 = jf1 - jf2;
|
||||
f3 = jf1 * jf2; // Result is _Real
|
||||
f3 = jf1 / jf2; // Result is _Real
|
||||
|
||||
// _Imaginary binaryop _Real
|
||||
cf3 = jf1 + f2;
|
||||
cf3 = jf1 - f2;
|
||||
jf3 = jf1 * f2; // Result is _Imaginary
|
||||
jf3 = jf1 / f2; // Result is _Imaginary
|
||||
|
||||
// _Real binaryop _Imaginary
|
||||
cf3 = f1 + jf2;
|
||||
cf3 = f1 - jf2;
|
||||
jf3 = f1 * jf2; // Result is _Imaginary
|
||||
jf3 = f1 / jf2; // Result is _Imaginary
|
||||
}
|
||||
|
||||
void complex_conversions(void) {
|
||||
float f = 2.0;
|
||||
double d = 3.0;
|
||||
long double ld = 5.0;
|
||||
_Complex float cf = 7.0;
|
||||
_Complex double cd = 11.0;
|
||||
_Complex long double cld = 13.0;
|
||||
_Imaginary float jf = __I__;
|
||||
_Imaginary double jd = __I__;
|
||||
_Imaginary long double jld = __I__;
|
||||
|
||||
// _Complex to _Complex
|
||||
cf = cf;
|
||||
cf = cd;
|
||||
cf = cld;
|
||||
cd = cf;
|
||||
cd = cd;
|
||||
cd = cld;
|
||||
cld = cf;
|
||||
cld = cd;
|
||||
cld = cld;
|
||||
|
||||
// _Real to _Complex
|
||||
cf = f;
|
||||
cf = d;
|
||||
cf = ld;
|
||||
cd = f;
|
||||
cd = d;
|
||||
cd = ld;
|
||||
cld = f;
|
||||
cld = d;
|
||||
cld = ld;
|
||||
|
||||
// _Complex to _Real
|
||||
f = cf;
|
||||
f = cd;
|
||||
f = cld;
|
||||
d = cf;
|
||||
d = cd;
|
||||
d = cld;
|
||||
ld = cf;
|
||||
ld = cd;
|
||||
ld = cld;
|
||||
|
||||
// _Imaginary to _Complex
|
||||
cf = jf;
|
||||
cf = jd;
|
||||
cf = jld;
|
||||
cd = jf;
|
||||
cd = jd;
|
||||
cd = jld;
|
||||
cld = jf;
|
||||
cld = jd;
|
||||
cld = jld;
|
||||
|
||||
// _Complex to _Imaginary
|
||||
jf = cf;
|
||||
jf = cd;
|
||||
jf = cld;
|
||||
jd = cf;
|
||||
jd = cd;
|
||||
jd = cld;
|
||||
jld = cf;
|
||||
jld = cd;
|
||||
jld = cld;
|
||||
|
||||
// _Real to _Imaginary
|
||||
jf = f;
|
||||
jf = d;
|
||||
jf = ld;
|
||||
jd = f;
|
||||
jd = d;
|
||||
jd = ld;
|
||||
jld = f;
|
||||
jld = d;
|
||||
jld = ld;
|
||||
|
||||
// _Imaginary to _Real
|
||||
f = jf;
|
||||
f = jd;
|
||||
f = jld;
|
||||
d = jf;
|
||||
d = jd;
|
||||
d = jld;
|
||||
ld = jf;
|
||||
ld = jd;
|
||||
ld = jld;
|
||||
}
|
||||
|
||||
// semmle-extractor-options: --microsoft --edg --c99
|
||||
@@ -124,6 +124,580 @@ clang.cpp:
|
||||
# 5| v5_8(void) = AliasedUse : ~mu5_4
|
||||
# 5| v5_9(void) = ExitFunction :
|
||||
|
||||
complex.c:
|
||||
# 1| void complex_literals()
|
||||
# 1| Block 0
|
||||
# 1| v1_1(void) = EnterFunction :
|
||||
# 1| mu1_2(unknown) = AliasedDefinition :
|
||||
# 1| mu1_3(unknown) = InitializeNonLocal :
|
||||
# 1| mu1_4(unknown) = UnmodeledDefinition :
|
||||
# 2| r2_1(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 2| r2_2(double) = Constant[2.0] :
|
||||
# 2| r2_3(_Complex float) = Convert : r2_2
|
||||
# 2| mu2_4(_Complex float) = Store : &:r2_1, r2_3
|
||||
# 3| r3_1(_Imaginary float) = Constant[1.0i] :
|
||||
# 3| r3_2(_Complex float) = Convert : r3_1
|
||||
# 3| r3_3(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 3| mu3_4(_Complex float) = Store : &:r3_3, r3_2
|
||||
# 4| r4_1(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 4| r4_2(double) = Constant[3.0] :
|
||||
# 4| r4_3(_Complex double) = Convert : r4_2
|
||||
# 4| mu4_4(_Complex double) = Store : &:r4_1, r4_3
|
||||
# 5| r5_1(_Imaginary float) = Constant[1.0i] :
|
||||
# 5| r5_2(_Complex double) = Convert : r5_1
|
||||
# 5| r5_3(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 5| mu5_4(_Complex double) = Store : &:r5_3, r5_2
|
||||
# 6| r6_1(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 6| r6_2(double) = Constant[5.0] :
|
||||
# 6| r6_3(_Complex long double) = Convert : r6_2
|
||||
# 6| mu6_4(_Complex long double) = Store : &:r6_1, r6_3
|
||||
# 7| r7_1(_Imaginary float) = Constant[1.0i] :
|
||||
# 7| r7_2(_Complex long double) = Convert : r7_1
|
||||
# 7| r7_3(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 7| mu7_4(_Complex long double) = Store : &:r7_3, r7_2
|
||||
# 9| r9_1(glval<_Imaginary float>) = VariableAddress[jf] :
|
||||
# 9| r9_2(_Imaginary float) = Constant[1.0i] :
|
||||
# 9| mu9_3(_Imaginary float) = Store : &:r9_1, r9_2
|
||||
# 10| r10_1(glval<_Imaginary double>) = VariableAddress[jd] :
|
||||
# 10| r10_2(_Imaginary float) = Constant[1.0i] :
|
||||
# 10| r10_3(_Imaginary double) = Convert : r10_2
|
||||
# 10| mu10_4(_Imaginary double) = Store : &:r10_1, r10_3
|
||||
# 11| r11_1(glval<_Imaginary long double>) = VariableAddress[jld] :
|
||||
# 11| r11_2(_Imaginary float) = Constant[1.0i] :
|
||||
# 11| r11_3(_Imaginary long double) = Convert : r11_2
|
||||
# 11| mu11_4(_Imaginary long double) = Store : &:r11_1, r11_3
|
||||
# 12| v12_1(void) = NoOp :
|
||||
# 1| v1_5(void) = ReturnVoid :
|
||||
# 1| v1_6(void) = UnmodeledUse : mu*
|
||||
# 1| v1_7(void) = AliasedUse : ~mu1_4
|
||||
# 1| v1_8(void) = ExitFunction :
|
||||
|
||||
# 14| void complex_arithmetic()
|
||||
# 14| Block 0
|
||||
# 14| v14_1(void) = EnterFunction :
|
||||
# 14| mu14_2(unknown) = AliasedDefinition :
|
||||
# 14| mu14_3(unknown) = InitializeNonLocal :
|
||||
# 14| mu14_4(unknown) = UnmodeledDefinition :
|
||||
# 15| r15_1(glval<float>) = VariableAddress[f1] :
|
||||
# 15| r15_2(float) = Constant[5.0] :
|
||||
# 15| mu15_3(float) = Store : &:r15_1, r15_2
|
||||
# 16| r16_1(glval<float>) = VariableAddress[f2] :
|
||||
# 16| r16_2(float) = Constant[7.0] :
|
||||
# 16| mu16_3(float) = Store : &:r16_1, r16_2
|
||||
# 17| r17_1(glval<float>) = VariableAddress[f3] :
|
||||
# 17| mu17_2(float) = Uninitialized[f3] : &:r17_1
|
||||
# 18| r18_1(glval<_Complex float>) = VariableAddress[cf1] :
|
||||
# 18| r18_2(double) = Constant[2.0] :
|
||||
# 18| r18_3(_Complex float) = Convert : r18_2
|
||||
# 18| mu18_4(_Complex float) = Store : &:r18_1, r18_3
|
||||
# 19| r19_1(glval<_Complex float>) = VariableAddress[cf2] :
|
||||
# 19| r19_2(_Imaginary float) = Constant[1.0i] :
|
||||
# 19| r19_3(_Complex float) = Convert : r19_2
|
||||
# 19| mu19_4(_Complex float) = Store : &:r19_1, r19_3
|
||||
# 20| r20_1(glval<_Complex float>) = VariableAddress[cf3] :
|
||||
# 20| mu20_2(_Complex float) = Uninitialized[cf3] : &:r20_1
|
||||
# 21| r21_1(glval<_Imaginary float>) = VariableAddress[jf1] :
|
||||
# 21| r21_2(_Imaginary float) = Constant[1.0i] :
|
||||
# 21| mu21_3(_Imaginary float) = Store : &:r21_1, r21_2
|
||||
# 22| r22_1(glval<_Imaginary float>) = VariableAddress[jf2] :
|
||||
# 22| r22_2(_Imaginary float) = Constant[1.0i] :
|
||||
# 22| mu22_3(_Imaginary float) = Store : &:r22_1, r22_2
|
||||
# 23| r23_1(glval<_Imaginary float>) = VariableAddress[jf3] :
|
||||
# 23| mu23_2(_Imaginary float) = Uninitialized[jf3] : &:r23_1
|
||||
# 26| r26_1(glval<_Complex float>) = VariableAddress[cf1] :
|
||||
# 26| r26_2(_Complex float) = Load : &:r26_1, ~mu14_4
|
||||
# 26| r26_3(_Complex float) = CopyValue : r26_2
|
||||
# 26| r26_4(glval<_Complex float>) = VariableAddress[cf3] :
|
||||
# 26| mu26_5(_Complex float) = Store : &:r26_4, r26_3
|
||||
# 27| r27_1(glval<_Complex float>) = VariableAddress[cf1] :
|
||||
# 27| r27_2(_Complex float) = Load : &:r27_1, ~mu14_4
|
||||
# 27| r27_3(_Complex float) = Negate : r27_2
|
||||
# 27| r27_4(glval<_Complex float>) = VariableAddress[cf3] :
|
||||
# 27| mu27_5(_Complex float) = Store : &:r27_4, r27_3
|
||||
# 30| r30_1(glval<_Complex float>) = VariableAddress[cf1] :
|
||||
# 30| r30_2(_Complex float) = Load : &:r30_1, ~mu14_4
|
||||
# 30| r30_3(glval<_Complex float>) = VariableAddress[cf2] :
|
||||
# 30| r30_4(_Complex float) = Load : &:r30_3, ~mu14_4
|
||||
# 30| r30_5(_Complex float) = Add : r30_2, r30_4
|
||||
# 30| r30_6(glval<_Complex float>) = VariableAddress[cf3] :
|
||||
# 30| mu30_7(_Complex float) = Store : &:r30_6, r30_5
|
||||
# 31| r31_1(glval<_Complex float>) = VariableAddress[cf1] :
|
||||
# 31| r31_2(_Complex float) = Load : &:r31_1, ~mu14_4
|
||||
# 31| r31_3(glval<_Complex float>) = VariableAddress[cf2] :
|
||||
# 31| r31_4(_Complex float) = Load : &:r31_3, ~mu14_4
|
||||
# 31| r31_5(_Complex float) = Sub : r31_2, r31_4
|
||||
# 31| r31_6(glval<_Complex float>) = VariableAddress[cf3] :
|
||||
# 31| mu31_7(_Complex float) = Store : &:r31_6, r31_5
|
||||
# 32| r32_1(glval<_Complex float>) = VariableAddress[cf1] :
|
||||
# 32| r32_2(_Complex float) = Load : &:r32_1, ~mu14_4
|
||||
# 32| r32_3(glval<_Complex float>) = VariableAddress[cf2] :
|
||||
# 32| r32_4(_Complex float) = Load : &:r32_3, ~mu14_4
|
||||
# 32| r32_5(_Complex float) = Mul : r32_2, r32_4
|
||||
# 32| r32_6(glval<_Complex float>) = VariableAddress[cf3] :
|
||||
# 32| mu32_7(_Complex float) = Store : &:r32_6, r32_5
|
||||
# 33| r33_1(glval<_Complex float>) = VariableAddress[cf1] :
|
||||
# 33| r33_2(_Complex float) = Load : &:r33_1, ~mu14_4
|
||||
# 33| r33_3(glval<_Complex float>) = VariableAddress[cf2] :
|
||||
# 33| r33_4(_Complex float) = Load : &:r33_3, ~mu14_4
|
||||
# 33| r33_5(_Complex float) = Div : r33_2, r33_4
|
||||
# 33| r33_6(glval<_Complex float>) = VariableAddress[cf3] :
|
||||
# 33| mu33_7(_Complex float) = Store : &:r33_6, r33_5
|
||||
# 36| r36_1(glval<_Imaginary float>) = VariableAddress[jf1] :
|
||||
# 36| r36_2(_Imaginary float) = Load : &:r36_1, ~mu14_4
|
||||
# 36| r36_3(_Imaginary float) = CopyValue : r36_2
|
||||
# 36| r36_4(glval<_Imaginary float>) = VariableAddress[jf3] :
|
||||
# 36| mu36_5(_Imaginary float) = Store : &:r36_4, r36_3
|
||||
# 37| r37_1(glval<_Imaginary float>) = VariableAddress[jf1] :
|
||||
# 37| r37_2(_Imaginary float) = Load : &:r37_1, ~mu14_4
|
||||
# 37| r37_3(_Imaginary float) = Negate : r37_2
|
||||
# 37| r37_4(glval<_Imaginary float>) = VariableAddress[jf3] :
|
||||
# 37| mu37_5(_Imaginary float) = Store : &:r37_4, r37_3
|
||||
# 40| r40_1(glval<_Imaginary float>) = VariableAddress[jf1] :
|
||||
# 40| r40_2(_Imaginary float) = Load : &:r40_1, ~mu14_4
|
||||
# 40| r40_3(glval<_Imaginary float>) = VariableAddress[jf2] :
|
||||
# 40| r40_4(_Imaginary float) = Load : &:r40_3, ~mu14_4
|
||||
# 40| r40_5(_Imaginary float) = Add : r40_2, r40_4
|
||||
# 40| r40_6(glval<_Imaginary float>) = VariableAddress[jf3] :
|
||||
# 40| mu40_7(_Imaginary float) = Store : &:r40_6, r40_5
|
||||
# 41| r41_1(glval<_Imaginary float>) = VariableAddress[jf1] :
|
||||
# 41| r41_2(_Imaginary float) = Load : &:r41_1, ~mu14_4
|
||||
# 41| r41_3(glval<_Imaginary float>) = VariableAddress[jf2] :
|
||||
# 41| r41_4(_Imaginary float) = Load : &:r41_3, ~mu14_4
|
||||
# 41| r41_5(_Imaginary float) = Sub : r41_2, r41_4
|
||||
# 41| r41_6(glval<_Imaginary float>) = VariableAddress[jf3] :
|
||||
# 41| mu41_7(_Imaginary float) = Store : &:r41_6, r41_5
|
||||
# 42| r42_1(glval<_Imaginary float>) = VariableAddress[jf1] :
|
||||
# 42| r42_2(_Imaginary float) = Load : &:r42_1, ~mu14_4
|
||||
# 42| r42_3(glval<_Imaginary float>) = VariableAddress[jf2] :
|
||||
# 42| r42_4(_Imaginary float) = Load : &:r42_3, ~mu14_4
|
||||
# 42| r42_5(float) = Mul : r42_2, r42_4
|
||||
# 42| r42_6(glval<float>) = VariableAddress[f3] :
|
||||
# 42| mu42_7(float) = Store : &:r42_6, r42_5
|
||||
# 43| r43_1(glval<_Imaginary float>) = VariableAddress[jf1] :
|
||||
# 43| r43_2(_Imaginary float) = Load : &:r43_1, ~mu14_4
|
||||
# 43| r43_3(glval<_Imaginary float>) = VariableAddress[jf2] :
|
||||
# 43| r43_4(_Imaginary float) = Load : &:r43_3, ~mu14_4
|
||||
# 43| r43_5(float) = Div : r43_2, r43_4
|
||||
# 43| r43_6(glval<float>) = VariableAddress[f3] :
|
||||
# 43| mu43_7(float) = Store : &:r43_6, r43_5
|
||||
# 46| r46_1(glval<_Imaginary float>) = VariableAddress[jf1] :
|
||||
# 46| r46_2(_Imaginary float) = Load : &:r46_1, ~mu14_4
|
||||
# 46| r46_3(glval<float>) = VariableAddress[f2] :
|
||||
# 46| r46_4(float) = Load : &:r46_3, ~mu14_4
|
||||
# 46| r46_5(_Complex float) = Add : r46_2, r46_4
|
||||
# 46| r46_6(glval<_Complex float>) = VariableAddress[cf3] :
|
||||
# 46| mu46_7(_Complex float) = Store : &:r46_6, r46_5
|
||||
# 47| r47_1(glval<_Imaginary float>) = VariableAddress[jf1] :
|
||||
# 47| r47_2(_Imaginary float) = Load : &:r47_1, ~mu14_4
|
||||
# 47| r47_3(glval<float>) = VariableAddress[f2] :
|
||||
# 47| r47_4(float) = Load : &:r47_3, ~mu14_4
|
||||
# 47| r47_5(_Complex float) = Sub : r47_2, r47_4
|
||||
# 47| r47_6(glval<_Complex float>) = VariableAddress[cf3] :
|
||||
# 47| mu47_7(_Complex float) = Store : &:r47_6, r47_5
|
||||
# 48| r48_1(glval<_Imaginary float>) = VariableAddress[jf1] :
|
||||
# 48| r48_2(_Imaginary float) = Load : &:r48_1, ~mu14_4
|
||||
# 48| r48_3(glval<float>) = VariableAddress[f2] :
|
||||
# 48| r48_4(float) = Load : &:r48_3, ~mu14_4
|
||||
# 48| r48_5(_Imaginary float) = Mul : r48_2, r48_4
|
||||
# 48| r48_6(glval<_Imaginary float>) = VariableAddress[jf3] :
|
||||
# 48| mu48_7(_Imaginary float) = Store : &:r48_6, r48_5
|
||||
# 49| r49_1(glval<_Imaginary float>) = VariableAddress[jf1] :
|
||||
# 49| r49_2(_Imaginary float) = Load : &:r49_1, ~mu14_4
|
||||
# 49| r49_3(glval<float>) = VariableAddress[f2] :
|
||||
# 49| r49_4(float) = Load : &:r49_3, ~mu14_4
|
||||
# 49| r49_5(_Imaginary float) = Div : r49_2, r49_4
|
||||
# 49| r49_6(glval<_Imaginary float>) = VariableAddress[jf3] :
|
||||
# 49| mu49_7(_Imaginary float) = Store : &:r49_6, r49_5
|
||||
# 52| r52_1(glval<float>) = VariableAddress[f1] :
|
||||
# 52| r52_2(float) = Load : &:r52_1, ~mu14_4
|
||||
# 52| r52_3(glval<_Imaginary float>) = VariableAddress[jf2] :
|
||||
# 52| r52_4(_Imaginary float) = Load : &:r52_3, ~mu14_4
|
||||
# 52| r52_5(_Complex float) = Add : r52_2, r52_4
|
||||
# 52| r52_6(glval<_Complex float>) = VariableAddress[cf3] :
|
||||
# 52| mu52_7(_Complex float) = Store : &:r52_6, r52_5
|
||||
# 53| r53_1(glval<float>) = VariableAddress[f1] :
|
||||
# 53| r53_2(float) = Load : &:r53_1, ~mu14_4
|
||||
# 53| r53_3(glval<_Imaginary float>) = VariableAddress[jf2] :
|
||||
# 53| r53_4(_Imaginary float) = Load : &:r53_3, ~mu14_4
|
||||
# 53| r53_5(_Complex float) = Sub : r53_2, r53_4
|
||||
# 53| r53_6(glval<_Complex float>) = VariableAddress[cf3] :
|
||||
# 53| mu53_7(_Complex float) = Store : &:r53_6, r53_5
|
||||
# 54| r54_1(glval<float>) = VariableAddress[f1] :
|
||||
# 54| r54_2(float) = Load : &:r54_1, ~mu14_4
|
||||
# 54| r54_3(glval<_Imaginary float>) = VariableAddress[jf2] :
|
||||
# 54| r54_4(_Imaginary float) = Load : &:r54_3, ~mu14_4
|
||||
# 54| r54_5(_Imaginary float) = Mul : r54_2, r54_4
|
||||
# 54| r54_6(glval<_Imaginary float>) = VariableAddress[jf3] :
|
||||
# 54| mu54_7(_Imaginary float) = Store : &:r54_6, r54_5
|
||||
# 55| r55_1(glval<float>) = VariableAddress[f1] :
|
||||
# 55| r55_2(float) = Load : &:r55_1, ~mu14_4
|
||||
# 55| r55_3(glval<_Imaginary float>) = VariableAddress[jf2] :
|
||||
# 55| r55_4(_Imaginary float) = Load : &:r55_3, ~mu14_4
|
||||
# 55| r55_5(_Imaginary float) = Div : r55_2, r55_4
|
||||
# 55| r55_6(glval<_Imaginary float>) = VariableAddress[jf3] :
|
||||
# 55| mu55_7(_Imaginary float) = Store : &:r55_6, r55_5
|
||||
# 56| v56_1(void) = NoOp :
|
||||
# 14| v14_5(void) = ReturnVoid :
|
||||
# 14| v14_6(void) = UnmodeledUse : mu*
|
||||
# 14| v14_7(void) = AliasedUse : ~mu14_4
|
||||
# 14| v14_8(void) = ExitFunction :
|
||||
|
||||
# 58| void complex_conversions()
|
||||
# 58| Block 0
|
||||
# 58| v58_1(void) = EnterFunction :
|
||||
# 58| mu58_2(unknown) = AliasedDefinition :
|
||||
# 58| mu58_3(unknown) = InitializeNonLocal :
|
||||
# 58| mu58_4(unknown) = UnmodeledDefinition :
|
||||
# 59| r59_1(glval<float>) = VariableAddress[f] :
|
||||
# 59| r59_2(float) = Constant[2.0] :
|
||||
# 59| mu59_3(float) = Store : &:r59_1, r59_2
|
||||
# 60| r60_1(glval<double>) = VariableAddress[d] :
|
||||
# 60| r60_2(double) = Constant[3.0] :
|
||||
# 60| mu60_3(double) = Store : &:r60_1, r60_2
|
||||
# 61| r61_1(glval<long double>) = VariableAddress[ld] :
|
||||
# 61| r61_2(long double) = Constant[5.0] :
|
||||
# 61| mu61_3(long double) = Store : &:r61_1, r61_2
|
||||
# 62| r62_1(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 62| r62_2(double) = Constant[7.0] :
|
||||
# 62| r62_3(_Complex float) = Convert : r62_2
|
||||
# 62| mu62_4(_Complex float) = Store : &:r62_1, r62_3
|
||||
# 63| r63_1(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 63| r63_2(double) = Constant[11.0] :
|
||||
# 63| r63_3(_Complex double) = Convert : r63_2
|
||||
# 63| mu63_4(_Complex double) = Store : &:r63_1, r63_3
|
||||
# 64| r64_1(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 64| r64_2(double) = Constant[13.0] :
|
||||
# 64| r64_3(_Complex long double) = Convert : r64_2
|
||||
# 64| mu64_4(_Complex long double) = Store : &:r64_1, r64_3
|
||||
# 65| r65_1(glval<_Imaginary float>) = VariableAddress[jf] :
|
||||
# 65| r65_2(_Imaginary float) = Constant[1.0i] :
|
||||
# 65| mu65_3(_Imaginary float) = Store : &:r65_1, r65_2
|
||||
# 66| r66_1(glval<_Imaginary double>) = VariableAddress[jd] :
|
||||
# 66| r66_2(_Imaginary float) = Constant[1.0i] :
|
||||
# 66| r66_3(_Imaginary double) = Convert : r66_2
|
||||
# 66| mu66_4(_Imaginary double) = Store : &:r66_1, r66_3
|
||||
# 67| r67_1(glval<_Imaginary long double>) = VariableAddress[jld] :
|
||||
# 67| r67_2(_Imaginary float) = Constant[1.0i] :
|
||||
# 67| r67_3(_Imaginary long double) = Convert : r67_2
|
||||
# 67| mu67_4(_Imaginary long double) = Store : &:r67_1, r67_3
|
||||
# 70| r70_1(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 70| r70_2(_Complex float) = Load : &:r70_1, ~mu58_4
|
||||
# 70| r70_3(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 70| mu70_4(_Complex float) = Store : &:r70_3, r70_2
|
||||
# 71| r71_1(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 71| r71_2(_Complex double) = Load : &:r71_1, ~mu58_4
|
||||
# 71| r71_3(_Complex float) = Convert : r71_2
|
||||
# 71| r71_4(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 71| mu71_5(_Complex float) = Store : &:r71_4, r71_3
|
||||
# 72| r72_1(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 72| r72_2(_Complex long double) = Load : &:r72_1, ~mu58_4
|
||||
# 72| r72_3(_Complex float) = Convert : r72_2
|
||||
# 72| r72_4(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 72| mu72_5(_Complex float) = Store : &:r72_4, r72_3
|
||||
# 73| r73_1(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 73| r73_2(_Complex float) = Load : &:r73_1, ~mu58_4
|
||||
# 73| r73_3(_Complex double) = Convert : r73_2
|
||||
# 73| r73_4(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 73| mu73_5(_Complex double) = Store : &:r73_4, r73_3
|
||||
# 74| r74_1(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 74| r74_2(_Complex double) = Load : &:r74_1, ~mu58_4
|
||||
# 74| r74_3(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 74| mu74_4(_Complex double) = Store : &:r74_3, r74_2
|
||||
# 75| r75_1(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 75| r75_2(_Complex long double) = Load : &:r75_1, ~mu58_4
|
||||
# 75| r75_3(_Complex double) = Convert : r75_2
|
||||
# 75| r75_4(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 75| mu75_5(_Complex double) = Store : &:r75_4, r75_3
|
||||
# 76| r76_1(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 76| r76_2(_Complex float) = Load : &:r76_1, ~mu58_4
|
||||
# 76| r76_3(_Complex long double) = Convert : r76_2
|
||||
# 76| r76_4(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 76| mu76_5(_Complex long double) = Store : &:r76_4, r76_3
|
||||
# 77| r77_1(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 77| r77_2(_Complex double) = Load : &:r77_1, ~mu58_4
|
||||
# 77| r77_3(_Complex long double) = Convert : r77_2
|
||||
# 77| r77_4(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 77| mu77_5(_Complex long double) = Store : &:r77_4, r77_3
|
||||
# 78| r78_1(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 78| r78_2(_Complex long double) = Load : &:r78_1, ~mu58_4
|
||||
# 78| r78_3(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 78| mu78_4(_Complex long double) = Store : &:r78_3, r78_2
|
||||
# 81| r81_1(glval<float>) = VariableAddress[f] :
|
||||
# 81| r81_2(float) = Load : &:r81_1, ~mu58_4
|
||||
# 81| r81_3(_Complex float) = Convert : r81_2
|
||||
# 81| r81_4(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 81| mu81_5(_Complex float) = Store : &:r81_4, r81_3
|
||||
# 82| r82_1(glval<double>) = VariableAddress[d] :
|
||||
# 82| r82_2(double) = Load : &:r82_1, ~mu58_4
|
||||
# 82| r82_3(_Complex float) = Convert : r82_2
|
||||
# 82| r82_4(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 82| mu82_5(_Complex float) = Store : &:r82_4, r82_3
|
||||
# 83| r83_1(glval<long double>) = VariableAddress[ld] :
|
||||
# 83| r83_2(long double) = Load : &:r83_1, ~mu58_4
|
||||
# 83| r83_3(_Complex float) = Convert : r83_2
|
||||
# 83| r83_4(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 83| mu83_5(_Complex float) = Store : &:r83_4, r83_3
|
||||
# 84| r84_1(glval<float>) = VariableAddress[f] :
|
||||
# 84| r84_2(float) = Load : &:r84_1, ~mu58_4
|
||||
# 84| r84_3(_Complex double) = Convert : r84_2
|
||||
# 84| r84_4(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 84| mu84_5(_Complex double) = Store : &:r84_4, r84_3
|
||||
# 85| r85_1(glval<double>) = VariableAddress[d] :
|
||||
# 85| r85_2(double) = Load : &:r85_1, ~mu58_4
|
||||
# 85| r85_3(_Complex double) = Convert : r85_2
|
||||
# 85| r85_4(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 85| mu85_5(_Complex double) = Store : &:r85_4, r85_3
|
||||
# 86| r86_1(glval<long double>) = VariableAddress[ld] :
|
||||
# 86| r86_2(long double) = Load : &:r86_1, ~mu58_4
|
||||
# 86| r86_3(_Complex double) = Convert : r86_2
|
||||
# 86| r86_4(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 86| mu86_5(_Complex double) = Store : &:r86_4, r86_3
|
||||
# 87| r87_1(glval<float>) = VariableAddress[f] :
|
||||
# 87| r87_2(float) = Load : &:r87_1, ~mu58_4
|
||||
# 87| r87_3(_Complex long double) = Convert : r87_2
|
||||
# 87| r87_4(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 87| mu87_5(_Complex long double) = Store : &:r87_4, r87_3
|
||||
# 88| r88_1(glval<double>) = VariableAddress[d] :
|
||||
# 88| r88_2(double) = Load : &:r88_1, ~mu58_4
|
||||
# 88| r88_3(_Complex long double) = Convert : r88_2
|
||||
# 88| r88_4(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 88| mu88_5(_Complex long double) = Store : &:r88_4, r88_3
|
||||
# 89| r89_1(glval<long double>) = VariableAddress[ld] :
|
||||
# 89| r89_2(long double) = Load : &:r89_1, ~mu58_4
|
||||
# 89| r89_3(_Complex long double) = Convert : r89_2
|
||||
# 89| r89_4(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 89| mu89_5(_Complex long double) = Store : &:r89_4, r89_3
|
||||
# 92| r92_1(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 92| r92_2(_Complex float) = Load : &:r92_1, ~mu58_4
|
||||
# 92| r92_3(float) = Convert : r92_2
|
||||
# 92| r92_4(glval<float>) = VariableAddress[f] :
|
||||
# 92| mu92_5(float) = Store : &:r92_4, r92_3
|
||||
# 93| r93_1(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 93| r93_2(_Complex double) = Load : &:r93_1, ~mu58_4
|
||||
# 93| r93_3(float) = Convert : r93_2
|
||||
# 93| r93_4(glval<float>) = VariableAddress[f] :
|
||||
# 93| mu93_5(float) = Store : &:r93_4, r93_3
|
||||
# 94| r94_1(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 94| r94_2(_Complex long double) = Load : &:r94_1, ~mu58_4
|
||||
# 94| r94_3(float) = Convert : r94_2
|
||||
# 94| r94_4(glval<float>) = VariableAddress[f] :
|
||||
# 94| mu94_5(float) = Store : &:r94_4, r94_3
|
||||
# 95| r95_1(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 95| r95_2(_Complex float) = Load : &:r95_1, ~mu58_4
|
||||
# 95| r95_3(double) = Convert : r95_2
|
||||
# 95| r95_4(glval<double>) = VariableAddress[d] :
|
||||
# 95| mu95_5(double) = Store : &:r95_4, r95_3
|
||||
# 96| r96_1(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 96| r96_2(_Complex double) = Load : &:r96_1, ~mu58_4
|
||||
# 96| r96_3(double) = Convert : r96_2
|
||||
# 96| r96_4(glval<double>) = VariableAddress[d] :
|
||||
# 96| mu96_5(double) = Store : &:r96_4, r96_3
|
||||
# 97| r97_1(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 97| r97_2(_Complex long double) = Load : &:r97_1, ~mu58_4
|
||||
# 97| r97_3(double) = Convert : r97_2
|
||||
# 97| r97_4(glval<double>) = VariableAddress[d] :
|
||||
# 97| mu97_5(double) = Store : &:r97_4, r97_3
|
||||
# 98| r98_1(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 98| r98_2(_Complex float) = Load : &:r98_1, ~mu58_4
|
||||
# 98| r98_3(long double) = Convert : r98_2
|
||||
# 98| r98_4(glval<long double>) = VariableAddress[ld] :
|
||||
# 98| mu98_5(long double) = Store : &:r98_4, r98_3
|
||||
# 99| r99_1(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 99| r99_2(_Complex double) = Load : &:r99_1, ~mu58_4
|
||||
# 99| r99_3(long double) = Convert : r99_2
|
||||
# 99| r99_4(glval<long double>) = VariableAddress[ld] :
|
||||
# 99| mu99_5(long double) = Store : &:r99_4, r99_3
|
||||
# 100| r100_1(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 100| r100_2(_Complex long double) = Load : &:r100_1, ~mu58_4
|
||||
# 100| r100_3(long double) = Convert : r100_2
|
||||
# 100| r100_4(glval<long double>) = VariableAddress[ld] :
|
||||
# 100| mu100_5(long double) = Store : &:r100_4, r100_3
|
||||
# 103| r103_1(glval<_Imaginary float>) = VariableAddress[jf] :
|
||||
# 103| r103_2(_Imaginary float) = Load : &:r103_1, ~mu58_4
|
||||
# 103| r103_3(_Complex float) = Convert : r103_2
|
||||
# 103| r103_4(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 103| mu103_5(_Complex float) = Store : &:r103_4, r103_3
|
||||
# 104| r104_1(glval<_Imaginary double>) = VariableAddress[jd] :
|
||||
# 104| r104_2(_Imaginary double) = Load : &:r104_1, ~mu58_4
|
||||
# 104| r104_3(_Complex float) = Convert : r104_2
|
||||
# 104| r104_4(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 104| mu104_5(_Complex float) = Store : &:r104_4, r104_3
|
||||
# 105| r105_1(glval<_Imaginary long double>) = VariableAddress[jld] :
|
||||
# 105| r105_2(_Imaginary long double) = Load : &:r105_1, ~mu58_4
|
||||
# 105| r105_3(_Complex float) = Convert : r105_2
|
||||
# 105| r105_4(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 105| mu105_5(_Complex float) = Store : &:r105_4, r105_3
|
||||
# 106| r106_1(glval<_Imaginary float>) = VariableAddress[jf] :
|
||||
# 106| r106_2(_Imaginary float) = Load : &:r106_1, ~mu58_4
|
||||
# 106| r106_3(_Complex double) = Convert : r106_2
|
||||
# 106| r106_4(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 106| mu106_5(_Complex double) = Store : &:r106_4, r106_3
|
||||
# 107| r107_1(glval<_Imaginary double>) = VariableAddress[jd] :
|
||||
# 107| r107_2(_Imaginary double) = Load : &:r107_1, ~mu58_4
|
||||
# 107| r107_3(_Complex double) = Convert : r107_2
|
||||
# 107| r107_4(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 107| mu107_5(_Complex double) = Store : &:r107_4, r107_3
|
||||
# 108| r108_1(glval<_Imaginary long double>) = VariableAddress[jld] :
|
||||
# 108| r108_2(_Imaginary long double) = Load : &:r108_1, ~mu58_4
|
||||
# 108| r108_3(_Complex double) = Convert : r108_2
|
||||
# 108| r108_4(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 108| mu108_5(_Complex double) = Store : &:r108_4, r108_3
|
||||
# 109| r109_1(glval<_Imaginary float>) = VariableAddress[jf] :
|
||||
# 109| r109_2(_Imaginary float) = Load : &:r109_1, ~mu58_4
|
||||
# 109| r109_3(_Complex long double) = Convert : r109_2
|
||||
# 109| r109_4(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 109| mu109_5(_Complex long double) = Store : &:r109_4, r109_3
|
||||
# 110| r110_1(glval<_Imaginary double>) = VariableAddress[jd] :
|
||||
# 110| r110_2(_Imaginary double) = Load : &:r110_1, ~mu58_4
|
||||
# 110| r110_3(_Complex long double) = Convert : r110_2
|
||||
# 110| r110_4(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 110| mu110_5(_Complex long double) = Store : &:r110_4, r110_3
|
||||
# 111| r111_1(glval<_Imaginary long double>) = VariableAddress[jld] :
|
||||
# 111| r111_2(_Imaginary long double) = Load : &:r111_1, ~mu58_4
|
||||
# 111| r111_3(_Complex long double) = Convert : r111_2
|
||||
# 111| r111_4(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 111| mu111_5(_Complex long double) = Store : &:r111_4, r111_3
|
||||
# 114| r114_1(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 114| r114_2(_Complex float) = Load : &:r114_1, ~mu58_4
|
||||
# 114| r114_3(_Imaginary float) = Convert : r114_2
|
||||
# 114| r114_4(glval<_Imaginary float>) = VariableAddress[jf] :
|
||||
# 114| mu114_5(_Imaginary float) = Store : &:r114_4, r114_3
|
||||
# 115| r115_1(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 115| r115_2(_Complex double) = Load : &:r115_1, ~mu58_4
|
||||
# 115| r115_3(_Imaginary float) = Convert : r115_2
|
||||
# 115| r115_4(glval<_Imaginary float>) = VariableAddress[jf] :
|
||||
# 115| mu115_5(_Imaginary float) = Store : &:r115_4, r115_3
|
||||
# 116| r116_1(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 116| r116_2(_Complex long double) = Load : &:r116_1, ~mu58_4
|
||||
# 116| r116_3(_Imaginary float) = Convert : r116_2
|
||||
# 116| r116_4(glval<_Imaginary float>) = VariableAddress[jf] :
|
||||
# 116| mu116_5(_Imaginary float) = Store : &:r116_4, r116_3
|
||||
# 117| r117_1(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 117| r117_2(_Complex float) = Load : &:r117_1, ~mu58_4
|
||||
# 117| r117_3(_Imaginary double) = Convert : r117_2
|
||||
# 117| r117_4(glval<_Imaginary double>) = VariableAddress[jd] :
|
||||
# 117| mu117_5(_Imaginary double) = Store : &:r117_4, r117_3
|
||||
# 118| r118_1(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 118| r118_2(_Complex double) = Load : &:r118_1, ~mu58_4
|
||||
# 118| r118_3(_Imaginary double) = Convert : r118_2
|
||||
# 118| r118_4(glval<_Imaginary double>) = VariableAddress[jd] :
|
||||
# 118| mu118_5(_Imaginary double) = Store : &:r118_4, r118_3
|
||||
# 119| r119_1(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 119| r119_2(_Complex long double) = Load : &:r119_1, ~mu58_4
|
||||
# 119| r119_3(_Imaginary double) = Convert : r119_2
|
||||
# 119| r119_4(glval<_Imaginary double>) = VariableAddress[jd] :
|
||||
# 119| mu119_5(_Imaginary double) = Store : &:r119_4, r119_3
|
||||
# 120| r120_1(glval<_Complex float>) = VariableAddress[cf] :
|
||||
# 120| r120_2(_Complex float) = Load : &:r120_1, ~mu58_4
|
||||
# 120| r120_3(_Imaginary long double) = Convert : r120_2
|
||||
# 120| r120_4(glval<_Imaginary long double>) = VariableAddress[jld] :
|
||||
# 120| mu120_5(_Imaginary long double) = Store : &:r120_4, r120_3
|
||||
# 121| r121_1(glval<_Complex double>) = VariableAddress[cd] :
|
||||
# 121| r121_2(_Complex double) = Load : &:r121_1, ~mu58_4
|
||||
# 121| r121_3(_Imaginary long double) = Convert : r121_2
|
||||
# 121| r121_4(glval<_Imaginary long double>) = VariableAddress[jld] :
|
||||
# 121| mu121_5(_Imaginary long double) = Store : &:r121_4, r121_3
|
||||
# 122| r122_1(glval<_Complex long double>) = VariableAddress[cld] :
|
||||
# 122| r122_2(_Complex long double) = Load : &:r122_1, ~mu58_4
|
||||
# 122| r122_3(_Imaginary long double) = Convert : r122_2
|
||||
# 122| r122_4(glval<_Imaginary long double>) = VariableAddress[jld] :
|
||||
# 122| mu122_5(_Imaginary long double) = Store : &:r122_4, r122_3
|
||||
# 125| r125_1(glval<float>) = VariableAddress[f] :
|
||||
# 125| r125_2(float) = Load : &:r125_1, ~mu58_4
|
||||
# 125| r125_3(_Imaginary float) = Convert : r125_2
|
||||
# 125| r125_4(glval<_Imaginary float>) = VariableAddress[jf] :
|
||||
# 125| mu125_5(_Imaginary float) = Store : &:r125_4, r125_3
|
||||
# 126| r126_1(glval<double>) = VariableAddress[d] :
|
||||
# 126| r126_2(double) = Load : &:r126_1, ~mu58_4
|
||||
# 126| r126_3(_Imaginary float) = Convert : r126_2
|
||||
# 126| r126_4(glval<_Imaginary float>) = VariableAddress[jf] :
|
||||
# 126| mu126_5(_Imaginary float) = Store : &:r126_4, r126_3
|
||||
# 127| r127_1(glval<long double>) = VariableAddress[ld] :
|
||||
# 127| r127_2(long double) = Load : &:r127_1, ~mu58_4
|
||||
# 127| r127_3(_Imaginary float) = Convert : r127_2
|
||||
# 127| r127_4(glval<_Imaginary float>) = VariableAddress[jf] :
|
||||
# 127| mu127_5(_Imaginary float) = Store : &:r127_4, r127_3
|
||||
# 128| r128_1(glval<float>) = VariableAddress[f] :
|
||||
# 128| r128_2(float) = Load : &:r128_1, ~mu58_4
|
||||
# 128| r128_3(_Imaginary double) = Convert : r128_2
|
||||
# 128| r128_4(glval<_Imaginary double>) = VariableAddress[jd] :
|
||||
# 128| mu128_5(_Imaginary double) = Store : &:r128_4, r128_3
|
||||
# 129| r129_1(glval<double>) = VariableAddress[d] :
|
||||
# 129| r129_2(double) = Load : &:r129_1, ~mu58_4
|
||||
# 129| r129_3(_Imaginary double) = Convert : r129_2
|
||||
# 129| r129_4(glval<_Imaginary double>) = VariableAddress[jd] :
|
||||
# 129| mu129_5(_Imaginary double) = Store : &:r129_4, r129_3
|
||||
# 130| r130_1(glval<long double>) = VariableAddress[ld] :
|
||||
# 130| r130_2(long double) = Load : &:r130_1, ~mu58_4
|
||||
# 130| r130_3(_Imaginary double) = Convert : r130_2
|
||||
# 130| r130_4(glval<_Imaginary double>) = VariableAddress[jd] :
|
||||
# 130| mu130_5(_Imaginary double) = Store : &:r130_4, r130_3
|
||||
# 131| r131_1(glval<float>) = VariableAddress[f] :
|
||||
# 131| r131_2(float) = Load : &:r131_1, ~mu58_4
|
||||
# 131| r131_3(_Imaginary long double) = Convert : r131_2
|
||||
# 131| r131_4(glval<_Imaginary long double>) = VariableAddress[jld] :
|
||||
# 131| mu131_5(_Imaginary long double) = Store : &:r131_4, r131_3
|
||||
# 132| r132_1(glval<double>) = VariableAddress[d] :
|
||||
# 132| r132_2(double) = Load : &:r132_1, ~mu58_4
|
||||
# 132| r132_3(_Imaginary long double) = Convert : r132_2
|
||||
# 132| r132_4(glval<_Imaginary long double>) = VariableAddress[jld] :
|
||||
# 132| mu132_5(_Imaginary long double) = Store : &:r132_4, r132_3
|
||||
# 133| r133_1(glval<long double>) = VariableAddress[ld] :
|
||||
# 133| r133_2(long double) = Load : &:r133_1, ~mu58_4
|
||||
# 133| r133_3(_Imaginary long double) = Convert : r133_2
|
||||
# 133| r133_4(glval<_Imaginary long double>) = VariableAddress[jld] :
|
||||
# 133| mu133_5(_Imaginary long double) = Store : &:r133_4, r133_3
|
||||
# 136| r136_1(glval<_Imaginary float>) = VariableAddress[jf] :
|
||||
# 136| r136_2(_Imaginary float) = Load : &:r136_1, ~mu58_4
|
||||
# 136| r136_3(float) = Convert : r136_2
|
||||
# 136| r136_4(glval<float>) = VariableAddress[f] :
|
||||
# 136| mu136_5(float) = Store : &:r136_4, r136_3
|
||||
# 137| r137_1(glval<_Imaginary double>) = VariableAddress[jd] :
|
||||
# 137| r137_2(_Imaginary double) = Load : &:r137_1, ~mu58_4
|
||||
# 137| r137_3(float) = Convert : r137_2
|
||||
# 137| r137_4(glval<float>) = VariableAddress[f] :
|
||||
# 137| mu137_5(float) = Store : &:r137_4, r137_3
|
||||
# 138| r138_1(glval<_Imaginary long double>) = VariableAddress[jld] :
|
||||
# 138| r138_2(_Imaginary long double) = Load : &:r138_1, ~mu58_4
|
||||
# 138| r138_3(float) = Convert : r138_2
|
||||
# 138| r138_4(glval<float>) = VariableAddress[f] :
|
||||
# 138| mu138_5(float) = Store : &:r138_4, r138_3
|
||||
# 139| r139_1(glval<_Imaginary float>) = VariableAddress[jf] :
|
||||
# 139| r139_2(_Imaginary float) = Load : &:r139_1, ~mu58_4
|
||||
# 139| r139_3(double) = Convert : r139_2
|
||||
# 139| r139_4(glval<double>) = VariableAddress[d] :
|
||||
# 139| mu139_5(double) = Store : &:r139_4, r139_3
|
||||
# 140| r140_1(glval<_Imaginary double>) = VariableAddress[jd] :
|
||||
# 140| r140_2(_Imaginary double) = Load : &:r140_1, ~mu58_4
|
||||
# 140| r140_3(double) = Convert : r140_2
|
||||
# 140| r140_4(glval<double>) = VariableAddress[d] :
|
||||
# 140| mu140_5(double) = Store : &:r140_4, r140_3
|
||||
# 141| r141_1(glval<_Imaginary long double>) = VariableAddress[jld] :
|
||||
# 141| r141_2(_Imaginary long double) = Load : &:r141_1, ~mu58_4
|
||||
# 141| r141_3(double) = Convert : r141_2
|
||||
# 141| r141_4(glval<double>) = VariableAddress[d] :
|
||||
# 141| mu141_5(double) = Store : &:r141_4, r141_3
|
||||
# 142| r142_1(glval<_Imaginary float>) = VariableAddress[jf] :
|
||||
# 142| r142_2(_Imaginary float) = Load : &:r142_1, ~mu58_4
|
||||
# 142| r142_3(long double) = Convert : r142_2
|
||||
# 142| r142_4(glval<long double>) = VariableAddress[ld] :
|
||||
# 142| mu142_5(long double) = Store : &:r142_4, r142_3
|
||||
# 143| r143_1(glval<_Imaginary double>) = VariableAddress[jd] :
|
||||
# 143| r143_2(_Imaginary double) = Load : &:r143_1, ~mu58_4
|
||||
# 143| r143_3(long double) = Convert : r143_2
|
||||
# 143| r143_4(glval<long double>) = VariableAddress[ld] :
|
||||
# 143| mu143_5(long double) = Store : &:r143_4, r143_3
|
||||
# 144| r144_1(glval<_Imaginary long double>) = VariableAddress[jld] :
|
||||
# 144| r144_2(_Imaginary long double) = Load : &:r144_1, ~mu58_4
|
||||
# 144| r144_3(long double) = Convert : r144_2
|
||||
# 144| r144_4(glval<long double>) = VariableAddress[ld] :
|
||||
# 144| mu144_5(long double) = Store : &:r144_4, r144_3
|
||||
# 145| v145_1(void) = NoOp :
|
||||
# 58| v58_5(void) = ReturnVoid :
|
||||
# 58| v58_6(void) = UnmodeledUse : mu*
|
||||
# 58| v58_7(void) = AliasedUse : ~mu58_4
|
||||
# 58| v58_8(void) = ExitFunction :
|
||||
|
||||
ir.cpp:
|
||||
# 1| void Constants()
|
||||
# 1| Block 0
|
||||
|
||||
15
cpp/ql/test/library-tests/ir/types/complex.c
Normal file
15
cpp/ql/test/library-tests/ir/types/complex.c
Normal file
@@ -0,0 +1,15 @@
|
||||
void Complex(void) {
|
||||
_Complex float cf; //$irtype=cfloat8
|
||||
_Complex double cd; //$irtype=cfloat16
|
||||
_Complex long double cld; //$irtype=cfloat32
|
||||
// _Complex __float128 cf128;
|
||||
}
|
||||
|
||||
void Imaginary(void) {
|
||||
_Imaginary float jf; //$irtype=ifloat4
|
||||
_Imaginary double jd; //$irtype=ifloat8
|
||||
_Imaginary long double jld; //$irtype=ifloat16
|
||||
// _Imaginary __float128 jf128;
|
||||
}
|
||||
|
||||
// semmle-extractor-options: --microsoft --edg --c99
|
||||
65
cpp/ql/test/library-tests/ir/types/irtypes.cpp
Normal file
65
cpp/ql/test/library-tests/ir/types/irtypes.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
struct A {
|
||||
int f_a;
|
||||
};
|
||||
|
||||
struct B {
|
||||
double f_a;
|
||||
float f_b;
|
||||
};
|
||||
|
||||
enum E {
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
Three
|
||||
};
|
||||
|
||||
enum class ScopedE {
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
Three
|
||||
};
|
||||
|
||||
void IRTypes() {
|
||||
char c; //$irtype=int1
|
||||
signed char sc; //$irtype=int1
|
||||
unsigned char uc; //$irtype=uint1
|
||||
short s; //$irtype=int2
|
||||
signed short ss; //$irtype=int2
|
||||
unsigned short us; //$irtype=uint2
|
||||
int i; //$irtype=int4
|
||||
signed int si; //$irtype=int4
|
||||
unsigned int ui; //$irtype=uint4
|
||||
long l; //$irtype=int8
|
||||
signed long sl; //$irtype=int8
|
||||
unsigned long ul; //$irtype=uint8
|
||||
long long ll; //$irtype=int8
|
||||
signed long long sll; //$irtype=int8
|
||||
unsigned long long ull; //$irtype=uint8
|
||||
bool b; //$irtype=bool1
|
||||
float f; //$irtype=float4
|
||||
double d; //$irtype=float8
|
||||
long double ld; //$irtype=float16
|
||||
__float128 f128; //$irtype=float16
|
||||
|
||||
wchar_t wc; //$irtype=uint4
|
||||
// char8_t c8; //$irtype=uint1
|
||||
char16_t c16; //$irtype=uint2
|
||||
char32_t c32; //$irtype=uint4
|
||||
|
||||
int* pi; //$irtype=addr8
|
||||
int& ri = i; //$irtype=addr8
|
||||
void (*pfn)() = nullptr; //$irtype=func8
|
||||
void (&rfn)() = IRTypes; //$irtype=func8
|
||||
|
||||
A s_a; //$irtype=opaque4{A}
|
||||
B s_b; //$irtype=opaque16{B}
|
||||
|
||||
E e; //$irtype=uint4
|
||||
ScopedE se; //$irtype=uint4
|
||||
|
||||
B a_b[10]; //$irtype=opaque160{B[10]}
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++17 --clang
|
||||
0
cpp/ql/test/library-tests/ir/types/irtypes.expected
Normal file
0
cpp/ql/test/library-tests/ir/types/irtypes.expected
Normal file
18
cpp/ql/test/library-tests/ir/types/irtypes.ql
Normal file
18
cpp/ql/test/library-tests/ir/types/irtypes.ql
Normal file
@@ -0,0 +1,18 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.implementation.raw.IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class IRTypesTest extends InlineExpectationsTest {
|
||||
IRTypesTest() { this = "IRTypesTest" }
|
||||
|
||||
override string getARelevantTag() { result = "irtype" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(IRUserVariable irVar |
|
||||
location = irVar.getLocation() and
|
||||
element = irVar.toString() and
|
||||
tag = "irtype" and
|
||||
value = irVar.getIRType().toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -425,27 +425,27 @@ test.cpp:
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 56| Block 3
|
||||
# 56| m56_1(decltype(nullptr)) = Phi : from 2:m55_4, from 5:m56_23
|
||||
# 56| m56_1(char *) = Phi : from 2:m55_4, from 5:m56_23
|
||||
# 56| valnum = m56_1, r56_13, r56_20, r56_3, r59_2
|
||||
# 56| r56_2(glval<char *>) = VariableAddress[ptr] :
|
||||
# 56| r56_2(glval<char *>) = VariableAddress[ptr] :
|
||||
# 56| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1
|
||||
# 56| r56_3(char *) = Load : &:r56_2, m56_1
|
||||
# 56| r56_3(char *) = Load : &:r56_2, m56_1
|
||||
# 56| valnum = m56_1, r56_13, r56_20, r56_3, r59_2
|
||||
# 56| r56_4(char) = Load : &:r56_3, ~m49_4
|
||||
# 56| r56_4(char) = Load : &:r56_3, ~m49_4
|
||||
# 56| valnum = r56_14, r56_4, r59_3
|
||||
# 56| r56_5(int) = Convert : r56_4
|
||||
# 56| r56_5(int) = Convert : r56_4
|
||||
# 56| valnum = r56_15, r56_5, r59_4
|
||||
# 56| r56_6(glval<char *>) = VariableAddress[str] :
|
||||
# 56| r56_6(glval<char *>) = VariableAddress[str] :
|
||||
# 56| valnum = r49_6, r53_2, r56_6
|
||||
# 56| r56_7(char *) = Load : &:r56_6, m49_7
|
||||
# 56| r56_7(char *) = Load : &:r56_6, m49_7
|
||||
# 56| valnum = m49_7, r49_8, r53_3, r56_7
|
||||
# 56| r56_8(char) = Load : &:r56_7, ~m49_9
|
||||
# 56| r56_8(char) = Load : &:r56_7, ~m49_9
|
||||
# 56| valnum = r53_4, r56_8
|
||||
# 56| r56_9(int) = Convert : r56_8
|
||||
# 56| r56_9(int) = Convert : r56_8
|
||||
# 56| valnum = r53_5, r56_9
|
||||
# 56| r56_10(bool) = CompareNE : r56_5, r56_9
|
||||
# 56| r56_10(bool) = CompareNE : r56_5, r56_9
|
||||
# 56| valnum = unique
|
||||
# 56| v56_11(void) = ConditionalBranch : r56_10
|
||||
# 56| v56_11(void) = ConditionalBranch : r56_10
|
||||
#-----| False -> Block 6
|
||||
#-----| True -> Block 4
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
| ..()(..) | RoutineType | | | | |
|
||||
| ..(*)(..) | FunctionPointerType | | ..()(..) | | |
|
||||
| _Complex __float128 | FloatingPointType | | | | |
|
||||
| _Complex double | FloatingPointType | | | | |
|
||||
| _Complex float | FloatingPointType | | | | |
|
||||
| _Complex long double | FloatingPointType | | | | |
|
||||
| _Complex __float128 | BinaryFloatingPointType, ComplexNumberType | | | | |
|
||||
| _Complex double | BinaryFloatingPointType, ComplexNumberType | | | | |
|
||||
| _Complex float | BinaryFloatingPointType, ComplexNumberType | | | | |
|
||||
| _Complex long double | BinaryFloatingPointType, ComplexNumberType | | | | |
|
||||
| _Decimal32 | Decimal32Type | | | | |
|
||||
| _Decimal64 | Decimal64Type | | | | |
|
||||
| _Decimal128 | Decimal128Type | | | | |
|
||||
| _Float32 | FloatingPointType | | | | |
|
||||
| _Float32x | FloatingPointType | | | | |
|
||||
| _Float64 | FloatingPointType | | | | |
|
||||
| _Float64x | FloatingPointType | | | | |
|
||||
| _Float128 | FloatingPointType | | | | |
|
||||
| _Float128x | FloatingPointType | | | | |
|
||||
| _Imaginary double | FloatingPointType | | | | |
|
||||
| _Imaginary float | FloatingPointType | | | | |
|
||||
| _Imaginary long double | FloatingPointType | | | | |
|
||||
| _Float32 | BinaryFloatingPointType, RealNumberType | | | | |
|
||||
| _Float32x | BinaryFloatingPointType, RealNumberType | | | | |
|
||||
| _Float64 | BinaryFloatingPointType, RealNumberType | | | | |
|
||||
| _Float64x | BinaryFloatingPointType, RealNumberType | | | | |
|
||||
| _Float128 | BinaryFloatingPointType, RealNumberType | | | | |
|
||||
| _Float128x | BinaryFloatingPointType, RealNumberType | | | | |
|
||||
| _Imaginary double | BinaryFloatingPointType, ImaginaryNumberType | | | | |
|
||||
| _Imaginary float | BinaryFloatingPointType, ImaginaryNumberType | | | | |
|
||||
| _Imaginary long double | BinaryFloatingPointType, ImaginaryNumberType | | | | |
|
||||
| __float128 | Float128Type | | | | |
|
||||
| __int128 | Int128Type | | | | |
|
||||
| __va_list_tag | DirectAccessHolder, MetricClass, Struct, StructLikeClass | | | | |
|
||||
|
||||
@@ -5,12 +5,6 @@ edges
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | (unsigned long)... |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | (unsigned long)... |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | tainted |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | tainted |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | tainted |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | tainted |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... |
|
||||
@@ -33,42 +27,38 @@ edges
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | (unsigned long)... |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | (unsigned long)... |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | tainted |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | tainted |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | tainted |
|
||||
| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | tainted |
|
||||
| test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:27 | (unsigned long)... |
|
||||
| test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:27 | size |
|
||||
| test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:27 | size |
|
||||
| test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... |
|
||||
| test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... |
|
||||
| test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:27 | (unsigned long)... |
|
||||
| test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:27 | size |
|
||||
| test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:27 | size |
|
||||
| test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:41 | ... * ... |
|
||||
| test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:41 | ... * ... |
|
||||
| test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:13 | (unsigned long)... |
|
||||
| test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:13 | size |
|
||||
| test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:13 | size |
|
||||
| test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:27 | ... * ... |
|
||||
| test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:27 | ... * ... |
|
||||
| test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:13 | (unsigned long)... |
|
||||
| test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:13 | size |
|
||||
| test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:13 | size |
|
||||
| test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:27 | ... * ... |
|
||||
| test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:27 | ... * ... |
|
||||
| test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:14 | (unsigned long)... |
|
||||
| test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:14 | size |
|
||||
| test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:14 | size |
|
||||
| test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:28 | ... * ... |
|
||||
| test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:28 | ... * ... |
|
||||
| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:14 | (unsigned long)... |
|
||||
| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:14 | size |
|
||||
| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:14 | size |
|
||||
| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:28 | ... * ... |
|
||||
| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:28 | ... * ... |
|
||||
| test.cpp:201:9:201:42 | Store | test.cpp:231:9:231:24 | call to get_tainted_size |
|
||||
| test.cpp:201:9:201:42 | Store | test.cpp:231:9:231:24 | call to get_tainted_size |
|
||||
| test.cpp:201:14:201:19 | call to getenv | test.cpp:201:9:201:42 | Store |
|
||||
| test.cpp:201:14:201:27 | (const char *)... | test.cpp:201:9:201:42 | Store |
|
||||
| test.cpp:214:23:214:23 | s | test.cpp:215:21:215:21 | s |
|
||||
| test.cpp:214:23:214:23 | s | test.cpp:215:21:215:21 | s |
|
||||
| test.cpp:220:21:220:21 | s | test.cpp:221:21:221:21 | s |
|
||||
| test.cpp:220:21:220:21 | s | test.cpp:221:21:221:21 | s |
|
||||
| test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | (size_t)... |
|
||||
| test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size |
|
||||
| test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size |
|
||||
| test.cpp:227:24:227:29 | call to getenv | test.cpp:235:11:235:20 | (size_t)... |
|
||||
| test.cpp:227:24:227:29 | call to getenv | test.cpp:237:10:237:19 | (size_t)... |
|
||||
| test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | (size_t)... |
|
||||
| test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | local_size |
|
||||
| test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | local_size |
|
||||
| test.cpp:227:24:227:37 | (const char *)... | test.cpp:235:11:235:20 | (size_t)... |
|
||||
| test.cpp:227:24:227:37 | (const char *)... | test.cpp:237:10:237:19 | (size_t)... |
|
||||
| test.cpp:235:11:235:20 | (size_t)... | test.cpp:214:23:214:23 | s |
|
||||
| test.cpp:237:10:237:19 | (size_t)... | test.cpp:220:21:220:21 | s |
|
||||
nodes
|
||||
| test.cpp:39:21:39:24 | argv | semmle.label | argv |
|
||||
| test.cpp:39:21:39:24 | argv | semmle.label | argv |
|
||||
@@ -77,11 +67,6 @@ nodes
|
||||
| test.cpp:42:38:42:44 | tainted | semmle.label | tainted |
|
||||
| test.cpp:42:38:42:44 | tainted | semmle.label | tainted |
|
||||
| test.cpp:42:38:42:44 | tainted | semmle.label | tainted |
|
||||
| test.cpp:43:38:43:44 | (unsigned long)... | semmle.label | (unsigned long)... |
|
||||
| test.cpp:43:38:43:44 | (unsigned long)... | semmle.label | (unsigned long)... |
|
||||
| test.cpp:43:38:43:44 | tainted | semmle.label | tainted |
|
||||
| test.cpp:43:38:43:44 | tainted | semmle.label | tainted |
|
||||
| test.cpp:43:38:43:44 | tainted | semmle.label | tainted |
|
||||
| test.cpp:43:38:43:63 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:43:38:43:63 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:43:38:43:63 | ... * ... | semmle.label | ... * ... |
|
||||
@@ -99,53 +84,55 @@ nodes
|
||||
| test.cpp:52:35:52:60 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:52:35:52:60 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:52:35:52:60 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:52:54:52:60 | (unsigned long)... | semmle.label | (unsigned long)... |
|
||||
| test.cpp:52:54:52:60 | (unsigned long)... | semmle.label | (unsigned long)... |
|
||||
| test.cpp:52:54:52:60 | tainted | semmle.label | tainted |
|
||||
| test.cpp:52:54:52:60 | tainted | semmle.label | tainted |
|
||||
| test.cpp:52:54:52:60 | tainted | semmle.label | tainted |
|
||||
| test.cpp:123:18:123:23 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:123:18:123:31 | (const char *)... | semmle.label | (const char *)... |
|
||||
| test.cpp:127:24:127:27 | (unsigned long)... | semmle.label | (unsigned long)... |
|
||||
| test.cpp:127:24:127:27 | (unsigned long)... | semmle.label | (unsigned long)... |
|
||||
| test.cpp:127:24:127:27 | size | semmle.label | size |
|
||||
| test.cpp:127:24:127:27 | size | semmle.label | size |
|
||||
| test.cpp:127:24:127:27 | size | semmle.label | size |
|
||||
| test.cpp:127:24:127:41 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:127:24:127:41 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:127:24:127:41 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:132:19:132:24 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:132:19:132:32 | (const char *)... | semmle.label | (const char *)... |
|
||||
| test.cpp:134:10:134:13 | (unsigned long)... | semmle.label | (unsigned long)... |
|
||||
| test.cpp:134:10:134:13 | (unsigned long)... | semmle.label | (unsigned long)... |
|
||||
| test.cpp:134:10:134:13 | size | semmle.label | size |
|
||||
| test.cpp:134:10:134:13 | size | semmle.label | size |
|
||||
| test.cpp:134:10:134:13 | size | semmle.label | size |
|
||||
| test.cpp:134:10:134:27 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:134:10:134:27 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:134:10:134:27 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:138:19:138:24 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:138:19:138:32 | (const char *)... | semmle.label | (const char *)... |
|
||||
| test.cpp:142:11:142:14 | (unsigned long)... | semmle.label | (unsigned long)... |
|
||||
| test.cpp:142:11:142:14 | (unsigned long)... | semmle.label | (unsigned long)... |
|
||||
| test.cpp:142:11:142:14 | size | semmle.label | size |
|
||||
| test.cpp:142:11:142:14 | size | semmle.label | size |
|
||||
| test.cpp:142:11:142:14 | size | semmle.label | size |
|
||||
| test.cpp:142:11:142:28 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:142:11:142:28 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:142:11:142:28 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:201:9:201:42 | Store | semmle.label | Store |
|
||||
| test.cpp:201:14:201:19 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:201:14:201:27 | (const char *)... | semmle.label | (const char *)... |
|
||||
| test.cpp:214:23:214:23 | s | semmle.label | s |
|
||||
| test.cpp:215:21:215:21 | s | semmle.label | s |
|
||||
| test.cpp:215:21:215:21 | s | semmle.label | s |
|
||||
| test.cpp:215:21:215:21 | s | semmle.label | s |
|
||||
| test.cpp:220:21:220:21 | s | semmle.label | s |
|
||||
| test.cpp:221:21:221:21 | s | semmle.label | s |
|
||||
| test.cpp:221:21:221:21 | s | semmle.label | s |
|
||||
| test.cpp:221:21:221:21 | s | semmle.label | s |
|
||||
| test.cpp:227:24:227:29 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:227:24:227:37 | (const char *)... | semmle.label | (const char *)... |
|
||||
| test.cpp:229:9:229:18 | (size_t)... | semmle.label | (size_t)... |
|
||||
| test.cpp:229:9:229:18 | (size_t)... | semmle.label | (size_t)... |
|
||||
| test.cpp:229:9:229:18 | local_size | semmle.label | local_size |
|
||||
| test.cpp:229:9:229:18 | local_size | semmle.label | local_size |
|
||||
| test.cpp:229:9:229:18 | local_size | semmle.label | local_size |
|
||||
| test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size |
|
||||
| test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size |
|
||||
| test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size |
|
||||
| test.cpp:235:11:235:20 | (size_t)... | semmle.label | (size_t)... |
|
||||
| test.cpp:237:10:237:19 | (size_t)... | semmle.label | (size_t)... |
|
||||
#select
|
||||
| test.cpp:42:31:42:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:43:31:43:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:43:38:43:63 | ... * ... | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:45:31:45:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:45:38:45:63 | ... + ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:48:25:48:30 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | size | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:49:17:49:30 | new[] | test.cpp:39:21:39:24 | argv | test.cpp:49:26:49:29 | size | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:52:21:52:27 | call to realloc | test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:52:35:52:60 | ... * ... | test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:127:17:127:22 | call to malloc | test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:123:18:123:23 | call to getenv | user input (getenv) |
|
||||
| test.cpp:127:24:127:41 | ... * ... | test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:27 | size | This allocation size is derived from $@ and might overflow | test.cpp:123:18:123:23 | call to getenv | user input (getenv) |
|
||||
| test.cpp:134:3:134:8 | call to malloc | test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:132:19:132:24 | call to getenv | user input (getenv) |
|
||||
| test.cpp:134:10:134:27 | ... * ... | test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:13 | size | This allocation size is derived from $@ and might overflow | test.cpp:132:19:132:24 | call to getenv | user input (getenv) |
|
||||
| test.cpp:142:4:142:9 | call to malloc | test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:138:19:138:24 | call to getenv | user input (getenv) |
|
||||
| test.cpp:142:11:142:28 | ... * ... | test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:14 | size | This allocation size is derived from $@ and might overflow | test.cpp:138:19:138:24 | call to getenv | user input (getenv) |
|
||||
| test.cpp:215:14:215:19 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:215:21:215:21 | s | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) |
|
||||
| test.cpp:221:14:221:19 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:221:21:221:21 | s | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) |
|
||||
| test.cpp:229:2:229:7 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) |
|
||||
| test.cpp:231:2:231:7 | call to malloc | test.cpp:201:14:201:19 | call to getenv | test.cpp:231:9:231:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow | test.cpp:201:14:201:19 | call to getenv | user input (getenv) |
|
||||
|
||||
@@ -5,8 +5,8 @@ typedef struct {} FILE;
|
||||
|
||||
void *malloc(size_t size);
|
||||
void *realloc(void *ptr, size_t size);
|
||||
void free(void *ptr);
|
||||
int atoi(const char *nptr);
|
||||
|
||||
struct MyStruct
|
||||
{
|
||||
char data[256];
|
||||
@@ -190,3 +190,49 @@ void more_bounded_tests() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t get_untainted_size()
|
||||
{
|
||||
return 10 * sizeof(int);
|
||||
}
|
||||
|
||||
size_t get_tainted_size()
|
||||
{
|
||||
return atoi(getenv("USER")) * sizeof(int);
|
||||
}
|
||||
|
||||
size_t get_bounded_size()
|
||||
{
|
||||
size_t s = atoi(getenv("USER")) * sizeof(int);
|
||||
|
||||
if (s < 0) { s = 0; }
|
||||
if (s > 100) { s = 100; }
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void *my_alloc(size_t s) {
|
||||
void *ptr = malloc(s); // [UNHELPFUL RESULT]
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void my_func(size_t s) {
|
||||
void *ptr = malloc(s); // BAD
|
||||
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void more_cases() {
|
||||
int local_size = atoi(getenv("USER")) * sizeof(int);
|
||||
|
||||
malloc(local_size); // BAD
|
||||
malloc(get_untainted_size()); // GOOD
|
||||
malloc(get_tainted_size()); // BAD
|
||||
malloc(get_bounded_size()); // GOOD
|
||||
|
||||
my_alloc(100); // GOOD
|
||||
my_alloc(local_size); // BAD [NOT DETECTED IN CORRECT LOCATION]
|
||||
my_func(100); // GOOD
|
||||
my_func(local_size); // GOOD
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace Semmle.Autobuild
|
||||
arguments.Append(" &&");
|
||||
}
|
||||
|
||||
public CommandBuilder RunCommand(string exe, string? argumentsOpt = null)
|
||||
public CommandBuilder RunCommand(string exe, string? argumentsOpt = null, bool quoteExe = true)
|
||||
{
|
||||
var (exe0, arg0) =
|
||||
escapingMode == EscapeMode.Process && exe.EndsWith(".exe", System.StringComparison.Ordinal)
|
||||
@@ -183,7 +183,10 @@ namespace Semmle.Autobuild
|
||||
}
|
||||
else
|
||||
{
|
||||
QuoteArgument(exe0);
|
||||
if (quoteExe)
|
||||
QuoteArgument(exe0);
|
||||
else
|
||||
Argument(exe0);
|
||||
}
|
||||
Argument(arg0);
|
||||
Argument(argumentsOpt);
|
||||
|
||||
@@ -57,7 +57,14 @@ namespace Semmle.Autobuild
|
||||
var command = new CommandBuilder(builder.Actions);
|
||||
|
||||
if (vsTools != null)
|
||||
{
|
||||
command.CallBatFile(vsTools.Path);
|
||||
// `vcvarsall.bat` sets a default Platform environment variable,
|
||||
// which may not be compatible with the supported platforms of the
|
||||
// given project/solution. Unsetting it means that the default platform
|
||||
// of the project/solution is used instead.
|
||||
command.RunCommand("set Platform=&& type NUL", quoteExe: false);
|
||||
}
|
||||
|
||||
builder.MaybeIndex(command, MsBuild);
|
||||
command.QuoteArgument(projectOrSolution.FullPath);
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
|
||||
public new static Accessor Create(Context cx, IMethodSymbol symbol) =>
|
||||
AccessorFactory.Instance.CreateEntity(cx, symbol);
|
||||
AccessorFactory.Instance.CreateEntityFromSymbol(cx, symbol);
|
||||
|
||||
class AccessorFactory : ICachedEntityFactory<IMethodSymbol, Accessor>
|
||||
{
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
case MethodKind.StaticConstructor:
|
||||
case MethodKind.Constructor:
|
||||
return ConstructorFactory.Instance.CreateEntity(cx, constructor);
|
||||
return ConstructorFactory.Instance.CreateEntityFromSymbol(cx, constructor);
|
||||
default:
|
||||
throw new InternalError(constructor, "Attempt to create a Constructor from a symbol that isn't a constructor");
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
: base(cx, init) { }
|
||||
|
||||
public new static Conversion Create(Context cx, IMethodSymbol symbol) =>
|
||||
ConversionFactory.Instance.CreateEntity(cx, symbol);
|
||||
ConversionFactory.Instance.CreateEntityFromSymbol(cx, symbol);
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
|
||||
public new static Destructor Create(Context cx, IMethodSymbol symbol) =>
|
||||
DestructorFactory.Instance.CreateEntity(cx, symbol);
|
||||
DestructorFactory.Instance.CreateEntityFromSymbol(cx, symbol);
|
||||
|
||||
class DestructorFactory : ICachedEntityFactory<IMethodSymbol, Destructor>
|
||||
{
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
TypeMention.Create(Context, syntaxType, this, type);
|
||||
}
|
||||
|
||||
public static Event Create(Context cx, IEventSymbol symbol) => EventFactory.Instance.CreateEntity(cx, symbol);
|
||||
public static Event Create(Context cx, IEventSymbol symbol) => EventFactory.Instance.CreateEntityFromSymbol(cx, symbol);
|
||||
|
||||
class EventFactory : ICachedEntityFactory<IEventSymbol, Event>
|
||||
{
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
|
||||
public new static EventAccessor Create(Context cx, IMethodSymbol symbol) =>
|
||||
EventAccessorFactory.Instance.CreateEntity(cx, symbol);
|
||||
EventAccessorFactory.Instance.CreateEntityFromSymbol(cx, symbol);
|
||||
|
||||
class EventAccessorFactory : ICachedEntityFactory<IMethodSymbol, EventAccessor>
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
type = new Lazy<AnnotatedType>(() => Entities.Type.Create(cx, symbol.GetAnnotatedType()));
|
||||
}
|
||||
|
||||
public static Field Create(Context cx, IFieldSymbol field) => FieldFactory.Instance.CreateEntity(cx, field);
|
||||
public static Field Create(Context cx, IFieldSymbol field) => FieldFactory.Instance.CreateEntityFromSymbol(cx, field);
|
||||
|
||||
// Do not populate backing fields.
|
||||
// Populate Tuple fields.
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
TypeMention.Create(Context, syntax.Type, this, type);
|
||||
}
|
||||
|
||||
public static new Indexer Create(Context cx, IPropertySymbol prop) => IndexerFactory.Instance.CreateEntity(cx, prop);
|
||||
public static new Indexer Create(Context cx, IPropertySymbol prop) => IndexerFactory.Instance.CreateEntityFromSymbol(cx, prop);
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
trapFile.Write('*');
|
||||
}
|
||||
|
||||
public static new LocalFunction Create(Context cx, IMethodSymbol field) => LocalFunctionFactory.Instance.CreateEntity(cx, field);
|
||||
public static new LocalFunction Create(Context cx, IMethodSymbol field) => LocalFunctionFactory.Instance.CreateEntityFromSymbol(cx, field);
|
||||
|
||||
class LocalFunctionFactory : ICachedEntityFactory<IMethodSymbol, LocalFunction>
|
||||
{
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public static LocalVariable Create(Context cx, ISymbol local)
|
||||
{
|
||||
return LocalVariableFactory.Instance.CreateEntity(cx, local);
|
||||
return LocalVariableFactory.Instance.CreateEntityFromSymbol(cx, local);
|
||||
}
|
||||
|
||||
void DefineConstantValue(TextWriter trapFile)
|
||||
|
||||
@@ -129,7 +129,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
// Type arguments with different nullability can result in
|
||||
// a constructed method with different nullability of its parameters and return type,
|
||||
// so we need to create a distinct database entity for it.
|
||||
trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol); trapFile.Write((int)ta.Nullability); });
|
||||
trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol, m.symbol); trapFile.Write((int)ta.Nullability); });
|
||||
trapFile.Write('>');
|
||||
}
|
||||
}
|
||||
@@ -199,12 +199,9 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
/// to make the reference to <code>#3</code> in the label definition <code>#4</code> for
|
||||
/// <code>T</code> valid.
|
||||
/// </summary>
|
||||
protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type)
|
||||
protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type, ISymbol symbolBeingDefined)
|
||||
{
|
||||
if (type.ContainsTypeParameters(cx, method))
|
||||
type.BuildTypeId(cx, trapFile, (cx0, tb0, type0) => AddSignatureTypeToId(cx, tb0, method, type0));
|
||||
else
|
||||
trapFile.WriteSubId(Type.Create(cx, type));
|
||||
type.BuildTypeId(cx, trapFile, false, symbolBeingDefined, (cx0, tb0, type0, g) => AddSignatureTypeToId(cx, tb0, method, type0, g));
|
||||
}
|
||||
|
||||
protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method)
|
||||
@@ -215,13 +212,13 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
if (method.MethodKind == MethodKind.ReducedExtension)
|
||||
{
|
||||
trapFile.WriteSeparator(",", ref index);
|
||||
AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType);
|
||||
AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, method);
|
||||
}
|
||||
|
||||
foreach (var param in method.Parameters)
|
||||
{
|
||||
trapFile.WriteSeparator(",", ref index);
|
||||
AddSignatureTypeToId(cx, trapFile, method, param.Type);
|
||||
AddSignatureTypeToId(cx, trapFile, method, param.Type, method);
|
||||
switch (param.RefKind)
|
||||
{
|
||||
case RefKind.Out:
|
||||
@@ -244,9 +241,10 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public static void AddExplicitInterfaceQualifierToId(Context cx, System.IO.TextWriter trapFile, IEnumerable<ISymbol> explicitInterfaceImplementations)
|
||||
{
|
||||
if (explicitInterfaceImplementations.Any())
|
||||
foreach (var i in explicitInterfaceImplementations)
|
||||
{
|
||||
trapFile.AppendList(",", explicitInterfaceImplementations.Select(impl => cx.CreateEntity(impl.ContainingType)));
|
||||
trapFile.Write(';');
|
||||
i.ContainingType.BuildNestedTypeId(cx, trapFile, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
ExtractCompilerGenerated(trapFile);
|
||||
}
|
||||
|
||||
public new static OrdinaryMethod Create(Context cx, IMethodSymbol method) => OrdinaryMethodFactory.Instance.CreateEntity(cx, method);
|
||||
public new static OrdinaryMethod Create(Context cx, IMethodSymbol method) => OrdinaryMethodFactory.Instance.CreateEntityFromSymbol(cx, method);
|
||||
|
||||
class OrdinaryMethodFactory : ICachedEntityFactory<IMethodSymbol, OrdinaryMethod>
|
||||
{
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
bool isIndexer = prop.IsIndexer || prop.Parameters.Any();
|
||||
|
||||
return isIndexer ? Indexer.Create(cx, prop) : PropertyFactory.Instance.CreateEntity(cx, prop);
|
||||
return isIndexer ? Indexer.Create(cx, prop) : PropertyFactory.Instance.CreateEntityFromSymbol(cx, prop);
|
||||
}
|
||||
|
||||
public void VisitDeclaration(Context cx, PropertyDeclarationSyntax p)
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
trapFile.Write(";type");
|
||||
}
|
||||
|
||||
public static ArrayType Create(Context cx, IArrayTypeSymbol symbol) => ArrayTypeFactory.Instance.CreateEntity(cx, symbol);
|
||||
public static ArrayType Create(Context cx, IArrayTypeSymbol symbol) => ArrayTypeFactory.Instance.CreateEntityFromSymbol(cx, symbol);
|
||||
|
||||
class ArrayTypeFactory : ICachedEntityFactory<IArrayTypeSymbol, ArrayType>
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
DynamicType(Context cx, IDynamicTypeSymbol init)
|
||||
: base(cx, init) { }
|
||||
|
||||
public static DynamicType Create(Context cx, IDynamicTypeSymbol type) => DynamicTypeFactory.Instance.CreateEntity(cx, type);
|
||||
public static DynamicType Create(Context cx, IDynamicTypeSymbol type) => DynamicTypeFactory.Instance.CreateEntityFromSymbol(cx, type);
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => Context.Compilation.ObjectType.Locations.FirstOrDefault();
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
typeArgumentsLazy = new Lazy<Type[]>(() => symbol.TypeArguments.Select(t => Create(cx, t)).ToArray());
|
||||
}
|
||||
|
||||
public static NamedType Create(Context cx, INamedTypeSymbol type) => NamedTypeFactory.Instance.CreateEntity(cx, type);
|
||||
public static NamedType Create(Context cx, INamedTypeSymbol type) => NamedTypeFactory.Instance.CreateEntityFromSymbol(cx, type);
|
||||
|
||||
public override bool NeedsPopulation => base.NeedsPopulation || symbol.TypeKind == TypeKind.Error;
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub)));
|
||||
symbol.BuildTypeId(Context, trapFile, true, symbol, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)));
|
||||
trapFile.Write(";type");
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteSubId(referencedType);
|
||||
referencedType.symbol.BuildNestedTypeId(Context, trapFile, referencedType.symbol);
|
||||
trapFile.Write(";typeRef");
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public Type PointedAtType { get; private set; }
|
||||
|
||||
public static PointerType Create(Context cx, IPointerTypeSymbol symbol) => PointerTypeFactory.Instance.CreateEntity(cx, symbol);
|
||||
public static PointerType Create(Context cx, IPointerTypeSymbol symbol) => PointerTypeFactory.Instance.CreateEntityFromSymbol(cx, symbol);
|
||||
|
||||
class PointerTypeFactory : ICachedEntityFactory<IPointerTypeSymbol, PointerType>
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
/// </summary>
|
||||
class TupleType : Type<INamedTypeSymbol>
|
||||
{
|
||||
public static TupleType Create(Context cx, INamedTypeSymbol type) => TupleTypeFactory.Instance.CreateEntity(cx, type);
|
||||
public static TupleType Create(Context cx, INamedTypeSymbol type) => TupleTypeFactory.Instance.CreateEntityFromSymbol(cx, type);
|
||||
|
||||
class TupleTypeFactory : ICachedEntityFactory<INamedTypeSymbol, TupleType>
|
||||
{
|
||||
@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub)));
|
||||
symbol.BuildTypeId(Context, trapFile, false, symbol, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)));
|
||||
trapFile.Write(";tuple");
|
||||
}
|
||||
|
||||
|
||||
@@ -324,6 +324,14 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
|
||||
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var other = obj as Type;
|
||||
return other?.GetType() == GetType() && SymbolEqualityComparer.IncludeNullability.Equals(other.symbol, symbol);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => SymbolEqualityComparer.IncludeNullability.GetHashCode(symbol);
|
||||
}
|
||||
|
||||
abstract class Type<T> : Type where T : ITypeSymbol
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
|
||||
static public TypeParameter Create(Context cx, ITypeParameterSymbol p) =>
|
||||
TypeParameterFactory.Instance.CreateEntity(cx, p);
|
||||
TypeParameterFactory.Instance.CreateEntityFromSymbol(cx, p);
|
||||
|
||||
/// <summary>
|
||||
/// The variance of this type parameter.
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType); // Needed for op_explicit(), which differs only by return type.
|
||||
AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType, symbol); // Needed for op_explicit(), which differs only by return type.
|
||||
trapFile.Write(' ');
|
||||
BuildMethodId(this, trapFile);
|
||||
}
|
||||
@@ -190,7 +190,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
return result;
|
||||
}
|
||||
|
||||
public new static UserOperator Create(Context cx, IMethodSymbol symbol) => UserOperatorFactory.Instance.CreateEntity(cx, symbol);
|
||||
public new static UserOperator Create(Context cx, IMethodSymbol symbol) => UserOperatorFactory.Instance.CreateEntityFromSymbol(cx, symbol);
|
||||
|
||||
class UserOperatorFactory : ICachedEntityFactory<IMethodSymbol, UserOperator>
|
||||
{
|
||||
|
||||
@@ -122,6 +122,24 @@ namespace Semmle.Extraction.CSharp
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the identifier for the symbol <paramref name="type"/> to the trapfile <paramref name="trapFile"/>.
|
||||
/// If any nested types are found in the identifier, then they are written out explicitly, without
|
||||
/// prefixing the assembly ID.
|
||||
/// </summary>
|
||||
/// <param name="type">The type to write.</param>
|
||||
/// <param name="cx">The extraction context.</param>
|
||||
/// <param name="trapFile">The trap file to write to.</param>
|
||||
/// <param name="symbolBeingDefined">The outer symbol being defined (to avoid recursive ids).</param>
|
||||
public static void BuildNestedTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined)
|
||||
{
|
||||
void WriteType(Context cx, TextWriter trapFile, ITypeSymbol symbol, ISymbol symbolBeingDefined)
|
||||
{
|
||||
symbol.BuildTypeId(cx, trapFile, false, symbolBeingDefined, WriteType);
|
||||
}
|
||||
WriteType(cx, trapFile, type, symbolBeingDefined);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a unique string for this type symbol.
|
||||
///
|
||||
@@ -130,10 +148,12 @@ namespace Semmle.Extraction.CSharp
|
||||
/// </summary>
|
||||
/// <param name="cx">The extraction context.</param>
|
||||
/// <param name="trapFile">The trap builder used to store the result.</param>
|
||||
/// <param name="prefix">Whether to prefix the type ID with the assembly ID.</param>
|
||||
/// <param name="symbolBeingDefined">The outer symbol being defined (to avoid recursive ids).</param>
|
||||
/// <param name="subTermAction">The action to apply to syntactic sub terms of this type.</param>
|
||||
public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, Action<Context, TextWriter, ITypeSymbol> subTermAction)
|
||||
public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, bool prefix, ISymbol symbolBeingDefined, Action<Context, TextWriter, ITypeSymbol, ISymbol> subTermAction)
|
||||
{
|
||||
if (type.SpecialType != SpecialType.None)
|
||||
if (type.SpecialType != SpecialType.None && !(type is INamedTypeSymbol n && n.IsGenericType))
|
||||
{
|
||||
/*
|
||||
* Use the keyword ("int" etc) for the built-in types.
|
||||
@@ -150,7 +170,7 @@ namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
case TypeKind.Array:
|
||||
var array = (IArrayTypeSymbol)type;
|
||||
subTermAction(cx, trapFile, array.ElementType);
|
||||
subTermAction(cx, trapFile, array.ElementType, symbolBeingDefined);
|
||||
array.BuildArraySuffix(trapFile);
|
||||
return;
|
||||
case TypeKind.Class:
|
||||
@@ -160,15 +180,30 @@ namespace Semmle.Extraction.CSharp
|
||||
case TypeKind.Delegate:
|
||||
case TypeKind.Error:
|
||||
var named = (INamedTypeSymbol)type;
|
||||
named.BuildNamedTypeId(cx, trapFile, subTermAction);
|
||||
named.BuildNamedTypeId(cx, trapFile, prefix, symbolBeingDefined, subTermAction);
|
||||
return;
|
||||
case TypeKind.Pointer:
|
||||
var ptr = (IPointerTypeSymbol)type;
|
||||
subTermAction(cx, trapFile, ptr.PointedAtType);
|
||||
subTermAction(cx, trapFile, ptr.PointedAtType, symbolBeingDefined);
|
||||
trapFile.Write('*');
|
||||
return;
|
||||
case TypeKind.TypeParameter:
|
||||
var tp = (ITypeParameterSymbol)type;
|
||||
if (!SymbolEqualityComparer.Default.Equals(tp.ContainingSymbol, symbolBeingDefined))
|
||||
{
|
||||
switch (tp.TypeParameterKind)
|
||||
{
|
||||
case TypeParameterKind.Method:
|
||||
var method = Method.Create(cx, (IMethodSymbol)tp.ContainingSymbol);
|
||||
trapFile.WriteSubId(method);
|
||||
trapFile.Write('_');
|
||||
break;
|
||||
case TypeParameterKind.Type:
|
||||
subTermAction(cx, trapFile, tp.ContainingType, symbolBeingDefined);
|
||||
trapFile.Write('_');
|
||||
break;
|
||||
}
|
||||
}
|
||||
trapFile.Write(tp.Name);
|
||||
return;
|
||||
case TypeKind.Dynamic:
|
||||
@@ -211,9 +246,8 @@ namespace Semmle.Extraction.CSharp
|
||||
trapFile.Write("::");
|
||||
}
|
||||
|
||||
static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action<Context, TextWriter, ITypeSymbol> subTermAction)
|
||||
static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, bool prefixAssembly, ISymbol symbolBeingDefined, Action<Context, TextWriter, ITypeSymbol, ISymbol> subTermAction)
|
||||
{
|
||||
bool prefixAssembly = true;
|
||||
if (named.ContainingAssembly is null) prefixAssembly = false;
|
||||
|
||||
if (named.IsTupleType)
|
||||
@@ -224,7 +258,7 @@ namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
trapFile.Write(f.Name);
|
||||
trapFile.Write(":");
|
||||
subTermAction(cx, tb0, f.Type);
|
||||
subTermAction(cx, tb0, f.Type, symbolBeingDefined);
|
||||
}
|
||||
);
|
||||
trapFile.Write(")");
|
||||
@@ -233,7 +267,7 @@ namespace Semmle.Extraction.CSharp
|
||||
|
||||
if (named.ContainingType != null)
|
||||
{
|
||||
subTermAction(cx, trapFile, named.ContainingType);
|
||||
subTermAction(cx, trapFile, named.ContainingType, symbolBeingDefined);
|
||||
trapFile.Write('.');
|
||||
}
|
||||
else if (named.ContainingNamespace != null)
|
||||
@@ -255,14 +289,14 @@ namespace Semmle.Extraction.CSharp
|
||||
}
|
||||
else
|
||||
{
|
||||
subTermAction(cx, trapFile, named.ConstructedFrom);
|
||||
subTermAction(cx, trapFile, named.ConstructedFrom, symbolBeingDefined);
|
||||
trapFile.Write('<');
|
||||
// Encode the nullability of the type arguments in the label.
|
||||
// Type arguments with different nullability can result in
|
||||
// a constructed type with different nullability of its members and methods,
|
||||
// so we need to create a distinct database entity for it.
|
||||
trapFile.BuildList(",", named.GetAnnotatedTypeArguments(),
|
||||
(ta, tb0) => subTermAction(cx, tb0, ta.Symbol)
|
||||
(ta, tb0) => subTermAction(cx, tb0, ta.Symbol, symbolBeingDefined)
|
||||
);
|
||||
trapFile.Write('>');
|
||||
}
|
||||
@@ -274,16 +308,16 @@ namespace Semmle.Extraction.CSharp
|
||||
trapFile.Write('.');
|
||||
}
|
||||
|
||||
static void BuildAnonymousName(this ITypeSymbol type, Context cx, TextWriter trapFile, Action<Context, TextWriter, ITypeSymbol> subTermAction, bool includeParamName)
|
||||
static void BuildAnonymousName(this ITypeSymbol type, Context cx, TextWriter trapFile, Action<Context, TextWriter, ITypeSymbol, ISymbol> subTermAction, bool includeParamName)
|
||||
{
|
||||
var buildParam = includeParamName
|
||||
? (prop, tb0) =>
|
||||
{
|
||||
tb0.Write(prop.Name);
|
||||
tb0.Write(' ');
|
||||
subTermAction(cx, tb0, prop.Type);
|
||||
subTermAction(cx, tb0, prop.Type, null);
|
||||
}
|
||||
: (Action<IPropertySymbol, TextWriter>)((prop, tb0) => subTermAction(cx, tb0, prop.Type));
|
||||
: (Action<IPropertySymbol, TextWriter>)((prop, tb0) => subTermAction(cx, tb0, prop.Type, null));
|
||||
int memberCount = type.GetMembers().OfType<IPropertySymbol>().Count();
|
||||
int hackTypeNumber = memberCount == 1 ? 1 : 0;
|
||||
trapFile.Write("<>__AnonType");
|
||||
@@ -355,7 +389,7 @@ namespace Semmle.Extraction.CSharp
|
||||
|
||||
if (namedType.IsAnonymousType)
|
||||
{
|
||||
namedType.BuildAnonymousName(cx, trapFile, (cx0, tb0, sub) => sub.BuildDisplayName(cx0, tb0), false);
|
||||
namedType.BuildAnonymousName(cx, trapFile, (cx0, tb0, sub, _) => sub.BuildDisplayName(cx0, tb0), false);
|
||||
}
|
||||
|
||||
trapFile.Write(namedType.Name);
|
||||
|
||||
@@ -51,7 +51,20 @@ namespace Semmle.Extraction
|
||||
/// <returns>The new/existing entity.</returns>
|
||||
public Entity CreateEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity
|
||||
{
|
||||
return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init);
|
||||
return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init, objectEntityCache);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new entity using the factory.
|
||||
/// </summary>
|
||||
/// <param name="factory">The entity factory.</param>
|
||||
/// <param name="init">The initializer for the entity.</param>
|
||||
/// <returns>The new/existing entity.</returns>
|
||||
public Entity CreateEntityFromSymbol<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init)
|
||||
where Entity : ICachedEntity
|
||||
where Type: ISymbol
|
||||
{
|
||||
return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init, symbolEntityCache);
|
||||
}
|
||||
|
||||
// A recursion guard against writing to the trap file whilst writing an id to the trap file.
|
||||
@@ -136,8 +149,13 @@ namespace Semmle.Extraction
|
||||
public Label GetNewLabel() => new Label(GetNewId());
|
||||
|
||||
private Entity CreateNonNullEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity
|
||||
=> CreateNonNullEntity(factory, init, objectEntityCache);
|
||||
|
||||
private Entity CreateNonNullEntity<Type, Src, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init, IDictionary<Src, ICachedEntity> dictionary)
|
||||
where Entity : ICachedEntity
|
||||
where Type : Src
|
||||
{
|
||||
if (objectEntityCache.TryGetValue(init, out var cached))
|
||||
if (dictionary.TryGetValue(init, out var cached))
|
||||
return (Entity)cached;
|
||||
|
||||
using (StackGuard)
|
||||
@@ -146,7 +164,7 @@ namespace Semmle.Extraction
|
||||
var entity = factory.Create(this, init);
|
||||
entity.Label = label;
|
||||
|
||||
objectEntityCache[init] = entity;
|
||||
dictionary[init] = entity;
|
||||
|
||||
DefineLabel(entity, TrapWriter.Writer, Extractor);
|
||||
if (entity.NeedsPopulation)
|
||||
@@ -200,7 +218,9 @@ namespace Semmle.Extraction
|
||||
#if DEBUG_LABELS
|
||||
readonly Dictionary<string, ICachedEntity> idLabelCache = new Dictionary<string, ICachedEntity>();
|
||||
#endif
|
||||
readonly Dictionary<object, ICachedEntity> objectEntityCache = new Dictionary<object, ICachedEntity>();
|
||||
|
||||
readonly IDictionary<object, ICachedEntity> objectEntityCache = new Dictionary<object, ICachedEntity>();
|
||||
readonly IDictionary<ISymbol, ICachedEntity> symbolEntityCache = new Dictionary<ISymbol, ICachedEntity>(10000, SymbolEqualityComparer.IncludeNullability);
|
||||
readonly Dictionary<ICachedEntity, Label> entityLabelCache = new Dictionary<ICachedEntity, Label>();
|
||||
readonly HashSet<Label> extractedGenerics = new HashSet<Label>();
|
||||
|
||||
|
||||
@@ -130,6 +130,19 @@ namespace Semmle.Extraction
|
||||
public static Entity CreateEntity<Type, Entity>(this ICachedEntityFactory<Type, Entity> factory, Context cx, Type init)
|
||||
where Entity : ICachedEntity => cx.CreateEntity(factory, init);
|
||||
|
||||
/// <summary>
|
||||
/// Creates and populates a new entity, or returns the existing one from the cache.
|
||||
/// </summary>
|
||||
/// <typeparam name="Type">The symbol type used to construct the entity.</typeparam>
|
||||
/// <typeparam name="Entity">The type of the entity to create.</typeparam>
|
||||
/// <param name="cx">The extractor context.</param>
|
||||
/// <param name="factory">The factory used to construct the entity.</param>
|
||||
/// <param name="init">The initializer for the entity, which may not be null.</param>
|
||||
/// <returns>The entity.</returns>
|
||||
public static Entity CreateEntityFromSymbol<Type, Entity>(this ICachedEntityFactory<Type, Entity> factory, Context cx, Type init)
|
||||
where Entity : ICachedEntity
|
||||
where Type : ISymbol => cx.CreateEntityFromSymbol(factory, init);
|
||||
|
||||
/// <summary>
|
||||
/// Creates and populates a new entity, but uses a different cache.
|
||||
/// </summary>
|
||||
|
||||
@@ -12,7 +12,9 @@ private newtype TIRType =
|
||||
TIRBooleanType(int byteSize) { Language::hasBooleanType(byteSize) } or
|
||||
TIRSignedIntegerType(int byteSize) { Language::hasSignedIntegerType(byteSize) } or
|
||||
TIRUnsignedIntegerType(int byteSize) { Language::hasUnsignedIntegerType(byteSize) } or
|
||||
TIRFloatingPointType(int byteSize) { Language::hasFloatingPointType(byteSize) } or
|
||||
TIRFloatingPointType(int byteSize, int base, Language::TypeDomain domain) {
|
||||
Language::hasFloatingPointType(byteSize, base, domain)
|
||||
} or
|
||||
TIRAddressType(int byteSize) { Language::hasAddressType(byteSize) } or
|
||||
TIRFunctionAddressType(int byteSize) { Language::hasFunctionAddressType(byteSize) } or
|
||||
TIROpaqueType(Language::OpaqueTypeTag tag, int byteSize) {
|
||||
@@ -104,7 +106,7 @@ private class IRSizedType extends IRType {
|
||||
this = TIRBooleanType(byteSize) or
|
||||
this = TIRSignedIntegerType(byteSize) or
|
||||
this = TIRUnsignedIntegerType(byteSize) or
|
||||
this = TIRFloatingPointType(byteSize) or
|
||||
this = TIRFloatingPointType(byteSize, _, _) or
|
||||
this = TIRAddressType(byteSize) or
|
||||
this = TIRFunctionAddressType(byteSize) or
|
||||
this = TIROpaqueType(_, byteSize)
|
||||
@@ -133,7 +135,7 @@ class IRNumericType extends IRSizedType {
|
||||
IRNumericType() {
|
||||
this = TIRSignedIntegerType(byteSize) or
|
||||
this = TIRUnsignedIntegerType(byteSize) or
|
||||
this = TIRFloatingPointType(byteSize)
|
||||
this = TIRFloatingPointType(byteSize, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,14 +173,43 @@ class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType {
|
||||
* A floating-point type.
|
||||
*/
|
||||
class IRFloatingPointType extends IRNumericType, TIRFloatingPointType {
|
||||
final override string toString() { result = "float" + byteSize.toString() }
|
||||
final private int base;
|
||||
final private Language::TypeDomain domain;
|
||||
|
||||
IRFloatingPointType() { this = TIRFloatingPointType(_, base, domain) }
|
||||
|
||||
final override string toString() {
|
||||
result = getDomainPrefix() + getBaseString() + byteSize.toString()
|
||||
}
|
||||
|
||||
final override Language::LanguageType getCanonicalLanguageType() {
|
||||
result = Language::getCanonicalFloatingPointType(byteSize)
|
||||
result = Language::getCanonicalFloatingPointType(byteSize, base, domain)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final override int getByteSize() { result = byteSize }
|
||||
|
||||
/** Gets the numeric base of the type. Can be either 2 (binary) or 10 (decimal). */
|
||||
final int getBase() { result = base }
|
||||
|
||||
/**
|
||||
* Gets the type domain of the type. Can be `RealDomain`, `ComplexDomain`, or `ImaginaryDomain`.
|
||||
*/
|
||||
final Language::TypeDomain getDomain() { result = domain }
|
||||
|
||||
private string getBaseString() {
|
||||
base = 2 and result = "float"
|
||||
or
|
||||
base = 10 and result = "decimal"
|
||||
}
|
||||
|
||||
private string getDomainPrefix() {
|
||||
domain instanceof Language::RealDomain and result = ""
|
||||
or
|
||||
domain instanceof Language::ComplexDomain and result = "c"
|
||||
or
|
||||
domain instanceof Language::ImaginaryDomain and result = "i"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,11 +6,12 @@ private import DebugSSA
|
||||
|
||||
bindingset[offset]
|
||||
private string getKeySuffixForOffset(int offset) {
|
||||
offset >= 0 and
|
||||
if offset % 2 = 0 then result = "" else result = "_Chi"
|
||||
}
|
||||
|
||||
bindingset[offset]
|
||||
private int getIndexForOffset(int offset) { result = offset / 2 }
|
||||
private int getIndexForOffset(int offset) { offset >= 0 and result = offset / 2 }
|
||||
|
||||
/**
|
||||
* Property provide that dumps the memory access of each result. Useful for debugging SSA
|
||||
|
||||
@@ -61,9 +61,13 @@ predicate hasUnsignedIntegerType(int byteSize) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an `IRFloatingPointType` with the specified `byteSize` should exist.
|
||||
* Holds if an `IRFloatingPointType` with the specified size, base, and type domain should exist.
|
||||
*/
|
||||
predicate hasFloatingPointType(int byteSize) { byteSize = any(FloatingPointType type).getSize() }
|
||||
predicate hasFloatingPointType(int byteSize, int base, Language::TypeDomain domain) {
|
||||
byteSize = any(FloatingPointType type).getSize() and
|
||||
base = 2 and
|
||||
domain instanceof Language::RealDomain
|
||||
}
|
||||
|
||||
private predicate isPointerIshType(Type type) {
|
||||
type instanceof PointerType or
|
||||
@@ -314,9 +318,11 @@ CSharpPRValueType getCanonicalUnsignedIntegerType(int byteSize) {
|
||||
|
||||
/**
|
||||
* Gets the `CSharpType` that is the canonical type for an `IRFloatingPointType` with the specified
|
||||
* `byteSize`.
|
||||
* size, base, and type domain.
|
||||
*/
|
||||
CSharpPRValueType getCanonicalFloatingPointType(int byteSize) {
|
||||
CSharpPRValueType getCanonicalFloatingPointType(int byteSize, int base, Language::TypeDomain domain) {
|
||||
base = 2 and
|
||||
domain instanceof Language::RealDomain and
|
||||
result = TPRValueType(any(FloatingPointType type | type.getSize() = byteSize))
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,44 @@ class IntegralType = CSharp::IntegralType;
|
||||
|
||||
class FloatingPointType = CSharp::FloatingPointType;
|
||||
|
||||
private newtype TTypeDomain = TRealDomain()
|
||||
|
||||
/**
|
||||
* The type domain of a floating-point type. One of `RealDomain`, `ComplexDomain`, or
|
||||
* `ImaginaryDomain`.
|
||||
*/
|
||||
class TypeDomain extends TTypeDomain {
|
||||
/** Gets a textual representation of this type domain. */
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The type domain of a floating-point type that represents a real number.
|
||||
*/
|
||||
class RealDomain extends TypeDomain, TRealDomain {
|
||||
final override string toString() { result = "real" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The type domain of a floating-point type that represents a complex number. Not currently used in
|
||||
* C#.
|
||||
*/
|
||||
class ComplexDomain extends TypeDomain {
|
||||
ComplexDomain() { none() }
|
||||
|
||||
final override string toString() { result = "complex" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The type domain of a floating-point type that represents an imaginary number. Not currently used
|
||||
* in C#.
|
||||
*/
|
||||
class ImaginaryDomain extends TypeDomain {
|
||||
ImaginaryDomain() { none() }
|
||||
|
||||
final override string toString() { result = "imaginary" }
|
||||
}
|
||||
|
||||
private newtype TClassDerivation =
|
||||
// Note that this is the `Class` type exported from this module, not CSharp::Class.
|
||||
MkClassDerivation(Class base, Class derived) { derived.getABaseType() = base }
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
| Program.cs:18:21:18:22 | c1 | Assembly1.dll:0:0:0:0 | Class |
|
||||
| Program.cs:18:21:18:22 | c1 | Assembly2.dll:0:0:0:0 | Class |
|
||||
| Program.cs:18:21:18:22 | c1 | Program.cs:10:7:10:11 | Class |
|
||||
| Program.cs:19:21:19:22 | c2 | Assembly1.dll:0:0:0:0 | Class |
|
||||
| Program.cs:19:21:19:22 | c2 | Assembly2.dll:0:0:0:0 | Class |
|
||||
| Program.cs:19:21:19:22 | c2 | Program.cs:10:7:10:11 | Class |
|
||||
| Program.cs:20:15:20:16 | c3 | Assembly1.dll:0:0:0:0 | Class |
|
||||
| Program.cs:20:15:20:16 | c3 | Assembly2.dll:0:0:0:0 | Class |
|
||||
| Program.cs:20:15:20:16 | c3 | Program.cs:10:7:10:11 | Class |
|
||||
|
||||
@@ -243,7 +243,7 @@ expressionTypes
|
||||
| NullableRefTypes.cs:19:33:19:36 | this access | MyClass! |
|
||||
| NullableRefTypes.cs:26:44:26:53 | throw ... | MyClass![]! |
|
||||
| NullableRefTypes.cs:26:50:26:53 | null | null |
|
||||
| NullableRefTypes.cs:27:44:27:53 | throw ... | MyClass![]! |
|
||||
| NullableRefTypes.cs:27:44:27:53 | throw ... | MyClass?[]! |
|
||||
| NullableRefTypes.cs:27:50:27:53 | null | null |
|
||||
| NullableRefTypes.cs:30:21:30:24 | null | null |
|
||||
| NullableRefTypes.cs:31:20:31:23 | this access | MyClass! |
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
// semmle-extractor-options: /r:System.Linq.dll
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class CollectionFlow
|
||||
{
|
||||
public class A { }
|
||||
|
||||
public void ArrayInitializerFlow()
|
||||
{
|
||||
var a = new A();
|
||||
var @as = new[] { a };
|
||||
Sink(@as[0]); // flow
|
||||
SinkElem(@as); // flow
|
||||
Sink(First(@as)); // flow
|
||||
}
|
||||
|
||||
public void ArrayInitializerNoFlow(A other)
|
||||
{
|
||||
var a = new A();
|
||||
var @as = new[] { other };
|
||||
Sink(@as[0]); // no flow
|
||||
SinkElem(@as); // no flow
|
||||
Sink(First(@as)); // no flow
|
||||
}
|
||||
|
||||
public void ArrayAssignmentFlow()
|
||||
{
|
||||
var a = new A();
|
||||
var @as = new A[1];
|
||||
@as[0] = a;
|
||||
Sink(@as[0]); // flow
|
||||
SinkElem(@as); // flow
|
||||
Sink(First(@as)); // flow
|
||||
}
|
||||
|
||||
public void ArrayAssignmentNoFlow(A other)
|
||||
{
|
||||
var a = new A();
|
||||
var @as = new A[1];
|
||||
@as[0] = other;
|
||||
Sink(@as[0]); // no flow
|
||||
SinkElem(@as); // no flow
|
||||
Sink(First(@as)); // no flow
|
||||
}
|
||||
|
||||
public void ListAssignmentFlow()
|
||||
{
|
||||
var a = new A();
|
||||
var list = new List<A>();
|
||||
list[0] = a;
|
||||
Sink(list[0]); // flow
|
||||
SinkListElem(list); // flow
|
||||
Sink(ListFirst(list)); // flow
|
||||
}
|
||||
|
||||
public void ListAssignmentNoFlow(A other)
|
||||
{
|
||||
var list = new List<A>();
|
||||
list[0] = other;
|
||||
Sink(list[0]); // no flow
|
||||
SinkListElem(list); // no flow
|
||||
Sink(ListFirst(list)); // no flow
|
||||
}
|
||||
|
||||
public void ListInitializerFlow()
|
||||
{
|
||||
var a = new A();
|
||||
var list = new List<A>() { a };
|
||||
Sink(list[0]); // flow
|
||||
SinkListElem(list); // flow
|
||||
Sink(ListFirst(list)); // flow
|
||||
}
|
||||
|
||||
public void ListInitializerNoFlow(A other)
|
||||
{
|
||||
var list = new List<A>() { other };
|
||||
Sink(list[0]); // no flow
|
||||
SinkListElem(list); // no flow
|
||||
Sink(ListFirst(list)); // no flow
|
||||
}
|
||||
|
||||
public void ListAddFlow()
|
||||
{
|
||||
var a = new A();
|
||||
var list = new List<A>();
|
||||
list.Add(a);
|
||||
Sink(list[0]); // flow
|
||||
SinkListElem(list); // flow
|
||||
Sink(ListFirst(list)); // flow
|
||||
}
|
||||
|
||||
public void ListAddNoFlow(A other)
|
||||
{
|
||||
var list = new List<A>();
|
||||
list.Add(other);
|
||||
Sink(list[0]); // no flow
|
||||
SinkListElem(list); // no flow
|
||||
Sink(ListFirst(list)); // no flow
|
||||
}
|
||||
|
||||
public void DictionaryAssignmentFlow()
|
||||
{
|
||||
var a = new A();
|
||||
var dict = new Dictionary<int, A>();
|
||||
dict[0] = a;
|
||||
Sink(dict[0]); // flow
|
||||
SinkDictValue(dict); // flow
|
||||
Sink(DictIndexZero(dict)); // flow
|
||||
Sink(DictFirstValue(dict)); // flow [MISSING]
|
||||
Sink(DictValuesFirst(dict)); // flow
|
||||
}
|
||||
|
||||
public void DictionaryAssignmentNoFlow(A other)
|
||||
{
|
||||
var dict = new Dictionary<int, A>();
|
||||
dict[0] = other;
|
||||
Sink(dict[0]); // no flow
|
||||
SinkDictValue(dict); // no flow
|
||||
Sink(DictIndexZero(dict)); // no flow
|
||||
Sink(DictFirstValue(dict)); // no flow
|
||||
Sink(DictValuesFirst(dict)); // no flow
|
||||
}
|
||||
|
||||
public void DictionaryValueInitializerFlow()
|
||||
{
|
||||
var a = new A();
|
||||
var dict = new Dictionary<int, A>() { { 0, a } };
|
||||
Sink(dict[0]); // flow
|
||||
SinkDictValue(dict); // flow
|
||||
Sink(DictIndexZero(dict)); // flow
|
||||
Sink(DictFirstValue(dict)); // flow [MISSING]
|
||||
Sink(DictValuesFirst(dict)); // flow
|
||||
}
|
||||
|
||||
public void DictionaryValueInitializerNoFlow(A other)
|
||||
{
|
||||
var dict = new Dictionary<int, A>() { { 0, other } };
|
||||
Sink(dict[0]); // no flow
|
||||
SinkDictValue(dict); // no flow
|
||||
Sink(DictIndexZero(dict)); // no flow
|
||||
Sink(DictFirstValue(dict)); // no flow
|
||||
Sink(DictValuesFirst(dict)); // no flow
|
||||
}
|
||||
|
||||
public void DictionaryKeyInitializerFlow()
|
||||
{
|
||||
var a = new A();
|
||||
var dict = new Dictionary<A, int>() { { a, 0 } };
|
||||
Sink(dict.Keys.First()); // flow [MISSING]
|
||||
SinkDictKey(dict); // flow [MISSING]
|
||||
Sink(DictKeysFirst(dict)); // flow [MISSING]
|
||||
Sink(DictFirstKey(dict)); // flow [MISSING]
|
||||
}
|
||||
|
||||
public void DictionaryKeyInitializerNoFlow(A other)
|
||||
{
|
||||
var dict = new Dictionary<A, int>() { { other, 0 } };
|
||||
Sink(dict.Keys.First()); // no flow
|
||||
SinkDictKey(dict); // no flow
|
||||
Sink(DictKeysFirst(dict)); // no flow
|
||||
Sink(DictFirstKey(dict)); // no flow
|
||||
}
|
||||
|
||||
public void ForeachFlow()
|
||||
{
|
||||
var a = new A();
|
||||
var @as = new[] { a };
|
||||
foreach (var x in @as)
|
||||
Sink(x); // flow
|
||||
}
|
||||
|
||||
public void ForeachNoFlow(A other)
|
||||
{
|
||||
var @as = new[] { other };
|
||||
foreach (var x in @as)
|
||||
Sink(x); // no flow
|
||||
}
|
||||
|
||||
public void ArrayGetEnumeratorFlow()
|
||||
{
|
||||
var a = new A();
|
||||
var @as = new[] { a };
|
||||
var enumerator = @as.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
Sink(enumerator.Current); // flow
|
||||
}
|
||||
|
||||
public void ArrayGetEnumeratorNoFlow(A other)
|
||||
{
|
||||
var @as = new[] { other };
|
||||
var enumerator = @as.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
Sink(enumerator.Current); // no flow
|
||||
}
|
||||
|
||||
public void ListGetEnumeratorFlow()
|
||||
{
|
||||
var a = new A();
|
||||
var list = new List<A>();
|
||||
list.Add(a);
|
||||
var enumerator = list.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
Sink(enumerator.Current); // flow [MISSING]
|
||||
}
|
||||
|
||||
public static void Sink<T>(T t) { }
|
||||
|
||||
public static void SinkElem<T>(T[] ts) => Sink(ts[0]);
|
||||
|
||||
public static void SinkListElem<T>(IList<T> list) => Sink(list[0]);
|
||||
|
||||
public static void SinkDictValue<T>(IDictionary<int, T> dict) => Sink(dict[0]);
|
||||
|
||||
public static void SinkDictKey<T>(IDictionary<T, int> dict) => Sink(dict.Keys.First());
|
||||
|
||||
public static T First<T>(T[] ts) => ts[0];
|
||||
|
||||
public static T ListFirst<T>(IList<T> list) => list[0];
|
||||
|
||||
public static T DictIndexZero<T>(IDictionary<int, T> dict) => dict[0];
|
||||
|
||||
public static T DictFirstValue<T>(IDictionary<int, T> dict) => dict.First().Value;
|
||||
|
||||
public static T DictValuesFirst<T>(IDictionary<int, T> dict) => dict.Values.First();
|
||||
|
||||
public static T DictKeysFirst<T>(IDictionary<T, int> dict) => dict.Keys.First();
|
||||
|
||||
public static T DictFirstKey<T>(IDictionary<T, int> dict) => dict.First().Key;
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
edges
|
||||
| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:14:14:14:19 | access to array element |
|
||||
| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:15:18:15:20 | access to local variable as : A[] |
|
||||
| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:16:20:16:22 | access to local variable as : A[] |
|
||||
| CollectionFlow.cs:15:18:15:20 | access to local variable as : A[] | CollectionFlow.cs:210:40:210:41 | ts : A[] |
|
||||
| CollectionFlow.cs:16:20:16:22 | access to local variable as : A[] | CollectionFlow.cs:16:14:16:23 | call to method First |
|
||||
| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:33:14:33:19 | access to array element |
|
||||
| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:34:18:34:20 | access to local variable as : A[] |
|
||||
| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:35:20:35:22 | access to local variable as : A[] |
|
||||
| CollectionFlow.cs:34:18:34:20 | access to local variable as : A[] | CollectionFlow.cs:210:40:210:41 | ts : A[] |
|
||||
| CollectionFlow.cs:35:20:35:22 | access to local variable as : A[] | CollectionFlow.cs:35:14:35:23 | call to method First |
|
||||
| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:20 | access to indexer |
|
||||
| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:54:22:54:25 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:24:55:27 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:53:14:53:20 | access to indexer |
|
||||
| CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:54:22:54:25 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:55:24:55:27 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:54:22:54:25 | access to local variable list : List<A> | CollectionFlow.cs:212:49:212:52 | list : List<A> |
|
||||
| CollectionFlow.cs:55:24:55:27 | access to local variable list : List<A> | CollectionFlow.cs:55:14:55:28 | call to method ListFirst |
|
||||
| CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:62:14:62:20 | access to indexer |
|
||||
| CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:63:22:63:25 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:64:24:64:27 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:63:22:63:25 | access to local variable list : List<A> | CollectionFlow.cs:212:49:212:52 | list : List<A> |
|
||||
| CollectionFlow.cs:64:24:64:27 | access to local variable list : List<A> | CollectionFlow.cs:64:14:64:28 | call to method ListFirst |
|
||||
| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:71:14:71:20 | access to indexer |
|
||||
| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:72:22:72:25 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:73:24:73:27 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:71:14:71:20 | access to indexer |
|
||||
| CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:72:22:72:25 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:73:24:73:27 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:72:22:72:25 | access to local variable list : List<A> | CollectionFlow.cs:212:49:212:52 | list : List<A> |
|
||||
| CollectionFlow.cs:73:24:73:27 | access to local variable list : List<A> | CollectionFlow.cs:73:14:73:28 | call to method ListFirst |
|
||||
| CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:79:14:79:20 | access to indexer |
|
||||
| CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:80:22:80:25 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:81:24:81:27 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:80:22:80:25 | access to local variable list : List<A> | CollectionFlow.cs:212:49:212:52 | list : List<A> |
|
||||
| CollectionFlow.cs:81:24:81:27 | access to local variable list : List<A> | CollectionFlow.cs:81:14:81:28 | call to method ListFirst |
|
||||
| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:89:14:89:20 | access to indexer |
|
||||
| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:90:22:90:25 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:91:24:91:27 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:89:14:89:20 | access to indexer |
|
||||
| CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:90:22:90:25 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:91:24:91:27 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:90:22:90:25 | access to local variable list : List<A> | CollectionFlow.cs:212:49:212:52 | list : List<A> |
|
||||
| CollectionFlow.cs:91:24:91:27 | access to local variable list : List<A> | CollectionFlow.cs:91:14:91:28 | call to method ListFirst |
|
||||
| CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:98:14:98:20 | access to indexer |
|
||||
| CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:99:22:99:25 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:100:24:100:27 | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:99:22:99:25 | access to local variable list : List<A> | CollectionFlow.cs:212:49:212:52 | list : List<A> |
|
||||
| CollectionFlow.cs:100:24:100:27 | access to local variable list : List<A> | CollectionFlow.cs:100:14:100:28 | call to method ListFirst |
|
||||
| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:108:14:108:20 | access to indexer |
|
||||
| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:108:14:108:20 | access to indexer |
|
||||
| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:214:61:214:64 | dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero |
|
||||
| CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst |
|
||||
| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:119:14:119:20 | access to indexer |
|
||||
| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:120:23:120:26 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:121:28:121:31 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:123:30:123:33 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:120:23:120:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:214:61:214:64 | dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:121:28:121:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero |
|
||||
| CollectionFlow.cs:123:30:123:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst |
|
||||
| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:20 | access to indexer |
|
||||
| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:130:14:130:20 | access to indexer |
|
||||
| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:214:61:214:64 | dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero |
|
||||
| CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst |
|
||||
| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:140:14:140:20 | access to indexer |
|
||||
| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:141:23:141:26 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:142:28:142:31 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:144:30:144:33 | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:141:23:141:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:214:61:214:64 | dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:142:28:142:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero |
|
||||
| CollectionFlow.cs:144:30:144:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst |
|
||||
| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | CollectionFlow.cs:171:18:171:18 | access to local variable x |
|
||||
| CollectionFlow.cs:183:17:183:23 | object creation of type A : A | CollectionFlow.cs:187:18:187:35 | access to property Current |
|
||||
| CollectionFlow.cs:210:40:210:41 | ts : A[] | CollectionFlow.cs:210:52:210:56 | access to array element |
|
||||
| CollectionFlow.cs:212:49:212:52 | list : List<A> | CollectionFlow.cs:212:63:212:69 | access to indexer |
|
||||
| CollectionFlow.cs:214:61:214:64 | dict : Dictionary<Int32,A> | CollectionFlow.cs:214:75:214:81 | access to indexer |
|
||||
nodes
|
||||
| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | semmle.label | object creation of type A : A |
|
||||
| CollectionFlow.cs:14:14:14:19 | access to array element | semmle.label | access to array element |
|
||||
| CollectionFlow.cs:15:18:15:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] |
|
||||
| CollectionFlow.cs:16:14:16:23 | call to method First | semmle.label | call to method First |
|
||||
| CollectionFlow.cs:16:20:16:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] |
|
||||
| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | semmle.label | object creation of type A : A |
|
||||
| CollectionFlow.cs:33:14:33:19 | access to array element | semmle.label | access to array element |
|
||||
| CollectionFlow.cs:34:18:34:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] |
|
||||
| CollectionFlow.cs:35:14:35:23 | call to method First | semmle.label | call to method First |
|
||||
| CollectionFlow.cs:35:20:35:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] |
|
||||
| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | semmle.label | object creation of type A : A |
|
||||
| CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> |
|
||||
| CollectionFlow.cs:53:14:53:20 | access to indexer | semmle.label | access to indexer |
|
||||
| CollectionFlow.cs:54:22:54:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:55:14:55:28 | call to method ListFirst | semmle.label | call to method ListFirst |
|
||||
| CollectionFlow.cs:55:24:55:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> |
|
||||
| CollectionFlow.cs:62:14:62:20 | access to indexer | semmle.label | access to indexer |
|
||||
| CollectionFlow.cs:63:22:63:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:64:14:64:28 | call to method ListFirst | semmle.label | call to method ListFirst |
|
||||
| CollectionFlow.cs:64:24:64:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | semmle.label | object creation of type A : A |
|
||||
| CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> |
|
||||
| CollectionFlow.cs:71:14:71:20 | access to indexer | semmle.label | access to indexer |
|
||||
| CollectionFlow.cs:72:22:72:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:73:14:73:28 | call to method ListFirst | semmle.label | call to method ListFirst |
|
||||
| CollectionFlow.cs:73:24:73:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> |
|
||||
| CollectionFlow.cs:79:14:79:20 | access to indexer | semmle.label | access to indexer |
|
||||
| CollectionFlow.cs:80:22:80:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:81:14:81:28 | call to method ListFirst | semmle.label | call to method ListFirst |
|
||||
| CollectionFlow.cs:81:24:81:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | semmle.label | object creation of type A : A |
|
||||
| CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> |
|
||||
| CollectionFlow.cs:89:14:89:20 | access to indexer | semmle.label | access to indexer |
|
||||
| CollectionFlow.cs:90:22:90:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:91:14:91:28 | call to method ListFirst | semmle.label | call to method ListFirst |
|
||||
| CollectionFlow.cs:91:24:91:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> |
|
||||
| CollectionFlow.cs:98:14:98:20 | access to indexer | semmle.label | access to indexer |
|
||||
| CollectionFlow.cs:99:22:99:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:100:14:100:28 | call to method ListFirst | semmle.label | call to method ListFirst |
|
||||
| CollectionFlow.cs:100:24:100:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> |
|
||||
| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | semmle.label | object creation of type A : A |
|
||||
| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:108:14:108:20 | access to indexer | semmle.label | access to indexer |
|
||||
| CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero |
|
||||
| CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst |
|
||||
| CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:119:14:119:20 | access to indexer | semmle.label | access to indexer |
|
||||
| CollectionFlow.cs:120:23:120:26 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero |
|
||||
| CollectionFlow.cs:121:28:121:31 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst |
|
||||
| CollectionFlow.cs:123:30:123:33 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | semmle.label | object creation of type A : A |
|
||||
| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:130:14:130:20 | access to indexer | semmle.label | access to indexer |
|
||||
| CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero |
|
||||
| CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst |
|
||||
| CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:140:14:140:20 | access to indexer | semmle.label | access to indexer |
|
||||
| CollectionFlow.cs:141:23:141:26 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero |
|
||||
| CollectionFlow.cs:142:28:142:31 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst |
|
||||
| CollectionFlow.cs:144:30:144:33 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | semmle.label | object creation of type A : A |
|
||||
| CollectionFlow.cs:171:18:171:18 | access to local variable x | semmle.label | access to local variable x |
|
||||
| CollectionFlow.cs:183:17:183:23 | object creation of type A : A | semmle.label | object creation of type A : A |
|
||||
| CollectionFlow.cs:187:18:187:35 | access to property Current | semmle.label | access to property Current |
|
||||
| CollectionFlow.cs:210:40:210:41 | ts : A[] | semmle.label | ts : A[] |
|
||||
| CollectionFlow.cs:210:52:210:56 | access to array element | semmle.label | access to array element |
|
||||
| CollectionFlow.cs:212:49:212:52 | list : List<A> | semmle.label | list : List<A> |
|
||||
| CollectionFlow.cs:212:63:212:69 | access to indexer | semmle.label | access to indexer |
|
||||
| CollectionFlow.cs:214:61:214:64 | dict : Dictionary<Int32,A> | semmle.label | dict : Dictionary<Int32,A> |
|
||||
| CollectionFlow.cs:214:75:214:81 | access to indexer | semmle.label | access to indexer |
|
||||
#select
|
||||
| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:14:14:14:19 | access to array element | $@ | CollectionFlow.cs:14:14:14:19 | access to array element | access to array element |
|
||||
| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:16:14:16:23 | call to method First | $@ | CollectionFlow.cs:16:14:16:23 | call to method First | call to method First |
|
||||
| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:210:52:210:56 | access to array element | $@ | CollectionFlow.cs:210:52:210:56 | access to array element | access to array element |
|
||||
| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:33:14:33:19 | access to array element | $@ | CollectionFlow.cs:33:14:33:19 | access to array element | access to array element |
|
||||
| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:35:14:35:23 | call to method First | $@ | CollectionFlow.cs:35:14:35:23 | call to method First | call to method First |
|
||||
| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:210:52:210:56 | access to array element | $@ | CollectionFlow.cs:210:52:210:56 | access to array element | access to array element |
|
||||
| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:20 | access to indexer | $@ | CollectionFlow.cs:53:14:53:20 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | $@ | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | call to method ListFirst |
|
||||
| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:53:14:53:20 | access to indexer | $@ | CollectionFlow.cs:53:14:53:20 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | $@ | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | call to method ListFirst |
|
||||
| CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:62:14:62:20 | access to indexer | $@ | CollectionFlow.cs:62:14:62:20 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:64:14:64:28 | call to method ListFirst | $@ | CollectionFlow.cs:64:14:64:28 | call to method ListFirst | call to method ListFirst |
|
||||
| CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:71:14:71:20 | access to indexer | $@ | CollectionFlow.cs:71:14:71:20 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | $@ | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | call to method ListFirst |
|
||||
| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:71:14:71:20 | access to indexer | $@ | CollectionFlow.cs:71:14:71:20 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | $@ | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | call to method ListFirst |
|
||||
| CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:79:14:79:20 | access to indexer | $@ | CollectionFlow.cs:79:14:79:20 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:81:14:81:28 | call to method ListFirst | $@ | CollectionFlow.cs:81:14:81:28 | call to method ListFirst | call to method ListFirst |
|
||||
| CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:89:14:89:20 | access to indexer | $@ | CollectionFlow.cs:89:14:89:20 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | $@ | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | call to method ListFirst |
|
||||
| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:89:14:89:20 | access to indexer | $@ | CollectionFlow.cs:89:14:89:20 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | $@ | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | call to method ListFirst |
|
||||
| CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:98:14:98:20 | access to indexer | $@ | CollectionFlow.cs:98:14:98:20 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:100:14:100:28 | call to method ListFirst | $@ | CollectionFlow.cs:100:14:100:28 | call to method ListFirst | call to method ListFirst |
|
||||
| CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:108:14:108:20 | access to indexer | $@ | CollectionFlow.cs:108:14:108:20 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | call to method DictIndexZero |
|
||||
| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | call to method DictValuesFirst |
|
||||
| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:108:14:108:20 | access to indexer | $@ | CollectionFlow.cs:108:14:108:20 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | call to method DictIndexZero |
|
||||
| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | call to method DictValuesFirst |
|
||||
| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:119:14:119:20 | access to indexer | $@ | CollectionFlow.cs:119:14:119:20 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | call to method DictIndexZero |
|
||||
| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | call to method DictValuesFirst |
|
||||
| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:20 | access to indexer | $@ | CollectionFlow.cs:130:14:130:20 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | call to method DictIndexZero |
|
||||
| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | call to method DictValuesFirst |
|
||||
| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:130:14:130:20 | access to indexer | $@ | CollectionFlow.cs:130:14:130:20 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | call to method DictIndexZero |
|
||||
| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | call to method DictValuesFirst |
|
||||
| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:140:14:140:20 | access to indexer | $@ | CollectionFlow.cs:140:14:140:20 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | call to method DictIndexZero |
|
||||
| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | call to method DictValuesFirst |
|
||||
| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer |
|
||||
| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | CollectionFlow.cs:168:17:168:23 | object creation of type A : A | CollectionFlow.cs:171:18:171:18 | access to local variable x | $@ | CollectionFlow.cs:171:18:171:18 | access to local variable x | access to local variable x |
|
||||
| CollectionFlow.cs:183:17:183:23 | object creation of type A : A | CollectionFlow.cs:183:17:183:23 | object creation of type A : A | CollectionFlow.cs:187:18:187:35 | access to property Current | $@ | CollectionFlow.cs:187:18:187:35 | access to property Current | access to property Current |
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import DataFlow::PathGraph
|
||||
|
||||
class Conf extends TaintTracking::Configuration {
|
||||
Conf() { this = "ArrayFlowConf" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ObjectCreation }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc |
|
||||
mc.getTarget().hasName("Sink") and
|
||||
mc.getAnArgument() = sink.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, Conf conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
select source, source, sink, "$@", sink, sink.toString()
|
||||
@@ -1588,7 +1588,16 @@ public class TypeScriptASTConverter {
|
||||
}
|
||||
|
||||
private Node convertLiteralType(JsonObject node, SourceLocation loc) throws ParseError {
|
||||
return convertChild(node, "literal");
|
||||
Node literal = convertChild(node, "literal");
|
||||
// Convert a negated literal to a negative number
|
||||
if (literal instanceof UnaryExpression) {
|
||||
UnaryExpression unary = (UnaryExpression) literal;
|
||||
if (unary.getOperator().equals("-") && unary.getArgument() instanceof Literal) {
|
||||
Literal arg = (Literal) unary.getArgument();
|
||||
literal = new Literal(loc, arg.getTokenType(), "-" + arg.getValue());
|
||||
}
|
||||
}
|
||||
return literal;
|
||||
}
|
||||
|
||||
private Node convertMappedType(JsonObject node, SourceLocation loc) throws ParseError {
|
||||
|
||||
@@ -14,6 +14,37 @@
|
||||
|
||||
import Misspelling
|
||||
|
||||
from GlobalVarAccess gva, VarDecl lvd
|
||||
where misspelledVariableName(gva, lvd)
|
||||
select gva, "'" + gva + "' may be a typo for variable $@.", lvd, lvd.getName()
|
||||
/**
|
||||
* Gets the number of times a local variable with name `name` occurs in the program.
|
||||
*/
|
||||
bindingset[name]
|
||||
int localAcceses(string name) {
|
||||
result = count(VarAccess acc | acc.getName() = name and not acc instanceof GlobalVarAccess)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of times a global variable with name `name` occurs in the program.
|
||||
*/
|
||||
bindingset[name]
|
||||
int globalAccesses(string name) { result = count(GlobalVarAccess acc | acc.getName() = name) }
|
||||
|
||||
/**
|
||||
* Holds if our heuristic says that the local variable `lvd` seems to be a misspelling of the global variable `gva`.
|
||||
* Otherwise the global variable is likely the misspelling.
|
||||
*/
|
||||
predicate globalIsLikelyCorrect(GlobalVarAccess gva, VarDecl lvd) {
|
||||
// If there are more occurrences of the global (by a margin of at least 2), and the local is missing one letter compared to the global.
|
||||
globalAccesses(gva.getName()) >= localAcceses(lvd.getName()) + 2 and
|
||||
lvd.getName().length() = gva.getName().length() - 1
|
||||
or
|
||||
// Or if there are many more of the global.
|
||||
globalAccesses(gva.getName()) > 2 * localAcceses(lvd.getName()) + 2
|
||||
}
|
||||
|
||||
from GlobalVarAccess gva, VarDecl lvd, string msg
|
||||
where
|
||||
misspelledVariableName(gva, lvd) and
|
||||
if globalIsLikelyCorrect(gva, lvd)
|
||||
then msg = "$@ may be a typo for '" + gva + "'."
|
||||
else msg = "'" + gva + "' may be a typo for variable $@."
|
||||
select gva, msg, lvd, lvd.getName()
|
||||
|
||||
@@ -12,6 +12,7 @@ import semmle.javascript.Base64
|
||||
import semmle.javascript.CFG
|
||||
import semmle.javascript.Classes
|
||||
import semmle.javascript.Closure
|
||||
import semmle.javascript.Collections
|
||||
import semmle.javascript.Comments
|
||||
import semmle.javascript.Concepts
|
||||
import semmle.javascript.Constants
|
||||
|
||||
@@ -125,6 +125,42 @@ class ASTNode extends @ast_node, Locatable {
|
||||
/** Holds if this syntactic entity belongs to an externs file. */
|
||||
predicate inExternsFile() { getTopLevel().isExterns() }
|
||||
|
||||
/**
|
||||
* Holds if this is an ambient node that is not a `TypeExpr` and is not inside a `.d.ts` file
|
||||
*
|
||||
* Since the overwhelming majority of ambient nodes are `TypeExpr` or inside `.d.ts` files,
|
||||
* we avoid caching them.
|
||||
*/
|
||||
cached
|
||||
private predicate isAmbientInternal() {
|
||||
getParent().isAmbientInternal()
|
||||
or
|
||||
not isAmbientTopLevel(getTopLevel()) and
|
||||
(
|
||||
this instanceof ExternalModuleDeclaration
|
||||
or
|
||||
this instanceof GlobalAugmentationDeclaration
|
||||
or
|
||||
this instanceof ExportAsNamespaceDeclaration
|
||||
or
|
||||
this instanceof TypeAliasDeclaration
|
||||
or
|
||||
this instanceof InterfaceDeclaration
|
||||
or
|
||||
hasDeclareKeyword(this)
|
||||
or
|
||||
hasTypeKeyword(this)
|
||||
or
|
||||
// An export such as `export declare function f()` should be seen as ambient.
|
||||
hasDeclareKeyword(this.(ExportNamedDeclaration).getOperand())
|
||||
or
|
||||
exists(Function f |
|
||||
this = f and
|
||||
not f.hasBody()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this is part of an ambient declaration or type annotation in a TypeScript file.
|
||||
*
|
||||
@@ -134,9 +170,22 @@ class ASTNode extends @ast_node, Locatable {
|
||||
* The TypeScript compiler emits no code for ambient declarations, but they
|
||||
* can affect name resolution and type checking at compile-time.
|
||||
*/
|
||||
predicate isAmbient() { getParent().isAmbient() }
|
||||
pragma[inline]
|
||||
predicate isAmbient() {
|
||||
isAmbientInternal()
|
||||
or
|
||||
isAmbientTopLevel(getTopLevel())
|
||||
or
|
||||
this instanceof TypeExpr
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given file is a `.d.ts` file.
|
||||
*/
|
||||
cached
|
||||
private predicate isAmbientTopLevel(TopLevel tl) { tl.getFile().getBaseName().matches("%.d.ts") }
|
||||
|
||||
/**
|
||||
* A toplevel syntactic unit; that is, a stand-alone script, an inline script
|
||||
* embedded in an HTML `<script>` tag, a code snippet assigned to an HTML event
|
||||
@@ -197,11 +246,6 @@ class TopLevel extends @toplevel, StmtContainer {
|
||||
override ControlFlowNode getFirstControlFlowNode() { result = getEntry() }
|
||||
|
||||
override string toString() { result = "<toplevel>" }
|
||||
|
||||
override predicate isAmbient() {
|
||||
getFile().getFileType().isTypeScript() and
|
||||
getFile().getBaseName().matches("%.d.ts")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -96,10 +96,55 @@ module ArrayTaintTracking {
|
||||
* Classes and predicates for modelling data-flow for arrays.
|
||||
*/
|
||||
private module ArrayDataFlow {
|
||||
private import DataFlow::PseudoProperties
|
||||
|
||||
/**
|
||||
* Gets a pseudo-field representing an element inside an array.
|
||||
* A step modelling the creation of an Array using the `Array.from(x)` method.
|
||||
* The step copies the elements of the argument (set, array, or iterator elements) into the resulting array.
|
||||
*/
|
||||
private string arrayElement() { result = "$arrayElement$" }
|
||||
private class ArrayFrom extends DataFlow::AdditionalFlowStep, DataFlow::CallNode {
|
||||
ArrayFrom() { this = DataFlow::globalVarRef("Array").getAMemberCall("from") }
|
||||
|
||||
override predicate loadStoreStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
|
||||
) {
|
||||
pred = this.getArgument(0) and
|
||||
succ = this and
|
||||
fromProp = arrayLikeElement() and
|
||||
toProp = arrayElement()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step modelling an array copy where the spread operator is used.
|
||||
* The result is essentially array concatenation.
|
||||
*
|
||||
* Such a step can occur both with the `push` and `unshift` methods, or when creating a new array.
|
||||
*/
|
||||
private class ArrayCopySpread extends DataFlow::AdditionalFlowStep {
|
||||
DataFlow::Node spreadArgument; // the spread argument containing the elements to be copied.
|
||||
DataFlow::Node base; // the object where the elements should be copied to.
|
||||
|
||||
ArrayCopySpread() {
|
||||
exists(DataFlow::MethodCallNode mcn | mcn = this |
|
||||
mcn.getMethodName() = ["push", "unshift"] and
|
||||
spreadArgument = mcn.getASpreadArgument() and
|
||||
base = mcn.getReceiver().getALocalSource()
|
||||
)
|
||||
or
|
||||
spreadArgument = this.(DataFlow::ArrayCreationNode).getASpreadArgument() and
|
||||
base = this
|
||||
}
|
||||
|
||||
override predicate loadStoreStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
|
||||
) {
|
||||
pred = spreadArgument and
|
||||
succ = base and
|
||||
fromProp = arrayLikeElement() and
|
||||
toProp = arrayElement()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for storing an element on an array using `arr.push(e)` or `arr.unshift(e)`.
|
||||
@@ -110,10 +155,10 @@ private module ArrayDataFlow {
|
||||
this.getMethodName() = "unshift"
|
||||
}
|
||||
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) {
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
|
||||
prop = arrayElement() and
|
||||
(element = this.getAnArgument() or element = this.getASpreadArgument()) and
|
||||
obj = this.getReceiver().getALocalSource()
|
||||
element = this.getAnArgument() and
|
||||
obj.getAMethodCall() = this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,10 +188,10 @@ private module ArrayDataFlow {
|
||||
element = this
|
||||
}
|
||||
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) {
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
|
||||
prop = arrayElement() and
|
||||
element = this.(DataFlow::PropWrite).getRhs() and
|
||||
this = obj.(DataFlow::SourceNode).getAPropertyWrite()
|
||||
this = obj.getAPropertyWrite()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +234,7 @@ private module ArrayDataFlow {
|
||||
element = getCallback(0).getParameter(0)
|
||||
}
|
||||
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) {
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
|
||||
this.getMethodName() = "map" and
|
||||
prop = arrayElement() and
|
||||
element = this.getCallback(0).getAReturn() and
|
||||
@@ -209,7 +254,7 @@ private module ArrayDataFlow {
|
||||
private class ArrayCreationStep extends DataFlow::AdditionalFlowStep, DataFlow::Node {
|
||||
ArrayCreationStep() { this instanceof DataFlow::ArrayCreationNode }
|
||||
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) {
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
|
||||
prop = arrayElement() and
|
||||
element = this.(DataFlow::ArrayCreationNode).getAnElement() and
|
||||
obj = this
|
||||
@@ -223,10 +268,10 @@ private module ArrayDataFlow {
|
||||
private class ArraySpliceStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode {
|
||||
ArraySpliceStep() { this.getMethodName() = "splice" }
|
||||
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) {
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
|
||||
prop = arrayElement() and
|
||||
element = getArgument(2) and
|
||||
obj = this.getReceiver().getALocalSource()
|
||||
this = obj.getAMethodCall()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,4 +305,20 @@ private module ArrayDataFlow {
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for modelling `for of` iteration on arrays.
|
||||
*/
|
||||
private class ForOfStep extends DataFlow::AdditionalFlowStep, DataFlow::ValueNode {
|
||||
ForOfStmt forOf;
|
||||
DataFlow::Node element;
|
||||
|
||||
ForOfStep() { this.asExpr() = forOf.getIterationDomain() }
|
||||
|
||||
override predicate loadStep(DataFlow::Node obj, DataFlow::Node e, string prop) {
|
||||
obj = this and
|
||||
e = DataFlow::lvalueNode(forOf.getLValue()) and
|
||||
prop = arrayElement()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1059,12 +1059,6 @@ class FieldDeclaration extends MemberDeclaration, @field {
|
||||
|
||||
/** Holds if this is a TypeScript field marked as definitely assigned with the `!` operator. */
|
||||
predicate hasDefiniteAssignmentAssertion() { hasDefiniteAssignmentAssertion(this) }
|
||||
|
||||
override predicate isAmbient() {
|
||||
hasDeclareKeyword(this)
|
||||
or
|
||||
getParent().isAmbient()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
278
javascript/ql/src/semmle/javascript/Collections.qll
Normal file
278
javascript/ql/src/semmle/javascript/Collections.qll
Normal file
@@ -0,0 +1,278 @@
|
||||
/**
|
||||
* Provides predicates and classes for working with the standard library collection implementations.
|
||||
* Currently [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) and
|
||||
* [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) are implemented.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
private import semmle.javascript.dataflow.internal.StepSummary
|
||||
private import DataFlow::PseudoProperties
|
||||
|
||||
/**
|
||||
* A pseudo-property used in a data-flow/type-tracking step for collections.
|
||||
*
|
||||
* By extending `TypeTrackingPseudoProperty` the class enables the use of the collection related pseudo-properties in type-tracking predicates.
|
||||
*/
|
||||
private class PseudoProperty extends TypeTrackingPseudoProperty {
|
||||
PseudoProperty() {
|
||||
this = [arrayLikeElement(), "1"] or // the "1" is required for the `ForOfStep`.
|
||||
this = any(CollectionDataFlow::MapSet step).getAPseudoProperty()
|
||||
}
|
||||
|
||||
override PseudoProperty getLoadStoreToProp() {
|
||||
exists(CollectionFlowStep step | step.loadStore(_, _, this, result))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An `AdditionalFlowStep` used to model a data-flow step related to standard library collections.
|
||||
*
|
||||
* The `loadStep`/`storeStep`/`loadStoreStep` methods are overloaded such that the new predicates
|
||||
* `load`/`store`/`loadStore` can be used in the `CollectionsTypeTracking` module.
|
||||
* (Thereby avoiding naming conflicts with a "cousin" `AdditionalFlowStep` implementation.)
|
||||
*/
|
||||
abstract private class CollectionFlowStep extends DataFlow::AdditionalFlowStep {
|
||||
final override predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
|
||||
|
||||
final override predicate step(
|
||||
DataFlow::Node p, DataFlow::Node s, DataFlow::FlowLabel pl, DataFlow::FlowLabel sl
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the property `prop` of the object `pred` should be loaded into `succ`.
|
||||
*/
|
||||
predicate load(DataFlow::Node pred, DataFlow::Node succ, PseudoProperty prop) { none() }
|
||||
|
||||
final override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
this.load(pred, succ, prop)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
|
||||
*/
|
||||
predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, PseudoProperty prop) { none() }
|
||||
|
||||
final override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
this.store(pred, succ, prop)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the property `prop` should be copied from the object `pred` to the object `succ`.
|
||||
*/
|
||||
predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, PseudoProperty prop) { none() }
|
||||
|
||||
final override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
this.loadStore(pred, succ, prop, prop)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the property `loadProp` should be copied from the object `pred` to the property `storeProp` of object `succ`.
|
||||
*/
|
||||
predicate loadStore(
|
||||
DataFlow::Node pred, DataFlow::Node succ, PseudoProperty loadProp, PseudoProperty storeProp
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
final override predicate loadStoreStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp
|
||||
) {
|
||||
this.loadStore(pred, succ, loadProp, storeProp)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides predicates and clases for type-tracking collections.
|
||||
*/
|
||||
module CollectionsTypeTracking {
|
||||
/**
|
||||
* Gets the result from a single step through a collection, from `pred` to `result` summarized by `summary`.
|
||||
*/
|
||||
pragma[inline]
|
||||
DataFlow::SourceNode collectionStep(DataFlow::Node pred, StepSummary summary) {
|
||||
exists(CollectionFlowStep step, PseudoProperty field |
|
||||
summary = LoadStep(field) and
|
||||
step.load(pred, result, field) and
|
||||
not field = mapValueUnknownKey() // prune unknown reads in type-tracking
|
||||
or
|
||||
summary = StoreStep(field) and
|
||||
step.store(pred, result, field)
|
||||
or
|
||||
summary = CopyStep(field) and
|
||||
step.loadStore(pred, result, field)
|
||||
or
|
||||
exists(PseudoProperty toField | summary = LoadStoreStep(field, toField) |
|
||||
step.loadStore(pred, result, field, toField)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result from a single step through a collection, from `pred` with tracker `t2` to `result` with tracker `t`.
|
||||
*/
|
||||
pragma[inline]
|
||||
DataFlow::SourceNode collectionStep(
|
||||
DataFlow::SourceNode pred, DataFlow::TypeTracker t, DataFlow::TypeTracker t2
|
||||
) {
|
||||
exists(DataFlow::Node mid, StepSummary summary | pred.flowsTo(mid) and t = t2.append(summary) |
|
||||
result = collectionStep(mid, summary)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A module for data-flow steps related standard library collection implementations.
|
||||
*/
|
||||
private module CollectionDataFlow {
|
||||
/**
|
||||
* A step for `Set.add()` method, which adds an element to a Set.
|
||||
*/
|
||||
private class SetAdd extends CollectionFlowStep, DataFlow::MethodCallNode {
|
||||
SetAdd() { this.getMethodName() = "add" }
|
||||
|
||||
override predicate store(DataFlow::Node element, DataFlow::SourceNode obj, PseudoProperty prop) {
|
||||
this = obj.getAMethodCall() and
|
||||
element = this.getArgument(0) and
|
||||
prop = setElement()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for the `Set` constructor, which copies any elements from the first argument into the resulting set.
|
||||
*/
|
||||
private class SetConstructor extends CollectionFlowStep, DataFlow::NewNode {
|
||||
SetConstructor() { this = DataFlow::globalVarRef("Set").getAnInstantiation() }
|
||||
|
||||
override predicate loadStore(
|
||||
DataFlow::Node pred, DataFlow::Node succ, PseudoProperty fromProp, PseudoProperty toProp
|
||||
) {
|
||||
pred = this.getArgument(0) and
|
||||
succ = this and
|
||||
fromProp = arrayLikeElement() and
|
||||
toProp = setElement()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for a `for of` statement on a Map, Set, or Iterator.
|
||||
* For Sets and iterators the l-value are the elements of the set/iterator.
|
||||
* For Maps the l-value is a tuple containing a key and a value.
|
||||
*/
|
||||
// This is partially duplicated behavior with the `for of` step for Arrays (`ArrayDataFlow::ForOfStep`).
|
||||
// This duplication is required for the type-tracking steps defined in `CollectionsTypeTracking`.
|
||||
private class ForOfStep extends CollectionFlowStep, DataFlow::ValueNode {
|
||||
ForOfStmt forOf;
|
||||
DataFlow::Node element;
|
||||
|
||||
ForOfStep() {
|
||||
this.asExpr() = forOf.getIterationDomain() and
|
||||
element = DataFlow::lvalueNode(forOf.getLValue())
|
||||
}
|
||||
|
||||
override predicate load(DataFlow::Node obj, DataFlow::Node e, PseudoProperty prop) {
|
||||
obj = this and
|
||||
e = element and
|
||||
prop = arrayLikeElement()
|
||||
}
|
||||
|
||||
override predicate loadStore(
|
||||
DataFlow::Node pred, DataFlow::Node succ, PseudoProperty fromProp, PseudoProperty toProp
|
||||
) {
|
||||
pred = this and
|
||||
succ = element and
|
||||
fromProp = mapValueAll() and
|
||||
toProp = "1"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for a call to `forEach` on a Set or Map.
|
||||
*/
|
||||
private class SetMapForEach extends CollectionFlowStep, DataFlow::MethodCallNode {
|
||||
SetMapForEach() { this.getMethodName() = "forEach" }
|
||||
|
||||
override predicate load(DataFlow::Node obj, DataFlow::Node element, PseudoProperty prop) {
|
||||
obj = this.getReceiver() and
|
||||
element = this.getCallback(0).getParameter(0) and
|
||||
prop = [setElement(), mapValueAll()]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the `get` method on a Map.
|
||||
* If the key of the call to `get` has a known string value, then only the value corresponding to that key will be retrieved. (The known string value is encoded as part of the pseudo-property)
|
||||
*/
|
||||
private class MapGet extends CollectionFlowStep, DataFlow::MethodCallNode {
|
||||
MapGet() { this.getMethodName() = "get" }
|
||||
|
||||
override predicate load(DataFlow::Node obj, DataFlow::Node element, PseudoProperty prop) {
|
||||
obj = this.getReceiver() and
|
||||
element = this and
|
||||
// reading the join of known and unknown values
|
||||
(prop = mapValue(this.getArgument(0)) or prop = mapValueUnknownKey())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the `set` method on a Map.
|
||||
*
|
||||
* If the key of the call to `set` has a known string value,
|
||||
* then the value will be stored into a pseudo-property corresponding to the known string value.
|
||||
* Otherwise the value will be stored into a pseudo-property corresponding to values with unknown keys.
|
||||
* The value will additionally be stored into a pseudo-property corresponding to all values.
|
||||
*/
|
||||
class MapSet extends CollectionFlowStep, DataFlow::MethodCallNode {
|
||||
MapSet() { this.getMethodName() = "set" }
|
||||
|
||||
override predicate store(DataFlow::Node element, DataFlow::SourceNode obj, PseudoProperty prop) {
|
||||
this = obj.getAMethodCall() and
|
||||
element = this.getArgument(1) and
|
||||
prop = getAPseudoProperty()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property used to store an element in a map.
|
||||
* The pseudo-property represents both values where the key is a known string value (which is encoded in the pseudo-property),
|
||||
* and values where the key is unknown.
|
||||
*
|
||||
* Additionally, all elements are stored into the pseudo-property `mapValueAll()`.
|
||||
*
|
||||
* The return-type is `string` as this predicate is used to define which pseudo-properties exist.
|
||||
*/
|
||||
string getAPseudoProperty() { result = [mapValue(this.getArgument(0)), mapValueAll()] }
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for a call to `values` on a Map or a Set.
|
||||
*/
|
||||
private class MapAndSetValues extends CollectionFlowStep, DataFlow::MethodCallNode {
|
||||
MapAndSetValues() { this.getMethodName() = "values" }
|
||||
|
||||
override predicate loadStore(
|
||||
DataFlow::Node pred, DataFlow::Node succ, PseudoProperty fromProp, PseudoProperty toProp
|
||||
) {
|
||||
pred = this.getReceiver() and
|
||||
succ = this and
|
||||
fromProp = [mapValueAll(), setElement()] and
|
||||
toProp = iteratorElement()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for a call to `keys` on a Set.
|
||||
*/
|
||||
private class SetKeys extends CollectionFlowStep, DataFlow::MethodCallNode {
|
||||
SetKeys() { this.getMethodName() = "keys" }
|
||||
|
||||
override predicate loadStore(
|
||||
DataFlow::Node pred, DataFlow::Node succ, PseudoProperty fromProp, PseudoProperty toProp
|
||||
) {
|
||||
pred = this.getReceiver() and
|
||||
succ = this and
|
||||
fromProp = setElement() and
|
||||
toProp = iteratorElement()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,11 +79,6 @@ class ImportDeclaration extends Stmt, Import, @importdeclaration {
|
||||
|
||||
/** Holds if this is declared with the `type` keyword, so it only imports types. */
|
||||
predicate isTypeOnly() { hasTypeKeyword(this) }
|
||||
|
||||
override predicate isAmbient() {
|
||||
Stmt.super.isAmbient() or
|
||||
isTypeOnly()
|
||||
}
|
||||
}
|
||||
|
||||
/** A literal path expression appearing in an `import` declaration. */
|
||||
@@ -267,11 +262,6 @@ abstract class ExportDeclaration extends Stmt, @exportdeclaration {
|
||||
|
||||
/** Holds if is declared with the `type` keyword, so only types are exported. */
|
||||
predicate isTypeOnly() { hasTypeKeyword(this) }
|
||||
|
||||
override predicate isAmbient() {
|
||||
Stmt.super.isAmbient() or
|
||||
isTypeOnly()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -422,11 +412,6 @@ class ExportNamedDeclaration extends ExportDeclaration, @exportnameddeclaration
|
||||
|
||||
/** Gets an export specifier of this declaration. */
|
||||
ExportSpecifier getASpecifier() { result = getSpecifier(_) }
|
||||
|
||||
override predicate isAmbient() {
|
||||
// An export such as `export declare function f()` should be seen as ambient.
|
||||
hasDeclareKeyword(getOperand()) or getParent().isAmbient()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -397,8 +397,6 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine
|
||||
*/
|
||||
predicate isAbstract() { exists(MethodDeclaration md | this = md.getBody() | md.isAbstract()) }
|
||||
|
||||
override predicate isAmbient() { getParent().isAmbient() or not hasBody() }
|
||||
|
||||
/**
|
||||
* Holds if this function cannot be invoked using `new` because it
|
||||
* is of the given `kind`.
|
||||
|
||||
@@ -176,7 +176,7 @@ module PromiseTypeTracking {
|
||||
summary = StoreStep(field) and
|
||||
step.store(pred, result, field)
|
||||
or
|
||||
summary = LoadStoreStep(field) and
|
||||
summary = CopyStep(field) and
|
||||
step.loadStore(pred, result, field)
|
||||
)
|
||||
}
|
||||
@@ -232,9 +232,9 @@ abstract private class PromiseFlowStep extends DataFlow::AdditionalFlowStep {
|
||||
/**
|
||||
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
|
||||
*/
|
||||
predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
|
||||
predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() }
|
||||
|
||||
final override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
final override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
this.store(pred, succ, prop)
|
||||
}
|
||||
|
||||
@@ -246,6 +246,12 @@ abstract private class PromiseFlowStep extends DataFlow::AdditionalFlowStep {
|
||||
final override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
this.loadStore(pred, succ, prop)
|
||||
}
|
||||
|
||||
final override predicate loadStoreStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp
|
||||
) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -267,7 +273,7 @@ private module PromiseFlow {
|
||||
|
||||
PromiseDefitionStep() { this = promise }
|
||||
|
||||
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
prop = valueProp() and
|
||||
pred = promise.getResolveParameter().getACall().getArgument(0) and
|
||||
succ = this
|
||||
@@ -296,7 +302,7 @@ private module PromiseFlow {
|
||||
|
||||
CreationStep() { this = promise }
|
||||
|
||||
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
prop = valueProp() and
|
||||
pred = promise.getValue() and
|
||||
succ = this
|
||||
@@ -362,7 +368,7 @@ private module PromiseFlow {
|
||||
succ = this
|
||||
}
|
||||
|
||||
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
prop = valueProp() and
|
||||
pred = getCallback([0 .. 1]).getAReturn() and
|
||||
succ = this
|
||||
@@ -396,7 +402,7 @@ private module PromiseFlow {
|
||||
succ = this
|
||||
}
|
||||
|
||||
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
prop = errorProp() and
|
||||
pred = getCallback(0).getExceptionalReturn() and
|
||||
succ = this
|
||||
@@ -424,7 +430,7 @@ private module PromiseFlow {
|
||||
succ = this
|
||||
}
|
||||
|
||||
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
prop = errorProp() and
|
||||
pred = getCallback(0).getExceptionalReturn() and
|
||||
succ = this
|
||||
|
||||
@@ -54,8 +54,6 @@ class Stmt extends @stmt, ExprOrStmt, Documentable {
|
||||
getContainer().(Expr).getEnclosingStmt().nestedIn(outer)
|
||||
}
|
||||
|
||||
override predicate isAmbient() { hasDeclareKeyword(this) or getParent().isAmbient() }
|
||||
|
||||
/**
|
||||
* Gets the `try` statement with a catch block containing this statement without
|
||||
* crossing function boundaries or other `try ` statements with catch blocks.
|
||||
@@ -931,8 +929,6 @@ class DebuggerStmt extends @debuggerstmt, Stmt {
|
||||
*/
|
||||
class FunctionDeclStmt extends @functiondeclstmt, Stmt, Function {
|
||||
override Stmt getEnclosingStmt() { result = this }
|
||||
|
||||
override predicate isAmbient() { Function.super.isAmbient() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -155,8 +155,6 @@ class ExternalModuleDeclaration extends Stmt, StmtContainer, @externalmoduledecl
|
||||
int getNumStmt() { result = count(getAStmt()) }
|
||||
|
||||
override StmtContainer getEnclosingContainer() { result = this.getContainer() }
|
||||
|
||||
override predicate isAmbient() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,8 +174,6 @@ class GlobalAugmentationDeclaration extends Stmt, StmtContainer, @globalaugmenta
|
||||
int getNumStmt() { result = count(getAStmt()) }
|
||||
|
||||
override StmtContainer getEnclosingContainer() { result = this.getContainer() }
|
||||
|
||||
override predicate isAmbient() { any() }
|
||||
}
|
||||
|
||||
/** A TypeScript "import-equals" declaration. */
|
||||
@@ -237,8 +233,6 @@ class ExportAsNamespaceDeclaration extends Stmt, @exportasnamespacedeclaration {
|
||||
* Gets the `X` in `export as namespace X`.
|
||||
*/
|
||||
Identifier getIdentifier() { result = getChildExpr(0) }
|
||||
|
||||
override predicate isAmbient() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -259,8 +253,6 @@ class TypeAliasDeclaration extends @typealiasdeclaration, TypeParameterized, Stm
|
||||
|
||||
override string describe() { result = "type alias " + getName() }
|
||||
|
||||
override predicate isAmbient() { any() }
|
||||
|
||||
/**
|
||||
* Gets the canonical name of the type being defined.
|
||||
*/
|
||||
@@ -286,8 +278,6 @@ class InterfaceDeclaration extends Stmt, InterfaceDefinition, @interfacedeclarat
|
||||
|
||||
override StmtContainer getContainer() { result = Stmt.super.getContainer() }
|
||||
|
||||
override predicate isAmbient() { any() }
|
||||
|
||||
override string describe() { result = "interface " + getName() }
|
||||
|
||||
/**
|
||||
@@ -533,8 +523,6 @@ class LocalNamespaceName extends @local_namespace_name, LexicalName {
|
||||
class TypeExpr extends ExprOrType, @typeexpr, TypeAnnotation {
|
||||
override string toString() { typeexprs(this, _, _, _, result) }
|
||||
|
||||
override predicate isAmbient() { any() }
|
||||
|
||||
/**
|
||||
* Gets the static type expressed by this type annotation.
|
||||
*
|
||||
@@ -1410,8 +1398,6 @@ class EnumDeclaration extends NamespaceDefinition, @enumdeclaration, AST::ValueN
|
||||
/** Holds if this enumeration is declared with the `const` keyword. */
|
||||
predicate isConst() { isConstEnum(this) }
|
||||
|
||||
override predicate isAmbient() { hasDeclareKeyword(this) or getParent().isAmbient() }
|
||||
|
||||
override ControlFlowNode getFirstControlFlowNode() { result = getIdentifier() }
|
||||
}
|
||||
|
||||
|
||||
@@ -244,8 +244,11 @@ abstract class Configuration extends string {
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
|
||||
* The object `succ` must be a `DataFlow::SourceNode` for the object wherein the value is stored.
|
||||
*/
|
||||
predicate isAdditionalStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
|
||||
predicate isAdditionalStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
@@ -540,9 +543,10 @@ abstract class AdditionalFlowStep extends DataFlow::Node {
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
|
||||
* The object `succ` must be a `DataFlow::SourceNode` for the object wherein the value is stored.
|
||||
*/
|
||||
cached
|
||||
predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
|
||||
predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() }
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
@@ -574,6 +578,71 @@ abstract class AdditionalFlowStep extends DataFlow::Node {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of pseudo-properties that are used in multiple files.
|
||||
*
|
||||
* A pseudo-property represents the location where some value is stored in an object.
|
||||
*
|
||||
* For use with load/store steps in `DataFlow::AdditionalFlowStep` and TypeTracking.
|
||||
*/
|
||||
module PseudoProperties {
|
||||
bindingset[s]
|
||||
private string pseudoProperty(string s) { result = "$" + s + "$" }
|
||||
|
||||
bindingset[s, v]
|
||||
private string pseudoProperty(string s, string v) { result = "$" + s + "|" + v + "$" }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of elements in a `Set`
|
||||
*/
|
||||
string setElement() { result = pseudoProperty("setElement") }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of elements in a JavaScript iterator.
|
||||
*/
|
||||
string iteratorElement() { result = pseudoProperty("iteratorElement") }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of elements in an `Array`.
|
||||
*/
|
||||
string arrayElement() { result = pseudoProperty("arrayElement") }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of elements in some array-like object. (Set, Array, or Iterator).
|
||||
*/
|
||||
string arrayLikeElement() { result = [setElement(), iteratorElement(), arrayElement()] }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of map values, where the key is unknown.
|
||||
*/
|
||||
string mapValueUnknownKey() { result = pseudoProperty("mapValueUnknownKey") }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of all the values in a map.
|
||||
*/
|
||||
string mapValueAll() { result = pseudoProperty("allMapValues") }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of a map value where the key is `key`.
|
||||
* The string value of the `key` is encoded in the result, and there is only a result if the string value of `key` is known.
|
||||
*/
|
||||
pragma[inline]
|
||||
string mapValueKnownKey(DataFlow::Node key) {
|
||||
result = pseudoProperty("mapValue", any(string s | key.mayHaveStringValue(s)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of a map value where the key is `key`.
|
||||
*/
|
||||
pragma[inline]
|
||||
string mapValue(DataFlow::Node key) {
|
||||
result = mapValueKnownKey(key)
|
||||
or
|
||||
not exists(mapValueKnownKey(key)) and
|
||||
result = mapValueUnknownKey()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node that should be considered a source for some specific configuration,
|
||||
* in addition to any other sources that configuration may recognize.
|
||||
|
||||
@@ -620,6 +620,16 @@ class ArrayCreationNode extends DataFlow::ValueNode, DataFlow::SourceNode {
|
||||
result = this.(ArrayLiteralNode).getSize() or
|
||||
result = this.(ArrayConstructorInvokeNode).getSize()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data flow node corresponding to an array of values being passed as
|
||||
* individual arguments to this array creation.
|
||||
*/
|
||||
DataFlow::Node getASpreadArgument() {
|
||||
exists(SpreadElement arg | arg = getAnElement().getEnclosingExpr() |
|
||||
result = DataFlow::valueNode(arg.getOperand())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,11 +39,7 @@ class SourceNode extends DataFlow::Node {
|
||||
* Holds if this node flows into `sink` in zero or more local (that is,
|
||||
* intra-procedural) steps.
|
||||
*/
|
||||
cached
|
||||
predicate flowsTo(DataFlow::Node sink) {
|
||||
sink = this or
|
||||
flowsTo(sink.getAPredecessor())
|
||||
}
|
||||
predicate flowsTo(DataFlow::Node sink) { hasLocalSource(sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if this node flows into `sink` in zero or more local (that is,
|
||||
@@ -195,6 +191,24 @@ class SourceNode extends DataFlow::Node {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `source` is a `SourceNode` that can reach `sink` via local flow steps.
|
||||
*
|
||||
* The slightly backwards parametering ordering is to force correct indexing.
|
||||
*/
|
||||
cached
|
||||
private predicate hasLocalSource(DataFlow::Node sink, DataFlow::Node source) {
|
||||
// Declaring `source` to be a `SourceNode` currently causes a redundant check in the
|
||||
// recursive case, so instead we check it explicitly here.
|
||||
source = sink and
|
||||
source instanceof DataFlow::SourceNode
|
||||
or
|
||||
exists(DataFlow::Node mid |
|
||||
hasLocalSource(mid, source) and
|
||||
DataFlow::localFlowStep(mid, sink)
|
||||
)
|
||||
}
|
||||
|
||||
module SourceNode {
|
||||
/**
|
||||
* A data flow node that should be considered a source node.
|
||||
|
||||
@@ -603,15 +603,10 @@ module TaintTracking {
|
||||
* 3) A `URLSearchParams` object (either `url.searchParams` or `new URLSearchParams(input)`) has a tainted value,
|
||||
* which can be accessed using a `get` or `getAll` call. (See getableUrlPseudoProperty())
|
||||
*/
|
||||
override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
succ = this and
|
||||
(
|
||||
(
|
||||
prop = "searchParams" or
|
||||
prop = "hash" or
|
||||
prop = "search" or
|
||||
prop = hiddenUrlPseudoProperty()
|
||||
) and
|
||||
prop = ["searchParams", "hash", "search", hiddenUrlPseudoProperty()] and
|
||||
exists(DataFlow::NewNode newUrl | succ = newUrl |
|
||||
newUrl = DataFlow::globalVarRef("URL").getAnInstantiation() and
|
||||
pred = newUrl.getArgument(0)
|
||||
|
||||
@@ -53,7 +53,11 @@ class TypeTracker extends TTypeTracker {
|
||||
TypeTracker append(StepSummary step) {
|
||||
step = LevelStep() and result = this
|
||||
or
|
||||
step = LoadStoreStep(prop) and result = this
|
||||
exists(string toProp | step = LoadStoreStep(prop, toProp) |
|
||||
result = MkTypeTracker(hasCall, toProp)
|
||||
)
|
||||
or
|
||||
step = CopyStep(prop) and result = this
|
||||
or
|
||||
step = CallStep() and result = MkTypeTracker(true, prop)
|
||||
or
|
||||
@@ -213,7 +217,11 @@ class TypeBackTracker extends TTypeBackTracker {
|
||||
TypeBackTracker prepend(StepSummary step) {
|
||||
step = LevelStep() and result = this
|
||||
or
|
||||
step = LoadStoreStep(prop) and result = this
|
||||
exists(string fromProp | step = LoadStoreStep(fromProp, prop) |
|
||||
result = MkTypeBackTracker(hasReturn, fromProp)
|
||||
)
|
||||
or
|
||||
step = CopyStep(prop) and result = this
|
||||
or
|
||||
step = CallStep() and hasReturn = false and result = this
|
||||
or
|
||||
|
||||
@@ -24,6 +24,11 @@ class OptionalPropertyName extends string {
|
||||
abstract class TypeTrackingPseudoProperty extends string {
|
||||
bindingset[this]
|
||||
TypeTrackingPseudoProperty() { any() }
|
||||
|
||||
/**
|
||||
* Gets a property name that `this` can be copied to in a `LoadStoreStep(this, result)`.
|
||||
*/
|
||||
string getLoadStoreToProp() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,7 +40,10 @@ newtype TStepSummary =
|
||||
ReturnStep() or
|
||||
StoreStep(PropertyName prop) or
|
||||
LoadStep(PropertyName prop) or
|
||||
LoadStoreStep(PropertyName prop)
|
||||
CopyStep(PropertyName prop) or
|
||||
LoadStoreStep(PropertyName fromProp, PropertyName toProp) {
|
||||
exists(TypeTrackingPseudoProperty prop | fromProp = prop and toProp = prop.getLoadStoreToProp())
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Use `TypeTracker` or `TypeBackTracker` instead.
|
||||
@@ -55,7 +63,11 @@ class StepSummary extends TStepSummary {
|
||||
or
|
||||
exists(string prop | this = LoadStep(prop) | result = "load " + prop)
|
||||
or
|
||||
exists(string prop | this = LoadStoreStep(prop) | result = "in " + prop)
|
||||
exists(string prop | this = CopyStep(prop) | result = "copy " + prop)
|
||||
or
|
||||
exists(string fromProp, string toProp | this = LoadStoreStep(fromProp, toProp) |
|
||||
result = "load " + fromProp + " and store to " + toProp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -459,7 +459,7 @@ module NodeJSLib {
|
||||
private class NodeJSFileSystemAccess extends FileSystemAccess, DataFlow::CallNode {
|
||||
string methodName;
|
||||
|
||||
NodeJSFileSystemAccess() { this = fsModuleMember(methodName).getACall() }
|
||||
NodeJSFileSystemAccess() { this = maybePromisified(fsModuleMember(methodName)).getACall() }
|
||||
|
||||
/**
|
||||
* Gets the name of the called method.
|
||||
@@ -586,6 +586,19 @@ module NodeJSLib {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possibly promisified (using `util.promisify`) version of the input `callback`.
|
||||
*/
|
||||
private DataFlow::SourceNode maybePromisified(DataFlow::SourceNode callback) {
|
||||
result = callback
|
||||
or
|
||||
exists(DataFlow::CallNode promisify |
|
||||
promisify = DataFlow::moduleMember("util", "promisify").getACall()
|
||||
|
|
||||
result = promisify and promisify.getArgument(0).getALocalSource() = callback
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a method from module `child_process`.
|
||||
*/
|
||||
@@ -593,7 +606,7 @@ module NodeJSLib {
|
||||
string methodName;
|
||||
|
||||
ChildProcessMethodCall() {
|
||||
this = DataFlow::moduleMember("child_process", methodName).getACall()
|
||||
this = maybePromisified(DataFlow::moduleMember("child_process", methodName)).getACall()
|
||||
}
|
||||
|
||||
private DataFlow::Node getACommandArgument(boolean shell) {
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:15:27:15:27 | e |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:16:23:16:23 | e |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:20:8:20:16 | arr.pop() |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:52:10:52:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:56:10:56:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:60:10:60:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:66:10:66:10 | x |
|
||||
| arrays.js:18:22:18:29 | "source" | arrays.js:18:50:18:50 | e |
|
||||
| arrays.js:22:15:22:22 | "source" | arrays.js:23:8:23:17 | arr2.pop() |
|
||||
| arrays.js:25:15:25:22 | "source" | arrays.js:26:8:26:17 | arr3.pop() |
|
||||
|
||||
@@ -47,4 +47,22 @@
|
||||
});
|
||||
|
||||
sink(arr[0]); // OK - tuple like usage.
|
||||
|
||||
for (const x of arr) {
|
||||
sink(x); // NOT OK
|
||||
}
|
||||
|
||||
for (const x of Array.from(arr)) {
|
||||
sink(x); // NOT OK
|
||||
}
|
||||
|
||||
for (const x of [...arr]) {
|
||||
sink(x); // NOT OK
|
||||
}
|
||||
|
||||
var arr7 = [];
|
||||
arr7.push(...arr);
|
||||
for (const x of arr7) {
|
||||
sink(x); // NOT OK
|
||||
}
|
||||
});
|
||||
|
||||
@@ -222,135 +222,135 @@ flow
|
||||
exclusiveTaintFlow
|
||||
| interflow.js:3:18:3:25 | "source" | interflow.js:18:10:18:14 | error |
|
||||
typetrack
|
||||
| flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:20:31:20:31 | x | flow.js:20:2:20:24 | Promise ... source) | load $PromiseResolveField$ |
|
||||
| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:36:22:41 | foo(x) | in $PromiseResolveField$ |
|
||||
| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:36:22:41 | foo(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:36:22:41 | foo(x) | store $PromiseResolveField$ |
|
||||
| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:49:22:55 | sink(y) | in $PromiseResolveField$ |
|
||||
| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:49:22:55 | sink(y) | copy $PromiseResolveField$ |
|
||||
| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:49:22:55 | sink(y) | store $PromiseResolveField$ |
|
||||
| flow.js:22:31:22:31 | x | flow.js:22:2:22:24 | Promise ... source) | load $PromiseResolveField$ |
|
||||
| flow.js:24:2:24:68 | new Pro ... ink(x)) | flow.js:24:61:24:67 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:24:2:24:68 | new Pro ... ink(x)) | flow.js:24:61:24:67 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:24:2:24:68 | new Pro ... ink(x)) | flow.js:24:61:24:67 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:24:56:24:56 | x | flow.js:24:2:24:49 | new Pro ... ource)) | load $PromiseResolveField$ |
|
||||
| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:61:26:66 | foo(x) | in $PromiseResolveField$ |
|
||||
| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:61:26:66 | foo(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:61:26:66 | foo(x) | store $PromiseResolveField$ |
|
||||
| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:74:26:80 | sink(y) | in $PromiseResolveField$ |
|
||||
| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:74:26:80 | sink(y) | copy $PromiseResolveField$ |
|
||||
| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:74:26:80 | sink(y) | store $PromiseResolveField$ |
|
||||
| flow.js:26:56:26:56 | x | flow.js:26:2:26:49 | new Pro ... ource)) | load $PromiseResolveField$ |
|
||||
| flow.js:28:2:28:60 | Promise ... ink(z)) | flow.js:28:53:28:59 | sink(z) | in $PromiseResolveField$ |
|
||||
| flow.js:28:2:28:60 | Promise ... ink(z)) | flow.js:28:53:28:59 | sink(z) | copy $PromiseResolveField$ |
|
||||
| flow.js:28:2:28:60 | Promise ... ink(z)) | flow.js:28:53:28:59 | sink(z) | store $PromiseResolveField$ |
|
||||
| flow.js:28:30:28:30 | x | flow.js:28:2:28:23 | Promise ... ("foo") | load $PromiseResolveField$ |
|
||||
| flow.js:28:48:28:48 | z | flow.js:28:2:28:41 | Promise ... source) | load $PromiseResolveField$ |
|
||||
| flow.js:30:2:30:60 | Promise ... ink(z)) | flow.js:30:53:30:59 | sink(z) | in $PromiseResolveField$ |
|
||||
| flow.js:30:2:30:60 | Promise ... ink(z)) | flow.js:30:53:30:59 | sink(z) | copy $PromiseResolveField$ |
|
||||
| flow.js:30:2:30:60 | Promise ... ink(z)) | flow.js:30:53:30:59 | sink(z) | store $PromiseResolveField$ |
|
||||
| flow.js:30:31:30:31 | x | flow.js:30:2:30:24 | Promise ... source) | load $PromiseResolveField$ |
|
||||
| flow.js:30:48:30:48 | z | flow.js:30:2:30:41 | Promise ... "foo") | load $PromiseResolveField$ |
|
||||
| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:2:32:49 | new Pro ... ource)) | in $PromiseResolveField$ |
|
||||
| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:62:32:68 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:2:32:49 | new Pro ... ource)) | copy $PromiseResolveField$ |
|
||||
| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:62:32:68 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:62:32:68 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:34:2:34:41 | Promise ... => { }) | flow.js:34:2:34:24 | Promise ... source) | in $PromiseResolveField$ |
|
||||
| flow.js:34:2:34:60 | Promise ... ink(a)) | flow.js:34:53:34:59 | sink(a) | in $PromiseResolveField$ |
|
||||
| flow.js:34:2:34:41 | Promise ... => { }) | flow.js:34:2:34:24 | Promise ... source) | copy $PromiseResolveField$ |
|
||||
| flow.js:34:2:34:60 | Promise ... ink(a)) | flow.js:34:53:34:59 | sink(a) | copy $PromiseResolveField$ |
|
||||
| flow.js:34:2:34:60 | Promise ... ink(a)) | flow.js:34:53:34:59 | sink(a) | store $PromiseResolveField$ |
|
||||
| flow.js:34:48:34:48 | a | flow.js:34:2:34:41 | Promise ... => { }) | load $PromiseResolveField$ |
|
||||
| flow.js:37:11:37:29 | p5.catch(() => { }) | flow.js:36:11:36:33 | Promise ... source) | in $PromiseResolveField$ |
|
||||
| flow.js:38:11:38:31 | p6.then ... ink(a)) | flow.js:38:24:38:30 | sink(a) | in $PromiseResolveField$ |
|
||||
| flow.js:37:11:37:29 | p5.catch(() => { }) | flow.js:36:11:36:33 | Promise ... source) | copy $PromiseResolveField$ |
|
||||
| flow.js:38:11:38:31 | p6.then ... ink(a)) | flow.js:38:24:38:30 | sink(a) | copy $PromiseResolveField$ |
|
||||
| flow.js:38:11:38:31 | p6.then ... ink(a)) | flow.js:38:24:38:30 | sink(a) | store $PromiseResolveField$ |
|
||||
| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:2:40:65 | new Pro ... => { }) | in $PromiseResolveField$ |
|
||||
| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:78:40:84 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:2:40:65 | new Pro ... => { }) | copy $PromiseResolveField$ |
|
||||
| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:78:40:84 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:78:40:84 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:2:42:76 | new Pro ... => { }) | in $PromiseResolveField$ |
|
||||
| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:89:42:95 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:2:42:76 | new Pro ... => { }) | copy $PromiseResolveField$ |
|
||||
| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:89:42:95 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:89:42:95 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:41 | Promise ... => { }) | flow.js:44:2:44:24 | Promise ... source) | in $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:58 | Promise ... => { }) | flow.js:44:2:44:41 | Promise ... => { }) | in $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:75 | Promise ... => { }) | flow.js:44:2:44:58 | Promise ... => { }) | in $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:94 | Promise ... ink(a)) | flow.js:44:87:44:93 | sink(a) | in $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:41 | Promise ... => { }) | flow.js:44:2:44:24 | Promise ... source) | copy $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:58 | Promise ... => { }) | flow.js:44:2:44:41 | Promise ... => { }) | copy $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:75 | Promise ... => { }) | flow.js:44:2:44:58 | Promise ... => { }) | copy $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:94 | Promise ... ink(a)) | flow.js:44:87:44:93 | sink(a) | copy $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:94 | Promise ... ink(a)) | flow.js:44:87:44:93 | sink(a) | store $PromiseResolveField$ |
|
||||
| flow.js:44:82:44:82 | a | flow.js:44:2:44:75 | Promise ... => { }) | load $PromiseResolveField$ |
|
||||
| flow.js:46:2:46:43 | Promise ... => { }) | flow.js:46:2:46:24 | Promise ... source) | in $PromiseResolveField$ |
|
||||
| flow.js:46:2:46:62 | Promise ... ink(a)) | flow.js:46:55:46:61 | sink(a) | in $PromiseResolveField$ |
|
||||
| flow.js:46:2:46:43 | Promise ... => { }) | flow.js:46:2:46:24 | Promise ... source) | copy $PromiseResolveField$ |
|
||||
| flow.js:46:2:46:62 | Promise ... ink(a)) | flow.js:46:55:46:61 | sink(a) | copy $PromiseResolveField$ |
|
||||
| flow.js:46:2:46:62 | Promise ... ink(a)) | flow.js:46:55:46:61 | sink(a) | store $PromiseResolveField$ |
|
||||
| flow.js:46:50:46:50 | a | flow.js:46:2:46:43 | Promise ... => { }) | load $PromiseResolveField$ |
|
||||
| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:2:48:36 | new Pro ... urce }) | in $PromiseResolveField$ |
|
||||
| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:49:48:55 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:2:48:36 | new Pro ... urce }) | copy $PromiseResolveField$ |
|
||||
| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:49:48:55 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:49:48:55 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:53:2:53:41 | createP ... ink(v)) | flow.js:53:34:53:40 | sink(v) | in $PromiseResolveField$ |
|
||||
| flow.js:53:2:53:41 | createP ... ink(v)) | flow.js:53:34:53:40 | sink(v) | copy $PromiseResolveField$ |
|
||||
| flow.js:53:2:53:41 | createP ... ink(v)) | flow.js:53:34:53:40 | sink(v) | store $PromiseResolveField$ |
|
||||
| flow.js:53:29:53:29 | v | flow.js:53:2:53:22 | createP ... source) | load $PromiseResolveField$ |
|
||||
| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:57:12:57:31 | p9.finally(() => {}) | in $PromiseResolveField$ |
|
||||
| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:58:19:58:25 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:57:12:57:31 | p9.finally(() => {}) | copy $PromiseResolveField$ |
|
||||
| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:58:19:58:25 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:58:19:58:25 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:61:12:61:29 | p11.then(() => {}) | in $PromiseResolveField$ |
|
||||
| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:62:17:62:23 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:61:12:61:29 | p11.then(() => {}) | copy $PromiseResolveField$ |
|
||||
| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:62:17:62:23 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:62:17:62:23 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:65:3:65:56 | await n ... ource)) | flow.js:65:9:65:56 | new Pro ... ource)) | load $PromiseResolveField$ |
|
||||
| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:2:76:32 | chained ... => {}) | in $PromiseResolveField$ |
|
||||
| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:45:76:51 | sink(e) | in $PromiseResolveField$ |
|
||||
| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:2:76:32 | chained ... => {}) | copy $PromiseResolveField$ |
|
||||
| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:45:76:51 | sink(e) | copy $PromiseResolveField$ |
|
||||
| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:45:76:51 | sink(e) | store $PromiseResolveField$ |
|
||||
| flow.js:79:3:79:22 | p.then(x => sink(x)) | flow.js:79:15:79:21 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:79:3:79:22 | p.then(x => sink(x)) | flow.js:79:15:79:21 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:79:3:79:22 | p.then(x => sink(x)) | flow.js:79:15:79:21 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:83:32:83:32 | p | in $PromiseResolveField$ |
|
||||
| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:84:16:84:22 | sink(e) | in $PromiseResolveField$ |
|
||||
| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:83:32:83:32 | p | copy $PromiseResolveField$ |
|
||||
| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:84:16:84:22 | sink(e) | copy $PromiseResolveField$ |
|
||||
| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:84:16:84:22 | sink(e) | store $PromiseResolveField$ |
|
||||
| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:3:89:27 | ("foo", ... => {}) | in $PromiseResolveField$ |
|
||||
| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:40:89:46 | sink(e) | in $PromiseResolveField$ |
|
||||
| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:3:89:27 | ("foo", ... => {}) | copy $PromiseResolveField$ |
|
||||
| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:40:89:46 | sink(e) | copy $PromiseResolveField$ |
|
||||
| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:40:89:46 | sink(e) | store $PromiseResolveField$ |
|
||||
| flow.js:103:2:103:76 | new Pro ... ource}) | flow.js:103:2:103:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
|
||||
| flow.js:103:2:103:95 | new Pro ... ink(x)) | flow.js:103:88:103:94 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:103:2:103:76 | new Pro ... ource}) | flow.js:103:2:103:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
|
||||
| flow.js:103:2:103:95 | new Pro ... ink(x)) | flow.js:103:88:103:94 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:103:2:103:95 | new Pro ... ink(x)) | flow.js:103:88:103:94 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:103:83:103:83 | x | flow.js:103:2:103:76 | new Pro ... ource}) | load $PromiseResolveField$ |
|
||||
| flow.js:105:2:105:77 | new Pro ... ource}) | flow.js:105:2:105:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
|
||||
| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:2:105:77 | new Pro ... ource}) | in $PromiseResolveField$ |
|
||||
| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:90:105:96 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:105:2:105:77 | new Pro ... ource}) | flow.js:105:2:105:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
|
||||
| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:2:105:77 | new Pro ... ource}) | copy $PromiseResolveField$ |
|
||||
| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:90:105:96 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:90:105:96 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:109:2:109:71 | new Pro ... jected) | flow.js:109:2:109:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
|
||||
| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:2:109:71 | new Pro ... jected) | in $PromiseResolveField$ |
|
||||
| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:84:109:90 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:109:2:109:71 | new Pro ... jected) | flow.js:109:2:109:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
|
||||
| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:2:109:71 | new Pro ... jected) | copy $PromiseResolveField$ |
|
||||
| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:84:109:90 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:84:109:90 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:111:2:111:69 | new Pro ... jected) | flow.js:111:2:111:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
|
||||
| flow.js:111:2:111:88 | new Pro ... ink(x)) | flow.js:111:81:111:87 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:111:2:111:69 | new Pro ... jected) | flow.js:111:2:111:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
|
||||
| flow.js:111:2:111:88 | new Pro ... ink(x)) | flow.js:111:81:111:87 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:111:2:111:88 | new Pro ... ink(x)) | flow.js:111:81:111:87 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:111:76:111:76 | x | flow.js:111:2:111:69 | new Pro ... jected) | load $PromiseResolveField$ |
|
||||
| flow.js:113:2:113:69 | new Pro ... jected) | flow.js:113:2:113:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
|
||||
| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:2:113:69 | new Pro ... jected) | in $PromiseResolveField$ |
|
||||
| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:82:113:88 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:113:2:113:69 | new Pro ... jected) | flow.js:113:2:113:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
|
||||
| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:2:113:69 | new Pro ... jected) | copy $PromiseResolveField$ |
|
||||
| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:82:113:88 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:82:113:88 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:117:2:117:69 | new Pro ... solved) | flow.js:117:2:117:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
|
||||
| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:2:117:69 | new Pro ... solved) | in $PromiseResolveField$ |
|
||||
| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:82:117:88 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:117:2:117:69 | new Pro ... solved) | flow.js:117:2:117:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
|
||||
| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:2:117:69 | new Pro ... solved) | copy $PromiseResolveField$ |
|
||||
| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:82:117:88 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:82:117:88 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:119:2:119:69 | new Pro ... solved) | flow.js:119:2:119:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
|
||||
| flow.js:119:2:119:88 | new Pro ... ink(x)) | flow.js:119:81:119:87 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:119:2:119:69 | new Pro ... solved) | flow.js:119:2:119:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
|
||||
| flow.js:119:2:119:88 | new Pro ... ink(x)) | flow.js:119:81:119:87 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:119:2:119:88 | new Pro ... ink(x)) | flow.js:119:81:119:87 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:119:76:119:76 | x | flow.js:119:2:119:69 | new Pro ... solved) | load $PromiseResolveField$ |
|
||||
| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:2:121:41 | Promise ... solved) | in $PromiseResolveField$ |
|
||||
| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:54:121:60 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:2:121:41 | Promise ... solved) | copy $PromiseResolveField$ |
|
||||
| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:54:121:60 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:54:121:60 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:121:28:121:28 | x | flow.js:121:2:121:21 | Promise.resolve(123) | load $PromiseResolveField$ |
|
||||
| flow.js:123:2:123:60 | Promise ... ink(x)) | flow.js:123:53:123:59 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:123:2:123:60 | Promise ... ink(x)) | flow.js:123:53:123:59 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:123:2:123:60 | Promise ... ink(x)) | flow.js:123:53:123:59 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:123:28:123:28 | x | flow.js:123:2:123:21 | Promise.resolve(123) | load $PromiseResolveField$ |
|
||||
| flow.js:123:48:123:48 | x | flow.js:123:2:123:41 | Promise ... solved) | load $PromiseResolveField$ |
|
||||
| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:2:125:41 | Promise ... jected) | in $PromiseResolveField$ |
|
||||
| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:54:125:60 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:2:125:41 | Promise ... jected) | copy $PromiseResolveField$ |
|
||||
| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:54:125:60 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:54:125:60 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:125:28:125:28 | x | flow.js:125:2:125:21 | Promise.resolve(123) | load $PromiseResolveField$ |
|
||||
| flow.js:127:2:127:60 | Promise ... ink(x)) | flow.js:127:53:127:59 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:127:2:127:60 | Promise ... ink(x)) | flow.js:127:53:127:59 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:127:2:127:60 | Promise ... ink(x)) | flow.js:127:53:127:59 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:127:28:127:28 | x | flow.js:127:2:127:21 | Promise.resolve(123) | load $PromiseResolveField$ |
|
||||
| flow.js:127:48:127:48 | x | flow.js:127:2:127:41 | Promise ... jected) | load $PromiseResolveField$ |
|
||||
| flow.js:129:2:129:71 | new Pro ... ink(x)) | flow.js:129:64:129:70 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:129:2:129:71 | new Pro ... ink(x)) | flow.js:129:64:129:70 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:129:2:129:71 | new Pro ... ink(x)) | flow.js:129:64:129:70 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:129:59:129:59 | x | flow.js:129:2:129:52 | new Pro ... olved)) | load $PromiseResolveField$ |
|
||||
| flow.js:131:2:131:45 | Promise ... ink(x)) | flow.js:131:38:131:44 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:131:2:131:45 | Promise ... ink(x)) | flow.js:131:38:131:44 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:131:2:131:45 | Promise ... ink(x)) | flow.js:131:38:131:44 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:131:33:131:33 | x | flow.js:131:2:131:26 | Promise ... solved) | load $PromiseResolveField$ |
|
||||
| interflow.js:6:3:9:23 | loadScr ... eError) | interflow.js:6:3:8:26 | loadScr ... () { }) | in $PromiseResolveField$ |
|
||||
| promises.js:23:3:25:4 | promise ... v;\\n }) | promises.js:10:18:17:4 | new Pro ... );\\n }) | in $PromiseResolveField$ |
|
||||
| promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:34:17:34:22 | source | in $PromiseResolveField$ |
|
||||
| interflow.js:6:3:9:23 | loadScr ... eError) | interflow.js:6:3:8:26 | loadScr ... () { }) | copy $PromiseResolveField$ |
|
||||
| promises.js:23:3:25:4 | promise ... v;\\n }) | promises.js:10:18:17:4 | new Pro ... );\\n }) | copy $PromiseResolveField$ |
|
||||
| promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:34:17:34:22 | source | copy $PromiseResolveField$ |
|
||||
| promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:34:17:34:22 | source | store $PromiseResolveField$ |
|
||||
| promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:44:17:44:22 | source | in $PromiseResolveField$ |
|
||||
| promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:44:17:44:22 | source | copy $PromiseResolveField$ |
|
||||
| promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:44:17:44:22 | source | store $PromiseResolveField$ |
|
||||
| promises.js:71:34:71:36 | val | promises.js:71:5:71:27 | Promise ... source) | load $PromiseResolveField$ |
|
||||
| promises.js:72:48:72:50 | val | promises.js:72:5:72:41 | new Pro ... ource)) | load $PromiseResolveField$ |
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
| tst.ts:1:25:1:26 | -1 | -1 | -1 |
|
||||
@@ -0,0 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from NumberLiteralTypeExpr t
|
||||
select t, t.getValue(), t.getIntValue()
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"include": ["."]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
type Foo<T> = T extends -1 ? true : false;
|
||||
@@ -0,0 +1,28 @@
|
||||
dataFlow
|
||||
| tst.js:2:16:2:23 | source() | tst.js:7:7:7:7 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:11:10:11:10 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:17:10:17:10 | v |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:21:10:21:14 | value |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:26:10:26:14 | value |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:30:7:30:7 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:34:7:34:7 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:38:7:38:7 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:42:7:42:7 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:46:7:46:7 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:50:10:50:10 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:53:8:53:21 | map.get("key") |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:59:8:59:22 | map2.get("foo") |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:64:8:64:26 | map3.get(unknown()) |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:69:8:69:26 | map3.get(unknown()) |
|
||||
typeTracking
|
||||
| tst.js:2:16:2:23 | source() | tst.js:2:16:2:23 | source() |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:6:14:6:14 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:10:15:10:15 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:16:15:16:15 | v |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:20:20:20:24 | value |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:25:14:25:18 | value |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:29:14:29:14 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:33:14:33:14 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:37:14:37:14 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:45:14:45:14 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:53:8:53:21 | map.get("key") |
|
||||
@@ -0,0 +1,33 @@
|
||||
import javascript
|
||||
|
||||
class Config extends DataFlow::Configuration {
|
||||
Config() { this = "Config" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.(DataFlow::CallNode).getCalleeName() = "source"
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(DataFlow::CallNode call | call.getCalleeName() = "sink" | call.getAnArgument() = sink)
|
||||
}
|
||||
}
|
||||
|
||||
query predicate dataFlow(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
any(Config c).hasFlow(pred, succ)
|
||||
}
|
||||
|
||||
DataFlow::SourceNode trackSource(DataFlow::TypeTracker t, DataFlow::SourceNode start) {
|
||||
t.start() and
|
||||
result.(DataFlow::CallNode).getCalleeName() = "source" and
|
||||
start = result
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | t = t2.step(trackSource(t2, start), result))
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
result = CollectionsTypeTracking::collectionStep(trackSource(t2, start), t, t2)
|
||||
)
|
||||
}
|
||||
|
||||
query DataFlow::SourceNode typeTracking(DataFlow::Node start) {
|
||||
result = trackSource(DataFlow::TypeTracker::end(), start)
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
(function() {
|
||||
var source = source();
|
||||
var set = new Set();
|
||||
set.add(source);
|
||||
|
||||
for (const e of set) {
|
||||
sink(e); // NOT OK.
|
||||
}
|
||||
|
||||
set.forEach(e => {
|
||||
sink(e);
|
||||
})
|
||||
|
||||
var map = new Map();
|
||||
map.set("key", source);
|
||||
map.forEach(v => {
|
||||
sink(v);
|
||||
});
|
||||
|
||||
for (const [key, value] of map) {
|
||||
sink(value); // NOT OK.
|
||||
sink(key); // OK
|
||||
}
|
||||
|
||||
for (const value of map.values()) {
|
||||
sink(value); // NOT OK.
|
||||
}
|
||||
|
||||
for (const e of set.values()) {
|
||||
sink(e); // NOT OK
|
||||
}
|
||||
|
||||
for (const e of set.keys()) {
|
||||
sink(e); // NOT OK
|
||||
}
|
||||
|
||||
for (const e of new Set(set.keys())) {
|
||||
sink(e); // NOT OK
|
||||
}
|
||||
|
||||
for (const e of new Set([source])) {
|
||||
sink(e); // NOT OK (not caught by type-tracking, as it doesn't include array steps).
|
||||
}
|
||||
|
||||
for (const e of new Set(set)) {
|
||||
sink(e); // NOT OK
|
||||
}
|
||||
|
||||
for (const e of Array.from(set)) {
|
||||
sink(e); // NOT OK (not caught by type-tracking, as it doesn't include array steps).
|
||||
}
|
||||
|
||||
sink(map.get("key")); // NOT OK.
|
||||
sink(map.get("nonExistingKey")); // OK.
|
||||
|
||||
// unknown write, known read
|
||||
var map2 = new map();
|
||||
map2.set(unknown(), source);
|
||||
sink(map2.get("foo")); // NOT OK (for data-flow). OK for type-tracking.
|
||||
|
||||
// unknown write, unknown read
|
||||
var map3 = new map();
|
||||
map3.set(unknown(), source);
|
||||
sink(map3.get(unknown())); // NOT OK (for data-flow). OK for type-tracking.
|
||||
|
||||
// known write, unknown read
|
||||
var map4 = new map();
|
||||
map4.set("foo", source);
|
||||
sink(map3.get(unknown())); // NOT OK (for data-flow). OK for type-tracking.
|
||||
})();
|
||||
@@ -1,5 +1,13 @@
|
||||
| MisspelledVariableName.js:2:40:2:45 | lenght | 'lenght' may be a typo for variable $@. | MisspelledVariableName.js:2:19:2:24 | length | length |
|
||||
| tst.js:2:10:2:20 | errorMesage | 'errorMesage' may be a typo for variable $@. | tst.js:1:12:1:23 | errorMessage | errorMessage |
|
||||
| tst.js:6:10:6:21 | errorMessage | 'errorMessage' may be a typo for variable $@. | tst.js:5:12:5:22 | errorMesage | errorMesage |
|
||||
| tst.js:6:10:6:21 | errorMessage | $@ may be a typo for 'errorMessage'. | tst.js:5:12:5:22 | errorMesage | errorMesage |
|
||||
| tst.js:11:12:11:22 | errorMesage | 'errorMesage' may be a typo for variable $@. | tst.js:9:12:9:23 | errorMessage | errorMessage |
|
||||
| tst.js:17:5:17:16 | errorMessage | 'errorMessage' may be a typo for variable $@. | tst.js:15:12:15:22 | errorMesage | errorMesage |
|
||||
| tst.js:17:5:17:16 | errorMessage | $@ may be a typo for 'errorMessage'. | tst.js:15:12:15:22 | errorMesage | errorMesage |
|
||||
| tst.js:22:2:22:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander |
|
||||
| tst.js:23:2:23:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander |
|
||||
| tst.js:24:2:24:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander |
|
||||
| tst.js:25:2:25:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander |
|
||||
| tst.js:26:2:26:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander |
|
||||
| tst.js:27:2:27:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander |
|
||||
| tst.js:28:2:28:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander |
|
||||
| tst.js:29:2:29:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander |
|
||||
|
||||
@@ -16,3 +16,15 @@ function k(errorMesage) {
|
||||
let inner = () =>
|
||||
errorMessage;
|
||||
}
|
||||
|
||||
function foo() {
|
||||
var thisHander;
|
||||
thisHandler.foo1;
|
||||
thisHandler.foo2;
|
||||
thisHandler.foo3;
|
||||
thisHandler.foo4;
|
||||
thisHandler.foo5;
|
||||
thisHandler.foo6;
|
||||
thisHandler.foo7;
|
||||
thisHandler.foo8;
|
||||
}
|
||||
@@ -2082,6 +2082,92 @@ nodes
|
||||
| other-fs-libraries.js:24:35:24:38 | path |
|
||||
| other-fs-libraries.js:24:35:24:38 | path |
|
||||
| other-fs-libraries.js:24:35:24:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| tainted-require.js:7:19:7:37 | req.param("module") |
|
||||
| tainted-require.js:7:19:7:37 | req.param("module") |
|
||||
| tainted-require.js:7:19:7:37 | req.param("module") |
|
||||
@@ -5673,6 +5759,118 @@ edges
|
||||
| other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:9:14:9:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:9:14:9:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:9:14:9:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") |
|
||||
| tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") |
|
||||
| tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") |
|
||||
@@ -6572,6 +6770,7 @@ edges
|
||||
| other-fs-libraries.js:17:35:17:38 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:17:35:17:38 | path | This path depends on $@. | other-fs-libraries.js:9:24:9:30 | req.url | a user-provided value |
|
||||
| other-fs-libraries.js:19:56:19:59 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:19:56:19:59 | path | This path depends on $@. | other-fs-libraries.js:9:24:9:30 | req.url | a user-provided value |
|
||||
| other-fs-libraries.js:24:35:24:38 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:24:35:24:38 | path | This path depends on $@. | other-fs-libraries.js:9:24:9:30 | req.url | a user-provided value |
|
||||
| other-fs-libraries.js:40:35:40:38 | path | other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:40:35:40:38 | path | This path depends on $@. | other-fs-libraries.js:38:24:38:30 | req.url | a user-provided value |
|
||||
| tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value |
|
||||
| tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | a user-provided value |
|
||||
| tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | a user-provided value |
|
||||
|
||||
@@ -31,3 +31,11 @@ function getFsModule(special) {
|
||||
return require("original-fs");
|
||||
}
|
||||
}
|
||||
|
||||
var util = require("util");
|
||||
|
||||
http.createServer(function(req, res) {
|
||||
var path = url.parse(req.url, true).query.path;
|
||||
|
||||
util.promisify(fs.readFileSync)(path); // NOT OK
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user