Merge remote-tracking branch 'upstream/master' into XssDom

This commit is contained in:
Erik Krogh Kristensen
2020-04-22 10:20:40 +02:00
109 changed files with 4820 additions and 399 deletions

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View 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

View File

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

View 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

View 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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1 @@
| tst.ts:1:25:1:26 | -1 | -1 | -1 |

View File

@@ -0,0 +1,4 @@
import javascript
from NumberLiteralTypeExpr t
select t, t.getValue(), t.getIntValue()

View File

@@ -0,0 +1,3 @@
{
"include": ["."]
}

View File

@@ -0,0 +1 @@
type Foo<T> = T extends -1 ? true : false;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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