Merge branch 'main' into java-kotlin-sensitive-logging-substring-barriers

This commit is contained in:
Owen Mansel-Chan
2025-11-25 23:24:58 +00:00
committed by GitHub
113 changed files with 16095 additions and 2994 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
description: Add databaseMetadata and overlayChangedFiles relations
compatibility: full
databaseMetadata.rel: delete
overlayChangedFiles.rel: delete

View File

@@ -21,3 +21,4 @@ dataExtensions:
- ext/deallocation/*.model.yml - ext/deallocation/*.model.yml
- ext/allocation/*.model.yml - ext/allocation/*.model.yml
warnOnImplicitThis: true warnOnImplicitThis: true
compileForOverlayEval: true

View File

@@ -2078,38 +2078,151 @@ predicate localExprFlow(Expr e1, Expr e2) {
localExprFlowPlus(e1, e2) localExprFlowPlus(e1, e2)
} }
/**
* A canonical representation of a field.
*
* For performance reasons we want a unique `Content` that represents
* a given field across any template instantiation of a class.
*
* This is possible in _almost_ all cases, but there are cases where it is
* not possible to map between a field in the uninstantiated template to a
* field in the instantiated template. This happens in the case of local class
* definitions (because the local class is not the template that constructs
* the instantiation - it is the enclosing function). So this abstract class
* has two implementations: a non-local case (where we can represent a
* canonical field as the field declaration from an uninstantiated class
* template or a non-templated class), and a local case (where we simply use
* the field from the instantiated class).
*/
abstract private class CanonicalField extends Field {
/** Gets a field represented by this canonical field. */
abstract Field getAField();
/**
* Gets a class that declares a field represented by this canonical field.
*/
abstract Class getADeclaringType();
/**
* Gets a type that this canonical field may have. Note that this may
* not be a unique type. For example, consider this case:
* ```
* template<typename T>
* struct S { T x; };
*
* S<int> s1;
* S<char> s2;
* ```
* In this case the canonical field corresponding to `S::x` has two types:
* `int` and `char`.
*/
Type getAType() { result = this.getAField().getType() }
Type getAnUnspecifiedType() { result = this.getAType().getUnspecifiedType() }
}
private class NonLocalCanonicalField extends CanonicalField {
Class declaringType;
NonLocalCanonicalField() {
declaringType = this.getDeclaringType() and
not declaringType.isFromTemplateInstantiation(_) and
not declaringType.isLocal() // handled in LocalCanonicalField
}
override Field getAField() {
exists(Class c | result.getDeclaringType() = c |
// Either the declaring class of the field is a template instantiation
// that has been constructed from this canonical declaration
c.isConstructedFrom(declaringType) and
pragma[only_bind_out](result.getName()) = pragma[only_bind_out](this.getName())
or
// or this canonical declaration is not a template.
not c.isConstructedFrom(_) and
result = this
)
}
override Class getADeclaringType() {
result = this.getDeclaringType()
or
result.isConstructedFrom(this.getDeclaringType())
}
}
private class LocalCanonicalField extends CanonicalField {
Class declaringType;
LocalCanonicalField() {
declaringType = this.getDeclaringType() and
declaringType.isLocal()
}
override Field getAField() { result = this }
override Class getADeclaringType() { result = declaringType }
}
/**
* A canonical representation of a `Union`. See `CanonicalField` for the explanation for
* why we need a canonical representation.
*/
abstract private class CanonicalUnion extends Union {
/** Gets a union represented by this canonical union. */
abstract Union getAUnion();
/** Gets a canonical field of this canonical union. */
CanonicalField getACanonicalField() { result.getDeclaringType() = this }
}
private class NonLocalCanonicalUnion extends CanonicalUnion {
NonLocalCanonicalUnion() { not this.isFromTemplateInstantiation(_) and not this.isLocal() }
override Union getAUnion() {
result = this
or
result.isConstructedFrom(this)
}
}
private class LocalCanonicalUnion extends CanonicalUnion {
LocalCanonicalUnion() { this.isLocal() }
override Union getAUnion() { result = this }
}
bindingset[f] bindingset[f]
pragma[inline_late] pragma[inline_late]
private int getFieldSize(Field f) { result = f.getType().getSize() } private int getFieldSize(CanonicalField f) { result = max(f.getAType().getSize()) }
/** /**
* Gets a field in the union `u` whose size * Gets a field in the union `u` whose size
* is `bytes` number of bytes. * is `bytes` number of bytes.
*/ */
private Field getAFieldWithSize(Union u, int bytes) { private CanonicalField getAFieldWithSize(CanonicalUnion u, int bytes) {
result = u.getAField() and result = u.getACanonicalField() and
bytes = getFieldSize(result) bytes = getFieldSize(result)
} }
cached cached
private newtype TContent = private newtype TContent =
TNonUnionContent(Field f, int indirectionIndex) { TNonUnionContent(CanonicalField f, int indirectionIndex) {
// the indirection index for field content starts at 1 (because `TNonUnionContent` is thought of as // the indirection index for field content starts at 1 (because `TNonUnionContent` is thought of as
// the address of the field, `FieldAddress` in the IR). // the address of the field, `FieldAddress` in the IR).
indirectionIndex = [1 .. SsaImpl::getMaxIndirectionsForType(f.getUnspecifiedType())] and indirectionIndex = [1 .. max(SsaImpl::getMaxIndirectionsForType(f.getAnUnspecifiedType()))] and
// Reads and writes of union fields are tracked using `UnionContent`. // Reads and writes of union fields are tracked using `UnionContent`.
not f.getDeclaringType() instanceof Union not f.getDeclaringType() instanceof Union
} or } or
TUnionContent(Union u, int bytes, int indirectionIndex) { TUnionContent(CanonicalUnion u, int bytes, int indirectionIndex) {
exists(Field f | exists(CanonicalField f |
f = u.getAField() and f = u.getACanonicalField() and
bytes = getFieldSize(f) and bytes = getFieldSize(f) and
// We key `UnionContent` by the union instead of its fields since a write to one // We key `UnionContent` by the union instead of its fields since a write to one
// field can be read by any read of the union's fields. Again, the indirection index // field can be read by any read of the union's fields. Again, the indirection index
// is 1-based (because 0 is considered the address). // is 1-based (because 0 is considered the address).
indirectionIndex = indirectionIndex =
[1 .. max(SsaImpl::getMaxIndirectionsForType(getAFieldWithSize(u, bytes) [1 .. max(SsaImpl::getMaxIndirectionsForType(getAFieldWithSize(u, bytes)
.getUnspecifiedType()) .getAnUnspecifiedType())
)] )]
) )
} or } or
@@ -2175,8 +2288,12 @@ class FieldContent extends Content, TFieldContent {
/** /**
* Gets the field associated with this `Content`, if a unique one exists. * Gets the field associated with this `Content`, if a unique one exists.
*
* For fields from template instantiations this predicate may still return
* more than one field, but all the fields will be constructed from the same
* template.
*/ */
final Field getField() { result = unique( | | this.getAField()) } Field getField() { none() } // overridden in subclasses
override int getIndirectionIndex() { none() } // overridden in subclasses override int getIndirectionIndex() { none() } // overridden in subclasses
@@ -2187,32 +2304,33 @@ class FieldContent extends Content, TFieldContent {
/** A reference through a non-union instance field. */ /** A reference through a non-union instance field. */
class NonUnionFieldContent extends FieldContent, TNonUnionContent { class NonUnionFieldContent extends FieldContent, TNonUnionContent {
private Field f; private CanonicalField f;
private int indirectionIndex; private int indirectionIndex;
NonUnionFieldContent() { this = TNonUnionContent(f, indirectionIndex) } NonUnionFieldContent() { this = TNonUnionContent(f, indirectionIndex) }
override string toString() { result = contentStars(this) + f.toString() } override string toString() { result = contentStars(this) + f.toString() }
override Field getAField() { result = f } final override Field getField() { result = f.getAField() }
override Field getAField() { result = this.getField() }
/** Gets the indirection index of this `FieldContent`. */ /** Gets the indirection index of this `FieldContent`. */
override int getIndirectionIndex() { result = indirectionIndex } override int getIndirectionIndex() { result = indirectionIndex }
override predicate impliesClearOf(Content c) { override predicate impliesClearOf(Content c) {
exists(FieldContent fc | exists(int i |
fc = c and c = TNonUnionContent(f, i) and
fc.getField() = f and
// If `this` is `f` then `c` is cleared if it's of the // If `this` is `f` then `c` is cleared if it's of the
// form `*f`, `**f`, etc. // form `*f`, `**f`, etc.
fc.getIndirectionIndex() >= indirectionIndex i >= indirectionIndex
) )
} }
} }
/** A reference through an instance field of a union. */ /** A reference through an instance field of a union. */
class UnionContent extends FieldContent, TUnionContent { class UnionContent extends FieldContent, TUnionContent {
private Union u; private CanonicalUnion u;
private int indirectionIndex; private int indirectionIndex;
private int bytes; private int bytes;
@@ -2220,24 +2338,31 @@ class UnionContent extends FieldContent, TUnionContent {
override string toString() { result = contentStars(this) + u.toString() } override string toString() { result = contentStars(this) + u.toString() }
final override Field getField() { result = unique( | | u.getACanonicalField()).getAField() }
/** Gets a field of the underlying union of this `UnionContent`, if any. */ /** Gets a field of the underlying union of this `UnionContent`, if any. */
override Field getAField() { result = u.getAField() and getFieldSize(result) = bytes } override Field getAField() {
exists(CanonicalField cf |
cf = u.getACanonicalField() and
result = cf.getAField() and
getFieldSize(cf) = bytes
)
}
/** Gets the underlying union of this `UnionContent`. */ /** Gets the underlying union of this `UnionContent`. */
Union getUnion() { result = u } Union getUnion() { result = u.getAUnion() }
/** Gets the indirection index of this `UnionContent`. */ /** Gets the indirection index of this `UnionContent`. */
override int getIndirectionIndex() { result = indirectionIndex } override int getIndirectionIndex() { result = indirectionIndex }
override predicate impliesClearOf(Content c) { override predicate impliesClearOf(Content c) {
exists(UnionContent uc | exists(int i |
uc = c and c = TUnionContent(u, _, i) and
uc.getUnion() = u and
// If `this` is `u` then `c` is cleared if it's of the // If `this` is `u` then `c` is cleared if it's of the
// form `*u`, `**u`, etc. (and we ignore `bytes` because // form `*u`, `**u`, etc. (and we ignore `bytes` because
// we know the entire union is overwritten because it's a // we know the entire union is overwritten because it's a
// union). // union).
uc.getIndirectionIndex() >= indirectionIndex i >= indirectionIndex
) )
} }
} }

View File

@@ -1,3 +1,4 @@
/*- Compilations -*/ /*- Compilations -*/
/** /**
@@ -2378,6 +2379,24 @@ link_parent(
int link_target : @link_target ref int link_target : @link_target ref
); );
/**
* The CLI will automatically emit applicable tuples for this table,
* such as `databaseMetadata("isOverlay", "true")` when building an
* overlay database.
*/
databaseMetadata(
string metadataKey: string ref,
string value: string ref
);
/**
* The CLI will automatically emit tuples for each new/modified/deleted file
* when building an overlay database.
*/
overlayChangedFiles(
string path: string ref
);
/*- XML Files -*/ /*- XML Files -*/
xmlEncoding( xmlEncoding(

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Add databaseMetadata and overlayChangedFiles relations
compatibility: full

View File

@@ -142,6 +142,7 @@ postWithInFlow
| simple.cpp:92:7:92:7 | i [post update] | PostUpdateNode should not be the target of local flow. | | simple.cpp:92:7:92:7 | i [post update] | PostUpdateNode should not be the target of local flow. |
| simple.cpp:118:7:118:7 | i [post update] | PostUpdateNode should not be the target of local flow. | | simple.cpp:118:7:118:7 | i [post update] | PostUpdateNode should not be the target of local flow. |
| simple.cpp:124:5:124:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. | | simple.cpp:124:5:124:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| simple.cpp:167:9:167:9 | x [post update] | PostUpdateNode should not be the target of local flow. |
viableImplInCallContextTooLarge viableImplInCallContextTooLarge
uniqueParameterNodeAtPosition uniqueParameterNodeAtPosition
uniqueParameterNodePosition uniqueParameterNodePosition

View File

@@ -308,3 +308,5 @@ WARNING: module 'DataFlow' has been deprecated and may be removed in future (par
| simple.cpp:124:5:124:6 | * ... | AST only | | simple.cpp:124:5:124:6 | * ... | AST only |
| simple.cpp:131:14:131:14 | a | IR only | | simple.cpp:131:14:131:14 | a | IR only |
| simple.cpp:136:10:136:10 | a | IR only | | simple.cpp:136:10:136:10 | a | IR only |
| simple.cpp:167:9:167:9 | x | AST only |
| simple.cpp:168:8:168:12 | u_int | IR only |

View File

@@ -670,6 +670,8 @@
| simple.cpp:131:14:131:14 | a | | simple.cpp:131:14:131:14 | a |
| simple.cpp:135:20:135:20 | q | | simple.cpp:135:20:135:20 | q |
| simple.cpp:136:10:136:10 | a | | simple.cpp:136:10:136:10 | a |
| simple.cpp:167:3:167:7 | u_int |
| simple.cpp:168:8:168:12 | u_int |
| struct_init.c:15:8:15:9 | ab | | struct_init.c:15:8:15:9 | ab |
| struct_init.c:15:12:15:12 | a | | struct_init.c:15:12:15:12 | a |
| struct_init.c:16:8:16:9 | ab | | struct_init.c:16:8:16:9 | ab |

View File

@@ -597,6 +597,8 @@ WARNING: module 'DataFlow' has been deprecated and may be removed in future (par
| simple.cpp:118:7:118:7 | i | | simple.cpp:118:7:118:7 | i |
| simple.cpp:124:5:124:6 | * ... | | simple.cpp:124:5:124:6 | * ... |
| simple.cpp:135:20:135:20 | q | | simple.cpp:135:20:135:20 | q |
| simple.cpp:167:3:167:7 | u_int |
| simple.cpp:167:9:167:9 | x |
| struct_init.c:15:8:15:9 | ab | | struct_init.c:15:8:15:9 | ab |
| struct_init.c:15:12:15:12 | a | | struct_init.c:15:12:15:12 | a |
| struct_init.c:16:8:16:9 | ab | | struct_init.c:16:8:16:9 | ab |

View File

@@ -136,4 +136,36 @@ void alias_with_fields(bool b) {
sink(a.i); // $ MISSING: ast,ir sink(a.i); // $ MISSING: ast,ir
} }
template<typename T>
union U_with_two_instantiations_of_different_size {
int x;
T y;
};
struct LargeStruct {
int data[64];
};
void test_union_with_two_instantiations_of_different_sizes() {
// A union's fields is partitioned into "chunks" for field-flow in order to
// improve performance (so that a write to a field of a union does not flow
// to too many reads that don't happen at runtime). The partitioning is based
// the size of the types in the union. So a write to a field of size k only
// flows to a read of size k.
// Since field-flow is based on uninstantiated types a field can have
// multiple sizes if the union is instantiated with types of
// different sizes. So to compute the partition we pick the maximum size.
// Because of this there are `Content`s corresponding to the union
// `U_with_two_instantiations_of_different_size<T>`: The one for size
// `sizeof(int)`, and the one for size `sizeof(LargeStruct)` (because
// `LargeStruct` is larger than `int`). So the write to `x` writes to the
// `Content` for size `sizeof(int)`, and the read of `y` reads from the
// `Content` for size `sizeof(LargeStruct)`.
U_with_two_instantiations_of_different_size<int> u_int;
U_with_two_instantiations_of_different_size<LargeStruct> u_very_large;
u_int.x = user_input();
sink(u_int.y); // $ MISSING: ir
}
} // namespace Simple } // namespace Simple

View File

@@ -2,10 +2,10 @@
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | address && | SemanticStackVariable | | | | file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | address && | SemanticStackVariable | | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | const __va_list_tag & | SemanticStackVariable | | | | file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | const __va_list_tag & | SemanticStackVariable | | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | const address & | SemanticStackVariable | | | | file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | const address & | SemanticStackVariable | | |
| file://:0:0:0:0 | fp_offset | file://:0:0:0:0 | unsigned int | Field | | | | file://:0:0:0:0 | fp_offset | file://:0:0:0:0 | unsigned int | NonLocalCanonicalField | | |
| file://:0:0:0:0 | gp_offset | file://:0:0:0:0 | unsigned int | Field | | | | file://:0:0:0:0 | gp_offset | file://:0:0:0:0 | unsigned int | NonLocalCanonicalField | | |
| file://:0:0:0:0 | overflow_arg_area | file://:0:0:0:0 | void * | Field | | | | file://:0:0:0:0 | overflow_arg_area | file://:0:0:0:0 | void * | NonLocalCanonicalField | | |
| file://:0:0:0:0 | reg_save_area | file://:0:0:0:0 | void * | Field | | | | file://:0:0:0:0 | reg_save_area | file://:0:0:0:0 | void * | NonLocalCanonicalField | | |
| variables.cpp:1:12:1:12 | i | file://:0:0:0:0 | int | GlobalLikeVariable, GlobalVariable, StaticStorageDurationVariable | | | | variables.cpp:1:12:1:12 | i | file://:0:0:0:0 | int | GlobalLikeVariable, GlobalVariable, StaticStorageDurationVariable | | |
| variables.cpp:2:12:2:12 | i | file://:0:0:0:0 | int | GlobalLikeVariable, GlobalVariable, StaticStorageDurationVariable | | | | variables.cpp:2:12:2:12 | i | file://:0:0:0:0 | int | GlobalLikeVariable, GlobalVariable, StaticStorageDurationVariable | | |
| variables.cpp:3:12:3:12 | i | file://:0:0:0:0 | int | GlobalLikeVariable, GlobalVariable, StaticStorageDurationVariable | | | | variables.cpp:3:12:3:12 | i | file://:0:0:0:0 | int | GlobalLikeVariable, GlobalVariable, StaticStorageDurationVariable | | |
@@ -33,10 +33,10 @@
| variables.cpp:37:6:37:8 | ap3 | file://:0:0:0:0 | int * | GlobalLikeVariable, GlobalVariable, StaticStorageDurationVariable | | | | variables.cpp:37:6:37:8 | ap3 | file://:0:0:0:0 | int * | GlobalLikeVariable, GlobalVariable, StaticStorageDurationVariable | | |
| variables.cpp:41:7:41:11 | local | file://:0:0:0:0 | char[] | LocalVariable, SemanticStackVariable | | | | variables.cpp:41:7:41:11 | local | file://:0:0:0:0 | char[] | LocalVariable, SemanticStackVariable | | |
| variables.cpp:43:14:43:18 | local | file://:0:0:0:0 | int | GlobalLikeVariable, StaticLocalVariable | | static | | variables.cpp:43:14:43:18 | local | file://:0:0:0:0 | int | GlobalLikeVariable, StaticLocalVariable | | static |
| variables.cpp:48:9:48:12 | name | file://:0:0:0:0 | char * | Field | | | | variables.cpp:48:9:48:12 | name | file://:0:0:0:0 | char * | NonLocalCanonicalField | | |
| variables.cpp:49:12:49:17 | number | file://:0:0:0:0 | long | Field | | | | variables.cpp:49:12:49:17 | number | file://:0:0:0:0 | long | NonLocalCanonicalField | | |
| variables.cpp:50:9:50:14 | street | file://:0:0:0:0 | char * | Field | | | | variables.cpp:50:9:50:14 | street | file://:0:0:0:0 | char * | NonLocalCanonicalField | | |
| variables.cpp:51:9:51:12 | town | file://:0:0:0:0 | char * | Field | | | | variables.cpp:51:9:51:12 | town | file://:0:0:0:0 | char * | NonLocalCanonicalField | | |
| variables.cpp:52:16:52:22 | country | file://:0:0:0:0 | char * | MemberVariable, StaticStorageDurationVariable | | static | | variables.cpp:52:16:52:22 | country | file://:0:0:0:0 | char * | MemberVariable, StaticStorageDurationVariable | | static |
| variables.cpp:56:14:56:29 | externInFunction | file://:0:0:0:0 | int | GlobalLikeVariable, GlobalVariable, StaticStorageDurationVariable | | | | variables.cpp:56:14:56:29 | externInFunction | file://:0:0:0:0 | int | GlobalLikeVariable, GlobalVariable, StaticStorageDurationVariable | | |
| variables.cpp:60:10:60:17 | __func__ | file://:0:0:0:0 | const char[9] | GlobalLikeVariable, StaticInitializedStaticLocalVariable | | static | | variables.cpp:60:10:60:17 | __func__ | file://:0:0:0:0 | const char[9] | GlobalLikeVariable, StaticInitializedStaticLocalVariable | | static |

View File

@@ -12,6 +12,7 @@ ql/go/ql/src/Security/CWE-079/HtmlTemplateEscapingBypassXss.ql
ql/go/ql/src/Security/CWE-079/ReflectedXss.ql ql/go/ql/src/Security/CWE-079/ReflectedXss.ql
ql/go/ql/src/Security/CWE-089/SqlInjection.ql ql/go/ql/src/Security/CWE-089/SqlInjection.ql
ql/go/ql/src/Security/CWE-089/StringBreak.ql ql/go/ql/src/Security/CWE-089/StringBreak.ql
ql/go/ql/src/Security/CWE-1004/CookieWithoutHttpOnly.ql
ql/go/ql/src/Security/CWE-190/AllocationSizeOverflow.ql ql/go/ql/src/Security/CWE-190/AllocationSizeOverflow.ql
ql/go/ql/src/Security/CWE-209/StackTraceExposure.ql ql/go/ql/src/Security/CWE-209/StackTraceExposure.ql
ql/go/ql/src/Security/CWE-295/DisabledCertificateCheck.ql ql/go/ql/src/Security/CWE-295/DisabledCertificateCheck.ql
@@ -26,6 +27,7 @@ ql/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.ql
ql/go/ql/src/Security/CWE-352/ConstantOauth2State.ql ql/go/ql/src/Security/CWE-352/ConstantOauth2State.ql
ql/go/ql/src/Security/CWE-601/BadRedirectCheck.ql ql/go/ql/src/Security/CWE-601/BadRedirectCheck.ql
ql/go/ql/src/Security/CWE-601/OpenUrlRedirect.ql ql/go/ql/src/Security/CWE-601/OpenUrlRedirect.ql
ql/go/ql/src/Security/CWE-614/CookieWithoutSecure.ql
ql/go/ql/src/Security/CWE-640/EmailInjection.ql ql/go/ql/src/Security/CWE-640/EmailInjection.ql
ql/go/ql/src/Security/CWE-643/XPathInjection.ql ql/go/ql/src/Security/CWE-643/XPathInjection.ql
ql/go/ql/src/Security/CWE-681/IncorrectIntegerConversionQuery.ql ql/go/ql/src/Security/CWE-681/IncorrectIntegerConversionQuery.ql

View File

@@ -34,6 +34,7 @@ ql/go/ql/src/Security/CWE-079/HtmlTemplateEscapingBypassXss.ql
ql/go/ql/src/Security/CWE-079/ReflectedXss.ql ql/go/ql/src/Security/CWE-079/ReflectedXss.ql
ql/go/ql/src/Security/CWE-089/SqlInjection.ql ql/go/ql/src/Security/CWE-089/SqlInjection.ql
ql/go/ql/src/Security/CWE-089/StringBreak.ql ql/go/ql/src/Security/CWE-089/StringBreak.ql
ql/go/ql/src/Security/CWE-1004/CookieWithoutHttpOnly.ql
ql/go/ql/src/Security/CWE-117/LogInjection.ql ql/go/ql/src/Security/CWE-117/LogInjection.ql
ql/go/ql/src/Security/CWE-190/AllocationSizeOverflow.ql ql/go/ql/src/Security/CWE-190/AllocationSizeOverflow.ql
ql/go/ql/src/Security/CWE-209/StackTraceExposure.ql ql/go/ql/src/Security/CWE-209/StackTraceExposure.ql
@@ -49,6 +50,7 @@ ql/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.ql
ql/go/ql/src/Security/CWE-352/ConstantOauth2State.ql ql/go/ql/src/Security/CWE-352/ConstantOauth2State.ql
ql/go/ql/src/Security/CWE-601/BadRedirectCheck.ql ql/go/ql/src/Security/CWE-601/BadRedirectCheck.ql
ql/go/ql/src/Security/CWE-601/OpenUrlRedirect.ql ql/go/ql/src/Security/CWE-601/OpenUrlRedirect.ql
ql/go/ql/src/Security/CWE-614/CookieWithoutSecure.ql
ql/go/ql/src/Security/CWE-640/EmailInjection.ql ql/go/ql/src/Security/CWE-640/EmailInjection.ql
ql/go/ql/src/Security/CWE-643/XPathInjection.ql ql/go/ql/src/Security/CWE-643/XPathInjection.ql
ql/go/ql/src/Security/CWE-681/IncorrectIntegerConversionQuery.ql ql/go/ql/src/Security/CWE-681/IncorrectIntegerConversionQuery.ql

View File

@@ -12,6 +12,7 @@ ql/go/ql/src/Security/CWE-079/HtmlTemplateEscapingBypassXss.ql
ql/go/ql/src/Security/CWE-079/ReflectedXss.ql ql/go/ql/src/Security/CWE-079/ReflectedXss.ql
ql/go/ql/src/Security/CWE-089/SqlInjection.ql ql/go/ql/src/Security/CWE-089/SqlInjection.ql
ql/go/ql/src/Security/CWE-089/StringBreak.ql ql/go/ql/src/Security/CWE-089/StringBreak.ql
ql/go/ql/src/Security/CWE-1004/CookieWithoutHttpOnly.ql
ql/go/ql/src/Security/CWE-117/LogInjection.ql ql/go/ql/src/Security/CWE-117/LogInjection.ql
ql/go/ql/src/Security/CWE-190/AllocationSizeOverflow.ql ql/go/ql/src/Security/CWE-190/AllocationSizeOverflow.ql
ql/go/ql/src/Security/CWE-209/StackTraceExposure.ql ql/go/ql/src/Security/CWE-209/StackTraceExposure.ql
@@ -27,6 +28,7 @@ ql/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.ql
ql/go/ql/src/Security/CWE-352/ConstantOauth2State.ql ql/go/ql/src/Security/CWE-352/ConstantOauth2State.ql
ql/go/ql/src/Security/CWE-601/BadRedirectCheck.ql ql/go/ql/src/Security/CWE-601/BadRedirectCheck.ql
ql/go/ql/src/Security/CWE-601/OpenUrlRedirect.ql ql/go/ql/src/Security/CWE-601/OpenUrlRedirect.ql
ql/go/ql/src/Security/CWE-614/CookieWithoutSecure.ql
ql/go/ql/src/Security/CWE-640/EmailInjection.ql ql/go/ql/src/Security/CWE-640/EmailInjection.ql
ql/go/ql/src/Security/CWE-643/XPathInjection.ql ql/go/ql/src/Security/CWE-643/XPathInjection.ql
ql/go/ql/src/Security/CWE-681/IncorrectIntegerConversionQuery.ql ql/go/ql/src/Security/CWE-681/IncorrectIntegerConversionQuery.ql

View File

@@ -9,7 +9,6 @@ ql/go/ql/src/Security/CWE-079/StoredXss.ql
ql/go/ql/src/Security/CWE-798/HardcodedCredentials.ql ql/go/ql/src/Security/CWE-798/HardcodedCredentials.ql
ql/go/ql/src/definitions.ql ql/go/ql/src/definitions.ql
ql/go/ql/src/experimental/CWE-090/LDAPInjection.ql ql/go/ql/src/experimental/CWE-090/LDAPInjection.ql
ql/go/ql/src/experimental/CWE-1004/CookieWithoutHttpOnly.ql
ql/go/ql/src/experimental/CWE-203/Timing.ql ql/go/ql/src/experimental/CWE-203/Timing.ql
ql/go/ql/src/experimental/CWE-285/PamAuthBypass.ql ql/go/ql/src/experimental/CWE-285/PamAuthBypass.ql
ql/go/ql/src/experimental/CWE-287/ImproperLdapAuth.ql ql/go/ql/src/experimental/CWE-287/ImproperLdapAuth.ql

View File

@@ -41,6 +41,7 @@ import semmle.go.frameworks.ElazarlGoproxy
import semmle.go.frameworks.Email import semmle.go.frameworks.Email
import semmle.go.frameworks.Encoding import semmle.go.frameworks.Encoding
import semmle.go.frameworks.Fasthttp import semmle.go.frameworks.Fasthttp
import semmle.go.frameworks.Gin
import semmle.go.frameworks.GinCors import semmle.go.frameworks.GinCors
import semmle.go.frameworks.Glog import semmle.go.frameworks.Glog
import semmle.go.frameworks.GoJose import semmle.go.frameworks.GoJose

View File

@@ -380,4 +380,96 @@ module Http {
/** Gets a node that is used in a check that is tested before this handler is run. */ /** Gets a node that is used in a check that is tested before this handler is run. */
predicate guardedBy(DataFlow::Node check) { super.guardedBy(check) } predicate guardedBy(DataFlow::Node check) { super.guardedBy(check) }
} }
/** Provides a class for modeling new HTTP response cookie write APIs. */
module CookieWrite {
/**
* A write of an HTTP Cookie to an HTTP response.
*
* Extend this class to model new APIs. If you want to refine existing API models,
* extend `HTTP::CookieWrite` instead.
*/
abstract class Range extends DataFlow::Node {
/** Gets the name of the cookie written. */
abstract DataFlow::Node getName();
/** Gets the value of the cookie written. */
abstract DataFlow::Node getValue();
/** Gets the `Secure` attribute of the cookie written. */
abstract DataFlow::Node getSecure();
/** Gets the `HttpOnly` attribute of the cookie written. */
abstract DataFlow::Node getHttpOnly();
}
}
/**
* A write of an HTTP Cookie to an HTTP response.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `HTTP::CookieWrite::Range` instead.
*/
class CookieWrite extends DataFlow::Node instanceof CookieWrite::Range {
/** Gets the name of the cookie written. */
DataFlow::Node getName() { result = super.getName() }
/** Gets the value of the cookie written. */
DataFlow::Node getValue() { result = super.getValue() }
/** Gets the `Secure` attribute of the cookie written. */
DataFlow::Node getSecure() { result = super.getSecure() }
/** Gets the `HttpOnly` attribute of the cookie written. */
DataFlow::Node getHttpOnly() { result = super.getHttpOnly() }
}
/** Provides a class for modeling the new APIs for writes to options of an HTTP cookie. */
module CookieOptionWrite {
/**
* A write to an option of an HTTP cookie object.
*
* Extend this class to model new APIs. If you want to refine existing API models,
* extend `HTTP::CookieOptionWrite` instead.
*/
abstract class Range extends DataFlow::Node {
/** Gets the node representing the cookie object for the options being set. */
abstract DataFlow::Node getCookieOutput();
/** Gets the name of the cookie represented, if any. */
abstract DataFlow::Node getName();
/** Gets the value of the cookie represented, if any. */
abstract DataFlow::Node getValue();
/** Gets the `Secure` attribute of the cookie represented, if any. */
abstract DataFlow::Node getSecure();
/** Gets the `HttpOnly` attribute of the cookie represented, if any. */
abstract DataFlow::Node getHttpOnly();
}
}
/**
* A write to an option of an HTTP cookie object.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `HTTP::CookieOptionWrite::Range` instead.
*/
class CookieOptionWrite extends DataFlow::Node instanceof CookieOptionWrite::Range {
/** Gets the node representing the cookie object for the options being set. */
DataFlow::Node getCookieOutput() { result = super.getCookieOutput() }
/** Gets the name of the cookie represented, if any. */
DataFlow::Node getName() { result = super.getName() }
/** Gets the value of the cookie represented, if any. */
DataFlow::Node getValue() { result = super.getValue() }
/** Gets the `Secure` attribute of the cookie represented, if any. */
DataFlow::Node getSecure() { result = super.getSecure() }
/** Gets the `HttpOnly` attribute of the cookie represented, if any. */
DataFlow::Node getHttpOnly() { result = super.getHttpOnly() }
}
} }

View File

@@ -0,0 +1,24 @@
/**
* Provides classes for modeling the `github.com/gin-gonic/gin` package.
*/
import go
import semmle.go.concepts.HTTP
/** Provides models for the `gin-gonic/gin` package. */
module Gin {
/** Gets the package name `github.com/gin-gonic/gin`. */
string packagePath() { result = package("github.com/gin-gonic/gin", "") }
private class GinCookieWrite extends Http::CookieWrite::Range, DataFlow::MethodCallNode {
GinCookieWrite() { this.getTarget().hasQualifiedName(packagePath(), "Context", "SetCookie") }
override DataFlow::Node getName() { result = this.getArgument(0) }
override DataFlow::Node getValue() { result = this.getArgument(1) }
override DataFlow::Node getSecure() { result = this.getArgument(5) }
override DataFlow::Node getHttpOnly() { result = this.getArgument(6) }
}
}

View File

@@ -293,4 +293,38 @@ module NetHttp {
override DataFlow::Node getAPathArgument() { result = this.getArgument(2) } override DataFlow::Node getAPathArgument() { result = this.getArgument(2) }
} }
private class CookieWrite extends Http::CookieWrite::Range, DataFlow::CallNode {
CookieWrite() { this.getTarget().hasQualifiedName(package("net/http", ""), "SetCookie") }
override DataFlow::Node getName() { result = this.getArgument(1) }
override DataFlow::Node getValue() { result = this.getArgument(1) }
override DataFlow::Node getSecure() { result = this.getArgument(1) }
override DataFlow::Node getHttpOnly() { result = this.getArgument(1) }
}
private class CookieFieldWrite extends Http::CookieOptionWrite::Range {
DataFlow::Node written;
string fieldName;
CookieFieldWrite() {
exists(Write w, Field f |
f.hasQualifiedName(package("net/http", ""), "Cookie", fieldName) and
w.writesField(this, f, written)
)
}
override DataFlow::Node getCookieOutput() { result = this }
override DataFlow::Node getName() { fieldName = "Name" and result = written }
override DataFlow::Node getValue() { fieldName = "Value" and result = written }
override DataFlow::Node getSecure() { fieldName = "Secure" and result = written }
override DataFlow::Node getHttpOnly() { fieldName = "HttpOnly" and result = written }
}
} }

View File

@@ -0,0 +1,77 @@
/** Provides classes and predicates for identifying HTTP cookies without the `HttpOnly` attribute. */
import go
import semmle.go.concepts.HTTP
import semmle.go.dataflow.DataFlow
private module SensitiveCookieNameConfig implements DataFlow::ConfigSig {
/**
* Holds if `source` is an expression with a name or literal value `val` indicating a sensitive cookie.
*/
additional predicate isSource(DataFlow::Node source, string val) {
(
val = source.asExpr().getStringValue() or
val = source.asExpr().(Name).getTarget().getName()
) and
val.regexpMatch("(?i).*(session|login|token|user|auth|credential).*") and
not val.regexpMatch("(?i).*(xsrf|csrf|forgery).*")
}
predicate isSource(DataFlow::Node source) { isSource(source, _) }
additional predicate isSink(DataFlow::Node sink, Http::CookieWrite cw) { sink = cw.getName() }
predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(Http::CookieOptionWrite co | co.getName() = pred and co.getCookieOutput() = succ)
}
}
/** Tracks flow from sensitive names to HTTP cookie writes. */
module SensitiveCookieNameFlow = TaintTracking::Global<SensitiveCookieNameConfig>;
private module BooleanCookieHttpOnlyConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.getType().getUnderlyingType() instanceof BoolType
}
predicate isSink(DataFlow::Node sink) { exists(Http::CookieWrite cw | sink = cw.getHttpOnly()) }
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(Http::CookieOptionWrite co | co.getHttpOnly() = pred and co.getCookieOutput() = succ)
}
}
/** Tracks flow from boolean expressions to the `HttpOnly` attribute of HTTP cookie writes. */
module BooleanCookieHttpOnlyFlow = TaintTracking::Global<BooleanCookieHttpOnlyConfig>;
/** Holds if `cw` has the `HttpOnly` attribute left at its default value of `false`. */
predicate isNonHttpOnlyDefault(Http::CookieWrite cw) {
not BooleanCookieHttpOnlyFlow::flowTo(cw.getHttpOnly())
}
/** Holds if `cw` has the `HttpOnly` attribute explicitly set to `false`, from the expression `boolFalse`. */
predicate isNonHttpOnlyDirect(Http::CookieWrite cw, Expr boolFalse) {
BooleanCookieHttpOnlyFlow::flow(DataFlow::exprNode(boolFalse), cw.getHttpOnly()) and
boolFalse.getBoolValue() = false
}
/** Holds if `cw` has the `HttpOnly` attribute set to `false`, either explicitly or by default. */
predicate isNonHttpOnlyCookie(Http::CookieWrite cw) {
isNonHttpOnlyDefault(cw) or
isNonHttpOnlyDirect(cw, _)
}
/**
* Holds if `cw` has the sensitive name `name`, from the expression `nameExpr`.
* `source` and `sink` represent the data flow path from the sensitive name expression to the cookie write.
*/
predicate isSensitiveCookie(
Http::CookieWrite cw, string name, SensitiveCookieNameFlow::PathNode source,
SensitiveCookieNameFlow::PathNode sink
) {
SensitiveCookieNameFlow::flowPath(source, sink) and
SensitiveCookieNameConfig::isSource(source.getNode(), name) and
SensitiveCookieNameConfig::isSink(sink.getNode(), cw)
}

View File

@@ -0,0 +1,37 @@
/** Provides classes and predicates for identifying HTTP cookies without the `Secure` attribute. */
import go
import semmle.go.concepts.HTTP
import semmle.go.dataflow.DataFlow
private module BooleanCookieSecureConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.getType().getUnderlyingType() instanceof BoolType
}
predicate isSink(DataFlow::Node sink) { exists(Http::CookieWrite cw | sink = cw.getSecure()) }
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(Http::CookieOptionWrite co | co.getSecure() = pred and co.getCookieOutput() = succ)
}
}
/** Tracks flow from boolean expressions to the `Secure` attribute of HTTP cookie writes. */
module BooleanCookieSecureFlow = TaintTracking::Global<BooleanCookieSecureConfig>;
/** Holds if `cw` has the `Secure` attribute left at its default value of `false`. */
predicate isInsecureDefault(Http::CookieWrite cw) {
not BooleanCookieSecureFlow::flowTo(cw.getSecure())
}
/** Holds if `cw` has the `Secure` attribute explicitly set to `false`, from the expression `boolFalse`. */
predicate isInsecureDirect(Http::CookieWrite cw, Expr boolFalse) {
BooleanCookieSecureFlow::flow(DataFlow::exprNode(boolFalse), cw.getSecure()) and
boolFalse.getBoolValue() = false
}
/** Holds if `cw` has the `Secure` attribute set to `false`, either explicitly or by default. */
predicate isInsecureCookie(Http::CookieWrite cw) {
isInsecureDefault(cw) or
isInsecureDirect(cw, _)
}

View File

@@ -0,0 +1,34 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Cookies without the <code>HttpOnly</code> flag set are accessible to client-side scripts such as JavaScript running in the same origin.
In case of a Cross-Site Scripting (XSS) vulnerability, the cookie can be stolen by a malicious script.
If a sensitive cookie does not need to be accessed directly by client-side JS, the <code>HttpOnly</code> flag should be set.</p>
</overview>
<recommendation>
<p>
Set the <code>HttpOnly</code> flag to <code>true</code> for authentication cookies to ensure they are not accessible to client-side scripts.
</p>
</recommendation>
<example>
<p>
In the following example, in the case marked BAD, the <code>HttpOnly</code> flag is not set, so the default value of <code>false</code> is used.
In the case marked GOOD, the <code>HttpOnly</code> flag is set to <code>true</code>.
</p>
<sample src="examples/CookieWithoutHttpOnly.go"/>
</example>
<references>
<li>MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie">Set-Cookie</a> Header.</li>
<li>PortSwigger: <a href="https://portswigger.net/kb/issues/00500600_cookie-without-httponly-flag-set">Cookie without HttpOnly flag set</a></li>
</references>
</qhelp>

View File

@@ -0,0 +1,25 @@
/**
* @name Cookie 'HttpOnly' attribute is not set to true
* @description Sensitive cookies without the `HttpOnly` property set are accessible by client-side scripts such as JavaScript.
* This makes them more vulnerable to being stolen by an XSS attack.
* @kind path-problem
* @problem.severity warning
* @precision high
* @security-severity 5.0
* @id go/cookie-httponly-not-set
* @tags security
* external/cwe/cwe-1004
*/
import go
import semmle.go.security.CookieWithoutHttpOnly
import SensitiveCookieNameFlow::PathGraph
from
Http::CookieWrite cw, string name, SensitiveCookieNameFlow::PathNode source,
SensitiveCookieNameFlow::PathNode sink
where
isSensitiveCookie(cw, name, source, sink) and
isNonHttpOnlyCookie(cw)
select cw, source, sink, "Sensitive cookie $@ does not set HttpOnly attribute to true.", source,
name

View File

@@ -0,0 +1,22 @@
package main
import (
"net/http"
)
func handlerBad(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session",
Value: "secret",
}
http.SetCookie(w, &c) // BAD: The HttpOnly flag is set to false by default.
}
func handlerGood(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session",
Value: "secret",
HttpOnly: true,
}
http.SetCookie(w, &c) // GOOD: The HttpOnly flag is set to true.
}

View File

@@ -0,0 +1,35 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Cookies without the <code>Secure</code> flag set may be transmitted using HTTP instead of HTTPS.
This leaves them vulnerable to being read by a third party attacker. If a sensitive cookie such as a session
key is intercepted this way, it would allow the attacker to perform actions on a user's behalf.</p>
</overview>
<recommendation>
<p>
Set the <code>Secure</code> flag to <code>true</code> to ensure cookies are only transmitted over secure HTTPS connections.
</p>
</recommendation>
<example>
<p>
In the following example, in the case marked BAD, the <code>Secure</code> flag is set to <code>false</code> by default.
In the case marked GOOD, the <code>Secure</code> flag is set to <code>true</code>.
</p>
<sample src="examples/CookieWithoutSecure.go"/>
</example>
<references>
<li>MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie">Set-Cookie</a> Header.</li>
<li>Detectify: <a href="https://support.detectify.com/support/solutions/articles/48001048982-cookie-lack-secure-flag">Cookie lack Secure flag</a>.</li>
<li>PortSwigger: <a href="https://portswigger.net/kb/issues/00500200_tls-cookie-without-secure-flag-set">TLS cookie without secure flag set</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,19 @@
/**
* @name Cookie 'Secure' attribute is not set to true
* @description Cookies without the `Secure` flag may be sent in cleartext.
* This makes them vulnerable to be intercepted by an attacker.
* @kind problem
* @problem.severity warning
* @precision high
* @security-severity 4.0
* @id go/cookie-secure-not-set
* @tags security
* external/cwe/cwe-614
*/
import go
import semmle.go.security.CookieWithoutSecure
from Http::CookieWrite cw
where isInsecureCookie(cw)
select cw, "Cookie does not set Secure attribute to true."

View File

@@ -0,0 +1,22 @@
package main
import (
"net/http"
)
func handlerBad(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session",
Value: "secret",
}
http.SetCookie(w, &c) // BAD: The Secure flag is set to false by default.
}
func handlerGood(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session",
Value: "secret",
Secure: true,
}
http.SetCookie(w, &c) // GOOD: The Secure flag is set to true.
}

View File

@@ -0,0 +1,5 @@
---
category: newQuery
---
* The `go/cookie-http-only-not-set` query has been promoted from the experimental query pack. This query was originally contributed to the experimental query pack by @edvraa.
* A new query `go/cookie-secure-not-set` has been added to detect cookies without the `Secure` flag set.

View File

@@ -1,245 +0,0 @@
import go
private class NetHttpCookieType extends Type {
NetHttpCookieType() { this.hasQualifiedName(package("net/http", ""), "Cookie") }
}
private class GinContextSetCookieMethod extends Method {
GinContextSetCookieMethod() {
this.hasQualifiedName(package("github.com/gin-gonic/gin", ""), "Context", "SetCookie")
}
}
private class GorillaSessionOptionsField extends Field {
GorillaSessionOptionsField() {
this.hasQualifiedName(package("github.com/gorilla/sessions", ""), "Session", "Options")
}
}
/**
* A simplistic points-to alternative: given a struct creation and a field name, get the values that field can be assigned.
*
* Assumptions:
* - we don't reassign the variable that the creation is stored in
* - we always access the creation through the same variable it is initially assigned to
*
* This should cover most typical patterns...
*/
private DataFlow::Node getValueForFieldWrite(StructLit sl, string field) {
exists(Write w, DataFlow::Node base, Field f |
f.getName() = field and
w.writesFieldPreUpdate(base, f, result) and
(
sl = base.asExpr()
or
base.asExpr() instanceof VariableName and
base.getAPredecessor*().asExpr() = sl
)
)
}
/**
* Holds if the expression or its value has a sensitive name
*/
private predicate isAuthVariable(Expr expr) {
exists(string val |
(
val = expr.getStringValue() or
val = expr.(Name).getTarget().getName()
) and
val.regexpMatch("(?i).*(session|login|token|user|auth|credential).*") and
not val.regexpMatch("(?i).*(xsrf|csrf|forgery).*")
)
}
/**
* A cookie passed as the second parameter to `net/http.SetCookie`.
*/
private class SetCookieSink extends DataFlow::Node {
SetCookieSink() {
exists(DataFlow::CallNode cn |
cn.getTarget().hasQualifiedName(package("net/http", ""), "SetCookie") and
this = cn.getArgument(1)
)
}
}
private module NameToNetHttpCookieTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { isAuthVariable(source.asExpr()) }
predicate isSink(DataFlow::Node sink) { sink instanceof SetCookieSink }
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(StructLit sl |
sl.getType() instanceof NetHttpCookieType and
getValueForFieldWrite(sl, "Name") = pred and
sl = succ.asExpr()
)
}
}
/** Tracks taint flow from sensitive names to `net/http.SetCookie`. */
module NameToNetHttpCookieTrackingFlow = TaintTracking::Global<NameToNetHttpCookieTrackingConfig>;
private module BoolToNetHttpCookieTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.getType().getUnderlyingType() instanceof BoolType
}
predicate isSink(DataFlow::Node sink) { sink instanceof SetCookieSink }
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(StructLit sl |
sl.getType() instanceof NetHttpCookieType and
getValueForFieldWrite(sl, "HttpOnly") = pred and
sl = succ.asExpr()
)
}
}
/**
* Tracks taint flow from a `bool` assigned to `HttpOnly` to
* `net/http.SetCookie`.
*/
module BoolToNetHttpCookieTrackingFlow = TaintTracking::Global<BoolToNetHttpCookieTrackingConfig>;
private module BoolToGinSetCookieTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.getBoolValue() = false }
predicate isSink(DataFlow::Node sink) {
exists(DataFlow::MethodCallNode mcn |
mcn.getTarget() instanceof GinContextSetCookieMethod and
mcn.getArgument(6) = sink and
exists(DataFlow::Node nameArg |
NameToGinSetCookieTrackingFlow::flowTo(nameArg) and
mcn.getArgument(0) = nameArg
)
)
}
predicate observeDiffInformedIncrementalMode() {
any() // Merged with other flows in CookieWithoutHttpOnly.ql
}
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
}
/**
* Tracks data flow from `HttpOnly` set to `false` to
* `gin-gonic/gin.Context.SetCookie`.
*/
module BoolToGinSetCookieTrackingFlow = DataFlow::Global<BoolToGinSetCookieTrackingConfig>;
private module NameToGinSetCookieTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { isAuthVariable(source.asExpr()) }
predicate isSink(DataFlow::Node sink) {
exists(DataFlow::MethodCallNode mcn |
mcn.getTarget() instanceof GinContextSetCookieMethod and
mcn.getArgument(0) = sink
)
}
}
/**
* Tracks taint flow from sensitive names to `gin-gonic/gin.Context.SetCookie`.
*/
private module NameToGinSetCookieTrackingFlow = DataFlow::Global<NameToGinSetCookieTrackingConfig>;
/**
* The receiver of `gorilla/sessions.Session.Save` call.
*/
private class GorillaSessionSaveSink extends DataFlow::Node {
GorillaSessionSaveSink() {
exists(DataFlow::MethodCallNode mcn |
this = mcn.getReceiver() and
mcn.getTarget()
.hasQualifiedName(package("github.com/gorilla/sessions", ""), "Session", "Save")
)
}
}
private class GorillaStoreSaveSink extends DataFlow::Node {
GorillaStoreSaveSink() {
exists(DataFlow::MethodCallNode mcn |
this = mcn.getArgument(2) and
mcn.getTarget()
.hasQualifiedName(package("github.com/gorilla/sessions", ""), "CookieStore", "Save")
)
}
}
private module GorillaCookieStoreSaveTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source
.(DataFlow::CallNode)
.getTarget()
.hasQualifiedName(package("github.com/gorilla/sessions", ""), "NewCookieStore")
}
predicate isSink(DataFlow::Node sink) {
sink instanceof GorillaSessionSaveSink or
sink instanceof GorillaStoreSaveSink
}
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(DataFlow::MethodCallNode cn |
cn.getTarget()
.hasQualifiedName(package("github.com/gorilla/sessions", ""), "CookieStore", "Get") and
pred = cn.getReceiver() and
succ = cn.getResult(0)
)
}
}
/**
* Tracks data flow from gorilla cookie store creation to
* `gorilla/sessions.Session.Save`.
*/
module GorillaCookieStoreSaveTrackingFlow = DataFlow::Global<GorillaCookieStoreSaveTrackingConfig>;
private module GorillaSessionOptionsTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(StructLit sl |
sl.getType().hasQualifiedName(package("github.com/gorilla/sessions", ""), "Options") and
source.asExpr() = sl
)
}
predicate isSink(DataFlow::Node sink) { sink instanceof GorillaSessionSaveSink }
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(GorillaSessionOptionsField f, DataFlow::Write w | w.writesField(succ, f, pred))
}
}
/**
* Tracks taint flow from session options to
* `gorilla/sessions.Session.Save`.
*/
module GorillaSessionOptionsTrackingFlow =
TaintTracking::Global<GorillaSessionOptionsTrackingConfig>;
private module BoolToGorillaSessionOptionsTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.getType().getUnderlyingType() instanceof BoolType
}
predicate isSink(DataFlow::Node sink) { sink instanceof GorillaSessionSaveSink }
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(StructLit sl |
getValueForFieldWrite(sl, "HttpOnly") = pred and
sl = succ.asExpr()
)
or
exists(GorillaSessionOptionsField f, DataFlow::Write w | w.writesField(succ, f, pred))
}
}
/**
* Tracks taint flow from a `bool` assigned to `HttpOnly` to
* `gorilla/sessions.Session.Save`.
*/
module BoolToGorillaSessionOptionsTrackingFlow =
TaintTracking::Global<BoolToGorillaSessionOptionsTrackingConfig>;

View File

@@ -1,42 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Cookies without <code>HttpOnly</code> attribute are accessible to JavaScript running in the same origin. In case of
Cross-Site Scripting (XSS) vulnerability the cookie can be stolen by malicious script.
</p>
</overview>
<recommendation>
<p>
Protect sensitive cookies, such as related to authentication, by setting <code>HttpOnly</code> to <code>true</code> to make
them not accessible to JavaScript.
</p>
</recommendation>
<example>
<p>
In the following example the default <code>HttpOnly</code> value is <code>false</code>.
</p>
<sample src="CookieWithoutHttpOnlyBad.go" />
<p>
In the example below <code>HttpOnly</code> is set to <code>true</code>.
</p>
<sample src="CookieWithoutHttpOnlyGood.go" />
</example>
<references>
<li><a href="https://golang.org/pkg/net/http/#Cookie">type Cookie,</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie">Set-Cookie</a> Header,</li>
</references>
</qhelp>

View File

@@ -1,99 +0,0 @@
/**
* @name 'HttpOnly' attribute is not set to true
* @description Omitting the 'HttpOnly' attribute for security sensitive data allows
* malicious JavaScript to steal it in case of XSS vulnerability. Always set
* 'HttpOnly' to 'true' to authentication related cookie to make it
* not accessible by JavaScript.
* @kind path-problem
* @problem.severity warning
* @precision high
* @id go/cookie-httponly-not-set
* @tags security
* experimental
* external/cwe/cwe-1004
*/
import go
import AuthCookie
module NetHttpCookieTrackingFlow =
DataFlow::MergePathGraph<NameToNetHttpCookieTrackingFlow::PathNode,
BoolToNetHttpCookieTrackingFlow::PathNode, NameToNetHttpCookieTrackingFlow::PathGraph,
BoolToNetHttpCookieTrackingFlow::PathGraph>;
module GorillaTrackingFlow =
DataFlow::MergePathGraph3<GorillaCookieStoreSaveTrackingFlow::PathNode,
GorillaSessionOptionsTrackingFlow::PathNode, BoolToGorillaSessionOptionsTrackingFlow::PathNode,
GorillaCookieStoreSaveTrackingFlow::PathGraph, GorillaSessionOptionsTrackingFlow::PathGraph,
BoolToGorillaSessionOptionsTrackingFlow::PathGraph>;
module MergedFlow =
DataFlow::MergePathGraph3<NetHttpCookieTrackingFlow::PathNode,
BoolToGinSetCookieTrackingFlow::PathNode, GorillaTrackingFlow::PathNode,
NetHttpCookieTrackingFlow::PathGraph, BoolToGinSetCookieTrackingFlow::PathGraph,
GorillaTrackingFlow::PathGraph>;
import MergedFlow::PathGraph
/** Holds if `HttpOnly` of `net/http.SetCookie` is set to `false` or not set (default value is used). */
predicate isNetHttpCookieFlow(
NetHttpCookieTrackingFlow::PathNode source, NetHttpCookieTrackingFlow::PathNode sink
) {
exists(
NameToNetHttpCookieTrackingFlow::PathNode sensitiveName,
NameToNetHttpCookieTrackingFlow::PathNode setCookieSink
|
NameToNetHttpCookieTrackingFlow::flowPath(sensitiveName, setCookieSink) and
(
not BoolToNetHttpCookieTrackingFlow::flowTo(sink.getNode()) and
source.asPathNode1() = sensitiveName and
sink.asPathNode1() = setCookieSink
or
BoolToNetHttpCookieTrackingFlow::flowPath(source.asPathNode2(), sink.asPathNode2()) and
source.getNode().getBoolValue() = false and
setCookieSink.getNode() = sink.getNode()
)
)
}
/**
* Holds if there is gorilla cookie store creation to `Save` path and
* `HttpOnly` is set to `false` or not set (default value is used).
*/
predicate isGorillaSessionsCookieFlow(
GorillaTrackingFlow::PathNode source, GorillaTrackingFlow::PathNode sink
) {
exists(
GorillaCookieStoreSaveTrackingFlow::PathNode cookieStoreCreate,
GorillaCookieStoreSaveTrackingFlow::PathNode sessionSave
|
GorillaCookieStoreSaveTrackingFlow::flowPath(cookieStoreCreate, sessionSave) and
(
not GorillaSessionOptionsTrackingFlow::flowTo(sink.getNode()) and
source.asPathNode1() = cookieStoreCreate and
sink.asPathNode1() = sessionSave
or
exists(GorillaTrackingFlow::PathNode options, GorillaTrackingFlow::PathNode sessionSave2 |
GorillaSessionOptionsTrackingFlow::flowPath(options.asPathNode2(),
sessionSave2.asPathNode2()) and
(
not BoolToGorillaSessionOptionsTrackingFlow::flowTo(sink.getNode()) and
sink = sessionSave2 and
source = options and
sessionSave.getNode() = sessionSave2.getNode()
or
BoolToGorillaSessionOptionsTrackingFlow::flowPath(source.asPathNode3(), sink.asPathNode3()) and
source.getNode().getBoolValue() = false and
sink.getNode() = sessionSave.getNode()
)
)
)
)
}
from MergedFlow::PathNode source, MergedFlow::PathNode sink
where
isNetHttpCookieFlow(source.asPathNode1(), sink.asPathNode1()) or
BoolToGinSetCookieTrackingFlow::flowPath(source.asPathNode2(), sink.asPathNode2()) or
isGorillaSessionsCookieFlow(source.asPathNode3(), sink.asPathNode3())
select sink.getNode(), source, sink, "Cookie attribute 'HttpOnly' is not set to true."

View File

@@ -1,17 +0,0 @@
package main
import (
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session",
Value: "secret",
}
http.SetCookie(w, &c)
}
func main() {
http.HandleFunc("/", handler)
}

View File

@@ -1,18 +0,0 @@
package main
import (
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session",
Value: "secret",
HttpOnly: true,
}
http.SetCookie(w, &c)
}
func main() {
http.HandleFunc("/", handler)
}

View File

@@ -1,432 +0,0 @@
edges
| CookieWithoutHttpOnly.go:11:7:14:2 | struct literal | CookieWithoutHttpOnly.go:15:20:15:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:11:7:14:2 | struct literal | CookieWithoutHttpOnly.go:15:21:15:21 | c | provenance | |
| CookieWithoutHttpOnly.go:12:10:12:18 | "session" | CookieWithoutHttpOnly.go:11:7:14:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:15:20:15:21 | &... [pointer] | CookieWithoutHttpOnly.go:15:20:15:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:15:21:15:21 | c | CookieWithoutHttpOnly.go:15:20:15:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:15:21:15:21 | c | CookieWithoutHttpOnly.go:15:20:15:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | CookieWithoutHttpOnly.go:24:20:24:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | CookieWithoutHttpOnly.go:24:20:24:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | CookieWithoutHttpOnly.go:24:21:24:21 | c | provenance | |
| CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | CookieWithoutHttpOnly.go:24:21:24:21 | c | provenance | |
| CookieWithoutHttpOnly.go:20:13:20:21 | "session" | CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:22:13:22:17 | false | CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:24:20:24:21 | &... [pointer] | CookieWithoutHttpOnly.go:24:20:24:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:24:20:24:21 | &... [pointer] | CookieWithoutHttpOnly.go:24:20:24:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:24:21:24:21 | c | CookieWithoutHttpOnly.go:24:20:24:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:24:21:24:21 | c | CookieWithoutHttpOnly.go:24:20:24:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:24:21:24:21 | c | CookieWithoutHttpOnly.go:24:20:24:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:24:21:24:21 | c | CookieWithoutHttpOnly.go:24:20:24:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | CookieWithoutHttpOnly.go:33:20:33:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | CookieWithoutHttpOnly.go:33:20:33:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | CookieWithoutHttpOnly.go:33:21:33:21 | c | provenance | |
| CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | CookieWithoutHttpOnly.go:33:21:33:21 | c | provenance | |
| CookieWithoutHttpOnly.go:29:13:29:21 | "session" | CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:31:13:31:16 | true | CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:33:20:33:21 | &... [pointer] | CookieWithoutHttpOnly.go:33:20:33:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:33:20:33:21 | &... [pointer] | CookieWithoutHttpOnly.go:33:20:33:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:33:21:33:21 | c | CookieWithoutHttpOnly.go:33:20:33:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:33:21:33:21 | c | CookieWithoutHttpOnly.go:33:20:33:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:33:21:33:21 | c | CookieWithoutHttpOnly.go:33:20:33:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:33:21:33:21 | c | CookieWithoutHttpOnly.go:33:20:33:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | CookieWithoutHttpOnly.go:42:20:42:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | CookieWithoutHttpOnly.go:42:20:42:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | CookieWithoutHttpOnly.go:42:21:42:21 | c | provenance | |
| CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | CookieWithoutHttpOnly.go:42:21:42:21 | c | provenance | |
| CookieWithoutHttpOnly.go:38:10:38:18 | "session" | CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:41:15:41:18 | true | CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:42:20:42:21 | &... [pointer] | CookieWithoutHttpOnly.go:42:20:42:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:42:20:42:21 | &... [pointer] | CookieWithoutHttpOnly.go:42:20:42:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:42:21:42:21 | c | CookieWithoutHttpOnly.go:42:20:42:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:42:21:42:21 | c | CookieWithoutHttpOnly.go:42:20:42:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:42:21:42:21 | c | CookieWithoutHttpOnly.go:42:20:42:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:42:21:42:21 | c | CookieWithoutHttpOnly.go:42:20:42:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | CookieWithoutHttpOnly.go:51:20:51:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | CookieWithoutHttpOnly.go:51:20:51:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | CookieWithoutHttpOnly.go:51:21:51:21 | c | provenance | |
| CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | CookieWithoutHttpOnly.go:51:21:51:21 | c | provenance | |
| CookieWithoutHttpOnly.go:47:10:47:18 | "session" | CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:50:15:50:19 | false | CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:51:20:51:21 | &... [pointer] | CookieWithoutHttpOnly.go:51:20:51:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:51:20:51:21 | &... [pointer] | CookieWithoutHttpOnly.go:51:20:51:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:51:21:51:21 | c | CookieWithoutHttpOnly.go:51:20:51:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:51:21:51:21 | c | CookieWithoutHttpOnly.go:51:20:51:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:51:21:51:21 | c | CookieWithoutHttpOnly.go:51:20:51:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:51:21:51:21 | c | CookieWithoutHttpOnly.go:51:20:51:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:55:2:55:4 | definition of val | CookieWithoutHttpOnly.go:59:13:59:15 | val | provenance | |
| CookieWithoutHttpOnly.go:55:9:55:13 | false | CookieWithoutHttpOnly.go:59:13:59:15 | val | provenance | |
| CookieWithoutHttpOnly.go:56:7:60:2 | struct literal | CookieWithoutHttpOnly.go:61:20:61:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:56:7:60:2 | struct literal | CookieWithoutHttpOnly.go:61:20:61:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:56:7:60:2 | struct literal | CookieWithoutHttpOnly.go:61:21:61:21 | c | provenance | |
| CookieWithoutHttpOnly.go:56:7:60:2 | struct literal | CookieWithoutHttpOnly.go:61:21:61:21 | c | provenance | |
| CookieWithoutHttpOnly.go:57:13:57:21 | "session" | CookieWithoutHttpOnly.go:56:7:60:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:59:13:59:15 | val | CookieWithoutHttpOnly.go:56:7:60:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:61:20:61:21 | &... [pointer] | CookieWithoutHttpOnly.go:61:20:61:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:61:20:61:21 | &... [pointer] | CookieWithoutHttpOnly.go:61:20:61:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:61:21:61:21 | c | CookieWithoutHttpOnly.go:61:20:61:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:61:21:61:21 | c | CookieWithoutHttpOnly.go:61:20:61:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:61:21:61:21 | c | CookieWithoutHttpOnly.go:61:20:61:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:61:21:61:21 | c | CookieWithoutHttpOnly.go:61:20:61:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:65:2:65:4 | definition of val | CookieWithoutHttpOnly.go:69:13:69:15 | val | provenance | |
| CookieWithoutHttpOnly.go:65:9:65:12 | true | CookieWithoutHttpOnly.go:69:13:69:15 | val | provenance | |
| CookieWithoutHttpOnly.go:66:7:70:2 | struct literal | CookieWithoutHttpOnly.go:71:20:71:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:66:7:70:2 | struct literal | CookieWithoutHttpOnly.go:71:20:71:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:66:7:70:2 | struct literal | CookieWithoutHttpOnly.go:71:21:71:21 | c | provenance | |
| CookieWithoutHttpOnly.go:66:7:70:2 | struct literal | CookieWithoutHttpOnly.go:71:21:71:21 | c | provenance | |
| CookieWithoutHttpOnly.go:67:13:67:21 | "session" | CookieWithoutHttpOnly.go:66:7:70:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:69:13:69:15 | val | CookieWithoutHttpOnly.go:66:7:70:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:71:20:71:21 | &... [pointer] | CookieWithoutHttpOnly.go:71:20:71:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:71:20:71:21 | &... [pointer] | CookieWithoutHttpOnly.go:71:20:71:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:71:21:71:21 | c | CookieWithoutHttpOnly.go:71:20:71:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:71:21:71:21 | c | CookieWithoutHttpOnly.go:71:20:71:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:71:21:71:21 | c | CookieWithoutHttpOnly.go:71:20:71:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:71:21:71:21 | c | CookieWithoutHttpOnly.go:71:20:71:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:75:2:75:4 | definition of val | CookieWithoutHttpOnly.go:80:15:80:17 | val | provenance | |
| CookieWithoutHttpOnly.go:75:9:75:12 | true | CookieWithoutHttpOnly.go:80:15:80:17 | val | provenance | |
| CookieWithoutHttpOnly.go:76:7:79:2 | struct literal | CookieWithoutHttpOnly.go:81:20:81:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:76:7:79:2 | struct literal | CookieWithoutHttpOnly.go:81:20:81:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:76:7:79:2 | struct literal | CookieWithoutHttpOnly.go:81:21:81:21 | c | provenance | |
| CookieWithoutHttpOnly.go:76:7:79:2 | struct literal | CookieWithoutHttpOnly.go:81:21:81:21 | c | provenance | |
| CookieWithoutHttpOnly.go:77:10:77:18 | "session" | CookieWithoutHttpOnly.go:76:7:79:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:80:15:80:17 | val | CookieWithoutHttpOnly.go:76:7:79:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:81:20:81:21 | &... [pointer] | CookieWithoutHttpOnly.go:81:20:81:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:81:20:81:21 | &... [pointer] | CookieWithoutHttpOnly.go:81:20:81:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:81:21:81:21 | c | CookieWithoutHttpOnly.go:81:20:81:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:81:21:81:21 | c | CookieWithoutHttpOnly.go:81:20:81:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:81:21:81:21 | c | CookieWithoutHttpOnly.go:81:20:81:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:81:21:81:21 | c | CookieWithoutHttpOnly.go:81:20:81:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:85:2:85:4 | definition of val | CookieWithoutHttpOnly.go:90:15:90:17 | val | provenance | |
| CookieWithoutHttpOnly.go:85:9:85:13 | false | CookieWithoutHttpOnly.go:90:15:90:17 | val | provenance | |
| CookieWithoutHttpOnly.go:86:7:89:2 | struct literal | CookieWithoutHttpOnly.go:91:20:91:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:86:7:89:2 | struct literal | CookieWithoutHttpOnly.go:91:20:91:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:86:7:89:2 | struct literal | CookieWithoutHttpOnly.go:91:21:91:21 | c | provenance | |
| CookieWithoutHttpOnly.go:86:7:89:2 | struct literal | CookieWithoutHttpOnly.go:91:21:91:21 | c | provenance | |
| CookieWithoutHttpOnly.go:87:10:87:18 | "session" | CookieWithoutHttpOnly.go:86:7:89:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:90:15:90:17 | val | CookieWithoutHttpOnly.go:86:7:89:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:91:20:91:21 | &... [pointer] | CookieWithoutHttpOnly.go:91:20:91:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:91:20:91:21 | &... [pointer] | CookieWithoutHttpOnly.go:91:20:91:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:91:21:91:21 | c | CookieWithoutHttpOnly.go:91:20:91:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:91:21:91:21 | c | CookieWithoutHttpOnly.go:91:20:91:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:91:21:91:21 | c | CookieWithoutHttpOnly.go:91:20:91:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:91:21:91:21 | c | CookieWithoutHttpOnly.go:91:20:91:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:95:7:98:2 | struct literal | CookieWithoutHttpOnly.go:100:20:100:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:95:7:98:2 | struct literal | CookieWithoutHttpOnly.go:100:21:100:21 | c | provenance | |
| CookieWithoutHttpOnly.go:99:15:99:19 | false | CookieWithoutHttpOnly.go:95:7:98:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:100:20:100:21 | &... [pointer] | CookieWithoutHttpOnly.go:100:20:100:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:100:21:100:21 | c | CookieWithoutHttpOnly.go:100:20:100:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:100:21:100:21 | c | CookieWithoutHttpOnly.go:100:20:100:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:104:10:104:18 | "session" | CookieWithoutHttpOnly.go:106:10:106:13 | name | provenance | |
| CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | CookieWithoutHttpOnly.go:110:20:110:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | CookieWithoutHttpOnly.go:110:20:110:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | CookieWithoutHttpOnly.go:110:21:110:21 | c | provenance | |
| CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | CookieWithoutHttpOnly.go:110:21:110:21 | c | provenance | |
| CookieWithoutHttpOnly.go:106:10:106:13 | name | CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:109:15:109:19 | false | CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:110:20:110:21 | &... [pointer] | CookieWithoutHttpOnly.go:110:20:110:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:110:20:110:21 | &... [pointer] | CookieWithoutHttpOnly.go:110:20:110:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:110:21:110:21 | c | CookieWithoutHttpOnly.go:110:20:110:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:110:21:110:21 | c | CookieWithoutHttpOnly.go:110:20:110:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:110:21:110:21 | c | CookieWithoutHttpOnly.go:110:20:110:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:110:21:110:21 | c | CookieWithoutHttpOnly.go:110:20:110:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:114:13:114:24 | "login_name" | CookieWithoutHttpOnly.go:116:10:116:16 | session | provenance | |
| CookieWithoutHttpOnly.go:115:7:118:2 | struct literal | CookieWithoutHttpOnly.go:120:20:120:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:115:7:118:2 | struct literal | CookieWithoutHttpOnly.go:120:20:120:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:115:7:118:2 | struct literal | CookieWithoutHttpOnly.go:120:21:120:21 | c | provenance | |
| CookieWithoutHttpOnly.go:115:7:118:2 | struct literal | CookieWithoutHttpOnly.go:120:21:120:21 | c | provenance | |
| CookieWithoutHttpOnly.go:116:10:116:16 | session | CookieWithoutHttpOnly.go:115:7:118:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:119:15:119:19 | false | CookieWithoutHttpOnly.go:115:7:118:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:120:20:120:21 | &... [pointer] | CookieWithoutHttpOnly.go:120:20:120:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:120:20:120:21 | &... [pointer] | CookieWithoutHttpOnly.go:120:20:120:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:120:21:120:21 | c | CookieWithoutHttpOnly.go:120:20:120:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:120:21:120:21 | c | CookieWithoutHttpOnly.go:120:20:120:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:120:21:120:21 | c | CookieWithoutHttpOnly.go:120:20:120:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:120:21:120:21 | c | CookieWithoutHttpOnly.go:120:20:120:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:123:13:123:49 | call to NewCookieStore | CookieWithoutHttpOnly.go:126:16:126:20 | store | provenance | |
| CookieWithoutHttpOnly.go:123:13:123:49 | call to NewCookieStore | CookieWithoutHttpOnly.go:134:16:134:20 | store | provenance | |
| CookieWithoutHttpOnly.go:123:13:123:49 | call to NewCookieStore | CookieWithoutHttpOnly.go:146:16:146:20 | store | provenance | |
| CookieWithoutHttpOnly.go:123:13:123:49 | call to NewCookieStore | CookieWithoutHttpOnly.go:158:16:158:20 | store | provenance | |
| CookieWithoutHttpOnly.go:123:13:123:49 | call to NewCookieStore | CookieWithoutHttpOnly.go:170:16:170:20 | store | provenance | |
| CookieWithoutHttpOnly.go:123:13:123:49 | call to NewCookieStore | CookieWithoutHttpOnly.go:183:16:183:20 | store | provenance | |
| CookieWithoutHttpOnly.go:123:13:123:49 | call to NewCookieStore | CookieWithoutHttpOnly.go:195:16:195:20 | store | provenance | |
| CookieWithoutHttpOnly.go:126:2:126:43 | ... := ...[0] | CookieWithoutHttpOnly.go:129:2:129:8 | session | provenance | |
| CookieWithoutHttpOnly.go:126:16:126:20 | store | CookieWithoutHttpOnly.go:126:2:126:43 | ... := ...[0] | provenance | Config |
| CookieWithoutHttpOnly.go:133:2:133:9 | definition of httpOnly | CookieWithoutHttpOnly.go:139:13:139:20 | httpOnly | provenance | |
| CookieWithoutHttpOnly.go:133:14:133:18 | false | CookieWithoutHttpOnly.go:139:13:139:20 | httpOnly | provenance | |
| CookieWithoutHttpOnly.go:134:2:134:43 | ... := ...[0] | CookieWithoutHttpOnly.go:142:2:142:8 | session | provenance | |
| CookieWithoutHttpOnly.go:134:16:134:20 | store | CookieWithoutHttpOnly.go:134:2:134:43 | ... := ...[0] | provenance | Config |
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference [postupdate] | CookieWithoutHttpOnly.go:137:2:137:8 | session [postupdate] | provenance | |
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference [postupdate] | CookieWithoutHttpOnly.go:137:2:137:8 | session [postupdate] | provenance | |
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference [postupdate] | CookieWithoutHttpOnly.go:137:2:137:8 | session [postupdate] [pointer] | provenance | |
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference [postupdate] | CookieWithoutHttpOnly.go:137:2:137:8 | session [postupdate] [pointer] | provenance | |
| CookieWithoutHttpOnly.go:137:2:137:8 | session [postupdate] | CookieWithoutHttpOnly.go:142:2:142:8 | session | provenance | |
| CookieWithoutHttpOnly.go:137:2:137:8 | session [postupdate] | CookieWithoutHttpOnly.go:142:2:142:8 | session | provenance | |
| CookieWithoutHttpOnly.go:137:2:137:8 | session [postupdate] [pointer] | CookieWithoutHttpOnly.go:142:2:142:8 | session | provenance | |
| CookieWithoutHttpOnly.go:137:2:137:8 | session [postupdate] [pointer] | CookieWithoutHttpOnly.go:142:2:142:8 | session | provenance | |
| CookieWithoutHttpOnly.go:137:20:140:2 | &... | CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference [postupdate] | provenance | Config |
| CookieWithoutHttpOnly.go:137:20:140:2 | &... | CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference [postupdate] | provenance | Config |
| CookieWithoutHttpOnly.go:137:20:140:2 | &... | CookieWithoutHttpOnly.go:137:2:137:8 | session [postupdate] | provenance | Config |
| CookieWithoutHttpOnly.go:137:20:140:2 | &... | CookieWithoutHttpOnly.go:137:2:137:8 | session [postupdate] | provenance | Config |
| CookieWithoutHttpOnly.go:137:21:140:2 | struct literal | CookieWithoutHttpOnly.go:137:20:140:2 | &... | provenance | |
| CookieWithoutHttpOnly.go:137:21:140:2 | struct literal | CookieWithoutHttpOnly.go:137:20:140:2 | &... | provenance | |
| CookieWithoutHttpOnly.go:139:13:139:20 | httpOnly | CookieWithoutHttpOnly.go:137:21:140:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:146:2:146:43 | ... := ...[0] | CookieWithoutHttpOnly.go:153:2:153:8 | session | provenance | |
| CookieWithoutHttpOnly.go:146:16:146:20 | store | CookieWithoutHttpOnly.go:146:2:146:43 | ... := ...[0] | provenance | Config |
| CookieWithoutHttpOnly.go:149:2:149:8 | implicit dereference [postupdate] | CookieWithoutHttpOnly.go:149:2:149:8 | session [postupdate] | provenance | |
| CookieWithoutHttpOnly.go:149:2:149:8 | implicit dereference [postupdate] | CookieWithoutHttpOnly.go:149:2:149:8 | session [postupdate] [pointer] | provenance | |
| CookieWithoutHttpOnly.go:149:2:149:8 | session [postupdate] | CookieWithoutHttpOnly.go:153:2:153:8 | session | provenance | |
| CookieWithoutHttpOnly.go:149:2:149:8 | session [postupdate] [pointer] | CookieWithoutHttpOnly.go:153:2:153:8 | session | provenance | |
| CookieWithoutHttpOnly.go:149:20:151:2 | &... | CookieWithoutHttpOnly.go:149:2:149:8 | implicit dereference [postupdate] | provenance | Config |
| CookieWithoutHttpOnly.go:149:20:151:2 | &... | CookieWithoutHttpOnly.go:149:2:149:8 | session [postupdate] | provenance | Config |
| CookieWithoutHttpOnly.go:149:21:151:2 | struct literal | CookieWithoutHttpOnly.go:149:20:151:2 | &... | provenance | |
| CookieWithoutHttpOnly.go:157:2:157:9 | definition of httpOnly | CookieWithoutHttpOnly.go:163:13:163:20 | httpOnly | provenance | |
| CookieWithoutHttpOnly.go:157:14:157:17 | true | CookieWithoutHttpOnly.go:163:13:163:20 | httpOnly | provenance | |
| CookieWithoutHttpOnly.go:158:2:158:43 | ... := ...[0] | CookieWithoutHttpOnly.go:166:2:166:8 | session | provenance | |
| CookieWithoutHttpOnly.go:158:16:158:20 | store | CookieWithoutHttpOnly.go:158:2:158:43 | ... := ...[0] | provenance | Config |
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference [postupdate] | CookieWithoutHttpOnly.go:161:2:161:8 | session [postupdate] | provenance | |
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference [postupdate] | CookieWithoutHttpOnly.go:161:2:161:8 | session [postupdate] | provenance | |
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference [postupdate] | CookieWithoutHttpOnly.go:161:2:161:8 | session [postupdate] [pointer] | provenance | |
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference [postupdate] | CookieWithoutHttpOnly.go:161:2:161:8 | session [postupdate] [pointer] | provenance | |
| CookieWithoutHttpOnly.go:161:2:161:8 | session [postupdate] | CookieWithoutHttpOnly.go:166:2:166:8 | session | provenance | |
| CookieWithoutHttpOnly.go:161:2:161:8 | session [postupdate] | CookieWithoutHttpOnly.go:166:2:166:8 | session | provenance | |
| CookieWithoutHttpOnly.go:161:2:161:8 | session [postupdate] [pointer] | CookieWithoutHttpOnly.go:166:2:166:8 | session | provenance | |
| CookieWithoutHttpOnly.go:161:2:161:8 | session [postupdate] [pointer] | CookieWithoutHttpOnly.go:166:2:166:8 | session | provenance | |
| CookieWithoutHttpOnly.go:161:20:164:2 | &... | CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference [postupdate] | provenance | Config |
| CookieWithoutHttpOnly.go:161:20:164:2 | &... | CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference [postupdate] | provenance | Config |
| CookieWithoutHttpOnly.go:161:20:164:2 | &... | CookieWithoutHttpOnly.go:161:2:161:8 | session [postupdate] | provenance | Config |
| CookieWithoutHttpOnly.go:161:20:164:2 | &... | CookieWithoutHttpOnly.go:161:2:161:8 | session [postupdate] | provenance | Config |
| CookieWithoutHttpOnly.go:161:21:164:2 | struct literal | CookieWithoutHttpOnly.go:161:20:164:2 | &... | provenance | |
| CookieWithoutHttpOnly.go:161:21:164:2 | struct literal | CookieWithoutHttpOnly.go:161:20:164:2 | &... | provenance | |
| CookieWithoutHttpOnly.go:163:13:163:20 | httpOnly | CookieWithoutHttpOnly.go:161:21:164:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:169:56:169:63 | argument corresponding to httpOnly | CookieWithoutHttpOnly.go:175:13:175:20 | httpOnly | provenance | |
| CookieWithoutHttpOnly.go:169:56:169:63 | definition of httpOnly | CookieWithoutHttpOnly.go:175:13:175:20 | httpOnly | provenance | |
| CookieWithoutHttpOnly.go:170:2:170:43 | ... := ...[0] | CookieWithoutHttpOnly.go:178:2:178:8 | session | provenance | |
| CookieWithoutHttpOnly.go:170:16:170:20 | store | CookieWithoutHttpOnly.go:170:2:170:43 | ... := ...[0] | provenance | Config |
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference [postupdate] | CookieWithoutHttpOnly.go:173:2:173:8 | session [postupdate] | provenance | |
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference [postupdate] | CookieWithoutHttpOnly.go:173:2:173:8 | session [postupdate] | provenance | |
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference [postupdate] | CookieWithoutHttpOnly.go:173:2:173:8 | session [postupdate] [pointer] | provenance | |
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference [postupdate] | CookieWithoutHttpOnly.go:173:2:173:8 | session [postupdate] [pointer] | provenance | |
| CookieWithoutHttpOnly.go:173:2:173:8 | session [postupdate] | CookieWithoutHttpOnly.go:178:2:178:8 | session | provenance | |
| CookieWithoutHttpOnly.go:173:2:173:8 | session [postupdate] | CookieWithoutHttpOnly.go:178:2:178:8 | session | provenance | |
| CookieWithoutHttpOnly.go:173:2:173:8 | session [postupdate] [pointer] | CookieWithoutHttpOnly.go:178:2:178:8 | session | provenance | |
| CookieWithoutHttpOnly.go:173:2:173:8 | session [postupdate] [pointer] | CookieWithoutHttpOnly.go:178:2:178:8 | session | provenance | |
| CookieWithoutHttpOnly.go:173:20:176:2 | &... | CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference [postupdate] | provenance | Config |
| CookieWithoutHttpOnly.go:173:20:176:2 | &... | CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference [postupdate] | provenance | Config |
| CookieWithoutHttpOnly.go:173:20:176:2 | &... | CookieWithoutHttpOnly.go:173:2:173:8 | session [postupdate] | provenance | Config |
| CookieWithoutHttpOnly.go:173:20:176:2 | &... | CookieWithoutHttpOnly.go:173:2:173:8 | session [postupdate] | provenance | Config |
| CookieWithoutHttpOnly.go:173:21:176:2 | struct literal | CookieWithoutHttpOnly.go:173:20:176:2 | &... | provenance | |
| CookieWithoutHttpOnly.go:173:21:176:2 | struct literal | CookieWithoutHttpOnly.go:173:20:176:2 | &... | provenance | |
| CookieWithoutHttpOnly.go:175:13:175:20 | httpOnly | CookieWithoutHttpOnly.go:173:21:176:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:183:2:183:43 | ... := ...[0] | CookieWithoutHttpOnly.go:191:19:191:25 | session | provenance | |
| CookieWithoutHttpOnly.go:183:16:183:20 | store | CookieWithoutHttpOnly.go:183:2:183:43 | ... := ...[0] | provenance | Config |
| CookieWithoutHttpOnly.go:195:2:195:43 | ... := ...[0] | CookieWithoutHttpOnly.go:202:19:202:25 | session | provenance | |
| CookieWithoutHttpOnly.go:195:16:195:20 | store | CookieWithoutHttpOnly.go:195:2:195:43 | ... := ...[0] | provenance | Config |
nodes
| CookieWithoutHttpOnly.go:11:7:14:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:12:10:12:18 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:15:20:15:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:15:20:15:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:15:21:15:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:20:13:20:21 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:22:13:22:17 | false | semmle.label | false |
| CookieWithoutHttpOnly.go:24:20:24:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:24:20:24:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:24:20:24:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:24:20:24:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:24:21:24:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:24:21:24:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:29:13:29:21 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:31:13:31:16 | true | semmle.label | true |
| CookieWithoutHttpOnly.go:33:20:33:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:33:20:33:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:33:20:33:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:33:20:33:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:33:21:33:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:33:21:33:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:38:10:38:18 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:41:15:41:18 | true | semmle.label | true |
| CookieWithoutHttpOnly.go:42:20:42:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:42:20:42:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:42:20:42:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:42:20:42:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:42:21:42:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:42:21:42:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:47:10:47:18 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:50:15:50:19 | false | semmle.label | false |
| CookieWithoutHttpOnly.go:51:20:51:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:51:20:51:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:51:20:51:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:51:20:51:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:51:21:51:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:51:21:51:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:55:2:55:4 | definition of val | semmle.label | definition of val |
| CookieWithoutHttpOnly.go:55:9:55:13 | false | semmle.label | false |
| CookieWithoutHttpOnly.go:56:7:60:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:56:7:60:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:57:13:57:21 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:59:13:59:15 | val | semmle.label | val |
| CookieWithoutHttpOnly.go:61:20:61:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:61:20:61:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:61:20:61:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:61:20:61:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:61:21:61:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:61:21:61:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:65:2:65:4 | definition of val | semmle.label | definition of val |
| CookieWithoutHttpOnly.go:65:9:65:12 | true | semmle.label | true |
| CookieWithoutHttpOnly.go:66:7:70:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:66:7:70:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:67:13:67:21 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:69:13:69:15 | val | semmle.label | val |
| CookieWithoutHttpOnly.go:71:20:71:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:71:20:71:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:71:20:71:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:71:20:71:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:71:21:71:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:71:21:71:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:75:2:75:4 | definition of val | semmle.label | definition of val |
| CookieWithoutHttpOnly.go:75:9:75:12 | true | semmle.label | true |
| CookieWithoutHttpOnly.go:76:7:79:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:76:7:79:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:77:10:77:18 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:80:15:80:17 | val | semmle.label | val |
| CookieWithoutHttpOnly.go:81:20:81:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:81:20:81:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:81:20:81:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:81:20:81:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:81:21:81:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:81:21:81:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:85:2:85:4 | definition of val | semmle.label | definition of val |
| CookieWithoutHttpOnly.go:85:9:85:13 | false | semmle.label | false |
| CookieWithoutHttpOnly.go:86:7:89:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:86:7:89:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:87:10:87:18 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:90:15:90:17 | val | semmle.label | val |
| CookieWithoutHttpOnly.go:91:20:91:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:91:20:91:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:91:20:91:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:91:20:91:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:91:21:91:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:91:21:91:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:95:7:98:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:99:15:99:19 | false | semmle.label | false |
| CookieWithoutHttpOnly.go:100:20:100:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:100:20:100:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:100:21:100:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:104:10:104:18 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:106:10:106:13 | name | semmle.label | name |
| CookieWithoutHttpOnly.go:109:15:109:19 | false | semmle.label | false |
| CookieWithoutHttpOnly.go:110:20:110:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:110:20:110:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:110:20:110:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:110:20:110:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:110:21:110:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:110:21:110:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:114:13:114:24 | "login_name" | semmle.label | "login_name" |
| CookieWithoutHttpOnly.go:115:7:118:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:115:7:118:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:116:10:116:16 | session | semmle.label | session |
| CookieWithoutHttpOnly.go:119:15:119:19 | false | semmle.label | false |
| CookieWithoutHttpOnly.go:120:20:120:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:120:20:120:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:120:20:120:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:120:20:120:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:120:21:120:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:120:21:120:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:123:13:123:49 | call to NewCookieStore | semmle.label | call to NewCookieStore |
| CookieWithoutHttpOnly.go:126:2:126:43 | ... := ...[0] | semmle.label | ... := ...[0] |
| CookieWithoutHttpOnly.go:126:16:126:20 | store | semmle.label | store |
| CookieWithoutHttpOnly.go:129:2:129:8 | session | semmle.label | session |
| CookieWithoutHttpOnly.go:133:2:133:9 | definition of httpOnly | semmle.label | definition of httpOnly |
| CookieWithoutHttpOnly.go:133:14:133:18 | false | semmle.label | false |
| CookieWithoutHttpOnly.go:134:2:134:43 | ... := ...[0] | semmle.label | ... := ...[0] |
| CookieWithoutHttpOnly.go:134:16:134:20 | store | semmle.label | store |
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference [postupdate] | semmle.label | implicit dereference [postupdate] |
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference [postupdate] | semmle.label | implicit dereference [postupdate] |
| CookieWithoutHttpOnly.go:137:2:137:8 | session [postupdate] | semmle.label | session [postupdate] |
| CookieWithoutHttpOnly.go:137:2:137:8 | session [postupdate] | semmle.label | session [postupdate] |
| CookieWithoutHttpOnly.go:137:2:137:8 | session [postupdate] [pointer] | semmle.label | session [postupdate] [pointer] |
| CookieWithoutHttpOnly.go:137:2:137:8 | session [postupdate] [pointer] | semmle.label | session [postupdate] [pointer] |
| CookieWithoutHttpOnly.go:137:20:140:2 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:137:20:140:2 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:137:21:140:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:137:21:140:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:139:13:139:20 | httpOnly | semmle.label | httpOnly |
| CookieWithoutHttpOnly.go:142:2:142:8 | session | semmle.label | session |
| CookieWithoutHttpOnly.go:142:2:142:8 | session | semmle.label | session |
| CookieWithoutHttpOnly.go:142:2:142:8 | session | semmle.label | session |
| CookieWithoutHttpOnly.go:146:2:146:43 | ... := ...[0] | semmle.label | ... := ...[0] |
| CookieWithoutHttpOnly.go:146:16:146:20 | store | semmle.label | store |
| CookieWithoutHttpOnly.go:149:2:149:8 | implicit dereference [postupdate] | semmle.label | implicit dereference [postupdate] |
| CookieWithoutHttpOnly.go:149:2:149:8 | session [postupdate] | semmle.label | session [postupdate] |
| CookieWithoutHttpOnly.go:149:2:149:8 | session [postupdate] [pointer] | semmle.label | session [postupdate] [pointer] |
| CookieWithoutHttpOnly.go:149:20:151:2 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:149:21:151:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:153:2:153:8 | session | semmle.label | session |
| CookieWithoutHttpOnly.go:153:2:153:8 | session | semmle.label | session |
| CookieWithoutHttpOnly.go:157:2:157:9 | definition of httpOnly | semmle.label | definition of httpOnly |
| CookieWithoutHttpOnly.go:157:14:157:17 | true | semmle.label | true |
| CookieWithoutHttpOnly.go:158:2:158:43 | ... := ...[0] | semmle.label | ... := ...[0] |
| CookieWithoutHttpOnly.go:158:16:158:20 | store | semmle.label | store |
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference [postupdate] | semmle.label | implicit dereference [postupdate] |
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference [postupdate] | semmle.label | implicit dereference [postupdate] |
| CookieWithoutHttpOnly.go:161:2:161:8 | session [postupdate] | semmle.label | session [postupdate] |
| CookieWithoutHttpOnly.go:161:2:161:8 | session [postupdate] | semmle.label | session [postupdate] |
| CookieWithoutHttpOnly.go:161:2:161:8 | session [postupdate] [pointer] | semmle.label | session [postupdate] [pointer] |
| CookieWithoutHttpOnly.go:161:2:161:8 | session [postupdate] [pointer] | semmle.label | session [postupdate] [pointer] |
| CookieWithoutHttpOnly.go:161:20:164:2 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:161:20:164:2 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:161:21:164:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:161:21:164:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:163:13:163:20 | httpOnly | semmle.label | httpOnly |
| CookieWithoutHttpOnly.go:166:2:166:8 | session | semmle.label | session |
| CookieWithoutHttpOnly.go:166:2:166:8 | session | semmle.label | session |
| CookieWithoutHttpOnly.go:166:2:166:8 | session | semmle.label | session |
| CookieWithoutHttpOnly.go:169:56:169:63 | argument corresponding to httpOnly | semmle.label | argument corresponding to httpOnly |
| CookieWithoutHttpOnly.go:169:56:169:63 | definition of httpOnly | semmle.label | definition of httpOnly |
| CookieWithoutHttpOnly.go:170:2:170:43 | ... := ...[0] | semmle.label | ... := ...[0] |
| CookieWithoutHttpOnly.go:170:16:170:20 | store | semmle.label | store |
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference [postupdate] | semmle.label | implicit dereference [postupdate] |
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference [postupdate] | semmle.label | implicit dereference [postupdate] |
| CookieWithoutHttpOnly.go:173:2:173:8 | session [postupdate] | semmle.label | session [postupdate] |
| CookieWithoutHttpOnly.go:173:2:173:8 | session [postupdate] | semmle.label | session [postupdate] |
| CookieWithoutHttpOnly.go:173:2:173:8 | session [postupdate] [pointer] | semmle.label | session [postupdate] [pointer] |
| CookieWithoutHttpOnly.go:173:2:173:8 | session [postupdate] [pointer] | semmle.label | session [postupdate] [pointer] |
| CookieWithoutHttpOnly.go:173:20:176:2 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:173:20:176:2 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:173:21:176:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:173:21:176:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:175:13:175:20 | httpOnly | semmle.label | httpOnly |
| CookieWithoutHttpOnly.go:178:2:178:8 | session | semmle.label | session |
| CookieWithoutHttpOnly.go:178:2:178:8 | session | semmle.label | session |
| CookieWithoutHttpOnly.go:178:2:178:8 | session | semmle.label | session |
| CookieWithoutHttpOnly.go:183:2:183:43 | ... := ...[0] | semmle.label | ... := ...[0] |
| CookieWithoutHttpOnly.go:183:16:183:20 | store | semmle.label | store |
| CookieWithoutHttpOnly.go:191:19:191:25 | session | semmle.label | session |
| CookieWithoutHttpOnly.go:195:2:195:43 | ... := ...[0] | semmle.label | ... := ...[0] |
| CookieWithoutHttpOnly.go:195:16:195:20 | store | semmle.label | store |
| CookieWithoutHttpOnly.go:202:19:202:25 | session | semmle.label | session |
| CookieWithoutHttpOnly.go:214:66:214:70 | false | semmle.label | false |
subpaths
#select
| CookieWithoutHttpOnly.go:15:20:15:21 | &... | CookieWithoutHttpOnly.go:12:10:12:18 | "session" | CookieWithoutHttpOnly.go:15:20:15:21 | &... | Cookie attribute 'HttpOnly' is not set to true. |
| CookieWithoutHttpOnly.go:24:20:24:21 | &... | CookieWithoutHttpOnly.go:22:13:22:17 | false | CookieWithoutHttpOnly.go:24:20:24:21 | &... | Cookie attribute 'HttpOnly' is not set to true. |
| CookieWithoutHttpOnly.go:51:20:51:21 | &... | CookieWithoutHttpOnly.go:50:15:50:19 | false | CookieWithoutHttpOnly.go:51:20:51:21 | &... | Cookie attribute 'HttpOnly' is not set to true. |
| CookieWithoutHttpOnly.go:61:20:61:21 | &... | CookieWithoutHttpOnly.go:55:9:55:13 | false | CookieWithoutHttpOnly.go:61:20:61:21 | &... | Cookie attribute 'HttpOnly' is not set to true. |
| CookieWithoutHttpOnly.go:91:20:91:21 | &... | CookieWithoutHttpOnly.go:85:9:85:13 | false | CookieWithoutHttpOnly.go:91:20:91:21 | &... | Cookie attribute 'HttpOnly' is not set to true. |
| CookieWithoutHttpOnly.go:110:20:110:21 | &... | CookieWithoutHttpOnly.go:109:15:109:19 | false | CookieWithoutHttpOnly.go:110:20:110:21 | &... | Cookie attribute 'HttpOnly' is not set to true. |
| CookieWithoutHttpOnly.go:120:20:120:21 | &... | CookieWithoutHttpOnly.go:119:15:119:19 | false | CookieWithoutHttpOnly.go:120:20:120:21 | &... | Cookie attribute 'HttpOnly' is not set to true. |
| CookieWithoutHttpOnly.go:129:2:129:8 | session | CookieWithoutHttpOnly.go:123:13:123:49 | call to NewCookieStore | CookieWithoutHttpOnly.go:129:2:129:8 | session | Cookie attribute 'HttpOnly' is not set to true. |
| CookieWithoutHttpOnly.go:142:2:142:8 | session | CookieWithoutHttpOnly.go:133:14:133:18 | false | CookieWithoutHttpOnly.go:142:2:142:8 | session | Cookie attribute 'HttpOnly' is not set to true. |
| CookieWithoutHttpOnly.go:153:2:153:8 | session | CookieWithoutHttpOnly.go:149:21:151:2 | struct literal | CookieWithoutHttpOnly.go:153:2:153:8 | session | Cookie attribute 'HttpOnly' is not set to true. |
| CookieWithoutHttpOnly.go:191:19:191:25 | session | CookieWithoutHttpOnly.go:123:13:123:49 | call to NewCookieStore | CookieWithoutHttpOnly.go:191:19:191:25 | session | Cookie attribute 'HttpOnly' is not set to true. |
| CookieWithoutHttpOnly.go:202:19:202:25 | session | CookieWithoutHttpOnly.go:123:13:123:49 | call to NewCookieStore | CookieWithoutHttpOnly.go:202:19:202:25 | session | Cookie attribute 'HttpOnly' is not set to true. |
| CookieWithoutHttpOnly.go:214:66:214:70 | false | CookieWithoutHttpOnly.go:214:66:214:70 | false | CookieWithoutHttpOnly.go:214:66:214:70 | false | Cookie attribute 'HttpOnly' is not set to true. |

View File

@@ -1,219 +0,0 @@
package main
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/gorilla/sessions"
)
func handler1(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session",
Value: "secret",
}
http.SetCookie(w, &c) // BAD: HttpOnly set to false by default
}
func handler2(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session",
Value: "secret",
HttpOnly: false,
}
http.SetCookie(w, &c) // BAD: HttpOnly explicitly set to false
}
func handler3(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session",
Value: "secret",
HttpOnly: true,
}
http.SetCookie(w, &c) // GOOD: HttpOnly explicitly set to true
}
func handler4(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session",
Value: "secret",
}
c.HttpOnly = true
http.SetCookie(w, &c) // GOOD: HttpOnly explicitly set to true
}
func handler5(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session",
Value: "secret",
}
c.HttpOnly = false
http.SetCookie(w, &c) // BAD: HttpOnly explicitly set to false
}
func handler6(w http.ResponseWriter, r *http.Request) {
val := false
c := http.Cookie{
Name: "session",
Value: "secret",
HttpOnly: val,
}
http.SetCookie(w, &c) // BAD: HttpOnly explicitly set to false
}
func handler7(w http.ResponseWriter, r *http.Request) {
val := true
c := http.Cookie{
Name: "session",
Value: "secret",
HttpOnly: val,
}
http.SetCookie(w, &c) // GOOD: HttpOnly explicitly set to true
}
func handler8(w http.ResponseWriter, r *http.Request) {
val := true
c := http.Cookie{
Name: "session",
Value: "secret",
}
c.HttpOnly = val
http.SetCookie(w, &c) // GOOD: HttpOnly explicitly set to true
}
func handler9(w http.ResponseWriter, r *http.Request) {
val := false
c := http.Cookie{
Name: "session",
Value: "secret",
}
c.HttpOnly = val
http.SetCookie(w, &c) // BAD: HttpOnly explicitly set to false
}
func handler10(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "consent",
Value: "1",
}
c.HttpOnly = false
http.SetCookie(w, &c) // GOOD: Name is not auth related
}
func handler11(w http.ResponseWriter, r *http.Request) {
name := "session"
c := http.Cookie{
Name: name,
Value: "secret",
}
c.HttpOnly = false
http.SetCookie(w, &c) // BAD: auth related name
}
func handler12(w http.ResponseWriter, r *http.Request) {
session := "login_name"
c := http.Cookie{
Name: session,
Value: "secret",
}
c.HttpOnly = false
http.SetCookie(w, &c) // BAD: auth related name
}
var store = sessions.NewCookieStore([]byte("aa"))
func handler13(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "session-name")
session.Values["foo"] = "secret"
session.Save(r, w) // BAD: Default options are set (false)
}
func handler14(w http.ResponseWriter, r *http.Request) {
httpOnly := false
session, _ := store.Get(r, "session-name")
session.Values["foo"] = "secret"
session.Options = &sessions.Options{
MaxAge: -1,
HttpOnly: httpOnly,
}
session.Save(r, w) // BAD: Explicitly set to false
}
func handler15(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "session-name")
session.Values["foo"] = "secret"
session.Options = &sessions.Options{
MaxAge: -1,
}
session.Save(r, w) // BAD: default (false) is used
}
func handler16(w http.ResponseWriter, r *http.Request) {
httpOnly := true
session, _ := store.Get(r, "session-name")
session.Values["foo"] = "secret"
session.Options = &sessions.Options{
MaxAge: -1,
HttpOnly: httpOnly,
}
session.Save(r, w) // GOOD: value is true
}
func handler17(w http.ResponseWriter, r *http.Request, httpOnly bool) {
session, _ := store.Get(r, "session-name")
session.Values["foo"] = "secret"
session.Options = &sessions.Options{
MaxAge: -1,
HttpOnly: httpOnly,
}
session.Save(r, w) // GOOD: value is unknown
}
func handler18(w http.ResponseWriter, r *http.Request) {
httpOnly := false
session, _ := store.Get(r, "session-name")
session.Values["foo"] = "secret"
session.Options = &sessions.Options{
MaxAge: -1,
HttpOnly: httpOnly,
}
store.Save(r, w, session) // BAD: Explicitly set to false
}
func handler19(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "session-name")
session.Values["foo"] = "secret"
session.Options = &sessions.Options{
MaxAge: -1,
}
store.Save(r, w, session) // BAD: default (false) is used
}
func main() {
router := gin.Default()
router.GET("/cookie", func(c *gin.Context) {
_, err := c.Cookie("session")
if err != nil {
c.SetCookie("session", "test", 3600, "/", "localhost", false, false) // BAD: httpOnly set to false
}
})
router.Run()
}

View File

@@ -1 +0,0 @@
experimental/CWE-1004/CookieWithoutHttpOnly.ql

View File

@@ -1,75 +0,0 @@
// Code generated by depstubber. DO NOT EDIT.
// This is a simple stub for github.com/gorilla/sessions, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: github.com/gorilla/sessions (exports: CookieStore; functions: NewCookieStore)
// Package sessions is a stub of github.com/gorilla/sessions, generated by depstubber.
package sessions
import (
http "net/http"
)
type CookieStore struct {
Codecs []interface{}
Options *Options
}
func (_ *CookieStore) Get(_ *http.Request, _ string) (*Session, error) {
return nil, nil
}
func (_ *CookieStore) MaxAge(_ int) {}
func (_ *CookieStore) New(_ *http.Request, _ string) (*Session, error) {
return nil, nil
}
func (_ *CookieStore) Save(_ *http.Request, _ http.ResponseWriter, _ *Session) error {
return nil
}
func NewCookieStore(_ ...[]byte) *CookieStore {
return nil
}
type Options struct {
Path string
Domain string
MaxAge int
Secure bool
HttpOnly bool
SameSite http.SameSite
}
type Session struct {
ID string
Values map[interface{}]interface{}
Options *Options
IsNew bool
}
func (_ *Session) AddFlash(_ interface{}, _ ...string) {}
func (_ *Session) Flashes(_ ...string) []interface{} {
return nil
}
func (_ *Session) Name() string {
return ""
}
func (_ *Session) Save(_ *http.Request, _ http.ResponseWriter) error {
return nil
}
func (_ *Session) Store() Store {
return nil
}
type Store interface {
Get(_ *http.Request, _ string) (*Session, error)
New(_ *http.Request, _ string) (*Session, error)
Save(_ *http.Request, _ http.ResponseWriter, _ *Session) error
}

View File

@@ -1,6 +0,0 @@
# github.com/gin-gonic/gin v1.7.1
## explicit
github.com/gin-gonic/gin
# github.com/gorilla/sessions v1.2.1
## explicit
github.com/gorilla/sessions

View File

@@ -0,0 +1,139 @@
#select
| CookieWithoutHttpOnly.go:14:2:14:22 | call to SetCookie | CookieWithoutHttpOnly.go:11:10:11:18 | "session" | CookieWithoutHttpOnly.go:14:20:14:21 | &... | Sensitive cookie $@ does not set HttpOnly attribute to true. | CookieWithoutHttpOnly.go:11:10:11:18 | "session" | session |
| CookieWithoutHttpOnly.go:23:2:23:22 | call to SetCookie | CookieWithoutHttpOnly.go:19:13:19:21 | "session" | CookieWithoutHttpOnly.go:23:20:23:21 | &... | Sensitive cookie $@ does not set HttpOnly attribute to true. | CookieWithoutHttpOnly.go:19:13:19:21 | "session" | session |
| CookieWithoutHttpOnly.go:50:2:50:22 | call to SetCookie | CookieWithoutHttpOnly.go:46:10:46:18 | "session" | CookieWithoutHttpOnly.go:50:20:50:21 | &... | Sensitive cookie $@ does not set HttpOnly attribute to true. | CookieWithoutHttpOnly.go:46:10:46:18 | "session" | session |
| CookieWithoutHttpOnly.go:60:2:60:22 | call to SetCookie | CookieWithoutHttpOnly.go:56:13:56:21 | "session" | CookieWithoutHttpOnly.go:60:20:60:21 | &... | Sensitive cookie $@ does not set HttpOnly attribute to true. | CookieWithoutHttpOnly.go:56:13:56:21 | "session" | session |
| CookieWithoutHttpOnly.go:90:2:90:22 | call to SetCookie | CookieWithoutHttpOnly.go:86:10:86:18 | "session" | CookieWithoutHttpOnly.go:90:20:90:21 | &... | Sensitive cookie $@ does not set HttpOnly attribute to true. | CookieWithoutHttpOnly.go:86:10:86:18 | "session" | session |
| CookieWithoutHttpOnly.go:109:2:109:22 | call to SetCookie | CookieWithoutHttpOnly.go:103:10:103:18 | "session" | CookieWithoutHttpOnly.go:109:20:109:21 | &... | Sensitive cookie $@ does not set HttpOnly attribute to true. | CookieWithoutHttpOnly.go:103:10:103:18 | "session" | session |
| CookieWithoutHttpOnly.go:119:2:119:22 | call to SetCookie | CookieWithoutHttpOnly.go:113:13:113:24 | "login_name" | CookieWithoutHttpOnly.go:119:20:119:21 | &... | Sensitive cookie $@ does not set HttpOnly attribute to true. | CookieWithoutHttpOnly.go:113:13:113:24 | "login_name" | login_name |
| CookieWithoutHttpOnly.go:119:2:119:22 | call to SetCookie | CookieWithoutHttpOnly.go:115:10:115:16 | session | CookieWithoutHttpOnly.go:119:20:119:21 | &... | Sensitive cookie $@ does not set HttpOnly attribute to true. | CookieWithoutHttpOnly.go:115:10:115:16 | session | session |
| CookieWithoutHttpOnly.go:131:4:131:71 | call to SetCookie | CookieWithoutHttpOnly.go:131:16:131:24 | "session" | CookieWithoutHttpOnly.go:131:16:131:24 | "session" | Sensitive cookie $@ does not set HttpOnly attribute to true. | CookieWithoutHttpOnly.go:131:16:131:24 | "session" | session |
edges
| CookieWithoutHttpOnly.go:10:7:13:2 | struct literal | CookieWithoutHttpOnly.go:14:20:14:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:10:7:13:2 | struct literal | CookieWithoutHttpOnly.go:14:21:14:21 | c | provenance | |
| CookieWithoutHttpOnly.go:11:10:11:18 | "session" | CookieWithoutHttpOnly.go:10:7:13:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:14:20:14:21 | &... [pointer] | CookieWithoutHttpOnly.go:14:20:14:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:14:21:14:21 | c | CookieWithoutHttpOnly.go:14:20:14:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:14:21:14:21 | c | CookieWithoutHttpOnly.go:14:20:14:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:18:7:22:2 | struct literal | CookieWithoutHttpOnly.go:23:20:23:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:18:7:22:2 | struct literal | CookieWithoutHttpOnly.go:23:21:23:21 | c | provenance | |
| CookieWithoutHttpOnly.go:19:13:19:21 | "session" | CookieWithoutHttpOnly.go:18:7:22:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:23:20:23:21 | &... [pointer] | CookieWithoutHttpOnly.go:23:20:23:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:23:21:23:21 | c | CookieWithoutHttpOnly.go:23:20:23:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:23:21:23:21 | c | CookieWithoutHttpOnly.go:23:20:23:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:27:7:31:2 | struct literal | CookieWithoutHttpOnly.go:32:20:32:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:27:7:31:2 | struct literal | CookieWithoutHttpOnly.go:32:21:32:21 | c | provenance | |
| CookieWithoutHttpOnly.go:28:13:28:21 | "session" | CookieWithoutHttpOnly.go:27:7:31:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:32:20:32:21 | &... [pointer] | CookieWithoutHttpOnly.go:32:20:32:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:32:21:32:21 | c | CookieWithoutHttpOnly.go:32:20:32:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:32:21:32:21 | c | CookieWithoutHttpOnly.go:32:20:32:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:36:7:39:2 | struct literal | CookieWithoutHttpOnly.go:41:20:41:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:36:7:39:2 | struct literal | CookieWithoutHttpOnly.go:41:21:41:21 | c | provenance | |
| CookieWithoutHttpOnly.go:37:10:37:18 | "session" | CookieWithoutHttpOnly.go:36:7:39:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:41:20:41:21 | &... [pointer] | CookieWithoutHttpOnly.go:41:20:41:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:41:21:41:21 | c | CookieWithoutHttpOnly.go:41:20:41:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:41:21:41:21 | c | CookieWithoutHttpOnly.go:41:20:41:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:45:7:48:2 | struct literal | CookieWithoutHttpOnly.go:50:20:50:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:45:7:48:2 | struct literal | CookieWithoutHttpOnly.go:50:21:50:21 | c | provenance | |
| CookieWithoutHttpOnly.go:46:10:46:18 | "session" | CookieWithoutHttpOnly.go:45:7:48:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:50:20:50:21 | &... [pointer] | CookieWithoutHttpOnly.go:50:20:50:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:50:21:50:21 | c | CookieWithoutHttpOnly.go:50:20:50:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:50:21:50:21 | c | CookieWithoutHttpOnly.go:50:20:50:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:55:7:59:2 | struct literal | CookieWithoutHttpOnly.go:60:20:60:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:55:7:59:2 | struct literal | CookieWithoutHttpOnly.go:60:21:60:21 | c | provenance | |
| CookieWithoutHttpOnly.go:56:13:56:21 | "session" | CookieWithoutHttpOnly.go:55:7:59:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:60:20:60:21 | &... [pointer] | CookieWithoutHttpOnly.go:60:20:60:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:60:21:60:21 | c | CookieWithoutHttpOnly.go:60:20:60:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:60:21:60:21 | c | CookieWithoutHttpOnly.go:60:20:60:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:65:7:69:2 | struct literal | CookieWithoutHttpOnly.go:70:20:70:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:65:7:69:2 | struct literal | CookieWithoutHttpOnly.go:70:21:70:21 | c | provenance | |
| CookieWithoutHttpOnly.go:66:13:66:21 | "session" | CookieWithoutHttpOnly.go:65:7:69:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:70:20:70:21 | &... [pointer] | CookieWithoutHttpOnly.go:70:20:70:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:70:21:70:21 | c | CookieWithoutHttpOnly.go:70:20:70:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:70:21:70:21 | c | CookieWithoutHttpOnly.go:70:20:70:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:75:7:78:2 | struct literal | CookieWithoutHttpOnly.go:80:20:80:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:75:7:78:2 | struct literal | CookieWithoutHttpOnly.go:80:21:80:21 | c | provenance | |
| CookieWithoutHttpOnly.go:76:10:76:18 | "session" | CookieWithoutHttpOnly.go:75:7:78:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:80:20:80:21 | &... [pointer] | CookieWithoutHttpOnly.go:80:20:80:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:80:21:80:21 | c | CookieWithoutHttpOnly.go:80:20:80:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:80:21:80:21 | c | CookieWithoutHttpOnly.go:80:20:80:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:85:7:88:2 | struct literal | CookieWithoutHttpOnly.go:90:20:90:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:85:7:88:2 | struct literal | CookieWithoutHttpOnly.go:90:21:90:21 | c | provenance | |
| CookieWithoutHttpOnly.go:86:10:86:18 | "session" | CookieWithoutHttpOnly.go:85:7:88:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:90:20:90:21 | &... [pointer] | CookieWithoutHttpOnly.go:90:20:90:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:90:21:90:21 | c | CookieWithoutHttpOnly.go:90:20:90:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:90:21:90:21 | c | CookieWithoutHttpOnly.go:90:20:90:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:103:10:103:18 | "session" | CookieWithoutHttpOnly.go:105:10:105:13 | name | provenance | |
| CookieWithoutHttpOnly.go:104:7:107:2 | struct literal | CookieWithoutHttpOnly.go:109:20:109:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:104:7:107:2 | struct literal | CookieWithoutHttpOnly.go:109:21:109:21 | c | provenance | |
| CookieWithoutHttpOnly.go:105:10:105:13 | name | CookieWithoutHttpOnly.go:104:7:107:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:109:20:109:21 | &... [pointer] | CookieWithoutHttpOnly.go:109:20:109:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:109:21:109:21 | c | CookieWithoutHttpOnly.go:109:20:109:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:109:21:109:21 | c | CookieWithoutHttpOnly.go:109:20:109:21 | &... [pointer] | provenance | |
| CookieWithoutHttpOnly.go:113:13:113:24 | "login_name" | CookieWithoutHttpOnly.go:115:10:115:16 | session | provenance | |
| CookieWithoutHttpOnly.go:114:7:117:2 | struct literal | CookieWithoutHttpOnly.go:119:20:119:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:114:7:117:2 | struct literal | CookieWithoutHttpOnly.go:119:21:119:21 | c | provenance | |
| CookieWithoutHttpOnly.go:115:10:115:16 | session | CookieWithoutHttpOnly.go:114:7:117:2 | struct literal | provenance | Config |
| CookieWithoutHttpOnly.go:119:20:119:21 | &... [pointer] | CookieWithoutHttpOnly.go:119:20:119:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:119:21:119:21 | c | CookieWithoutHttpOnly.go:119:20:119:21 | &... | provenance | |
| CookieWithoutHttpOnly.go:119:21:119:21 | c | CookieWithoutHttpOnly.go:119:20:119:21 | &... [pointer] | provenance | |
nodes
| CookieWithoutHttpOnly.go:10:7:13:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:11:10:11:18 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:14:20:14:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:14:20:14:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:14:21:14:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:18:7:22:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:19:13:19:21 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:23:20:23:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:23:20:23:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:23:21:23:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:27:7:31:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:28:13:28:21 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:32:20:32:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:32:20:32:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:32:21:32:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:36:7:39:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:37:10:37:18 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:41:20:41:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:41:20:41:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:41:21:41:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:45:7:48:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:46:10:46:18 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:50:20:50:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:50:20:50:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:50:21:50:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:55:7:59:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:56:13:56:21 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:60:20:60:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:60:20:60:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:60:21:60:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:65:7:69:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:66:13:66:21 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:70:20:70:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:70:20:70:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:70:21:70:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:75:7:78:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:76:10:76:18 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:80:20:80:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:80:20:80:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:80:21:80:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:85:7:88:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:86:10:86:18 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:90:20:90:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:90:20:90:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:90:21:90:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:103:10:103:18 | "session" | semmle.label | "session" |
| CookieWithoutHttpOnly.go:104:7:107:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:105:10:105:13 | name | semmle.label | name |
| CookieWithoutHttpOnly.go:109:20:109:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:109:20:109:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:109:21:109:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:113:13:113:24 | "login_name" | semmle.label | "login_name" |
| CookieWithoutHttpOnly.go:114:7:117:2 | struct literal | semmle.label | struct literal |
| CookieWithoutHttpOnly.go:115:10:115:16 | session | semmle.label | session |
| CookieWithoutHttpOnly.go:119:20:119:21 | &... | semmle.label | &... |
| CookieWithoutHttpOnly.go:119:20:119:21 | &... [pointer] | semmle.label | &... [pointer] |
| CookieWithoutHttpOnly.go:119:21:119:21 | c | semmle.label | c |
| CookieWithoutHttpOnly.go:131:16:131:24 | "session" | semmle.label | "session" |
subpaths

View File

@@ -0,0 +1,136 @@
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func handler1(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session", // $ Source
Value: "secret",
}
http.SetCookie(w, &c) // $ Alert // BAD: HttpOnly set to false by default
}
func handler2(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session", // $ Source
Value: "secret",
HttpOnly: false,
}
http.SetCookie(w, &c) // $ Alert // BAD: HttpOnly explicitly set to false
}
func handler3(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session",
Value: "secret",
HttpOnly: true,
}
http.SetCookie(w, &c) // GOOD: HttpOnly explicitly set to true
}
func handler4(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session",
Value: "secret",
}
c.HttpOnly = true
http.SetCookie(w, &c) // GOOD: HttpOnly explicitly set to true
}
func handler5(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session", // $ Source
Value: "secret",
}
c.HttpOnly = false
http.SetCookie(w, &c) // $ Alert // BAD: HttpOnly explicitly set to false
}
func handler6(w http.ResponseWriter, r *http.Request) {
val := false
c := http.Cookie{
Name: "session", // $ Source
Value: "secret",
HttpOnly: val,
}
http.SetCookie(w, &c) // $ Alert // BAD: HttpOnly explicitly set to false
}
func handler7(w http.ResponseWriter, r *http.Request) {
val := true
c := http.Cookie{
Name: "session",
Value: "secret",
HttpOnly: val,
}
http.SetCookie(w, &c) // GOOD: HttpOnly explicitly set to true
}
func handler8(w http.ResponseWriter, r *http.Request) {
val := true
c := http.Cookie{
Name: "session",
Value: "secret",
}
c.HttpOnly = val
http.SetCookie(w, &c) // GOOD: HttpOnly explicitly set to true
}
func handler9(w http.ResponseWriter, r *http.Request) {
val := false
c := http.Cookie{
Name: "session", // $ Source
Value: "secret",
}
c.HttpOnly = val
http.SetCookie(w, &c) // $ Alert //BAD: HttpOnly explicitly set to false
}
func handler10(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "consent",
Value: "1",
}
c.HttpOnly = false
http.SetCookie(w, &c) // GOOD: Name is not auth related
}
func handler11(w http.ResponseWriter, r *http.Request) {
name := "session" // $ Source
c := http.Cookie{
Name: name,
Value: "secret",
}
c.HttpOnly = false
http.SetCookie(w, &c) // $ Alert // BAD: auth related name
}
func handler12(w http.ResponseWriter, r *http.Request) {
session := "login_name" // $ Source
c := http.Cookie{
Name: session, // $ Source
Value: "secret",
}
c.HttpOnly = false
http.SetCookie(w, &c) // $ Alert // BAD: auth related name
}
func main() {
router := gin.Default()
router.GET("/cookie", func(c *gin.Context) {
_, err := c.Cookie("session")
if err != nil {
c.SetCookie("session", "test", 3600, "/", "localhost", false, false) // $ Alert // BAD: httpOnly set to false
}
})
router.Run()
}

View File

@@ -0,0 +1,2 @@
query: Security/CWE-1004/CookieWithoutHttpOnly.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -4,5 +4,4 @@ go 1.14
require ( require (
github.com/gin-gonic/gin v1.7.1 github.com/gin-gonic/gin v1.7.1
github.com/gorilla/sessions v1.2.1
) )

View File

@@ -0,0 +1,3 @@
# github.com/gin-gonic/gin v1.7.1
## explicit
github.com/gin-gonic/gin

View File

@@ -0,0 +1,6 @@
| CookieWithoutSecure.go:14:2:14:22 | call to SetCookie | Cookie does not set Secure attribute to true. |
| CookieWithoutSecure.go:23:2:23:22 | call to SetCookie | Cookie does not set Secure attribute to true. |
| CookieWithoutSecure.go:50:2:50:22 | call to SetCookie | Cookie does not set Secure attribute to true. |
| CookieWithoutSecure.go:60:2:60:22 | call to SetCookie | Cookie does not set Secure attribute to true. |
| CookieWithoutSecure.go:90:2:90:22 | call to SetCookie | Cookie does not set Secure attribute to true. |
| CookieWithoutSecure.go:102:4:102:71 | call to SetCookie | Cookie does not set Secure attribute to true. |

View File

@@ -0,0 +1,107 @@
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func handler1(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session", // $ Source
Value: "secret",
}
http.SetCookie(w, &c) // $ Alert // BAD: Secure set to false by default
}
func handler2(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session", // $ Source
Value: "secret",
Secure: false,
}
http.SetCookie(w, &c) // $ Alert // BAD: Secure explicitly set to false
}
func handler3(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session",
Value: "secret",
Secure: true,
}
http.SetCookie(w, &c) // GOOD: Secure explicitly set to true
}
func handler4(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session",
Value: "secret",
}
c.Secure = true
http.SetCookie(w, &c) // GOOD: Secure explicitly set to true
}
func handler5(w http.ResponseWriter, r *http.Request) {
c := http.Cookie{
Name: "session", // $ Source
Value: "secret",
}
c.Secure = false
http.SetCookie(w, &c) // $ Alert // BAD: Secure explicitly set to false
}
func handler6(w http.ResponseWriter, r *http.Request) {
val := false
c := http.Cookie{
Name: "session", // $ Source
Value: "secret",
Secure: val,
}
http.SetCookie(w, &c) // $ Alert // BAD: Secure explicitly set to false
}
func handler7(w http.ResponseWriter, r *http.Request) {
val := true
c := http.Cookie{
Name: "session",
Value: "secret",
Secure: val,
}
http.SetCookie(w, &c) // GOOD: Secure explicitly set to true
}
func handler8(w http.ResponseWriter, r *http.Request) {
val := true
c := http.Cookie{
Name: "session",
Value: "secret",
}
c.Secure = val
http.SetCookie(w, &c) // GOOD: Secure explicitly set to true
}
func handler9(w http.ResponseWriter, r *http.Request) {
val := false
c := http.Cookie{
Name: "session", // $ Source
Value: "secret",
}
c.Secure = val
http.SetCookie(w, &c) // $ Alert //BAD: Secure explicitly set to false
}
func main() {
router := gin.Default()
router.GET("/cookie", func(c *gin.Context) {
_, err := c.Cookie("session")
if err != nil {
c.SetCookie("session", "test", 3600, "/", "localhost", false, false) // $ Alert // BAD: Secure set to false
}
})
router.Run()
}

View File

@@ -0,0 +1,2 @@
query: Security/CWE-614/CookieWithoutSecure.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -0,0 +1,7 @@
module example.com/m
go 1.14
require (
github.com/gin-gonic/gin v1.7.1
)

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Manuel Martínez-Almeida
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,12 @@
// Code generated by depstubber. DO NOT EDIT.
// This is a simple stub for github.com/gin-gonic/gin/binding, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: github.com/gin-gonic/gin/binding (exports: ; functions: YAML)
// Package binding is a stub of github.com/gin-gonic/gin/binding, generated by depstubber.
package binding
import ()
var YAML interface{} = nil

View File

@@ -0,0 +1,677 @@
// Code generated by depstubber. DO NOT EDIT.
// This is a simple stub for github.com/gin-gonic/gin, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: github.com/gin-gonic/gin (exports: Context; functions: Default)
// Package gin is a stub of github.com/gin-gonic/gin, generated by depstubber.
package gin
import (
bufio "bufio"
template "html/template"
io "io"
multipart "mime/multipart"
net "net"
http "net/http"
time "time"
)
type Context struct {
Request *http.Request
Writer ResponseWriter
Params Params
Keys map[string]interface{}
Errors interface{}
Accepted []string
}
func (_ *Context) Abort() {}
func (_ *Context) AbortWithError(_ int, _ error) *Error {
return nil
}
func (_ *Context) AbortWithStatus(_ int) {}
func (_ *Context) AbortWithStatusJSON(_ int, _ interface{}) {}
func (_ *Context) AsciiJSON(_ int, _ interface{}) {}
func (_ *Context) Bind(_ interface{}) error {
return nil
}
func (_ *Context) BindHeader(_ interface{}) error {
return nil
}
func (_ *Context) BindJSON(_ interface{}) error {
return nil
}
func (_ *Context) BindQuery(_ interface{}) error {
return nil
}
func (_ *Context) BindUri(_ interface{}) error {
return nil
}
func (_ *Context) BindWith(_ interface{}, _ interface{}) error {
return nil
}
func (_ *Context) BindXML(_ interface{}) error {
return nil
}
func (_ *Context) BindYAML(_ interface{}) error {
return nil
}
func (_ *Context) ClientIP() string {
return ""
}
func (_ *Context) ContentType() string {
return ""
}
func (_ *Context) Cookie(_ string) (string, error) {
return "", nil
}
func (_ *Context) Copy() *Context {
return nil
}
func (_ *Context) Data(_ int, _ string, _ []byte) {}
func (_ *Context) DataFromReader(_ int, _ int64, _ string, _ io.Reader, _ map[string]string) {}
func (_ *Context) Deadline() (time.Time, bool) {
return time.Time{}, false
}
func (_ *Context) DefaultPostForm(_ string, _ string) string {
return ""
}
func (_ *Context) DefaultQuery(_ string, _ string) string {
return ""
}
func (_ *Context) Done() <-chan struct{} {
return nil
}
func (_ *Context) Err() error {
return nil
}
func (_ *Context) Error(_ error) *Error {
return nil
}
func (_ *Context) File(_ string) {}
func (_ *Context) FileAttachment(_ string, _ string) {}
func (_ *Context) FileFromFS(_ string, _ http.FileSystem) {}
func (_ *Context) FormFile(_ string) (*multipart.FileHeader, error) {
return nil, nil
}
func (_ *Context) FullPath() string {
return ""
}
func (_ *Context) Get(_ string) (interface{}, bool) {
return nil, false
}
func (_ *Context) GetBool(_ string) bool {
return false
}
func (_ *Context) GetDuration(_ string) time.Duration {
return 0
}
func (_ *Context) GetFloat64(_ string) float64 {
return 0
}
func (_ *Context) GetHeader(_ string) string {
return ""
}
func (_ *Context) GetInt(_ string) int {
return 0
}
func (_ *Context) GetInt64(_ string) int64 {
return 0
}
func (_ *Context) GetPostForm(_ string) (string, bool) {
return "", false
}
func (_ *Context) GetPostFormArray(_ string) ([]string, bool) {
return nil, false
}
func (_ *Context) GetPostFormMap(_ string) (map[string]string, bool) {
return nil, false
}
func (_ *Context) GetQuery(_ string) (string, bool) {
return "", false
}
func (_ *Context) GetQueryArray(_ string) ([]string, bool) {
return nil, false
}
func (_ *Context) GetQueryMap(_ string) (map[string]string, bool) {
return nil, false
}
func (_ *Context) GetRawData() ([]byte, error) {
return nil, nil
}
func (_ *Context) GetString(_ string) string {
return ""
}
func (_ *Context) GetStringMap(_ string) map[string]interface{} {
return nil
}
func (_ *Context) GetStringMapString(_ string) map[string]string {
return nil
}
func (_ *Context) GetStringMapStringSlice(_ string) map[string][]string {
return nil
}
func (_ *Context) GetStringSlice(_ string) []string {
return nil
}
func (_ *Context) GetTime(_ string) time.Time {
return time.Time{}
}
func (_ *Context) GetUint(_ string) uint {
return 0
}
func (_ *Context) GetUint64(_ string) uint64 {
return 0
}
func (_ *Context) HTML(_ int, _ string, _ interface{}) {}
func (_ *Context) Handler() HandlerFunc {
return nil
}
func (_ *Context) HandlerName() string {
return ""
}
func (_ *Context) HandlerNames() []string {
return nil
}
func (_ *Context) Header(_ string, _ string) {}
func (_ *Context) IndentedJSON(_ int, _ interface{}) {}
func (_ *Context) IsAborted() bool {
return false
}
func (_ *Context) IsWebsocket() bool {
return false
}
func (_ *Context) JSON(_ int, _ interface{}) {}
func (_ *Context) JSONP(_ int, _ interface{}) {}
func (_ *Context) MultipartForm() (*multipart.Form, error) {
return nil, nil
}
func (_ *Context) MustBindWith(_ interface{}, _ interface{}) error {
return nil
}
func (_ *Context) MustGet(_ string) interface{} {
return nil
}
func (_ *Context) Negotiate(_ int, _ Negotiate) {}
func (_ *Context) NegotiateFormat(_ ...string) string {
return ""
}
func (_ *Context) Next() {}
func (_ *Context) Param(_ string) string {
return ""
}
func (_ *Context) PostForm(_ string) string {
return ""
}
func (_ *Context) PostFormArray(_ string) []string {
return nil
}
func (_ *Context) PostFormMap(_ string) map[string]string {
return nil
}
func (_ *Context) ProtoBuf(_ int, _ interface{}) {}
func (_ *Context) PureJSON(_ int, _ interface{}) {}
func (_ *Context) Query(_ string) string {
return ""
}
func (_ *Context) QueryArray(_ string) []string {
return nil
}
func (_ *Context) QueryMap(_ string) map[string]string {
return nil
}
func (_ *Context) Redirect(_ int, _ string) {}
func (_ *Context) RemoteIP() (net.IP, bool) {
return nil, false
}
func (_ *Context) Render(_ int, _ interface{}) {}
func (_ *Context) SSEvent(_ string, _ interface{}) {}
func (_ *Context) SaveUploadedFile(_ *multipart.FileHeader, _ string) error {
return nil
}
func (_ *Context) SecureJSON(_ int, _ interface{}) {}
func (_ *Context) Set(_ string, _ interface{}) {}
func (_ *Context) SetAccepted(_ ...string) {}
func (_ *Context) SetCookie(_ string, _ string, _ int, _ string, _ string, _ bool, _ bool) {}
func (_ *Context) SetSameSite(_ http.SameSite) {}
func (_ *Context) ShouldBind(_ interface{}) error {
return nil
}
func (_ *Context) ShouldBindBodyWith(_ interface{}, _ interface{}) error {
return nil
}
func (_ *Context) ShouldBindHeader(_ interface{}) error {
return nil
}
func (_ *Context) ShouldBindJSON(_ interface{}) error {
return nil
}
func (_ *Context) ShouldBindQuery(_ interface{}) error {
return nil
}
func (_ *Context) ShouldBindUri(_ interface{}) error {
return nil
}
func (_ *Context) ShouldBindWith(_ interface{}, _ interface{}) error {
return nil
}
func (_ *Context) ShouldBindXML(_ interface{}) error {
return nil
}
func (_ *Context) ShouldBindYAML(_ interface{}) error {
return nil
}
func (_ *Context) Status(_ int) {}
func (_ *Context) Stream(_ func(io.Writer) bool) bool {
return false
}
func (_ *Context) String(_ int, _ string, _ ...interface{}) {}
func (_ *Context) Value(_ interface{}) interface{} {
return nil
}
func (_ *Context) XML(_ int, _ interface{}) {}
func (_ *Context) YAML(_ int, _ interface{}) {}
func Default() *Engine {
return nil
}
type Engine struct {
RouterGroup RouterGroup
RedirectTrailingSlash bool
RedirectFixedPath bool
HandleMethodNotAllowed bool
ForwardedByClientIP bool
RemoteIPHeaders []string
TrustedProxies []string
AppEngine bool
UseRawPath bool
UnescapePathValues bool
MaxMultipartMemory int64
RemoveExtraSlash bool
HTMLRender interface{}
FuncMap template.FuncMap
}
func (_ *Engine) Any(_ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *Engine) BasePath() string {
return ""
}
func (_ *Engine) DELETE(_ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *Engine) Delims(_ string, _ string) *Engine {
return nil
}
func (_ *Engine) GET(_ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *Engine) Group(_ string, _ ...HandlerFunc) *RouterGroup {
return nil
}
func (_ *Engine) HEAD(_ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *Engine) Handle(_ string, _ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *Engine) HandleContext(_ *Context) {}
func (_ *Engine) LoadHTMLFiles(_ ...string) {}
func (_ *Engine) LoadHTMLGlob(_ string) {}
func (_ *Engine) NoMethod(_ ...HandlerFunc) {}
func (_ *Engine) NoRoute(_ ...HandlerFunc) {}
func (_ *Engine) OPTIONS(_ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *Engine) PATCH(_ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *Engine) POST(_ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *Engine) PUT(_ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *Engine) Routes() RoutesInfo {
return nil
}
func (_ *Engine) Run(_ ...string) error {
return nil
}
func (_ *Engine) RunFd(_ int) error {
return nil
}
func (_ *Engine) RunListener(_ net.Listener) error {
return nil
}
func (_ *Engine) RunTLS(_ string, _ string, _ string) error {
return nil
}
func (_ *Engine) RunUnix(_ string) error {
return nil
}
func (_ *Engine) SecureJsonPrefix(_ string) *Engine {
return nil
}
func (_ *Engine) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {}
func (_ *Engine) SetFuncMap(_ template.FuncMap) {}
func (_ *Engine) SetHTMLTemplate(_ *template.Template) {}
func (_ *Engine) Static(_ string, _ string) IRoutes {
return nil
}
func (_ *Engine) StaticFS(_ string, _ http.FileSystem) IRoutes {
return nil
}
func (_ *Engine) StaticFile(_ string, _ string) IRoutes {
return nil
}
func (_ *Engine) Use(_ ...HandlerFunc) IRoutes {
return nil
}
type Error struct {
Err error
Type ErrorType
Meta interface{}
}
func (_ Error) Error() string {
return ""
}
func (_ *Error) IsType(_ ErrorType) bool {
return false
}
func (_ *Error) JSON() interface{} {
return nil
}
func (_ *Error) MarshalJSON() ([]byte, error) {
return nil, nil
}
func (_ *Error) SetMeta(_ interface{}) *Error {
return nil
}
func (_ *Error) SetType(_ ErrorType) *Error {
return nil
}
func (_ *Error) Unwrap() error {
return nil
}
type ErrorType uint64
type HandlerFunc func(*Context)
type HandlersChain []HandlerFunc
func (_ HandlersChain) Last() HandlerFunc {
return nil
}
type IRoutes interface {
Any(_ string, _ ...HandlerFunc) IRoutes
DELETE(_ string, _ ...HandlerFunc) IRoutes
GET(_ string, _ ...HandlerFunc) IRoutes
HEAD(_ string, _ ...HandlerFunc) IRoutes
Handle(_ string, _ string, _ ...HandlerFunc) IRoutes
OPTIONS(_ string, _ ...HandlerFunc) IRoutes
PATCH(_ string, _ ...HandlerFunc) IRoutes
POST(_ string, _ ...HandlerFunc) IRoutes
PUT(_ string, _ ...HandlerFunc) IRoutes
Static(_ string, _ string) IRoutes
StaticFS(_ string, _ http.FileSystem) IRoutes
StaticFile(_ string, _ string) IRoutes
Use(_ ...HandlerFunc) IRoutes
}
type Negotiate struct {
Offered []string
HTMLName string
HTMLData interface{}
JSONData interface{}
XMLData interface{}
YAMLData interface{}
Data interface{}
}
type Param struct {
Key string
Value string
}
type Params []Param
func (_ Params) ByName(_ string) string {
return ""
}
func (_ Params) Get(_ string) (string, bool) {
return "", false
}
type ResponseWriter interface {
CloseNotify() <-chan bool
Flush()
Header() http.Header
Hijack() (net.Conn, *bufio.ReadWriter, error)
Pusher() http.Pusher
Size() int
Status() int
Write(_ []byte) (int, error)
WriteHeader(_ int)
WriteHeaderNow()
WriteString(_ string) (int, error)
Written() bool
}
type RouteInfo struct {
Method string
Path string
Handler string
HandlerFunc HandlerFunc
}
type RouterGroup struct {
Handlers HandlersChain
}
func (_ *RouterGroup) Any(_ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *RouterGroup) BasePath() string {
return ""
}
func (_ *RouterGroup) DELETE(_ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *RouterGroup) GET(_ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *RouterGroup) Group(_ string, _ ...HandlerFunc) *RouterGroup {
return nil
}
func (_ *RouterGroup) HEAD(_ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *RouterGroup) Handle(_ string, _ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *RouterGroup) OPTIONS(_ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *RouterGroup) PATCH(_ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *RouterGroup) POST(_ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *RouterGroup) PUT(_ string, _ ...HandlerFunc) IRoutes {
return nil
}
func (_ *RouterGroup) Static(_ string, _ string) IRoutes {
return nil
}
func (_ *RouterGroup) StaticFS(_ string, _ http.FileSystem) IRoutes {
return nil
}
func (_ *RouterGroup) StaticFile(_ string, _ string) IRoutes {
return nil
}
func (_ *RouterGroup) Use(_ ...HandlerFunc) IRoutes {
return nil
}
type RoutesInfo []RouteInfo

View File

@@ -0,0 +1,3 @@
# github.com/gin-gonic/gin v1.7.1
## explicit
github.com/gin-gonic/gin

View File

@@ -86,6 +86,8 @@ pragma[nomagic]
private predicate constantIntegerExpr(Expr e, int val) { private predicate constantIntegerExpr(Expr e, int val) {
e.(CompileTimeConstantExpr).getIntValue() = val e.(CompileTimeConstantExpr).getIntValue() = val
or or
e.(LongLiteral).getValue().toInt() = val
or
exists(SsaExplicitWrite v, Expr src | exists(SsaExplicitWrite v, Expr src |
e = v.getARead() and e = v.getARead() and
src = v.getValue() and src = v.getValue() and

View File

@@ -2,7 +2,7 @@ import rust
import codeql.rust.internal.PathResolution import codeql.rust.internal.PathResolution
import utils.test.PathResolutionInlineExpectationsTest import utils.test.PathResolutionInlineExpectationsTest
query predicate resolveDollarCrate(RelevantPath p, Crate c) { query predicate resolveDollarCrate(PathExt p, Crate c) {
c = resolvePath(p) and c = resolvePath(p) and
p.isDollarCrate() and p.isDollarCrate() and
p.fromSource() and p.fromSource() and

View File

@@ -11,6 +11,7 @@ ql/rust/ql/src/queries/diagnostics/UnresolvedMacroCalls.ql
ql/rust/ql/src/queries/security/CWE-020/RegexInjection.ql ql/rust/ql/src/queries/security/CWE-020/RegexInjection.ql
ql/rust/ql/src/queries/security/CWE-022/TaintedPath.ql ql/rust/ql/src/queries/security/CWE-022/TaintedPath.ql
ql/rust/ql/src/queries/security/CWE-089/SqlInjection.ql ql/rust/ql/src/queries/security/CWE-089/SqlInjection.ql
ql/rust/ql/src/queries/security/CWE-295/DisabledCertificateCheck.ql
ql/rust/ql/src/queries/security/CWE-311/CleartextTransmission.ql ql/rust/ql/src/queries/security/CWE-311/CleartextTransmission.ql
ql/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql ql/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql
ql/rust/ql/src/queries/security/CWE-312/CleartextStorageDatabase.ql ql/rust/ql/src/queries/security/CWE-312/CleartextStorageDatabase.ql

View File

@@ -12,6 +12,7 @@ ql/rust/ql/src/queries/security/CWE-020/RegexInjection.ql
ql/rust/ql/src/queries/security/CWE-022/TaintedPath.ql ql/rust/ql/src/queries/security/CWE-022/TaintedPath.ql
ql/rust/ql/src/queries/security/CWE-089/SqlInjection.ql ql/rust/ql/src/queries/security/CWE-089/SqlInjection.ql
ql/rust/ql/src/queries/security/CWE-117/LogInjection.ql ql/rust/ql/src/queries/security/CWE-117/LogInjection.ql
ql/rust/ql/src/queries/security/CWE-295/DisabledCertificateCheck.ql
ql/rust/ql/src/queries/security/CWE-311/CleartextTransmission.ql ql/rust/ql/src/queries/security/CWE-311/CleartextTransmission.ql
ql/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql ql/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql
ql/rust/ql/src/queries/security/CWE-312/CleartextStorageDatabase.ql ql/rust/ql/src/queries/security/CWE-312/CleartextStorageDatabase.ql

View File

@@ -12,6 +12,7 @@ ql/rust/ql/src/queries/security/CWE-020/RegexInjection.ql
ql/rust/ql/src/queries/security/CWE-022/TaintedPath.ql ql/rust/ql/src/queries/security/CWE-022/TaintedPath.ql
ql/rust/ql/src/queries/security/CWE-089/SqlInjection.ql ql/rust/ql/src/queries/security/CWE-089/SqlInjection.ql
ql/rust/ql/src/queries/security/CWE-117/LogInjection.ql ql/rust/ql/src/queries/security/CWE-117/LogInjection.ql
ql/rust/ql/src/queries/security/CWE-295/DisabledCertificateCheck.ql
ql/rust/ql/src/queries/security/CWE-311/CleartextTransmission.ql ql/rust/ql/src/queries/security/CWE-311/CleartextTransmission.ql
ql/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql ql/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql
ql/rust/ql/src/queries/security/CWE-312/CleartextStorageDatabase.ql ql/rust/ql/src/queries/security/CWE-312/CleartextStorageDatabase.ql

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added more detailed models for `std::fs` and `std::path`.

View File

@@ -1,5 +1,6 @@
private import codeql.util.Boolean private import codeql.util.Boolean
private import codeql.rust.controlflow.ControlFlowGraph private import codeql.rust.controlflow.ControlFlowGraph
private import codeql.rust.elements.internal.VariableImpl::Impl as VariableImpl
private import rust private import rust
newtype TCompletion = newtype TCompletion =
@@ -123,13 +124,7 @@ class BooleanCompletion extends ConditionalCompletion, TBooleanCompletion {
*/ */
private predicate cannotCauseMatchFailure(Pat pat) { private predicate cannotCauseMatchFailure(Pat pat) {
pat instanceof RangePat or pat instanceof RangePat or
// Identifier patterns that are in fact path patterns can cause failures. For pat = any(IdentPat p | p.hasPat() or VariableImpl::variableDecl(_, p.getName(), _)) or
// instance `None`. Only if an `@ ...` part is present can we be sure that
// it's an actual identifier pattern. As a heuristic, if the identifier starts
// with a lower case letter, then we assume that it's an identifier. This
// works for code that follows the Rust naming convention for enums and
// constants.
pat = any(IdentPat p | p.hasPat() or p.getName().getText().charAt(0).isLowercase()) or
pat instanceof WildcardPat or pat instanceof WildcardPat or
pat instanceof RestPat or pat instanceof RestPat or
pat instanceof RefPat or pat instanceof RefPat or

View File

@@ -82,7 +82,7 @@ module Impl {
} }
private predicate callHasTraitQualifier(CallExpr call, Trait qualifier) { private predicate callHasTraitQualifier(CallExpr call, Trait qualifier) {
exists(RelevantPath qualifierPath | exists(PathExt qualifierPath |
callHasQualifier(call, _, qualifierPath) and callHasQualifier(call, _, qualifierPath) and
qualifier = resolvePath(qualifierPath) and qualifier = resolvePath(qualifierPath) and
// When the qualifier is `Self` and resolves to a trait, it's inside a // When the qualifier is `Self` and resolves to a trait, it's inside a

View File

@@ -5,6 +5,8 @@
*/ */
private import codeql.rust.elements.internal.generated.Const private import codeql.rust.elements.internal.generated.Const
private import codeql.rust.elements.internal.AstNodeImpl::Impl as AstNodeImpl
private import codeql.rust.elements.internal.IdentPatImpl::Impl as IdentPatImpl
private import codeql.rust.elements.internal.PathExprImpl::Impl as PathExprImpl private import codeql.rust.elements.internal.PathExprImpl::Impl as PathExprImpl
private import codeql.rust.internal.PathResolution private import codeql.rust.internal.PathResolution
@@ -36,14 +38,30 @@ module Impl {
* } * }
* ``` * ```
*/ */
class ConstAccess extends PathExprImpl::PathExpr { abstract class ConstAccess extends AstNodeImpl::AstNode {
private Const c;
ConstAccess() { c = resolvePath(this.getPath()) }
/** Gets the constant being accessed. */ /** Gets the constant being accessed. */
Const getConst() { result = c } abstract Const getConst();
override string getAPrimaryQlClass() { result = "ConstAccess" } override string getAPrimaryQlClass() { result = "ConstAccess" }
} }
private class PathExprConstAccess extends ConstAccess, PathExprImpl::PathExpr {
private Const c;
PathExprConstAccess() { c = resolvePath(this.getPath()) }
override Const getConst() { result = c }
override string getAPrimaryQlClass() { result = ConstAccess.super.getAPrimaryQlClass() }
}
private class IdentPatConstAccess extends ConstAccess, IdentPatImpl::IdentPat {
private Const c;
IdentPatConstAccess() { c = resolvePath(this) }
override Const getConst() { result = c }
override string getAPrimaryQlClass() { result = ConstAccess.super.getAPrimaryQlClass() }
}
} }

View File

@@ -31,6 +31,8 @@ module Impl {
override string toStringImpl() { result = this.getName() } override string toStringImpl() { result = this.getName() }
override string getAPrimaryQlClass() { result = "FormatTemplateVariableAccess" }
/** Gets the name of the variable */ /** Gets the name of the variable */
string getName() { result = argument.getName() } string getName() { result = argument.getName() }

View File

@@ -4,6 +4,7 @@
* INTERNAL: Do not use. * INTERNAL: Do not use.
*/ */
private import rust
private import codeql.rust.elements.internal.generated.PathExpr private import codeql.rust.elements.internal.generated.PathExpr
/** /**
@@ -25,5 +26,11 @@ module Impl {
override string toStringImpl() { result = this.toAbbreviatedString() } override string toStringImpl() { result = this.toAbbreviatedString() }
override string toAbbreviatedString() { result = this.getPath().toStringImpl() } override string toAbbreviatedString() { result = this.getPath().toStringImpl() }
override string getAPrimaryQlClass() {
if this instanceof VariableAccess
then result = "VariableAccess"
else result = super.getAPrimaryQlClass()
}
} }
} }

View File

@@ -1,8 +1,9 @@
private import rust private import rust
private import codeql.rust.controlflow.ControlFlowGraph private import codeql.rust.controlflow.ControlFlowGraph
private import codeql.rust.internal.PathResolution as PathResolution
private import codeql.rust.elements.internal.generated.ParentChild as ParentChild private import codeql.rust.elements.internal.generated.ParentChild as ParentChild
private import codeql.rust.elements.internal.AstNodeImpl::Impl as AstNodeImpl
private import codeql.rust.elements.internal.PathImpl::Impl as PathImpl private import codeql.rust.elements.internal.PathImpl::Impl as PathImpl
private import codeql.rust.elements.internal.PathExprBaseImpl::Impl as PathExprBaseImpl
private import codeql.rust.elements.internal.FormatTemplateVariableAccessImpl::Impl as FormatTemplateVariableAccessImpl private import codeql.rust.elements.internal.FormatTemplateVariableAccessImpl::Impl as FormatTemplateVariableAccessImpl
private import codeql.util.DenseRank private import codeql.util.DenseRank
@@ -98,7 +99,7 @@ module Impl {
* pattern. * pattern.
*/ */
cached cached
private predicate variableDecl(AstNode definingNode, Name name, string text) { predicate variableDecl(AstNode definingNode, Name name, string text) {
Cached::ref() and Cached::ref() and
exists(SelfParam sp | exists(SelfParam sp |
name = sp.getName() and name = sp.getName() and
@@ -117,11 +118,7 @@ module Impl {
not exists(getOutermostEnclosingOrPat(pat)) and definingNode = name not exists(getOutermostEnclosingOrPat(pat)) and definingNode = name
) and ) and
text = name.getText() and text = name.getText() and
// exclude for now anything starting with an uppercase character, which may be a reference to not PathResolution::identPatIsResolvable(pat) and
// an enum constant (e.g. `None`). This excludes static and constant variables (UPPERCASE),
// which we don't appear to recognize yet anyway. This also assumes programmers follow the
// naming guidelines, which they generally do, but they're not enforced.
not text.charAt(0).isUppercase() and
// exclude parameters from functions without a body as these are trait method declarations // exclude parameters from functions without a body as these are trait method declarations
// without implementations // without implementations
not exists(Function f | not f.hasBody() and f.getAParam().getPat() = pat) and not exists(Function f | not f.hasBody() and f.getAParam().getPat() = pat) and
@@ -666,7 +663,7 @@ module Impl {
} }
/** A variable access. */ /** A variable access. */
class VariableAccess extends PathExprBaseImpl::PathExprBase { class VariableAccess extends PathExprBase {
private string name; private string name;
private Variable v; private Variable v;
@@ -677,10 +674,6 @@ module Impl {
/** Holds if this access is a capture. */ /** Holds if this access is a capture. */
predicate isCapture() { this.getEnclosingCfgScope() != v.getEnclosingCfgScope() } predicate isCapture() { this.getEnclosingCfgScope() != v.getEnclosingCfgScope() }
override string toStringImpl() { result = name }
override string getAPrimaryQlClass() { result = "VariableAccess" }
} }
/** Holds if `e` occurs in the LHS of an assignment or compound assignment. */ /** Holds if `e` occurs in the LHS of an assignment or compound assignment. */
@@ -722,7 +715,7 @@ module Impl {
} }
/** A nested function access. */ /** A nested function access. */
class NestedFunctionAccess extends PathExprBaseImpl::PathExprBase { class NestedFunctionAccess extends PathExprBase {
private Function f; private Function f;
NestedFunctionAccess() { nestedFunctionAccess(_, f, this) } NestedFunctionAccess() { nestedFunctionAccess(_, f, this) }

View File

@@ -0,0 +1,9 @@
extensions:
- addsTo:
pack: codeql/rust-all
extensible: sinkModel
data:
- ["<native_tls::TlsConnectorBuilder>::danger_accept_invalid_certs", "Argument[0]", "disable-certificate", "manual"]
- ["<native_tls::TlsConnectorBuilder>::danger_accept_invalid_hostnames", "Argument[0]", "disable-certificate", "manual"]
- ["<async_native_tls::connect::TlsConnector>::danger_accept_invalid_certs", "Argument[0]", "disable-certificate", "manual"]
- ["<async_native_tls::connect::TlsConnector>::danger_accept_invalid_hostnames", "Argument[0]", "disable-certificate", "manual"]

View File

@@ -11,6 +11,10 @@ extensions:
data: data:
- ["<reqwest::async_impl::client::Client>::request", "Argument[1]", "request-url", "manual"] - ["<reqwest::async_impl::client::Client>::request", "Argument[1]", "request-url", "manual"]
- ["<reqwest::blocking::client::Client>::request", "Argument[1]", "request-url", "manual"] - ["<reqwest::blocking::client::Client>::request", "Argument[1]", "request-url", "manual"]
- ["<reqwest::async_impl::client::ClientBuilder>::danger_accept_invalid_certs", "Argument[0]", "disable-certificate", "manual"]
- ["<reqwest::async_impl::client::ClientBuilder>::danger_accept_invalid_hostnames", "Argument[0]", "disable-certificate", "manual"]
- ["<reqwest::blocking::client::ClientBuilder>::danger_accept_invalid_certs", "Argument[0]", "disable-certificate", "manual"]
- ["<reqwest::blocking::client::ClientBuilder>::danger_accept_invalid_hostnames", "Argument[0]", "disable-certificate", "manual"]
- addsTo: - addsTo:
pack: codeql/rust-all pack: codeql/rust-all
extensible: summaryModel extensible: summaryModel

View File

@@ -60,6 +60,7 @@ extensions:
- ["core::ptr::dangling", "ReturnValue", "pointer-invalidate", "manual"] - ["core::ptr::dangling", "ReturnValue", "pointer-invalidate", "manual"]
- ["core::ptr::dangling_mut", "ReturnValue", "pointer-invalidate", "manual"] - ["core::ptr::dangling_mut", "ReturnValue", "pointer-invalidate", "manual"]
- ["core::ptr::null", "ReturnValue", "pointer-invalidate", "manual"] - ["core::ptr::null", "ReturnValue", "pointer-invalidate", "manual"]
- ["core::ptr::null_mut", "ReturnValue", "pointer-invalidate", "manual"]
- ["v8::primitives::null", "ReturnValue", "pointer-invalidate", "manual"] - ["v8::primitives::null", "ReturnValue", "pointer-invalidate", "manual"]
- addsTo: - addsTo:
pack: codeql/rust-all pack: codeql/rust-all

View File

@@ -3,14 +3,27 @@ extensions:
pack: codeql/rust-all pack: codeql/rust-all
extensible: sourceModel extensible: sourceModel
data: data:
- ["std::fs::exists", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["std::fs::read", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"] - ["std::fs::read", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["std::fs::read_dir", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["std::fs::read_to_string", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"] - ["std::fs::read_to_string", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["std::fs::read_link", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"] - ["std::fs::read_link", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["std::fs::metadata", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["std::fs::symlink_metadata", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["<std::fs::DirEntry>::path", "ReturnValue", "file", "manual"] - ["<std::fs::DirEntry>::path", "ReturnValue", "file", "manual"]
- ["<std::fs::DirEntry>::file_name", "ReturnValue", "file", "manual"] - ["<std::fs::DirEntry>::file_name", "ReturnValue", "file", "manual"]
- ["<std::fs::File>::open", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"] - ["<std::fs::File>::open", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["<std::fs::File>::open_buffered", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"] - ["<std::fs::File>::open_buffered", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["<std::fs::OpenOptions>::open", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"] - ["<std::fs::OpenOptions>::open", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["<std::path::Path>::exists", "ReturnValue", "file", "manual"]
- ["<std::path::Path>::try_exists", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["<std::path::Path>::is_file", "ReturnValue", "file", "manual"]
- ["<std::path::Path>::is_dir", "ReturnValue", "file", "manual"]
- ["<std::path::Path>::is_symlink", "ReturnValue", "file", "manual"]
- ["<std::path::Path>::metadata", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["<std::path::Path>::symlink_metadata", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["<std::path::Path>::read_dir", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- ["<std::path::Path>::read_link", "ReturnValue.Field[core::result::Result::Ok(0)]", "file", "manual"]
- addsTo: - addsTo:
pack: codeql/rust-all pack: codeql/rust-all
extensible: sinkModel extensible: sinkModel
@@ -68,3 +81,12 @@ extensions:
- ["<std::path::Path>::with_extension", "Argument[Self].Reference", "ReturnValue", "taint", "manual"] - ["<std::path::Path>::with_extension", "Argument[Self].Reference", "ReturnValue", "taint", "manual"]
- ["<std::path::Path>::with_file_name", "Argument[Self].Reference", "ReturnValue", "taint", "manual"] - ["<std::path::Path>::with_file_name", "Argument[Self].Reference", "ReturnValue", "taint", "manual"]
- ["<std::path::Path>::with_file_name", "Argument[0]", "ReturnValue", "taint", "manual"] - ["<std::path::Path>::with_file_name", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["<std::fs::Metadata>::accessed", "Argument[self].Reference", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
- ["<std::fs::Metadata>::created", "Argument[self].Reference", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
- ["<std::fs::Metadata>::file_type", "Argument[self].Reference", "ReturnValue", "taint", "manual"]
- ["<std::fs::Metadata>::is_file", "Argument[self].Reference", "ReturnValue", "taint", "manual"]
- ["<std::fs::Metadata>::is_dir", "Argument[self].Reference", "ReturnValue", "taint", "manual"]
- ["<std::fs::Metadata>::is_symlink", "Argument[self].Reference", "ReturnValue", "taint", "manual"]
- ["<std::fs::Metadata>::len", "Argument[self].Reference", "ReturnValue", "taint", "manual"]
- ["<std::fs::Metadata>::modified", "Argument[self].Reference", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
- ["<std::fs::Metadata>::permissions", "Argument[self].Reference", "ReturnValue", "taint", "manual"]

View File

@@ -115,13 +115,11 @@ module Stages {
predicate backref() { predicate backref() {
1 = 1 1 = 1
or or
exists(resolvePath(_)) exists(resolvePathIgnoreVariableShadowing(_))
or or
exists(any(ItemNode i).getASuccessor(_, _, _)) exists(any(ItemNode i).getASuccessor(_, _, _))
or or
exists(any(ImplOrTraitItemNode i).getASelfPath()) exists(any(ImplOrTraitItemNode i).getASelfPath())
or
any(TypeParamItemNode i).hasTraitBound()
} }
} }

View File

@@ -37,6 +37,9 @@ private module Cached {
TFormatArgsArgIndex(Expr e) { e = any(FormatArgsArg a).getExpr() } or TFormatArgsArgIndex(Expr e) { e = any(FormatArgsArg a).getExpr() } or
TItemNode(ItemNode i) TItemNode(ItemNode i)
pragma[nomagic]
private predicate isMacroCallLocation(Location loc) { loc = any(MacroCall m).getLocation() }
/** /**
* Gets an element, of kind `kind`, that element `use` uses, if any. * Gets an element, of kind `kind`, that element `use` uses, if any.
*/ */
@@ -44,7 +47,7 @@ private module Cached {
Definition definitionOf(Use use, string kind) { Definition definitionOf(Use use, string kind) {
result = use.getDefinition() and result = use.getDefinition() and
kind = use.getUseType() and kind = use.getUseType() and
not result.getLocation() = any(MacroCall m).getLocation() not isMacroCallLocation(result.getLocation())
} }
} }

View File

@@ -1,9 +1,49 @@
/** /**
* Provides functionality for resolving paths, using the predicate `resolvePath`. * Provides functionality for resolving paths, using the predicate `resolvePath`.
*
* Path resolution needs to happen before variable resolution, because otherwise
* we cannot know whether an identifier pattern binds a new variable or whether it
* refers to a constructor or constant:
*
* ```rust
* let x = ...; // `x` is only a variable if it does not resolve to a constructor/constant
* ```
*
* Even though variable names typically start with a lowercase letter and constructors
* with an uppercase letter, this is not enforced by the Rust language.
*
* Variables may shadow declarations, so variable resolution also needs to affect
* path resolution:
*
* ```rust
* fn foo() {} // (1)
*
* fn bar() {
* let f = foo; // `foo` here refers to (1) via path resolution
* let foo = f(); // (2)
* foo // `foo` here refers to (2) via variable resolution
* }
* ```
*
* So it may seem that path resolution and variable resolution must happen in mutual
* recursion, but we would like to keep the inherently global path resolution logic
* separate from the inherently local variable resolution logic. We achieve this by
*
* - First computing global path resolution, where variable shadowing is ignored,
* exposed as the internal predicate `resolvePathIgnoreVariableShadowing`.
* - `resolvePathIgnoreVariableShadowing` is sufficient to determine whether an
* identifier pattern resolves to a constructor/constant, since if it does, it cannot
* be shadowed by a variable. We expose this as the predicate `identPatIsResolvable`.
* - Variable resolution can then be computed as a local property, using only the
* global information from `identPatIsResolvable`.
* - Finally, path resolution can be computed by restricting
* `resolvePathIgnoreVariableShadowing` to paths that are not resolvable via
* variable resolution.
*/ */
private import rust private import rust
private import codeql.rust.elements.internal.generated.ParentChild private import codeql.rust.elements.internal.generated.ParentChild
private import codeql.rust.elements.internal.AstNodeImpl::Impl as AstNodeImpl
private import codeql.rust.elements.internal.CallExprImpl::Impl as CallExprImpl private import codeql.rust.elements.internal.CallExprImpl::Impl as CallExprImpl
private import codeql.rust.internal.CachedStages private import codeql.rust.internal.CachedStages
private import codeql.rust.frameworks.stdlib.Builtins as Builtins private import codeql.rust.frameworks.stdlib.Builtins as Builtins
@@ -184,7 +224,7 @@ abstract class ItemNode extends Locatable {
pragma[nomagic] pragma[nomagic]
final Attr getAttr(string name) { final Attr getAttr(string name) {
result = this.getAnAttr() and result = this.getAnAttr() and
result.getMeta().getPath().(RelevantPath).isUnqualified(name) result.getMeta().getPath().(PathExt).isUnqualified(name)
} }
final predicate hasAttr(string name) { exists(this.getAttr(name)) } final predicate hasAttr(string name) { exists(this.getAttr(name)) }
@@ -1159,34 +1199,6 @@ final class TypeParamItemNode extends TypeItemNode instanceof TypeParam {
ItemNode resolveABound() { result = resolvePath(this.getABoundPath()) } ItemNode resolveABound() { result = resolvePath(this.getABoundPath()) }
/**
* Holds if this type parameter has a trait bound. Examples:
*
* ```rust
* impl<T> Foo<T> { ... } // has no trait bound
*
* impl<T: Trait> Foo<T> { ... } // has trait bound
*
* impl<T> Foo<T> where T: Trait { ... } // has trait bound
* ```
*/
cached
predicate hasTraitBound() { Stages::PathResolutionStage::ref() and exists(this.getABoundPath()) }
/**
* Holds if this type parameter has no trait bound. Examples:
*
* ```rust
* impl<T> Foo<T> { ... } // has no trait bound
*
* impl<T: Trait> Foo<T> { ... } // has trait bound
*
* impl<T> Foo<T> where T: Trait { ... } // has trait bound
* ```
*/
pragma[nomagic]
predicate hasNoTraitBound() { not this.hasTraitBound() }
override string getName() { result = TypeParam.super.getName().getText() } override string getName() { result = TypeParam.super.getName().getText() }
override Namespace getNamespace() { result.isType() } override Namespace getNamespace() { result.isType() }
@@ -1525,20 +1537,22 @@ private predicate declares(ItemNode item, Namespace ns, string name) {
) )
} }
/** A path that does not access a local variable. */ /**
class RelevantPath extends Path { * A `Path` or an `IdentPat`.
RelevantPath() { not this = any(VariableAccess va).(PathExpr).getPath() } *
* `IdentPat`s are included in order to resolve unqualified references to
* constructors in patterns.
*/
abstract class PathExt extends AstNode {
abstract string getText();
/** Holds if this is an unqualified path with the textual value `name`. */ /** Holds if this is an unqualified path with the textual value `name`. */
pragma[nomagic] pragma[nomagic]
predicate isUnqualified(string name) { abstract predicate isUnqualified(string name);
not exists(this.getQualifier()) and
not exists(UseTree tree | abstract Path getQualifier();
tree.hasPath() and
this = getAUseTreeUseTree(tree).getPath().getQualifier*() abstract string toStringDebug();
) and
name = this.getText()
}
/** /**
* Holds if this is an unqualified path with the textual value `name` and * Holds if this is an unqualified path with the textual value `name` and
@@ -1560,6 +1574,33 @@ class RelevantPath extends Path {
predicate isDollarCrate() { this.isUnqualified("$crate", _) } predicate isDollarCrate() { this.isUnqualified("$crate", _) }
} }
private class PathExtPath extends PathExt instanceof Path {
override string getText() { result = Path.super.getText() }
override predicate isUnqualified(string name) {
not exists(Path.super.getQualifier()) and
not exists(UseTree tree |
tree.hasPath() and
this = getAUseTreeUseTree(tree).getPath().getQualifier*()
) and
name = Path.super.getText()
}
override Path getQualifier() { result = Path.super.getQualifier() }
override string toStringDebug() { result = Path.super.toStringDebug() }
}
private class PathExtIdentPat extends PathExt, IdentPat {
override string getText() { result = this.getName().getText() }
override predicate isUnqualified(string name) { name = this.getText() }
override Path getQualifier() { none() }
override string toStringDebug() { result = this.getText() }
}
private predicate isModule(ItemNode m) { m instanceof Module } private predicate isModule(ItemNode m) { m instanceof Module }
/** Holds if source file `source` contains the module `m`. */ /** Holds if source file `source` contains the module `m`. */
@@ -1583,7 +1624,7 @@ private ItemNode getOuterScope(ItemNode i) {
pragma[nomagic] pragma[nomagic]
private predicate unqualifiedPathLookup(ItemNode ancestor, string name, Namespace ns, ItemNode encl) { private predicate unqualifiedPathLookup(ItemNode ancestor, string name, Namespace ns, ItemNode encl) {
// lookup in the immediately enclosing item // lookup in the immediately enclosing item
exists(RelevantPath path | exists(PathExt path |
path.isUnqualified(name, encl) and path.isUnqualified(name, encl) and
ancestor = encl and ancestor = encl and
not name = ["crate", "$crate", "super", "self"] not name = ["crate", "$crate", "super", "self"]
@@ -1619,7 +1660,7 @@ private ItemNode getASuccessor(
private predicate isSourceFile(ItemNode source) { source instanceof SourceFileItemNode } private predicate isSourceFile(ItemNode source) { source instanceof SourceFileItemNode }
private predicate hasCratePath(ItemNode i) { any(RelevantPath path).isCratePath(_, i) } private predicate hasCratePath(ItemNode i) { any(PathExt path).isCratePath(_, i) }
private predicate hasChild(ItemNode parent, ItemNode child) { child.getImmediateParent() = parent } private predicate hasChild(ItemNode parent, ItemNode child) { child.getImmediateParent() = parent }
@@ -1631,7 +1672,7 @@ private predicate sourceFileHasCratePathTc(ItemNode i1, ItemNode i2) =
* `name` may be looked up inside `ancestor`. * `name` may be looked up inside `ancestor`.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate keywordLookup(ItemNode ancestor, string name, RelevantPath p) { private predicate keywordLookup(ItemNode ancestor, string name, PathExt p) {
// For `crate`, jump directly to the root module // For `crate`, jump directly to the root module
exists(ItemNode i | p.isCratePath(name, i) | exists(ItemNode i | p.isCratePath(name, i) |
ancestor instanceof SourceFile and ancestor instanceof SourceFile and
@@ -1645,7 +1686,7 @@ private predicate keywordLookup(ItemNode ancestor, string name, RelevantPath p)
} }
pragma[nomagic] pragma[nomagic]
private ItemNode unqualifiedPathLookup(RelevantPath p, Namespace ns, SuccessorKind kind) { private ItemNode unqualifiedPathLookup(PathExt p, Namespace ns, SuccessorKind kind) {
exists(ItemNode ancestor, string name | exists(ItemNode ancestor, string name |
result = getASuccessor(ancestor, pragma[only_bind_into](name), ns, kind, _) and result = getASuccessor(ancestor, pragma[only_bind_into](name), ns, kind, _) and
kind.isInternalOrBoth() kind.isInternalOrBoth()
@@ -1660,7 +1701,7 @@ private ItemNode unqualifiedPathLookup(RelevantPath p, Namespace ns, SuccessorKi
} }
pragma[nomagic] pragma[nomagic]
private predicate isUnqualifiedSelfPath(RelevantPath path) { path.isUnqualified("Self") } private predicate isUnqualifiedSelfPath(PathExt path) { path.isUnqualified("Self") }
/** Provides the input to `TraitIsVisible`. */ /** Provides the input to `TraitIsVisible`. */
signature predicate relevantTraitVisibleSig(Element element, Trait trait); signature predicate relevantTraitVisibleSig(Element element, Trait trait);
@@ -1743,14 +1784,14 @@ private module DollarCrateResolution {
isDollarCrateSupportedMacroExpansion(_, expansion) isDollarCrateSupportedMacroExpansion(_, expansion)
} }
private predicate isDollarCratePath(RelevantPath p) { p.isDollarCrate() } private predicate isDollarCratePath(PathExt p) { p.isDollarCrate() }
private predicate isInDollarCrateMacroExpansion(RelevantPath p, AstNode expansion) = private predicate isInDollarCrateMacroExpansion(PathExt p, AstNode expansion) =
doublyBoundedFastTC(hasParent/2, isDollarCratePath/1, isDollarCrateSupportedMacroExpansion/1)(p, doublyBoundedFastTC(hasParent/2, isDollarCratePath/1, isDollarCrateSupportedMacroExpansion/1)(p,
expansion) expansion)
pragma[nomagic] pragma[nomagic]
private predicate isInDollarCrateMacroExpansionFromFile(File macroDefFile, RelevantPath p) { private predicate isInDollarCrateMacroExpansionFromFile(File macroDefFile, PathExt p) {
exists(Path macroDefPath, AstNode expansion | exists(Path macroDefPath, AstNode expansion |
isDollarCrateSupportedMacroExpansion(macroDefPath, expansion) and isDollarCrateSupportedMacroExpansion(macroDefPath, expansion) and
isInDollarCrateMacroExpansion(p, expansion) and isInDollarCrateMacroExpansion(p, expansion) and
@@ -1765,17 +1806,17 @@ private module DollarCrateResolution {
* calls. * calls.
*/ */
pragma[nomagic] pragma[nomagic]
predicate resolveDollarCrate(RelevantPath p, CrateItemNode crate) { predicate resolveDollarCrate(PathExt p, CrateItemNode crate) {
isInDollarCrateMacroExpansionFromFile(crate.getASourceFile().getFile(), p) isInDollarCrateMacroExpansionFromFile(crate.getASourceFile().getFile(), p)
} }
} }
pragma[nomagic] pragma[nomagic]
private ItemNode resolvePathCand0(RelevantPath path, Namespace ns) { private ItemNode resolvePathCand0(PathExt path, Namespace ns) {
exists(ItemNode res | exists(ItemNode res |
res = unqualifiedPathLookup(path, ns, _) and res = unqualifiedPathLookup(path, ns, _) and
if if
not any(RelevantPath parent).getQualifier() = path and not any(PathExt parent).getQualifier() = path and
isUnqualifiedSelfPath(path) and isUnqualifiedSelfPath(path) and
res instanceof ImplItemNode res instanceof ImplItemNode
then result = res.(ImplItemNodeImpl).resolveSelfTyCand() then result = res.(ImplItemNodeImpl).resolveSelfTyCand()
@@ -1790,13 +1831,16 @@ private ItemNode resolvePathCand0(RelevantPath path, Namespace ns) {
result = resolveUseTreeListItem(_, _, path, _) and result = resolveUseTreeListItem(_, _, path, _) and
ns = result.getNamespace() ns = result.getNamespace()
or or
result = resolveBuiltin(path.getSegment().getTypeRepr()) and exists(PathSegment seg |
not path.getSegment().hasTraitTypeRepr() and seg = path.(Path).getSegment() and
ns.isType() result = resolveBuiltin(seg.getTypeRepr()) and
not seg.hasTraitTypeRepr() and
ns.isType()
)
} }
pragma[nomagic] pragma[nomagic]
private ItemNode resolvePathCandQualifier(RelevantPath qualifier, RelevantPath path, string name) { private ItemNode resolvePathCandQualifier(PathExt qualifier, PathExt path, string name) {
qualifier = path.getQualifier() and qualifier = path.getQualifier() and
result = resolvePathCand(qualifier) and result = resolvePathCand(qualifier) and
name = path.getText() name = path.getText()
@@ -1844,9 +1888,7 @@ private predicate checkQualifiedVisibility(
* qualifier of `path` and `qualifier` resolves to `q`, if any. * qualifier of `path` and `qualifier` resolves to `q`, if any.
*/ */
pragma[nomagic] pragma[nomagic]
private ItemNode resolvePathCandQualified( private ItemNode resolvePathCandQualified(PathExt qualifier, ItemNode q, PathExt path, Namespace ns) {
RelevantPath qualifier, ItemNode q, RelevantPath path, Namespace ns
) {
exists(string name, SuccessorKind kind, UseOption useOpt | exists(string name, SuccessorKind kind, UseOption useOpt |
q = resolvePathCandQualifier(qualifier, path, name) and q = resolvePathCandQualifier(qualifier, path, name) and
result = getASuccessor(q, name, ns, kind, useOpt) and result = getASuccessor(q, name, ns, kind, useOpt) and
@@ -1855,12 +1897,14 @@ private ItemNode resolvePathCandQualified(
} }
/** Holds if path `p` must be looked up in namespace `n`. */ /** Holds if path `p` must be looked up in namespace `n`. */
private predicate pathUsesNamespace(Path p, Namespace n) { private predicate pathUsesNamespace(PathExt p, Namespace n) {
n.isValue() and n.isValue() and
( (
p = any(PathExpr pe).getPath() p = any(PathExpr pe).getPath()
or or
p = any(TupleStructPat tsp).getPath() p = any(TupleStructPat tsp).getPath()
or
p instanceof PathExtIdentPat
) )
or or
n.isType() and n.isType() and
@@ -1936,7 +1980,7 @@ private predicate macroUseEdge(
* result in non-monotonic recursion. * result in non-monotonic recursion.
*/ */
pragma[nomagic] pragma[nomagic]
private ItemNode resolvePathCand(RelevantPath path) { private ItemNode resolvePathCand(PathExt path) {
exists(Namespace ns | exists(Namespace ns |
result = resolvePathCand0(path, ns) and result = resolvePathCand0(path, ns) and
if path = any(ImplItemNode i).getSelfPath() if path = any(ImplItemNode i).getSelfPath()
@@ -1949,7 +1993,13 @@ private ItemNode resolvePathCand(RelevantPath path) {
else else
if path = any(PathTypeRepr p).getPath() if path = any(PathTypeRepr p).getPath()
then result instanceof TypeItemNode then result instanceof TypeItemNode
else any() else
if path instanceof IdentPat
then
result instanceof VariantItemNode or
result instanceof StructItemNode or
result instanceof ConstItemNode
else any()
| |
pathUsesNamespace(path, ns) pathUsesNamespace(path, ns)
or or
@@ -1966,7 +2016,7 @@ private ItemNode resolvePathCand(RelevantPath path) {
} }
/** Get a trait that should be visible when `path` resolves to `node`, if any. */ /** Get a trait that should be visible when `path` resolves to `node`, if any. */
private Trait getResolvePathTraitUsed(RelevantPath path, AssocItemNode node) { private Trait getResolvePathTraitUsed(PathExt path, AssocItemNode node) {
exists(TypeItemNode type, ImplItemNodeImpl impl | exists(TypeItemNode type, ImplItemNodeImpl impl |
node = resolvePathCandQualified(_, type, path, _) and node = resolvePathCandQualified(_, type, path, _) and
typeImplEdge(type, impl, _, _, node, _) and typeImplEdge(type, impl, _, _, node, _) and
@@ -1978,9 +2028,9 @@ private predicate pathTraitUsed(Element path, Trait trait) {
trait = getResolvePathTraitUsed(path, _) trait = getResolvePathTraitUsed(path, _)
} }
/** Gets the item that `path` resolves to, if any. */ /** INTERNAL: Do not use; use `resolvePath` instead. */
cached cached
ItemNode resolvePath(RelevantPath path) { ItemNode resolvePathIgnoreVariableShadowing(PathExt path) {
result = resolvePathCand(path) and result = resolvePathCand(path) and
not path = any(Path parent | exists(resolvePathCand(parent))).getQualifier() and not path = any(Path parent | exists(resolvePathCand(parent))).getQualifier() and
( (
@@ -1993,29 +2043,43 @@ ItemNode resolvePath(RelevantPath path) {
or or
// if `path` is the qualifier of a resolvable `parent`, then we should // if `path` is the qualifier of a resolvable `parent`, then we should
// resolve `path` to something consistent with what `parent` resolves to // resolve `path` to something consistent with what `parent` resolves to
exists(RelevantPath parent | exists(PathExt parent |
resolvePathCandQualified(path, result, parent, _) = resolvePath(parent) resolvePathCandQualified(path, result, parent, _) = resolvePathIgnoreVariableShadowing(parent)
) )
} }
private predicate isUseTreeSubPath(UseTree tree, RelevantPath path) { /**
* Holds if `ip` resolves to some constructor or constant.
*/
// use `forceLocal` once we implement overlay support
pragma[nomagic]
predicate identPatIsResolvable(IdentPat ip) { exists(resolvePathIgnoreVariableShadowing(ip)) }
/** Gets the item that `path` resolves to, if any. */
pragma[nomagic]
ItemNode resolvePath(PathExt path) {
result = resolvePathIgnoreVariableShadowing(path) and
not path = any(VariableAccess va).(PathExpr).getPath()
}
private predicate isUseTreeSubPath(UseTree tree, PathExt path) {
path = tree.getPath() path = tree.getPath()
or or
exists(RelevantPath mid | exists(PathExt mid |
isUseTreeSubPath(tree, mid) and isUseTreeSubPath(tree, mid) and
path = mid.getQualifier() path = mid.getQualifier()
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate isUseTreeSubPathUnqualified(UseTree tree, RelevantPath path, string name) { private predicate isUseTreeSubPathUnqualified(UseTree tree, PathExt path, string name) {
isUseTreeSubPath(tree, path) and isUseTreeSubPath(tree, path) and
not exists(path.getQualifier()) and not exists(path.getQualifier()) and
name = path.getText() name = path.getText()
} }
pragma[nomagic] pragma[nomagic]
private ItemNode resolveUseTreeListItem(Use use, UseTree tree, RelevantPath path, SuccessorKind kind) { private ItemNode resolveUseTreeListItem(Use use, UseTree tree, PathExt path, SuccessorKind kind) {
exists(UseOption useOpt | checkQualifiedVisibility(use, result, kind, useOpt) | exists(UseOption useOpt | checkQualifiedVisibility(use, result, kind, useOpt) |
exists(UseTree midTree, ItemNode mid, string name | exists(UseTree midTree, ItemNode mid, string name |
mid = resolveUseTreeListItem(use, midTree) and mid = resolveUseTreeListItem(use, midTree) and
@@ -2032,9 +2096,7 @@ private ItemNode resolveUseTreeListItem(Use use, UseTree tree, RelevantPath path
} }
pragma[nomagic] pragma[nomagic]
private ItemNode resolveUseTreeListItemQualifier( private ItemNode resolveUseTreeListItemQualifier(Use use, UseTree tree, PathExt path, string name) {
Use use, UseTree tree, RelevantPath path, string name
) {
result = resolveUseTreeListItem(use, tree, path.getQualifier(), _) and result = resolveUseTreeListItem(use, tree, path.getQualifier(), _) and
name = path.getText() name = path.getText()
} }
@@ -2189,7 +2251,7 @@ private module Debug {
} }
predicate debugUnqualifiedPathLookup( predicate debugUnqualifiedPathLookup(
RelevantPath p, string name, Namespace ns, ItemNode ancestor, string path PathExt p, string name, Namespace ns, ItemNode ancestor, string path
) { ) {
p = getRelevantLocatable() and p = getRelevantLocatable() and
exists(ItemNode encl | exists(ItemNode encl |
@@ -2199,14 +2261,19 @@ private module Debug {
path = p.toStringDebug() path = p.toStringDebug()
} }
ItemNode debugUnqualifiedPathLookup(PathExt p, Namespace ns, SuccessorKind kind) {
p = getRelevantLocatable() and
result = unqualifiedPathLookup(p, ns, kind)
}
predicate debugItemNode(ItemNode item) { item = getRelevantLocatable() } predicate debugItemNode(ItemNode item) { item = getRelevantLocatable() }
ItemNode debugResolvePath(RelevantPath path) { ItemNode debugResolvePath(PathExt path) {
path = getRelevantLocatable() and path = getRelevantLocatable() and
result = resolvePath(path) result = resolvePath(path)
} }
ItemNode debugResolveUseTreeListItem(Use use, UseTree tree, RelevantPath path, SuccessorKind kind) { ItemNode debugResolveUseTreeListItem(Use use, UseTree tree, PathExt path, SuccessorKind kind) {
use = getRelevantLocatable() and use = getRelevantLocatable() and
result = resolveUseTreeListItem(use, tree, path, kind) result = resolveUseTreeListItem(use, tree, path, kind)
} }

View File

@@ -352,7 +352,7 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
| |
rnk = 0 rnk = 0
or or
argsAreInstantiationsOfFromIndex(call, abs, f, rnk - 1) argsAreInstantiationsOfToIndex(call, abs, f, rnk - 1)
) )
} }
@@ -361,15 +361,15 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
} }
} }
private module ArgIsInstantiationOfFromIndex = private module ArgIsInstantiationOfToIndex =
ArgIsInstantiationOf<CallAndPos, ArgIsInstantiationOfInput>; ArgIsInstantiationOf<CallAndPos, ArgIsInstantiationOfInput>;
pragma[nomagic] pragma[nomagic]
private predicate argsAreInstantiationsOfFromIndex( private predicate argsAreInstantiationsOfToIndex(
Input::Call call, ImplOrTraitItemNode i, Function f, int rnk Input::Call call, ImplOrTraitItemNode i, Function f, int rnk
) { ) {
exists(FunctionPosition pos | exists(FunctionPosition pos |
ArgIsInstantiationOfFromIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and ArgIsInstantiationOfToIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and
call.hasTargetCand(i, f) and call.hasTargetCand(i, f) and
toCheckRanked(i, f, pos, rnk) toCheckRanked(i, f, pos, rnk)
) )
@@ -382,7 +382,7 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
pragma[nomagic] pragma[nomagic]
predicate argsAreInstantiationsOf(Input::Call call, ImplOrTraitItemNode i, Function f) { predicate argsAreInstantiationsOf(Input::Call call, ImplOrTraitItemNode i, Function f) {
exists(int rnk | exists(int rnk |
argsAreInstantiationsOfFromIndex(call, i, f, rnk) and argsAreInstantiationsOfToIndex(call, i, f, rnk) and
rnk = max(int r | toCheckRanked(i, f, _, r)) rnk = max(int r | toCheckRanked(i, f, _, r))
) )
} }

View File

@@ -9,6 +9,7 @@ private import codeql.rust.dataflow.FlowSource
private import codeql.rust.dataflow.FlowSink private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts private import codeql.rust.Concepts
private import codeql.rust.dataflow.internal.Node private import codeql.rust.dataflow.internal.Node
private import codeql.rust.security.Barriers as Barriers
/** /**
* Provides default sources, sinks and barriers for detecting accesses to * Provides default sources, sinks and barriers for detecting accesses to
@@ -59,4 +60,10 @@ module AccessInvalidPointer {
private class ModelsAsDataSink extends Sink { private class ModelsAsDataSink extends Sink {
ModelsAsDataSink() { sinkNode(this, "pointer-access") } ModelsAsDataSink() { sinkNode(this, "pointer-access") }
} }
/**
* A barrier for invalid pointer access vulnerabilities for values checked to
* be non-`null`.
*/
private class NotNullCheckBarrier extends Barrier instanceof Barriers::NotNullCheckBarrier { }
} }

View File

@@ -7,6 +7,8 @@ import rust
private import codeql.rust.dataflow.DataFlow private import codeql.rust.dataflow.DataFlow
private import codeql.rust.internal.TypeInference as TypeInference private import codeql.rust.internal.TypeInference as TypeInference
private import codeql.rust.internal.Type private import codeql.rust.internal.Type
private import codeql.rust.controlflow.ControlFlowGraph as Cfg
private import codeql.rust.controlflow.CfgNodes as CfgNodes
private import codeql.rust.frameworks.stdlib.Builtins as Builtins private import codeql.rust.frameworks.stdlib.Builtins as Builtins
/** /**
@@ -40,3 +42,25 @@ class IntegralOrBooleanTypeBarrier extends DataFlow::Node {
) )
} }
} }
/**
* Holds if guard expression `g` having result `branch` indicates that the
* sub-expression `e` is not null. For example when `ptr.is_null()` is
* `false`, we have that `ptr` is not null.
*/
private predicate notNullCheck(AstNode g, Expr e, boolean branch) {
exists(MethodCallExpr call |
call.getStaticTarget().getName().getText() = "is_null" and
g = call and
e = call.getReceiver() and
branch = false
)
}
/**
* A node representing a value checked to be non-null. This may be an
* appropriate taint flow barrier for some queries.
*/
class NotNullCheckBarrier extends DataFlow::Node {
NotNullCheckBarrier() { this = DataFlow::BarrierGuard<notNullCheck/3>::getABarrierNode() }
}

View File

@@ -0,0 +1,45 @@
/**
* Provides classes and predicates for reasoning about disabled certificate
* check vulnerabilities.
*/
import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts
private import codeql.rust.dataflow.internal.Node as Node
/**
* Provides default sinks for detecting disabled certificate check
* vulnerabilities, as well as extension points for adding your own.
*/
module DisabledCertificateCheckExtensions {
/**
* A data flow sink for disabled certificate check vulnerabilities.
*/
abstract class Sink extends QuerySink::Range {
override string getSinkType() { result = "DisabledCertificateCheck" }
}
/**
* A sink for disabled certificate check vulnerabilities from model data.
*/
private class ModelsAsDataSink extends Sink {
ModelsAsDataSink() { sinkNode(this, "disable-certificate") }
}
/**
* A heuristic sink for disabled certificate check vulnerabilities based on function names.
*/
private class HeuristicSink extends Sink {
HeuristicSink() {
exists(CallExprBase fc |
fc.getStaticTarget().(Function).getName().getText() =
["danger_accept_invalid_certs", "danger_accept_invalid_hostnames"] and
fc.getArg(0) = this.asExpr() and
// don't duplicate modeled sinks
not exists(ModelsAsDataSink s | s.(Node::FlowSummaryNode).getSinkElement().getCall() = fc)
)
}
}
}

View File

@@ -0,0 +1,4 @@
---
category: newQuery
---
* Added a new query `rust/disabled-certificate-check`, to detect disabled TLS certificate checks.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `rust/access-invalid-pointer` query has been improved with new flow sources and barriers.

View File

@@ -0,0 +1,42 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
The <code>danger_accept_invalid_certs</code> option on TLS connectors and HTTP clients controls whether certificate verification is performed. If this option is set to <code>true</code>, the client will accept any certificate, making it susceptible to man-in-the-middle attacks.
</p>
<p>
Similarly, the <code>danger_accept_invalid_hostnames</code> option controls whether hostname verification is performed. If this option is set to <code>true</code>, the client will accept any valid certificate regardless of the site that certificate is for, again making it susceptible to man-in-the-middle attacks.
</p>
</overview>
<recommendation>
<p>
Do not set <code>danger_accept_invalid_certs</code> or <code>danger_accept_invalid_hostnames</code> to <code>true</code>, except in controlled environments such as tests. In production, always ensure certificate and hostname verification is enabled to prevent security risks.
</p>
</recommendation>
<example>
<p>
The following code snippet shows a function that creates an HTTP client with certificate verification disabled:
</p>
<sample src="DisabledCertificateCheckBad.rs"/>
<p>
In production code, always configure clients to verify certificates:
</p>
<sample src="DisabledCertificateCheckGood.rs"/>
</example>
<references>
<li>
Rust native-tls crate: <a href="https://docs.rs/native-tls/latest/native_tls/struct.TlsConnectorBuilder.html">TlsConnectorBuilder</a>.
</li>
<li>
Rust reqwest crate: <a href="https://docs.rs/reqwest/latest/reqwest/struct.ClientBuilder.html">ClientBuilder</a>.
</li>
<li>
SSL.com: <a href="https://www.ssl.com/article/browsers-and-certificate-validation/">Browsers and Certificate Validation</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,47 @@
/**
* @name Disabled TLS certificate check
* @description An application that disables TLS certificate checking is more vulnerable to
* man-in-the-middle attacks.
* @kind path-problem
* @problem.severity warning
* @security-severity 7.5
* @precision high
* @id rust/disabled-certificate-check
* @tags security
* external/cwe/cwe-295
*/
import rust
import codeql.rust.dataflow.DataFlow
import codeql.rust.dataflow.TaintTracking
import codeql.rust.security.DisabledCertificateCheckExtensions
import codeql.rust.Concepts
/**
* A taint configuration for disabled TLS certificate checks.
*/
module DisabledCertificateCheckConfig implements DataFlow::ConfigSig {
import DisabledCertificateCheckExtensions
predicate isSource(DataFlow::Node node) {
// the constant `true`
node.asExpr().(BooleanLiteralExpr).getTextValue() = "true"
or
// a value controlled by a potential attacker
node instanceof ActiveThreatModelSource
}
predicate isSink(DataFlow::Node node) { node instanceof Sink }
predicate observeDiffInformedIncrementalMode() { any() }
}
module DisabledCertificateCheckFlow = TaintTracking::Global<DisabledCertificateCheckConfig>;
import DisabledCertificateCheckFlow::PathGraph
from
DisabledCertificateCheckFlow::PathNode sourceNode, DisabledCertificateCheckFlow::PathNode sinkNode
where DisabledCertificateCheckFlow::flowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode,
"Disabling TLS certificate validation can expose the application to man-in-the-middle attacks."

View File

@@ -0,0 +1,6 @@
// BAD: Disabling certificate validation in Rust
let _client = reqwest::Client::builder()
.danger_accept_invalid_certs(true) // disables certificate validation
.build()
.unwrap();

View File

@@ -0,0 +1,10 @@
// GOOD: Certificate validation is enabled (default)
let _client = reqwest::Client::builder()
.danger_accept_invalid_certs(false) // certificate validation enabled explicitly
.build()
.unwrap();
let _client = native_tls::TlsConnector::builder() // certificate validation enabled by default
.build()
.unwrap();

View File

@@ -22,11 +22,13 @@ import AccessInvalidPointerFlow::PathGraph
* A data flow configuration for accesses to invalid pointers. * A data flow configuration for accesses to invalid pointers.
*/ */
module AccessInvalidPointerConfig implements DataFlow::ConfigSig { module AccessInvalidPointerConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node instanceof AccessInvalidPointer::Source } import AccessInvalidPointer
predicate isSink(DataFlow::Node node) { node instanceof AccessInvalidPointer::Sink } predicate isSource(DataFlow::Node node) { node instanceof Source }
predicate isBarrier(DataFlow::Node barrier) { barrier instanceof AccessInvalidPointer::Barrier } predicate isSink(DataFlow::Node node) { node instanceof Sink }
predicate isBarrier(DataFlow::Node barrier) { barrier instanceof Barrier }
predicate isBarrierOut(DataFlow::Node node) { predicate isBarrierOut(DataFlow::Node node) {
// make sinks barriers so that we only report the closest instance // make sinks barriers so that we only report the closest instance

View File

@@ -22,6 +22,7 @@ private import codeql.rust.security.AccessInvalidPointerExtensions
private import codeql.rust.security.CleartextLoggingExtensions private import codeql.rust.security.CleartextLoggingExtensions
private import codeql.rust.security.CleartextStorageDatabaseExtensions private import codeql.rust.security.CleartextStorageDatabaseExtensions
private import codeql.rust.security.CleartextTransmissionExtensions private import codeql.rust.security.CleartextTransmissionExtensions
private import codeql.rust.security.DisabledCertificateCheckExtensions
private import codeql.rust.security.HardcodedCryptographicValueExtensions private import codeql.rust.security.HardcodedCryptographicValueExtensions
private import codeql.rust.security.InsecureCookieExtensions private import codeql.rust.security.InsecureCookieExtensions
private import codeql.rust.security.LogInjectionExtensions private import codeql.rust.security.LogInjectionExtensions

View File

@@ -660,7 +660,7 @@ macro_expansion.rs:
# 71| getSegment(): [PathSegment] i32 # 71| getSegment(): [PathSegment] i32
# 71| getIdentifier(): [NameRef] i32 # 71| getIdentifier(): [NameRef] i32
# 72| getTailExpr(): [CastExpr] a as ... # 72| getTailExpr(): [CastExpr] a as ...
# 72| getExpr(): [PathExpr,VariableAccess] a # 72| getExpr(): [VariableAccess] a
# 72| getPath(): [Path] a # 72| getPath(): [Path] a
# 72| getSegment(): [PathSegment] a # 72| getSegment(): [PathSegment] a
# 72| getIdentifier(): [NameRef] a # 72| getIdentifier(): [NameRef] a
@@ -738,7 +738,7 @@ macro_expansion.rs:
# 84| getFunctionBody(): [BlockExpr] { ... } # 84| getFunctionBody(): [BlockExpr] { ... }
# 84| getStmtList(): [StmtList] StmtList # 84| getStmtList(): [StmtList] StmtList
# 84| getTailExpr(): [MatchExpr] match self { ... } # 84| getTailExpr(): [MatchExpr] match self { ... }
# 83| getScrutinee(): [PathExpr,VariableAccess] self # 83| getScrutinee(): [VariableAccess] self
# 83| getPath(): [Path] self # 83| getPath(): [Path] self
# 83| getSegment(): [PathSegment] self # 83| getSegment(): [PathSegment] self
# 83| getIdentifier(): [NameRef] self # 83| getIdentifier(): [NameRef] self
@@ -751,7 +751,7 @@ macro_expansion.rs:
# 85| getArgList(): [ArgList] ArgList # 85| getArgList(): [ArgList] ArgList
# 83| getArg(0): [StringLiteralExpr] "field" # 83| getArg(0): [StringLiteralExpr] "field"
# 85| getArg(1): [RefExpr] &field # 85| getArg(1): [RefExpr] &field
# 85| getExpr(): [PathExpr,VariableAccess] field # 85| getExpr(): [VariableAccess] field
# 85| getPath(): [Path] field # 85| getPath(): [Path] field
# 85| getSegment(): [PathSegment] field # 85| getSegment(): [PathSegment] field
# 85| getIdentifier(): [NameRef] field # 85| getIdentifier(): [NameRef] field
@@ -760,7 +760,7 @@ macro_expansion.rs:
# 83| getArgList(): [ArgList] ArgList # 83| getArgList(): [ArgList] ArgList
# 83| getArg(0): [StringLiteralExpr] "MyDerive" # 83| getArg(0): [StringLiteralExpr] "MyDerive"
# 83| getIdentifier(): [NameRef] debug_struct # 83| getIdentifier(): [NameRef] debug_struct
# 83| getReceiver(): [PathExpr,VariableAccess] f # 83| getReceiver(): [VariableAccess] f
# 83| getPath(): [Path] f # 83| getPath(): [Path] f
# 83| getSegment(): [PathSegment] f # 83| getSegment(): [PathSegment] f
# 83| getIdentifier(): [NameRef] f # 83| getIdentifier(): [NameRef] f
@@ -836,11 +836,11 @@ macro_expansion.rs:
# 89| getStmtList(): [StmtList] StmtList # 89| getStmtList(): [StmtList] StmtList
# 89| getTailExpr(): [MatchExpr] match ... { ... } # 89| getTailExpr(): [MatchExpr] match ... { ... }
# 88| getScrutinee(): [TupleExpr] TupleExpr # 88| getScrutinee(): [TupleExpr] TupleExpr
# 88| getField(0): [PathExpr,VariableAccess] self # 88| getField(0): [VariableAccess] self
# 88| getPath(): [Path] self # 88| getPath(): [Path] self
# 88| getSegment(): [PathSegment] self # 88| getSegment(): [PathSegment] self
# 88| getIdentifier(): [NameRef] self # 88| getIdentifier(): [NameRef] self
# 88| getField(1): [PathExpr,VariableAccess] other # 88| getField(1): [VariableAccess] other
# 88| getPath(): [Path] other # 88| getPath(): [Path] other
# 88| getSegment(): [PathSegment] other # 88| getSegment(): [PathSegment] other
# 88| getIdentifier(): [NameRef] other # 88| getIdentifier(): [NameRef] other
@@ -1076,7 +1076,7 @@ proc_macro.rs:
# 6| getMacroCallExpansion(): [MatchExpr] match ... { ... } # 6| getMacroCallExpansion(): [MatchExpr] match ... { ... }
# 6| getScrutinee(): [CallExpr] ...::parse::<...>(...) # 6| getScrutinee(): [CallExpr] ...::parse::<...>(...)
# 6| getArgList(): [ArgList] ArgList # 6| getArgList(): [ArgList] ArgList
# 6| getArg(0): [PathExpr,VariableAccess] attr # 6| getArg(0): [VariableAccess] attr
# 6| getPath(): [Path] attr # 6| getPath(): [Path] attr
# 6| getSegment(): [PathSegment] attr # 6| getSegment(): [PathSegment] attr
# 6| getIdentifier(): [NameRef] attr # 6| getIdentifier(): [NameRef] attr
@@ -1098,7 +1098,7 @@ proc_macro.rs:
# 6| getIdentifier(): [NameRef] parse # 6| getIdentifier(): [NameRef] parse
# 6| getMatchArmList(): [MatchArmList] MatchArmList # 6| getMatchArmList(): [MatchArmList] MatchArmList
# 6| getArm(0): [MatchArm] ... => data # 6| getArm(0): [MatchArm] ... => data
# 6| getExpr(): [PathExpr,VariableAccess] data # 6| getExpr(): [VariableAccess] data
# 6| getPath(): [Path] data # 6| getPath(): [Path] data
# 6| getSegment(): [PathSegment] data # 6| getSegment(): [PathSegment] data
# 6| getIdentifier(): [NameRef] data # 6| getIdentifier(): [NameRef] data
@@ -1124,7 +1124,7 @@ proc_macro.rs:
# 6| getArg(0): [MethodCallExpr] err.to_compile_error() # 6| getArg(0): [MethodCallExpr] err.to_compile_error()
# 6| getArgList(): [ArgList] ArgList # 6| getArgList(): [ArgList] ArgList
# 6| getIdentifier(): [NameRef] to_compile_error # 6| getIdentifier(): [NameRef] to_compile_error
# 6| getReceiver(): [PathExpr,VariableAccess] err # 6| getReceiver(): [VariableAccess] err
# 6| getPath(): [Path] err # 6| getPath(): [Path] err
# 6| getSegment(): [PathSegment] err # 6| getSegment(): [PathSegment] err
# 6| getIdentifier(): [NameRef] err # 6| getIdentifier(): [NameRef] err
@@ -1168,7 +1168,7 @@ proc_macro.rs:
# 7| getMacroCallExpansion(): [MatchExpr] match ... { ... } # 7| getMacroCallExpansion(): [MatchExpr] match ... { ... }
# 7| getScrutinee(): [CallExpr] ...::parse::<...>(...) # 7| getScrutinee(): [CallExpr] ...::parse::<...>(...)
# 7| getArgList(): [ArgList] ArgList # 7| getArgList(): [ArgList] ArgList
# 7| getArg(0): [PathExpr,VariableAccess] item # 7| getArg(0): [VariableAccess] item
# 7| getPath(): [Path] item # 7| getPath(): [Path] item
# 7| getSegment(): [PathSegment] item # 7| getSegment(): [PathSegment] item
# 7| getIdentifier(): [NameRef] item # 7| getIdentifier(): [NameRef] item
@@ -1190,7 +1190,7 @@ proc_macro.rs:
# 7| getIdentifier(): [NameRef] parse # 7| getIdentifier(): [NameRef] parse
# 7| getMatchArmList(): [MatchArmList] MatchArmList # 7| getMatchArmList(): [MatchArmList] MatchArmList
# 7| getArm(0): [MatchArm] ... => data # 7| getArm(0): [MatchArm] ... => data
# 7| getExpr(): [PathExpr,VariableAccess] data # 7| getExpr(): [VariableAccess] data
# 7| getPath(): [Path] data # 7| getPath(): [Path] data
# 7| getSegment(): [PathSegment] data # 7| getSegment(): [PathSegment] data
# 7| getIdentifier(): [NameRef] data # 7| getIdentifier(): [NameRef] data
@@ -1216,7 +1216,7 @@ proc_macro.rs:
# 7| getArg(0): [MethodCallExpr] err.to_compile_error() # 7| getArg(0): [MethodCallExpr] err.to_compile_error()
# 7| getArgList(): [ArgList] ArgList # 7| getArgList(): [ArgList] ArgList
# 7| getIdentifier(): [NameRef] to_compile_error # 7| getIdentifier(): [NameRef] to_compile_error
# 7| getReceiver(): [PathExpr,VariableAccess] err # 7| getReceiver(): [VariableAccess] err
# 7| getPath(): [Path] err # 7| getPath(): [Path] err
# 7| getSegment(): [PathSegment] err # 7| getSegment(): [PathSegment] err
# 7| getIdentifier(): [NameRef] err # 7| getIdentifier(): [NameRef] err
@@ -1273,7 +1273,7 @@ proc_macro.rs:
# 10| getInitializer(): [MethodCallExpr] ast.clone() # 10| getInitializer(): [MethodCallExpr] ast.clone()
# 10| getArgList(): [ArgList] ArgList # 10| getArgList(): [ArgList] ArgList
# 10| getIdentifier(): [NameRef] clone # 10| getIdentifier(): [NameRef] clone
# 10| getReceiver(): [PathExpr,VariableAccess] ast # 10| getReceiver(): [VariableAccess] ast
# 10| getPath(): [Path] ast # 10| getPath(): [Path] ast
# 10| getSegment(): [PathSegment] ast # 10| getSegment(): [PathSegment] ast
# 10| getIdentifier(): [NameRef] ast # 10| getIdentifier(): [NameRef] ast
@@ -1283,7 +1283,7 @@ proc_macro.rs:
# 11| getExpr(): [AssignmentExpr] ... = ... # 11| getExpr(): [AssignmentExpr] ... = ...
# 11| getLhs(): [FieldExpr] ... .ident # 11| getLhs(): [FieldExpr] ... .ident
# 11| getContainer(): [FieldExpr] new_ast.sig # 11| getContainer(): [FieldExpr] new_ast.sig
# 11| getContainer(): [PathExpr,VariableAccess] new_ast # 11| getContainer(): [VariableAccess] new_ast
# 11| getPath(): [Path] new_ast # 11| getPath(): [Path] new_ast
# 11| getSegment(): [PathSegment] new_ast # 11| getSegment(): [PathSegment] new_ast
# 11| getIdentifier(): [NameRef] new_ast # 11| getIdentifier(): [NameRef] new_ast
@@ -1320,14 +1320,14 @@ proc_macro.rs:
# 11| getArg(0): [FormatArgsArg] FormatArgsArg # 11| getArg(0): [FormatArgsArg] FormatArgsArg
# 11| getExpr(): [FieldExpr] ... .ident # 11| getExpr(): [FieldExpr] ... .ident
# 11| getContainer(): [FieldExpr] ast.sig # 11| getContainer(): [FieldExpr] ast.sig
# 11| getContainer(): [PathExpr,VariableAccess] ast # 11| getContainer(): [VariableAccess] ast
# 11| getPath(): [Path] ast # 11| getPath(): [Path] ast
# 11| getSegment(): [PathSegment] ast # 11| getSegment(): [PathSegment] ast
# 11| getIdentifier(): [NameRef] ast # 11| getIdentifier(): [NameRef] ast
# 11| getIdentifier(): [NameRef] sig # 11| getIdentifier(): [NameRef] sig
# 11| getIdentifier(): [NameRef] ident # 11| getIdentifier(): [NameRef] ident
# 11| getArg(1): [FormatArgsArg] FormatArgsArg # 11| getArg(1): [FormatArgsArg] FormatArgsArg
# 11| getExpr(): [PathExpr,VariableAccess] i # 11| getExpr(): [VariableAccess] i
# 11| getPath(): [Path] i # 11| getPath(): [Path] i
# 11| getSegment(): [PathSegment] i # 11| getSegment(): [PathSegment] i
# 11| getIdentifier(): [NameRef] i # 11| getIdentifier(): [NameRef] i
@@ -1359,7 +1359,7 @@ proc_macro.rs:
# 11| getIdentifier(): [NameRef] span # 11| getIdentifier(): [NameRef] span
# 11| getReceiver(): [FieldExpr] ... .ident # 11| getReceiver(): [FieldExpr] ... .ident
# 11| getContainer(): [FieldExpr] ast.sig # 11| getContainer(): [FieldExpr] ast.sig
# 11| getContainer(): [PathExpr,VariableAccess] ast # 11| getContainer(): [VariableAccess] ast
# 11| getPath(): [Path] ast # 11| getPath(): [Path] ast
# 11| getSegment(): [PathSegment] ast # 11| getSegment(): [PathSegment] ast
# 11| getIdentifier(): [NameRef] ast # 11| getIdentifier(): [NameRef] ast
@@ -1375,14 +1375,14 @@ proc_macro.rs:
# 11| getIdentifier(): [NameRef] Ident # 11| getIdentifier(): [NameRef] Ident
# 11| getSegment(): [PathSegment] new # 11| getSegment(): [PathSegment] new
# 11| getIdentifier(): [NameRef] new # 11| getIdentifier(): [NameRef] new
# 12| getTailExpr(): [PathExpr,VariableAccess] new_ast # 12| getTailExpr(): [VariableAccess] new_ast
# 12| getPath(): [Path] new_ast # 12| getPath(): [Path] new_ast
# 12| getSegment(): [PathSegment] new_ast # 12| getSegment(): [PathSegment] new_ast
# 12| getIdentifier(): [NameRef] new_ast # 12| getIdentifier(): [NameRef] new_ast
# 9| getIdentifier(): [NameRef] map # 9| getIdentifier(): [NameRef] map
# 8| getReceiver(): [ParenExpr] (...) # 8| getReceiver(): [ParenExpr] (...)
# 8| getExpr(): [RangeExpr] 0..number # 8| getExpr(): [RangeExpr] 0..number
# 8| getEnd(): [PathExpr,VariableAccess] number # 8| getEnd(): [VariableAccess] number
# 8| getPath(): [Path] number # 8| getPath(): [Path] number
# 8| getSegment(): [PathSegment] number # 8| getSegment(): [PathSegment] number
# 8| getIdentifier(): [NameRef] number # 8| getIdentifier(): [NameRef] number
@@ -1614,7 +1614,7 @@ proc_macro.rs:
# 16| getInitializer(): [MethodCallExpr] items.quote_into_iter() # 16| getInitializer(): [MethodCallExpr] items.quote_into_iter()
# 15| getArgList(): [ArgList] ArgList # 15| getArgList(): [ArgList] ArgList
# 15| getIdentifier(): [NameRef] quote_into_iter # 15| getIdentifier(): [NameRef] quote_into_iter
# 16| getReceiver(): [PathExpr,VariableAccess] items # 16| getReceiver(): [VariableAccess] items
# 16| getPath(): [Path] items # 16| getPath(): [Path] items
# 16| getSegment(): [PathSegment] items # 16| getSegment(): [PathSegment] items
# 16| getIdentifier(): [NameRef] items # 16| getIdentifier(): [NameRef] items
@@ -1625,11 +1625,11 @@ proc_macro.rs:
# 15| getName(): [Name] i # 15| getName(): [Name] i
# 15| getStatement(1): [LetStmt] let ... = ... # 15| getStatement(1): [LetStmt] let ... = ...
# 15| getInitializer(): [BinaryExpr] ... | ... # 15| getInitializer(): [BinaryExpr] ... | ...
# 15| getLhs(): [PathExpr,VariableAccess] has_iter # 15| getLhs(): [VariableAccess] has_iter
# 15| getPath(): [Path] has_iter # 15| getPath(): [Path] has_iter
# 15| getSegment(): [PathSegment] has_iter # 15| getSegment(): [PathSegment] has_iter
# 15| getIdentifier(): [NameRef] has_iter # 15| getIdentifier(): [NameRef] has_iter
# 15| getRhs(): [PathExpr,VariableAccess] i # 15| getRhs(): [VariableAccess] i
# 15| getPath(): [Path] i # 15| getPath(): [Path] i
# 15| getSegment(): [PathSegment] i # 15| getSegment(): [PathSegment] i
# 15| getIdentifier(): [NameRef] i # 15| getIdentifier(): [NameRef] i
@@ -1646,7 +1646,7 @@ proc_macro.rs:
# 16| getTokenTree(): [TokenTree] TokenTree # 16| getTokenTree(): [TokenTree] TokenTree
# 15| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr # 15| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
# 15| getStatement(3): [LetStmt] let _ = has_iter # 15| getStatement(3): [LetStmt] let _ = has_iter
# 15| getInitializer(): [PathExpr,VariableAccess] has_iter # 15| getInitializer(): [VariableAccess] has_iter
# 15| getPath(): [Path] has_iter # 15| getPath(): [Path] has_iter
# 15| getSegment(): [PathSegment] has_iter # 15| getSegment(): [PathSegment] has_iter
# 15| getIdentifier(): [NameRef] has_iter # 15| getIdentifier(): [NameRef] has_iter
@@ -1764,7 +1764,7 @@ proc_macro.rs:
# 16| getScrutinee(): [MethodCallExpr] items.next() # 16| getScrutinee(): [MethodCallExpr] items.next()
# 15| getArgList(): [ArgList] ArgList # 15| getArgList(): [ArgList] ArgList
# 15| getIdentifier(): [NameRef] next # 15| getIdentifier(): [NameRef] next
# 16| getReceiver(): [PathExpr,VariableAccess] items # 16| getReceiver(): [VariableAccess] items
# 16| getPath(): [Path] items # 16| getPath(): [Path] items
# 16| getSegment(): [PathSegment] items # 16| getSegment(): [PathSegment] items
# 16| getIdentifier(): [NameRef] items # 16| getIdentifier(): [NameRef] items
@@ -1772,7 +1772,7 @@ proc_macro.rs:
# 15| getArm(0): [MatchArm] ... => ... # 15| getArm(0): [MatchArm] ... => ...
# 15| getExpr(): [CallExpr] ...::RepInterp(...) # 15| getExpr(): [CallExpr] ...::RepInterp(...)
# 15| getArgList(): [ArgList] ArgList # 15| getArgList(): [ArgList] ArgList
# 15| getArg(0): [PathExpr] _x # 15| getArg(0): [VariableAccess] _x
# 15| getPath(): [Path] _x # 15| getPath(): [Path] _x
# 15| getSegment(): [PathSegment] _x # 15| getSegment(): [PathSegment] _x
# 15| getIdentifier(): [NameRef] _x # 15| getIdentifier(): [NameRef] _x
@@ -1876,12 +1876,12 @@ proc_macro.rs:
# 16| getExpr(): [CallExpr] ...::to_tokens(...) # 16| getExpr(): [CallExpr] ...::to_tokens(...)
# 16| getArgList(): [ArgList] ArgList # 16| getArgList(): [ArgList] ArgList
# 16| getArg(0): [RefExpr] &items # 16| getArg(0): [RefExpr] &items
# 16| getExpr(): [PathExpr,VariableAccess] items # 16| getExpr(): [VariableAccess] items
# 16| getPath(): [Path] items # 16| getPath(): [Path] items
# 16| getSegment(): [PathSegment] items # 16| getSegment(): [PathSegment] items
# 16| getIdentifier(): [NameRef] items # 16| getIdentifier(): [NameRef] items
# 15| getArg(1): [RefExpr] &mut _s # 15| getArg(1): [RefExpr] &mut _s
# 15| getExpr(): [PathExpr] _s # 15| getExpr(): [VariableAccess] _s
# 15| getPath(): [Path] _s # 15| getPath(): [Path] _s
# 15| getSegment(): [PathSegment] _s # 15| getSegment(): [PathSegment] _s
# 15| getIdentifier(): [NameRef] _s # 15| getIdentifier(): [NameRef] _s
@@ -1993,7 +1993,7 @@ proc_macro.rs:
# 15| getIdentifier(): [NameRef] quote_token_with_context # 15| getIdentifier(): [NameRef] quote_token_with_context
# 16| getTokenTree(): [TokenTree] TokenTree # 16| getTokenTree(): [TokenTree] TokenTree
# 15| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr # 15| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
# 15| getTailExpr(): [PathExpr] _s # 15| getTailExpr(): [VariableAccess] _s
# 15| getPath(): [Path] _s # 15| getPath(): [Path] _s
# 15| getSegment(): [PathSegment] _s # 15| getSegment(): [PathSegment] _s
# 15| getIdentifier(): [NameRef] _s # 15| getIdentifier(): [NameRef] _s
@@ -2040,7 +2040,7 @@ proc_macro.rs:
# 22| getMacroCallExpansion(): [MatchExpr] match ... { ... } # 22| getMacroCallExpansion(): [MatchExpr] match ... { ... }
# 22| getScrutinee(): [CallExpr] ...::parse::<...>(...) # 22| getScrutinee(): [CallExpr] ...::parse::<...>(...)
# 22| getArgList(): [ArgList] ArgList # 22| getArgList(): [ArgList] ArgList
# 22| getArg(0): [PathExpr,VariableAccess] item # 22| getArg(0): [VariableAccess] item
# 22| getPath(): [Path] item # 22| getPath(): [Path] item
# 22| getSegment(): [PathSegment] item # 22| getSegment(): [PathSegment] item
# 22| getIdentifier(): [NameRef] item # 22| getIdentifier(): [NameRef] item
@@ -2062,7 +2062,7 @@ proc_macro.rs:
# 22| getIdentifier(): [NameRef] parse # 22| getIdentifier(): [NameRef] parse
# 22| getMatchArmList(): [MatchArmList] MatchArmList # 22| getMatchArmList(): [MatchArmList] MatchArmList
# 22| getArm(0): [MatchArm] ... => data # 22| getArm(0): [MatchArm] ... => data
# 22| getExpr(): [PathExpr,VariableAccess] data # 22| getExpr(): [VariableAccess] data
# 22| getPath(): [Path] data # 22| getPath(): [Path] data
# 22| getSegment(): [PathSegment] data # 22| getSegment(): [PathSegment] data
# 22| getIdentifier(): [NameRef] data # 22| getIdentifier(): [NameRef] data
@@ -2088,7 +2088,7 @@ proc_macro.rs:
# 22| getArg(0): [MethodCallExpr] err.to_compile_error() # 22| getArg(0): [MethodCallExpr] err.to_compile_error()
# 22| getArgList(): [ArgList] ArgList # 22| getArgList(): [ArgList] ArgList
# 22| getIdentifier(): [NameRef] to_compile_error # 22| getIdentifier(): [NameRef] to_compile_error
# 22| getReceiver(): [PathExpr,VariableAccess] err # 22| getReceiver(): [VariableAccess] err
# 22| getPath(): [Path] err # 22| getPath(): [Path] err
# 22| getSegment(): [PathSegment] err # 22| getSegment(): [PathSegment] err
# 22| getIdentifier(): [NameRef] err # 22| getIdentifier(): [NameRef] err
@@ -2123,7 +2123,7 @@ proc_macro.rs:
# 23| getInitializer(): [MethodCallExpr] ast.clone() # 23| getInitializer(): [MethodCallExpr] ast.clone()
# 23| getArgList(): [ArgList] ArgList # 23| getArgList(): [ArgList] ArgList
# 23| getIdentifier(): [NameRef] clone # 23| getIdentifier(): [NameRef] clone
# 23| getReceiver(): [PathExpr,VariableAccess] ast # 23| getReceiver(): [VariableAccess] ast
# 23| getPath(): [Path] ast # 23| getPath(): [Path] ast
# 23| getSegment(): [PathSegment] ast # 23| getSegment(): [PathSegment] ast
# 23| getIdentifier(): [NameRef] ast # 23| getIdentifier(): [NameRef] ast
@@ -2133,7 +2133,7 @@ proc_macro.rs:
# 24| getExpr(): [AssignmentExpr] ... = ... # 24| getExpr(): [AssignmentExpr] ... = ...
# 24| getLhs(): [FieldExpr] ... .ident # 24| getLhs(): [FieldExpr] ... .ident
# 24| getContainer(): [FieldExpr] new_ast.sig # 24| getContainer(): [FieldExpr] new_ast.sig
# 24| getContainer(): [PathExpr,VariableAccess] new_ast # 24| getContainer(): [VariableAccess] new_ast
# 24| getPath(): [Path] new_ast # 24| getPath(): [Path] new_ast
# 24| getSegment(): [PathSegment] new_ast # 24| getSegment(): [PathSegment] new_ast
# 24| getIdentifier(): [NameRef] new_ast # 24| getIdentifier(): [NameRef] new_ast
@@ -2170,7 +2170,7 @@ proc_macro.rs:
# 24| getArg(0): [FormatArgsArg] FormatArgsArg # 24| getArg(0): [FormatArgsArg] FormatArgsArg
# 24| getExpr(): [FieldExpr] ... .ident # 24| getExpr(): [FieldExpr] ... .ident
# 24| getContainer(): [FieldExpr] ast.sig # 24| getContainer(): [FieldExpr] ast.sig
# 24| getContainer(): [PathExpr,VariableAccess] ast # 24| getContainer(): [VariableAccess] ast
# 24| getPath(): [Path] ast # 24| getPath(): [Path] ast
# 24| getSegment(): [PathSegment] ast # 24| getSegment(): [PathSegment] ast
# 24| getIdentifier(): [NameRef] ast # 24| getIdentifier(): [NameRef] ast
@@ -2203,7 +2203,7 @@ proc_macro.rs:
# 24| getIdentifier(): [NameRef] span # 24| getIdentifier(): [NameRef] span
# 24| getReceiver(): [FieldExpr] ... .ident # 24| getReceiver(): [FieldExpr] ... .ident
# 24| getContainer(): [FieldExpr] ast.sig # 24| getContainer(): [FieldExpr] ast.sig
# 24| getContainer(): [PathExpr,VariableAccess] ast # 24| getContainer(): [VariableAccess] ast
# 24| getPath(): [Path] ast # 24| getPath(): [Path] ast
# 24| getSegment(): [PathSegment] ast # 24| getSegment(): [PathSegment] ast
# 24| getIdentifier(): [NameRef] ast # 24| getIdentifier(): [NameRef] ast
@@ -2317,12 +2317,12 @@ proc_macro.rs:
# 26| getExpr(): [CallExpr] ...::to_tokens(...) # 26| getExpr(): [CallExpr] ...::to_tokens(...)
# 26| getArgList(): [ArgList] ArgList # 26| getArgList(): [ArgList] ArgList
# 26| getArg(0): [RefExpr] &ast # 26| getArg(0): [RefExpr] &ast
# 26| getExpr(): [PathExpr,VariableAccess] ast # 26| getExpr(): [VariableAccess] ast
# 26| getPath(): [Path] ast # 26| getPath(): [Path] ast
# 26| getSegment(): [PathSegment] ast # 26| getSegment(): [PathSegment] ast
# 26| getIdentifier(): [NameRef] ast # 26| getIdentifier(): [NameRef] ast
# 25| getArg(1): [RefExpr] &mut _s # 25| getArg(1): [RefExpr] &mut _s
# 25| getExpr(): [PathExpr] _s # 25| getExpr(): [VariableAccess] _s
# 25| getPath(): [Path] _s # 25| getPath(): [Path] _s
# 25| getSegment(): [PathSegment] _s # 25| getSegment(): [PathSegment] _s
# 25| getIdentifier(): [NameRef] _s # 25| getIdentifier(): [NameRef] _s
@@ -2362,12 +2362,12 @@ proc_macro.rs:
# 27| getExpr(): [CallExpr] ...::to_tokens(...) # 27| getExpr(): [CallExpr] ...::to_tokens(...)
# 27| getArgList(): [ArgList] ArgList # 27| getArgList(): [ArgList] ArgList
# 27| getArg(0): [RefExpr] &new_ast # 27| getArg(0): [RefExpr] &new_ast
# 27| getExpr(): [PathExpr,VariableAccess] new_ast # 27| getExpr(): [VariableAccess] new_ast
# 27| getPath(): [Path] new_ast # 27| getPath(): [Path] new_ast
# 27| getSegment(): [PathSegment] new_ast # 27| getSegment(): [PathSegment] new_ast
# 27| getIdentifier(): [NameRef] new_ast # 27| getIdentifier(): [NameRef] new_ast
# 25| getArg(1): [RefExpr] &mut _s # 25| getArg(1): [RefExpr] &mut _s
# 25| getExpr(): [PathExpr] _s # 25| getExpr(): [VariableAccess] _s
# 25| getPath(): [Path] _s # 25| getPath(): [Path] _s
# 25| getSegment(): [PathSegment] _s # 25| getSegment(): [PathSegment] _s
# 25| getIdentifier(): [NameRef] _s # 25| getIdentifier(): [NameRef] _s
@@ -2424,7 +2424,7 @@ proc_macro.rs:
# 25| getIdentifier(): [NameRef] quote_token_with_context # 25| getIdentifier(): [NameRef] quote_token_with_context
# 27| getTokenTree(): [TokenTree] TokenTree # 27| getTokenTree(): [TokenTree] TokenTree
# 25| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr # 25| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
# 25| getTailExpr(): [PathExpr] _s # 25| getTailExpr(): [VariableAccess] _s
# 25| getPath(): [Path] _s # 25| getPath(): [Path] _s
# 25| getSegment(): [PathSegment] _s # 25| getSegment(): [PathSegment] _s
# 25| getIdentifier(): [NameRef] _s # 25| getIdentifier(): [NameRef] _s
@@ -2504,7 +2504,7 @@ proc_macro.rs:
# 38| getMacroCallExpansion(): [MatchExpr] match ... { ... } # 38| getMacroCallExpansion(): [MatchExpr] match ... { ... }
# 38| getScrutinee(): [CallExpr] ...::parse::<...>(...) # 38| getScrutinee(): [CallExpr] ...::parse::<...>(...)
# 38| getArgList(): [ArgList] ArgList # 38| getArgList(): [ArgList] ArgList
# 38| getArg(0): [PathExpr,VariableAccess] input # 38| getArg(0): [VariableAccess] input
# 38| getPath(): [Path] input # 38| getPath(): [Path] input
# 38| getSegment(): [PathSegment] input # 38| getSegment(): [PathSegment] input
# 38| getIdentifier(): [NameRef] input # 38| getIdentifier(): [NameRef] input
@@ -2526,7 +2526,7 @@ proc_macro.rs:
# 38| getIdentifier(): [NameRef] parse # 38| getIdentifier(): [NameRef] parse
# 38| getMatchArmList(): [MatchArmList] MatchArmList # 38| getMatchArmList(): [MatchArmList] MatchArmList
# 38| getArm(0): [MatchArm] ... => data # 38| getArm(0): [MatchArm] ... => data
# 38| getExpr(): [PathExpr,VariableAccess] data # 38| getExpr(): [VariableAccess] data
# 38| getPath(): [Path] data # 38| getPath(): [Path] data
# 38| getSegment(): [PathSegment] data # 38| getSegment(): [PathSegment] data
# 38| getIdentifier(): [NameRef] data # 38| getIdentifier(): [NameRef] data
@@ -2552,7 +2552,7 @@ proc_macro.rs:
# 38| getArg(0): [MethodCallExpr] err.to_compile_error() # 38| getArg(0): [MethodCallExpr] err.to_compile_error()
# 38| getArgList(): [ArgList] ArgList # 38| getArgList(): [ArgList] ArgList
# 38| getIdentifier(): [NameRef] to_compile_error # 38| getIdentifier(): [NameRef] to_compile_error
# 38| getReceiver(): [PathExpr,VariableAccess] err # 38| getReceiver(): [VariableAccess] err
# 38| getPath(): [Path] err # 38| getPath(): [Path] err
# 38| getSegment(): [PathSegment] err # 38| getSegment(): [PathSegment] err
# 38| getIdentifier(): [NameRef] err # 38| getIdentifier(): [NameRef] err
@@ -2586,7 +2586,7 @@ proc_macro.rs:
# 39| getStatement(1): [LetStmt] let ... = ... # 39| getStatement(1): [LetStmt] let ... = ...
# 39| getInitializer(): [RefExpr] &... # 39| getInitializer(): [RefExpr] &...
# 39| getExpr(): [FieldExpr] ast.ident # 39| getExpr(): [FieldExpr] ast.ident
# 39| getContainer(): [PathExpr,VariableAccess] ast # 39| getContainer(): [VariableAccess] ast
# 39| getPath(): [Path] ast # 39| getPath(): [Path] ast
# 39| getSegment(): [PathSegment] ast # 39| getSegment(): [PathSegment] ast
# 39| getIdentifier(): [NameRef] ast # 39| getIdentifier(): [NameRef] ast
@@ -2623,7 +2623,7 @@ proc_macro.rs:
# 40| getTokenTree(): [TokenTree] TokenTree # 40| getTokenTree(): [TokenTree] TokenTree
# 40| getMacroCallExpansion(): [FormatArgsExpr] FormatArgsExpr # 40| getMacroCallExpansion(): [FormatArgsExpr] FormatArgsExpr
# 40| getArg(0): [FormatArgsArg] FormatArgsArg # 40| getArg(0): [FormatArgsArg] FormatArgsArg
# 40| getExpr(): [PathExpr,VariableAccess] name # 40| getExpr(): [VariableAccess] name
# 40| getPath(): [Path] name # 40| getPath(): [Path] name
# 40| getSegment(): [PathSegment] name # 40| getSegment(): [PathSegment] name
# 40| getIdentifier(): [NameRef] name # 40| getIdentifier(): [NameRef] name
@@ -2652,7 +2652,7 @@ proc_macro.rs:
# 40| getArg(1): [MethodCallExpr] name.span() # 40| getArg(1): [MethodCallExpr] name.span()
# 40| getArgList(): [ArgList] ArgList # 40| getArgList(): [ArgList] ArgList
# 40| getIdentifier(): [NameRef] span # 40| getIdentifier(): [NameRef] span
# 40| getReceiver(): [PathExpr,VariableAccess] name # 40| getReceiver(): [VariableAccess] name
# 40| getPath(): [Path] name # 40| getPath(): [Path] name
# 40| getSegment(): [PathSegment] name # 40| getSegment(): [PathSegment] name
# 40| getIdentifier(): [NameRef] name # 40| getIdentifier(): [NameRef] name
@@ -2776,7 +2776,7 @@ proc_macro.rs:
# 42| getExpr(): [CallExpr] ...::push_ident(...) # 42| getExpr(): [CallExpr] ...::push_ident(...)
# 42| getArgList(): [ArgList] ArgList # 42| getArgList(): [ArgList] ArgList
# 41| getArg(0): [RefExpr] &mut _s # 41| getArg(0): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -2812,12 +2812,12 @@ proc_macro.rs:
# 42| getExpr(): [CallExpr] ...::to_tokens(...) # 42| getExpr(): [CallExpr] ...::to_tokens(...)
# 42| getArgList(): [ArgList] ArgList # 42| getArgList(): [ArgList] ArgList
# 42| getArg(0): [RefExpr] &const_ident # 42| getArg(0): [RefExpr] &const_ident
# 42| getExpr(): [PathExpr,VariableAccess] const_ident # 42| getExpr(): [VariableAccess] const_ident
# 42| getPath(): [Path] const_ident # 42| getPath(): [Path] const_ident
# 42| getSegment(): [PathSegment] const_ident # 42| getSegment(): [PathSegment] const_ident
# 42| getIdentifier(): [NameRef] const_ident # 42| getIdentifier(): [NameRef] const_ident
# 41| getArg(1): [RefExpr] &mut _s # 41| getArg(1): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -2867,7 +2867,7 @@ proc_macro.rs:
# 41| getExpr(): [CallExpr] ...::push_colon(...) # 41| getExpr(): [CallExpr] ...::push_colon(...)
# 41| getArgList(): [ArgList] ArgList # 41| getArgList(): [ArgList] ArgList
# 41| getArg(0): [RefExpr] &mut _s # 41| getArg(0): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -2906,7 +2906,7 @@ proc_macro.rs:
# 42| getExpr(): [CallExpr] ...::push_ident(...) # 42| getExpr(): [CallExpr] ...::push_ident(...)
# 42| getArgList(): [ArgList] ArgList # 42| getArgList(): [ArgList] ArgList
# 41| getArg(0): [RefExpr] &mut _s # 41| getArg(0): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -2952,7 +2952,7 @@ proc_macro.rs:
# 41| getExpr(): [CallExpr] ...::push_eq(...) # 41| getExpr(): [CallExpr] ...::push_eq(...)
# 41| getArgList(): [ArgList] ArgList # 41| getArgList(): [ArgList] ArgList
# 41| getArg(0): [RefExpr] &mut _s # 41| getArg(0): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -2991,7 +2991,7 @@ proc_macro.rs:
# 42| getExpr(): [CallExpr] ...::parse(...) # 42| getExpr(): [CallExpr] ...::parse(...)
# 42| getArgList(): [ArgList] ArgList # 42| getArgList(): [ArgList] ArgList
# 41| getArg(0): [RefExpr] &mut _s # 41| getArg(0): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -3037,7 +3037,7 @@ proc_macro.rs:
# 41| getExpr(): [CallExpr] ...::push_semi(...) # 41| getExpr(): [CallExpr] ...::push_semi(...)
# 41| getArgList(): [ArgList] ArgList # 41| getArgList(): [ArgList] ArgList
# 41| getArg(0): [RefExpr] &mut _s # 41| getArg(0): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -3076,7 +3076,7 @@ proc_macro.rs:
# 44| getExpr(): [CallExpr] ...::push_ident(...) # 44| getExpr(): [CallExpr] ...::push_ident(...)
# 44| getArgList(): [ArgList] ArgList # 44| getArgList(): [ArgList] ArgList
# 41| getArg(0): [RefExpr] &mut _s # 41| getArg(0): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -3122,7 +3122,7 @@ proc_macro.rs:
# 44| getExpr(): [CallExpr] ...::push_ident(...) # 44| getExpr(): [CallExpr] ...::push_ident(...)
# 44| getArgList(): [ArgList] ArgList # 44| getArgList(): [ArgList] ArgList
# 41| getArg(0): [RefExpr] &mut _s # 41| getArg(0): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -3168,7 +3168,7 @@ proc_macro.rs:
# 44| getExpr(): [CallExpr] ...::push_ident(...) # 44| getExpr(): [CallExpr] ...::push_ident(...)
# 44| getArgList(): [ArgList] ArgList # 44| getArgList(): [ArgList] ArgList
# 41| getArg(0): [RefExpr] &mut _s # 41| getArg(0): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -3204,12 +3204,12 @@ proc_macro.rs:
# 44| getExpr(): [CallExpr] ...::to_tokens(...) # 44| getExpr(): [CallExpr] ...::to_tokens(...)
# 44| getArgList(): [ArgList] ArgList # 44| getArgList(): [ArgList] ArgList
# 44| getArg(0): [RefExpr] &name # 44| getArg(0): [RefExpr] &name
# 44| getExpr(): [PathExpr,VariableAccess] name # 44| getExpr(): [VariableAccess] name
# 44| getPath(): [Path] name # 44| getPath(): [Path] name
# 44| getSegment(): [PathSegment] name # 44| getSegment(): [PathSegment] name
# 44| getIdentifier(): [NameRef] name # 44| getIdentifier(): [NameRef] name
# 41| getArg(1): [RefExpr] &mut _s # 41| getArg(1): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -3259,7 +3259,7 @@ proc_macro.rs:
# 45| getExpr(): [CallExpr] ...::push_group(...) # 45| getExpr(): [CallExpr] ...::push_group(...)
# 45| getArgList(): [ArgList] ArgList # 45| getArgList(): [ArgList] ArgList
# 41| getArg(0): [RefExpr] &mut _s # 41| getArg(0): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -3384,7 +3384,7 @@ proc_macro.rs:
# 45| getExpr(): [CallExpr] ...::push_ident(...) # 45| getExpr(): [CallExpr] ...::push_ident(...)
# 45| getArgList(): [ArgList] ArgList # 45| getArgList(): [ArgList] ArgList
# 41| getArg(0): [RefExpr] &mut _s # 41| getArg(0): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -3430,7 +3430,7 @@ proc_macro.rs:
# 45| getExpr(): [CallExpr] ...::push_ident(...) # 45| getExpr(): [CallExpr] ...::push_ident(...)
# 45| getArgList(): [ArgList] ArgList # 45| getArgList(): [ArgList] ArgList
# 41| getArg(0): [RefExpr] &mut _s # 41| getArg(0): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -3476,7 +3476,7 @@ proc_macro.rs:
# 41| getExpr(): [CallExpr] ...::push_group(...) # 41| getExpr(): [CallExpr] ...::push_group(...)
# 41| getArgList(): [ArgList] ArgList # 41| getArgList(): [ArgList] ArgList
# 41| getArg(0): [RefExpr] &mut _s # 41| getArg(0): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -3552,7 +3552,7 @@ proc_macro.rs:
# 41| getExpr(): [CallExpr] ...::push_rarrow(...) # 41| getExpr(): [CallExpr] ...::push_rarrow(...)
# 41| getArgList(): [ArgList] ArgList # 41| getArgList(): [ArgList] ArgList
# 41| getArg(0): [RefExpr] &mut _s # 41| getArg(0): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -3591,7 +3591,7 @@ proc_macro.rs:
# 45| getExpr(): [CallExpr] ...::push_ident(...) # 45| getExpr(): [CallExpr] ...::push_ident(...)
# 45| getArgList(): [ArgList] ArgList # 45| getArgList(): [ArgList] ArgList
# 41| getArg(0): [RefExpr] &mut _s # 41| getArg(0): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -3637,7 +3637,7 @@ proc_macro.rs:
# 46| getExpr(): [CallExpr] ...::push_group(...) # 46| getExpr(): [CallExpr] ...::push_group(...)
# 46| getArgList(): [ArgList] ArgList # 46| getArgList(): [ArgList] ArgList
# 41| getArg(0): [RefExpr] &mut _s # 41| getArg(0): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -3687,12 +3687,12 @@ proc_macro.rs:
# 46| getExpr(): [CallExpr] ...::to_tokens(...) # 46| getExpr(): [CallExpr] ...::to_tokens(...)
# 46| getArgList(): [ArgList] ArgList # 46| getArgList(): [ArgList] ArgList
# 46| getArg(0): [RefExpr] &const_ident # 46| getArg(0): [RefExpr] &const_ident
# 46| getExpr(): [PathExpr,VariableAccess] const_ident # 46| getExpr(): [VariableAccess] const_ident
# 46| getPath(): [Path] const_ident # 46| getPath(): [Path] const_ident
# 46| getSegment(): [PathSegment] const_ident # 46| getSegment(): [PathSegment] const_ident
# 46| getIdentifier(): [NameRef] const_ident # 46| getIdentifier(): [NameRef] const_ident
# 41| getArg(1): [RefExpr] &mut _s # 41| getArg(1): [RefExpr] &mut _s
# 41| getExpr(): [PathExpr] _s # 41| getExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -3706,7 +3706,7 @@ proc_macro.rs:
# 41| getIdentifier(): [NameRef] ToTokens # 41| getIdentifier(): [NameRef] ToTokens
# 41| getSegment(): [PathSegment] to_tokens # 41| getSegment(): [PathSegment] to_tokens
# 41| getIdentifier(): [NameRef] to_tokens # 41| getIdentifier(): [NameRef] to_tokens
# 41| getTailExpr(): [PathExpr] _s # 41| getTailExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -3752,7 +3752,7 @@ proc_macro.rs:
# 41| getIdentifier(): [NameRef] quote_token_with_context # 41| getIdentifier(): [NameRef] quote_token_with_context
# 45| getTokenTree(): [TokenTree] TokenTree # 45| getTokenTree(): [TokenTree] TokenTree
# 41| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr # 41| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
# 41| getTailExpr(): [PathExpr] _s # 41| getTailExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s
@@ -3798,7 +3798,7 @@ proc_macro.rs:
# 41| getIdentifier(): [NameRef] quote_token_with_context # 41| getIdentifier(): [NameRef] quote_token_with_context
# 44| getTokenTree(): [TokenTree] TokenTree # 44| getTokenTree(): [TokenTree] TokenTree
# 41| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr # 41| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
# 41| getTailExpr(): [PathExpr] _s # 41| getTailExpr(): [VariableAccess] _s
# 41| getPath(): [Path] _s # 41| getPath(): [Path] _s
# 41| getSegment(): [PathSegment] _s # 41| getSegment(): [PathSegment] _s
# 41| getIdentifier(): [NameRef] _s # 41| getIdentifier(): [NameRef] _s

View File

@@ -4,8 +4,10 @@
| test.rs:17:31:17:38 | ...::read | Flow source 'FileSource' of type file (DEFAULT). | | test.rs:17:31:17:38 | ...::read | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:22:22:22:39 | ...::read_to_string | Flow source 'FileSource' of type file (DEFAULT). | | test.rs:22:22:22:39 | ...::read_to_string | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:22:22:22:39 | ...::read_to_string | Flow source 'FileSource' of type file (DEFAULT). | | test.rs:22:22:22:39 | ...::read_to_string | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:26:18:26:29 | ...::read_dir | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:29:22:29:25 | path | Flow source 'FileSource' of type file (DEFAULT). | | test.rs:29:22:29:25 | path | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:43:27:43:35 | file_name | Flow source 'FileSource' of type file (DEFAULT). | | test.rs:43:27:43:35 | file_name | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:51:52:51:59 | read_dir | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:54:22:54:25 | path | Flow source 'FileSource' of type file (DEFAULT). | | test.rs:54:22:54:25 | path | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:55:27:55:35 | file_name | Flow source 'FileSource' of type file (DEFAULT). | | test.rs:55:27:55:35 | file_name | Flow source 'FileSource' of type file (DEFAULT). |
| test.rs:65:22:65:34 | ...::read_link | Flow source 'FileSource' of type file (DEFAULT). | | test.rs:65:22:65:34 | ...::read_link | Flow source 'FileSource' of type file (DEFAULT). |

View File

@@ -23,7 +23,7 @@ fn test_fs() -> Result<(), Box<dyn std::error::Error>> {
sink(buffer); // $ hasTaintFlow="file.txt" sink(buffer); // $ hasTaintFlow="file.txt"
} }
for entry in fs::read_dir("directory")? { for entry in fs::read_dir("directory")? { // $ Alert[rust/summary/taint-sources]
let e = entry?; let e = entry?;
let path = e.path(); // $ Alert[rust/summary/taint-sources] let path = e.path(); // $ Alert[rust/summary/taint-sources]
@@ -48,7 +48,7 @@ fn test_fs() -> Result<(), Box<dyn std::error::Error>> {
sink(file_name.clone().as_encoded_bytes()); // $ MISSING: hasTaintFlow sink(file_name.clone().as_encoded_bytes()); // $ MISSING: hasTaintFlow
sink(file_name); // $ hasTaintFlow sink(file_name); // $ hasTaintFlow
} }
for entry in std::path::Path::new("directory").read_dir()? { for entry in std::path::Path::new("directory").read_dir()? { // $ Alert[rust/summary/taint-sources]
let e = entry?; let e = entry?;
let path = e.path(); // $ Alert[rust/summary/taint-sources] let path = e.path(); // $ Alert[rust/summary/taint-sources]

View File

@@ -1,6 +1,8 @@
| struct Array | | | struct Array | |
| struct Ptr | | | struct Ptr | |
| struct PtrMut | |
| struct Ref | | | struct Ref | |
| struct RefMut | |
| struct Slice | | | struct Slice | |
| struct Tuple0 | | | struct Tuple0 | |
| struct Tuple1 | | | struct Tuple1 | |

View File

@@ -790,6 +790,49 @@ mod impl_with_attribute_macro {
} // impl_with_attribute_macro::test } // impl_with_attribute_macro::test
} }
mod patterns {
#[rustfmt::skip]
pub fn test() -> Option<i32> { // $ item=Option $ item=i32
let x = Some(42); // $ item=Some
let y : Option<i32> = match x { // $ item=Option $ item=i32
Some(y) => { // $ item=Some
None // $ item=None
}
None => // $ item=None
None // $ item=None
};
match y {
N0ne => // local variable
N0ne
}
} // patterns::test
#[rustfmt::skip]
fn test2() -> Option<i32> { // $ item=Option $ item=i32
let test_alias = test; // $ item=patterns::test
let test = test_alias();
test
}
#[rustfmt::skip]
const z: i32 // $ item=i32
= 0; // constz
#[rustfmt::skip]
fn test3() {
let x = Some(0); // $ item=Some
match x {
Some(x) // $ item=Some
=> x,
_ => 0
};
match x {
Some(z) => z, // $ item=Some item=constz
_ => 0
};
}
}
fn main() { fn main() {
my::nested::nested1::nested2::f(); // $ item=I4 my::nested::nested1::nested2::f(); // $ item=I4
my::f(); // $ item=I38 my::f(); // $ item=I38
@@ -826,4 +869,5 @@ fn main() {
AStruct::z_on_type(); // $ item=I124 AStruct::z_on_type(); // $ item=I124
AStruct {}.z_on_instance(); // $ item=I123 item=I125 AStruct {}.z_on_instance(); // $ item=I123 item=I125
impl_with_attribute_macro::test(); // $ item=impl_with_attribute_macro::test impl_with_attribute_macro::test(); // $ item=impl_with_attribute_macro::test
patterns::test(); // $ item=patterns::test
} }

View File

@@ -32,6 +32,7 @@ mod
| main.rs:629:1:697:1 | mod m24 | | main.rs:629:1:697:1 | mod m24 |
| main.rs:714:1:766:1 | mod associated_types | | main.rs:714:1:766:1 | mod associated_types |
| main.rs:772:1:791:1 | mod impl_with_attribute_macro | | main.rs:772:1:791:1 | mod impl_with_attribute_macro |
| main.rs:793:1:834:1 | mod patterns |
| my2/mod.rs:1:1:1:16 | mod nested2 | | my2/mod.rs:1:1:1:16 | mod nested2 |
| my2/mod.rs:20:1:20:12 | mod my3 | | my2/mod.rs:20:1:20:12 | mod my3 |
| my2/mod.rs:22:1:23:10 | mod mymod | | my2/mod.rs:22:1:23:10 | mod mymod |
@@ -72,7 +73,7 @@ resolvePath
| main.rs:37:17:37:24 | ...::f | main.rs:26:9:28:9 | fn f | | main.rs:37:17:37:24 | ...::f | main.rs:26:9:28:9 | fn f |
| main.rs:39:17:39:23 | println | {EXTERNAL LOCATION} | MacroRules | | main.rs:39:17:39:23 | println | {EXTERNAL LOCATION} | MacroRules |
| main.rs:40:17:40:17 | f | main.rs:26:9:28:9 | fn f | | main.rs:40:17:40:17 | f | main.rs:26:9:28:9 | fn f |
| main.rs:47:9:47:13 | super | main.rs:1:1:829:2 | SourceFile | | main.rs:47:9:47:13 | super | main.rs:1:1:873:2 | SourceFile |
| main.rs:47:9:47:17 | ...::m1 | main.rs:20:1:44:1 | mod m1 | | main.rs:47:9:47:17 | ...::m1 | main.rs:20:1:44:1 | mod m1 |
| main.rs:47:9:47:21 | ...::m2 | main.rs:25:5:43:5 | mod m2 | | main.rs:47:9:47:21 | ...::m2 | main.rs:25:5:43:5 | mod m2 |
| main.rs:47:9:47:24 | ...::g | main.rs:30:9:34:9 | fn g | | main.rs:47:9:47:24 | ...::g | main.rs:30:9:34:9 | fn g |
@@ -87,7 +88,7 @@ resolvePath
| main.rs:68:17:68:19 | Foo | main.rs:66:9:66:21 | struct Foo | | main.rs:68:17:68:19 | Foo | main.rs:66:9:66:21 | struct Foo |
| main.rs:71:13:71:15 | Foo | main.rs:60:5:60:17 | struct Foo | | main.rs:71:13:71:15 | Foo | main.rs:60:5:60:17 | struct Foo |
| main.rs:73:5:73:5 | f | main.rs:62:5:69:5 | fn f | | main.rs:73:5:73:5 | f | main.rs:62:5:69:5 | fn f |
| main.rs:75:5:75:8 | self | main.rs:1:1:829:2 | SourceFile | | main.rs:75:5:75:8 | self | main.rs:1:1:873:2 | SourceFile |
| main.rs:75:5:75:11 | ...::i | main.rs:78:1:90:1 | fn i | | main.rs:75:5:75:11 | ...::i | main.rs:78:1:90:1 | fn i |
| main.rs:79:5:79:11 | println | {EXTERNAL LOCATION} | MacroRules | | main.rs:79:5:79:11 | println | {EXTERNAL LOCATION} | MacroRules |
| main.rs:81:13:81:15 | Foo | main.rs:55:1:55:13 | struct Foo | | main.rs:81:13:81:15 | Foo | main.rs:55:1:55:13 | struct Foo |
@@ -109,7 +110,7 @@ resolvePath
| main.rs:112:9:112:15 | println | {EXTERNAL LOCATION} | MacroRules | | main.rs:112:9:112:15 | println | {EXTERNAL LOCATION} | MacroRules |
| main.rs:118:9:118:15 | println | {EXTERNAL LOCATION} | MacroRules | | main.rs:118:9:118:15 | println | {EXTERNAL LOCATION} | MacroRules |
| main.rs:122:9:122:15 | println | {EXTERNAL LOCATION} | MacroRules | | main.rs:122:9:122:15 | println | {EXTERNAL LOCATION} | MacroRules |
| main.rs:125:13:125:17 | super | main.rs:1:1:829:2 | SourceFile | | main.rs:125:13:125:17 | super | main.rs:1:1:873:2 | SourceFile |
| main.rs:125:13:125:21 | ...::m5 | main.rs:110:1:114:1 | mod m5 | | main.rs:125:13:125:21 | ...::m5 | main.rs:110:1:114:1 | mod m5 |
| main.rs:126:9:126:9 | f | main.rs:111:5:113:5 | fn f | | main.rs:126:9:126:9 | f | main.rs:111:5:113:5 | fn f |
| main.rs:126:9:126:9 | f | main.rs:117:5:119:5 | fn f | | main.rs:126:9:126:9 | f | main.rs:117:5:119:5 | fn f |
@@ -397,77 +398,97 @@ resolvePath
| main.rs:781:21:781:23 | i64 | {EXTERNAL LOCATION} | struct i64 | | main.rs:781:21:781:23 | i64 | {EXTERNAL LOCATION} | struct i64 |
| main.rs:783:11:783:13 | i64 | {EXTERNAL LOCATION} | struct i64 | | main.rs:783:11:783:13 | i64 | {EXTERNAL LOCATION} | struct i64 |
| main.rs:789:17:789:19 | Foo | main.rs:774:5:774:15 | struct Foo | | main.rs:789:17:789:19 | Foo | main.rs:774:5:774:15 | struct Foo |
| main.rs:794:5:794:6 | my | main.rs:1:1:1:7 | mod my | | main.rs:795:22:795:32 | Option::<...> | {EXTERNAL LOCATION} | enum Option |
| main.rs:794:5:794:14 | ...::nested | my.rs:1:1:1:15 | mod nested | | main.rs:795:29:795:31 | i32 | {EXTERNAL LOCATION} | struct i32 |
| main.rs:794:5:794:23 | ...::nested1 | my/nested.rs:1:1:17:1 | mod nested1 | | main.rs:796:17:796:20 | Some | {EXTERNAL LOCATION} | Some |
| main.rs:794:5:794:32 | ...::nested2 | my/nested.rs:2:5:11:5 | mod nested2 | | main.rs:797:17:797:27 | Option::<...> | {EXTERNAL LOCATION} | enum Option |
| main.rs:794:5:794:35 | ...::f | my/nested.rs:3:9:5:9 | fn f | | main.rs:797:24:797:26 | i32 | {EXTERNAL LOCATION} | struct i32 |
| main.rs:795:5:795:6 | my | main.rs:1:1:1:7 | mod my | | main.rs:798:13:798:16 | Some | {EXTERNAL LOCATION} | Some |
| main.rs:795:5:795:9 | ...::f | my.rs:5:1:7:1 | fn f | | main.rs:799:17:799:20 | None | {EXTERNAL LOCATION} | None |
| main.rs:796:5:796:11 | nested2 | my2/mod.rs:1:1:1:16 | mod nested2 | | main.rs:801:13:801:16 | None | {EXTERNAL LOCATION} | None |
| main.rs:796:5:796:20 | ...::nested3 | my2/nested2.rs:1:1:11:1 | mod nested3 | | main.rs:802:17:802:20 | None | {EXTERNAL LOCATION} | None |
| main.rs:796:5:796:29 | ...::nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 | | main.rs:811:19:811:29 | Option::<...> | {EXTERNAL LOCATION} | enum Option |
| main.rs:796:5:796:32 | ...::f | my2/nested2.rs:3:9:5:9 | fn f | | main.rs:811:26:811:28 | i32 | {EXTERNAL LOCATION} | struct i32 |
| main.rs:797:5:797:5 | f | my2/nested2.rs:3:9:5:9 | fn f | | main.rs:812:26:812:29 | test | main.rs:794:5:808:5 | fn test |
| main.rs:798:5:798:5 | g | my2/nested2.rs:7:9:9:9 | fn g | | main.rs:818:14:818:16 | i32 | {EXTERNAL LOCATION} | struct i32 |
| main.rs:799:5:799:9 | crate | main.rs:0:0:0:0 | Crate(main@0.0.1) | | main.rs:823:17:823:20 | Some | {EXTERNAL LOCATION} | Some |
| main.rs:799:5:799:12 | ...::h | main.rs:57:1:76:1 | fn h | | main.rs:825:13:825:16 | Some | {EXTERNAL LOCATION} | Some |
| main.rs:800:5:800:6 | m1 | main.rs:20:1:44:1 | mod m1 | | main.rs:830:13:830:16 | Some | {EXTERNAL LOCATION} | Some |
| main.rs:800:5:800:10 | ...::m2 | main.rs:25:5:43:5 | mod m2 | | main.rs:830:18:830:18 | z | main.rs:817:5:819:12 | Const |
| main.rs:800:5:800:13 | ...::g | main.rs:30:9:34:9 | fn g | | main.rs:830:24:830:24 | z | main.rs:817:5:819:12 | Const |
| main.rs:801:5:801:6 | m1 | main.rs:20:1:44:1 | mod m1 | | main.rs:837:5:837:6 | my | main.rs:1:1:1:7 | mod my |
| main.rs:801:5:801:10 | ...::m2 | main.rs:25:5:43:5 | mod m2 | | main.rs:837:5:837:14 | ...::nested | my.rs:1:1:1:15 | mod nested |
| main.rs:801:5:801:14 | ...::m3 | main.rs:36:9:42:9 | mod m3 | | main.rs:837:5:837:23 | ...::nested1 | my/nested.rs:1:1:17:1 | mod nested1 |
| main.rs:801:5:801:17 | ...::h | main.rs:37:27:41:13 | fn h | | main.rs:837:5:837:32 | ...::nested2 | my/nested.rs:2:5:11:5 | mod nested2 |
| main.rs:802:5:802:6 | m4 | main.rs:46:1:53:1 | mod m4 | | main.rs:837:5:837:35 | ...::f | my/nested.rs:3:9:5:9 | fn f |
| main.rs:802:5:802:9 | ...::i | main.rs:49:5:52:5 | fn i | | main.rs:838:5:838:6 | my | main.rs:1:1:1:7 | mod my |
| main.rs:803:5:803:5 | h | main.rs:57:1:76:1 | fn h | | main.rs:838:5:838:9 | ...::f | my.rs:5:1:7:1 | fn f |
| main.rs:804:5:804:11 | f_alias | my2/nested2.rs:3:9:5:9 | fn f | | main.rs:839:5:839:11 | nested2 | my2/mod.rs:1:1:1:16 | mod nested2 |
| main.rs:805:5:805:11 | g_alias | my2/nested2.rs:7:9:9:9 | fn g | | main.rs:839:5:839:20 | ...::nested3 | my2/nested2.rs:1:1:11:1 | mod nested3 |
| main.rs:806:5:806:5 | j | main.rs:104:1:108:1 | fn j | | main.rs:839:5:839:29 | ...::nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 |
| main.rs:807:5:807:6 | m6 | main.rs:116:1:128:1 | mod m6 | | main.rs:839:5:839:32 | ...::f | my2/nested2.rs:3:9:5:9 | fn f |
| main.rs:807:5:807:9 | ...::g | main.rs:121:5:127:5 | fn g | | main.rs:840:5:840:5 | f | my2/nested2.rs:3:9:5:9 | fn f |
| main.rs:808:5:808:6 | m7 | main.rs:130:1:149:1 | mod m7 | | main.rs:841:5:841:5 | g | my2/nested2.rs:7:9:9:9 | fn g |
| main.rs:808:5:808:9 | ...::f | main.rs:141:5:148:5 | fn f | | main.rs:842:5:842:9 | crate | main.rs:0:0:0:0 | Crate(main@0.0.1) |
| main.rs:809:5:809:6 | m8 | main.rs:151:1:205:1 | mod m8 | | main.rs:842:5:842:12 | ...::h | main.rs:57:1:76:1 | fn h |
| main.rs:809:5:809:9 | ...::g | main.rs:189:5:204:5 | fn g | | main.rs:843:5:843:6 | m1 | main.rs:20:1:44:1 | mod m1 |
| main.rs:810:5:810:6 | m9 | main.rs:207:1:215:1 | mod m9 | | main.rs:843:5:843:10 | ...::m2 | main.rs:25:5:43:5 | mod m2 |
| main.rs:810:5:810:9 | ...::f | main.rs:210:5:214:5 | fn f | | main.rs:843:5:843:13 | ...::g | main.rs:30:9:34:9 | fn g |
| main.rs:811:5:811:7 | m11 | main.rs:238:1:275:1 | mod m11 | | main.rs:844:5:844:6 | m1 | main.rs:20:1:44:1 | mod m1 |
| main.rs:811:5:811:10 | ...::f | main.rs:243:5:246:5 | fn f | | main.rs:844:5:844:10 | ...::m2 | main.rs:25:5:43:5 | mod m2 |
| main.rs:812:5:812:7 | m15 | main.rs:306:1:375:1 | mod m15 | | main.rs:844:5:844:14 | ...::m3 | main.rs:36:9:42:9 | mod m3 |
| main.rs:812:5:812:10 | ...::f | main.rs:362:5:374:5 | fn f | | main.rs:844:5:844:17 | ...::h | main.rs:37:27:41:13 | fn h |
| main.rs:813:5:813:7 | m16 | main.rs:377:1:469:1 | mod m16 | | main.rs:845:5:845:6 | m4 | main.rs:46:1:53:1 | mod m4 |
| main.rs:813:5:813:10 | ...::f | main.rs:444:5:468:5 | fn f | | main.rs:845:5:845:9 | ...::i | main.rs:49:5:52:5 | fn i |
| main.rs:814:5:814:20 | trait_visibility | main.rs:471:1:521:1 | mod trait_visibility | | main.rs:846:5:846:5 | h | main.rs:57:1:76:1 | fn h |
| main.rs:814:5:814:23 | ...::f | main.rs:498:5:520:5 | fn f | | main.rs:847:5:847:11 | f_alias | my2/nested2.rs:3:9:5:9 | fn f |
| main.rs:815:5:815:7 | m17 | main.rs:523:1:553:1 | mod m17 | | main.rs:848:5:848:11 | g_alias | my2/nested2.rs:7:9:9:9 | fn g |
| main.rs:815:5:815:10 | ...::f | main.rs:547:5:552:5 | fn f | | main.rs:849:5:849:5 | j | main.rs:104:1:108:1 | fn j |
| main.rs:816:5:816:11 | nested6 | my2/nested2.rs:14:5:18:5 | mod nested6 | | main.rs:850:5:850:6 | m6 | main.rs:116:1:128:1 | mod m6 |
| main.rs:816:5:816:14 | ...::f | my2/nested2.rs:15:9:17:9 | fn f | | main.rs:850:5:850:9 | ...::g | main.rs:121:5:127:5 | fn g |
| main.rs:817:5:817:11 | nested8 | my2/nested2.rs:22:5:26:5 | mod nested8 | | main.rs:851:5:851:6 | m7 | main.rs:130:1:149:1 | mod m7 |
| main.rs:817:5:817:14 | ...::f | my2/nested2.rs:23:9:25:9 | fn f | | main.rs:851:5:851:9 | ...::f | main.rs:141:5:148:5 | fn f |
| main.rs:818:5:818:7 | my3 | my2/mod.rs:20:1:20:12 | mod my3 | | main.rs:852:5:852:6 | m8 | main.rs:151:1:205:1 | mod m8 |
| main.rs:818:5:818:10 | ...::f | my2/my3/mod.rs:1:1:5:1 | fn f | | main.rs:852:5:852:9 | ...::g | main.rs:189:5:204:5 | fn g |
| main.rs:819:5:819:12 | nested_f | my/my4/my5/mod.rs:1:1:3:1 | fn f | | main.rs:853:5:853:6 | m9 | main.rs:207:1:215:1 | mod m9 |
| main.rs:820:5:820:12 | my_alias | main.rs:1:1:1:7 | mod my | | main.rs:853:5:853:9 | ...::f | main.rs:210:5:214:5 | fn f |
| main.rs:820:5:820:22 | ...::nested_f | my/my4/my5/mod.rs:1:1:3:1 | fn f | | main.rs:854:5:854:7 | m11 | main.rs:238:1:275:1 | mod m11 |
| main.rs:821:5:821:7 | m18 | main.rs:555:1:573:1 | mod m18 | | main.rs:854:5:854:10 | ...::f | main.rs:243:5:246:5 | fn f |
| main.rs:821:5:821:12 | ...::m19 | main.rs:560:5:572:5 | mod m19 | | main.rs:855:5:855:7 | m15 | main.rs:306:1:375:1 | mod m15 |
| main.rs:821:5:821:17 | ...::m20 | main.rs:565:9:571:9 | mod m20 | | main.rs:855:5:855:10 | ...::f | main.rs:362:5:374:5 | fn f |
| main.rs:821:5:821:20 | ...::g | main.rs:566:13:570:13 | fn g | | main.rs:856:5:856:7 | m16 | main.rs:377:1:469:1 | mod m16 |
| main.rs:822:5:822:7 | m23 | main.rs:602:1:627:1 | mod m23 | | main.rs:856:5:856:10 | ...::f | main.rs:444:5:468:5 | fn f |
| main.rs:822:5:822:10 | ...::f | main.rs:622:5:626:5 | fn f | | main.rs:857:5:857:20 | trait_visibility | main.rs:471:1:521:1 | mod trait_visibility |
| main.rs:823:5:823:7 | m24 | main.rs:629:1:697:1 | mod m24 | | main.rs:857:5:857:23 | ...::f | main.rs:498:5:520:5 | fn f |
| main.rs:823:5:823:10 | ...::f | main.rs:683:5:696:5 | fn f | | main.rs:858:5:858:7 | m17 | main.rs:523:1:553:1 | mod m17 |
| main.rs:824:5:824:8 | zelf | main.rs:0:0:0:0 | Crate(main@0.0.1) | | main.rs:858:5:858:10 | ...::f | main.rs:547:5:552:5 | fn f |
| main.rs:824:5:824:11 | ...::h | main.rs:57:1:76:1 | fn h | | main.rs:859:5:859:11 | nested6 | my2/nested2.rs:14:5:18:5 | mod nested6 |
| main.rs:825:5:825:13 | z_changed | main.rs:702:1:702:9 | fn z_changed | | main.rs:859:5:859:14 | ...::f | my2/nested2.rs:15:9:17:9 | fn f |
| main.rs:826:5:826:11 | AStruct | main.rs:704:1:704:17 | struct AStruct | | main.rs:860:5:860:11 | nested8 | my2/nested2.rs:22:5:26:5 | mod nested8 |
| main.rs:826:5:826:22 | ...::z_on_type | main.rs:708:5:708:17 | fn z_on_type | | main.rs:860:5:860:14 | ...::f | my2/nested2.rs:23:9:25:9 | fn f |
| main.rs:827:5:827:11 | AStruct | main.rs:704:1:704:17 | struct AStruct | | main.rs:861:5:861:7 | my3 | my2/mod.rs:20:1:20:12 | mod my3 |
| main.rs:828:5:828:29 | impl_with_attribute_macro | main.rs:772:1:791:1 | mod impl_with_attribute_macro | | main.rs:861:5:861:10 | ...::f | my2/my3/mod.rs:1:1:5:1 | fn f |
| main.rs:828:5:828:35 | ...::test | main.rs:787:5:790:5 | fn test | | main.rs:862:5:862:12 | nested_f | my/my4/my5/mod.rs:1:1:3:1 | fn f |
| main.rs:863:5:863:12 | my_alias | main.rs:1:1:1:7 | mod my |
| main.rs:863:5:863:22 | ...::nested_f | my/my4/my5/mod.rs:1:1:3:1 | fn f |
| main.rs:864:5:864:7 | m18 | main.rs:555:1:573:1 | mod m18 |
| main.rs:864:5:864:12 | ...::m19 | main.rs:560:5:572:5 | mod m19 |
| main.rs:864:5:864:17 | ...::m20 | main.rs:565:9:571:9 | mod m20 |
| main.rs:864:5:864:20 | ...::g | main.rs:566:13:570:13 | fn g |
| main.rs:865:5:865:7 | m23 | main.rs:602:1:627:1 | mod m23 |
| main.rs:865:5:865:10 | ...::f | main.rs:622:5:626:5 | fn f |
| main.rs:866:5:866:7 | m24 | main.rs:629:1:697:1 | mod m24 |
| main.rs:866:5:866:10 | ...::f | main.rs:683:5:696:5 | fn f |
| main.rs:867:5:867:8 | zelf | main.rs:0:0:0:0 | Crate(main@0.0.1) |
| main.rs:867:5:867:11 | ...::h | main.rs:57:1:76:1 | fn h |
| main.rs:868:5:868:13 | z_changed | main.rs:702:1:702:9 | fn z_changed |
| main.rs:869:5:869:11 | AStruct | main.rs:704:1:704:17 | struct AStruct |
| main.rs:869:5:869:22 | ...::z_on_type | main.rs:708:5:708:17 | fn z_on_type |
| main.rs:870:5:870:11 | AStruct | main.rs:704:1:704:17 | struct AStruct |
| main.rs:871:5:871:29 | impl_with_attribute_macro | main.rs:772:1:791:1 | mod impl_with_attribute_macro |
| main.rs:871:5:871:35 | ...::test | main.rs:787:5:790:5 | fn test |
| main.rs:872:5:872:12 | patterns | main.rs:793:1:834:1 | mod patterns |
| main.rs:872:5:872:18 | ...::test | main.rs:794:5:808:5 | fn test |
| my2/mod.rs:4:5:4:11 | println | {EXTERNAL LOCATION} | MacroRules | | my2/mod.rs:4:5:4:11 | println | {EXTERNAL LOCATION} | MacroRules |
| my2/mod.rs:5:5:5:11 | nested2 | my2/mod.rs:1:1:1:16 | mod nested2 | | my2/mod.rs:5:5:5:11 | nested2 | my2/mod.rs:1:1:1:16 | mod nested2 |
| my2/mod.rs:5:5:5:20 | ...::nested3 | my2/nested2.rs:1:1:11:1 | mod nested3 | | my2/mod.rs:5:5:5:20 | ...::nested3 | my2/nested2.rs:1:1:11:1 | mod nested3 |
@@ -493,7 +514,7 @@ resolvePath
| my2/my3/mod.rs:3:5:3:5 | g | my2/mod.rs:3:1:6:1 | fn g | | my2/my3/mod.rs:3:5:3:5 | g | my2/mod.rs:3:1:6:1 | fn g |
| my2/my3/mod.rs:4:5:4:5 | h | main.rs:57:1:76:1 | fn h | | my2/my3/mod.rs:4:5:4:5 | h | main.rs:57:1:76:1 | fn h |
| my2/my3/mod.rs:7:5:7:9 | super | my2/mod.rs:1:1:25:34 | SourceFile | | my2/my3/mod.rs:7:5:7:9 | super | my2/mod.rs:1:1:25:34 | SourceFile |
| my2/my3/mod.rs:7:5:7:16 | ...::super | main.rs:1:1:829:2 | SourceFile | | my2/my3/mod.rs:7:5:7:16 | ...::super | main.rs:1:1:873:2 | SourceFile |
| my2/my3/mod.rs:7:5:7:19 | ...::h | main.rs:57:1:76:1 | fn h | | my2/my3/mod.rs:7:5:7:19 | ...::h | main.rs:57:1:76:1 | fn h |
| my2/my3/mod.rs:8:5:8:9 | super | my2/mod.rs:1:1:25:34 | SourceFile | | my2/my3/mod.rs:8:5:8:9 | super | my2/mod.rs:1:1:25:34 | SourceFile |
| my2/my3/mod.rs:8:5:8:12 | ...::g | my2/mod.rs:3:1:6:1 | fn g | | my2/my3/mod.rs:8:5:8:12 | ...::g | my2/mod.rs:3:1:6:1 | fn g |

View File

@@ -5,7 +5,7 @@ import TestUtils
query predicate mod(Module m) { toBeTested(m) } query predicate mod(Module m) { toBeTested(m) }
query predicate resolvePath(Path p, ItemNode i) { query predicate resolvePath(PathExt p, ItemNode i) {
toBeTested(p) and toBeTested(p) and
not p.isFromMacroExpansion() and not p.isFromMacroExpansion() and
i = resolvePath(p) i = resolvePath(p)

View File

@@ -1798,145 +1798,216 @@ edges
| main.rs:753:5:753:16 | print_i64(...) | main.rs:744:18:754:1 | { ... } | | | main.rs:753:5:753:16 | print_i64(...) | main.rs:744:18:754:1 | { ... } | |
| main.rs:753:5:753:17 | ExprStmt | main.rs:753:5:753:13 | print_i64 | | | main.rs:753:5:753:17 | ExprStmt | main.rs:753:5:753:13 | print_i64 | |
| main.rs:753:15:753:15 | x | main.rs:753:5:753:16 | print_i64(...) | | | main.rs:753:15:753:15 | x | main.rs:753:5:753:16 | print_i64(...) | |
| main.rs:756:1:800:1 | enter fn main | main.rs:757:5:757:25 | ExprStmt | | | main.rs:757:5:772:5 | enter fn test | main.rs:759:9:759:25 | let ... = ... | |
| main.rs:756:1:800:1 | exit fn main (normal) | main.rs:756:1:800:1 | exit fn main | | | main.rs:757:5:772:5 | exit fn test (normal) | main.rs:757:5:772:5 | exit fn test | |
| main.rs:756:11:800:1 | { ... } | main.rs:756:1:800:1 | exit fn main (normal) | | | main.rs:758:34:772:5 | { ... } | main.rs:757:5:772:5 | exit fn test (normal) | |
| main.rs:757:5:757:22 | immutable_variable | main.rs:757:5:757:24 | immutable_variable(...) | | | main.rs:759:9:759:25 | let ... = ... | main.rs:759:17:759:20 | Some | |
| main.rs:757:5:757:24 | immutable_variable(...) | main.rs:758:5:758:23 | ExprStmt | | | main.rs:759:13:759:13 | x | main.rs:759:13:759:13 | x | |
| main.rs:757:5:757:25 | ExprStmt | main.rs:757:5:757:22 | immutable_variable | | | main.rs:759:13:759:13 | x | main.rs:760:9:767:10 | let ... = ... | match |
| main.rs:758:5:758:20 | mutable_variable | main.rs:758:5:758:22 | mutable_variable(...) | | | main.rs:759:17:759:20 | Some | main.rs:759:22:759:23 | 42 | |
| main.rs:758:5:758:22 | mutable_variable(...) | main.rs:759:5:759:40 | ExprStmt | | | main.rs:759:17:759:24 | Some(...) | main.rs:759:13:759:13 | x | |
| main.rs:758:5:758:23 | ExprStmt | main.rs:758:5:758:20 | mutable_variable | | | main.rs:759:22:759:23 | 42 | main.rs:759:17:759:24 | Some(...) | |
| main.rs:759:5:759:37 | mutable_variable_immutable_borrow | main.rs:759:5:759:39 | mutable_variable_immutable_borrow(...) | | | main.rs:760:9:767:10 | let ... = ... | main.rs:761:19:761:19 | x | |
| main.rs:759:5:759:39 | mutable_variable_immutable_borrow(...) | main.rs:760:5:760:23 | ExprStmt | | | main.rs:760:13:760:13 | y | main.rs:760:13:760:13 | y | |
| main.rs:759:5:759:40 | ExprStmt | main.rs:759:5:759:37 | mutable_variable_immutable_borrow | | | main.rs:760:13:760:13 | y | main.rs:768:15:768:15 | y | match |
| main.rs:760:5:760:20 | variable_shadow1 | main.rs:760:5:760:22 | variable_shadow1(...) | | | main.rs:761:13:767:9 | match x { ... } | main.rs:760:13:760:13 | y | |
| main.rs:760:5:760:22 | variable_shadow1(...) | main.rs:761:5:761:23 | ExprStmt | | | main.rs:761:19:761:19 | x | main.rs:762:13:762:19 | Some(...) | |
| main.rs:760:5:760:23 | ExprStmt | main.rs:760:5:760:20 | variable_shadow1 | | | main.rs:762:13:762:19 | Some(...) | main.rs:762:18:762:18 | y | match |
| main.rs:761:5:761:20 | variable_shadow2 | main.rs:761:5:761:22 | variable_shadow2(...) | | | main.rs:762:13:762:19 | Some(...) | main.rs:765:13:765:16 | None | no-match |
| main.rs:761:5:761:22 | variable_shadow2(...) | main.rs:762:5:762:19 | ExprStmt | | | main.rs:762:18:762:18 | y | main.rs:762:18:762:18 | y | |
| main.rs:761:5:761:23 | ExprStmt | main.rs:761:5:761:20 | variable_shadow2 | | | main.rs:762:18:762:18 | y | main.rs:763:17:763:20 | None | match |
| main.rs:762:5:762:16 | let_pattern1 | main.rs:762:5:762:18 | let_pattern1(...) | | | main.rs:762:24:764:13 | { ... } | main.rs:761:13:767:9 | match x { ... } | |
| main.rs:762:5:762:18 | let_pattern1(...) | main.rs:763:5:763:19 | ExprStmt | | | main.rs:763:17:763:20 | None | main.rs:762:24:764:13 | { ... } | |
| main.rs:762:5:762:19 | ExprStmt | main.rs:762:5:762:16 | let_pattern1 | | | main.rs:765:13:765:16 | None | main.rs:765:13:765:16 | None | |
| main.rs:763:5:763:16 | let_pattern2 | main.rs:763:5:763:18 | let_pattern2(...) | | | main.rs:765:13:765:16 | None | main.rs:766:17:766:20 | None | match |
| main.rs:763:5:763:18 | let_pattern2(...) | main.rs:764:5:764:19 | ExprStmt | | | main.rs:766:17:766:20 | None | main.rs:761:13:767:9 | match x { ... } | |
| main.rs:763:5:763:19 | ExprStmt | main.rs:763:5:763:16 | let_pattern2 | | | main.rs:768:9:771:9 | match y { ... } | main.rs:758:34:772:5 | { ... } | |
| main.rs:764:5:764:16 | let_pattern3 | main.rs:764:5:764:18 | let_pattern3(...) | | | main.rs:768:15:768:15 | y | main.rs:769:13:769:16 | N0ne | |
| main.rs:764:5:764:18 | let_pattern3(...) | main.rs:765:5:765:19 | ExprStmt | | | main.rs:769:13:769:16 | N0ne | main.rs:769:13:769:16 | N0ne | |
| main.rs:764:5:764:19 | ExprStmt | main.rs:764:5:764:16 | let_pattern3 | | | main.rs:769:13:769:16 | N0ne | main.rs:770:17:770:20 | N0ne | match |
| main.rs:765:5:765:16 | let_pattern4 | main.rs:765:5:765:18 | let_pattern4(...) | | | main.rs:770:17:770:20 | N0ne | main.rs:768:9:771:9 | match y { ... } | |
| main.rs:765:5:765:18 | let_pattern4(...) | main.rs:766:5:766:21 | ExprStmt | | | main.rs:774:5:781:5 | enter fn test2 | main.rs:776:9:777:17 | let ... = test | |
| main.rs:765:5:765:19 | ExprStmt | main.rs:765:5:765:16 | let_pattern4 | | | main.rs:774:5:781:5 | exit fn test2 (normal) | main.rs:774:5:781:5 | exit fn test2 | |
| main.rs:766:5:766:18 | match_pattern1 | main.rs:766:5:766:20 | match_pattern1(...) | | | main.rs:775:31:781:5 | { ... } | main.rs:774:5:781:5 | exit fn test2 (normal) | |
| main.rs:766:5:766:20 | match_pattern1(...) | main.rs:767:5:767:21 | ExprStmt | | | main.rs:776:9:777:17 | let ... = test | main.rs:777:13:777:16 | test | |
| main.rs:766:5:766:21 | ExprStmt | main.rs:766:5:766:18 | match_pattern1 | | | main.rs:776:13:776:22 | test_alias | main.rs:776:13:776:22 | test_alias | |
| main.rs:767:5:767:18 | match_pattern2 | main.rs:767:5:767:20 | match_pattern2(...) | | | main.rs:776:13:776:22 | test_alias | main.rs:778:9:779:25 | let ... = ... | match |
| main.rs:767:5:767:20 | match_pattern2(...) | main.rs:768:5:768:21 | ExprStmt | | | main.rs:777:13:777:16 | test | main.rs:776:13:776:22 | test_alias | |
| main.rs:767:5:767:21 | ExprStmt | main.rs:767:5:767:18 | match_pattern2 | | | main.rs:778:9:779:25 | let ... = ... | main.rs:779:13:779:22 | test_alias | |
| main.rs:768:5:768:18 | match_pattern3 | main.rs:768:5:768:20 | match_pattern3(...) | | | main.rs:778:13:778:16 | test | main.rs:778:13:778:16 | test | |
| main.rs:768:5:768:20 | match_pattern3(...) | main.rs:769:5:769:21 | ExprStmt | | | main.rs:778:13:778:16 | test | main.rs:780:9:780:12 | test | match |
| main.rs:768:5:768:21 | ExprStmt | main.rs:768:5:768:18 | match_pattern3 | | | main.rs:779:13:779:22 | test_alias | main.rs:779:13:779:24 | test_alias(...) | |
| main.rs:769:5:769:18 | match_pattern4 | main.rs:769:5:769:20 | match_pattern4(...) | | | main.rs:779:13:779:24 | test_alias(...) | main.rs:778:13:778:16 | test | |
| main.rs:769:5:769:20 | match_pattern4(...) | main.rs:770:5:770:21 | ExprStmt | | | main.rs:780:9:780:12 | test | main.rs:775:31:781:5 | { ... } | |
| main.rs:769:5:769:21 | ExprStmt | main.rs:769:5:769:18 | match_pattern4 | | | main.rs:785:5:798:5 | enter fn test3 | main.rs:787:9:787:24 | let ... = ... | |
| main.rs:770:5:770:18 | match_pattern5 | main.rs:770:5:770:20 | match_pattern5(...) | | | main.rs:785:5:798:5 | exit fn test3 (normal) | main.rs:785:5:798:5 | exit fn test3 | |
| main.rs:770:5:770:20 | match_pattern5(...) | main.rs:771:5:771:21 | ExprStmt | | | main.rs:786:16:798:5 | { ... } | main.rs:785:5:798:5 | exit fn test3 (normal) | |
| main.rs:770:5:770:21 | ExprStmt | main.rs:770:5:770:18 | match_pattern5 | | | main.rs:787:9:787:24 | let ... = ... | main.rs:787:17:787:20 | Some | |
| main.rs:771:5:771:18 | match_pattern6 | main.rs:771:5:771:20 | match_pattern6(...) | | | main.rs:787:13:787:13 | x | main.rs:787:13:787:13 | x | |
| main.rs:771:5:771:20 | match_pattern6(...) | main.rs:772:5:772:21 | ExprStmt | | | main.rs:787:13:787:13 | x | main.rs:788:9:792:10 | ExprStmt | match |
| main.rs:771:5:771:21 | ExprStmt | main.rs:771:5:771:18 | match_pattern6 | | | main.rs:787:17:787:20 | Some | main.rs:787:22:787:22 | 0 | |
| main.rs:772:5:772:18 | match_pattern7 | main.rs:772:5:772:20 | match_pattern7(...) | | | main.rs:787:17:787:23 | Some(...) | main.rs:787:13:787:13 | x | |
| main.rs:772:5:772:20 | match_pattern7(...) | main.rs:773:5:773:21 | ExprStmt | | | main.rs:787:22:787:22 | 0 | main.rs:787:17:787:23 | Some(...) | |
| main.rs:772:5:772:21 | ExprStmt | main.rs:772:5:772:18 | match_pattern7 | | | main.rs:788:9:792:9 | match x { ... } | main.rs:793:9:797:10 | ExprStmt | |
| main.rs:773:5:773:18 | match_pattern8 | main.rs:773:5:773:20 | match_pattern8(...) | | | main.rs:788:9:792:10 | ExprStmt | main.rs:788:15:788:15 | x | |
| main.rs:773:5:773:20 | match_pattern8(...) | main.rs:774:5:774:21 | ExprStmt | | | main.rs:788:15:788:15 | x | main.rs:789:13:789:19 | Some(...) | |
| main.rs:773:5:773:21 | ExprStmt | main.rs:773:5:773:18 | match_pattern8 | | | main.rs:789:13:789:19 | Some(...) | main.rs:789:18:789:18 | x | match |
| main.rs:774:5:774:18 | match_pattern9 | main.rs:774:5:774:20 | match_pattern9(...) | | | main.rs:789:13:789:19 | Some(...) | main.rs:791:13:791:13 | _ | no-match |
| main.rs:774:5:774:20 | match_pattern9(...) | main.rs:775:5:775:22 | ExprStmt | | | main.rs:789:18:789:18 | x | main.rs:789:18:789:18 | x | |
| main.rs:774:5:774:21 | ExprStmt | main.rs:774:5:774:18 | match_pattern9 | | | main.rs:789:18:789:18 | x | main.rs:790:20:790:20 | x | match |
| main.rs:775:5:775:19 | match_pattern10 | main.rs:775:5:775:21 | match_pattern10(...) | | | main.rs:790:20:790:20 | x | main.rs:788:9:792:9 | match x { ... } | |
| main.rs:775:5:775:21 | match_pattern10(...) | main.rs:776:5:776:22 | ExprStmt | | | main.rs:791:13:791:13 | _ | main.rs:791:18:791:18 | 0 | match |
| main.rs:775:5:775:22 | ExprStmt | main.rs:775:5:775:19 | match_pattern10 | | | main.rs:791:18:791:18 | 0 | main.rs:788:9:792:9 | match x { ... } | |
| main.rs:776:5:776:19 | match_pattern11 | main.rs:776:5:776:21 | match_pattern11(...) | | | main.rs:793:9:797:9 | match x { ... } | main.rs:786:16:798:5 | { ... } | |
| main.rs:776:5:776:21 | match_pattern11(...) | main.rs:777:5:777:22 | ExprStmt | | | main.rs:793:9:797:10 | ExprStmt | main.rs:793:15:793:15 | x | |
| main.rs:776:5:776:22 | ExprStmt | main.rs:776:5:776:19 | match_pattern11 | | | main.rs:793:15:793:15 | x | main.rs:794:13:794:19 | Some(...) | |
| main.rs:777:5:777:19 | match_pattern12 | main.rs:777:5:777:21 | match_pattern12(...) | | | main.rs:794:13:794:19 | Some(...) | main.rs:794:18:794:18 | z | match |
| main.rs:777:5:777:21 | match_pattern12(...) | main.rs:778:5:778:22 | ExprStmt | | | main.rs:794:13:794:19 | Some(...) | main.rs:796:13:796:13 | _ | no-match |
| main.rs:777:5:777:22 | ExprStmt | main.rs:777:5:777:19 | match_pattern12 | | | main.rs:794:18:794:18 | z | main.rs:794:18:794:18 | z | |
| main.rs:778:5:778:19 | match_pattern13 | main.rs:778:5:778:21 | match_pattern13(...) | | | main.rs:794:18:794:18 | z | main.rs:795:17:795:17 | z | match |
| main.rs:778:5:778:21 | match_pattern13(...) | main.rs:779:5:779:22 | ExprStmt | | | main.rs:794:18:794:18 | z | main.rs:796:13:796:13 | _ | no-match |
| main.rs:778:5:778:22 | ExprStmt | main.rs:778:5:778:19 | match_pattern13 | | | main.rs:795:17:795:17 | z | main.rs:793:9:797:9 | match x { ... } | |
| main.rs:779:5:779:19 | match_pattern14 | main.rs:779:5:779:21 | match_pattern14(...) | | | main.rs:796:13:796:13 | _ | main.rs:796:18:796:18 | 0 | match |
| main.rs:779:5:779:21 | match_pattern14(...) | main.rs:780:5:780:22 | ExprStmt | | | main.rs:796:18:796:18 | 0 | main.rs:793:9:797:9 | match x { ... } | |
| main.rs:779:5:779:22 | ExprStmt | main.rs:779:5:779:19 | match_pattern14 | | | main.rs:801:1:845:1 | enter fn main | main.rs:802:5:802:25 | ExprStmt | |
| main.rs:780:5:780:19 | match_pattern15 | main.rs:780:5:780:21 | match_pattern15(...) | | | main.rs:801:1:845:1 | exit fn main (normal) | main.rs:801:1:845:1 | exit fn main | |
| main.rs:780:5:780:21 | match_pattern15(...) | main.rs:781:5:781:22 | ExprStmt | | | main.rs:801:11:845:1 | { ... } | main.rs:801:1:845:1 | exit fn main (normal) | |
| main.rs:780:5:780:22 | ExprStmt | main.rs:780:5:780:19 | match_pattern15 | | | main.rs:802:5:802:22 | immutable_variable | main.rs:802:5:802:24 | immutable_variable(...) | |
| main.rs:781:5:781:19 | match_pattern16 | main.rs:781:5:781:21 | match_pattern16(...) | | | main.rs:802:5:802:24 | immutable_variable(...) | main.rs:803:5:803:23 | ExprStmt | |
| main.rs:781:5:781:21 | match_pattern16(...) | main.rs:782:5:782:36 | ExprStmt | | | main.rs:802:5:802:25 | ExprStmt | main.rs:802:5:802:22 | immutable_variable | |
| main.rs:781:5:781:22 | ExprStmt | main.rs:781:5:781:19 | match_pattern16 | | | main.rs:803:5:803:20 | mutable_variable | main.rs:803:5:803:22 | mutable_variable(...) | |
| main.rs:782:5:782:18 | param_pattern1 | main.rs:782:20:782:22 | "a" | | | main.rs:803:5:803:22 | mutable_variable(...) | main.rs:804:5:804:40 | ExprStmt | |
| main.rs:782:5:782:35 | param_pattern1(...) | main.rs:783:5:783:37 | ExprStmt | | | main.rs:803:5:803:23 | ExprStmt | main.rs:803:5:803:20 | mutable_variable | |
| main.rs:782:5:782:36 | ExprStmt | main.rs:782:5:782:18 | param_pattern1 | | | main.rs:804:5:804:37 | mutable_variable_immutable_borrow | main.rs:804:5:804:39 | mutable_variable_immutable_borrow(...) | |
| main.rs:782:20:782:22 | "a" | main.rs:782:26:782:28 | "b" | | | main.rs:804:5:804:39 | mutable_variable_immutable_borrow(...) | main.rs:805:5:805:23 | ExprStmt | |
| main.rs:782:25:782:34 | TupleExpr | main.rs:782:5:782:35 | param_pattern1(...) | | | main.rs:804:5:804:40 | ExprStmt | main.rs:804:5:804:37 | mutable_variable_immutable_borrow | |
| main.rs:782:26:782:28 | "b" | main.rs:782:31:782:33 | "c" | | | main.rs:805:5:805:20 | variable_shadow1 | main.rs:805:5:805:22 | variable_shadow1(...) | |
| main.rs:782:31:782:33 | "c" | main.rs:782:25:782:34 | TupleExpr | | | main.rs:805:5:805:22 | variable_shadow1(...) | main.rs:806:5:806:23 | ExprStmt | |
| main.rs:783:5:783:18 | param_pattern2 | main.rs:783:20:783:31 | ...::Left | | | main.rs:805:5:805:23 | ExprStmt | main.rs:805:5:805:20 | variable_shadow1 | |
| main.rs:783:5:783:36 | param_pattern2(...) | main.rs:784:5:784:26 | ExprStmt | | | main.rs:806:5:806:20 | variable_shadow2 | main.rs:806:5:806:22 | variable_shadow2(...) | |
| main.rs:783:5:783:37 | ExprStmt | main.rs:783:5:783:18 | param_pattern2 | | | main.rs:806:5:806:22 | variable_shadow2(...) | main.rs:807:5:807:19 | ExprStmt | |
| main.rs:783:20:783:31 | ...::Left | main.rs:783:33:783:34 | 45 | | | main.rs:806:5:806:23 | ExprStmt | main.rs:806:5:806:20 | variable_shadow2 | |
| main.rs:783:20:783:35 | ...::Left(...) | main.rs:783:5:783:36 | param_pattern2(...) | | | main.rs:807:5:807:16 | let_pattern1 | main.rs:807:5:807:18 | let_pattern1(...) | |
| main.rs:783:33:783:34 | 45 | main.rs:783:20:783:35 | ...::Left(...) | | | main.rs:807:5:807:18 | let_pattern1(...) | main.rs:808:5:808:19 | ExprStmt | |
| main.rs:784:5:784:23 | destruct_assignment | main.rs:784:5:784:25 | destruct_assignment(...) | | | main.rs:807:5:807:19 | ExprStmt | main.rs:807:5:807:16 | let_pattern1 | |
| main.rs:784:5:784:25 | destruct_assignment(...) | main.rs:785:5:785:23 | ExprStmt | | | main.rs:808:5:808:16 | let_pattern2 | main.rs:808:5:808:18 | let_pattern2(...) | |
| main.rs:784:5:784:26 | ExprStmt | main.rs:784:5:784:23 | destruct_assignment | | | main.rs:808:5:808:18 | let_pattern2(...) | main.rs:809:5:809:19 | ExprStmt | |
| main.rs:785:5:785:20 | closure_variable | main.rs:785:5:785:22 | closure_variable(...) | | | main.rs:808:5:808:19 | ExprStmt | main.rs:808:5:808:16 | let_pattern2 | |
| main.rs:785:5:785:22 | closure_variable(...) | main.rs:786:5:786:22 | ExprStmt | | | main.rs:809:5:809:16 | let_pattern3 | main.rs:809:5:809:18 | let_pattern3(...) | |
| main.rs:785:5:785:23 | ExprStmt | main.rs:785:5:785:20 | closure_variable | | | main.rs:809:5:809:18 | let_pattern3(...) | main.rs:810:5:810:19 | ExprStmt | |
| main.rs:786:5:786:19 | nested_function | main.rs:786:5:786:21 | nested_function(...) | | | main.rs:809:5:809:19 | ExprStmt | main.rs:809:5:809:16 | let_pattern3 | |
| main.rs:786:5:786:21 | nested_function(...) | main.rs:787:5:787:19 | ExprStmt | | | main.rs:810:5:810:16 | let_pattern4 | main.rs:810:5:810:18 | let_pattern4(...) | |
| main.rs:786:5:786:22 | ExprStmt | main.rs:786:5:786:19 | nested_function | | | main.rs:810:5:810:18 | let_pattern4(...) | main.rs:811:5:811:21 | ExprStmt | |
| main.rs:787:5:787:16 | for_variable | main.rs:787:5:787:18 | for_variable(...) | | | main.rs:810:5:810:19 | ExprStmt | main.rs:810:5:810:16 | let_pattern4 | |
| main.rs:787:5:787:18 | for_variable(...) | main.rs:788:5:788:17 | ExprStmt | | | main.rs:811:5:811:18 | match_pattern1 | main.rs:811:5:811:20 | match_pattern1(...) | |
| main.rs:787:5:787:19 | ExprStmt | main.rs:787:5:787:16 | for_variable | | | main.rs:811:5:811:20 | match_pattern1(...) | main.rs:812:5:812:21 | ExprStmt | |
| main.rs:788:5:788:14 | add_assign | main.rs:788:5:788:16 | add_assign(...) | | | main.rs:811:5:811:21 | ExprStmt | main.rs:811:5:811:18 | match_pattern1 | |
| main.rs:788:5:788:16 | add_assign(...) | main.rs:789:5:789:13 | ExprStmt | | | main.rs:812:5:812:18 | match_pattern2 | main.rs:812:5:812:20 | match_pattern2(...) | |
| main.rs:788:5:788:17 | ExprStmt | main.rs:788:5:788:14 | add_assign | | | main.rs:812:5:812:20 | match_pattern2(...) | main.rs:813:5:813:21 | ExprStmt | |
| main.rs:789:5:789:10 | mutate | main.rs:789:5:789:12 | mutate(...) | | | main.rs:812:5:812:21 | ExprStmt | main.rs:812:5:812:18 | match_pattern2 | |
| main.rs:789:5:789:12 | mutate(...) | main.rs:790:5:790:17 | ExprStmt | | | main.rs:813:5:813:18 | match_pattern3 | main.rs:813:5:813:20 | match_pattern3(...) | |
| main.rs:789:5:789:13 | ExprStmt | main.rs:789:5:789:10 | mutate | | | main.rs:813:5:813:20 | match_pattern3(...) | main.rs:814:5:814:21 | ExprStmt | |
| main.rs:790:5:790:14 | mutate_arg | main.rs:790:5:790:16 | mutate_arg(...) | | | main.rs:813:5:813:21 | ExprStmt | main.rs:813:5:813:18 | match_pattern3 | |
| main.rs:790:5:790:16 | mutate_arg(...) | main.rs:791:5:791:12 | ExprStmt | | | main.rs:814:5:814:18 | match_pattern4 | main.rs:814:5:814:20 | match_pattern4(...) | |
| main.rs:790:5:790:17 | ExprStmt | main.rs:790:5:790:14 | mutate_arg | | | main.rs:814:5:814:20 | match_pattern4(...) | main.rs:815:5:815:21 | ExprStmt | |
| main.rs:791:5:791:9 | alias | main.rs:791:5:791:11 | alias(...) | | | main.rs:814:5:814:21 | ExprStmt | main.rs:814:5:814:18 | match_pattern4 | |
| main.rs:791:5:791:11 | alias(...) | main.rs:792:5:792:18 | ExprStmt | | | main.rs:815:5:815:18 | match_pattern5 | main.rs:815:5:815:20 | match_pattern5(...) | |
| main.rs:791:5:791:12 | ExprStmt | main.rs:791:5:791:9 | alias | | | main.rs:815:5:815:20 | match_pattern5(...) | main.rs:816:5:816:21 | ExprStmt | |
| main.rs:792:5:792:15 | capture_mut | main.rs:792:5:792:17 | capture_mut(...) | | | main.rs:815:5:815:21 | ExprStmt | main.rs:815:5:815:18 | match_pattern5 | |
| main.rs:792:5:792:17 | capture_mut(...) | main.rs:793:5:793:20 | ExprStmt | | | main.rs:816:5:816:18 | match_pattern6 | main.rs:816:5:816:20 | match_pattern6(...) | |
| main.rs:792:5:792:18 | ExprStmt | main.rs:792:5:792:15 | capture_mut | | | main.rs:816:5:816:20 | match_pattern6(...) | main.rs:817:5:817:21 | ExprStmt | |
| main.rs:793:5:793:17 | capture_immut | main.rs:793:5:793:19 | capture_immut(...) | | | main.rs:816:5:816:21 | ExprStmt | main.rs:816:5:816:18 | match_pattern6 | |
| main.rs:793:5:793:19 | capture_immut(...) | main.rs:794:5:794:26 | ExprStmt | | | main.rs:817:5:817:18 | match_pattern7 | main.rs:817:5:817:20 | match_pattern7(...) | |
| main.rs:793:5:793:20 | ExprStmt | main.rs:793:5:793:17 | capture_immut | | | main.rs:817:5:817:20 | match_pattern7(...) | main.rs:818:5:818:21 | ExprStmt | |
| main.rs:794:5:794:23 | async_block_capture | main.rs:794:5:794:25 | async_block_capture(...) | | | main.rs:817:5:817:21 | ExprStmt | main.rs:817:5:817:18 | match_pattern7 | |
| main.rs:794:5:794:25 | async_block_capture(...) | main.rs:795:5:795:14 | ExprStmt | | | main.rs:818:5:818:18 | match_pattern8 | main.rs:818:5:818:20 | match_pattern8(...) | |
| main.rs:794:5:794:26 | ExprStmt | main.rs:794:5:794:23 | async_block_capture | | | main.rs:818:5:818:20 | match_pattern8(...) | main.rs:819:5:819:21 | ExprStmt | |
| main.rs:795:5:795:11 | structs | main.rs:795:5:795:13 | structs(...) | | | main.rs:818:5:818:21 | ExprStmt | main.rs:818:5:818:18 | match_pattern8 | |
| main.rs:795:5:795:13 | structs(...) | main.rs:796:5:796:14 | ExprStmt | | | main.rs:819:5:819:18 | match_pattern9 | main.rs:819:5:819:20 | match_pattern9(...) | |
| main.rs:795:5:795:14 | ExprStmt | main.rs:795:5:795:11 | structs | | | main.rs:819:5:819:20 | match_pattern9(...) | main.rs:820:5:820:22 | ExprStmt | |
| main.rs:796:5:796:11 | ref_arg | main.rs:796:5:796:13 | ref_arg(...) | | | main.rs:819:5:819:21 | ExprStmt | main.rs:819:5:819:18 | match_pattern9 | |
| main.rs:796:5:796:13 | ref_arg(...) | main.rs:797:5:797:30 | ExprStmt | | | main.rs:820:5:820:19 | match_pattern10 | main.rs:820:5:820:21 | match_pattern10(...) | |
| main.rs:796:5:796:14 | ExprStmt | main.rs:796:5:796:11 | ref_arg | | | main.rs:820:5:820:21 | match_pattern10(...) | main.rs:821:5:821:22 | ExprStmt | |
| main.rs:797:5:797:27 | ref_methodcall_receiver | main.rs:797:5:797:29 | ref_methodcall_receiver(...) | | | main.rs:820:5:820:22 | ExprStmt | main.rs:820:5:820:19 | match_pattern10 | |
| main.rs:797:5:797:29 | ref_methodcall_receiver(...) | main.rs:798:5:798:23 | ExprStmt | | | main.rs:821:5:821:19 | match_pattern11 | main.rs:821:5:821:21 | match_pattern11(...) | |
| main.rs:797:5:797:30 | ExprStmt | main.rs:797:5:797:27 | ref_methodcall_receiver | | | main.rs:821:5:821:21 | match_pattern11(...) | main.rs:822:5:822:22 | ExprStmt | |
| main.rs:798:5:798:20 | macro_invocation | main.rs:798:5:798:22 | macro_invocation(...) | | | main.rs:821:5:821:22 | ExprStmt | main.rs:821:5:821:19 | match_pattern11 | |
| main.rs:798:5:798:22 | macro_invocation(...) | main.rs:799:5:799:18 | ExprStmt | | | main.rs:822:5:822:19 | match_pattern12 | main.rs:822:5:822:21 | match_pattern12(...) | |
| main.rs:798:5:798:23 | ExprStmt | main.rs:798:5:798:20 | macro_invocation | | | main.rs:822:5:822:21 | match_pattern12(...) | main.rs:823:5:823:22 | ExprStmt | |
| main.rs:799:5:799:15 | capture_phi | main.rs:799:5:799:17 | capture_phi(...) | | | main.rs:822:5:822:22 | ExprStmt | main.rs:822:5:822:19 | match_pattern12 | |
| main.rs:799:5:799:17 | capture_phi(...) | main.rs:756:11:800:1 | { ... } | | | main.rs:823:5:823:19 | match_pattern13 | main.rs:823:5:823:21 | match_pattern13(...) | |
| main.rs:799:5:799:18 | ExprStmt | main.rs:799:5:799:15 | capture_phi | | | main.rs:823:5:823:21 | match_pattern13(...) | main.rs:824:5:824:22 | ExprStmt | |
| main.rs:823:5:823:22 | ExprStmt | main.rs:823:5:823:19 | match_pattern13 | |
| main.rs:824:5:824:19 | match_pattern14 | main.rs:824:5:824:21 | match_pattern14(...) | |
| main.rs:824:5:824:21 | match_pattern14(...) | main.rs:825:5:825:22 | ExprStmt | |
| main.rs:824:5:824:22 | ExprStmt | main.rs:824:5:824:19 | match_pattern14 | |
| main.rs:825:5:825:19 | match_pattern15 | main.rs:825:5:825:21 | match_pattern15(...) | |
| main.rs:825:5:825:21 | match_pattern15(...) | main.rs:826:5:826:22 | ExprStmt | |
| main.rs:825:5:825:22 | ExprStmt | main.rs:825:5:825:19 | match_pattern15 | |
| main.rs:826:5:826:19 | match_pattern16 | main.rs:826:5:826:21 | match_pattern16(...) | |
| main.rs:826:5:826:21 | match_pattern16(...) | main.rs:827:5:827:36 | ExprStmt | |
| main.rs:826:5:826:22 | ExprStmt | main.rs:826:5:826:19 | match_pattern16 | |
| main.rs:827:5:827:18 | param_pattern1 | main.rs:827:20:827:22 | "a" | |
| main.rs:827:5:827:35 | param_pattern1(...) | main.rs:828:5:828:37 | ExprStmt | |
| main.rs:827:5:827:36 | ExprStmt | main.rs:827:5:827:18 | param_pattern1 | |
| main.rs:827:20:827:22 | "a" | main.rs:827:26:827:28 | "b" | |
| main.rs:827:25:827:34 | TupleExpr | main.rs:827:5:827:35 | param_pattern1(...) | |
| main.rs:827:26:827:28 | "b" | main.rs:827:31:827:33 | "c" | |
| main.rs:827:31:827:33 | "c" | main.rs:827:25:827:34 | TupleExpr | |
| main.rs:828:5:828:18 | param_pattern2 | main.rs:828:20:828:31 | ...::Left | |
| main.rs:828:5:828:36 | param_pattern2(...) | main.rs:829:5:829:26 | ExprStmt | |
| main.rs:828:5:828:37 | ExprStmt | main.rs:828:5:828:18 | param_pattern2 | |
| main.rs:828:20:828:31 | ...::Left | main.rs:828:33:828:34 | 45 | |
| main.rs:828:20:828:35 | ...::Left(...) | main.rs:828:5:828:36 | param_pattern2(...) | |
| main.rs:828:33:828:34 | 45 | main.rs:828:20:828:35 | ...::Left(...) | |
| main.rs:829:5:829:23 | destruct_assignment | main.rs:829:5:829:25 | destruct_assignment(...) | |
| main.rs:829:5:829:25 | destruct_assignment(...) | main.rs:830:5:830:23 | ExprStmt | |
| main.rs:829:5:829:26 | ExprStmt | main.rs:829:5:829:23 | destruct_assignment | |
| main.rs:830:5:830:20 | closure_variable | main.rs:830:5:830:22 | closure_variable(...) | |
| main.rs:830:5:830:22 | closure_variable(...) | main.rs:831:5:831:22 | ExprStmt | |
| main.rs:830:5:830:23 | ExprStmt | main.rs:830:5:830:20 | closure_variable | |
| main.rs:831:5:831:19 | nested_function | main.rs:831:5:831:21 | nested_function(...) | |
| main.rs:831:5:831:21 | nested_function(...) | main.rs:832:5:832:19 | ExprStmt | |
| main.rs:831:5:831:22 | ExprStmt | main.rs:831:5:831:19 | nested_function | |
| main.rs:832:5:832:16 | for_variable | main.rs:832:5:832:18 | for_variable(...) | |
| main.rs:832:5:832:18 | for_variable(...) | main.rs:833:5:833:17 | ExprStmt | |
| main.rs:832:5:832:19 | ExprStmt | main.rs:832:5:832:16 | for_variable | |
| main.rs:833:5:833:14 | add_assign | main.rs:833:5:833:16 | add_assign(...) | |
| main.rs:833:5:833:16 | add_assign(...) | main.rs:834:5:834:13 | ExprStmt | |
| main.rs:833:5:833:17 | ExprStmt | main.rs:833:5:833:14 | add_assign | |
| main.rs:834:5:834:10 | mutate | main.rs:834:5:834:12 | mutate(...) | |
| main.rs:834:5:834:12 | mutate(...) | main.rs:835:5:835:17 | ExprStmt | |
| main.rs:834:5:834:13 | ExprStmt | main.rs:834:5:834:10 | mutate | |
| main.rs:835:5:835:14 | mutate_arg | main.rs:835:5:835:16 | mutate_arg(...) | |
| main.rs:835:5:835:16 | mutate_arg(...) | main.rs:836:5:836:12 | ExprStmt | |
| main.rs:835:5:835:17 | ExprStmt | main.rs:835:5:835:14 | mutate_arg | |
| main.rs:836:5:836:9 | alias | main.rs:836:5:836:11 | alias(...) | |
| main.rs:836:5:836:11 | alias(...) | main.rs:837:5:837:18 | ExprStmt | |
| main.rs:836:5:836:12 | ExprStmt | main.rs:836:5:836:9 | alias | |
| main.rs:837:5:837:15 | capture_mut | main.rs:837:5:837:17 | capture_mut(...) | |
| main.rs:837:5:837:17 | capture_mut(...) | main.rs:838:5:838:20 | ExprStmt | |
| main.rs:837:5:837:18 | ExprStmt | main.rs:837:5:837:15 | capture_mut | |
| main.rs:838:5:838:17 | capture_immut | main.rs:838:5:838:19 | capture_immut(...) | |
| main.rs:838:5:838:19 | capture_immut(...) | main.rs:839:5:839:26 | ExprStmt | |
| main.rs:838:5:838:20 | ExprStmt | main.rs:838:5:838:17 | capture_immut | |
| main.rs:839:5:839:23 | async_block_capture | main.rs:839:5:839:25 | async_block_capture(...) | |
| main.rs:839:5:839:25 | async_block_capture(...) | main.rs:840:5:840:14 | ExprStmt | |
| main.rs:839:5:839:26 | ExprStmt | main.rs:839:5:839:23 | async_block_capture | |
| main.rs:840:5:840:11 | structs | main.rs:840:5:840:13 | structs(...) | |
| main.rs:840:5:840:13 | structs(...) | main.rs:841:5:841:14 | ExprStmt | |
| main.rs:840:5:840:14 | ExprStmt | main.rs:840:5:840:11 | structs | |
| main.rs:841:5:841:11 | ref_arg | main.rs:841:5:841:13 | ref_arg(...) | |
| main.rs:841:5:841:13 | ref_arg(...) | main.rs:842:5:842:30 | ExprStmt | |
| main.rs:841:5:841:14 | ExprStmt | main.rs:841:5:841:11 | ref_arg | |
| main.rs:842:5:842:27 | ref_methodcall_receiver | main.rs:842:5:842:29 | ref_methodcall_receiver(...) | |
| main.rs:842:5:842:29 | ref_methodcall_receiver(...) | main.rs:843:5:843:23 | ExprStmt | |
| main.rs:842:5:842:30 | ExprStmt | main.rs:842:5:842:27 | ref_methodcall_receiver | |
| main.rs:843:5:843:20 | macro_invocation | main.rs:843:5:843:22 | macro_invocation(...) | |
| main.rs:843:5:843:22 | macro_invocation(...) | main.rs:844:5:844:18 | ExprStmt | |
| main.rs:843:5:843:23 | ExprStmt | main.rs:843:5:843:20 | macro_invocation | |
| main.rs:844:5:844:15 | capture_phi | main.rs:844:5:844:17 | capture_phi(...) | |
| main.rs:844:5:844:17 | capture_phi(...) | main.rs:801:11:845:1 | { ... } | |
| main.rs:844:5:844:18 | ExprStmt | main.rs:844:5:844:15 | capture_phi | |
breakTarget breakTarget
| main.rs:326:9:326:13 | break | main.rs:317:5:327:5 | while ... { ... } | | main.rs:326:9:326:13 | break | main.rs:317:5:327:5 | while ... { ... } |
continueTarget continueTarget

View File

@@ -196,6 +196,13 @@ definition
| main.rs:748:17:750:9 | SSA phi(x) | main.rs:745:13:745:13 | x | | main.rs:748:17:750:9 | SSA phi(x) | main.rs:745:13:745:13 | x |
| main.rs:749:13:749:13 | x | main.rs:745:13:745:13 | x | | main.rs:749:13:749:13 | x | main.rs:745:13:745:13 | x |
| main.rs:752:5:752:13 | <captured exit> x | main.rs:745:13:745:13 | x | | main.rs:752:5:752:13 | <captured exit> x | main.rs:745:13:745:13 | x |
| main.rs:759:13:759:13 | x | main.rs:759:13:759:13 | x |
| main.rs:760:13:760:13 | y | main.rs:760:13:760:13 | y |
| main.rs:769:13:769:16 | N0ne | main.rs:769:13:769:16 | N0ne |
| main.rs:776:13:776:22 | test_alias | main.rs:776:13:776:22 | test_alias |
| main.rs:778:13:778:16 | test | main.rs:778:13:778:16 | test |
| main.rs:787:13:787:13 | x | main.rs:787:13:787:13 | x |
| main.rs:789:18:789:18 | x | main.rs:789:18:789:18 | x |
read read
| main.rs:5:14:5:14 | s | main.rs:5:14:5:14 | s | main.rs:7:20:7:20 | s | | main.rs:5:14:5:14 | s | main.rs:5:14:5:14 | s | main.rs:7:20:7:20 | s |
| main.rs:10:14:10:14 | i | main.rs:10:14:10:14 | i | main.rs:12:20:12:20 | i | | main.rs:10:14:10:14 | i | main.rs:10:14:10:14 | i | main.rs:12:20:12:20 | i |
@@ -404,6 +411,14 @@ read
| main.rs:746:13:746:15 | cap | main.rs:746:13:746:15 | cap | main.rs:752:5:752:7 | cap | | main.rs:746:13:746:15 | cap | main.rs:746:13:746:15 | cap | main.rs:752:5:752:7 | cap |
| main.rs:746:20:746:20 | b | main.rs:746:20:746:20 | b | main.rs:748:20:748:20 | b | | main.rs:746:20:746:20 | b | main.rs:746:20:746:20 | b | main.rs:748:20:748:20 | b |
| main.rs:752:5:752:13 | <captured exit> x | main.rs:745:13:745:13 | x | main.rs:753:15:753:15 | x | | main.rs:752:5:752:13 | <captured exit> x | main.rs:745:13:745:13 | x | main.rs:753:15:753:15 | x |
| main.rs:759:13:759:13 | x | main.rs:759:13:759:13 | x | main.rs:761:19:761:19 | x |
| main.rs:760:13:760:13 | y | main.rs:760:13:760:13 | y | main.rs:768:15:768:15 | y |
| main.rs:769:13:769:16 | N0ne | main.rs:769:13:769:16 | N0ne | main.rs:770:17:770:20 | N0ne |
| main.rs:776:13:776:22 | test_alias | main.rs:776:13:776:22 | test_alias | main.rs:779:13:779:22 | test_alias |
| main.rs:778:13:778:16 | test | main.rs:778:13:778:16 | test | main.rs:780:9:780:12 | test |
| main.rs:787:13:787:13 | x | main.rs:787:13:787:13 | x | main.rs:788:15:788:15 | x |
| main.rs:787:13:787:13 | x | main.rs:787:13:787:13 | x | main.rs:793:15:793:15 | x |
| main.rs:789:18:789:18 | x | main.rs:789:18:789:18 | x | main.rs:790:20:790:20 | x |
firstRead firstRead
| main.rs:5:14:5:14 | s | main.rs:5:14:5:14 | s | main.rs:7:20:7:20 | s | | main.rs:5:14:5:14 | s | main.rs:5:14:5:14 | s | main.rs:7:20:7:20 | s |
| main.rs:10:14:10:14 | i | main.rs:10:14:10:14 | i | main.rs:12:20:12:20 | i | | main.rs:10:14:10:14 | i | main.rs:10:14:10:14 | i | main.rs:12:20:12:20 | i |
@@ -570,6 +585,13 @@ firstRead
| main.rs:746:13:746:15 | cap | main.rs:746:13:746:15 | cap | main.rs:752:5:752:7 | cap | | main.rs:746:13:746:15 | cap | main.rs:746:13:746:15 | cap | main.rs:752:5:752:7 | cap |
| main.rs:746:20:746:20 | b | main.rs:746:20:746:20 | b | main.rs:748:20:748:20 | b | | main.rs:746:20:746:20 | b | main.rs:746:20:746:20 | b | main.rs:748:20:748:20 | b |
| main.rs:752:5:752:13 | <captured exit> x | main.rs:745:13:745:13 | x | main.rs:753:15:753:15 | x | | main.rs:752:5:752:13 | <captured exit> x | main.rs:745:13:745:13 | x | main.rs:753:15:753:15 | x |
| main.rs:759:13:759:13 | x | main.rs:759:13:759:13 | x | main.rs:761:19:761:19 | x |
| main.rs:760:13:760:13 | y | main.rs:760:13:760:13 | y | main.rs:768:15:768:15 | y |
| main.rs:769:13:769:16 | N0ne | main.rs:769:13:769:16 | N0ne | main.rs:770:17:770:20 | N0ne |
| main.rs:776:13:776:22 | test_alias | main.rs:776:13:776:22 | test_alias | main.rs:779:13:779:22 | test_alias |
| main.rs:778:13:778:16 | test | main.rs:778:13:778:16 | test | main.rs:780:9:780:12 | test |
| main.rs:787:13:787:13 | x | main.rs:787:13:787:13 | x | main.rs:788:15:788:15 | x |
| main.rs:789:18:789:18 | x | main.rs:789:18:789:18 | x | main.rs:790:20:790:20 | x |
adjacentReads adjacentReads
| main.rs:27:5:27:6 | x2 | main.rs:25:13:25:14 | x2 | main.rs:28:15:28:16 | x2 | main.rs:29:10:29:11 | x2 | | main.rs:27:5:27:6 | x2 | main.rs:25:13:25:14 | x2 | main.rs:28:15:28:16 | x2 | main.rs:29:10:29:11 | x2 |
| main.rs:41:9:41:10 | x3 | main.rs:41:9:41:10 | x3 | main.rs:42:15:42:16 | x3 | main.rs:44:9:44:10 | x3 | | main.rs:41:9:41:10 | x3 | main.rs:41:9:41:10 | x3 | main.rs:42:15:42:16 | x3 | main.rs:44:9:44:10 | x3 |
@@ -616,6 +638,7 @@ adjacentReads
| main.rs:676:13:676:13 | a | main.rs:676:13:676:13 | a | main.rs:677:15:677:15 | a | main.rs:678:5:678:5 | a | | main.rs:676:13:676:13 | a | main.rs:676:13:676:13 | a | main.rs:677:15:677:15 | a | main.rs:678:5:678:5 | a |
| main.rs:676:13:676:13 | a | main.rs:676:13:676:13 | a | main.rs:678:5:678:5 | a | main.rs:679:15:679:15 | a | | main.rs:676:13:676:13 | a | main.rs:676:13:676:13 | a | main.rs:678:5:678:5 | a | main.rs:679:15:679:15 | a |
| main.rs:685:9:685:9 | x | main.rs:685:9:685:9 | x | main.rs:686:20:686:20 | x | main.rs:687:15:687:15 | x | | main.rs:685:9:685:9 | x | main.rs:685:9:685:9 | x | main.rs:686:20:686:20 | x | main.rs:687:15:687:15 | x |
| main.rs:787:13:787:13 | x | main.rs:787:13:787:13 | x | main.rs:788:15:788:15 | x | main.rs:793:15:793:15 | x |
phi phi
| main.rs:210:9:210:44 | SSA phi(a3) | main.rs:210:9:210:44 | a3 | main.rs:210:22:210:23 | a3 | | main.rs:210:9:210:44 | SSA phi(a3) | main.rs:210:9:210:44 | a3 | main.rs:210:22:210:23 | a3 |
| main.rs:210:9:210:44 | SSA phi(a3) | main.rs:210:9:210:44 | a3 | main.rs:210:42:210:43 | a3 | | main.rs:210:9:210:44 | SSA phi(a3) | main.rs:210:9:210:44 | a3 | main.rs:210:42:210:43 | a3 |
@@ -773,3 +796,8 @@ assigns
| main.rs:745:13:745:13 | x | main.rs:745:17:745:19 | 100 | | main.rs:745:13:745:13 | x | main.rs:745:17:745:19 | 100 |
| main.rs:746:13:746:15 | cap | main.rs:746:19:751:5 | \|...\| ... | | main.rs:746:13:746:15 | cap | main.rs:746:19:751:5 | \|...\| ... |
| main.rs:749:13:749:13 | x | main.rs:749:17:749:19 | 200 | | main.rs:749:13:749:13 | x | main.rs:749:17:749:19 | 200 |
| main.rs:759:13:759:13 | x | main.rs:759:17:759:24 | Some(...) |
| main.rs:760:13:760:13 | y | main.rs:761:13:767:9 | match x { ... } |
| main.rs:776:13:776:22 | test_alias | main.rs:777:13:777:16 | test |
| main.rs:778:13:778:16 | test | main.rs:779:13:779:24 | test_alias(...) |
| main.rs:787:13:787:13 | x | main.rs:787:17:787:23 | Some(...) |

View File

@@ -753,6 +753,51 @@ fn capture_phi() {
print_i64(x); // $ read_access=x print_i64(x); // $ read_access=x
} }
mod patterns {
#[rustfmt::skip]
pub fn test() -> Option<i32> {
let x = Some(42); // x
let y : Option<i32> = // y1
match x { // $ read_access=x
Some(y) => { // y2
None
}
None =>
None
};
match y { // $ read_access=y1
N0ne => // n0ne
N0ne // $ read_access=n0ne
}
}
#[rustfmt::skip]
fn test2() -> Option<i32> {
let test_alias = // test_alias
test;
let test = // test
test_alias(); // $ read_access=test_alias
test // $ read_access=test
}
const z: i32 = 0;
#[rustfmt::skip]
fn test3() {
let x = Some(0); // x1
match x { // $ read_access=x1
Some(x) // x2
=> x, // $ read_access=x2
_ => 0
};
match x { // $ read_access=x1
Some(z) =>
z,
_ => 0
};
}
}
fn main() { fn main() {
immutable_variable(); immutable_variable();
mutable_variable(); mutable_variable();

Some files were not shown because too many files have changed in this diff Show More