mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Merge branch 'main' into mathiasvp/read-step-without-memory-operands
This commit is contained in:
@@ -73,8 +73,20 @@ private predicate addressTakenVariable(StackVariable var) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is a stack-allocated reference-typed local variable. We don't
|
||||
* build SSA for such variables since they are likely to change values even
|
||||
* when not syntactically mentioned. For the same reason,
|
||||
* `addressTakenVariable` is used to prevent tracking variables that may be
|
||||
* aliased by such a reference.
|
||||
*
|
||||
* Reference-typed parameters are treated as if they weren't references.
|
||||
* That's because it's in practice highly unlikely that they alias other data
|
||||
* accessible from the function body.
|
||||
*/
|
||||
private predicate isReferenceVar(StackVariable v) {
|
||||
v.getUnspecifiedType() instanceof ReferenceType
|
||||
v.getUnspecifiedType() instanceof ReferenceType and
|
||||
not v instanceof Parameter
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -525,6 +525,19 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
inner = nodeTo.(InnerPartialDefinitionNode).getPreUpdateNode().asExpr() and
|
||||
outer = nodeFrom.(PartialDefinitionNode).getPreUpdateNode().asExpr()
|
||||
)
|
||||
or
|
||||
// Reverse flow: data that flows from the post-update node of a reference
|
||||
// returned by a function call, back into the qualifier of that function.
|
||||
// This allows data to flow 'in' through references returned by a modeled
|
||||
// function such as `operator[]`.
|
||||
exists(DataFlowFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
|
||||
call.getTarget() = f and
|
||||
inModel.isReturnValueDeref() and
|
||||
outModel.isQualifierObject() and
|
||||
f.hasDataFlow(inModel, outModel) and
|
||||
nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr() = call and
|
||||
nodeTo.asDefiningArgument() = call.getQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@ private import implementations.Fread
|
||||
private import implementations.Gets
|
||||
private import implementations.IdentityFunction
|
||||
private import implementations.Inet
|
||||
private import implementations.Iterator
|
||||
private import implementations.MemberFunction
|
||||
private import implementations.Memcpy
|
||||
private import implementations.Memset
|
||||
|
||||
273
cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll
Normal file
273
cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll
Normal file
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* Provides implementation classes modeling C++ iterators, including
|
||||
* `std::iterator`, `std::iterator_traits`, and types meeting the
|
||||
* `LegacyIterator` named requirement. See `semmle.code.cpp.models.Models` for
|
||||
* usage information.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.DataFlow
|
||||
|
||||
/**
|
||||
* An instantiation of the `std::iterator_traits` template.
|
||||
*/
|
||||
class IteratorTraits extends Class {
|
||||
IteratorTraits() {
|
||||
this.hasQualifiedName("std", "iterator_traits") and
|
||||
not this instanceof TemplateClass and
|
||||
exists(TypedefType t |
|
||||
this.getAMember() = t and
|
||||
t.getName() = "iterator_category"
|
||||
)
|
||||
}
|
||||
|
||||
Type getIteratorType() { result = this.getTemplateArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A type which has the typedefs expected for an iterator.
|
||||
*/
|
||||
class IteratorByTypedefs extends Class {
|
||||
IteratorByTypedefs() {
|
||||
this.getAMember().(TypedefType).hasName("difference_type") and
|
||||
this.getAMember().(TypedefType).hasName("value_type") and
|
||||
this.getAMember().(TypedefType).hasName("pointer") and
|
||||
this.getAMember().(TypedefType).hasName("reference") and
|
||||
this.getAMember().(TypedefType).hasName("iterator_category") and
|
||||
not this.hasQualifiedName("std", "iterator_traits")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::iterator` class.
|
||||
*/
|
||||
class StdIterator extends Class {
|
||||
StdIterator() { this.hasQualifiedName("std", "iterator") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A type which can be used as an iterator
|
||||
*/
|
||||
class Iterator extends Type {
|
||||
Iterator() {
|
||||
this instanceof IteratorByTypedefs or
|
||||
exists(IteratorTraits it | it.getIteratorType() = this) or
|
||||
this instanceof StdIterator
|
||||
}
|
||||
}
|
||||
|
||||
private FunctionInput getIteratorArgumentInput(Operator op, int index) {
|
||||
exists(Type t |
|
||||
t =
|
||||
op
|
||||
.getACallToThisFunction()
|
||||
.getArgument(index)
|
||||
.getExplicitlyConverted()
|
||||
.getType()
|
||||
.stripTopLevelSpecifiers()
|
||||
|
|
||||
(
|
||||
t instanceof Iterator or
|
||||
t.(ReferenceType).getBaseType() instanceof Iterator
|
||||
) and
|
||||
if op.getParameter(index).getUnspecifiedType() instanceof ReferenceType
|
||||
then result.isParameterDeref(index)
|
||||
else result.isParameter(index)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-member prefix `operator*` function for an iterator type.
|
||||
*/
|
||||
class IteratorPointerDereferenceOperator extends Operator, TaintFunction {
|
||||
FunctionInput iteratorInput;
|
||||
|
||||
IteratorPointerDereferenceOperator() {
|
||||
this.hasName("operator*") and
|
||||
iteratorInput = getIteratorArgumentInput(this, 0)
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = iteratorInput and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-member `operator++` or `operator--` function for an iterator type.
|
||||
*/
|
||||
class IteratorCrementOperator extends Operator, DataFlowFunction {
|
||||
FunctionInput iteratorInput;
|
||||
|
||||
IteratorCrementOperator() {
|
||||
this.hasName(["operator++", "operator--"]) and
|
||||
iteratorInput = getIteratorArgumentInput(this, 0)
|
||||
}
|
||||
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = iteratorInput and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-member `operator+` function for an iterator type.
|
||||
*/
|
||||
class IteratorAddOperator extends Operator, TaintFunction {
|
||||
FunctionInput iteratorInput;
|
||||
|
||||
IteratorAddOperator() {
|
||||
this.hasName("operator+") and
|
||||
iteratorInput = getIteratorArgumentInput(this, [0, 1])
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = iteratorInput and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-member `operator-` function that takes a pointer difference type as its second argument.
|
||||
*/
|
||||
class IteratorSubOperator extends Operator, TaintFunction {
|
||||
FunctionInput iteratorInput;
|
||||
|
||||
IteratorSubOperator() {
|
||||
this.hasName("operator-") and
|
||||
iteratorInput = getIteratorArgumentInput(this, 0) and
|
||||
this.getParameter(1).getUnspecifiedType() instanceof IntegralType // not an iterator difference
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = iteratorInput and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-member `operator+=` or `operator-=` function for an iterator type.
|
||||
*/
|
||||
class IteratorAssignArithmeticOperator extends Operator, DataFlowFunction, TaintFunction {
|
||||
IteratorAssignArithmeticOperator() {
|
||||
this.hasName(["operator+=", "operator-="]) and
|
||||
this.getDeclaringType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameter(0) and
|
||||
output.isReturnValue()
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameterDeref(1) and
|
||||
output.isParameterDeref(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A prefix `operator*` member function for an iterator type.
|
||||
*/
|
||||
class IteratorPointerDereferenceMemberOperator extends MemberFunction, TaintFunction {
|
||||
IteratorPointerDereferenceMemberOperator() {
|
||||
this.hasName("operator*") and
|
||||
this.getDeclaringType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An `operator++` or `operator--` member function for an iterator type.
|
||||
*/
|
||||
class IteratorCrementMemberOperator extends MemberFunction, DataFlowFunction, TaintFunction {
|
||||
IteratorCrementMemberOperator() {
|
||||
this.hasName(["operator++", "operator--"]) and
|
||||
this.getDeclaringType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierAddress() and
|
||||
output.isReturnValue()
|
||||
or
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A member `operator->` function for an iterator type.
|
||||
*/
|
||||
class IteratorFieldMemberOperator extends Operator, TaintFunction {
|
||||
IteratorFieldMemberOperator() {
|
||||
this.hasName("operator->") and
|
||||
this.getDeclaringType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An `operator+` or `operator-` member function of an iterator class.
|
||||
*/
|
||||
class IteratorBinaryArithmeticMemberOperator extends MemberFunction, TaintFunction {
|
||||
IteratorBinaryArithmeticMemberOperator() {
|
||||
this.hasName(["operator+", "operator-"]) and
|
||||
this.getDeclaringType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An `operator+=` or `operator-=` member function of an iterator class.
|
||||
*/
|
||||
class IteratorAssignArithmeticMemberOperator extends MemberFunction, DataFlowFunction, TaintFunction {
|
||||
IteratorAssignArithmeticMemberOperator() {
|
||||
this.hasName(["operator+=", "operator-="]) and
|
||||
this.getDeclaringType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierAddress() and
|
||||
output.isReturnValue()
|
||||
or
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An `operator[]` member function of an iterator class.
|
||||
*/
|
||||
class IteratorArrayMemberOperator extends MemberFunction, TaintFunction {
|
||||
IteratorArrayMemberOperator() {
|
||||
this.hasName("operator[]") and
|
||||
this.getDeclaringType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,11 @@
|
||||
/**
|
||||
* Provides implementation classes modeling `std::string` and other
|
||||
* instantiations of`std::basic_string`. See `semmle.code.cpp.models.Models`
|
||||
* for usage information.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.implementations.Iterator
|
||||
|
||||
/**
|
||||
* The `std::basic_string` template class.
|
||||
@@ -78,11 +85,17 @@ class StdStringAppend extends TaintFunction {
|
||||
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT`
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is an iterator.
|
||||
*/
|
||||
int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from string and parameter to string (qualifier) and return value
|
||||
(
|
||||
input.isQualifierObject() or
|
||||
input.isParameterDeref(getAStringParameterIndex())
|
||||
input.isParameterDeref(getAStringParameterIndex()) or
|
||||
input.isParameter(getAnIteratorParameterIndex())
|
||||
) and
|
||||
(
|
||||
output.isQualifierObject() or
|
||||
@@ -118,6 +131,28 @@ class StdStringAssign extends TaintFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard functions `std::string.begin` and `std::string.end` and their
|
||||
* variants.
|
||||
*/
|
||||
class StdStringBeginEnd extends TaintFunction {
|
||||
StdStringBeginEnd() {
|
||||
this.hasQualifiedName("std", "basic_string", "begin") or
|
||||
this.hasQualifiedName("std", "basic_string", "cbegin") or
|
||||
this.hasQualifiedName("std", "basic_string", "rbegin") or
|
||||
this.hasQualifiedName("std", "basic_string", "crbegin") or
|
||||
this.hasQualifiedName("std", "basic_string", "end") or
|
||||
this.hasQualifiedName("std", "basic_string", "cend") or
|
||||
this.hasQualifiedName("std", "basic_string", "rend") or
|
||||
this.hasQualifiedName("std", "basic_string", "crend")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard function `std::string.copy`.
|
||||
*/
|
||||
|
||||
@@ -191,6 +191,8 @@ private predicate linearAccessImpl(Expr expr, VariableAccess v, float p, float q
|
||||
// Base case
|
||||
expr = v and p = 1.0 and q = 0.0
|
||||
or
|
||||
expr.(ReferenceDereferenceExpr).getExpr() = v and p = 1.0 and q = 0.0
|
||||
or
|
||||
// a+(p*v+b) == p*v + (a+b)
|
||||
exists(AddExpr addExpr, float a, float b |
|
||||
addExpr.getLeftOperand().isConstant() and
|
||||
@@ -349,13 +351,20 @@ private predicate typeBounds(ArithmeticType t, float lb, float ub) {
|
||||
t instanceof FloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
|
||||
}
|
||||
|
||||
private Type stripReference(Type t) {
|
||||
if t instanceof ReferenceType then result = t.(ReferenceType).getBaseType() else result = t
|
||||
}
|
||||
|
||||
/** Gets the type used by range analysis for the given `StackVariable`. */
|
||||
Type getVariableRangeType(StackVariable v) { result = stripReference(v.getUnspecifiedType()) }
|
||||
|
||||
/**
|
||||
* Gets the lower bound for the unspecified type `t`.
|
||||
*
|
||||
* For example, if `t` is a signed 32-bit type then the result is
|
||||
* `-2^31`.
|
||||
*/
|
||||
float typeLowerBound(ArithmeticType t) { typeBounds(t, result, _) }
|
||||
float typeLowerBound(Type t) { typeBounds(stripReference(t), result, _) }
|
||||
|
||||
/**
|
||||
* Gets the upper bound for the unspecified type `t`.
|
||||
@@ -363,7 +372,7 @@ float typeLowerBound(ArithmeticType t) { typeBounds(t, result, _) }
|
||||
* For example, if `t` is a signed 32-bit type then the result is
|
||||
* `2^31 - 1`.
|
||||
*/
|
||||
float typeUpperBound(ArithmeticType t) { typeBounds(t, _, result) }
|
||||
float typeUpperBound(Type t) { typeBounds(stripReference(t), _, result) }
|
||||
|
||||
/**
|
||||
* Gets the minimum value that this expression could represent, based on
|
||||
|
||||
@@ -485,7 +485,7 @@ private predicate isRecursiveDef(RangeSsaDefinition def, StackVariable v) {
|
||||
* This predicate finds all the definitions in the first set.
|
||||
*/
|
||||
private predicate assignmentDef(RangeSsaDefinition def, StackVariable v, Expr expr) {
|
||||
v.getUnspecifiedType() instanceof ArithmeticType and
|
||||
getVariableRangeType(v) instanceof ArithmeticType and
|
||||
(
|
||||
def = v.getInitializer().getExpr() and def = expr
|
||||
or
|
||||
@@ -1329,7 +1329,7 @@ private float getDefLowerBounds(RangeSsaDefinition def, StackVariable v) {
|
||||
// recursion from exploding.
|
||||
result =
|
||||
max(float widenLB |
|
||||
widenLB = wideningLowerBounds(v.getUnspecifiedType()) and
|
||||
widenLB = wideningLowerBounds(getVariableRangeType(v)) and
|
||||
not widenLB > truncatedLB
|
||||
|
|
||||
widenLB
|
||||
@@ -1359,7 +1359,7 @@ private float getDefUpperBounds(RangeSsaDefinition def, StackVariable v) {
|
||||
// from exploding.
|
||||
result =
|
||||
min(float widenUB |
|
||||
widenUB = wideningUpperBounds(v.getUnspecifiedType()) and
|
||||
widenUB = wideningUpperBounds(getVariableRangeType(v)) and
|
||||
not widenUB < truncatedUB
|
||||
|
|
||||
widenUB
|
||||
@@ -1391,9 +1391,10 @@ private predicate unanalyzableDefBounds(RangeSsaDefinition def, StackVariable v,
|
||||
*/
|
||||
bindingset[guard, v, branch]
|
||||
predicate nonNanGuardedVariable(ComparisonOperation guard, VariableAccess v, boolean branch) {
|
||||
v.getUnspecifiedType() instanceof IntegralType
|
||||
getVariableRangeType(v.getTarget()) instanceof IntegralType
|
||||
or
|
||||
v.getUnspecifiedType() instanceof FloatingPointType and v instanceof NonNanVariableAccess
|
||||
getVariableRangeType(v.getTarget()) instanceof FloatingPointType and
|
||||
v instanceof NonNanVariableAccess
|
||||
or
|
||||
// The reason the following case is here is to ensure that when we say
|
||||
// `if (x > 5) { ...then... } else { ...else... }`
|
||||
@@ -1418,7 +1419,7 @@ private predicate lowerBoundFromGuard(
|
||||
then
|
||||
if
|
||||
strictness = Nonstrict() or
|
||||
not v.getUnspecifiedType() instanceof IntegralType
|
||||
not getVariableRangeType(v.getTarget()) instanceof IntegralType
|
||||
then lb = childLB
|
||||
else lb = childLB + 1
|
||||
else lb = varMinVal(v.getTarget())
|
||||
@@ -1440,7 +1441,7 @@ private predicate upperBoundFromGuard(
|
||||
then
|
||||
if
|
||||
strictness = Nonstrict() or
|
||||
not v.getUnspecifiedType() instanceof IntegralType
|
||||
not getVariableRangeType(v.getTarget()) instanceof IntegralType
|
||||
then ub = childUB
|
||||
else ub = childUB - 1
|
||||
else ub = varMaxVal(v.getTarget())
|
||||
|
||||
@@ -437,12 +437,34 @@
|
||||
| movableclass.cpp:65:13:65:18 | call to source | movableclass.cpp:65:13:65:20 | call to MyMovableClass | TAINT |
|
||||
| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:8:65:9 | ref arg s3 | TAINT |
|
||||
| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:11:65:11 | call to operator= | TAINT |
|
||||
| stl.h:139:30:139:40 | call to allocator | stl.h:139:21:139:41 | noexcept(...) | TAINT |
|
||||
| stl.h:139:30:139:40 | call to allocator | stl.h:139:21:139:41 | noexcept(...) | TAINT |
|
||||
| stl.h:139:30:139:40 | call to allocator | stl.h:139:21:139:41 | noexcept(...) | TAINT |
|
||||
| stl.h:139:30:139:40 | call to allocator | stl.h:139:21:139:41 | noexcept(...) | TAINT |
|
||||
| stl.h:139:30:139:40 | call to allocator | stl.h:139:21:139:41 | noexcept(...) | TAINT |
|
||||
| stl.h:139:53:139:63 | 0 | stl.h:139:46:139:64 | (no string representation) | TAINT |
|
||||
| standalone_iterators.cpp:39:45:39:51 | source1 | standalone_iterators.cpp:40:11:40:17 | source1 | |
|
||||
| standalone_iterators.cpp:39:45:39:51 | source1 | standalone_iterators.cpp:41:12:41:18 | source1 | |
|
||||
| standalone_iterators.cpp:39:45:39:51 | source1 | standalone_iterators.cpp:42:14:42:20 | source1 | |
|
||||
| standalone_iterators.cpp:40:11:40:17 | source1 | standalone_iterators.cpp:40:10:40:10 | call to operator* | TAINT |
|
||||
| standalone_iterators.cpp:41:12:41:18 | ref arg source1 | standalone_iterators.cpp:42:14:42:20 | source1 | |
|
||||
| standalone_iterators.cpp:41:12:41:18 | source1 | standalone_iterators.cpp:41:19:41:19 | call to operator++ | TAINT |
|
||||
| standalone_iterators.cpp:41:19:41:19 | call to operator++ | standalone_iterators.cpp:41:10:41:10 | call to operator* | TAINT |
|
||||
| standalone_iterators.cpp:42:12:42:12 | call to operator++ | standalone_iterators.cpp:42:10:42:10 | call to operator* | TAINT |
|
||||
| standalone_iterators.cpp:42:14:42:20 | source1 | standalone_iterators.cpp:42:12:42:12 | call to operator++ | TAINT |
|
||||
| standalone_iterators.cpp:45:39:45:45 | source1 | standalone_iterators.cpp:46:11:46:17 | source1 | |
|
||||
| standalone_iterators.cpp:45:39:45:45 | source1 | standalone_iterators.cpp:47:12:47:18 | source1 | |
|
||||
| standalone_iterators.cpp:45:39:45:45 | source1 | standalone_iterators.cpp:48:14:48:20 | source1 | |
|
||||
| standalone_iterators.cpp:46:11:46:17 | source1 | standalone_iterators.cpp:46:10:46:10 | call to operator* | TAINT |
|
||||
| standalone_iterators.cpp:47:12:47:18 | ref arg source1 | standalone_iterators.cpp:48:14:48:20 | source1 | |
|
||||
| standalone_iterators.cpp:47:12:47:18 | source1 | standalone_iterators.cpp:47:19:47:19 | call to operator++ | TAINT |
|
||||
| standalone_iterators.cpp:47:19:47:19 | call to operator++ | standalone_iterators.cpp:47:10:47:10 | call to operator* | TAINT |
|
||||
| standalone_iterators.cpp:48:12:48:12 | call to operator++ | standalone_iterators.cpp:48:10:48:10 | call to operator* | TAINT |
|
||||
| standalone_iterators.cpp:48:14:48:20 | source1 | standalone_iterators.cpp:48:12:48:12 | call to operator++ | TAINT |
|
||||
| standalone_iterators.cpp:51:37:51:43 | source1 | standalone_iterators.cpp:52:11:52:17 | source1 | |
|
||||
| standalone_iterators.cpp:51:37:51:43 | source1 | standalone_iterators.cpp:53:12:53:18 | source1 | |
|
||||
| standalone_iterators.cpp:51:37:51:43 | source1 | standalone_iterators.cpp:54:14:54:20 | source1 | |
|
||||
| standalone_iterators.cpp:53:12:53:18 | ref arg source1 | standalone_iterators.cpp:54:14:54:20 | source1 | |
|
||||
| stl.h:156:30:156:40 | call to allocator | stl.h:156:21:156:41 | noexcept(...) | TAINT |
|
||||
| stl.h:156:30:156:40 | call to allocator | stl.h:156:21:156:41 | noexcept(...) | TAINT |
|
||||
| stl.h:156:30:156:40 | call to allocator | stl.h:156:21:156:41 | noexcept(...) | TAINT |
|
||||
| stl.h:156:30:156:40 | call to allocator | stl.h:156:21:156:41 | noexcept(...) | TAINT |
|
||||
| stl.h:156:30:156:40 | call to allocator | stl.h:156:21:156:41 | noexcept(...) | TAINT |
|
||||
| stl.h:156:53:156:63 | 0 | stl.h:156:46:156:64 | (no string representation) | TAINT |
|
||||
| string.cpp:24:12:24:17 | call to source | string.cpp:28:7:28:7 | a | |
|
||||
| string.cpp:25:16:25:20 | 123 | string.cpp:25:16:25:21 | call to basic_string | TAINT |
|
||||
| string.cpp:25:16:25:21 | call to basic_string | string.cpp:29:7:29:7 | b | |
|
||||
@@ -503,6 +525,10 @@
|
||||
| string.cpp:119:16:119:24 | call to basic_string | string.cpp:124:33:124:33 | s | |
|
||||
| string.cpp:119:16:119:24 | call to basic_string | string.cpp:124:50:124:50 | s | |
|
||||
| string.cpp:119:16:119:24 | call to basic_string | string.cpp:128:16:128:16 | s | |
|
||||
| string.cpp:120:15:120:15 | (__begin) | string.cpp:120:15:120:15 | call to operator* | TAINT |
|
||||
| string.cpp:120:15:120:15 | (__begin) | string.cpp:120:15:120:15 | call to operator++ | TAINT |
|
||||
| string.cpp:120:15:120:15 | (__range) | string.cpp:120:15:120:15 | call to begin | TAINT |
|
||||
| string.cpp:120:15:120:15 | (__range) | string.cpp:120:15:120:15 | call to end | TAINT |
|
||||
| string.cpp:120:15:120:15 | call to begin | string.cpp:120:15:120:15 | (__begin) | |
|
||||
| string.cpp:120:15:120:15 | call to begin | string.cpp:120:15:120:15 | (__begin) | |
|
||||
| string.cpp:120:15:120:15 | call to begin | string.cpp:120:15:120:15 | (__begin) | |
|
||||
@@ -517,14 +543,22 @@
|
||||
| string.cpp:120:15:120:15 | s | string.cpp:120:15:120:15 | call to operator* | TAINT |
|
||||
| string.cpp:124:33:124:33 | ref arg s | string.cpp:124:50:124:50 | s | |
|
||||
| string.cpp:124:33:124:33 | ref arg s | string.cpp:128:16:128:16 | s | |
|
||||
| string.cpp:124:33:124:33 | s | string.cpp:124:35:124:39 | call to begin | TAINT |
|
||||
| string.cpp:124:35:124:39 | call to begin | string.cpp:124:44:124:45 | it | |
|
||||
| string.cpp:124:35:124:39 | call to begin | string.cpp:124:61:124:62 | it | |
|
||||
| string.cpp:124:35:124:39 | call to begin | string.cpp:125:9:125:10 | it | |
|
||||
| string.cpp:124:50:124:50 | ref arg s | string.cpp:124:50:124:50 | s | |
|
||||
| string.cpp:124:50:124:50 | ref arg s | string.cpp:128:16:128:16 | s | |
|
||||
| string.cpp:124:50:124:50 | s | string.cpp:124:52:124:54 | call to end | TAINT |
|
||||
| string.cpp:124:61:124:62 | it | string.cpp:124:59:124:59 | call to operator++ | TAINT |
|
||||
| string.cpp:124:61:124:62 | ref arg it | string.cpp:124:44:124:45 | it | |
|
||||
| string.cpp:124:61:124:62 | ref arg it | string.cpp:124:61:124:62 | it | |
|
||||
| string.cpp:124:61:124:62 | ref arg it | string.cpp:125:9:125:10 | it | |
|
||||
| string.cpp:125:9:125:10 | it | string.cpp:125:8:125:8 | call to operator* | TAINT |
|
||||
| string.cpp:128:16:128:16 | (__begin) | string.cpp:128:16:128:16 | call to operator* | TAINT |
|
||||
| string.cpp:128:16:128:16 | (__begin) | string.cpp:128:16:128:16 | call to operator++ | TAINT |
|
||||
| string.cpp:128:16:128:16 | (__range) | string.cpp:128:16:128:16 | call to begin | TAINT |
|
||||
| string.cpp:128:16:128:16 | (__range) | string.cpp:128:16:128:16 | call to end | TAINT |
|
||||
| string.cpp:128:16:128:16 | call to begin | string.cpp:128:16:128:16 | (__begin) | |
|
||||
| string.cpp:128:16:128:16 | call to begin | string.cpp:128:16:128:16 | (__begin) | |
|
||||
| string.cpp:128:16:128:16 | call to begin | string.cpp:128:16:128:16 | (__begin) | |
|
||||
@@ -539,6 +573,10 @@
|
||||
| string.cpp:128:16:128:16 | s | string.cpp:128:16:128:16 | call to operator* | TAINT |
|
||||
| string.cpp:132:28:132:33 | call to source | string.cpp:132:28:132:36 | call to basic_string | TAINT |
|
||||
| string.cpp:132:28:132:36 | call to basic_string | string.cpp:133:22:133:28 | const_s | |
|
||||
| string.cpp:133:22:133:22 | (__begin) | string.cpp:133:22:133:22 | call to operator* | TAINT |
|
||||
| string.cpp:133:22:133:22 | (__begin) | string.cpp:133:22:133:22 | call to operator++ | TAINT |
|
||||
| string.cpp:133:22:133:22 | (__range) | string.cpp:133:22:133:22 | call to begin | TAINT |
|
||||
| string.cpp:133:22:133:22 | (__range) | string.cpp:133:22:133:22 | call to end | TAINT |
|
||||
| string.cpp:133:22:133:22 | call to begin | string.cpp:133:22:133:22 | (__begin) | |
|
||||
| string.cpp:133:22:133:22 | call to begin | string.cpp:133:22:133:22 | (__begin) | |
|
||||
| string.cpp:133:22:133:22 | call to begin | string.cpp:133:22:133:22 | (__begin) | |
|
||||
@@ -857,6 +895,122 @@
|
||||
| string.cpp:348:13:348:13 | 1 | string.cpp:348:2:348:14 | access to array | TAINT |
|
||||
| string.cpp:348:18:348:32 | call to source | string.cpp:348:2:348:34 | ... = ... | |
|
||||
| string.cpp:350:7:350:9 | str | string.cpp:350:11:350:14 | call to data | TAINT |
|
||||
| string.cpp:355:18:355:24 | hello | string.cpp:355:18:355:25 | call to basic_string | TAINT |
|
||||
| string.cpp:355:18:355:25 | call to basic_string | string.cpp:360:8:360:9 | s1 | |
|
||||
| string.cpp:355:18:355:25 | call to basic_string | string.cpp:361:8:361:9 | s1 | |
|
||||
| string.cpp:355:18:355:25 | call to basic_string | string.cpp:362:8:362:9 | s1 | |
|
||||
| string.cpp:356:18:356:23 | call to source | string.cpp:356:18:356:26 | call to basic_string | TAINT |
|
||||
| string.cpp:356:18:356:26 | call to basic_string | string.cpp:361:18:361:19 | s2 | |
|
||||
| string.cpp:356:18:356:26 | call to basic_string | string.cpp:361:30:361:31 | s2 | |
|
||||
| string.cpp:357:18:357:24 | hello | string.cpp:357:18:357:25 | call to basic_string | TAINT |
|
||||
| string.cpp:357:18:357:25 | call to basic_string | string.cpp:364:8:364:9 | s3 | |
|
||||
| string.cpp:357:18:357:25 | call to basic_string | string.cpp:365:8:365:9 | s3 | |
|
||||
| string.cpp:357:18:357:25 | call to basic_string | string.cpp:366:8:366:9 | s3 | |
|
||||
| string.cpp:358:18:358:24 | world | string.cpp:358:18:358:25 | call to basic_string | TAINT |
|
||||
| string.cpp:358:18:358:25 | call to basic_string | string.cpp:365:18:365:19 | s4 | |
|
||||
| string.cpp:358:18:358:25 | call to basic_string | string.cpp:365:30:365:31 | s4 | |
|
||||
| string.cpp:361:8:361:9 | ref arg s1 | string.cpp:362:8:362:9 | s1 | |
|
||||
| string.cpp:361:8:361:9 | s1 | string.cpp:361:11:361:16 | call to append | TAINT |
|
||||
| string.cpp:361:18:361:19 | ref arg s2 | string.cpp:361:30:361:31 | s2 | |
|
||||
| string.cpp:361:18:361:19 | s2 | string.cpp:361:21:361:25 | call to begin | TAINT |
|
||||
| string.cpp:361:21:361:25 | call to begin | string.cpp:361:8:361:9 | ref arg s1 | TAINT |
|
||||
| string.cpp:361:21:361:25 | call to begin | string.cpp:361:11:361:16 | call to append | TAINT |
|
||||
| string.cpp:361:30:361:31 | s2 | string.cpp:361:33:361:35 | call to end | TAINT |
|
||||
| string.cpp:361:33:361:35 | call to end | string.cpp:361:8:361:9 | ref arg s1 | TAINT |
|
||||
| string.cpp:361:33:361:35 | call to end | string.cpp:361:11:361:16 | call to append | TAINT |
|
||||
| string.cpp:365:8:365:9 | ref arg s3 | string.cpp:366:8:366:9 | s3 | |
|
||||
| string.cpp:365:8:365:9 | s3 | string.cpp:365:11:365:16 | call to append | TAINT |
|
||||
| string.cpp:365:18:365:19 | ref arg s4 | string.cpp:365:30:365:31 | s4 | |
|
||||
| string.cpp:365:18:365:19 | s4 | string.cpp:365:21:365:25 | call to begin | TAINT |
|
||||
| string.cpp:365:21:365:25 | call to begin | string.cpp:365:8:365:9 | ref arg s3 | TAINT |
|
||||
| string.cpp:365:21:365:25 | call to begin | string.cpp:365:11:365:16 | call to append | TAINT |
|
||||
| string.cpp:365:30:365:31 | s4 | string.cpp:365:33:365:35 | call to end | TAINT |
|
||||
| string.cpp:365:33:365:35 | call to end | string.cpp:365:8:365:9 | ref arg s3 | TAINT |
|
||||
| string.cpp:365:33:365:35 | call to end | string.cpp:365:11:365:16 | call to append | TAINT |
|
||||
| string.cpp:371:18:371:24 | hello | string.cpp:371:18:371:25 | call to basic_string | TAINT |
|
||||
| string.cpp:371:18:371:25 | call to basic_string | string.cpp:374:28:374:29 | s1 | |
|
||||
| string.cpp:372:18:372:23 | call to source | string.cpp:372:18:372:26 | call to basic_string | TAINT |
|
||||
| string.cpp:372:18:372:26 | call to basic_string | string.cpp:378:28:378:29 | s2 | |
|
||||
| string.cpp:374:28:374:29 | s1 | string.cpp:374:31:374:35 | call to begin | TAINT |
|
||||
| string.cpp:374:31:374:35 | call to begin | string.cpp:376:9:376:13 | iter1 | |
|
||||
| string.cpp:374:31:374:35 | call to begin | string.cpp:377:8:377:12 | iter1 | |
|
||||
| string.cpp:376:9:376:13 | iter1 | string.cpp:376:8:376:8 | call to operator* | TAINT |
|
||||
| string.cpp:377:8:377:12 | iter1 | string.cpp:377:13:377:13 | call to operator[] | TAINT |
|
||||
| string.cpp:378:28:378:29 | s2 | string.cpp:378:31:378:35 | call to begin | TAINT |
|
||||
| string.cpp:378:31:378:35 | call to begin | string.cpp:380:9:380:13 | iter2 | |
|
||||
| string.cpp:378:31:378:35 | call to begin | string.cpp:381:8:381:12 | iter2 | |
|
||||
| string.cpp:380:9:380:13 | iter2 | string.cpp:380:8:380:8 | call to operator* | TAINT |
|
||||
| string.cpp:381:8:381:12 | iter2 | string.cpp:381:13:381:13 | call to operator[] | TAINT |
|
||||
| string.cpp:386:18:386:24 | hello | string.cpp:386:18:386:25 | call to basic_string | TAINT |
|
||||
| string.cpp:386:18:386:25 | call to basic_string | string.cpp:389:25:389:26 | s1 | |
|
||||
| string.cpp:387:18:387:23 | call to source | string.cpp:387:18:387:26 | call to basic_string | TAINT |
|
||||
| string.cpp:387:18:387:26 | call to basic_string | string.cpp:391:25:391:26 | s2 | |
|
||||
| string.cpp:387:18:387:26 | call to basic_string | string.cpp:411:8:411:9 | s2 | |
|
||||
| string.cpp:389:25:389:26 | s1 | string.cpp:389:28:389:32 | call to begin | TAINT |
|
||||
| string.cpp:391:25:391:26 | ref arg s2 | string.cpp:411:8:411:9 | s2 | |
|
||||
| string.cpp:391:25:391:26 | s2 | string.cpp:391:28:391:32 | call to begin | TAINT |
|
||||
| string.cpp:391:28:391:32 | call to begin | string.cpp:394:10:394:11 | i2 | |
|
||||
| string.cpp:391:28:391:32 | call to begin | string.cpp:395:10:395:11 | i2 | |
|
||||
| string.cpp:391:28:391:32 | call to begin | string.cpp:396:8:396:9 | i2 | |
|
||||
| string.cpp:391:28:391:32 | call to begin | string.cpp:398:8:398:9 | i2 | |
|
||||
| string.cpp:391:28:391:32 | call to begin | string.cpp:400:8:400:9 | i2 | |
|
||||
| string.cpp:391:28:391:32 | call to begin | string.cpp:403:8:403:9 | i2 | |
|
||||
| string.cpp:391:28:391:32 | call to begin | string.cpp:406:8:406:9 | i2 | |
|
||||
| string.cpp:391:28:391:32 | call to begin | string.cpp:408:8:408:9 | i2 | |
|
||||
| string.cpp:394:10:394:11 | i2 | string.cpp:394:12:394:12 | call to operator+ | TAINT |
|
||||
| string.cpp:394:10:394:11 | ref arg i2 | string.cpp:395:10:395:11 | i2 | |
|
||||
| string.cpp:394:10:394:11 | ref arg i2 | string.cpp:396:8:396:9 | i2 | |
|
||||
| string.cpp:394:10:394:11 | ref arg i2 | string.cpp:398:8:398:9 | i2 | |
|
||||
| string.cpp:394:10:394:11 | ref arg i2 | string.cpp:400:8:400:9 | i2 | |
|
||||
| string.cpp:394:10:394:11 | ref arg i2 | string.cpp:403:8:403:9 | i2 | |
|
||||
| string.cpp:394:10:394:11 | ref arg i2 | string.cpp:406:8:406:9 | i2 | |
|
||||
| string.cpp:394:10:394:11 | ref arg i2 | string.cpp:408:8:408:9 | i2 | |
|
||||
| string.cpp:394:12:394:12 | call to operator+ | string.cpp:394:8:394:8 | call to operator* | TAINT |
|
||||
| string.cpp:395:10:395:11 | i2 | string.cpp:395:12:395:12 | call to operator- | TAINT |
|
||||
| string.cpp:395:10:395:11 | ref arg i2 | string.cpp:396:8:396:9 | i2 | |
|
||||
| string.cpp:395:10:395:11 | ref arg i2 | string.cpp:398:8:398:9 | i2 | |
|
||||
| string.cpp:395:10:395:11 | ref arg i2 | string.cpp:400:8:400:9 | i2 | |
|
||||
| string.cpp:395:10:395:11 | ref arg i2 | string.cpp:403:8:403:9 | i2 | |
|
||||
| string.cpp:395:10:395:11 | ref arg i2 | string.cpp:406:8:406:9 | i2 | |
|
||||
| string.cpp:395:10:395:11 | ref arg i2 | string.cpp:408:8:408:9 | i2 | |
|
||||
| string.cpp:395:12:395:12 | call to operator- | string.cpp:395:8:395:8 | call to operator* | TAINT |
|
||||
| string.cpp:396:8:396:9 | i2 | string.cpp:396:3:396:9 | ... = ... | |
|
||||
| string.cpp:396:8:396:9 | i2 | string.cpp:397:12:397:13 | i3 | |
|
||||
| string.cpp:397:10:397:10 | call to operator++ | string.cpp:397:8:397:8 | call to operator* | TAINT |
|
||||
| string.cpp:397:12:397:13 | i3 | string.cpp:397:10:397:10 | call to operator++ | TAINT |
|
||||
| string.cpp:398:8:398:9 | i2 | string.cpp:398:3:398:9 | ... = ... | |
|
||||
| string.cpp:398:8:398:9 | i2 | string.cpp:399:12:399:13 | i4 | |
|
||||
| string.cpp:399:10:399:10 | call to operator-- | string.cpp:399:8:399:8 | call to operator* | TAINT |
|
||||
| string.cpp:399:12:399:13 | i4 | string.cpp:399:10:399:10 | call to operator-- | TAINT |
|
||||
| string.cpp:400:8:400:9 | i2 | string.cpp:400:3:400:9 | ... = ... | |
|
||||
| string.cpp:400:8:400:9 | i2 | string.cpp:401:3:401:4 | i5 | |
|
||||
| string.cpp:400:8:400:9 | i2 | string.cpp:402:9:402:10 | i5 | |
|
||||
| string.cpp:401:3:401:4 | i5 | string.cpp:401:5:401:5 | call to operator++ | TAINT |
|
||||
| string.cpp:401:3:401:4 | ref arg i5 | string.cpp:402:9:402:10 | i5 | |
|
||||
| string.cpp:402:9:402:10 | i5 | string.cpp:402:8:402:8 | call to operator* | TAINT |
|
||||
| string.cpp:403:8:403:9 | i2 | string.cpp:403:3:403:9 | ... = ... | |
|
||||
| string.cpp:403:8:403:9 | i2 | string.cpp:404:3:404:4 | i6 | |
|
||||
| string.cpp:403:8:403:9 | i2 | string.cpp:405:9:405:10 | i6 | |
|
||||
| string.cpp:404:3:404:4 | i6 | string.cpp:404:5:404:5 | call to operator-- | TAINT |
|
||||
| string.cpp:404:3:404:4 | ref arg i6 | string.cpp:405:9:405:10 | i6 | |
|
||||
| string.cpp:405:9:405:10 | i6 | string.cpp:405:8:405:8 | call to operator* | TAINT |
|
||||
| string.cpp:406:8:406:9 | i2 | string.cpp:406:3:406:9 | ... = ... | |
|
||||
| string.cpp:406:8:406:9 | i2 | string.cpp:407:10:407:11 | i7 | |
|
||||
| string.cpp:407:10:407:11 | i7 | string.cpp:407:12:407:12 | call to operator+= | TAINT |
|
||||
| string.cpp:407:12:407:12 | call to operator+= | string.cpp:407:8:407:8 | call to operator* | TAINT |
|
||||
| string.cpp:407:14:407:14 | 1 | string.cpp:407:12:407:12 | call to operator+= | |
|
||||
| string.cpp:408:8:408:9 | i2 | string.cpp:408:3:408:9 | ... = ... | |
|
||||
| string.cpp:408:8:408:9 | i2 | string.cpp:409:10:409:11 | i8 | |
|
||||
| string.cpp:409:10:409:11 | i8 | string.cpp:409:12:409:12 | call to operator-= | TAINT |
|
||||
| string.cpp:409:12:409:12 | call to operator-= | string.cpp:409:8:409:8 | call to operator* | TAINT |
|
||||
| string.cpp:409:14:409:14 | 1 | string.cpp:409:12:409:12 | call to operator-= | |
|
||||
| string.cpp:411:8:411:9 | s2 | string.cpp:411:11:411:13 | call to end | TAINT |
|
||||
| string.cpp:411:11:411:13 | call to end | string.cpp:411:3:411:15 | ... = ... | |
|
||||
| string.cpp:411:11:411:13 | call to end | string.cpp:412:5:412:6 | i9 | |
|
||||
| string.cpp:411:11:411:13 | call to end | string.cpp:413:9:413:10 | i9 | |
|
||||
| string.cpp:412:5:412:6 | i9 | string.cpp:412:3:412:3 | call to operator-- | TAINT |
|
||||
| string.cpp:412:5:412:6 | ref arg i9 | string.cpp:413:9:413:10 | i9 | |
|
||||
| string.cpp:413:9:413:10 | i9 | string.cpp:413:8:413:8 | call to operator* | TAINT |
|
||||
| stringstream.cpp:13:20:13:22 | call to basic_stringstream | stringstream.cpp:16:2:16:4 | ss1 | |
|
||||
| stringstream.cpp:13:20:13:22 | call to basic_stringstream | stringstream.cpp:22:7:22:9 | ss1 | |
|
||||
| stringstream.cpp:13:20:13:22 | call to basic_stringstream | stringstream.cpp:27:7:27:9 | ss1 | |
|
||||
@@ -1718,6 +1872,8 @@
|
||||
| vector.cpp:17:21:17:33 | call to vector | vector.cpp:27:15:27:15 | v | |
|
||||
| vector.cpp:17:21:17:33 | call to vector | vector.cpp:35:1:35:1 | v | |
|
||||
| vector.cpp:17:26:17:32 | source1 | vector.cpp:17:21:17:33 | call to vector | TAINT |
|
||||
| vector.cpp:19:14:19:14 | (__begin) | vector.cpp:19:14:19:14 | call to operator* | TAINT |
|
||||
| vector.cpp:19:14:19:14 | (__begin) | vector.cpp:19:14:19:14 | call to operator++ | TAINT |
|
||||
| vector.cpp:19:14:19:14 | call to begin | vector.cpp:19:14:19:14 | (__begin) | |
|
||||
| vector.cpp:19:14:19:14 | call to begin | vector.cpp:19:14:19:14 | (__begin) | |
|
||||
| vector.cpp:19:14:19:14 | call to begin | vector.cpp:19:14:19:14 | (__begin) | |
|
||||
@@ -1739,9 +1895,13 @@
|
||||
| vector.cpp:23:55:23:55 | ref arg v | vector.cpp:23:55:23:55 | v | |
|
||||
| vector.cpp:23:55:23:55 | ref arg v | vector.cpp:27:15:27:15 | v | |
|
||||
| vector.cpp:23:55:23:55 | ref arg v | vector.cpp:35:1:35:1 | v | |
|
||||
| vector.cpp:23:66:23:67 | it | vector.cpp:23:64:23:64 | call to operator++ | TAINT |
|
||||
| vector.cpp:23:66:23:67 | ref arg it | vector.cpp:23:49:23:50 | it | |
|
||||
| vector.cpp:23:66:23:67 | ref arg it | vector.cpp:23:66:23:67 | it | |
|
||||
| vector.cpp:23:66:23:67 | ref arg it | vector.cpp:24:9:24:10 | it | |
|
||||
| vector.cpp:24:9:24:10 | it | vector.cpp:24:8:24:8 | call to operator* | TAINT |
|
||||
| vector.cpp:27:15:27:15 | (__begin) | vector.cpp:27:15:27:15 | call to operator* | TAINT |
|
||||
| vector.cpp:27:15:27:15 | (__begin) | vector.cpp:27:15:27:15 | call to operator++ | TAINT |
|
||||
| vector.cpp:27:15:27:15 | call to begin | vector.cpp:27:15:27:15 | (__begin) | |
|
||||
| vector.cpp:27:15:27:15 | call to begin | vector.cpp:27:15:27:15 | (__begin) | |
|
||||
| vector.cpp:27:15:27:15 | call to begin | vector.cpp:27:15:27:15 | (__begin) | |
|
||||
@@ -1757,6 +1917,8 @@
|
||||
| vector.cpp:31:33:31:45 | call to vector | vector.cpp:32:21:32:27 | const_v | |
|
||||
| vector.cpp:31:33:31:45 | call to vector | vector.cpp:35:1:35:1 | const_v | |
|
||||
| vector.cpp:31:38:31:44 | source1 | vector.cpp:31:33:31:45 | call to vector | TAINT |
|
||||
| vector.cpp:32:21:32:21 | (__begin) | vector.cpp:32:21:32:21 | call to operator* | TAINT |
|
||||
| vector.cpp:32:21:32:21 | (__begin) | vector.cpp:32:21:32:21 | call to operator++ | TAINT |
|
||||
| vector.cpp:32:21:32:21 | call to begin | vector.cpp:32:21:32:21 | (__begin) | |
|
||||
| vector.cpp:32:21:32:21 | call to begin | vector.cpp:32:21:32:21 | (__begin) | |
|
||||
| vector.cpp:32:21:32:21 | call to begin | vector.cpp:32:21:32:21 | (__begin) | |
|
||||
@@ -2415,6 +2577,7 @@
|
||||
| vector.cpp:251:11:251:15 | call to begin | vector.cpp:253:8:253:9 | i1 | |
|
||||
| vector.cpp:251:11:251:15 | call to begin | vector.cpp:255:13:255:14 | i1 | |
|
||||
| vector.cpp:251:11:251:15 | call to begin | vector.cpp:259:8:259:9 | i1 | |
|
||||
| vector.cpp:252:3:252:4 | i1 | vector.cpp:252:5:252:5 | call to operator++ | TAINT |
|
||||
| vector.cpp:252:3:252:4 | ref arg i1 | vector.cpp:253:8:253:9 | i1 | |
|
||||
| vector.cpp:252:3:252:4 | ref arg i1 | vector.cpp:255:13:255:14 | i1 | |
|
||||
| vector.cpp:252:3:252:4 | ref arg i1 | vector.cpp:259:8:259:9 | i1 | |
|
||||
@@ -2422,6 +2585,7 @@
|
||||
| vector.cpp:253:8:253:9 | i1 | vector.cpp:254:3:254:4 | i2 | |
|
||||
| vector.cpp:253:8:253:9 | i1 | vector.cpp:255:17:255:18 | i2 | |
|
||||
| vector.cpp:253:8:253:9 | i1 | vector.cpp:260:8:260:9 | i2 | |
|
||||
| vector.cpp:254:3:254:4 | i2 | vector.cpp:254:5:254:5 | call to operator++ | TAINT |
|
||||
| vector.cpp:254:3:254:4 | ref arg i2 | vector.cpp:255:17:255:18 | i2 | |
|
||||
| vector.cpp:254:3:254:4 | ref arg i2 | vector.cpp:260:8:260:9 | i2 | |
|
||||
| vector.cpp:255:3:255:4 | ref arg v6 | vector.cpp:261:8:261:9 | v6 | |
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
#include "stl.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void sink(int);
|
||||
|
||||
class int_iterator_by_typedefs {
|
||||
public:
|
||||
typedef input_iterator_tag iterator_category;
|
||||
typedef int value_type;
|
||||
typedef size_t difference_type;
|
||||
typedef int * pointer;
|
||||
typedef int & reference;
|
||||
|
||||
int_iterator_by_typedefs &operator++();
|
||||
int_iterator_by_typedefs operator++(int);
|
||||
int operator*() const;
|
||||
};
|
||||
|
||||
class int_iterator_by_trait {
|
||||
public:
|
||||
int_iterator_by_trait &operator++();
|
||||
int_iterator_by_trait operator++(int);
|
||||
int operator*() const;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct std::iterator_traits<int_iterator_by_trait> {
|
||||
typedef input_iterator_tag iterator_category;
|
||||
};
|
||||
|
||||
class non_iterator {
|
||||
public:
|
||||
non_iterator &operator++();
|
||||
non_iterator operator++(int);
|
||||
int operator*() const;
|
||||
};
|
||||
|
||||
void test_typedefs(int_iterator_by_typedefs source1) {
|
||||
sink(*source1);
|
||||
sink(*(source1++));
|
||||
sink(*(++source1));
|
||||
}
|
||||
|
||||
void test_trait(int_iterator_by_trait source1) {
|
||||
sink(*source1);
|
||||
sink(*(source1++));
|
||||
sink(*(++source1));
|
||||
}
|
||||
|
||||
void test_non_iterator(non_iterator source1) {
|
||||
sink(*source1);
|
||||
sink(*(source1++));
|
||||
sink(*(++source1));
|
||||
}
|
||||
@@ -1,16 +1,13 @@
|
||||
|
||||
typedef unsigned long size_t;
|
||||
|
||||
// --- string ---
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<class charT> struct char_traits;
|
||||
|
||||
typedef size_t streamsize;
|
||||
// --- iterator ---
|
||||
|
||||
namespace std {
|
||||
struct ptrdiff_t;
|
||||
|
||||
template<class I> struct iterator_traits;
|
||||
|
||||
template <class Category,
|
||||
class value_type,
|
||||
class difference_type = ptrdiff_t,
|
||||
@@ -21,15 +18,33 @@ namespace std
|
||||
|
||||
iterator &operator++();
|
||||
iterator operator++(int);
|
||||
iterator &operator--();
|
||||
iterator operator--(int);
|
||||
bool operator==(iterator other) const;
|
||||
bool operator!=(iterator other) const;
|
||||
reference_type operator*() const;
|
||||
iterator operator+(int);
|
||||
iterator operator-(int);
|
||||
iterator &operator+=(int);
|
||||
iterator &operator-=(int);
|
||||
int operator-(iterator);
|
||||
reference_type operator[](int);
|
||||
};
|
||||
|
||||
struct input_iterator_tag {};
|
||||
struct forward_iterator_tag : public input_iterator_tag {};
|
||||
struct bidirectional_iterator_tag : public forward_iterator_tag {};
|
||||
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
|
||||
}
|
||||
|
||||
// --- string ---
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<class charT> struct char_traits;
|
||||
|
||||
typedef size_t streamsize;
|
||||
|
||||
|
||||
template <class T> class allocator {
|
||||
public:
|
||||
@@ -72,6 +87,8 @@ namespace std
|
||||
basic_string& append(const basic_string& str);
|
||||
basic_string& append(const charT* s);
|
||||
basic_string& append(size_type n, charT c);
|
||||
template<class InputIterator>
|
||||
/* constexpr */ basic_string& append(InputIterator first, InputIterator last);
|
||||
basic_string& assign(const basic_string& str);
|
||||
basic_string& assign(size_type n, charT c);
|
||||
basic_string& insert(size_type pos, const basic_string& str);
|
||||
|
||||
@@ -122,7 +122,7 @@ void test_range_based_for_loop_string() {
|
||||
}
|
||||
|
||||
for(std::string::iterator it = s.begin(); it != s.end(); ++it) {
|
||||
sink(*it); // tainted [NOT DETECTED]
|
||||
sink(*it); // tainted [NOT DETECTED by IR]
|
||||
}
|
||||
|
||||
for(char& c : s) {
|
||||
@@ -349,3 +349,67 @@ void test_string_data_more()
|
||||
sink(str); // tainted
|
||||
sink(str.data()); // tainted
|
||||
}
|
||||
void test_string_iterators() {
|
||||
// string append
|
||||
{
|
||||
std::string s1("hello");
|
||||
std::string s2(source());
|
||||
std::string s3("hello");
|
||||
std::string s4("world");
|
||||
|
||||
sink(s1);
|
||||
sink(s1.append(s2.begin(), s2.end())); // tainted
|
||||
sink(s1); // tainted
|
||||
|
||||
sink(s3);
|
||||
sink(s3.append(s4.begin(), s4.end()));
|
||||
sink(s3);
|
||||
}
|
||||
|
||||
// dereference
|
||||
{
|
||||
std::string s1("hello");
|
||||
std::string s2(source());
|
||||
|
||||
string::iterator iter1 = s1.begin();
|
||||
|
||||
sink(*iter1);
|
||||
sink(iter1[1]);
|
||||
string::iterator iter2 = s2.begin();
|
||||
|
||||
sink(*iter2); // tainted
|
||||
sink(iter2[1]); // tainted
|
||||
}
|
||||
|
||||
// arithmetic operators
|
||||
{
|
||||
std::string s1("hello");
|
||||
std::string s2(source());
|
||||
|
||||
string::iterator i1 = s1.begin();
|
||||
|
||||
string::iterator i2 = s2.begin();
|
||||
string::iterator i3, i4, i5, i6, i7, i8, i9;
|
||||
|
||||
sink(*(i2+1)); //tainted
|
||||
sink(*(i2-1)); // tainted
|
||||
i3 = i2;
|
||||
sink(*(++i3)); // tainted
|
||||
i4 = i2;
|
||||
sink(*(--i4)); // tainted
|
||||
i5 = i2;
|
||||
i5++;
|
||||
sink(*i5); // tainted
|
||||
i6 = i2;
|
||||
i6--;
|
||||
sink(*i6); // tainted
|
||||
i7 = i2;
|
||||
sink(*(i7+=1)); // tainted
|
||||
i8 = i2;
|
||||
sink(*(i8-=1)); // tainted
|
||||
|
||||
i9 = s2.end();
|
||||
--i9;
|
||||
sink(*i9); // tainted
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,12 @@
|
||||
| movableclass.cpp:55:8:55:9 | s2 | movableclass.cpp:52:23:52:28 | call to source |
|
||||
| movableclass.cpp:64:8:64:9 | s2 | movableclass.cpp:23:55:23:60 | call to source |
|
||||
| movableclass.cpp:65:11:65:11 | call to operator= | movableclass.cpp:65:13:65:18 | call to source |
|
||||
| standalone_iterators.cpp:40:10:40:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 |
|
||||
| standalone_iterators.cpp:41:10:41:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 |
|
||||
| standalone_iterators.cpp:42:10:42:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 |
|
||||
| standalone_iterators.cpp:46:10:46:10 | call to operator* | standalone_iterators.cpp:45:39:45:45 | source1 |
|
||||
| standalone_iterators.cpp:47:10:47:10 | call to operator* | standalone_iterators.cpp:45:39:45:45 | source1 |
|
||||
| standalone_iterators.cpp:48:10:48:10 | call to operator* | standalone_iterators.cpp:45:39:45:45 | source1 |
|
||||
| string.cpp:28:7:28:7 | a | string.cpp:24:12:24:17 | call to source |
|
||||
| string.cpp:30:7:30:7 | c | string.cpp:26:16:26:21 | call to source |
|
||||
| string.cpp:32:9:32:13 | call to c_str | string.cpp:26:16:26:21 | call to source |
|
||||
@@ -53,6 +59,7 @@
|
||||
| string.cpp:113:8:113:9 | s1 | string.cpp:109:32:109:37 | call to source |
|
||||
| string.cpp:114:8:114:9 | s2 | string.cpp:111:20:111:25 | call to source |
|
||||
| string.cpp:121:8:121:8 | c | string.cpp:119:16:119:21 | call to source |
|
||||
| string.cpp:125:8:125:8 | call to operator* | string.cpp:119:16:119:21 | call to source |
|
||||
| string.cpp:129:8:129:8 | c | string.cpp:119:16:119:21 | call to source |
|
||||
| string.cpp:134:8:134:8 | c | string.cpp:132:28:132:33 | call to source |
|
||||
| string.cpp:144:11:144:11 | call to operator+ | string.cpp:141:18:141:23 | call to source |
|
||||
@@ -101,6 +108,19 @@
|
||||
| string.cpp:341:7:341:7 | c | string.cpp:335:9:335:23 | call to source |
|
||||
| string.cpp:349:7:349:9 | str | string.cpp:348:18:348:32 | call to source |
|
||||
| string.cpp:350:11:350:14 | call to data | string.cpp:348:18:348:32 | call to source |
|
||||
| string.cpp:361:11:361:16 | call to append | string.cpp:356:18:356:23 | call to source |
|
||||
| string.cpp:362:8:362:9 | s1 | string.cpp:356:18:356:23 | call to source |
|
||||
| string.cpp:380:8:380:8 | call to operator* | string.cpp:372:18:372:23 | call to source |
|
||||
| string.cpp:381:13:381:13 | call to operator[] | string.cpp:372:18:372:23 | call to source |
|
||||
| string.cpp:394:8:394:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:395:8:395:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:397:8:397:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:399:8:399:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:402:8:402:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:405:8:405:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:407:8:407:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:409:8:409:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:413:8:413:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| structlikeclass.cpp:35:8:35:9 | s1 | structlikeclass.cpp:29:22:29:27 | call to source |
|
||||
| structlikeclass.cpp:36:8:36:9 | s2 | structlikeclass.cpp:30:24:30:29 | call to source |
|
||||
| structlikeclass.cpp:37:8:37:9 | s3 | structlikeclass.cpp:29:22:29:27 | call to source |
|
||||
|
||||
@@ -38,6 +38,12 @@
|
||||
| format.cpp:115:8:115:13 | format.cpp:114:37:114:50 | AST only |
|
||||
| movableclass.cpp:65:11:65:11 | movableclass.cpp:65:13:65:18 | AST only |
|
||||
| movableclass.cpp:65:11:65:21 | movableclass.cpp:65:13:65:18 | IR only |
|
||||
| standalone_iterators.cpp:40:10:40:10 | standalone_iterators.cpp:39:45:39:51 | AST only |
|
||||
| standalone_iterators.cpp:41:10:41:10 | standalone_iterators.cpp:39:45:39:51 | AST only |
|
||||
| standalone_iterators.cpp:42:10:42:10 | standalone_iterators.cpp:39:45:39:51 | AST only |
|
||||
| standalone_iterators.cpp:46:10:46:10 | standalone_iterators.cpp:45:39:45:45 | AST only |
|
||||
| standalone_iterators.cpp:47:10:47:10 | standalone_iterators.cpp:45:39:45:45 | AST only |
|
||||
| standalone_iterators.cpp:48:10:48:10 | standalone_iterators.cpp:45:39:45:45 | AST only |
|
||||
| string.cpp:30:7:30:7 | string.cpp:26:16:26:21 | AST only |
|
||||
| string.cpp:32:9:32:13 | string.cpp:26:16:26:21 | AST only |
|
||||
| string.cpp:38:13:38:17 | string.cpp:14:10:14:15 | AST only |
|
||||
@@ -53,6 +59,7 @@
|
||||
| string.cpp:113:8:113:9 | string.cpp:109:32:109:37 | AST only |
|
||||
| string.cpp:114:8:114:9 | string.cpp:111:20:111:25 | AST only |
|
||||
| string.cpp:121:8:121:8 | string.cpp:119:16:119:21 | AST only |
|
||||
| string.cpp:125:8:125:8 | string.cpp:119:16:119:21 | AST only |
|
||||
| string.cpp:129:8:129:8 | string.cpp:119:16:119:21 | AST only |
|
||||
| string.cpp:134:8:134:8 | string.cpp:132:28:132:33 | AST only |
|
||||
| string.cpp:144:11:144:11 | string.cpp:141:18:141:23 | AST only |
|
||||
@@ -101,6 +108,19 @@
|
||||
| string.cpp:341:7:341:7 | string.cpp:335:9:335:23 | AST only |
|
||||
| string.cpp:349:7:349:9 | string.cpp:348:18:348:32 | AST only |
|
||||
| string.cpp:350:11:350:14 | string.cpp:348:18:348:32 | AST only |
|
||||
| string.cpp:361:11:361:16 | string.cpp:356:18:356:23 | AST only |
|
||||
| string.cpp:362:8:362:9 | string.cpp:356:18:356:23 | AST only |
|
||||
| string.cpp:380:8:380:8 | string.cpp:372:18:372:23 | AST only |
|
||||
| string.cpp:381:13:381:13 | string.cpp:372:18:372:23 | AST only |
|
||||
| string.cpp:394:8:394:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:395:8:395:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:397:8:397:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:399:8:399:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:402:8:402:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:405:8:405:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:407:8:407:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:409:8:409:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:413:8:413:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| swap1.cpp:78:12:78:16 | swap1.cpp:69:23:69:23 | AST only |
|
||||
| swap1.cpp:87:13:87:17 | swap1.cpp:82:16:82:21 | AST only |
|
||||
| swap1.cpp:88:13:88:17 | swap1.cpp:81:27:81:28 | AST only |
|
||||
|
||||
@@ -573,3 +573,15 @@
|
||||
| test.cpp:75:22:75:30 | c_times_2 | 0 |
|
||||
| test.cpp:77:5:77:13 | c_times_2 | 0 |
|
||||
| test.cpp:79:3:79:11 | c_times_2 | 0 |
|
||||
| test.cpp:83:16:83:22 | aliased | -2147483648 |
|
||||
| test.cpp:85:7:85:7 | i | -2147483648 |
|
||||
| test.cpp:86:12:86:12 | i | 2 |
|
||||
| test.cpp:88:7:88:8 | ci | -2147483648 |
|
||||
| test.cpp:89:12:89:13 | ci | 2 |
|
||||
| test.cpp:91:7:91:13 | aliased | -2147483648 |
|
||||
| test.cpp:92:12:92:18 | aliased | -2147483648 |
|
||||
| test.cpp:94:7:94:11 | alias | -2147483648 |
|
||||
| test.cpp:95:12:95:16 | alias | -2147483648 |
|
||||
| test.cpp:97:10:97:10 | i | -2147483648 |
|
||||
| test.cpp:97:22:97:22 | i | -2147483648 |
|
||||
| test.cpp:98:5:98:5 | i | -2147483648 |
|
||||
|
||||
@@ -78,3 +78,25 @@ void use_after_cast(unsigned char c)
|
||||
}
|
||||
c_times_2;
|
||||
}
|
||||
|
||||
int ref_to_number(int &i, const int &ci, int &aliased) {
|
||||
int &alias = aliased; // no range analysis for either of the two aliased variables
|
||||
|
||||
if (i >= 2)
|
||||
return i;
|
||||
|
||||
if (ci >= 2)
|
||||
return ci;
|
||||
|
||||
if (aliased >= 2)
|
||||
return aliased;
|
||||
|
||||
if (alias >= 2)
|
||||
return alias;
|
||||
|
||||
for (; i <= 12345; i++) { // test that widening works for references
|
||||
i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -573,3 +573,15 @@
|
||||
| test.cpp:75:22:75:30 | c_times_2 | 510 |
|
||||
| test.cpp:77:5:77:13 | c_times_2 | 510 |
|
||||
| test.cpp:79:3:79:11 | c_times_2 | 510 |
|
||||
| test.cpp:83:16:83:22 | aliased | 2147483647 |
|
||||
| test.cpp:85:7:85:7 | i | 2147483647 |
|
||||
| test.cpp:86:12:86:12 | i | 2147483647 |
|
||||
| test.cpp:88:7:88:8 | ci | 2147483647 |
|
||||
| test.cpp:89:12:89:13 | ci | 2147483647 |
|
||||
| test.cpp:91:7:91:13 | aliased | 2147483647 |
|
||||
| test.cpp:92:12:92:18 | aliased | 2147483647 |
|
||||
| test.cpp:94:7:94:11 | alias | 2147483647 |
|
||||
| test.cpp:95:12:95:16 | alias | 2147483647 |
|
||||
| test.cpp:97:10:97:10 | i | 65535 |
|
||||
| test.cpp:97:22:97:22 | i | 32767 |
|
||||
| test.cpp:98:5:98:5 | i | 32767 |
|
||||
|
||||
@@ -4,6 +4,22 @@ import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.QueryInjection
|
||||
|
||||
/** A sink for MongoDB injection vulnerabilities. */
|
||||
class MongoDbInjectionSink extends QueryInjectionSink {
|
||||
MongoDbInjectionSink() {
|
||||
exists(MethodAccess call |
|
||||
call.getMethod().getDeclaringType().hasQualifiedName("com.mongodb", "BasicDBObject") and
|
||||
call.getMethod().hasName("parse") and
|
||||
this.asExpr() = call.getArgument(0)
|
||||
)
|
||||
or
|
||||
exists(CastExpr c |
|
||||
c.getExpr() = this.asExpr() and
|
||||
c.getTypeExpr().getType().(RefType).hasQualifiedName("com.mongodb", "DBObject")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class QueryInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
QueryInjectionFlowConfig() { this = "SqlInjectionLib::QueryInjectionFlowConfig" }
|
||||
|
||||
@@ -16,6 +32,10 @@ private class QueryInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
node.getType() instanceof BoxedType or
|
||||
node.getType() instanceof NumberType
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
mongoJsonStep(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -27,3 +47,12 @@ predicate queryTaintedBy(
|
||||
) {
|
||||
exists(QueryInjectionFlowConfig conf | conf.hasFlowPath(source, sink) and sink.getNode() = query)
|
||||
}
|
||||
|
||||
predicate mongoJsonStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod().getDeclaringType().hasQualifiedName("com.mongodb.util", "JSON") and
|
||||
ma.getMethod().hasName("parse") and
|
||||
ma.getArgument(0) = node1.asExpr() and
|
||||
ma = node2.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@ class LocalUserInputToQueryInjectionFlowConfig extends TaintTracking::Configurat
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
mongoJsonStep(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
from
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
public void transform(Socket socket, String inputXml) throws Exception {
|
||||
StreamSource xslt = new StreamSource(socket.getInputStream());
|
||||
StreamSource xml = new StreamSource(new StringReader(inputXml));
|
||||
StringWriter result = new StringWriter();
|
||||
TransformerFactory factory = TransformerFactory.newInstance();
|
||||
|
||||
// BAD: User provided XSLT stylesheet is processed
|
||||
factory.newTransformer(xslt).transform(xml, new StreamResult(result));
|
||||
|
||||
// GOOD: The secure processing mode is enabled
|
||||
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||
factory.newTransformer(xslt).transform(xml, new StreamResult(result));
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>XSLT (Extensible Stylesheet Language Transformations) is a language for transforming XML
|
||||
documents into other XML documents or other formats. Processing of unvalidated XSLT stylesheet can
|
||||
let attacker to read arbitrary files from the filesystem or to execute arbitrary code.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>The general recommendation is to not process untrusted XSLT stylesheets. If user provided
|
||||
stylesheets must be processed, enable the secure processing mode.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>In the following examples, the code accepts an XSLT stylesheet from the user and processes it.
|
||||
</p>
|
||||
|
||||
<p>In the first example, the user provided XSLT stylesheet is parsed and processed.</p>
|
||||
|
||||
<p>In the second example, secure processing mode is enabled.</p>
|
||||
|
||||
<sample src="XsltInjection.java" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/XSLT">XSLT</a>.</li>
|
||||
<li>Java Tutorial: <a href="https://docs.oracle.com/javase/tutorial/jaxp/xslt/transformingXML.html">Transforming XML Data with XSLT</a>.</li>
|
||||
<li><a href="https://blog.hunniccyber.com/ektron-cms-remote-code-execution-xslt-transform-injection-java/">XSLT Injection Basics</a>.</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @name XSLT transformation with user-controlled stylesheet
|
||||
* @description Doing an XSLT transformation with user-controlled stylesheet can lead to
|
||||
* information disclosure or execution of arbitrary code.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id java/xslt-injection
|
||||
* @tags security
|
||||
* external/cwe/cwe-074
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import XsltInjectionLib
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, XsltInjectionFlowConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "XSLT transformation might include stylesheet from $@.",
|
||||
source.getNode(), "this user input"
|
||||
@@ -0,0 +1,288 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.XmlParsers
|
||||
import DataFlow
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unvalidated user input that is used in XSLT transformation.
|
||||
*/
|
||||
class XsltInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
XsltInjectionFlowConfig() { this = "XsltInjectionFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof XsltInjectionSink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
xmlStreamReaderStep(node1, node2) or
|
||||
xmlEventReaderStep(node1, node2) or
|
||||
staxSourceStep(node1, node2) or
|
||||
documentBuilderStep(node1, node2) or
|
||||
domSourceStep(node1, node2) or
|
||||
newTransformerOrTemplatesStep(node1, node2) or
|
||||
newTransformerFromTemplatesStep(node1, node2) or
|
||||
xsltCompilerStep(node1, node2) or
|
||||
xsltExecutableStep(node1, node2) or
|
||||
xsltPackageStep(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
/** The class `javax.xml.transform.stax.StAXSource`. */
|
||||
class TypeStAXSource extends Class {
|
||||
TypeStAXSource() { this.hasQualifiedName("javax.xml.transform.stax", "StAXSource") }
|
||||
}
|
||||
|
||||
/** The class `javax.xml.transform.dom.DOMSource`. */
|
||||
class TypeDOMSource extends Class {
|
||||
TypeDOMSource() { this.hasQualifiedName("javax.xml.transform.dom", "DOMSource") }
|
||||
}
|
||||
|
||||
/** The interface `javax.xml.transform.Templates`. */
|
||||
class TypeTemplates extends Interface {
|
||||
TypeTemplates() { this.hasQualifiedName("javax.xml.transform", "Templates") }
|
||||
}
|
||||
|
||||
/** The method `net.sf.saxon.s9api.XsltTransformer.transform`. */
|
||||
class XsltTransformerTransformMethod extends Method {
|
||||
XsltTransformerTransformMethod() {
|
||||
this.getDeclaringType().hasQualifiedName("net.sf.saxon.s9api", "XsltTransformer") and
|
||||
this.hasName("transform")
|
||||
}
|
||||
}
|
||||
|
||||
/** The method `net.sf.saxon.s9api.Xslt30Transformer.transform`. */
|
||||
class Xslt30TransformerTransformMethod extends Method {
|
||||
Xslt30TransformerTransformMethod() {
|
||||
this.getDeclaringType().hasQualifiedName("net.sf.saxon.s9api", "Xslt30Transformer") and
|
||||
this.hasName("transform")
|
||||
}
|
||||
}
|
||||
|
||||
/** The method `net.sf.saxon.s9api.Xslt30Transformer.applyTemplates`. */
|
||||
class Xslt30TransformerApplyTemplatesMethod extends Method {
|
||||
Xslt30TransformerApplyTemplatesMethod() {
|
||||
this.getDeclaringType().hasQualifiedName("net.sf.saxon.s9api", "Xslt30Transformer") and
|
||||
this.hasName("applyTemplates")
|
||||
}
|
||||
}
|
||||
|
||||
/** The method `net.sf.saxon.s9api.Xslt30Transformer.callFunction`. */
|
||||
class Xslt30TransformerCallFunctionMethod extends Method {
|
||||
Xslt30TransformerCallFunctionMethod() {
|
||||
this.getDeclaringType().hasQualifiedName("net.sf.saxon.s9api", "Xslt30Transformer") and
|
||||
this.hasName("callFunction")
|
||||
}
|
||||
}
|
||||
|
||||
/** The method `net.sf.saxon.s9api.Xslt30Transformer.callTemplate`. */
|
||||
class Xslt30TransformerCallTemplateMethod extends Method {
|
||||
Xslt30TransformerCallTemplateMethod() {
|
||||
this.getDeclaringType().hasQualifiedName("net.sf.saxon.s9api", "Xslt30Transformer") and
|
||||
this.hasName("callTemplate")
|
||||
}
|
||||
}
|
||||
|
||||
/** The class `net.sf.saxon.s9api.XsltCompiler`. */
|
||||
class TypeXsltCompiler extends Class {
|
||||
TypeXsltCompiler() { this.hasQualifiedName("net.sf.saxon.s9api", "XsltCompiler") }
|
||||
}
|
||||
|
||||
/** The class `net.sf.saxon.s9api.XsltExecutable`. */
|
||||
class TypeXsltExecutable extends Class {
|
||||
TypeXsltExecutable() { this.hasQualifiedName("net.sf.saxon.s9api", "XsltExecutable") }
|
||||
}
|
||||
|
||||
/** The class `net.sf.saxon.s9api.XsltPackage`. */
|
||||
class TypeXsltPackage extends Class {
|
||||
TypeXsltPackage() { this.hasQualifiedName("net.sf.saxon.s9api", "XsltPackage") }
|
||||
}
|
||||
|
||||
/** A data flow sink for unvalidated user input that is used in XSLT transformation. */
|
||||
class XsltInjectionSink extends DataFlow::ExprNode {
|
||||
XsltInjectionSink() {
|
||||
exists(MethodAccess ma, Method m | m = ma.getMethod() and ma.getQualifier() = this.getExpr() |
|
||||
ma instanceof TransformerTransform or
|
||||
m instanceof XsltTransformerTransformMethod or
|
||||
m instanceof Xslt30TransformerTransformMethod or
|
||||
m instanceof Xslt30TransformerApplyTemplatesMethod or
|
||||
m instanceof Xslt30TransformerCallFunctionMethod or
|
||||
m instanceof Xslt30TransformerCallTemplateMethod
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `InputStream` or `Reader` and
|
||||
* `XMLStreamReader`, i.e. `XMLInputFactory.createXMLStreamReader(tainted)`.
|
||||
*/
|
||||
predicate xmlStreamReaderStep(ExprNode n1, ExprNode n2) {
|
||||
exists(XmlInputFactoryStreamReader xmlStreamReader |
|
||||
n1.asExpr() = xmlStreamReader.getSink() and
|
||||
n2.asExpr() = xmlStreamReader
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `InputStream` or `Reader` and
|
||||
* `XMLEventReader`, i.e. `XMLInputFactory.createXMLEventReader(tainted)`.
|
||||
*/
|
||||
predicate xmlEventReaderStep(ExprNode n1, ExprNode n2) {
|
||||
exists(XmlInputFactoryEventReader xmlEventReader |
|
||||
n1.asExpr() = xmlEventReader.getSink() and
|
||||
n2.asExpr() = xmlEventReader
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `XMLStreamReader` or
|
||||
* `XMLEventReader` and `StAXSource`, i.e. `new StAXSource(tainted)`.
|
||||
*/
|
||||
predicate staxSourceStep(ExprNode n1, ExprNode n2) {
|
||||
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeStAXSource |
|
||||
n1.asExpr() = cc.getAnArgument() and
|
||||
n2.asExpr() = cc
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `InputStream` and `Document`,
|
||||
* i.e. `DocumentBuilder.parse(tainted)`.
|
||||
*/
|
||||
predicate documentBuilderStep(ExprNode n1, ExprNode n2) {
|
||||
exists(DocumentBuilderParse documentBuilder |
|
||||
n1.asExpr() = documentBuilder.getSink() and
|
||||
n2.asExpr() = documentBuilder
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `Document` and `DOMSource`, i.e.
|
||||
* `new DOMSource(tainted)`.
|
||||
*/
|
||||
predicate domSourceStep(ExprNode n1, ExprNode n2) {
|
||||
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeDOMSource |
|
||||
n1.asExpr() = cc.getAnArgument() and
|
||||
n2.asExpr() = cc
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow configuration for secure processing feature that is enabled on `TransformerFactory`.
|
||||
*/
|
||||
private class TransformerFactoryWithSecureProcessingFeatureFlowConfig extends DataFlow2::Configuration {
|
||||
TransformerFactoryWithSecureProcessingFeatureFlowConfig() {
|
||||
this = "TransformerFactoryWithSecureProcessingFeatureFlowConfig"
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
exists(Variable v | v = src.asExpr().(VarAccess).getVariable() |
|
||||
exists(TransformerFactoryFeatureConfig config | config.getQualifier() = v.getAnAccess() |
|
||||
config.enables(configSecureProcessing())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
sink.asExpr() = ma.getQualifier() and
|
||||
ma.getMethod().getDeclaringType() instanceof TransformerFactory
|
||||
)
|
||||
}
|
||||
|
||||
override int fieldFlowBranchLimit() { result = 0 }
|
||||
}
|
||||
|
||||
/** A `ParserConfig` specific to `TransformerFactory`. */
|
||||
private class TransformerFactoryFeatureConfig extends ParserConfig {
|
||||
TransformerFactoryFeatureConfig() {
|
||||
exists(Method m |
|
||||
m = this.getMethod() and
|
||||
m.getDeclaringType() instanceof TransformerFactory and
|
||||
m.hasName("setFeature")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `Source` and `Transformer` or
|
||||
* `Templates`, i.e. `TransformerFactory.newTransformer(tainted)` or
|
||||
* `TransformerFactory.newTemplates(tainted)`.
|
||||
*/
|
||||
predicate newTransformerOrTemplatesStep(ExprNode n1, ExprNode n2) {
|
||||
exists(MethodAccess ma, Method m | ma.getMethod() = m |
|
||||
n1.asExpr() = ma.getAnArgument() and
|
||||
n2.asExpr() = ma and
|
||||
(
|
||||
m.getDeclaringType() instanceof TransformerFactory and m.hasName("newTransformer")
|
||||
or
|
||||
m.getDeclaringType() instanceof TransformerFactory and m.hasName("newTemplates")
|
||||
) and
|
||||
not exists(TransformerFactoryWithSecureProcessingFeatureFlowConfig conf |
|
||||
conf.hasFlowToExpr(ma.getQualifier())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `Templates` and `Transformer`,
|
||||
* i.e. `tainted.newTransformer()`.
|
||||
*/
|
||||
predicate newTransformerFromTemplatesStep(ExprNode n1, ExprNode n2) {
|
||||
exists(MethodAccess ma, Method m | ma.getMethod() = m |
|
||||
n1.asExpr() = ma.getQualifier() and
|
||||
n2.asExpr() = ma and
|
||||
m.getDeclaringType() instanceof TypeTemplates and
|
||||
m.hasName("newTransformer")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `Source` or `URI` and
|
||||
* `XsltExecutable` or `XsltPackage`, i.e. `XsltCompiler.compile(tainted)` or
|
||||
* `XsltCompiler.loadExecutablePackage(tainted)` or `XsltCompiler.compilePackage(tainted)` or
|
||||
* `XsltCompiler.loadLibraryPackage(tainted)`.
|
||||
*/
|
||||
predicate xsltCompilerStep(ExprNode n1, ExprNode n2) {
|
||||
exists(MethodAccess ma, Method m | ma.getMethod() = m |
|
||||
n1.asExpr() = ma.getArgument(0) and
|
||||
n2.asExpr() = ma and
|
||||
m.getDeclaringType() instanceof TypeXsltCompiler and
|
||||
(
|
||||
m.hasName("compile") or
|
||||
m.hasName("loadExecutablePackage") or
|
||||
m.hasName("compilePackage") or
|
||||
m.hasName("loadLibraryPackage")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `XsltExecutable` and
|
||||
* `XsltTransformer` or `Xslt30Transformer`, i.e. `XsltExecutable.load()` or
|
||||
* `XsltExecutable.load30()`.
|
||||
*/
|
||||
predicate xsltExecutableStep(ExprNode n1, ExprNode n2) {
|
||||
exists(MethodAccess ma, Method m | ma.getMethod() = m |
|
||||
n1.asExpr() = ma.getQualifier() and
|
||||
n2.asExpr() = ma and
|
||||
m.getDeclaringType() instanceof TypeXsltExecutable and
|
||||
(m.hasName("load") or m.hasName("load30"))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `XsltPackage` and
|
||||
* `XsltExecutable`, i.e. `XsltPackage.link()`.
|
||||
*/
|
||||
predicate xsltPackageStep(ExprNode n1, ExprNode n2) {
|
||||
exists(MethodAccess ma, Method m | ma.getMethod() = m |
|
||||
n1.asExpr() = ma.getQualifier() and
|
||||
n2.asExpr() = ma and
|
||||
m.getDeclaringType() instanceof TypeXsltPackage and
|
||||
m.hasName("link")
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
private import java
|
||||
private import DataFlowPrivate
|
||||
private import DataFlowUtil
|
||||
private import semmle.code.java.dataflow.InstanceAccess
|
||||
import semmle.code.java.dispatch.VirtualDispatch
|
||||
|
||||
private module DispatchImpl {
|
||||
@@ -17,6 +19,13 @@ private module DispatchImpl {
|
||||
not p.isVarargs() and
|
||||
c = ma.getEnclosingCallable()
|
||||
)
|
||||
or
|
||||
exists(OwnInstanceAccess ia |
|
||||
2 <= strictcount(viableImpl(ma)) and
|
||||
(ia.isExplicit(ma.getQualifier()) or ia.isImplicitMethodQualifier(ma)) and
|
||||
i = -1 and
|
||||
c = ma.getEnclosingCallable()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,18 +46,32 @@ private module DispatchImpl {
|
||||
* relevant call context.
|
||||
*/
|
||||
private predicate contextArgHasType(Call ctx, int i, RefType t, boolean exact) {
|
||||
exists(Expr arg, Expr src |
|
||||
relevantContext(ctx, i) and
|
||||
ctx.getArgument(i) = arg and
|
||||
src = variableTrack(arg) and
|
||||
exists(RefType srctype | srctype = src.getType() |
|
||||
exists(TypeVariable v | v = srctype |
|
||||
t = v.getUpperBoundType+() and not t instanceof TypeVariable
|
||||
)
|
||||
relevantContext(ctx, i) and
|
||||
exists(RefType srctype |
|
||||
exists(Expr arg, Expr src |
|
||||
i = -1 and
|
||||
ctx.getQualifier() = arg
|
||||
or
|
||||
t = srctype and not srctype instanceof TypeVariable
|
||||
) and
|
||||
if src instanceof ClassInstanceExpr then exact = true else exact = false
|
||||
ctx.getArgument(i) = arg
|
||||
|
|
||||
src = variableTrack(arg) and
|
||||
srctype = src.getType() and
|
||||
if src instanceof ClassInstanceExpr then exact = true else exact = false
|
||||
)
|
||||
or
|
||||
exists(Node arg |
|
||||
i = -1 and
|
||||
not exists(ctx.getQualifier()) and
|
||||
getInstanceArgument(ctx) = arg and
|
||||
arg.getTypeBound() = srctype and
|
||||
if ctx instanceof ClassInstanceExpr then exact = true else exact = false
|
||||
)
|
||||
|
|
||||
exists(TypeVariable v | v = srctype |
|
||||
t = v.getUpperBoundType+() and not t instanceof TypeVariable
|
||||
)
|
||||
or
|
||||
t = srctype and not srctype instanceof TypeVariable
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -193,6 +193,18 @@ predicate readStep(Node node1, Content f, Node node2) {
|
||||
fr.getField() = f.(FieldContent).getField() and
|
||||
fr = node2.asExpr()
|
||||
)
|
||||
or
|
||||
exists(Record r, Method getter, Field recf, MethodAccess get |
|
||||
getter.getDeclaringType() = r and
|
||||
recf.getDeclaringType() = r and
|
||||
getter.getNumberOfParameters() = 0 and
|
||||
getter.getName() = recf.getName() and
|
||||
not exists(getter.getBody()) and
|
||||
recf = f.(FieldContent).getField() and
|
||||
get.getMethod() = getter and
|
||||
node1.asExpr() = get.getQualifier() and
|
||||
node2.asExpr() = get
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1172,3 +1172,15 @@ class SimpleXMLFormatterCall extends XmlParserCall {
|
||||
|
||||
override predicate isSafe() { none() }
|
||||
}
|
||||
|
||||
/** A configuration for secure processing. */
|
||||
Expr configSecureProcessing() {
|
||||
result.(ConstantStringExpr).getStringValue() =
|
||||
"http://javax.xml.XMLConstants/feature/secure-processing"
|
||||
or
|
||||
exists(Field f |
|
||||
result = f.getAnAccess() and
|
||||
f.hasName("FEATURE_SECURE_PROCESSING") and
|
||||
f.getDeclaringType() instanceof XmlConstants
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
edges
|
||||
| XsltInjection.java:30:44:30:66 | getInputStream(...) : InputStream | XsltInjection.java:31:5:31:59 | newTransformer(...) |
|
||||
| XsltInjection.java:35:66:35:88 | getInputStream(...) : InputStream | XsltInjection.java:36:5:36:74 | newTransformer(...) |
|
||||
| XsltInjection.java:40:45:40:70 | param : String | XsltInjection.java:43:5:43:59 | newTransformer(...) |
|
||||
| XsltInjection.java:47:54:47:76 | getInputStream(...) : InputStream | XsltInjection.java:48:5:48:74 | newTransformer(...) |
|
||||
| XsltInjection.java:52:82:52:104 | getInputStream(...) : InputStream | XsltInjection.java:53:5:53:59 | newTransformer(...) |
|
||||
| XsltInjection.java:57:91:57:113 | getInputStream(...) : InputStream | XsltInjection.java:58:5:58:59 | newTransformer(...) |
|
||||
| XsltInjection.java:62:120:62:142 | getInputStream(...) : InputStream | XsltInjection.java:63:5:63:74 | newTransformer(...) |
|
||||
| XsltInjection.java:67:102:67:124 | getInputStream(...) : InputStream | XsltInjection.java:68:5:68:59 | newTransformer(...) |
|
||||
| XsltInjection.java:72:44:72:66 | getInputStream(...) : InputStream | XsltInjection.java:76:5:76:34 | newTransformer(...) |
|
||||
| XsltInjection.java:80:44:80:66 | getInputStream(...) : InputStream | XsltInjection.java:83:5:83:34 | newTransformer(...) |
|
||||
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:90:5:90:35 | load(...) |
|
||||
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:91:5:91:37 | load30(...) |
|
||||
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:92:5:92:37 | load30(...) |
|
||||
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:93:5:93:37 | load30(...) |
|
||||
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:94:5:94:37 | load30(...) |
|
||||
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:95:5:95:37 | load30(...) |
|
||||
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:96:5:96:37 | load30(...) |
|
||||
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:97:5:97:37 | load30(...) |
|
||||
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:98:5:98:37 | load30(...) |
|
||||
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:99:5:99:37 | load30(...) |
|
||||
| XsltInjection.java:103:36:103:61 | param : String | XsltInjection.java:108:5:108:46 | load(...) |
|
||||
| XsltInjection.java:103:36:103:61 | param : String | XsltInjection.java:110:5:110:50 | load(...) |
|
||||
| XsltInjection.java:105:44:105:66 | getInputStream(...) : InputStream | XsltInjection.java:109:5:109:49 | load(...) |
|
||||
nodes
|
||||
| XsltInjection.java:30:44:30:66 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| XsltInjection.java:31:5:31:59 | newTransformer(...) | semmle.label | newTransformer(...) |
|
||||
| XsltInjection.java:35:66:35:88 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| XsltInjection.java:36:5:36:74 | newTransformer(...) | semmle.label | newTransformer(...) |
|
||||
| XsltInjection.java:40:45:40:70 | param : String | semmle.label | param : String |
|
||||
| XsltInjection.java:43:5:43:59 | newTransformer(...) | semmle.label | newTransformer(...) |
|
||||
| XsltInjection.java:47:54:47:76 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| XsltInjection.java:48:5:48:74 | newTransformer(...) | semmle.label | newTransformer(...) |
|
||||
| XsltInjection.java:52:82:52:104 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| XsltInjection.java:53:5:53:59 | newTransformer(...) | semmle.label | newTransformer(...) |
|
||||
| XsltInjection.java:57:91:57:113 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| XsltInjection.java:58:5:58:59 | newTransformer(...) | semmle.label | newTransformer(...) |
|
||||
| XsltInjection.java:62:120:62:142 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| XsltInjection.java:63:5:63:74 | newTransformer(...) | semmle.label | newTransformer(...) |
|
||||
| XsltInjection.java:67:102:67:124 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| XsltInjection.java:68:5:68:59 | newTransformer(...) | semmle.label | newTransformer(...) |
|
||||
| XsltInjection.java:72:44:72:66 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| XsltInjection.java:76:5:76:34 | newTransformer(...) | semmle.label | newTransformer(...) |
|
||||
| XsltInjection.java:80:44:80:66 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| XsltInjection.java:83:5:83:34 | newTransformer(...) | semmle.label | newTransformer(...) |
|
||||
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| XsltInjection.java:90:5:90:35 | load(...) | semmle.label | load(...) |
|
||||
| XsltInjection.java:91:5:91:37 | load30(...) | semmle.label | load30(...) |
|
||||
| XsltInjection.java:92:5:92:37 | load30(...) | semmle.label | load30(...) |
|
||||
| XsltInjection.java:93:5:93:37 | load30(...) | semmle.label | load30(...) |
|
||||
| XsltInjection.java:94:5:94:37 | load30(...) | semmle.label | load30(...) |
|
||||
| XsltInjection.java:95:5:95:37 | load30(...) | semmle.label | load30(...) |
|
||||
| XsltInjection.java:96:5:96:37 | load30(...) | semmle.label | load30(...) |
|
||||
| XsltInjection.java:97:5:97:37 | load30(...) | semmle.label | load30(...) |
|
||||
| XsltInjection.java:98:5:98:37 | load30(...) | semmle.label | load30(...) |
|
||||
| XsltInjection.java:99:5:99:37 | load30(...) | semmle.label | load30(...) |
|
||||
| XsltInjection.java:103:36:103:61 | param : String | semmle.label | param : String |
|
||||
| XsltInjection.java:105:44:105:66 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| XsltInjection.java:108:5:108:46 | load(...) | semmle.label | load(...) |
|
||||
| XsltInjection.java:109:5:109:49 | load(...) | semmle.label | load(...) |
|
||||
| XsltInjection.java:110:5:110:50 | load(...) | semmle.label | load(...) |
|
||||
#select
|
||||
| XsltInjection.java:31:5:31:59 | newTransformer(...) | XsltInjection.java:30:44:30:66 | getInputStream(...) : InputStream | XsltInjection.java:31:5:31:59 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:30:44:30:66 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:36:5:36:74 | newTransformer(...) | XsltInjection.java:35:66:35:88 | getInputStream(...) : InputStream | XsltInjection.java:36:5:36:74 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:35:66:35:88 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:43:5:43:59 | newTransformer(...) | XsltInjection.java:40:45:40:70 | param : String | XsltInjection.java:43:5:43:59 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:40:45:40:70 | param | this user input |
|
||||
| XsltInjection.java:48:5:48:74 | newTransformer(...) | XsltInjection.java:47:54:47:76 | getInputStream(...) : InputStream | XsltInjection.java:48:5:48:74 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:47:54:47:76 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:53:5:53:59 | newTransformer(...) | XsltInjection.java:52:82:52:104 | getInputStream(...) : InputStream | XsltInjection.java:53:5:53:59 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:52:82:52:104 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:58:5:58:59 | newTransformer(...) | XsltInjection.java:57:91:57:113 | getInputStream(...) : InputStream | XsltInjection.java:58:5:58:59 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:57:91:57:113 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:63:5:63:74 | newTransformer(...) | XsltInjection.java:62:120:62:142 | getInputStream(...) : InputStream | XsltInjection.java:63:5:63:74 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:62:120:62:142 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:68:5:68:59 | newTransformer(...) | XsltInjection.java:67:102:67:124 | getInputStream(...) : InputStream | XsltInjection.java:68:5:68:59 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:67:102:67:124 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:76:5:76:34 | newTransformer(...) | XsltInjection.java:72:44:72:66 | getInputStream(...) : InputStream | XsltInjection.java:76:5:76:34 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:72:44:72:66 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:83:5:83:34 | newTransformer(...) | XsltInjection.java:80:44:80:66 | getInputStream(...) : InputStream | XsltInjection.java:83:5:83:34 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:80:44:80:66 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:90:5:90:35 | load(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:90:5:90:35 | load(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:91:5:91:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:91:5:91:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:92:5:92:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:92:5:92:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:93:5:93:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:93:5:93:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:94:5:94:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:94:5:94:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:95:5:95:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:95:5:95:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:96:5:96:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:96:5:96:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:97:5:97:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:97:5:97:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:98:5:98:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:98:5:98:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:99:5:99:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:99:5:99:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:108:5:108:46 | load(...) | XsltInjection.java:103:36:103:61 | param : String | XsltInjection.java:108:5:108:46 | load(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:103:36:103:61 | param | this user input |
|
||||
| XsltInjection.java:109:5:109:49 | load(...) | XsltInjection.java:105:44:105:66 | getInputStream(...) : InputStream | XsltInjection.java:109:5:109:49 | load(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:105:44:105:66 | getInputStream(...) | this user input |
|
||||
| XsltInjection.java:110:5:110:50 | load(...) | XsltInjection.java:103:36:103:61 | param : String | XsltInjection.java:110:5:110:50 | load(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:103:36:103:61 | param | this user input |
|
||||
@@ -0,0 +1,127 @@
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.net.Socket;
|
||||
import java.net.URI;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.sax.SAXSource;
|
||||
import javax.xml.transform.stax.StAXSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import net.sf.saxon.s9api.Processor;
|
||||
import net.sf.saxon.s9api.XdmValue;
|
||||
import net.sf.saxon.s9api.XsltCompiler;
|
||||
|
||||
@Controller
|
||||
public class XsltInjection {
|
||||
public void testStreamSourceInputStream(Socket socket) throws Exception {
|
||||
StreamSource source = new StreamSource(socket.getInputStream());
|
||||
TransformerFactory.newInstance().newTransformer(source).transform(null, null);
|
||||
}
|
||||
|
||||
public void testStreamSourceReader(Socket socket) throws Exception {
|
||||
StreamSource source = new StreamSource(new InputStreamReader(socket.getInputStream()));
|
||||
TransformerFactory.newInstance().newTemplates(source).newTransformer().transform(null, null);
|
||||
}
|
||||
|
||||
@RequestMapping
|
||||
public void testStreamSourceInjectedParam(@RequestParam String param) throws Exception {
|
||||
String xslt = "<xsl:stylesheet [...]" + param + "</xsl:stylesheet>";
|
||||
StreamSource source = new StreamSource(new StringReader(xslt));
|
||||
TransformerFactory.newInstance().newTransformer(source).transform(null, null);
|
||||
}
|
||||
|
||||
public void testSAXSourceInputStream(Socket socket) throws Exception {
|
||||
SAXSource source = new SAXSource(new InputSource(socket.getInputStream()));
|
||||
TransformerFactory.newInstance().newTemplates(source).newTransformer().transform(null, null);
|
||||
}
|
||||
|
||||
public void testSAXSourceReader(Socket socket) throws Exception {
|
||||
SAXSource source = new SAXSource(null, new InputSource(new InputStreamReader(socket.getInputStream())));
|
||||
TransformerFactory.newInstance().newTransformer(source).transform(null, null);
|
||||
}
|
||||
|
||||
public void testStAXSourceEventReader(Socket socket) throws Exception {
|
||||
StAXSource source = new StAXSource(XMLInputFactory.newInstance().createXMLEventReader(socket.getInputStream()));
|
||||
TransformerFactory.newInstance().newTransformer(source).transform(null, null);
|
||||
}
|
||||
|
||||
public void testStAXSourceEventStream(Socket socket) throws Exception {
|
||||
StAXSource source = new StAXSource(XMLInputFactory.newInstance().createXMLStreamReader(null, new InputStreamReader(socket.getInputStream())));
|
||||
TransformerFactory.newInstance().newTemplates(source).newTransformer().transform(null, null);
|
||||
}
|
||||
|
||||
public void testDOMSource(Socket socket) throws Exception {
|
||||
DOMSource source = new DOMSource(DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(socket.getInputStream()));
|
||||
TransformerFactory.newInstance().newTransformer(source).transform(null, null);
|
||||
}
|
||||
|
||||
public void testDisabledXXE(Socket socket) throws Exception {
|
||||
StreamSource source = new StreamSource(socket.getInputStream());
|
||||
TransformerFactory factory = TransformerFactory.newInstance();
|
||||
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
|
||||
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
|
||||
factory.newTransformer(source).transform(null, null);
|
||||
}
|
||||
|
||||
public void testFeatureSecureProcessingDisabled(Socket socket) throws Exception {
|
||||
StreamSource source = new StreamSource(socket.getInputStream());
|
||||
TransformerFactory factory = TransformerFactory.newInstance();
|
||||
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, false);
|
||||
factory.newTransformer(source).transform(null, null);
|
||||
}
|
||||
|
||||
public void testSaxon(Socket socket) throws Exception {
|
||||
StreamSource source = new StreamSource(socket.getInputStream());
|
||||
XsltCompiler compiler = new Processor(true).newXsltCompiler();
|
||||
|
||||
compiler.compile(source).load().transform();
|
||||
compiler.compile(source).load30().transform(null, null);
|
||||
compiler.compile(source).load30().applyTemplates((Source) null);
|
||||
compiler.compile(source).load30().applyTemplates((Source) null, null);
|
||||
compiler.compile(source).load30().applyTemplates((XdmValue) null);
|
||||
compiler.compile(source).load30().applyTemplates((XdmValue) null, null);
|
||||
compiler.compile(source).load30().callFunction(null, null);
|
||||
compiler.compile(source).load30().callFunction(null, null, null);
|
||||
compiler.compile(source).load30().callTemplate(null);
|
||||
compiler.compile(source).load30().callTemplate(null, null);
|
||||
}
|
||||
|
||||
@RequestMapping
|
||||
public void testSaxonXsltPackage(@RequestParam String param, Socket socket) throws Exception {
|
||||
URI uri = new URI(param);
|
||||
StreamSource source = new StreamSource(socket.getInputStream());
|
||||
XsltCompiler compiler = new Processor(true).newXsltCompiler();
|
||||
|
||||
compiler.loadExecutablePackage(uri).load().transform();
|
||||
compiler.compilePackage(source).link().load().transform();
|
||||
compiler.loadLibraryPackage(uri).link().load().transform();
|
||||
}
|
||||
|
||||
public void testOkFeatureSecureProcessing(Socket socket) throws Exception {
|
||||
StreamSource source = new StreamSource(socket.getInputStream());
|
||||
TransformerFactory factory = TransformerFactory.newInstance();
|
||||
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||
factory.newTransformer(source).transform(null, null);
|
||||
}
|
||||
|
||||
public void testOkSaxon(Socket socket) throws Exception {
|
||||
StreamSource source = new StreamSource(socket.getInputStream());
|
||||
XsltCompiler compiler = new Processor(true).newXsltCompiler();
|
||||
|
||||
compiler.compile(source).load().close();
|
||||
compiler.compile((Source) new Object()).load().transform();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE/CWE-074/XsltInjection.ql
|
||||
@@ -0,0 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/Saxon-HE-9.9.1-7
|
||||
@@ -0,0 +1,8 @@
|
||||
package net.sf.saxon;
|
||||
|
||||
import net.sf.saxon.lib.*;
|
||||
import net.sf.saxon.om.*;
|
||||
|
||||
public class Configuration implements SourceResolver, NotationSet {
|
||||
public interface ApiProvider {}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package net.sf.saxon.lib;
|
||||
|
||||
public interface SourceResolver { }
|
||||
@@ -0,0 +1,3 @@
|
||||
package net.sf.saxon.om;
|
||||
|
||||
public interface NotationSet { }
|
||||
@@ -0,0 +1,3 @@
|
||||
package net.sf.saxon.s9api;
|
||||
|
||||
abstract class AbstractXsltTransformer { }
|
||||
@@ -0,0 +1,3 @@
|
||||
package net.sf.saxon.s9api;
|
||||
|
||||
public interface Destination { }
|
||||
@@ -0,0 +1,9 @@
|
||||
package net.sf.saxon.s9api;
|
||||
|
||||
import net.sf.saxon.Configuration;
|
||||
|
||||
public class Processor implements Configuration.ApiProvider {
|
||||
public Processor(boolean licensedEdition) {}
|
||||
|
||||
public XsltCompiler newXsltCompiler() { return null; }
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package net.sf.saxon.s9api;
|
||||
|
||||
public class QName { }
|
||||
@@ -0,0 +1,3 @@
|
||||
package net.sf.saxon.s9api;
|
||||
|
||||
public class SaxonApiException extends Exception { }
|
||||
@@ -0,0 +1,3 @@
|
||||
package net.sf.saxon.s9api;
|
||||
|
||||
public class SaxonApiUncheckedException extends RuntimeException {}
|
||||
@@ -0,0 +1,3 @@
|
||||
package net.sf.saxon.s9api;
|
||||
|
||||
public abstract class XdmItem extends XdmValue { }
|
||||
@@ -0,0 +1,8 @@
|
||||
package net.sf.saxon.s9api;
|
||||
|
||||
import java.lang.Iterable;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class XdmValue implements Iterable<XdmItem> {
|
||||
public Iterator<XdmItem> iterator() throws SaxonApiUncheckedException { return null; }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package net.sf.saxon.s9api;
|
||||
|
||||
import javax.xml.transform.Source;
|
||||
|
||||
public class Xslt30Transformer extends AbstractXsltTransformer {
|
||||
public void transform(Source source, Destination destination) throws SaxonApiException {}
|
||||
public void applyTemplates(Source source, Destination destination) throws SaxonApiException {}
|
||||
public XdmValue applyTemplates(Source source) throws SaxonApiException { return null; }
|
||||
public void applyTemplates(XdmValue selection, Destination destination) throws SaxonApiException {}
|
||||
public XdmValue applyTemplates(XdmValue selection) throws SaxonApiException { return null; }
|
||||
public XdmValue callFunction(QName function, XdmValue[] arguments) throws SaxonApiException { return null; }
|
||||
public void callFunction(QName function, XdmValue[] arguments, Destination destination) throws SaxonApiException {}
|
||||
public XdmValue callTemplate(QName templateName) throws SaxonApiException { return null; }
|
||||
public void callTemplate(QName templateName, Destination destination) throws SaxonApiException {}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.sf.saxon.s9api;
|
||||
|
||||
import javax.xml.transform.Source;
|
||||
import java.net.URI;
|
||||
|
||||
public class XsltCompiler {
|
||||
public XsltExecutable compile(Source source) throws SaxonApiException { return null; }
|
||||
public XsltExecutable loadExecutablePackage(URI location) throws SaxonApiException { return null; }
|
||||
public XsltPackage compilePackage(Source source) throws SaxonApiException { return null; }
|
||||
public XsltPackage loadLibraryPackage(URI location) throws SaxonApiException { return null; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package net.sf.saxon.s9api;
|
||||
|
||||
public class XsltExecutable {
|
||||
public XsltTransformer load() { return null; }
|
||||
public Xslt30Transformer load30() { return null; }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package net.sf.saxon.s9api;
|
||||
|
||||
public class XsltPackage {
|
||||
public XsltExecutable link() throws SaxonApiException { return null; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package net.sf.saxon.s9api;
|
||||
|
||||
public class XsltTransformer extends AbstractXsltTransformer implements Destination {
|
||||
public void transform() throws SaxonApiException {}
|
||||
public void close() {}
|
||||
}
|
||||
63
java/ql/test/library-tests/dataflow/callctx/A.java
Normal file
63
java/ql/test/library-tests/dataflow/callctx/A.java
Normal file
@@ -0,0 +1,63 @@
|
||||
public class A {
|
||||
static void sink(Object x) { }
|
||||
|
||||
static Object source() { return null; }
|
||||
|
||||
static class C1 {
|
||||
C1() { }
|
||||
|
||||
C1(Object x) {
|
||||
foo(x);
|
||||
}
|
||||
|
||||
void wrapFoo1(Object x) {
|
||||
foo(x);
|
||||
}
|
||||
|
||||
void wrapFoo2(Object x) {
|
||||
this.foo(x);
|
||||
}
|
||||
|
||||
void foo(Object x) {
|
||||
Object c1 = x;
|
||||
sink(c1);
|
||||
}
|
||||
}
|
||||
|
||||
static class C2 extends C1 {
|
||||
C2() { }
|
||||
|
||||
C2(Object x) {
|
||||
super(x);
|
||||
}
|
||||
|
||||
void foo(Object x) {
|
||||
Object c2 = x;
|
||||
sink(c2);
|
||||
}
|
||||
|
||||
void callWrapFoo2() {
|
||||
wrapFoo2(source());
|
||||
}
|
||||
}
|
||||
|
||||
static void wrapFoo3(C1 c1, Object x) {
|
||||
c1.foo(x);
|
||||
}
|
||||
|
||||
void test(C1 c) {
|
||||
c.wrapFoo1(source());
|
||||
c.wrapFoo2(source());
|
||||
wrapFoo3(c, source());
|
||||
|
||||
new C1(source());
|
||||
new C1().wrapFoo1(source());
|
||||
new C1().wrapFoo2(source());
|
||||
wrapFoo3(new C1(), source());
|
||||
|
||||
new C2(source());
|
||||
new C2().wrapFoo1(source());
|
||||
new C2().wrapFoo2(source());
|
||||
wrapFoo3(new C2(), source());
|
||||
}
|
||||
}
|
||||
15
java/ql/test/library-tests/dataflow/callctx/test.expected
Normal file
15
java/ql/test/library-tests/dataflow/callctx/test.expected
Normal file
@@ -0,0 +1,15 @@
|
||||
| A.java:40:16:40:23 | source(...) | A.java:36:12:36:13 | c2 |
|
||||
| A.java:49:16:49:23 | source(...) | A.java:23:12:23:13 | c1 |
|
||||
| A.java:49:16:49:23 | source(...) | A.java:36:12:36:13 | c2 |
|
||||
| A.java:50:16:50:23 | source(...) | A.java:23:12:23:13 | c1 |
|
||||
| A.java:50:16:50:23 | source(...) | A.java:36:12:36:13 | c2 |
|
||||
| A.java:51:17:51:24 | source(...) | A.java:23:12:23:13 | c1 |
|
||||
| A.java:51:17:51:24 | source(...) | A.java:36:12:36:13 | c2 |
|
||||
| A.java:53:12:53:19 | source(...) | A.java:23:12:23:13 | c1 |
|
||||
| A.java:54:23:54:30 | source(...) | A.java:23:12:23:13 | c1 |
|
||||
| A.java:55:23:55:30 | source(...) | A.java:23:12:23:13 | c1 |
|
||||
| A.java:56:24:56:31 | source(...) | A.java:23:12:23:13 | c1 |
|
||||
| A.java:58:12:58:19 | source(...) | A.java:36:12:36:13 | c2 |
|
||||
| A.java:59:23:59:30 | source(...) | A.java:36:12:36:13 | c2 |
|
||||
| A.java:60:23:60:30 | source(...) | A.java:36:12:36:13 | c2 |
|
||||
| A.java:61:24:61:31 | source(...) | A.java:36:12:36:13 | c2 |
|
||||
15
java/ql/test/library-tests/dataflow/callctx/test.ql
Normal file
15
java/ql/test/library-tests/dataflow/callctx/test.ql
Normal file
@@ -0,0 +1,15 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import DataFlow
|
||||
|
||||
class Conf extends Configuration {
|
||||
Conf() { this = "qqconf" }
|
||||
|
||||
override predicate isSource(Node n) { n.asExpr().(MethodAccess).getMethod().hasName("source") }
|
||||
|
||||
override predicate isSink(Node n) { n.asExpr().(Argument).getCall().getCallee().hasName("sink") }
|
||||
}
|
||||
|
||||
from Node src, Node sink, Conf c
|
||||
where c.hasFlow(src, sink)
|
||||
select src, sink
|
||||
65
java/ql/test/library-tests/dataflow/records/A.java
Normal file
65
java/ql/test/library-tests/dataflow/records/A.java
Normal file
@@ -0,0 +1,65 @@
|
||||
public class A {
|
||||
record Pair(Object x, Object y) { }
|
||||
|
||||
static Object source() { return null; }
|
||||
|
||||
void sink(Object o) { }
|
||||
|
||||
void foo() {
|
||||
Pair p1 = new Pair(source(), null);
|
||||
Pair p2 = new Pair(new Object(), source());
|
||||
bar(p1, p2);
|
||||
}
|
||||
|
||||
void bar(Pair p1, Pair p2) {
|
||||
sink(p1.x);
|
||||
sink(p1.y);
|
||||
sink(p2.x);
|
||||
sink(p2.y);
|
||||
Object p1x = p1.x();
|
||||
Object p1y = p1.y();
|
||||
Object p2x = p2.x();
|
||||
Object p2y = p2.y();
|
||||
sink(p1x);
|
||||
sink(p1y);
|
||||
sink(p2x);
|
||||
sink(p2y);
|
||||
}
|
||||
|
||||
record RecWithGetter(Object f) {
|
||||
public Object f() {
|
||||
return this.f;
|
||||
}
|
||||
}
|
||||
|
||||
record RecWithWeirdGetter1(Object f) {
|
||||
public Object f() {
|
||||
return new Object();
|
||||
}
|
||||
}
|
||||
|
||||
record RecWithWeirdGetter2(Object f) {
|
||||
public Object f() {
|
||||
return source();
|
||||
}
|
||||
}
|
||||
|
||||
void testExplicitGetter1() {
|
||||
RecWithGetter r1 = new RecWithGetter(source());
|
||||
RecWithWeirdGetter1 r2 = new RecWithWeirdGetter1(source());
|
||||
RecWithWeirdGetter2 r3 = new RecWithWeirdGetter2(source());
|
||||
testExplicitGetter2(r1, r2, r3);
|
||||
}
|
||||
|
||||
void testExplicitGetter2(RecWithGetter r1, RecWithWeirdGetter1 r2, RecWithWeirdGetter2 r3) {
|
||||
sink(r1.f);
|
||||
sink(r2.f);
|
||||
sink(r3.f);
|
||||
Object r1f = r1.f();
|
||||
Object r2f = r2.f();
|
||||
Object r3f = r3.f();
|
||||
sink(r1f);
|
||||
sink(r2f);
|
||||
sink(r3f);
|
||||
}
|
||||
}
|
||||
1
java/ql/test/library-tests/dataflow/records/options
Normal file
1
java/ql/test/library-tests/dataflow/records/options
Normal file
@@ -0,0 +1 @@
|
||||
//semmle-extractor-options: --javac-args --enable-preview -source 14 -target 14
|
||||
@@ -0,0 +1,9 @@
|
||||
| A.java:9:24:9:31 | source(...) | A.java:15:10:15:13 | p1.x |
|
||||
| A.java:9:24:9:31 | source(...) | A.java:23:10:23:12 | p1x |
|
||||
| A.java:10:38:10:45 | source(...) | A.java:18:10:18:13 | p2.y |
|
||||
| A.java:10:38:10:45 | source(...) | A.java:26:10:26:12 | p2y |
|
||||
| A.java:43:14:43:21 | source(...) | A.java:63:10:63:12 | r3f |
|
||||
| A.java:48:42:48:49 | source(...) | A.java:55:10:55:13 | r1.f |
|
||||
| A.java:48:42:48:49 | source(...) | A.java:61:10:61:12 | r1f |
|
||||
| A.java:49:54:49:61 | source(...) | A.java:56:10:56:13 | r2.f |
|
||||
| A.java:50:54:50:61 | source(...) | A.java:57:10:57:13 | r3.f |
|
||||
15
java/ql/test/library-tests/dataflow/records/test.ql
Normal file
15
java/ql/test/library-tests/dataflow/records/test.ql
Normal file
@@ -0,0 +1,15 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import DataFlow
|
||||
|
||||
class Conf extends Configuration {
|
||||
Conf() { this = "qqconf" }
|
||||
|
||||
override predicate isSource(Node n) { n.asExpr().(MethodAccess).getMethod().hasName("source") }
|
||||
|
||||
override predicate isSink(Node n) { n.asExpr().(Argument).getCall().getCallee().hasName("sink") }
|
||||
}
|
||||
|
||||
from Conf conf, Node src, Node sink
|
||||
where conf.hasFlow(src, sink)
|
||||
select src, sink
|
||||
@@ -0,0 +1,25 @@
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.util.*;
|
||||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.DBCollection;
|
||||
import com.mongodb.DBCursor;
|
||||
import com.mongodb.*;
|
||||
|
||||
public class Mongo {
|
||||
public static void main(String[] args) {
|
||||
MongoClient mongoClient = new MongoClient(new ServerAddress("localhost", 27017));
|
||||
DB db = mongoClient.getDB("mydb");
|
||||
DBCollection collection = db.getCollection("test");
|
||||
|
||||
String name = args[1];
|
||||
String stringQuery = "{ 'name' : '" + name + "'}";
|
||||
DBObject databaseQuery = (DBObject) JSON.parse(stringQuery);
|
||||
DBCursor result = collection.find(databaseQuery);
|
||||
|
||||
String json = args[1];
|
||||
BasicDBObject bdb = BasicDBObject.parse(json);
|
||||
DBCursor result2 = collection.find(bdb);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
edges
|
||||
| Mongo.java:10:29:10:41 | args : String[] | Mongo.java:17:45:17:67 | parse(...) |
|
||||
| Mongo.java:10:29:10:41 | args : String[] | Mongo.java:21:49:21:52 | json |
|
||||
| Test.java:29:30:29:42 | args : String[] | Test.java:36:47:36:52 | query1 |
|
||||
| Test.java:29:30:29:42 | args : String[] | Test.java:42:57:42:62 | query2 |
|
||||
| Test.java:29:30:29:42 | args : String[] | Test.java:50:62:50:67 | query3 |
|
||||
@@ -11,6 +13,9 @@ edges
|
||||
| Test.java:214:11:214:14 | args : String[] | Test.java:29:30:29:42 | args : String[] |
|
||||
| Test.java:218:14:218:17 | args : String[] | Test.java:183:33:183:45 | args : String[] |
|
||||
nodes
|
||||
| Mongo.java:10:29:10:41 | args : String[] | semmle.label | args : String[] |
|
||||
| Mongo.java:17:45:17:67 | parse(...) | semmle.label | parse(...) |
|
||||
| Mongo.java:21:49:21:52 | json | semmle.label | json |
|
||||
| Test.java:29:30:29:42 | args : String[] | semmle.label | args : String[] |
|
||||
| Test.java:36:47:36:52 | query1 | semmle.label | query1 |
|
||||
| Test.java:42:57:42:62 | query2 | semmle.label | query2 |
|
||||
@@ -24,6 +29,8 @@ nodes
|
||||
| Test.java:214:11:214:14 | args : String[] | semmle.label | args : String[] |
|
||||
| Test.java:218:14:218:17 | args : String[] | semmle.label | args : String[] |
|
||||
#select
|
||||
| Mongo.java:17:45:17:67 | parse(...) | Mongo.java:10:29:10:41 | args : String[] | Mongo.java:17:45:17:67 | parse(...) | Query might include code from $@. | Mongo.java:10:29:10:41 | args | this user input |
|
||||
| Mongo.java:21:49:21:52 | json | Mongo.java:10:29:10:41 | args : String[] | Mongo.java:21:49:21:52 | json | Query might include code from $@. | Mongo.java:10:29:10:41 | args | this user input |
|
||||
| Test.java:36:47:36:52 | query1 | Test.java:213:26:213:38 | args : String[] | Test.java:36:47:36:52 | query1 | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input |
|
||||
| Test.java:42:57:42:62 | query2 | Test.java:213:26:213:38 | args : String[] | Test.java:42:57:42:62 | query2 | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input |
|
||||
| Test.java:50:62:50:67 | query3 | Test.java:213:26:213:38 | args : String[] | Test.java:50:62:50:67 | query3 | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input |
|
||||
|
||||
@@ -5,5 +5,6 @@ where
|
||||
controlledString(controlled) and
|
||||
method = controlled.getEnclosingCallable() and
|
||||
line = controlled.getLocation().getStartLine() - method.getLocation().getStartLine() and
|
||||
controlled.getCompilationUnit().fromSource()
|
||||
controlled.getCompilationUnit().fromSource() and
|
||||
controlled.getFile().getStem() = ["Test", "Validation"]
|
||||
select method.getName(), line, controlled
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import semmle.code.java.security.ControlledString
|
||||
|
||||
from Expr precedes, Method method
|
||||
where endsInQuote(precedes) and precedes.getEnclosingCallable() = method
|
||||
where
|
||||
endsInQuote(precedes) and
|
||||
precedes.getEnclosingCallable() = method and
|
||||
precedes.getFile().getStem() = "Test"
|
||||
select method.getName(),
|
||||
precedes.getLocation().getStartLine() - method.getLocation().getStartLine(), precedes
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/mongodbClient
|
||||
@@ -9,5 +9,8 @@ class Conf extends TaintTracking::Configuration {
|
||||
}
|
||||
|
||||
from Conf conf, Expr tainted, Method method
|
||||
where conf.hasFlowToExpr(tainted) and tainted.getEnclosingCallable() = method
|
||||
where
|
||||
conf.hasFlowToExpr(tainted) and
|
||||
tainted.getEnclosingCallable() = method and
|
||||
tainted.getFile().getStem() = ["Test", "Validation"]
|
||||
select method, tainted.getLocation().getStartLine() - method.getLocation().getStartLine(), tainted
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.mongodb;
|
||||
|
||||
public class BasicDBObject implements com.mongodb.DBObject {
|
||||
public static com.mongodb.BasicDBObject parse(java.lang.String json) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
8
java/ql/test/stubs/mongodbClient/com/mongodb/DB.java
Normal file
8
java/ql/test/stubs/mongodbClient/com/mongodb/DB.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package com.mongodb;
|
||||
|
||||
public class DB {
|
||||
|
||||
public com.mongodb.DBCollection getCollection(java.lang.String name) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.mongodb;
|
||||
|
||||
public class DBCollection {
|
||||
public com.mongodb.DBCursor find(com.mongodb.DBObject query) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package com.mongodb;
|
||||
|
||||
public class DBCursor {
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package com.mongodb;
|
||||
|
||||
public abstract interface DBObject {
|
||||
}
|
||||
10
java/ql/test/stubs/mongodbClient/com/mongodb/Mongo.java
Normal file
10
java/ql/test/stubs/mongodbClient/com/mongodb/Mongo.java
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
package com.mongodb;
|
||||
|
||||
public class Mongo {
|
||||
|
||||
public com.mongodb.DB getDB(java.lang.String dbName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.mongodb;
|
||||
|
||||
public class MongoClient extends com.mongodb.Mongo {
|
||||
public MongoClient(com.mongodb.ServerAddress addr) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// Failed to get sources. Instead, stub sources have been generated by the disassembler.
|
||||
// Implementation of methods is unavailable.
|
||||
package com.mongodb;
|
||||
|
||||
public class ServerAddress implements java.io.Serializable {
|
||||
|
||||
public ServerAddress() {
|
||||
}
|
||||
|
||||
public ServerAddress(java.lang.String host) {
|
||||
}
|
||||
|
||||
public ServerAddress(java.net.InetAddress inetAddress) {
|
||||
}
|
||||
|
||||
public ServerAddress(java.net.InetAddress inetAddress, int port) {
|
||||
}
|
||||
|
||||
public ServerAddress(java.net.InetSocketAddress inetSocketAddress) {
|
||||
}
|
||||
|
||||
public ServerAddress(java.lang.String host, int port) {
|
||||
}
|
||||
|
||||
public boolean equals(java.lang.Object o) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public java.lang.String getHost() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public java.net.InetSocketAddress getSocketAddress() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public java.util.List<java.net.InetSocketAddress> getSocketAddresses() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public java.lang.String toString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static java.lang.String defaultHost() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int defaultPort() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean sameHost(java.lang.String hostName) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.mongodb.util;
|
||||
|
||||
public class JSON {
|
||||
|
||||
public static java.lang.Object parse(java.lang.String jsonString) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
22
java/ql/test/stubs/mongodbClient/org/bson/BSONObject.java
Normal file
22
java/ql/test/stubs/mongodbClient/org/bson/BSONObject.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package org.bson;
|
||||
|
||||
public abstract interface BSONObject {
|
||||
|
||||
public abstract java.lang.Object put(java.lang.String arg0, java.lang.Object arg1);
|
||||
|
||||
public abstract void putAll(org.bson.BSONObject arg0);
|
||||
|
||||
public abstract void putAll(java.util.Map arg0);
|
||||
|
||||
public abstract java.lang.Object get(java.lang.String arg0);
|
||||
|
||||
public abstract java.util.Map toMap();
|
||||
|
||||
public abstract java.lang.Object removeField(java.lang.String arg0);
|
||||
|
||||
public abstract boolean containsKey(java.lang.String arg0);
|
||||
|
||||
public abstract boolean containsField(java.lang.String arg0);
|
||||
|
||||
public abstract java.util.Set<java.lang.String> keySet();
|
||||
}
|
||||
@@ -912,7 +912,7 @@ module DataFlow {
|
||||
function.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
override BasicBlock getBasicBlock() { result = function.(ExprOrStmt).getBasicBlock() }
|
||||
override BasicBlock getBasicBlock() { result = function.getExit().getBasicBlock() }
|
||||
|
||||
/**
|
||||
* Gets the function corresponding to this exceptional return node.
|
||||
@@ -938,7 +938,7 @@ module DataFlow {
|
||||
function.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
override BasicBlock getBasicBlock() { result = function.(ExprOrStmt).getBasicBlock() }
|
||||
override BasicBlock getBasicBlock() { result = function.getExit().getBasicBlock() }
|
||||
|
||||
/**
|
||||
* Gets the function corresponding to this return node.
|
||||
|
||||
543
javascript/ql/test/library-tests/DataFlow/basicBlock.expected
Normal file
543
javascript/ql/test/library-tests/DataFlow/basicBlock.expected
Normal file
@@ -0,0 +1,543 @@
|
||||
| arguments.js:1:1:1:0 | this | arguments.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| arguments.js:1:1:12:2 | (functi ... 3);\\n}) | arguments.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| arguments.js:1:1:12:4 | (functi ... );\\n})() | arguments.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| arguments.js:1:1:12:4 | exceptional return of (functi ... );\\n})() | arguments.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| arguments.js:1:2:1:1 | this | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} |
|
||||
| arguments.js:1:2:12:1 | exceptional return of anonymous function | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} |
|
||||
| arguments.js:1:2:12:1 | functio ... , 3);\\n} | arguments.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| arguments.js:1:2:12:1 | return of anonymous function | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} |
|
||||
| arguments.js:2:5:2:4 | this | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:2:5:2:5 | arguments | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:2:5:10:5 | exceptional return of function f | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} |
|
||||
| arguments.js:2:5:10:5 | return of function f | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:2:14:2:14 | f | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} |
|
||||
| arguments.js:2:14:2:14 | f | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} |
|
||||
| arguments.js:2:16:2:16 | x | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:2:16:2:16 | x | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:3:13:3:20 | firstArg | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:3:13:3:24 | firstArg = x | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:3:24:3:24 | x | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:4:13:4:24 | alsoFirstArg | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:4:13:4:39 | alsoFir ... ents[0] | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:4:28:4:36 | arguments | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:4:28:4:39 | arguments[0] | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:4:38:4:38 | 0 | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:5:13:5:21 | secondArg | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:5:13:5:36 | secondA ... ents[1] | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:5:25:5:33 | arguments | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:5:25:5:36 | arguments[1] | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:5:35:5:35 | 1 | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:6:13:6:16 | args | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:6:13:6:28 | args | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:6:13:6:28 | args = arguments | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:6:20:6:28 | arguments | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:7:13:7:20 | thirdArg | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:7:13:7:30 | thirdArg = args[2] | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:7:24:7:27 | args | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:7:24:7:30 | args[2] | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:7:29:7:29 | 2 | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:8:9:8:17 | arguments | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:8:9:8:22 | arguments | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:8:9:8:22 | arguments = {} | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:8:21:8:22 | {} | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:9:13:9:23 | notFirstArg | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:9:13:9:38 | notFirs ... ents[0] | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:9:27:9:35 | arguments | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:9:27:9:38 | arguments[0] | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:9:37:9:37 | 0 | arguments.js:2:5:2:4 | entry node of functio ... ;\\n } |
|
||||
| arguments.js:11:5:11:5 | f | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} |
|
||||
| arguments.js:11:5:11:14 | exceptional return of f(1, 2, 3) | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} |
|
||||
| arguments.js:11:5:11:14 | f(1, 2, 3) | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} |
|
||||
| arguments.js:11:7:11:7 | 1 | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} |
|
||||
| arguments.js:11:10:11:10 | 2 | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} |
|
||||
| arguments.js:11:13:11:13 | 3 | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} |
|
||||
| eval.js:1:1:1:0 | this | eval.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| eval.js:1:1:1:0 | this | eval.js:1:1:1:0 | entry node of functio ... eval`\\n} |
|
||||
| eval.js:1:1:5:1 | exceptional return of function k | eval.js:1:1:1:0 | entry node of functio ... eval`\\n} |
|
||||
| eval.js:1:1:5:1 | functio ... eval`\\n} | eval.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| eval.js:1:1:5:1 | return of function k | eval.js:1:1:1:0 | entry node of functio ... eval`\\n} |
|
||||
| eval.js:1:10:1:10 | k | eval.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| eval.js:2:7:2:7 | x | eval.js:1:1:1:0 | entry node of functio ... eval`\\n} |
|
||||
| eval.js:2:7:2:12 | x | eval.js:1:1:1:0 | entry node of functio ... eval`\\n} |
|
||||
| eval.js:2:7:2:12 | x = 42 | eval.js:1:1:1:0 | entry node of functio ... eval`\\n} |
|
||||
| eval.js:2:11:2:12 | 42 | eval.js:1:1:1:0 | entry node of functio ... eval`\\n} |
|
||||
| eval.js:3:3:3:6 | eval | eval.js:1:1:1:0 | entry node of functio ... eval`\\n} |
|
||||
| eval.js:3:3:3:16 | eval("x = 23") | eval.js:1:1:1:0 | entry node of functio ... eval`\\n} |
|
||||
| eval.js:3:3:3:16 | exceptional return of eval("x = 23") | eval.js:1:1:1:0 | entry node of functio ... eval`\\n} |
|
||||
| eval.js:3:8:3:15 | "x = 23" | eval.js:1:1:1:0 | entry node of functio ... eval`\\n} |
|
||||
| eval.js:4:3:4:3 | x | eval.js:1:1:1:0 | entry node of functio ... eval`\\n} |
|
||||
| sources.js:1:1:1:0 | this | sources.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| sources.js:1:1:1:12 | exceptional return of new (x => x) | sources.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| sources.js:1:1:1:12 | new (x => x) | sources.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| sources.js:1:5:1:12 | (x => x) | sources.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| sources.js:1:6:1:6 | x | sources.js:1:6:1:5 | entry node of x => x |
|
||||
| sources.js:1:6:1:6 | x | sources.js:1:6:1:5 | entry node of x => x |
|
||||
| sources.js:1:6:1:11 | exceptional return of anonymous function | sources.js:1:6:1:5 | entry node of x => x |
|
||||
| sources.js:1:6:1:11 | return of anonymous function | sources.js:1:6:1:5 | entry node of x => x |
|
||||
| sources.js:1:6:1:11 | x => x | sources.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| sources.js:1:11:1:11 | x | sources.js:1:6:1:5 | entry node of x => x |
|
||||
| sources.js:3:1:5:2 | (functi ... +19;\\n}) | sources.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| sources.js:3:1:5:6 | (functi ... \\n})(23) | sources.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| sources.js:3:1:5:6 | exceptional return of (functi ... \\n})(23) | sources.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| sources.js:3:2:3:1 | this | sources.js:3:2:3:1 | entry node of functio ... x+19;\\n} |
|
||||
| sources.js:3:2:5:1 | exceptional return of anonymous function | sources.js:3:2:3:1 | entry node of functio ... x+19;\\n} |
|
||||
| sources.js:3:2:5:1 | functio ... x+19;\\n} | sources.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| sources.js:3:2:5:1 | return of anonymous function | sources.js:3:2:3:1 | entry node of functio ... x+19;\\n} |
|
||||
| sources.js:3:11:3:11 | x | sources.js:3:2:3:1 | entry node of functio ... x+19;\\n} |
|
||||
| sources.js:3:11:3:11 | x | sources.js:3:2:3:1 | entry node of functio ... x+19;\\n} |
|
||||
| sources.js:4:10:4:10 | x | sources.js:3:2:3:1 | entry node of functio ... x+19;\\n} |
|
||||
| sources.js:4:10:4:13 | x+19 | sources.js:3:2:3:1 | entry node of functio ... x+19;\\n} |
|
||||
| sources.js:4:12:4:13 | 19 | sources.js:3:2:3:1 | entry node of functio ... x+19;\\n} |
|
||||
| sources.js:5:4:5:5 | 23 | sources.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| sources.js:7:1:7:3 | /x/ | sources.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| sources.js:9:1:9:0 | this | sources.js:9:1:9:0 | entry node of functio ... ey; }\\n} |
|
||||
| sources.js:9:1:12:1 | exceptional return of function foo | sources.js:12:2:12:1 | exit node of functio ... ey; }\\n} |
|
||||
| sources.js:9:1:12:1 | functio ... ey; }\\n} | sources.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| sources.js:9:1:12:1 | return of function foo | sources.js:12:2:12:1 | exit node of functio ... ey; }\\n} |
|
||||
| sources.js:9:10:9:12 | foo | sources.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| sources.js:9:14:9:18 | array | sources.js:9:1:9:0 | entry node of functio ... ey; }\\n} |
|
||||
| sources.js:9:14:9:18 | array | sources.js:9:1:9:0 | entry node of functio ... ey; }\\n} |
|
||||
| sources.js:10:12:10:14 | key | sources.js:10:8:10:14 | let key |
|
||||
| sources.js:10:12:10:14 | key | sources.js:10:8:10:14 | let key |
|
||||
| sources.js:10:12:10:14 | key | sources.js:10:8:10:14 | let key |
|
||||
| sources.js:10:19:10:23 | array | sources.js:9:1:9:0 | entry node of functio ... ey; }\\n} |
|
||||
| sources.js:10:28:10:30 | key | sources.js:10:8:10:14 | let key |
|
||||
| sources.js:11:12:11:18 | key | sources.js:11:8:11:18 | let { key } |
|
||||
| sources.js:11:12:11:18 | { key } | sources.js:11:8:11:18 | let { key } |
|
||||
| sources.js:11:12:11:18 | { key } | sources.js:11:8:11:18 | let { key } |
|
||||
| sources.js:11:14:11:16 | key | sources.js:11:8:11:18 | let { key } |
|
||||
| sources.js:11:14:11:16 | key | sources.js:11:8:11:18 | let { key } |
|
||||
| sources.js:11:14:11:16 | key | sources.js:11:8:11:18 | let { key } |
|
||||
| sources.js:11:14:11:16 | key | sources.js:11:8:11:18 | let { key } |
|
||||
| sources.js:11:23:11:27 | array | sources.js:11:23:11:27 | array |
|
||||
| sources.js:11:32:11:34 | key | sources.js:11:8:11:18 | let { key } |
|
||||
| tst2.ts:1:1:1:0 | this | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:1:1:1:1 | A | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:1:8:5:1 | A | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:1:8:5:1 | namespa ... lysed\\n} | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:1:18:1:18 | A | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:1:18:1:18 | A | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:2:14:2:14 | x | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:2:14:2:19 | x | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:2:14:2:19 | x = 42 | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:2:18:2:19 | 42 | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:3:3:3:6 | setX | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:3:3:3:8 | exceptional return of setX() | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:3:3:3:8 | setX() | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:4:3:4:3 | x | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:7:1:7:0 | A | tst2.ts:7:1:7:0 | entry node of functio ... = 23;\\n} |
|
||||
| tst2.ts:7:1:7:0 | this | tst2.ts:7:1:7:0 | entry node of functio ... = 23;\\n} |
|
||||
| tst2.ts:7:1:9:1 | exceptional return of function setX | tst2.ts:7:1:7:0 | entry node of functio ... = 23;\\n} |
|
||||
| tst2.ts:7:1:9:1 | functio ... = 23;\\n} | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:7:1:9:1 | return of function setX | tst2.ts:7:1:7:0 | entry node of functio ... = 23;\\n} |
|
||||
| tst2.ts:7:10:7:13 | setX | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:7:10:7:13 | setX | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:8:3:8:3 | A | tst2.ts:7:1:7:0 | entry node of functio ... = 23;\\n} |
|
||||
| tst2.ts:8:3:8:5 | A.x | tst2.ts:7:1:7:0 | entry node of functio ... = 23;\\n} |
|
||||
| tst2.ts:8:3:8:10 | A.x = 23 | tst2.ts:7:1:7:0 | entry node of functio ... = 23;\\n} |
|
||||
| tst2.ts:8:5:8:5 | x | tst2.ts:7:1:7:0 | entry node of functio ... = 23;\\n} |
|
||||
| tst2.ts:8:9:8:10 | 23 | tst2.ts:7:1:7:0 | entry node of functio ... = 23;\\n} |
|
||||
| tst2.ts:11:5:11:7 | nd2 | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:11:5:11:23 | nd2 = A.x as number | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:11:11:11:11 | A | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:11:11:11:13 | A.x | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:11:11:11:23 | A.x as number | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:11:13:11:13 | x | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:13:1:13:40 | class S ... ing> {} | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:13:7:13:16 | StringList | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:13:26:13:29 | List | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:13:26:13:37 | List<string> | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:13:39:13:38 | (...arg ... rgs); } | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:13:39:13:38 | ...args | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } |
|
||||
| tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } |
|
||||
| tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } |
|
||||
| tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } |
|
||||
| tst2.ts:13:39:13:38 | constru ... rgs); } | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:13:39:13:38 | constru ... rgs); } | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:13:39:13:38 | constructor | tst2.ts:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst2.ts:13:39:13:38 | exceptional return of default constructor of class StringList | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } |
|
||||
| tst2.ts:13:39:13:38 | exceptional return of super(...args) | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } |
|
||||
| tst2.ts:13:39:13:38 | return of default constructor of class StringList | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } |
|
||||
| tst2.ts:13:39:13:38 | super | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } |
|
||||
| tst2.ts:13:39:13:38 | super(...args) | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } |
|
||||
| tst2.ts:13:39:13:38 | this | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } |
|
||||
| tst.js:1:1:1:0 | this | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:1:1:1:1 | x | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:1:1:1:24 | import ... m 'fs'; | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:1:10:1:11 | fs | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:1:10:1:11 | fs | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:3:5:3:5 | x | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:3:5:3:5 | x | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:3:5:3:10 | x | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:3:5:3:10 | x = 42 | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:3:9:3:10 | 42 | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:4:5:4:5 | y | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:4:5:4:12 | y | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:4:5:4:12 | y = "hi" | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:4:9:4:12 | "hi" | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:5:5:5:5 | z | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:5:5:5:5 | z | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:7:1:7:2 | fs | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:8:1:8:1 | x | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:9:1:9:3 | (x) | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:9:2:9:2 | x | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:10:1:10:1 | x | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:10:1:10:4 | x, y | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:10:4:10:4 | y | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:11:1:11:1 | x | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:11:1:11:1 | x | tst.js:11:1:11:1 | guard: x is false |
|
||||
| tst.js:11:1:11:1 | x | tst.js:11:1:11:1 | guard: x is true |
|
||||
| tst.js:11:1:11:6 | x && y | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:11:6:11:6 | y | tst.js:11:1:11:1 | guard: x is true |
|
||||
| tst.js:12:1:12:1 | x | tst.js:12:1:12:1 | guard: x is false |
|
||||
| tst.js:12:1:12:1 | x | tst.js:12:1:12:1 | guard: x is true |
|
||||
| tst.js:12:1:12:1 | x | tst.js:12:1:12:7 | x \|\| y; |
|
||||
| tst.js:12:1:12:1 | x | tst.js:12:1:12:7 | x \|\| y; |
|
||||
| tst.js:12:1:12:6 | x \|\| y | tst.js:12:1:12:7 | x \|\| y; |
|
||||
| tst.js:12:6:12:6 | y | tst.js:12:1:12:1 | guard: x is false |
|
||||
| tst.js:13:1:13:1 | x | tst.js:13:1:13:6 | z = y; |
|
||||
| tst.js:13:1:13:1 | z | tst.js:13:1:13:6 | z = y; |
|
||||
| tst.js:13:1:13:5 | z | tst.js:13:1:13:6 | z = y; |
|
||||
| tst.js:13:1:13:5 | z = y | tst.js:13:1:13:6 | z = y; |
|
||||
| tst.js:13:5:13:5 | y | tst.js:13:1:13:6 | z = y; |
|
||||
| tst.js:14:1:14:1 | z | tst.js:13:1:13:6 | z = y; |
|
||||
| tst.js:14:1:14:9 | z ? x : y | tst.js:13:1:13:6 | z = y; |
|
||||
| tst.js:14:5:14:5 | x | tst.js:14:1:14:1 | guard: z is true |
|
||||
| tst.js:14:9:14:9 | y | tst.js:14:1:14:1 | guard: z is false |
|
||||
| tst.js:16:1:20:2 | (functi ... "";\\n}) | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:16:1:20:9 | (functi ... ("arg") | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:16:1:20:9 | exceptional return of (functi ... ("arg") | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:16:2:16:1 | this | tst.js:16:2:16:1 | entry node of functio ... n "";\\n} |
|
||||
| tst.js:16:2:20:1 | exceptional return of function f | tst.js:20:2:20:1 | exit node of functio ... n "";\\n} |
|
||||
| tst.js:16:2:20:1 | functio ... n "";\\n} | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:16:2:20:1 | return of function f | tst.js:20:2:20:1 | exit node of functio ... n "";\\n} |
|
||||
| tst.js:16:11:16:11 | f | tst.js:16:2:16:1 | entry node of functio ... n "";\\n} |
|
||||
| tst.js:16:13:16:13 | a | tst.js:16:2:16:1 | entry node of functio ... n "";\\n} |
|
||||
| tst.js:16:13:16:13 | a | tst.js:16:2:16:1 | entry node of functio ... n "";\\n} |
|
||||
| tst.js:17:7:17:10 | Math | tst.js:16:2:16:1 | entry node of functio ... n "";\\n} |
|
||||
| tst.js:17:7:17:17 | Math.random | tst.js:16:2:16:1 | entry node of functio ... n "";\\n} |
|
||||
| tst.js:17:7:17:19 | Math.random() | tst.js:16:2:16:1 | entry node of functio ... n "";\\n} |
|
||||
| tst.js:17:7:17:19 | exceptional return of Math.random() | tst.js:16:2:16:1 | entry node of functio ... n "";\\n} |
|
||||
| tst.js:17:7:17:25 | Math.random() > 0.5 | tst.js:16:2:16:1 | entry node of functio ... n "";\\n} |
|
||||
| tst.js:17:12:17:17 | random | tst.js:16:2:16:1 | entry node of functio ... n "";\\n} |
|
||||
| tst.js:17:23:17:25 | 0.5 | tst.js:16:2:16:1 | entry node of functio ... n "";\\n} |
|
||||
| tst.js:18:12:18:12 | a | tst.js:17:7:17:25 | guard: Math.random() > 0.5 is true |
|
||||
| tst.js:19:10:19:11 | "" | tst.js:17:7:17:25 | guard: Math.random() > 0.5 is false |
|
||||
| tst.js:20:4:20:8 | "arg" | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:22:5:22:20 | { readFileSync } | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:22:5:22:25 | readFileSync | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:22:5:22:25 | { readF ... } = fs | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:22:7:22:18 | readFileSync | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:22:7:22:18 | readFileSync | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:22:7:22:18 | readFileSync | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:22:7:22:18 | readFileSync | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:22:24:22:25 | fs | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:23:1:23:12 | readFileSync | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:25:1:25:3 | ++x | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:25:1:25:3 | x | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:25:3:25:3 | x | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:26:1:26:1 | x | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:28:1:30:1 | (() =>\\n ... ables\\n) | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:28:1:30:3 | (() =>\\n ... les\\n)() | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:28:1:30:3 | exceptional return of (() =>\\n ... les\\n)() | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:28:2:28:1 | x | tst.js:28:2:28:1 | entry node of () =>\\n x |
|
||||
| tst.js:28:2:29:3 | () =>\\n x | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:28:2:29:3 | exceptional return of anonymous function | tst.js:28:2:28:1 | entry node of () =>\\n x |
|
||||
| tst.js:28:2:29:3 | return of anonymous function | tst.js:28:2:28:1 | entry node of () =>\\n x |
|
||||
| tst.js:29:3:29:3 | x | tst.js:28:2:28:1 | entry node of () =>\\n x |
|
||||
| tst.js:32:1:32:0 | this | tst.js:32:1:32:0 | entry node of functio ... ables\\n} |
|
||||
| tst.js:32:1:32:0 | x | tst.js:32:1:32:0 | entry node of functio ... ables\\n} |
|
||||
| tst.js:32:1:34:1 | exceptional return of function g | tst.js:32:1:32:0 | entry node of functio ... ables\\n} |
|
||||
| tst.js:32:1:34:1 | functio ... ables\\n} | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:32:1:34:1 | return of function g | tst.js:32:1:32:0 | entry node of functio ... ables\\n} |
|
||||
| tst.js:32:10:32:10 | g | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:32:10:32:10 | g | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:32:12:32:12 | b | tst.js:32:1:32:0 | entry node of functio ... ables\\n} |
|
||||
| tst.js:33:10:33:10 | x | tst.js:32:1:32:0 | entry node of functio ... ables\\n} |
|
||||
| tst.js:35:1:35:1 | g | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:35:1:35:7 | exceptional return of g(true) | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:35:1:35:7 | g(true) | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:35:3:35:6 | true | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:37:5:37:5 | o | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:37:5:42:1 | o | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:37:5:42:1 | o = {\\n ... ;\\n }\\n} | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:37:9:42:1 | {\\n x: ... ;\\n }\\n} | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:38:3:38:3 | x | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:38:3:38:9 | x: null | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:38:3:38:9 | x: null | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:38:6:38:9 | null | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:39:3:39:3 | m | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:39:3:41:3 | m() {\\n this;\\n } | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:39:3:41:3 | m() {\\n this;\\n } | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:39:4:39:3 | this | tst.js:39:4:39:3 | entry node of () {\\n this;\\n } |
|
||||
| tst.js:39:4:41:3 | () {\\n this;\\n } | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:39:4:41:3 | exceptional return of method m | tst.js:39:4:39:3 | entry node of () {\\n this;\\n } |
|
||||
| tst.js:39:4:41:3 | return of method m | tst.js:39:4:39:3 | entry node of () {\\n this;\\n } |
|
||||
| tst.js:40:5:40:8 | this | tst.js:39:4:39:3 | entry node of () {\\n this;\\n } |
|
||||
| tst.js:43:1:43:1 | o | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:43:1:43:3 | o.x | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:43:3:43:3 | x | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:44:1:44:1 | o | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:44:1:44:3 | o.m | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:44:1:44:5 | exceptional return of o.m() | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:44:1:44:5 | o.m() | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:44:3:44:3 | m | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:46:1:46:6 | global | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:46:1:46:11 | global = "" | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:46:10:46:11 | "" | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:47:1:47:6 | global | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:49:1:54:1 | A | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:49:1:54:1 | class A ... `\\n }\\n} | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:49:7:49:7 | A | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:49:17:49:17 | B | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:50:3:50:13 | constructor | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:50:3:53:3 | constru ... et`\\n } | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:50:3:53:3 | constru ... et`\\n } | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:50:14:50:13 | this | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } |
|
||||
| tst.js:50:14:53:3 | () {\\n ... et`\\n } | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:50:14:53:3 | exceptional return of constructor of class A | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } |
|
||||
| tst.js:50:14:53:3 | return of constructor of class A | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } |
|
||||
| tst.js:51:5:51:9 | super | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } |
|
||||
| tst.js:51:5:51:13 | exceptional return of super(42) | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } |
|
||||
| tst.js:51:5:51:13 | super(42) | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } |
|
||||
| tst.js:51:11:51:12 | 42 | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } |
|
||||
| tst.js:52:5:52:14 | new.target | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } |
|
||||
| tst.js:55:1:55:1 | A | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:57:1:57:9 | `x: ${x}` | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:57:2:57:4 | x: | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:57:7:57:7 | x | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:58:1:58:3 | tag | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:58:1:58:13 | tag `x: ${x}` | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:58:5:58:13 | `x: ${x}` | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:58:6:58:8 | x: | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:58:11:58:11 | x | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:60:1:60:1 | g | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:61:1:61:5 | ::o.m | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:61:3:61:3 | o | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:61:3:61:5 | o.m | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:61:5:61:5 | m | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:62:1:62:1 | o | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:62:1:62:4 | o::g | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:62:4:62:4 | g | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:64:1:64:0 | this | tst.js:64:1:64:0 | entry node of functio ... lysed\\n} |
|
||||
| tst.js:64:1:67:1 | exceptional return of function h | tst.js:64:1:64:0 | entry node of functio ... lysed\\n} |
|
||||
| tst.js:64:1:67:1 | functio ... lysed\\n} | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:64:1:67:1 | return of function h | tst.js:64:1:64:0 | entry node of functio ... lysed\\n} |
|
||||
| tst.js:64:11:64:11 | h | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:64:11:64:11 | h | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:65:3:65:10 | yield 42 | tst.js:64:1:64:0 | entry node of functio ... lysed\\n} |
|
||||
| tst.js:65:9:65:10 | 42 | tst.js:64:1:64:0 | entry node of functio ... lysed\\n} |
|
||||
| tst.js:66:7:66:9 | tmp | tst.js:64:1:64:0 | entry node of functio ... lysed\\n} |
|
||||
| tst.js:66:7:66:25 | tmp = function.sent | tst.js:64:1:64:0 | entry node of functio ... lysed\\n} |
|
||||
| tst.js:66:13:66:25 | function.sent | tst.js:64:1:64:0 | entry node of functio ... lysed\\n} |
|
||||
| tst.js:68:5:68:8 | iter | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:68:5:68:14 | iter | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:68:5:68:14 | iter = h() | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:68:12:68:12 | h | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:68:12:68:14 | exceptional return of h() | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:68:12:68:14 | h() | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:69:1:69:4 | iter | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:69:1:69:9 | iter.next | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:69:1:69:13 | exceptional return of iter.next(23) | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:69:1:69:13 | iter.next(23) | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:69:6:69:9 | next | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:69:11:69:12 | 23 | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:71:1:71:0 | this | tst.js:71:1:71:0 | entry node of async f ... lysed\\n} |
|
||||
| tst.js:71:1:73:1 | async f ... lysed\\n} | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:71:1:73:1 | exceptional return of function k | tst.js:71:1:71:0 | entry node of async f ... lysed\\n} |
|
||||
| tst.js:71:1:73:1 | return of function k | tst.js:71:1:71:0 | entry node of async f ... lysed\\n} |
|
||||
| tst.js:71:16:71:16 | k | tst.js:1:1:1:0 | entry node of <toplevel> |
|
||||
| tst.js:72:3:72:11 | await p() | tst.js:71:1:71:0 | entry node of async f ... lysed\\n} |
|
||||
| tst.js:72:9:72:9 | p | tst.js:71:1:71:0 | entry node of async f ... lysed\\n} |
|
||||
| tst.js:72:9:72:11 | exceptional return of p() | tst.js:71:1:71:0 | entry node of async f ... lysed\\n} |
|
||||
| tst.js:72:9:72:11 | p() | tst.js:71:1:71:0 | entry node of async f ... lysed\\n} |
|
||||
| tst.js:75:5:75:5 | m | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:75:5:75:21 | m = import('foo') | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:75:9:75:21 | import('foo') | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:75:16:75:20 | 'foo' | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:77:10:77:10 | i | tst.js:77:6:77:10 | let i |
|
||||
| tst.js:77:10:77:10 | i | tst.js:77:6:77:10 | let i |
|
||||
| tst.js:77:10:77:10 | i | tst.js:77:6:77:10 | let i |
|
||||
| tst.js:77:15:77:15 | o | tst.js:16:1:20:10 | (functi ... "arg"); |
|
||||
| tst.js:78:3:78:3 | i | tst.js:77:6:77:10 | let i |
|
||||
| tst.js:80:10:80:10 | v | tst.js:80:6:80:10 | let v |
|
||||
| tst.js:80:10:80:10 | v | tst.js:80:6:80:10 | let v |
|
||||
| tst.js:80:10:80:10 | v | tst.js:80:6:80:10 | let v |
|
||||
| tst.js:80:15:80:15 | o | tst.js:80:15:80:15 | o |
|
||||
| tst.js:81:3:81:3 | v | tst.js:80:6:80:10 | let v |
|
||||
| tst.js:83:5:83:7 | vs1 | tst.js:83:1:83:29 | var vs1 ... o) v ]; |
|
||||
| tst.js:83:5:83:28 | vs1 = [ ... o) v ] | tst.js:83:5:83:28 | vs1 = [ ... o) v ] |
|
||||
| tst.js:83:11:83:28 | [ for (v of o) v ] | tst.js:83:1:83:29 | var vs1 ... o) v ]; |
|
||||
| tst.js:83:13:83:24 | for (v of o) | tst.js:83:1:83:29 | var vs1 ... o) v ]; |
|
||||
| tst.js:83:18:83:18 | v | tst.js:83:18:83:18 | v |
|
||||
| tst.js:83:18:83:18 | v | tst.js:83:18:83:18 | v |
|
||||
| tst.js:83:23:83:23 | o | tst.js:83:1:83:29 | var vs1 ... o) v ]; |
|
||||
| tst.js:83:26:83:26 | v | tst.js:83:18:83:18 | v |
|
||||
| tst.js:85:5:85:7 | vs2 | tst.js:83:5:83:28 | vs1 = [ ... o) v ] |
|
||||
| tst.js:85:5:85:28 | vs2 = ( ... o) v ) | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:85:11:85:28 | ( for (v of o) v ) | tst.js:83:5:83:28 | vs1 = [ ... o) v ] |
|
||||
| tst.js:85:13:85:24 | for (v of o) | tst.js:83:5:83:28 | vs1 = [ ... o) v ] |
|
||||
| tst.js:85:18:85:18 | v | tst.js:85:18:85:18 | v |
|
||||
| tst.js:85:18:85:18 | v | tst.js:85:18:85:18 | v |
|
||||
| tst.js:85:23:85:23 | o | tst.js:83:5:83:28 | vs1 = [ ... o) v ] |
|
||||
| tst.js:85:26:85:26 | v | tst.js:85:18:85:18 | v |
|
||||
| tst.js:87:1:92:2 | (functi ... + z;\\n}) | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:87:1:96:2 | (functi ... r: 0\\n}) | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:87:1:96:2 | exceptional return of (functi ... r: 0\\n}) | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:87:2:87:1 | this | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:87:2:92:1 | exceptional return of anonymous function | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:87:2:92:1 | functio ... + z;\\n} | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:87:2:92:1 | return of anonymous function | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:87:11:87:24 | o | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:87:11:87:24 | x | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:87:11:87:24 | { p: x, ...o } | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:87:13:87:13 | p | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:87:13:87:16 | p: x | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:87:13:87:16 | p: x | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:87:16:87:16 | x | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:87:22:87:22 | ...o | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:87:22:87:22 | o | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:88:7:88:14 | { q: y } | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:88:7:88:18 | y | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:88:7:88:18 | { q: y } = o | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:88:9:88:9 | q | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:88:9:88:12 | q: y | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:88:9:88:12 | q: y | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:88:12:88:12 | y | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:88:18:88:18 | o | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:89:7:89:7 | z | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:89:7:89:7 | z | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:90:3:90:16 | ({ r: z } = o) | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:90:4:90:11 | { r: z } | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:90:4:90:15 | z | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:90:4:90:15 | { r: z } = o | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:90:6:90:6 | r | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:90:6:90:9 | r: z | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:90:6:90:9 | r: z | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:90:9:90:9 | z | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:90:15:90:15 | o | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:91:10:91:10 | x | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:91:10:91:14 | x + y | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:91:10:91:18 | x + y + z | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:91:14:91:14 | y | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:91:18:91:18 | z | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:92:4:96:1 | {\\n p: ... r: 0\\n} | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:93:3:93:3 | p | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:93:3:93:7 | p: 19 | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:93:3:93:7 | p: 19 | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:93:6:93:7 | 19 | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:94:3:94:3 | q | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:94:3:94:7 | q: 23 | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:94:3:94:7 | q: 23 | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:94:6:94:7 | 23 | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:95:3:95:3 | r | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:95:3:95:6 | r: 0 | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:95:3:95:6 | r: 0 | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:95:6:95:6 | 0 | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:98:1:103:2 | (functi ... + z;\\n}) | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:98:1:103:17 | (functi ... 3, 0 ]) | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:98:1:103:17 | exceptional return of (functi ... 3, 0 ]) | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:98:2:98:1 | this | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:98:2:103:1 | exceptional return of anonymous function | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:98:2:103:1 | functio ... + z;\\n} | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:98:2:103:1 | return of anonymous function | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:98:11:98:24 | [ x, ...rest ] | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:98:11:98:24 | rest | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:98:11:98:24 | x | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:98:13:98:13 | x | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:98:13:98:13 | x | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:98:19:98:22 | ...rest | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:98:19:98:22 | rest | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:99:7:99:11 | [ y ] | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:99:7:99:18 | [ y ] = rest | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:99:7:99:18 | y | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:99:9:99:9 | y | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:99:9:99:9 | y | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:99:15:99:18 | rest | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:100:7:100:7 | z | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:100:7:100:7 | z | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:101:3:101:9 | [ , z ] | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:101:3:101:16 | [ , z ] = rest | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:101:3:101:16 | z | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:101:7:101:7 | z | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:101:7:101:7 | z | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:101:13:101:16 | rest | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:102:10:102:10 | x | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:102:10:102:14 | x + y | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:102:10:102:18 | x + y + z | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:102:14:102:14 | y | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:102:18:102:18 | z | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} |
|
||||
| tst.js:103:4:103:16 | [ 19, 23, 0 ] | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:103:6:103:7 | 19 | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:103:6:103:7 | 19 | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:103:10:103:11 | 23 | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:103:10:103:11 | 23 | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:103:14:103:14 | 0 | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:103:14:103:14 | 0 | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:105:1:105:1 | x | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:105:1:105:6 | x ?? y | tst.js:85:5:85:28 | vs2 = ( ... o) v ) |
|
||||
| tst.js:105:6:105:6 | y | tst.js:105:6:105:6 | y |
|
||||
| tst.js:107:1:113:2 | (functi ... v2c;\\n}) | tst.js:107:1:113:3 | (functi ... 2c;\\n}); |
|
||||
| tst.js:107:2:107:1 | this | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:107:2:113:1 | exceptional return of anonymous function | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:107:2:113:1 | functio ... v2c;\\n} | tst.js:107:1:113:3 | (functi ... 2c;\\n}); |
|
||||
| tst.js:107:2:113:1 | return of anonymous function | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:6:108:32 | {v1a, v ... = o1c} | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:6:108:38 | v1a | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:6:108:38 | v1b | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:6:108:38 | v1c | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:6:108:38 | {v1a, v ... } = o1d | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:7:108:9 | v1a | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:7:108:9 | v1a | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:7:108:9 | v1a | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:7:108:9 | v1a | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:12:108:14 | v1b | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:12:108:14 | v1b | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:12:108:20 | v1b = o1b | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:12:108:20 | v1b = o1b | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:18:108:20 | o1b | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:23:108:25 | v1c | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:23:108:25 | v1c | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:23:108:31 | v1c = o1c | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:23:108:31 | v1c = o1c | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:29:108:31 | o1c | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:108:36:108:38 | o1d | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:109:2:109:4 | v1a | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:109:2:109:10 | v1a + v1b | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:109:2:109:16 | v1a + v1b + v1c | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:109:8:109:10 | v1b | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:109:14:109:16 | v1c | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:111:6:111:32 | [v2a, v ... = o2c] | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:111:6:111:38 | [v2a, v ... ] = o2d | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:111:6:111:38 | v2a | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:111:6:111:38 | v2b | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:111:6:111:38 | v2c | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:111:7:111:9 | v2a | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:111:7:111:9 | v2a | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:111:12:111:14 | v2b | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:111:12:111:14 | v2b | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:111:18:111:20 | o2b | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:111:23:111:25 | v2c | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:111:23:111:25 | v2c | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:111:29:111:31 | o2c | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:111:36:111:38 | o2d | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:112:2:112:4 | v2a | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:112:2:112:10 | v2a + v2b | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:112:2:112:16 | v2a + v2b + v2c | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:112:8:112:10 | v2b | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:112:14:112:16 | v2c | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} |
|
||||
| tst.js:115:1:115:5 | Array | tst.js:107:1:113:3 | (functi ... 2c;\\n}); |
|
||||
| tst.js:115:1:115:10 | Array.call | tst.js:107:1:113:3 | (functi ... 2c;\\n}); |
|
||||
| tst.js:115:1:115:12 | Array.call() | tst.js:107:1:113:3 | (functi ... 2c;\\n}); |
|
||||
| tst.js:115:1:115:12 | exceptional return of Array.call() | tst.js:107:1:113:3 | (functi ... 2c;\\n}); |
|
||||
| tst.js:115:1:115:12 | reflective call | tst.js:107:1:113:3 | (functi ... 2c;\\n}); |
|
||||
| tst.js:115:7:115:10 | call | tst.js:107:1:113:3 | (functi ... 2c;\\n}); |
|
||||
| tst.js:117:5:117:6 | x2 | tst.js:107:1:113:3 | (functi ... 2c;\\n}); |
|
||||
| tst.js:117:5:117:24 | x2 = Object.seal(x1) | tst.js:107:1:113:3 | (functi ... 2c;\\n}); |
|
||||
| tst.js:117:10:117:15 | Object | tst.js:107:1:113:3 | (functi ... 2c;\\n}); |
|
||||
| tst.js:117:10:117:20 | Object.seal | tst.js:107:1:113:3 | (functi ... 2c;\\n}); |
|
||||
| tst.js:117:10:117:24 | Object.seal(x1) | tst.js:107:1:113:3 | (functi ... 2c;\\n}); |
|
||||
| tst.js:117:10:117:24 | exceptional return of Object.seal(x1) | tst.js:107:1:113:3 | (functi ... 2c;\\n}); |
|
||||
| tst.js:117:17:117:20 | seal | tst.js:107:1:113:3 | (functi ... 2c;\\n}); |
|
||||
| tst.js:117:22:117:23 | x1 | tst.js:107:1:113:3 | (functi ... 2c;\\n}); |
|
||||
4
javascript/ql/test/library-tests/DataFlow/basicBlock.ql
Normal file
4
javascript/ql/test/library-tests/DataFlow/basicBlock.ql
Normal file
@@ -0,0 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from DataFlow::Node node
|
||||
select node, node.getBasicBlock()
|
||||
282
python/ql/src/experimental/dataflow/TypeTracker.qll
Normal file
282
python/ql/src/experimental/dataflow/TypeTracker.qll
Normal file
@@ -0,0 +1,282 @@
|
||||
/** Step Summaries and Type Tracking */
|
||||
|
||||
import python
|
||||
import internal.DataFlowPublic
|
||||
import internal.DataFlowPrivate
|
||||
|
||||
/** Any string that may appear as the name of an attribute or access path. */
|
||||
class AttributeName extends string {
|
||||
AttributeName() { this = any(Attribute a).getName() }
|
||||
}
|
||||
|
||||
/** Either an attribute name, or the empty string (representing no attribute). */
|
||||
class OptionalAttributeName extends string {
|
||||
OptionalAttributeName() { this instanceof AttributeName or this = "" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A description of a step on an inter-procedural data flow path.
|
||||
*/
|
||||
private newtype TStepSummary =
|
||||
LevelStep() or
|
||||
CallStep() or
|
||||
ReturnStep() or
|
||||
StoreStep(AttributeName attr) or
|
||||
LoadStep(AttributeName attr)
|
||||
|
||||
/**
|
||||
* INTERNAL: Use `TypeTracker` or `TypeBackTracker` instead.
|
||||
*
|
||||
* A description of a step on an inter-procedural data flow path.
|
||||
*/
|
||||
class StepSummary extends TStepSummary {
|
||||
/** Gets a textual representation of this step summary. */
|
||||
string toString() {
|
||||
this instanceof LevelStep and result = "level"
|
||||
or
|
||||
this instanceof CallStep and result = "call"
|
||||
or
|
||||
this instanceof ReturnStep and result = "return"
|
||||
or
|
||||
exists(string attr | this = StoreStep(attr) | result = "store " + attr)
|
||||
or
|
||||
exists(string attr | this = LoadStep(attr) | result = "load " + attr)
|
||||
}
|
||||
}
|
||||
|
||||
module StepSummary {
|
||||
cached
|
||||
predicate step(Node nodeFrom, Node nodeTo, StepSummary summary) {
|
||||
exists(Node mid | EssaFlow::essaFlowStep*(nodeFrom, mid) and smallstep(mid, nodeTo, summary))
|
||||
}
|
||||
|
||||
predicate smallstep(Node nodeFrom, Node nodeTo, StepSummary summary) {
|
||||
EssaFlow::essaFlowStep(nodeFrom, nodeTo) and
|
||||
summary = LevelStep()
|
||||
or
|
||||
callStep(nodeFrom, nodeTo) and summary = CallStep()
|
||||
or
|
||||
returnStep(nodeFrom, nodeTo) and
|
||||
summary = ReturnStep()
|
||||
or
|
||||
exists(string attr |
|
||||
basicStoreStep(nodeFrom, nodeTo, attr) and
|
||||
summary = StoreStep(attr)
|
||||
or
|
||||
basicLoadStep(nodeFrom, nodeTo, attr) and summary = LoadStep(attr)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call. */
|
||||
predicate callStep(ArgumentNode nodeFrom, ParameterNode nodeTo) {
|
||||
// TODO: Support special methods?
|
||||
exists(DataFlowCall call, int i |
|
||||
nodeFrom.argumentOf(call, i) and nodeTo.isParameterOf(call.getCallable(), i)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `nodeFrom` steps to `nodeTo` by being returned from a call. */
|
||||
predicate returnStep(ReturnNode nodeFrom, Node nodeTo) {
|
||||
exists(DataFlowCall call |
|
||||
nodeFrom.getEnclosingCallable() = call.getCallable() and nodeTo.asCfgNode() = call.getNode()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `nodeFrom` is being written to the `attr` attribute of the object in `nodeTo`.
|
||||
*
|
||||
* Note that the choice of `nodeTo` does not have to make sense "chronologically".
|
||||
* All we care about is whether the `attr` attribute of `nodeTo` can have a specific type,
|
||||
* and the assumption is that if a specific type appears here, then any access of that
|
||||
* particular attribute can yield something of that particular type.
|
||||
*
|
||||
* Thus, in an example such as
|
||||
*
|
||||
* ```python
|
||||
* def foo(y):
|
||||
* x = Foo()
|
||||
* bar(x)
|
||||
* x.attr = y
|
||||
* baz(x)
|
||||
*
|
||||
* def bar(x):
|
||||
* z = x.attr
|
||||
* ```
|
||||
* for the attribute write `x.attr = y`, we will have `attr` being the literal string `"attr"`,
|
||||
* `nodeFrom` will be `y`, and `nodeTo` will be the object `Foo()` created on the first line of the
|
||||
* function. This means we will track the fact that `x.attr` can have the type of `y` into the
|
||||
* assignment to `z` inside `bar`, even though this attribute write happens _after_ `bar` is called.
|
||||
*/
|
||||
predicate basicStoreStep(Node nodeFrom, Node nodeTo, string attr) {
|
||||
exists(AttributeAssignment a, Node var |
|
||||
a.getName() = attr and
|
||||
EssaFlow::essaFlowStep*(nodeTo, var) and
|
||||
var.asVar() = a.getInput() and
|
||||
nodeFrom.asCfgNode() = a.getValue()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `nodeTo` is the result of accessing the `attr` attribute of `nodeFrom`.
|
||||
*/
|
||||
predicate basicLoadStep(Node nodeFrom, Node nodeTo, string attr) {
|
||||
exists(AttrNode s | nodeTo.asCfgNode() = s and s.getObject(attr) = nodeFrom.asCfgNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility class that is equivalent to `boolean` but does not require type joining.
|
||||
*/
|
||||
private class Boolean extends boolean {
|
||||
Boolean() { this = true or this = false }
|
||||
}
|
||||
|
||||
private newtype TTypeTracker = MkTypeTracker(Boolean hasCall, OptionalAttributeName attr)
|
||||
|
||||
/**
|
||||
* Summary of the steps needed to track a value to a given dataflow node.
|
||||
*
|
||||
* This can be used to track objects that implement a certain API in order to
|
||||
* recognize calls to that API. Note that type-tracking does not by itself provide a
|
||||
* source/sink relation, that is, it may determine that a node has a given type,
|
||||
* but it won't determine where that type came from.
|
||||
*
|
||||
* It is recommended that all uses of this type are written in the following form,
|
||||
* for tracking some type `myType`:
|
||||
* ```
|
||||
* Node myType(DataFlow::TypeTracker t) {
|
||||
* t.start() and
|
||||
* result = < source of myType >
|
||||
* or
|
||||
* exists (TypeTracker t2 |
|
||||
* result = myType(t2).track(t2, t)
|
||||
* )
|
||||
* }
|
||||
*
|
||||
* DataFlow::SourceNode myType() { result = myType(DataFlow::TypeTracker::end()) }
|
||||
* ```
|
||||
*
|
||||
* Instead of `result = myType(t2).track(t2, t)`, you can also use the equivalent
|
||||
* `t = t2.step(myType(t2), result)`. If you additionally want to track individual
|
||||
* intra-procedural steps, use `t = t2.smallstep(myCallback(t2), result)`.
|
||||
*/
|
||||
class TypeTracker extends TTypeTracker {
|
||||
Boolean hasCall;
|
||||
OptionalAttributeName attr;
|
||||
|
||||
TypeTracker() { this = MkTypeTracker(hasCall, attr) }
|
||||
|
||||
/** Gets the summary resulting from appending `step` to this type-tracking summary. */
|
||||
cached
|
||||
TypeTracker append(StepSummary step) {
|
||||
step = LevelStep() and result = this
|
||||
or
|
||||
step = CallStep() and result = MkTypeTracker(true, attr)
|
||||
or
|
||||
step = ReturnStep() and hasCall = false and result = this
|
||||
or
|
||||
step = LoadStep(attr) and result = MkTypeTracker(hasCall, "")
|
||||
or
|
||||
exists(string p | step = StoreStep(p) and attr = "" and result = MkTypeTracker(hasCall, p))
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this summary. */
|
||||
string toString() {
|
||||
exists(string withCall, string withAttr |
|
||||
(if hasCall = true then withCall = "with" else withCall = "without") and
|
||||
(if attr != "" then withAttr = " with attribute " + attr else withAttr = "") and
|
||||
result = "type tracker " + withCall + " call steps" + withAttr
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this is the starting point of type tracking.
|
||||
*/
|
||||
predicate start() { hasCall = false and attr = "" }
|
||||
|
||||
/**
|
||||
* Holds if this is the starting point of type tracking, and the value starts in the attribute named `attrName`.
|
||||
* The type tracking only ends after the attribute has been loaded.
|
||||
*/
|
||||
predicate startInAttr(AttributeName attrName) { hasCall = false and attr = attrName }
|
||||
|
||||
/**
|
||||
* Holds if this is the starting point of type tracking
|
||||
* when tracking a parameter into a call, but not out of it.
|
||||
*/
|
||||
predicate call() { hasCall = true and attr = "" }
|
||||
|
||||
/**
|
||||
* Holds if this is the end point of type tracking.
|
||||
*/
|
||||
predicate end() { attr = "" }
|
||||
|
||||
/**
|
||||
* INTERNAL. DO NOT USE.
|
||||
*
|
||||
* Holds if this type has been tracked into a call.
|
||||
*/
|
||||
boolean hasCall() { result = hasCall }
|
||||
|
||||
/**
|
||||
* INTERNAL. DO NOT USE.
|
||||
*
|
||||
* Gets the attribute associated with this type tracker.
|
||||
*/
|
||||
string getAttr() { result = attr }
|
||||
|
||||
/**
|
||||
* Gets a type tracker that starts where this one has left off to allow continued
|
||||
* tracking.
|
||||
*
|
||||
* This predicate is only defined if the type has not been tracked into an attribute.
|
||||
*/
|
||||
TypeTracker continue() { attr = "" and result = this }
|
||||
|
||||
/**
|
||||
* Gets the summary that corresponds to having taken a forwards
|
||||
* heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
|
||||
*/
|
||||
pragma[inline]
|
||||
TypeTracker step(Node nodeFrom, Node nodeTo) {
|
||||
exists(StepSummary summary |
|
||||
StepSummary::step(nodeFrom, nodeTo, summary) and
|
||||
result = this.append(summary)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the summary that corresponds to having taken a forwards
|
||||
* local, heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
|
||||
*
|
||||
* Unlike `TypeTracker::step`, this predicate exposes all edges
|
||||
* in the flow graph, and not just the edges between `Node`s.
|
||||
* It may therefore be less performant.
|
||||
*
|
||||
* Type tracking predicates using small steps typically take the following form:
|
||||
* ```ql
|
||||
* DataFlow::Node myType(DataFlow::TypeTracker t) {
|
||||
* t.start() and
|
||||
* result = < source of myType >
|
||||
* or
|
||||
* exists (DataFlow::TypeTracker t2 |
|
||||
* t = t2.smallstep(myType(t2), result)
|
||||
* )
|
||||
* }
|
||||
*
|
||||
* DataFlow::Node myType() {
|
||||
* result = myType(DataFlow::TypeTracker::end())
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
pragma[inline]
|
||||
TypeTracker smallstep(Node nodeFrom, Node nodeTo) {
|
||||
exists(StepSummary summary |
|
||||
StepSummary::smallstep(nodeFrom, nodeTo, summary) and
|
||||
result = this.append(summary)
|
||||
)
|
||||
or
|
||||
EssaFlow::essaFlowStep(nodeFrom, nodeTo) and
|
||||
result = this
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
private import python
|
||||
private import DataFlowPrivate
|
||||
import experimental.dataflow.TypeTracker
|
||||
|
||||
/**
|
||||
* IPA type for data flow nodes.
|
||||
@@ -69,6 +70,14 @@ class Node extends TNode {
|
||||
|
||||
/** Convenience method for casting to ExprNode and calling getNode and getNode again. */
|
||||
Expr asExpr() { none() }
|
||||
|
||||
/**
|
||||
* Gets a node that this node may flow to using one heap and/or interprocedural step.
|
||||
*
|
||||
* See `TypeTracker` for more details about how to use this.
|
||||
*/
|
||||
pragma[inline]
|
||||
Node track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) }
|
||||
}
|
||||
|
||||
class EssaNode extends Node, TEssaNode {
|
||||
|
||||
@@ -30,6 +30,16 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
|
||||
subscriptStep(nodeFrom, nodeTo)
|
||||
or
|
||||
stringManipulation(nodeFrom, nodeTo)
|
||||
or
|
||||
jsonStep(nodeFrom, nodeTo)
|
||||
or
|
||||
containerStep(nodeFrom, nodeTo)
|
||||
or
|
||||
copyStep(nodeFrom, nodeTo)
|
||||
or
|
||||
forStep(nodeFrom, nodeTo)
|
||||
or
|
||||
unpackingAssignmentStep(nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,8 +128,101 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT
|
||||
)
|
||||
or
|
||||
// f-strings
|
||||
nodeTo.getNode().getNode().(Fstring).getAValue() = nodeFrom.getNode().getNode()
|
||||
nodeTo.asExpr().(Fstring).getAValue() = nodeFrom.asExpr()
|
||||
// TODO: Handle encode/decode from base64/quopri
|
||||
// TODO: Handle os.path.join
|
||||
// TODO: Handle functions in https://docs.python.org/3/library/binascii.html
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to JSON encoding/decoding.
|
||||
*/
|
||||
predicate jsonStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
|
||||
exists(CallNode call | call = nodeTo.getNode() |
|
||||
call.getFunction().(AttrNode).getObject(["load", "loads", "dumps"]).(NameNode).getId() = "json" and
|
||||
call.getArg(0) = nodeFrom.getNode()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to containers
|
||||
* (lists/sets/dictionaries): literals, constructor invocation, methods. Note that this
|
||||
* is currently very imprecise, as an example, since we model `dict.get`, we treat any
|
||||
* `<tainted object>.get(<arg>)` will be tainted, whether it's true or not.
|
||||
*/
|
||||
predicate containerStep(DataFlow::CfgNode nodeFrom, DataFlow::Node nodeTo) {
|
||||
// construction by literal
|
||||
// TODO: Not limiting the content argument here feels like a BIG hack, but we currently get nothing for free :|
|
||||
storeStep(nodeFrom, _, nodeTo)
|
||||
or
|
||||
// constructor call
|
||||
exists(CallNode call | call = nodeTo.asCfgNode() |
|
||||
call.getFunction().(NameNode).getId() in ["list", "set", "frozenset", "dict", "defaultdict",
|
||||
"tuple"] and
|
||||
call.getArg(0) = nodeFrom.getNode()
|
||||
)
|
||||
or
|
||||
// functions operating on collections
|
||||
exists(CallNode call | call = nodeTo.asCfgNode() |
|
||||
call.getFunction().(NameNode).getId() in ["sorted", "reversed", "iter", "next"] and
|
||||
call.getArg(0) = nodeFrom.getNode()
|
||||
)
|
||||
or
|
||||
// methods
|
||||
exists(CallNode call, string name | call = nodeTo.asCfgNode() |
|
||||
name in ["copy",
|
||||
// general
|
||||
"pop",
|
||||
// dict
|
||||
"values", "items", "get", "popitem"] and
|
||||
call.getFunction().(AttrNode).getObject(name) = nodeFrom.asCfgNode()
|
||||
)
|
||||
or
|
||||
// list.append, set.add
|
||||
exists(CallNode call, string name |
|
||||
name in ["append", "add"] and
|
||||
call.getFunction().(AttrNode).getObject(name) =
|
||||
nodeTo.(PostUpdateNode).getPreUpdateNode().asCfgNode() and
|
||||
call.getArg(0) = nodeFrom.getNode()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to copying.
|
||||
*/
|
||||
predicate copyStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
|
||||
exists(CallNode call | call = nodeTo.getNode() |
|
||||
// Fully qualified: copy.copy, copy.deepcopy
|
||||
(
|
||||
call.getFunction().(NameNode).getId() in ["copy", "deepcopy"]
|
||||
or
|
||||
call.getFunction().(AttrNode).getObject(["copy", "deepcopy"]).(NameNode).getId() = "copy"
|
||||
) and
|
||||
call.getArg(0) = nodeFrom.getNode()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to `for`-iteration,
|
||||
* for example `for x in xs`, or `for x,y in points`.
|
||||
*/
|
||||
predicate forStep(DataFlow::CfgNode nodeFrom, DataFlow::EssaNode nodeTo) {
|
||||
exists(EssaNodeDefinition defn, For for |
|
||||
for.getTarget().getAChildNode*() = defn.getDefiningNode().getNode() and
|
||||
nodeTo.getVar() = defn and
|
||||
nodeFrom.asExpr() = for.getIter()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to iterable unpacking.
|
||||
* Only handles normal assignment (`x,y = calc_point()`), since `for x,y in points` is handled by `forStep`.
|
||||
*/
|
||||
predicate unpackingAssignmentStep(DataFlow::CfgNode nodeFrom, DataFlow::EssaNode nodeTo) {
|
||||
// `a, b = myiterable` or `head, *tail = myiterable` (only Python 3)
|
||||
exists(MultiAssignmentDefinition defn, Assign assign |
|
||||
assign.getATarget().contains(defn.getDefiningNode().getNode()) and
|
||||
nodeTo.getVar() = defn and
|
||||
nodeFrom.asExpr() = assign.getValue()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@ class TestTaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||
TestTaintTrackingConfiguration() { this = "TestTaintTrackingConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.(DataFlow::CfgNode).getNode().(NameNode).getId() in ["TAINTED_STRING", "TAINTED_BYTES"]
|
||||
source.(DataFlow::CfgNode).getNode().(NameNode).getId() in ["TAINTED_STRING", "TAINTED_BYTES",
|
||||
"TAINTED_LIST", "TAINTED_DICT"]
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
@@ -44,7 +45,8 @@ private string repr(Expr e) {
|
||||
|
||||
query predicate test_taint(string arg_location, string test_res, string function_name, string repr) {
|
||||
exists(Call call, Expr arg, boolean expected_taint, boolean has_taint |
|
||||
call.getLocation().getFile().getShortName() = "test.py" and
|
||||
// only consider files that are extracted as part of the test
|
||||
exists(call.getLocation().getFile().getRelativePath()) and
|
||||
(
|
||||
call.getFunc().(Name).getId() = "ensure_tainted" and
|
||||
expected_taint = true
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
| test_collections.py:16 | ok | test_access | tainted_list.copy() |
|
||||
| test_collections.py:24 | ok | list_clear | tainted_list |
|
||||
| test_collections.py:27 | fail | list_clear | tainted_list |
|
||||
| test_string.py:17 | ok | str_methods | ts.casefold() |
|
||||
| test_string.py:19 | ok | str_methods | ts.format_map(..) |
|
||||
| test_string.py:20 | ok | str_methods | "{unsafe}".format_map(..) |
|
||||
| test_string.py:31 | fail | binary_decode_encode | base64.a85encode(..) |
|
||||
| test_string.py:32 | fail | binary_decode_encode | base64.a85decode(..) |
|
||||
| test_string.py:35 | fail | binary_decode_encode | base64.b85encode(..) |
|
||||
| test_string.py:36 | fail | binary_decode_encode | base64.b85decode(..) |
|
||||
| test_string.py:39 | fail | binary_decode_encode | base64.encodebytes(..) |
|
||||
| test_string.py:40 | fail | binary_decode_encode | base64.decodebytes(..) |
|
||||
| test_string.py:48 | ok | f_strings | Fstring |
|
||||
| test_unpacking.py:18 | ok | extended_unpacking | first |
|
||||
| test_unpacking.py:18 | ok | extended_unpacking | last |
|
||||
| test_unpacking.py:18 | ok | extended_unpacking | rest |
|
||||
| test_unpacking.py:23 | ok | also_allowed | a |
|
||||
| test_unpacking.py:31 | ok | also_allowed | b |
|
||||
| test_unpacking.py:31 | ok | also_allowed | c |
|
||||
| test_unpacking.py:39 | ok | nested | x |
|
||||
| test_unpacking.py:39 | ok | nested | xs |
|
||||
| test_unpacking.py:39 | ok | nested | ys |
|
||||
@@ -0,0 +1,32 @@
|
||||
# Add taintlib to PATH so it can be imported during runtime without any hassle
|
||||
import sys; import os; sys.path.append(os.path.dirname(os.path.dirname((__file__))))
|
||||
from taintlib import *
|
||||
|
||||
# This has no runtime impact, but allows autocomplete to work
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from ..taintlib import *
|
||||
|
||||
# Actual tests
|
||||
|
||||
def test_access():
|
||||
tainted_list = TAINTED_LIST
|
||||
|
||||
ensure_tainted(
|
||||
tainted_list.copy(),
|
||||
)
|
||||
|
||||
|
||||
def list_clear():
|
||||
tainted_string = TAINTED_STRING
|
||||
tainted_list = [tainted_string]
|
||||
|
||||
ensure_tainted(tainted_list)
|
||||
|
||||
tainted_list.clear()
|
||||
ensure_not_tainted(tainted_list)
|
||||
|
||||
# Make tests runable
|
||||
|
||||
test_access()
|
||||
list_clear()
|
||||
@@ -1,20 +1,11 @@
|
||||
# Python 3 specific taint tracking for string
|
||||
|
||||
TAINTED_STRING = "TAINTED_STRING"
|
||||
TAINTED_BYTES = b"TAINTED_BYTES"
|
||||
|
||||
|
||||
def ensure_tainted(*args):
|
||||
print("- ensure_tainted")
|
||||
for i, arg in enumerate(args):
|
||||
print("arg {}: {!r}".format(i, arg))
|
||||
|
||||
|
||||
def ensure_not_tainted(*args):
|
||||
print("- ensure_not_tainted")
|
||||
for i, arg in enumerate(args):
|
||||
print("arg {}: {!r}".format(i, arg))
|
||||
# Add taintlib to PATH so it can be imported during runtime without any hassle
|
||||
import sys; import os; sys.path.append(os.path.dirname(os.path.dirname((__file__))))
|
||||
from taintlib import *
|
||||
|
||||
# This has no runtime impact, but allows autocomplete to work
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from ..taintlib import *
|
||||
|
||||
# Actual tests
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Add taintlib to PATH so it can be imported during runtime without any hassle
|
||||
import sys; import os; sys.path.append(os.path.dirname(os.path.dirname((__file__))))
|
||||
from taintlib import *
|
||||
|
||||
# This has no runtime impact, but allows autocomplete to work
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from ..taintlib import *
|
||||
|
||||
# Actual tests
|
||||
|
||||
# Extended Iterable Unpacking -- PEP 3132
|
||||
# https://www.python.org/dev/peps/pep-3132/
|
||||
|
||||
|
||||
def extended_unpacking():
|
||||
first, *rest, last = TAINTED_LIST
|
||||
ensure_tainted(first, rest, last)
|
||||
|
||||
|
||||
def also_allowed():
|
||||
*a, = TAINTED_LIST
|
||||
ensure_tainted(a)
|
||||
|
||||
# for b, *c in [(1, 2, 3), (4, 5, 6, 7)]:
|
||||
# print(c)
|
||||
# i=0; c=[2,3]
|
||||
# i=1; c=[5,6,7]
|
||||
|
||||
for b, *c in [TAINTED_LIST, TAINTED_LIST]:
|
||||
ensure_tainted(b, c)
|
||||
|
||||
|
||||
def nested():
|
||||
l = TAINTED_LIST
|
||||
ll = [l,l]
|
||||
|
||||
[[x, *xs], ys] = ll
|
||||
ensure_tainted(x, xs, ys)
|
||||
|
||||
|
||||
# Make tests runable
|
||||
|
||||
extended_unpacking()
|
||||
also_allowed()
|
||||
nested()
|
||||
@@ -0,0 +1,172 @@
|
||||
| test_collections.py:23 | ok | test_construction | tainted_string |
|
||||
| test_collections.py:24 | ok | test_construction | tainted_list |
|
||||
| test_collections.py:25 | ok | test_construction | tainted_tuple |
|
||||
| test_collections.py:26 | ok | test_construction | tainted_set |
|
||||
| test_collections.py:27 | ok | test_construction | tainted_dict |
|
||||
| test_collections.py:31 | ok | test_construction | list(..) |
|
||||
| test_collections.py:32 | ok | test_construction | list(..) |
|
||||
| test_collections.py:33 | ok | test_construction | list(..) |
|
||||
| test_collections.py:34 | ok | test_construction | list(..) |
|
||||
| test_collections.py:35 | ok | test_construction | list(..) |
|
||||
| test_collections.py:37 | ok | test_construction | tuple(..) |
|
||||
| test_collections.py:38 | ok | test_construction | set(..) |
|
||||
| test_collections.py:39 | ok | test_construction | frozenset(..) |
|
||||
| test_collections.py:47 | ok | test_access | tainted_list[0] |
|
||||
| test_collections.py:48 | ok | test_access | tainted_list[x] |
|
||||
| test_collections.py:49 | ok | test_access | tainted_list[Slice] |
|
||||
| test_collections.py:51 | ok | test_access | sorted(..) |
|
||||
| test_collections.py:52 | ok | test_access | reversed(..) |
|
||||
| test_collections.py:53 | ok | test_access | iter(..) |
|
||||
| test_collections.py:54 | ok | test_access | next(..) |
|
||||
| test_collections.py:58 | ok | test_access | a |
|
||||
| test_collections.py:58 | ok | test_access | b |
|
||||
| test_collections.py:58 | ok | test_access | c |
|
||||
| test_collections.py:61 | ok | test_access | h |
|
||||
| test_collections.py:63 | ok | test_access | i |
|
||||
| test_collections.py:70 | ok | test_dict_access | tainted_dict["name"] |
|
||||
| test_collections.py:71 | ok | test_dict_access | tainted_dict.get(..) |
|
||||
| test_collections.py:72 | ok | test_dict_access | tainted_dict[x] |
|
||||
| test_collections.py:73 | ok | test_dict_access | tainted_dict.copy() |
|
||||
| test_collections.py:77 | ok | test_dict_access | v |
|
||||
| test_collections.py:79 | ok | test_dict_access | v |
|
||||
| test_collections.py:87 | fail | test_named_tuple | point[0] |
|
||||
| test_collections.py:88 | fail | test_named_tuple | point.x |
|
||||
| test_collections.py:92 | ok | test_named_tuple | point[1] |
|
||||
| test_collections.py:93 | ok | test_named_tuple | point.y |
|
||||
| test_collections.py:97 | fail | test_named_tuple | a |
|
||||
| test_collections.py:98 | ok | test_named_tuple | b |
|
||||
| test_collections.py:106 | fail | test_defaultdict | tainted_default_dict["name"] |
|
||||
| test_collections.py:107 | fail | test_defaultdict | tainted_default_dict.get(..) |
|
||||
| test_collections.py:108 | fail | test_defaultdict | tainted_default_dict[x] |
|
||||
| test_collections.py:109 | fail | test_defaultdict | tainted_default_dict.copy() |
|
||||
| test_collections.py:112 | fail | test_defaultdict | v |
|
||||
| test_collections.py:114 | fail | test_defaultdict | v |
|
||||
| test_collections.py:121 | ok | test_copy_1 | copy(..) |
|
||||
| test_collections.py:122 | ok | test_copy_1 | deepcopy(..) |
|
||||
| test_collections.py:130 | ok | test_copy_2 | copy.copy(..) |
|
||||
| test_collections.py:131 | ok | test_copy_2 | copy.deepcopy(..) |
|
||||
| test_collections.py:139 | ok | list_index_assign | my_list |
|
||||
| test_collections.py:142 | fail | list_index_assign | my_list |
|
||||
| test_collections.py:149 | ok | list_index_aug_assign | my_list |
|
||||
| test_collections.py:152 | fail | list_index_aug_assign | my_list |
|
||||
| test_collections.py:159 | ok | list_append | my_list |
|
||||
| test_collections.py:162 | fail | list_append | my_list |
|
||||
| test_collections.py:169 | ok | list_extend | my_list |
|
||||
| test_collections.py:172 | fail | list_extend | my_list |
|
||||
| test_collections.py:179 | ok | dict_update_dict | my_dict |
|
||||
| test_collections.py:182 | fail | dict_update_dict | my_dict |
|
||||
| test_collections.py:189 | ok | dict_update_kv_list | my_dict |
|
||||
| test_collections.py:192 | fail | dict_update_kv_list | my_dict |
|
||||
| test_collections.py:198 | ok | dict_update_kv_arg | my_dict |
|
||||
| test_collections.py:201 | fail | dict_update_kv_arg | my_dict |
|
||||
| test_collections.py:208 | ok | dict_manual_update | my_dict |
|
||||
| test_collections.py:212 | fail | dict_manual_update | my_dict |
|
||||
| test_collections.py:220 | fail | dict_merge | merged |
|
||||
| test_collections.py:227 | ok | set_add | my_set |
|
||||
| test_collections.py:230 | fail | set_add | my_set |
|
||||
| test_json.py:26 | ok | test | json.dumps(..) |
|
||||
| test_json.py:27 | ok | test | json.loads(..) |
|
||||
| test_json.py:34 | fail | test | tainted_filelike |
|
||||
| test_json.py:35 | fail | test | json.load(..) |
|
||||
| test_json.py:48 | fail | non_syntacical | dumps(..) |
|
||||
| test_json.py:49 | fail | non_syntacical | dumps_alias(..) |
|
||||
| test_json.py:50 | fail | non_syntacical | loads(..) |
|
||||
| test_json.py:57 | fail | non_syntacical | tainted_filelike |
|
||||
| test_json.py:58 | fail | non_syntacical | load(..) |
|
||||
| test_string.py:25 | ok | str_operations | ts |
|
||||
| test_string.py:26 | ok | str_operations | BinaryExpr |
|
||||
| test_string.py:27 | ok | str_operations | BinaryExpr |
|
||||
| test_string.py:28 | ok | str_operations | BinaryExpr |
|
||||
| test_string.py:29 | ok | str_operations | ts[Slice] |
|
||||
| test_string.py:30 | ok | str_operations | ts[Slice] |
|
||||
| test_string.py:31 | ok | str_operations | ts[Slice] |
|
||||
| test_string.py:32 | ok | str_operations | ts[0] |
|
||||
| test_string.py:33 | ok | str_operations | str(..) |
|
||||
| test_string.py:34 | ok | str_operations | bytes(..) |
|
||||
| test_string.py:35 | ok | str_operations | unicode(..) |
|
||||
| test_string.py:39 | ok | str_operations | aug_assignment |
|
||||
| test_string.py:41 | ok | str_operations | aug_assignment |
|
||||
| test_string.py:49 | ok | str_methods | ts.capitalize() |
|
||||
| test_string.py:50 | ok | str_methods | ts.center(..) |
|
||||
| test_string.py:51 | ok | str_methods | ts.expandtabs() |
|
||||
| test_string.py:53 | ok | str_methods | ts.format() |
|
||||
| test_string.py:54 | ok | str_methods | "{}".format(..) |
|
||||
| test_string.py:55 | ok | str_methods | "{unsafe}".format(..) |
|
||||
| test_string.py:57 | ok | str_methods | ts.join(..) |
|
||||
| test_string.py:58 | ok | str_methods | "".join(..) |
|
||||
| test_string.py:60 | ok | str_methods | ts.ljust(..) |
|
||||
| test_string.py:61 | ok | str_methods | ts.lstrip() |
|
||||
| test_string.py:62 | ok | str_methods | ts.lower() |
|
||||
| test_string.py:64 | ok | str_methods | ts.replace(..) |
|
||||
| test_string.py:65 | ok | str_methods | "safe".replace(..) |
|
||||
| test_string.py:67 | ok | str_methods | ts.rjust(..) |
|
||||
| test_string.py:68 | ok | str_methods | ts.rstrip() |
|
||||
| test_string.py:69 | ok | str_methods | ts.strip() |
|
||||
| test_string.py:70 | ok | str_methods | ts.swapcase() |
|
||||
| test_string.py:71 | ok | str_methods | ts.title() |
|
||||
| test_string.py:72 | ok | str_methods | ts.upper() |
|
||||
| test_string.py:73 | ok | str_methods | ts.zfill(..) |
|
||||
| test_string.py:75 | ok | str_methods | ts.encode(..) |
|
||||
| test_string.py:76 | ok | str_methods | ts.encode(..).decode(..) |
|
||||
| test_string.py:78 | ok | str_methods | tb.decode(..) |
|
||||
| test_string.py:79 | ok | str_methods | tb.decode(..).encode(..) |
|
||||
| test_string.py:82 | ok | str_methods | ts.partition(..) |
|
||||
| test_string.py:83 | ok | str_methods | ts.rpartition(..) |
|
||||
| test_string.py:84 | ok | str_methods | ts.rsplit(..) |
|
||||
| test_string.py:85 | ok | str_methods | ts.split(..) |
|
||||
| test_string.py:86 | ok | str_methods | ts.splitlines() |
|
||||
| test_string.py:91 | ok | str_methods | "safe".replace(..) |
|
||||
| test_string.py:93 | fail | str_methods | ts.join(..) |
|
||||
| test_string.py:94 | fail | str_methods | ts.join(..) |
|
||||
| test_string.py:104 | fail | non_syntactic | meth() |
|
||||
| test_string.py:105 | fail | non_syntactic | _str(..) |
|
||||
| test_string.py:114 | ok | percent_fmt | BinaryExpr |
|
||||
| test_string.py:115 | ok | percent_fmt | BinaryExpr |
|
||||
| test_string.py:116 | ok | percent_fmt | BinaryExpr |
|
||||
| test_string.py:126 | fail | binary_decode_encode | base64.b64encode(..) |
|
||||
| test_string.py:127 | fail | binary_decode_encode | base64.b64decode(..) |
|
||||
| test_string.py:129 | fail | binary_decode_encode | base64.standard_b64encode(..) |
|
||||
| test_string.py:130 | fail | binary_decode_encode | base64.standard_b64decode(..) |
|
||||
| test_string.py:132 | fail | binary_decode_encode | base64.urlsafe_b64encode(..) |
|
||||
| test_string.py:133 | fail | binary_decode_encode | base64.urlsafe_b64decode(..) |
|
||||
| test_string.py:135 | fail | binary_decode_encode | base64.b32encode(..) |
|
||||
| test_string.py:136 | fail | binary_decode_encode | base64.b32decode(..) |
|
||||
| test_string.py:138 | fail | binary_decode_encode | base64.b16encode(..) |
|
||||
| test_string.py:139 | fail | binary_decode_encode | base64.b16decode(..) |
|
||||
| test_string.py:142 | fail | binary_decode_encode | base64.encodestring(..) |
|
||||
| test_string.py:143 | fail | binary_decode_encode | base64.decodestring(..) |
|
||||
| test_string.py:148 | fail | binary_decode_encode | quopri.encodestring(..) |
|
||||
| test_string.py:149 | fail | binary_decode_encode | quopri.decodestring(..) |
|
||||
| test_unpacking.py:16 | ok | unpacking | a |
|
||||
| test_unpacking.py:16 | ok | unpacking | b |
|
||||
| test_unpacking.py:16 | ok | unpacking | c |
|
||||
| test_unpacking.py:22 | ok | unpacking_to_list | a |
|
||||
| test_unpacking.py:22 | ok | unpacking_to_list | b |
|
||||
| test_unpacking.py:22 | ok | unpacking_to_list | c |
|
||||
| test_unpacking.py:31 | ok | nested | a1 |
|
||||
| test_unpacking.py:31 | ok | nested | a2 |
|
||||
| test_unpacking.py:31 | ok | nested | a3 |
|
||||
| test_unpacking.py:31 | ok | nested | b |
|
||||
| test_unpacking.py:31 | ok | nested | c |
|
||||
| test_unpacking.py:35 | ok | nested | a1 |
|
||||
| test_unpacking.py:35 | ok | nested | a2 |
|
||||
| test_unpacking.py:35 | ok | nested | a3 |
|
||||
| test_unpacking.py:35 | ok | nested | b |
|
||||
| test_unpacking.py:35 | ok | nested | c |
|
||||
| test_unpacking.py:39 | ok | nested | a1 |
|
||||
| test_unpacking.py:39 | ok | nested | a2 |
|
||||
| test_unpacking.py:39 | ok | nested | a3 |
|
||||
| test_unpacking.py:39 | ok | nested | b |
|
||||
| test_unpacking.py:39 | ok | nested | c |
|
||||
| test_unpacking.py:46 | ok | unpack_from_set | a |
|
||||
| test_unpacking.py:46 | ok | unpack_from_set | b |
|
||||
| test_unpacking.py:46 | ok | unpack_from_set | c |
|
||||
| test_unpacking.py:55 | ok | contrived_1 | a |
|
||||
| test_unpacking.py:55 | ok | contrived_1 | b |
|
||||
| test_unpacking.py:55 | ok | contrived_1 | c |
|
||||
| test_unpacking.py:56 | fail | contrived_1 | d |
|
||||
| test_unpacking.py:56 | fail | contrived_1 | e |
|
||||
| test_unpacking.py:56 | fail | contrived_1 | f |
|
||||
| test_unpacking.py:65 | ok | contrived_2 | a |
|
||||
| test_unpacking.py:65 | ok | contrived_2 | b |
|
||||
| test_unpacking.py:65 | ok | contrived_2 | c |
|
||||
@@ -0,0 +1,254 @@
|
||||
# Add taintlib to PATH so it can be imported during runtime without any hassle
|
||||
import sys; import os; sys.path.append(os.path.dirname(os.path.dirname((__file__))))
|
||||
from taintlib import *
|
||||
|
||||
# This has no runtime impact, but allows autocomplete to work
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from ..taintlib import *
|
||||
|
||||
|
||||
# Actual tests
|
||||
|
||||
from collections import defaultdict, namedtuple
|
||||
|
||||
def test_construction():
|
||||
tainted_string = TAINTED_STRING
|
||||
tainted_list = [tainted_string]
|
||||
tainted_tuple = (tainted_string,)
|
||||
tainted_set = {tainted_string}
|
||||
tainted_dict = {'key': tainted_string}
|
||||
|
||||
ensure_tainted(
|
||||
tainted_string,
|
||||
tainted_list,
|
||||
tainted_tuple,
|
||||
tainted_set,
|
||||
tainted_dict,
|
||||
)
|
||||
|
||||
ensure_tainted(
|
||||
list(tainted_list),
|
||||
list(tainted_tuple),
|
||||
list(tainted_set),
|
||||
list(tainted_dict.values()),
|
||||
list(tainted_dict.items()),
|
||||
|
||||
tuple(tainted_list),
|
||||
set(tainted_list),
|
||||
frozenset(tainted_list),
|
||||
)
|
||||
|
||||
|
||||
def test_access(x, y, z):
|
||||
tainted_list = TAINTED_LIST
|
||||
|
||||
ensure_tainted(
|
||||
tainted_list[0],
|
||||
tainted_list[x],
|
||||
tainted_list[y:z],
|
||||
|
||||
sorted(tainted_list),
|
||||
reversed(tainted_list),
|
||||
iter(tainted_list),
|
||||
next(iter(tainted_list)),
|
||||
)
|
||||
|
||||
a, b, c = tainted_list[0:3]
|
||||
ensure_tainted(a, b, c)
|
||||
|
||||
for h in tainted_list:
|
||||
ensure_tainted(h)
|
||||
for i in reversed(tainted_list):
|
||||
ensure_tainted(i)
|
||||
|
||||
|
||||
def test_dict_access(x):
|
||||
tainted_dict = TAINTED_DICT
|
||||
|
||||
ensure_tainted(
|
||||
tainted_dict["name"],
|
||||
tainted_dict.get("name"),
|
||||
tainted_dict[x],
|
||||
tainted_dict.copy(),
|
||||
)
|
||||
|
||||
for v in tainted_dict.values():
|
||||
ensure_tainted(v)
|
||||
for k, v in tainted_dict.items():
|
||||
ensure_tainted(v)
|
||||
|
||||
|
||||
def test_named_tuple(): # TODO: namedtuple currently not handled
|
||||
Point = namedtuple('Point', ['x', 'y'])
|
||||
point = Point(TAINTED_STRING, 'safe')
|
||||
|
||||
ensure_tainted(
|
||||
point[0],
|
||||
point.x,
|
||||
)
|
||||
|
||||
ensure_not_tainted(
|
||||
point[1],
|
||||
point.y,
|
||||
)
|
||||
|
||||
a, b = point
|
||||
ensure_tainted(a)
|
||||
ensure_not_tainted(b)
|
||||
|
||||
|
||||
def test_defaultdict(key, x): # TODO: defaultdict currently not handled
|
||||
tainted_default_dict = defaultdict(str)
|
||||
tainted_default_dict[key] += TAINTED_STRING
|
||||
|
||||
ensure_tainted(
|
||||
tainted_default_dict["name"],
|
||||
tainted_default_dict.get("name"),
|
||||
tainted_default_dict[x],
|
||||
tainted_default_dict.copy(),
|
||||
)
|
||||
for v in tainted_default_dict.values():
|
||||
ensure_tainted(v)
|
||||
for k, v in tainted_default_dict.items():
|
||||
ensure_tainted(v)
|
||||
|
||||
|
||||
def test_copy_1():
|
||||
from copy import copy, deepcopy
|
||||
|
||||
ensure_tainted(
|
||||
copy(TAINTED_LIST),
|
||||
deepcopy(TAINTED_LIST),
|
||||
)
|
||||
|
||||
|
||||
def test_copy_2():
|
||||
import copy
|
||||
|
||||
ensure_tainted(
|
||||
copy.copy(TAINTED_LIST),
|
||||
copy.deepcopy(TAINTED_LIST),
|
||||
)
|
||||
|
||||
|
||||
def list_index_assign():
|
||||
tainted_string = TAINTED_STRING
|
||||
my_list = ["safe"]
|
||||
|
||||
ensure_not_tainted(my_list)
|
||||
|
||||
my_list[0] = tainted_string
|
||||
ensure_tainted(my_list)
|
||||
|
||||
|
||||
def list_index_aug_assign():
|
||||
tainted_string = TAINTED_STRING
|
||||
my_list = ["safe"]
|
||||
|
||||
ensure_not_tainted(my_list)
|
||||
|
||||
my_list[0] += tainted_string
|
||||
ensure_tainted(my_list)
|
||||
|
||||
|
||||
def list_append():
|
||||
tainted_string = TAINTED_STRING
|
||||
my_list = ["safe"]
|
||||
|
||||
ensure_not_tainted(my_list)
|
||||
|
||||
my_list.append(tainted_string)
|
||||
ensure_tainted(my_list)
|
||||
|
||||
|
||||
def list_extend():
|
||||
my_list = ["safe"]
|
||||
tainted_list = [TAINTED_STRING]
|
||||
|
||||
ensure_not_tainted(my_list)
|
||||
|
||||
my_list.extend(tainted_list)
|
||||
ensure_tainted(my_list)
|
||||
|
||||
|
||||
def dict_update_dict():
|
||||
my_dict = {"key1": "safe"}
|
||||
tainted_dict = {"key2": TAINTED_STRING}
|
||||
|
||||
ensure_not_tainted(my_dict)
|
||||
|
||||
my_dict.update(tainted_dict)
|
||||
ensure_tainted(my_dict)
|
||||
|
||||
|
||||
def dict_update_kv_list():
|
||||
my_dict = {"key1": "safe"}
|
||||
tainted_kv_list = [("key2", TAINTED_STRING)]
|
||||
|
||||
ensure_not_tainted(my_dict)
|
||||
|
||||
my_dict.update(tainted_kv_list)
|
||||
ensure_tainted(my_dict)
|
||||
|
||||
|
||||
def dict_update_kv_arg():
|
||||
my_dict = {"key1": "safe"}
|
||||
|
||||
ensure_not_tainted(my_dict)
|
||||
|
||||
my_dict.update(key2=TAINTED_STRING)
|
||||
ensure_tainted(my_dict)
|
||||
|
||||
|
||||
def dict_manual_update():
|
||||
my_dict = {"key1": "safe"}
|
||||
tainted_dict = {"key2": TAINTED_STRING}
|
||||
|
||||
ensure_not_tainted(my_dict)
|
||||
|
||||
for k in tainted_dict:
|
||||
my_dict[k] = tainted_dict[k]
|
||||
ensure_tainted(my_dict)
|
||||
|
||||
|
||||
def dict_merge():
|
||||
my_dict = {"key1": "safe"}
|
||||
tainted_dict = {"key2": TAINTED_STRING}
|
||||
|
||||
merged = {**my_dict, **tainted_dict}
|
||||
ensure_tainted(merged)
|
||||
|
||||
|
||||
def set_add():
|
||||
tainted_string = TAINTED_STRING
|
||||
my_set = {"safe"}
|
||||
|
||||
ensure_not_tainted(my_set)
|
||||
|
||||
my_set.add(tainted_string)
|
||||
ensure_tainted(my_set)
|
||||
|
||||
|
||||
# Make tests runable
|
||||
|
||||
test_construction()
|
||||
test_access(0, 0, 2)
|
||||
test_dict_access("name")
|
||||
test_named_tuple()
|
||||
test_defaultdict("key", "key")
|
||||
test_copy_1()
|
||||
test_copy_2()
|
||||
|
||||
list_index_assign()
|
||||
list_index_aug_assign()
|
||||
list_append()
|
||||
list_extend()
|
||||
|
||||
dict_update_dict()
|
||||
dict_update_kv_list()
|
||||
dict_update_kv_arg()
|
||||
dict_manual_update()
|
||||
dict_merge()
|
||||
|
||||
set_add()
|
||||
@@ -0,0 +1,64 @@
|
||||
# Add taintlib to PATH so it can be imported during runtime without any hassle
|
||||
import sys; import os; sys.path.append(os.path.dirname(os.path.dirname((__file__))))
|
||||
from taintlib import *
|
||||
|
||||
# This has no runtime impact, but allows autocomplete to work
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from ..taintlib import *
|
||||
|
||||
|
||||
# Actual tests
|
||||
|
||||
from io import StringIO
|
||||
|
||||
# Workaround for Python3 not having unicode
|
||||
import sys
|
||||
if sys.version_info[0] == 3:
|
||||
unicode = str
|
||||
|
||||
def test():
|
||||
print("\n# test")
|
||||
ts = TAINTED_STRING
|
||||
import json
|
||||
|
||||
ensure_tainted(
|
||||
json.dumps(ts),
|
||||
json.loads(json.dumps(ts)),
|
||||
)
|
||||
|
||||
# For Python2, need to convert to unicode for StringIO to work
|
||||
tainted_filelike = StringIO(unicode(json.dumps(ts)))
|
||||
|
||||
ensure_tainted(
|
||||
tainted_filelike,
|
||||
json.load(tainted_filelike),
|
||||
)
|
||||
|
||||
def non_syntacical():
|
||||
print("\n# non_syntacical")
|
||||
ts = TAINTED_STRING
|
||||
|
||||
# a less syntactical approach
|
||||
from json import load, loads, dumps
|
||||
|
||||
dumps_alias = dumps
|
||||
|
||||
ensure_tainted(
|
||||
dumps(ts),
|
||||
dumps_alias(ts),
|
||||
loads(dumps(ts)),
|
||||
)
|
||||
|
||||
# For Python2, need to convert to unicode for StringIO to work
|
||||
tainted_filelike = StringIO(unicode(dumps(ts)))
|
||||
|
||||
ensure_tainted(
|
||||
tainted_filelike,
|
||||
load(tainted_filelike),
|
||||
)
|
||||
|
||||
# Make tests runable
|
||||
|
||||
test()
|
||||
non_syntacical()
|
||||
@@ -1,27 +1,20 @@
|
||||
import sys
|
||||
# Add taintlib to PATH so it can be imported during runtime without any hassle
|
||||
import sys; import os; sys.path.append(os.path.dirname(os.path.dirname((__file__))))
|
||||
from taintlib import *
|
||||
|
||||
if sys.version_info[0] == 3:
|
||||
unicode = str
|
||||
|
||||
|
||||
TAINTED_STRING = "TAINTED_STRING"
|
||||
TAINTED_BYTES = b"TAINTED_BYTES"
|
||||
|
||||
|
||||
def ensure_tainted(*args):
|
||||
print("- ensure_tainted")
|
||||
for i, arg in enumerate(args):
|
||||
print("arg {}: {!r}".format(i, arg))
|
||||
|
||||
|
||||
def ensure_not_tainted(*args):
|
||||
print("- ensure_not_tainted")
|
||||
for i, arg in enumerate(args):
|
||||
print("arg {}: {!r}".format(i, arg))
|
||||
# This has no runtime impact, but allows autocomplete to work
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from ..taintlib import *
|
||||
|
||||
|
||||
# Actual tests
|
||||
|
||||
# Workaround for Python3 not having unicode
|
||||
import sys
|
||||
if sys.version_info[0] == 3:
|
||||
unicode = str
|
||||
|
||||
|
||||
def str_operations():
|
||||
print("\n# str_operations")
|
||||
@@ -42,6 +35,11 @@ def str_operations():
|
||||
unicode(ts),
|
||||
)
|
||||
|
||||
aug_assignment = "safe"
|
||||
ensure_not_tainted(aug_assignment)
|
||||
aug_assignment += TAINTED_STRING
|
||||
ensure_tainted(aug_assignment)
|
||||
|
||||
|
||||
def str_methods():
|
||||
print("\n# str_methods")
|
||||
@@ -140,18 +138,6 @@ def binary_decode_encode():
|
||||
base64.b16encode(tb),
|
||||
base64.b16decode(base64.b16encode(tb)),
|
||||
|
||||
# # New in Python 3.4
|
||||
# base64.a85encode(tb),
|
||||
# base64.a85decode(base64.a85encode(tb)),
|
||||
|
||||
# # New in Python 3.4
|
||||
# base64.b85encode(tb),
|
||||
# base64.b85decode(base64.b85encode(tb)),
|
||||
|
||||
# # New in Python 3.1
|
||||
# base64.encodebytes(tb),
|
||||
# base64.decodebytes(base64.encodebytes(tb)),
|
||||
|
||||
# deprecated since Python 3.1, but still works
|
||||
base64.encodestring(tb),
|
||||
base64.decodestring(base64.encodestring(tb)),
|
||||
@@ -0,0 +1,75 @@
|
||||
# Add taintlib to PATH so it can be imported during runtime without any hassle
|
||||
import sys; import os; sys.path.append(os.path.dirname(os.path.dirname((__file__))))
|
||||
from taintlib import *
|
||||
|
||||
# This has no runtime impact, but allows autocomplete to work
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from ..taintlib import *
|
||||
|
||||
|
||||
# Actual tests
|
||||
|
||||
def unpacking():
|
||||
l = TAINTED_LIST[0:3]
|
||||
a, b, c = l
|
||||
ensure_tainted(a, b, c)
|
||||
|
||||
|
||||
def unpacking_to_list():
|
||||
l = TAINTED_LIST[0:3]
|
||||
[a, b, c] = l
|
||||
ensure_tainted(a, b, c)
|
||||
|
||||
|
||||
def nested():
|
||||
l = TAINTED_LIST[0:3]
|
||||
ll = [l, l, l]
|
||||
|
||||
# list
|
||||
[[a1, a2, a3], b, c] = ll
|
||||
ensure_tainted(a1, a2, a3, b, c)
|
||||
|
||||
# tuple
|
||||
((a1, a2, a3), b, c) = ll
|
||||
ensure_tainted(a1, a2, a3, b, c)
|
||||
|
||||
# mixed
|
||||
[(a1, a2, a3), b, c] = ll
|
||||
ensure_tainted(a1, a2, a3, b, c)
|
||||
|
||||
|
||||
def unpack_from_set():
|
||||
# no guarantee on ordering ... don't know why you would ever do this
|
||||
a, b, c = {"foo", "bar", TAINTED_STRING}
|
||||
# either all should be tainted, or none of them
|
||||
ensure_tainted(a, b, c)
|
||||
|
||||
|
||||
def contrived_1():
|
||||
# A contrived example. Don't know why anyone would ever actually do this.
|
||||
tainted_list = TAINTED_LIST[0:3]
|
||||
no_taint_list = [1,2,3]
|
||||
|
||||
(a, b, c), (d, e, f) = tainted_list, no_taint_list
|
||||
ensure_tainted(a, b, c)
|
||||
ensure_not_tainted(d, e, f) # FP: we mark `d`, `e` and `f` as tainted.
|
||||
|
||||
|
||||
def contrived_2():
|
||||
# A contrived example. Don't know why anyone would ever actually do this.
|
||||
|
||||
# Old taint tracking was only able to handle taint nested 2 levels in sequences,
|
||||
# so would not mark a, b, c as tainted
|
||||
[[[ (a, b, c) ]]] = [[[ TAINTED_LIST[0:3] ]]]
|
||||
ensure_tainted(a, b, c)
|
||||
|
||||
|
||||
# Make tests runable
|
||||
|
||||
unpacking()
|
||||
unpacking_to_list()
|
||||
nested()
|
||||
unpack_from_set()
|
||||
contrived_1()
|
||||
contrived_2()
|
||||
@@ -1,10 +0,0 @@
|
||||
| test.py:26 | ok | str_methods | ts.casefold() |
|
||||
| test.py:28 | ok | str_methods | ts.format_map(..) |
|
||||
| test.py:29 | fail | str_methods | "{unsafe}".format_map(..) |
|
||||
| test.py:40 | fail | binary_decode_encode | base64.a85encode(..) |
|
||||
| test.py:41 | fail | binary_decode_encode | base64.a85decode(..) |
|
||||
| test.py:44 | fail | binary_decode_encode | base64.b85encode(..) |
|
||||
| test.py:45 | fail | binary_decode_encode | base64.b85decode(..) |
|
||||
| test.py:48 | fail | binary_decode_encode | base64.encodebytes(..) |
|
||||
| test.py:49 | fail | binary_decode_encode | base64.decodebytes(..) |
|
||||
| test.py:57 | ok | f_strings | Fstring |
|
||||
@@ -1,62 +0,0 @@
|
||||
| test.py:32 | ok | str_operations | ts |
|
||||
| test.py:33 | ok | str_operations | BinaryExpr |
|
||||
| test.py:34 | ok | str_operations | BinaryExpr |
|
||||
| test.py:35 | ok | str_operations | BinaryExpr |
|
||||
| test.py:36 | ok | str_operations | ts[Slice] |
|
||||
| test.py:37 | ok | str_operations | ts[Slice] |
|
||||
| test.py:38 | ok | str_operations | ts[Slice] |
|
||||
| test.py:39 | ok | str_operations | ts[0] |
|
||||
| test.py:40 | ok | str_operations | str(..) |
|
||||
| test.py:41 | ok | str_operations | bytes(..) |
|
||||
| test.py:42 | ok | str_operations | unicode(..) |
|
||||
| test.py:51 | ok | str_methods | ts.capitalize() |
|
||||
| test.py:52 | ok | str_methods | ts.center(..) |
|
||||
| test.py:53 | ok | str_methods | ts.expandtabs() |
|
||||
| test.py:55 | ok | str_methods | ts.format() |
|
||||
| test.py:56 | ok | str_methods | "{}".format(..) |
|
||||
| test.py:57 | ok | str_methods | "{unsafe}".format(..) |
|
||||
| test.py:59 | ok | str_methods | ts.join(..) |
|
||||
| test.py:60 | fail | str_methods | "".join(..) |
|
||||
| test.py:62 | ok | str_methods | ts.ljust(..) |
|
||||
| test.py:63 | ok | str_methods | ts.lstrip() |
|
||||
| test.py:64 | ok | str_methods | ts.lower() |
|
||||
| test.py:66 | ok | str_methods | ts.replace(..) |
|
||||
| test.py:67 | ok | str_methods | "safe".replace(..) |
|
||||
| test.py:69 | ok | str_methods | ts.rjust(..) |
|
||||
| test.py:70 | ok | str_methods | ts.rstrip() |
|
||||
| test.py:71 | ok | str_methods | ts.strip() |
|
||||
| test.py:72 | ok | str_methods | ts.swapcase() |
|
||||
| test.py:73 | ok | str_methods | ts.title() |
|
||||
| test.py:74 | ok | str_methods | ts.upper() |
|
||||
| test.py:75 | ok | str_methods | ts.zfill(..) |
|
||||
| test.py:77 | ok | str_methods | ts.encode(..) |
|
||||
| test.py:78 | ok | str_methods | ts.encode(..).decode(..) |
|
||||
| test.py:80 | ok | str_methods | tb.decode(..) |
|
||||
| test.py:81 | ok | str_methods | tb.decode(..).encode(..) |
|
||||
| test.py:84 | ok | str_methods | ts.partition(..) |
|
||||
| test.py:85 | ok | str_methods | ts.rpartition(..) |
|
||||
| test.py:86 | ok | str_methods | ts.rsplit(..) |
|
||||
| test.py:87 | ok | str_methods | ts.split(..) |
|
||||
| test.py:88 | ok | str_methods | ts.splitlines() |
|
||||
| test.py:93 | ok | str_methods | "safe".replace(..) |
|
||||
| test.py:95 | fail | str_methods | ts.join(..) |
|
||||
| test.py:96 | fail | str_methods | ts.join(..) |
|
||||
| test.py:106 | fail | non_syntactic | meth() |
|
||||
| test.py:107 | fail | non_syntactic | _str(..) |
|
||||
| test.py:116 | ok | percent_fmt | BinaryExpr |
|
||||
| test.py:117 | ok | percent_fmt | BinaryExpr |
|
||||
| test.py:118 | fail | percent_fmt | BinaryExpr |
|
||||
| test.py:128 | fail | binary_decode_encode | base64.b64encode(..) |
|
||||
| test.py:129 | fail | binary_decode_encode | base64.b64decode(..) |
|
||||
| test.py:131 | fail | binary_decode_encode | base64.standard_b64encode(..) |
|
||||
| test.py:132 | fail | binary_decode_encode | base64.standard_b64decode(..) |
|
||||
| test.py:134 | fail | binary_decode_encode | base64.urlsafe_b64encode(..) |
|
||||
| test.py:135 | fail | binary_decode_encode | base64.urlsafe_b64decode(..) |
|
||||
| test.py:137 | fail | binary_decode_encode | base64.b32encode(..) |
|
||||
| test.py:138 | fail | binary_decode_encode | base64.b32decode(..) |
|
||||
| test.py:140 | fail | binary_decode_encode | base64.b16encode(..) |
|
||||
| test.py:141 | fail | binary_decode_encode | base64.b16decode(..) |
|
||||
| test.py:156 | fail | binary_decode_encode | base64.encodestring(..) |
|
||||
| test.py:157 | fail | binary_decode_encode | base64.decodestring(..) |
|
||||
| test.py:162 | fail | binary_decode_encode | quopri.encodestring(..) |
|
||||
| test.py:163 | fail | binary_decode_encode | quopri.decodestring(..) |
|
||||
@@ -0,0 +1,15 @@
|
||||
TAINTED_STRING = "TAINTED_STRING"
|
||||
TAINTED_BYTES = b"TAINTED_BYTES"
|
||||
TAINTED_LIST = ["tainted-{}".format(i) for i in range(5)]
|
||||
TAINTED_DICT = {"name": TAINTED_STRING, "some key": "foo"}
|
||||
|
||||
def ensure_tainted(*args):
|
||||
print("- ensure_tainted")
|
||||
for i, arg in enumerate(args):
|
||||
print("arg {}: {!r}".format(i, arg))
|
||||
|
||||
|
||||
def ensure_not_tainted(*args):
|
||||
print("- ensure_not_tainted")
|
||||
for i, arg in enumerate(args):
|
||||
print("arg {}: {!r}".format(i, arg))
|
||||
@@ -0,0 +1,31 @@
|
||||
class SomeClass:
|
||||
pass
|
||||
|
||||
def simple_read_write():
|
||||
x = SomeClass() # $tracked=foo
|
||||
x.foo = tracked # $tracked $tracked=foo
|
||||
y = x.foo # $tracked=foo $tracked
|
||||
do_stuff(y) # $tracked
|
||||
|
||||
def foo():
|
||||
x = SomeClass() # $tracked=attr
|
||||
bar(x) # $tracked=attr
|
||||
x.attr = tracked # $tracked=attr $tracked
|
||||
baz(x) # $tracked=attr
|
||||
|
||||
def bar(x): # $tracked=attr
|
||||
z = x.attr # $tracked $tracked=attr
|
||||
do_stuff(z) # $tracked
|
||||
|
||||
def expects_int(x): # $int=field $f+:str=field
|
||||
do_int_stuff(x.field) # $int $f+:str $int=field $f+:str=field
|
||||
|
||||
def expects_string(x): # $f+:int=field $str=field
|
||||
do_string_stuff(x.field) # $f+:int $str $f+:int=field $str=field
|
||||
|
||||
def test_incompatible_types():
|
||||
x = SomeClass() # $int,str=field
|
||||
x.field = int(5) # $int=field $f+:str=field $int $f+:str
|
||||
expects_int(x) # $int=field $f+:str=field
|
||||
x.field = str("Hello") # $f+:int=field $str=field $f+:int $str
|
||||
expects_string(x) # $f+:int=field $str=field
|
||||
61
python/ql/test/experimental/dataflow/typetracking/test.py
Normal file
61
python/ql/test/experimental/dataflow/typetracking/test.py
Normal file
@@ -0,0 +1,61 @@
|
||||
def get_tracked():
|
||||
x = tracked # $tracked
|
||||
return x # $tracked
|
||||
|
||||
def use_tracked_foo(x): # $tracked
|
||||
do_stuff(x) # $tracked
|
||||
|
||||
def foo():
|
||||
use_tracked_foo(
|
||||
get_tracked() # $tracked
|
||||
)
|
||||
|
||||
def use_tracked_bar(x): # $tracked
|
||||
do_stuff(x) # $tracked
|
||||
|
||||
def bar():
|
||||
x = get_tracked() # $tracked
|
||||
use_tracked_bar(x) # $tracked
|
||||
|
||||
def use_tracked_baz(x): # $tracked
|
||||
do_stuff(x) # $tracked
|
||||
|
||||
def baz():
|
||||
x = tracked # $tracked
|
||||
use_tracked_baz(x) # $tracked
|
||||
|
||||
def id(x): # $tracked
|
||||
return x # $tracked
|
||||
|
||||
def use_tracked_quux(x): # $f-:tracked
|
||||
do_stuff(y) # call after return -- not tracked in here.
|
||||
|
||||
def quux():
|
||||
x = tracked # $tracked
|
||||
y = id(x) # $tracked
|
||||
use_tracked_quux(y) # not tracked out of call to id.
|
||||
|
||||
g = None
|
||||
|
||||
def write_g(x): # $tracked
|
||||
g = x # $tracked
|
||||
|
||||
def use_g():
|
||||
do_stuff(g) # $f-:tracked // no global flow for now.
|
||||
|
||||
def global_var_write_test():
|
||||
x = tracked # $tracked
|
||||
write_g(x) # $tracked
|
||||
use_g()
|
||||
|
||||
def expects_int(x): # $int
|
||||
do_int_stuff(x) # $int
|
||||
|
||||
def expects_string(x): # $str
|
||||
do_string_stuff(x) # $str
|
||||
|
||||
def redefine_test():
|
||||
x = int(5) # $int
|
||||
expects_int(x) # $int
|
||||
x = str("Hello") # $str
|
||||
expects_string(x) # $str
|
||||
72
python/ql/test/experimental/dataflow/typetracking/tracked.ql
Normal file
72
python/ql/test/experimental/dataflow/typetracking/tracked.ql
Normal file
@@ -0,0 +1,72 @@
|
||||
import python
|
||||
import experimental.dataflow.TypeTracker
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
Node tracked(TypeTracker t) {
|
||||
t.start() and
|
||||
result.asCfgNode() = any(NameNode n | n.getId() = "tracked")
|
||||
or
|
||||
exists(TypeTracker t2 | result = tracked(t2).track(t2, t))
|
||||
}
|
||||
|
||||
class TrackedTest extends InlineExpectationsTest {
|
||||
TrackedTest() { this = "TrackedTest" }
|
||||
|
||||
override string getARelevantTag() { result = "tracked" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Node e, TypeTracker t |
|
||||
e = tracked(t) and
|
||||
tag = "tracked" and
|
||||
location = e.getLocation() and
|
||||
value = t.getAttr() and
|
||||
element = e.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Node int_type(TypeTracker t) {
|
||||
t.start() and
|
||||
result.asCfgNode() = any(CallNode c | c.getFunction().(NameNode).getId() = "int")
|
||||
or
|
||||
exists(TypeTracker t2 | result = int_type(t2).track(t2, t))
|
||||
}
|
||||
|
||||
Node string_type(TypeTracker t) {
|
||||
t.start() and
|
||||
result.asCfgNode() = any(CallNode c | c.getFunction().(NameNode).getId() = "str")
|
||||
or
|
||||
exists(TypeTracker t2 | result = string_type(t2).track(t2, t))
|
||||
}
|
||||
|
||||
class TrackedIntTest extends InlineExpectationsTest {
|
||||
TrackedIntTest() { this = "TrackedIntTest" }
|
||||
|
||||
override string getARelevantTag() { result = "int" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Node e, TypeTracker t |
|
||||
e = int_type(t) and
|
||||
tag = "int" and
|
||||
location = e.getLocation() and
|
||||
value = t.getAttr() and
|
||||
element = e.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TrackedStringTest extends InlineExpectationsTest {
|
||||
TrackedStringTest() { this = "TrackedStringTest" }
|
||||
|
||||
override string getARelevantTag() { result = "str" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Node e, TypeTracker t |
|
||||
e = string_type(t) and
|
||||
tag = "str" and
|
||||
location = e.getLocation() and
|
||||
value = t.getAttr() and
|
||||
element = e.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user