diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index c994cab6bb2..de1b0a2660f 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -7,6 +7,7 @@ private import PathResolution private import Type private import Type as T private import TypeMention +private import typeinference.DerefChain private import typeinference.FunctionType private import typeinference.FunctionOverloading as FunctionOverloading private import typeinference.BlanketImplementation as BlanketImplementation @@ -1535,24 +1536,13 @@ private module MethodResolution { * Same as `getACandidateReceiverTypeAt`, but without borrows. */ pragma[nomagic] - private Type getACandidateReceiverTypeAtNoBorrow(string derefChain, TypePath path) { + Type getACandidateReceiverTypeAtNoBorrow(DerefChain derefChain, TypePath path) { result = this.getReceiverTypeAt(path) and derefChain = "" or - this.supportsAutoDerefAndBorrow() and - exists(TypePath path0, Type t0, string derefChain0 | - this.hasNoCompatibleTargetMutBorrow(derefChain0) and - t0 = this.getACandidateReceiverTypeAtNoBorrow(derefChain0, path0) - | - path0.isCons(getRefTypeParameter(_), path) and - result = t0 and - derefChain = derefChain0 + ".ref" - or - path0.isEmpty() and - path = path0 and - t0 = getStringStruct() and - result = getStrStruct() and - derefChain = derefChain0 + ".str" + exists(DerefImplItemNode impl, DerefChain suffix | + result = ImplicitDeref::getDereferencedCandidateReceiverType(this, impl, suffix, path) and + derefChain = DerefChain::cons(impl, suffix) ) } @@ -1566,7 +1556,7 @@ private module MethodResolution { */ pragma[nomagic] private predicate hasIncompatibleTarget( - ImplOrTraitItemNode i, string derefChain, BorrowKind borrow, Type root + ImplOrTraitItemNode i, DerefChain derefChain, BorrowKind borrow, Type root ) { exists(TypePath path | ReceiverIsInstantiationOfSelfParam::argIsNotInstantiationOf(MkMethodCallCand(this, @@ -1583,7 +1573,7 @@ private module MethodResolution { */ pragma[nomagic] private predicate hasIncompatibleBlanketLikeTarget( - ImplItemNode impl, string derefChain, BorrowKind borrow + ImplItemNode impl, DerefChain derefChain, BorrowKind borrow ) { ReceiverIsNotInstantiationOfBlanketLikeSelfParam::argIsNotInstantiationOf(MkMethodCallCand(this, derefChain, borrow), impl, _, _) @@ -1596,7 +1586,9 @@ private module MethodResolution { * Same as `getACandidateReceiverTypeAt`, but excludes pseudo types `!` and `unknown`. */ pragma[nomagic] - Type getANonPseudoCandidateReceiverTypeAt(string derefChain, BorrowKind borrow, TypePath path) { + Type getANonPseudoCandidateReceiverTypeAt( + DerefChain derefChain, BorrowKind borrow, TypePath path + ) { result = this.getACandidateReceiverTypeAt(derefChain, borrow, path) and result != TNeverType() and result != TUnknownType() @@ -1604,7 +1596,7 @@ private module MethodResolution { pragma[nomagic] private Type getComplexStrippedType( - string derefChain, BorrowKind borrow, TypePath strippedTypePath + DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath ) { result = this.getANonPseudoCandidateReceiverTypeAt(derefChain, borrow, strippedTypePath) and isComplexRootStripped(strippedTypePath, result) @@ -1612,7 +1604,7 @@ private module MethodResolution { bindingset[derefChain, borrow, strippedTypePath, strippedType] private predicate hasNoCompatibleNonBlanketLikeTargetCheck( - string derefChain, BorrowKind borrow, TypePath strippedTypePath, Type strippedType + DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, Type strippedType ) { forall(ImplOrTraitItemNode i | methodCallNonBlanketCandidate(this, _, i, _, strippedTypePath, strippedType) @@ -1623,7 +1615,7 @@ private module MethodResolution { bindingset[derefChain, borrow, strippedTypePath, strippedType] private predicate hasNoCompatibleTargetCheck( - string derefChain, BorrowKind borrow, TypePath strippedTypePath, Type strippedType + DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, Type strippedType ) { this.hasNoCompatibleNonBlanketLikeTargetCheck(derefChain, borrow, strippedTypePath, strippedType) and @@ -1634,7 +1626,7 @@ private module MethodResolution { bindingset[derefChain, borrow, strippedTypePath, strippedType] private predicate hasNoCompatibleNonBlanketTargetCheck( - string derefChain, BorrowKind borrow, TypePath strippedTypePath, Type strippedType + DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, Type strippedType ) { this.hasNoCompatibleNonBlanketLikeTargetCheck(derefChain, borrow, strippedTypePath, strippedType) and @@ -1648,7 +1640,7 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleTargetNoBorrowToIndex( - string derefChain, TypePath strippedTypePath, Type strippedType, int n + DerefChain derefChain, TypePath strippedTypePath, Type strippedType, int n ) { ( this.supportsAutoDerefAndBorrow() @@ -1671,7 +1663,7 @@ private module MethodResolution { * have a matching method target. */ pragma[nomagic] - predicate hasNoCompatibleTargetNoBorrow(string derefChain) { + predicate hasNoCompatibleTargetNoBorrow(DerefChain derefChain) { exists(Type strippedType | this.hasNoCompatibleTargetNoBorrowToIndex(derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) @@ -1681,7 +1673,7 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleNonBlanketTargetNoBorrowToIndex( - string derefChain, TypePath strippedTypePath, Type strippedType, int n + DerefChain derefChain, TypePath strippedTypePath, Type strippedType, int n ) { ( this.supportsAutoDerefAndBorrow() @@ -1705,7 +1697,7 @@ private module MethodResolution { * a matching non-blanket method target. */ pragma[nomagic] - predicate hasNoCompatibleNonBlanketTargetNoBorrow(string derefChain) { + predicate hasNoCompatibleNonBlanketTargetNoBorrow(DerefChain derefChain) { exists(Type strippedType | this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) @@ -1715,7 +1707,7 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleTargetSharedBorrowToIndex( - string derefChain, TypePath strippedTypePath, Type strippedType, int n + DerefChain derefChain, TypePath strippedTypePath, Type strippedType, int n ) { this.hasNoCompatibleTargetNoBorrow(derefChain) and strippedType = @@ -1735,7 +1727,7 @@ private module MethodResolution { * by a shared borrow, does not have a matching method target. */ pragma[nomagic] - predicate hasNoCompatibleTargetSharedBorrow(string derefChain) { + predicate hasNoCompatibleTargetSharedBorrow(DerefChain derefChain) { exists(Type strippedType | this.hasNoCompatibleTargetSharedBorrowToIndex(derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) @@ -1745,7 +1737,7 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleTargetMutBorrowToIndex( - string derefChain, TypePath strippedTypePath, Type strippedType, int n + DerefChain derefChain, TypePath strippedTypePath, Type strippedType, int n ) { this.hasNoCompatibleTargetSharedBorrow(derefChain) and strippedType = @@ -1764,7 +1756,7 @@ private module MethodResolution { * by a `mut` borrow, does not have a matching method target. */ pragma[nomagic] - predicate hasNoCompatibleTargetMutBorrow(string derefChain) { + predicate hasNoCompatibleTargetMutBorrow(DerefChain derefChain) { exists(Type strippedType | this.hasNoCompatibleTargetMutBorrowToIndex(derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) @@ -1774,7 +1766,7 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleNonBlanketTargetSharedBorrowToIndex( - string derefChain, TypePath strippedTypePath, Type strippedType, int n + DerefChain derefChain, TypePath strippedTypePath, Type strippedType, int n ) { this.hasNoCompatibleTargetNoBorrow(derefChain) and strippedType = @@ -1794,7 +1786,7 @@ private module MethodResolution { * by a shared borrow, does not have a matching non-blanket method target. */ pragma[nomagic] - predicate hasNoCompatibleNonBlanketTargetSharedBorrow(string derefChain) { + predicate hasNoCompatibleNonBlanketTargetSharedBorrow(DerefChain derefChain) { exists(Type strippedType | this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) @@ -1804,7 +1796,7 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleNonBlanketTargetMutBorrowToIndex( - string derefChain, TypePath strippedTypePath, Type strippedType, int n + DerefChain derefChain, TypePath strippedTypePath, Type strippedType, int n ) { this.hasNoCompatibleNonBlanketTargetSharedBorrow(derefChain) and strippedType = @@ -1824,7 +1816,7 @@ private module MethodResolution { * by a `mut` borrow, does not have a matching non-blanket method target. */ pragma[nomagic] - predicate hasNoCompatibleNonBlanketTargetMutBorrow(string derefChain) { + predicate hasNoCompatibleNonBlanketTargetMutBorrow(DerefChain derefChain) { exists(Type strippedType | this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) @@ -1844,7 +1836,7 @@ private module MethodResolution { * [1]: https://doc.rust-lang.org/reference/expressions/method-call-expr.html#r-expr.method.candidate-receivers */ pragma[nomagic] - Type getACandidateReceiverTypeAt(string derefChain, BorrowKind borrow, TypePath path) { + Type getACandidateReceiverTypeAt(DerefChain derefChain, BorrowKind borrow, TypePath path) { result = this.getACandidateReceiverTypeAtNoBorrow(derefChain, path) and borrow.isNoBorrow() or @@ -1877,21 +1869,24 @@ private module MethodResolution { * `derefChain` and the enum `borrow`. */ pragma[nomagic] - Method resolveCallTarget(ImplOrTraitItemNode i, string derefChain, BorrowKind borrow) { + Method resolveCallTarget(ImplOrTraitItemNode i, DerefChain derefChain, BorrowKind borrow) { exists(MethodCallCand mcc | mcc = MkMethodCallCand(this, derefChain, borrow) and result = mcc.resolveCallTarget(i) ) } - predicate receiverHasImplicitDeref(AstNode receiver) { - exists(this.resolveCallTarget(_, ".ref", TNoBorrowKind())) and - receiver = this.getArg(any(ArgumentPosition pos | pos.isSelf())) - } - - predicate argumentHasImplicitBorrow(AstNode arg, boolean isMutable) { - exists(this.resolveCallTarget(_, "", TSomeBorrowKind(isMutable))) and - arg = this.getArg(any(ArgumentPosition pos | pos.isSelf())) + /** + * Holds if the argument `arg` of this call has been implicitly dereferenced + * and borrowed according to `derefChain` and `borrow`, in order to be able to + * resolve the call target. + */ + predicate argumentHasImplicitDerefChainBorrow( + AstNode arg, DerefChain derefChain, BorrowKind borrow + ) { + exists(this.resolveCallTarget(_, derefChain, borrow)) and + arg = this.getArg(any(ArgumentPosition pos | pos.isSelf())) and + not (derefChain.isEmpty() and borrow.isNoBorrow()) } } @@ -2029,10 +2024,14 @@ private module MethodResolution { result = inferType(this.getArg(pos), path) } - override predicate argumentHasImplicitBorrow(AstNode arg, boolean isMutable) { - exists(ArgumentPosition pos | + override predicate argumentHasImplicitDerefChainBorrow( + AstNode arg, DerefChain derefChain, BorrowKind borrow + ) { + exists(ArgumentPosition pos, boolean isMutable | this.implicitBorrowAt(pos, isMutable) and - arg = this.getArg(pos) + arg = this.getArg(pos) and + derefChain = DerefChain::nil() and + borrow = TSomeBorrowKind(isMutable) ) } @@ -2048,14 +2047,14 @@ private module MethodResolution { } private newtype TMethodCallCand = - MkMethodCallCand(MethodCall mc, string derefChain, BorrowKind borrow) { + MkMethodCallCand(MethodCall mc, DerefChain derefChain, BorrowKind borrow) { exists(mc.getACandidateReceiverTypeAt(derefChain, borrow, _)) } /** A method call with a dereference chain and a potential borrow. */ private class MethodCallCand extends MkMethodCallCand { MethodCall mc_; - string derefChain; + DerefChain derefChain; BorrowKind borrow; MethodCallCand() { this = MkMethodCallCand(mc_, derefChain, borrow) } @@ -2147,11 +2146,79 @@ private module MethodResolution { MethodArgsAreInstantiationsOf::argsAreInstantiationsOf(this, i, result) } - string toString() { result = mc_.toString() + " [" + derefChain + "; " + borrow + "]" } + string toString() { + result = mc_.toString() + " [" + derefChain.toString() + "; " + borrow + "]" + } Location getLocation() { result = mc_.getLocation() } } + /** + * Provides logic for resolving implicit `Deref::deref` calls. + */ + private module ImplicitDeref { + private newtype TMethodCallDerefCand = + MkMethodCallDerefCand(MethodCall mc, DerefChain derefChain) { + mc.supportsAutoDerefAndBorrow() and + mc.hasNoCompatibleTargetMutBorrow(derefChain) and + exists(mc.getACandidateReceiverTypeAtNoBorrow(derefChain, _)) + } + + /** A method call with a dereference chain. */ + private class MethodCallDerefCand extends MkMethodCallDerefCand { + MethodCall mc; + DerefChain derefChain; + + MethodCallDerefCand() { this = MkMethodCallDerefCand(mc, derefChain) } + + Type getTypeAt(TypePath path) { + result = substituteLookupTraits(mc.getACandidateReceiverTypeAtNoBorrow(derefChain, path)) and + result != TNeverType() and + result != TUnknownType() + } + + string toString() { result = mc.toString() + " [" + derefChain.toString() + "]" } + + Location getLocation() { result = mc.getLocation() } + } + + private module MethodCallSatisfiesDerefConstraintInput implements + SatisfiesConstraintInputSig + { + pragma[nomagic] + predicate relevantConstraint(MethodCallDerefCand mc, Type constraint) { + exists(mc) and + constraint.(TraitType).getTrait() instanceof DerefTrait + } + + predicate useUniversalConditions() { none() } + } + + private module MethodCallSatisfiesDerefConstraint = + SatisfiesConstraint; + + pragma[nomagic] + private AssociatedTypeTypeParameter getDerefTargetTypeParameter() { + result.getTypeAlias() = any(DerefTrait ft).getTargetType() + } + + /** + * Gets the type of the receiver of `mc` at `path` after applying the implicit + * dereference inside `impl`, following the existing dereference chain `derefChain`. + */ + pragma[nomagic] + Type getDereferencedCandidateReceiverType( + MethodCall mc, DerefImplItemNode impl, DerefChain derefChain, TypePath path + ) { + exists(MethodCallDerefCand mcc, TypePath exprPath | + mcc = MkMethodCallDerefCand(mc, derefChain) and + MethodCallSatisfiesDerefConstraint::satisfiesConstraintTypeThrough(mcc, impl, _, exprPath, + result) and + exprPath.isCons(getDerefTargetTypeParameter(), path) + ) + } + } + private module ReceiverSatisfiesBlanketLikeConstraintInput implements BlanketImplementation::SatisfiesBlanketConstraintInputSig { @@ -2378,10 +2445,21 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi class AccessEnvironment = string; bindingset[derefChain, borrow] - additional AccessEnvironment encodeDerefChainBorrow(string derefChain, BorrowKind borrow) { + private AccessEnvironment encodeDerefChainBorrow(DerefChain derefChain, BorrowKind borrow) { result = derefChain + ";" + borrow } + bindingset[derefChainBorrow] + additional predicate decodeDerefChainBorrow( + string derefChainBorrow, DerefChain derefChain, BorrowKind borrow + ) { + exists(string regexp | + regexp = "^(.*);(.*)$" and + derefChain = derefChainBorrow.regexpCapture(regexp, 1) and + borrow.toString() = derefChainBorrow.regexpCapture(regexp, 2) + ) + } + final private class MethodCallFinal = MethodResolution::MethodCall; class Access extends MethodCallFinal, ContextTyping::ContextTypedCallCand { @@ -2404,7 +2482,7 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi pragma[nomagic] private Type getInferredSelfType(AccessPosition apos, string derefChainBorrow, TypePath path) { - exists(string derefChain, BorrowKind borrow | + exists(DerefChain derefChain, BorrowKind borrow | result = this.getACandidateReceiverTypeAt(derefChain, borrow, path) and derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and apos.isSelf() @@ -2440,7 +2518,7 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi } Method getTarget(ImplOrTraitItemNode i, string derefChainBorrow) { - exists(string derefChain, BorrowKind borrow | + exists(DerefChain derefChain, BorrowKind borrow | derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and result = this.resolveCallTarget(i, derefChain, borrow) // mutual recursion; resolving method calls requires resolving types and vice versa ) @@ -2493,39 +2571,67 @@ private Type inferMethodCallType0( } pragma[nomagic] -private Type inferMethodCallType1(AstNode n, boolean isReturn, TypePath path) { - exists( - MethodCallMatchingInput::Access a, MethodCallMatchingInput::AccessPosition apos, - string derefChainBorrow, TypePath path0 - | - result = inferMethodCallType0(a, apos, n, derefChainBorrow, path0) and +private Type inferMethodCallTypeNonSelf(AstNode n, boolean isReturn, TypePath path) { + exists(MethodCallMatchingInput::AccessPosition apos | + result = inferMethodCallType0(_, apos, n, _, path) and + not apos.isSelf() and if apos.isReturn() then isReturn = true else isReturn = false - | - ( - not apos.isSelf() - or - derefChainBorrow = ";" - ) and - path = path0 - or - // adjust for implicit deref - apos.isSelf() and - derefChainBorrow = MethodCallMatchingInput::encodeDerefChainBorrow(".ref", TNoBorrowKind()) and - path = TypePath::cons(getRefTypeParameter(_), path0) - or - // adjust for implicit borrow - apos.isSelf() and - derefChainBorrow = MethodCallMatchingInput::encodeDerefChainBorrow("", TSomeBorrowKind(_)) and - path0.isCons(getRefTypeParameter(_), path) ) } +pragma[nomagic] +private Type inferMethodCallTypeSelf( + AstNode n, DerefChain derefChain, BorrowKind borrow, TypePath path +) { + exists(MethodCallMatchingInput::AccessPosition apos, string derefChainBorrow | + result = inferMethodCallType0(_, apos, n, derefChainBorrow, path) and + apos.isSelf() and + MethodCallMatchingInput::decodeDerefChainBorrow(derefChainBorrow, derefChain, borrow) + ) + or + // adjust for implicit borrow + exists(TypePath path0, BorrowKind borrow0 | + result = inferMethodCallTypeSelf(n, derefChain, borrow0, path0) and + path0.isCons(borrow0.getRefType().getPositionalTypeParameter(0), path) and + borrow.isNoBorrow() + ) + or + // adjust for implicit deref + exists( + DerefChain derefChain0, Type t0, TypePath path0, DerefImplItemNode impl, Type selfParamType, + TypePath selfPath + | + t0 = inferMethodCallTypeSelf(n, derefChain0, borrow, path0) and + derefChain0.isCons(impl, derefChain) and + borrow.isNoBorrow() and + selfParamType = impl.resolveSelfParamTypeStrippedAt(selfPath) + | + result = selfParamType and + path = selfPath and + not result instanceof TypeParameter + or + exists(TypeParameter tp, TypePath pathToTypeParam, TypePath suffix | + impl.returnTypeStrippedMentionsTypeParameterAt(tp, pathToTypeParam) and + path0 = pathToTypeParam.appendInverse(suffix) and + result = t0 and + path = selfPath.append(suffix) + ) + ) +} + +private Type inferMethodCallTypePreCheck(AstNode n, boolean isReturn, TypePath path) { + result = inferMethodCallTypeNonSelf(n, isReturn, path) + or + result = inferMethodCallTypeSelf(n, DerefChain::nil(), TNoBorrowKind(), path) and + isReturn = false +} + /** * Gets the type of `n` at `path`, where `n` is either a method call or an * argument/receiver of a method call. */ private predicate inferMethodCallType = - ContextTyping::CheckContextTyping::check/2; + ContextTyping::CheckContextTyping::check/2; /** * Provides logic for resolving calls to non-method items. This includes @@ -3127,19 +3233,28 @@ private predicate inferOperationType = ContextTyping::CheckContextTyping::check/2; pragma[nomagic] -private Type getFieldExprLookupType(FieldExpr fe, string name, boolean isDereferenced) { +private Type getFieldExprLookupType(FieldExpr fe, string name, DerefChain derefChain) { exists(TypePath path | result = inferType(fe.getContainer(), path) and name = fe.getIdentifier().getText() and - isComplexRootStripped(path, result) and - if path.isEmpty() then isDereferenced = false else isDereferenced = true + isComplexRootStripped(path, result) + | + // TODO: Support full derefence chains as for method calls + path.isEmpty() and + derefChain = DerefChain::nil() + or + exists(DerefImplItemNode impl, TypeParamTypeParameter tp | + tp = impl.getFirstSelfTypeParameter() and + path.getHead() = tp and + derefChain = DerefChain::singleton(impl) + ) ) } pragma[nomagic] -private Type getTupleFieldExprLookupType(FieldExpr fe, int pos, boolean isDereferenced) { +private Type getTupleFieldExprLookupType(FieldExpr fe, int pos, DerefChain derefChain) { exists(string name | - result = getFieldExprLookupType(fe, name, isDereferenced) and + result = getFieldExprLookupType(fe, name, derefChain) and pos = name.toInt() ) } @@ -3341,9 +3456,6 @@ private Type inferTryExprType(TryExpr te, TypePath path) { pragma[nomagic] private StructType getStrStruct() { result = TDataType(any(Builtins::Str s)) } -pragma[nomagic] -private StructType getStringStruct() { result = TDataType(any(StringStruct s)) } - pragma[nomagic] private Type inferLiteralType(LiteralExpr le, TypePath path, boolean certain) { path.isEmpty() and @@ -3800,20 +3912,27 @@ private module Cached { /** Holds if `n` is implicitly dereferenced. */ cached predicate implicitDeref(AstNode n) { - any(MethodResolution::MethodCall mc).receiverHasImplicitDeref(n) - or - n = - any(FieldExpr fe | - exists(resolveStructFieldExpr(fe, true)) - or - exists(resolveTupleFieldExpr(fe, true)) - ).getContainer() + exists(DerefChain derefChain, DerefImplItemNode impl | + impl.resolveSelfTyBuiltin() instanceof Builtins::RefType and + derefChain = DerefChain::singleton(impl) + | + any(MethodResolution::MethodCall mc) + .argumentHasImplicitDerefChainBorrow(n, derefChain, TNoBorrowKind()) + or + n = + any(FieldExpr fe | + exists(resolveStructFieldExpr(fe, derefChain)) + or + exists(resolveTupleFieldExpr(fe, derefChain)) + ).getContainer() + ) } /** Holds if `n` is implicitly borrowed. */ cached predicate implicitBorrow(AstNode n, boolean isMutable) { - any(MethodResolution::MethodCall mc).argumentHasImplicitBorrow(n, isMutable) + any(MethodResolution::MethodCall mc) + .argumentHasImplicitDerefChainBorrow(n, DerefChain::nil(), TSomeBorrowKind(isMutable)) } /** @@ -3843,9 +3962,9 @@ private module Cached { * Gets the struct field that the field expression `fe` resolves to, if any. */ cached - StructField resolveStructFieldExpr(FieldExpr fe, boolean isDereferenced) { + StructField resolveStructFieldExpr(FieldExpr fe, DerefChain derefChain) { exists(string name, DataType ty | - ty = getFieldExprLookupType(fe, pragma[only_bind_into](name), isDereferenced) + ty = getFieldExprLookupType(fe, pragma[only_bind_into](name), derefChain) | result = ty.(StructType).getTypeItem().getStructField(pragma[only_bind_into](name)) or result = ty.(UnionType).getTypeItem().getStructField(pragma[only_bind_into](name)) @@ -3856,10 +3975,10 @@ private module Cached { * Gets the tuple field that the field expression `fe` resolves to, if any. */ cached - TupleField resolveTupleFieldExpr(FieldExpr fe, boolean isDereferenced) { + TupleField resolveTupleFieldExpr(FieldExpr fe, DerefChain derefChain) { exists(int i | result = - getTupleFieldExprLookupType(fe, pragma[only_bind_into](i), isDereferenced) + getTupleFieldExprLookupType(fe, pragma[only_bind_into](i), derefChain) .(StructType) .getTypeItem() .getTupleField(pragma[only_bind_into](i)) diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/DerefChain.qll b/rust/ql/lib/codeql/rust/internal/typeinference/DerefChain.qll new file mode 100644 index 00000000000..cca2a1b20e1 --- /dev/null +++ b/rust/ql/lib/codeql/rust/internal/typeinference/DerefChain.qll @@ -0,0 +1,82 @@ +/** Provides logic for representing chains of implicit dereferences. */ + +private import rust +private import codeql.rust.internal.PathResolution +private import codeql.rust.internal.Type +private import codeql.rust.internal.TypeInference +private import codeql.rust.internal.TypeMention +private import codeql.rust.frameworks.stdlib.Stdlib +private import codeql.rust.frameworks.stdlib.Builtins as Builtins +private import codeql.util.UnboundList as UnboundListImpl + +/** An `impl` block that implements the `Deref` trait. */ +class DerefImplItemNode extends ImplItemNode { + DerefImplItemNode() { this.resolveTraitTy() instanceof DerefTrait } + + /** Gets the `deref` function in this `Deref` impl block. */ + Function getDerefFunction() { result = this.getAssocItem("deref") } + + private SelfParam getSelfParam() { result = this.getDerefFunction().getSelfParam() } + + /** + * Resolves the type at `path` of the `self` parameter inside the `deref` function, + * stripped of the leading `&`. + */ + pragma[nomagic] + Type resolveSelfParamTypeStrippedAt(TypePath path) { + exists(TypePath path0 | + result = getSelfParamTypeMention(this.getSelfParam()).resolveTypeAt(path0) and + path0.isCons(getRefTypeParameter(false), path) + ) + } + + /** + * Holds if the return type at `path` of the `deref` function, stripped of the + * leading `&`, mentions type parameter `tp` at `path`. + */ + pragma[nomagic] + predicate returnTypeStrippedMentionsTypeParameterAt(TypeParameter tp, TypePath path) { + exists(TypePath path0 | + tp = getReturnTypeMention(this.getDerefFunction()).resolveTypeAt(path0) and + path0.isCons(getRefTypeParameter(false), path) + ) + } + + /** Gets the first type parameter of the type being implemented, if any. */ + pragma[nomagic] + TypeParamTypeParameter getFirstSelfTypeParameter() { + result.getTypeParam() = this.resolveSelfTy().getTypeParam(0) + } +} + +private module UnboundListInput implements UnboundListImpl::InputSig { + private import codeql.rust.elements.internal.generated.Raw + private import codeql.rust.elements.internal.generated.Synth + + private class DerefImplItemRaw extends Raw::Impl { + DerefImplItemRaw() { this = Synth::convertAstNodeToRaw(any(DerefImplItemNode i)) } + } + + private predicate id(DerefImplItemRaw x, DerefImplItemRaw y) { x = y } + + private predicate idOfRaw(DerefImplItemRaw x, int y) = equivalenceRelation(id/2)(x, y) + + class Element = DerefImplItemNode; + + int getId(Element e) { idOfRaw(Synth::convertAstNodeToRaw(e), result) } + + string getElementString(Element e) { result = e.resolveSelfTy().getName() } + + int getLengthLimit() { result = 5 } +} + +private import UnboundListImpl::Make + +/** + * A sequence of `Deref` impl blocks representing a chain of implicit dereferences, + * encoded as a string. + */ +class DerefChain = UnboundList; + +/** Provides predicates for constructing `DerefChain`s. */ +module DerefChain = UnboundList; diff --git a/rust/ql/test/library-tests/dataflow/global/viableCallable.expected b/rust/ql/test/library-tests/dataflow/global/viableCallable.expected index 4e5714fa2d9..49de4868d73 100644 --- a/rust/ql/test/library-tests/dataflow/global/viableCallable.expected +++ b/rust/ql/test/library-tests/dataflow/global/viableCallable.expected @@ -84,6 +84,7 @@ | main.rs:292:13:292:14 | * ... | main.rs:251:5:253:5 | fn deref | | main.rs:293:5:293:11 | sink(...) | main.rs:5:1:7:1 | fn sink | | main.rs:295:28:295:37 | source(...) | main.rs:1:1:3:1 | fn source | +| main.rs:296:13:296:23 | a.min(...) | {EXTERNAL LOCATION} | fn min | | main.rs:297:5:297:11 | sink(...) | main.rs:5:1:7:1 | fn sink | | main.rs:319:28:319:36 | source(...) | main.rs:1:1:3:1 | fn source | | main.rs:321:30:321:54 | ...::take_self(...) | main.rs:309:5:311:5 | fn take_self | diff --git a/rust/ql/test/library-tests/dataflow/sources/file/InlineFlow.expected b/rust/ql/test/library-tests/dataflow/sources/file/InlineFlow.expected index 6f012e837a9..cffdc6d395b 100644 --- a/rust/ql/test/library-tests/dataflow/sources/file/InlineFlow.expected +++ b/rust/ql/test/library-tests/dataflow/sources/file/InlineFlow.expected @@ -35,7 +35,8 @@ models | 34 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_to_string; Argument[self].Reference; Argument[0].Reference; taint | | 35 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_u8; Argument[self].Reference; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | | 36 | Summary: ::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | -| 37 | Summary: ::as_path; Argument[self].Reference; ReturnValue.Reference; value | +| 37 | Summary: ::canonicalize; Argument[self].Reference.OptionalBarrier[normalize-path]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | +| 38 | Summary: ::as_path; Argument[self].Reference; ReturnValue.Reference; value | edges | test.rs:12:13:12:18 | buffer | test.rs:13:14:13:19 | buffer | provenance | | | test.rs:12:31:12:43 | ...::read | test.rs:12:31:12:55 | ...::read(...) [Ok] | provenance | Src:MaD:11 | @@ -51,12 +52,15 @@ edges | test.rs:22:22:22:52 | TryExpr | test.rs:22:13:22:18 | buffer | provenance | | | test.rs:29:13:29:16 | path | test.rs:30:14:30:17 | path | provenance | | | test.rs:29:13:29:16 | path | test.rs:31:14:31:17 | path | provenance | | +| test.rs:29:13:29:16 | path | test.rs:40:14:40:17 | path | provenance | | | test.rs:29:13:29:16 | path | test.rs:41:14:41:17 | path | provenance | | | test.rs:29:20:29:27 | e.path() | test.rs:29:13:29:16 | path | provenance | | | test.rs:29:22:29:25 | path | test.rs:29:20:29:27 | e.path() | provenance | Src:MaD:4 MaD:4 | | test.rs:30:14:30:17 | path | test.rs:30:14:30:25 | path.clone() | provenance | MaD:18 | | test.rs:31:14:31:17 | path | test.rs:31:14:31:25 | path.clone() | provenance | MaD:18 | -| test.rs:31:14:31:25 | path.clone() | test.rs:31:14:31:35 | ... .as_path() | provenance | MaD:37 | +| test.rs:31:14:31:25 | path.clone() | test.rs:31:14:31:35 | ... .as_path() | provenance | MaD:38 | +| test.rs:40:14:40:17 | path | test.rs:40:14:40:32 | path.canonicalize() [Ok] | provenance | MaD:37 | +| test.rs:40:14:40:32 | path.canonicalize() [Ok] | test.rs:40:14:40:41 | ... .unwrap() | provenance | MaD:36 | | test.rs:43:13:43:21 | file_name | test.rs:44:14:44:22 | file_name | provenance | | | test.rs:43:13:43:21 | file_name | test.rs:49:14:49:22 | file_name | provenance | | | test.rs:43:25:43:37 | e.file_name() | test.rs:43:13:43:21 | file_name | provenance | | @@ -273,6 +277,9 @@ nodes | test.rs:31:14:31:17 | path | semmle.label | path | | test.rs:31:14:31:25 | path.clone() | semmle.label | path.clone() | | test.rs:31:14:31:35 | ... .as_path() | semmle.label | ... .as_path() | +| test.rs:40:14:40:17 | path | semmle.label | path | +| test.rs:40:14:40:32 | path.canonicalize() [Ok] | semmle.label | path.canonicalize() [Ok] | +| test.rs:40:14:40:41 | ... .unwrap() | semmle.label | ... .unwrap() | | test.rs:41:14:41:17 | path | semmle.label | path | | test.rs:43:13:43:21 | file_name | semmle.label | file_name | | test.rs:43:25:43:37 | e.file_name() | semmle.label | e.file_name() | @@ -492,6 +499,7 @@ testFailures | test.rs:23:14:23:19 | buffer | test.rs:22:22:22:39 | ...::read_to_string | test.rs:23:14:23:19 | buffer | $@ | test.rs:22:22:22:39 | ...::read_to_string | ...::read_to_string | | test.rs:30:14:30:25 | path.clone() | test.rs:29:22:29:25 | path | test.rs:30:14:30:25 | path.clone() | $@ | test.rs:29:22:29:25 | path | path | | test.rs:31:14:31:35 | ... .as_path() | test.rs:29:22:29:25 | path | test.rs:31:14:31:35 | ... .as_path() | $@ | test.rs:29:22:29:25 | path | path | +| test.rs:40:14:40:41 | ... .unwrap() | test.rs:29:22:29:25 | path | test.rs:40:14:40:41 | ... .unwrap() | $@ | test.rs:29:22:29:25 | path | path | | test.rs:41:14:41:17 | path | test.rs:29:22:29:25 | path | test.rs:41:14:41:17 | path | $@ | test.rs:29:22:29:25 | path | path | | test.rs:44:14:44:30 | file_name.clone() | test.rs:43:27:43:35 | file_name | test.rs:44:14:44:30 | file_name.clone() | $@ | test.rs:43:27:43:35 | file_name | file_name | | test.rs:49:14:49:22 | file_name | test.rs:43:27:43:35 | file_name | test.rs:49:14:49:22 | file_name | $@ | test.rs:43:27:43:35 | file_name | file_name | diff --git a/rust/ql/test/library-tests/dataflow/sources/file/TaintSources.expected b/rust/ql/test/library-tests/dataflow/sources/file/TaintSources.expected index 0fb17232a39..dd1b94de717 100644 --- a/rust/ql/test/library-tests/dataflow/sources/file/TaintSources.expected +++ b/rust/ql/test/library-tests/dataflow/sources/file/TaintSources.expected @@ -7,6 +7,9 @@ | 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:55:27:55:35 | file_name | Flow source 'FileSource' of type file (DEFAULT). | +| test.rs:57:56:57:63 | read_dir | Flow source 'FileSource' of type file (DEFAULT). | +| test.rs:60:22:60:25 | path | Flow source 'FileSource' of type file (DEFAULT). | +| test.rs:61:27:61: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:74:31:74:45 | ...::read | Flow source 'FileSource' of type file (DEFAULT). | | test.rs:79:31:79:45 | ...::read | Flow source 'FileSource' of type file (DEFAULT). | diff --git a/rust/ql/test/library-tests/dataflow/sources/file/test.rs b/rust/ql/test/library-tests/dataflow/sources/file/test.rs index 0124d2a094e..4aa56a0dd74 100644 --- a/rust/ql/test/library-tests/dataflow/sources/file/test.rs +++ b/rust/ql/test/library-tests/dataflow/sources/file/test.rs @@ -37,7 +37,7 @@ fn test_fs() -> Result<(), Box> { sink(path.to_path_buf()); // $ MISSING: hasTaintFlow sink(path.file_name().unwrap()); // $ MISSING: hasTaintFlow sink(path.extension().unwrap()); // $ MISSING: hasTaintFlow - sink(path.canonicalize().unwrap()); // $ MISSING: hasTaintFlow + sink(path.canonicalize().unwrap()); // $ hasTaintFlow sink(path); // $ hasTaintFlow let file_name = e.file_name(); // $ Alert[rust/summary/taint-sources] @@ -54,11 +54,11 @@ fn test_fs() -> Result<(), Box> { let path = e.path(); // $ Alert[rust/summary/taint-sources] let file_name = e.file_name(); // $ Alert[rust/summary/taint-sources] } - for entry in std::path::PathBuf::from("directory").read_dir()? { + for entry in std::path::PathBuf::from("directory").read_dir()? { // $ Alert[rust/summary/taint-sources] let e = entry?; - let path = e.path(); // $ MISSING: Alert[rust/summary/taint-sources] - let file_name = e.file_name(); // $ MISSING: Alert[rust/summary/taint-sources] + let path = e.path(); // $ Alert[rust/summary/taint-sources] + let file_name = e.file_name(); // $ Alert[rust/summary/taint-sources] } { diff --git a/rust/ql/test/library-tests/dataflow/sources/net/InlineFlow.expected b/rust/ql/test/library-tests/dataflow/sources/net/InlineFlow.expected index 2b39cf16c42..a5a4846284e 100644 --- a/rust/ql/test/library-tests/dataflow/sources/net/InlineFlow.expected +++ b/rust/ql/test/library-tests/dataflow/sources/net/InlineFlow.expected @@ -1,93 +1,97 @@ models | 1 | Source: ::connect; ReturnValue.Future.Field[core::result::Result::Ok(0)]; remote | | 2 | Source: ::send_request; ReturnValue.Future.Field[core::result::Result::Ok(0)]; remote | -| 3 | Source: ::connect; ReturnValue.Field[core::result::Result::Ok(0)]; remote | -| 4 | Source: ::connect_timeout; ReturnValue.Field[core::result::Result::Ok(0)]; remote | -| 5 | Source: ::connect; ReturnValue.Future.Field[core::result::Result::Ok(0)]; remote | -| 6 | Source: reqwest::blocking::get; ReturnValue.Field[core::result::Result::Ok(0)]; remote | -| 7 | Source: reqwest::get; ReturnValue.Future.Field[core::result::Result::Ok(0)]; remote | -| 8 | Summary: <_ as core::ops::index::Index>::index; Argument[self].Reference.Element; ReturnValue.Reference; value | -| 9 | Summary: <_ as futures_io::if_std::AsyncBufRead>::poll_fill_buf; Argument[self].Reference; ReturnValue.Field[core::task::poll::Poll::Ready(0)].Field[core::result::Result::Ok(0)]; taint | -| 10 | Summary: <_ as futures_io::if_std::AsyncRead>::poll_read; Argument[self].Reference; Argument[1].Reference; taint | -| 11 | Summary: <_ as futures_util::io::AsyncBufReadExt>::fill_buf; Argument[self].Reference; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | -| 12 | Summary: <_ as futures_util::io::AsyncBufReadExt>::read_line; Argument[self].Reference; Argument[0].Reference; taint | -| 13 | Summary: <_ as futures_util::io::AsyncBufReadExt>::read_until; Argument[self].Reference; Argument[1].Reference; taint | -| 14 | Summary: <_ as futures_util::io::AsyncReadExt>::read; Argument[self].Reference; Argument[0].Reference; taint | -| 15 | Summary: <_ as futures_util::io::AsyncReadExt>::read_to_end; Argument[self].Reference; Argument[0].Reference; taint | -| 16 | Summary: <_ as std::io::BufRead>::read_line; Argument[self].Reference; Argument[0].Reference; taint | -| 17 | Summary: <_ as std::io::Read>::read; Argument[self].Reference; Argument[0].Reference; taint | -| 18 | Summary: <_ as std::io::Read>::take; Argument[self]; ReturnValue; taint | -| 19 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read; Argument[self].Reference; Argument[0].Reference; taint | -| 20 | Summary: ::unwrap; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value | -| 21 | Summary: ::new; Argument[0].Reference; ReturnValue; value | -| 22 | Summary: ::new; Argument[0]; ReturnValue.Field[core::pin::Pin::pointer]; value | -| 23 | Summary: ::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | -| 24 | Summary: ::connect; Argument[1]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | -| 25 | Summary: ::new; Argument[0]; ReturnValue; taint | -| 26 | Summary: ::bytes; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | -| 27 | Summary: ::chunk; Argument[self].Reference; ReturnValue.Future.Field[core::result::Result::Ok(0)].Field[core::option::Option::Some(0)]; taint | -| 28 | Summary: ::text; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | -| 29 | Summary: ::bytes; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | -| 30 | Summary: ::text; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | -| 31 | Summary: ::text_with_charset; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | -| 32 | Summary: ::new; Argument[0]; ReturnValue; taint | -| 33 | Summary: ::peek; Argument[self].Reference; Argument[0].Reference; taint | -| 34 | Summary: ::try_read; Argument[self].Reference; Argument[0].Reference; taint | -| 35 | Summary: ::try_read_buf; Argument[self].Reference; Argument[0].Reference; taint | +| 3 | Source: ::new; ReturnValue.Field[core::result::Result::Ok(0)]; remote | +| 4 | Source: ::connect; ReturnValue.Field[core::result::Result::Ok(0)]; remote | +| 5 | Source: ::connect_timeout; ReturnValue.Field[core::result::Result::Ok(0)]; remote | +| 6 | Source: ::connect; ReturnValue.Future.Field[core::result::Result::Ok(0)]; remote | +| 7 | Source: reqwest::blocking::get; ReturnValue.Field[core::result::Result::Ok(0)]; remote | +| 8 | Source: reqwest::get; ReturnValue.Future.Field[core::result::Result::Ok(0)]; remote | +| 9 | Summary: <_ as core::ops::index::Index>::index; Argument[self].Reference.Element; ReturnValue.Reference; value | +| 10 | Summary: <_ as futures_io::if_std::AsyncBufRead>::poll_fill_buf; Argument[self].Reference; ReturnValue.Field[core::task::poll::Poll::Ready(0)].Field[core::result::Result::Ok(0)]; taint | +| 11 | Summary: <_ as futures_io::if_std::AsyncRead>::poll_read; Argument[self].Reference; Argument[1].Reference; taint | +| 12 | Summary: <_ as futures_util::io::AsyncBufReadExt>::fill_buf; Argument[self].Reference; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | +| 13 | Summary: <_ as futures_util::io::AsyncBufReadExt>::read_line; Argument[self].Reference; Argument[0].Reference; taint | +| 14 | Summary: <_ as futures_util::io::AsyncBufReadExt>::read_until; Argument[self].Reference; Argument[1].Reference; taint | +| 15 | Summary: <_ as futures_util::io::AsyncReadExt>::read; Argument[self].Reference; Argument[0].Reference; taint | +| 16 | Summary: <_ as futures_util::io::AsyncReadExt>::read_to_end; Argument[self].Reference; Argument[0].Reference; taint | +| 17 | Summary: <_ as std::io::BufRead>::read_line; Argument[self].Reference; Argument[0].Reference; taint | +| 18 | Summary: <_ as std::io::Read>::read; Argument[self].Reference; Argument[0].Reference; taint | +| 19 | Summary: <_ as std::io::Read>::read_to_end; Argument[self].Reference; Argument[0].Reference; taint | +| 20 | Summary: <_ as std::io::Read>::read_to_string; Argument[self].Reference; Argument[0].Reference; taint | +| 21 | Summary: <_ as std::io::Read>::take; Argument[self]; ReturnValue; taint | +| 22 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read; Argument[self].Reference; Argument[0].Reference; taint | +| 23 | Summary: ::unwrap; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value | +| 24 | Summary: ::new; Argument[0].Reference; ReturnValue; value | +| 25 | Summary: ::new; Argument[0]; ReturnValue.Field[core::pin::Pin::pointer]; value | +| 26 | Summary: ::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | +| 27 | Summary: ::connect; Argument[1]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | +| 28 | Summary: ::new; Argument[0]; ReturnValue; taint | +| 29 | Summary: ::bytes; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | +| 30 | Summary: ::chunk; Argument[self].Reference; ReturnValue.Future.Field[core::result::Result::Ok(0)].Field[core::option::Option::Some(0)]; taint | +| 31 | Summary: ::text; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | +| 32 | Summary: ::bytes; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | +| 33 | Summary: ::text; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | +| 34 | Summary: ::text_with_charset; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | +| 35 | Summary: ::reader; Argument[self]; ReturnValue; taint | +| 36 | Summary: ::new; Argument[0]; ReturnValue; taint | +| 37 | Summary: ::peek; Argument[self].Reference; Argument[0].Reference; taint | +| 38 | Summary: ::try_read; Argument[self].Reference; Argument[0].Reference; taint | +| 39 | Summary: ::try_read_buf; Argument[self].Reference; Argument[0].Reference; taint | edges | test.rs:11:9:11:22 | remote_string1 | test.rs:12:10:12:23 | remote_string1 | provenance | | -| test.rs:11:26:11:47 | ...::get | test.rs:11:26:11:62 | ...::get(...) [Ok] | provenance | Src:MaD:6 | +| test.rs:11:26:11:47 | ...::get | test.rs:11:26:11:62 | ...::get(...) [Ok] | provenance | Src:MaD:7 | | test.rs:11:26:11:62 | ...::get(...) [Ok] | test.rs:11:26:11:63 | TryExpr | provenance | | -| test.rs:11:26:11:63 | TryExpr | test.rs:11:26:11:70 | ... .text() [Ok] | provenance | MaD:30 | +| test.rs:11:26:11:63 | TryExpr | test.rs:11:26:11:70 | ... .text() [Ok] | provenance | MaD:33 | | test.rs:11:26:11:70 | ... .text() [Ok] | test.rs:11:26:11:71 | TryExpr | provenance | | | test.rs:11:26:11:71 | TryExpr | test.rs:11:9:11:22 | remote_string1 | provenance | | | test.rs:14:9:14:22 | remote_string2 | test.rs:15:10:15:23 | remote_string2 | provenance | | -| test.rs:14:26:14:47 | ...::get | test.rs:14:26:14:62 | ...::get(...) [Ok] | provenance | Src:MaD:6 | -| test.rs:14:26:14:62 | ...::get(...) [Ok] | test.rs:14:26:14:71 | ... .unwrap() | provenance | MaD:23 | -| test.rs:14:26:14:71 | ... .unwrap() | test.rs:14:26:14:78 | ... .text() [Ok] | provenance | MaD:30 | -| test.rs:14:26:14:78 | ... .text() [Ok] | test.rs:14:26:14:87 | ... .unwrap() | provenance | MaD:23 | +| test.rs:14:26:14:47 | ...::get | test.rs:14:26:14:62 | ...::get(...) [Ok] | provenance | Src:MaD:7 | +| test.rs:14:26:14:62 | ...::get(...) [Ok] | test.rs:14:26:14:71 | ... .unwrap() | provenance | MaD:26 | +| test.rs:14:26:14:71 | ... .unwrap() | test.rs:14:26:14:78 | ... .text() [Ok] | provenance | MaD:33 | +| test.rs:14:26:14:78 | ... .text() [Ok] | test.rs:14:26:14:87 | ... .unwrap() | provenance | MaD:26 | | test.rs:14:26:14:87 | ... .unwrap() | test.rs:14:9:14:22 | remote_string2 | provenance | | | test.rs:17:9:17:22 | remote_string3 | test.rs:18:10:18:23 | remote_string3 | provenance | | -| test.rs:17:26:17:47 | ...::get | test.rs:17:26:17:62 | ...::get(...) [Ok] | provenance | Src:MaD:6 | -| test.rs:17:26:17:62 | ...::get(...) [Ok] | test.rs:17:26:17:71 | ... .unwrap() | provenance | MaD:23 | -| test.rs:17:26:17:71 | ... .unwrap() | test.rs:17:26:17:98 | ... .text_with_charset(...) [Ok] | provenance | MaD:31 | -| test.rs:17:26:17:98 | ... .text_with_charset(...) [Ok] | test.rs:17:26:17:107 | ... .unwrap() | provenance | MaD:23 | +| test.rs:17:26:17:47 | ...::get | test.rs:17:26:17:62 | ...::get(...) [Ok] | provenance | Src:MaD:7 | +| test.rs:17:26:17:62 | ...::get(...) [Ok] | test.rs:17:26:17:71 | ... .unwrap() | provenance | MaD:26 | +| test.rs:17:26:17:71 | ... .unwrap() | test.rs:17:26:17:98 | ... .text_with_charset(...) [Ok] | provenance | MaD:34 | +| test.rs:17:26:17:98 | ... .text_with_charset(...) [Ok] | test.rs:17:26:17:107 | ... .unwrap() | provenance | MaD:26 | | test.rs:17:26:17:107 | ... .unwrap() | test.rs:17:9:17:22 | remote_string3 | provenance | | | test.rs:20:9:20:22 | remote_string4 | test.rs:21:10:21:23 | remote_string4 | provenance | | -| test.rs:20:26:20:47 | ...::get | test.rs:20:26:20:62 | ...::get(...) [Ok] | provenance | Src:MaD:6 | -| test.rs:20:26:20:62 | ...::get(...) [Ok] | test.rs:20:26:20:71 | ... .unwrap() | provenance | MaD:23 | -| test.rs:20:26:20:71 | ... .unwrap() | test.rs:20:26:20:79 | ... .bytes() [Ok] | provenance | MaD:29 | -| test.rs:20:26:20:79 | ... .bytes() [Ok] | test.rs:20:26:20:88 | ... .unwrap() | provenance | MaD:23 | +| test.rs:20:26:20:47 | ...::get | test.rs:20:26:20:62 | ...::get(...) [Ok] | provenance | Src:MaD:7 | +| test.rs:20:26:20:62 | ...::get(...) [Ok] | test.rs:20:26:20:71 | ... .unwrap() | provenance | MaD:26 | +| test.rs:20:26:20:71 | ... .unwrap() | test.rs:20:26:20:79 | ... .bytes() [Ok] | provenance | MaD:32 | +| test.rs:20:26:20:79 | ... .bytes() [Ok] | test.rs:20:26:20:88 | ... .unwrap() | provenance | MaD:26 | | test.rs:20:26:20:88 | ... .unwrap() | test.rs:20:9:20:22 | remote_string4 | provenance | | | test.rs:23:9:23:22 | remote_string5 | test.rs:24:10:24:23 | remote_string5 | provenance | | -| test.rs:23:26:23:37 | ...::get | test.rs:23:26:23:52 | ...::get(...) [future, Ok] | provenance | Src:MaD:7 | +| test.rs:23:26:23:37 | ...::get | test.rs:23:26:23:52 | ...::get(...) [future, Ok] | provenance | Src:MaD:8 | | test.rs:23:26:23:52 | ...::get(...) [future, Ok] | test.rs:23:26:23:58 | await ... [Ok] | provenance | | | test.rs:23:26:23:58 | await ... [Ok] | test.rs:23:26:23:59 | TryExpr | provenance | | -| test.rs:23:26:23:59 | TryExpr | test.rs:23:26:23:66 | ... .text() [future, Ok] | provenance | MaD:28 | +| test.rs:23:26:23:59 | TryExpr | test.rs:23:26:23:66 | ... .text() [future, Ok] | provenance | MaD:31 | | test.rs:23:26:23:66 | ... .text() [future, Ok] | test.rs:23:26:23:72 | await ... [Ok] | provenance | | | test.rs:23:26:23:72 | await ... [Ok] | test.rs:23:26:23:73 | TryExpr | provenance | | | test.rs:23:26:23:73 | TryExpr | test.rs:23:9:23:22 | remote_string5 | provenance | | | test.rs:26:9:26:22 | remote_string6 | test.rs:27:10:27:23 | remote_string6 | provenance | | -| test.rs:26:26:26:37 | ...::get | test.rs:26:26:26:52 | ...::get(...) [future, Ok] | provenance | Src:MaD:7 | +| test.rs:26:26:26:37 | ...::get | test.rs:26:26:26:52 | ...::get(...) [future, Ok] | provenance | Src:MaD:8 | | test.rs:26:26:26:52 | ...::get(...) [future, Ok] | test.rs:26:26:26:58 | await ... [Ok] | provenance | | | test.rs:26:26:26:58 | await ... [Ok] | test.rs:26:26:26:59 | TryExpr | provenance | | -| test.rs:26:26:26:59 | TryExpr | test.rs:26:26:26:67 | ... .bytes() [future, Ok] | provenance | MaD:26 | +| test.rs:26:26:26:59 | TryExpr | test.rs:26:26:26:67 | ... .bytes() [future, Ok] | provenance | MaD:29 | | test.rs:26:26:26:67 | ... .bytes() [future, Ok] | test.rs:26:26:26:73 | await ... [Ok] | provenance | | | test.rs:26:26:26:73 | await ... [Ok] | test.rs:26:26:26:74 | TryExpr | provenance | | | test.rs:26:26:26:74 | TryExpr | test.rs:26:9:26:22 | remote_string6 | provenance | | | test.rs:29:9:29:20 | mut request1 | test.rs:30:10:30:17 | request1 | provenance | | | test.rs:29:9:29:20 | mut request1 | test.rs:31:29:31:36 | request1 | provenance | | -| test.rs:29:24:29:35 | ...::get | test.rs:29:24:29:50 | ...::get(...) [future, Ok] | provenance | Src:MaD:7 | +| test.rs:29:24:29:35 | ...::get | test.rs:29:24:29:50 | ...::get(...) [future, Ok] | provenance | Src:MaD:8 | | test.rs:29:24:29:50 | ...::get(...) [future, Ok] | test.rs:29:24:29:56 | await ... [Ok] | provenance | | | test.rs:29:24:29:56 | await ... [Ok] | test.rs:29:24:29:57 | TryExpr | provenance | | | test.rs:29:24:29:57 | TryExpr | test.rs:29:9:29:20 | mut request1 | provenance | | -| test.rs:30:10:30:17 | request1 | test.rs:30:10:30:25 | request1.chunk() [future, Ok, Some] | provenance | MaD:27 | +| test.rs:30:10:30:17 | request1 | test.rs:30:10:30:25 | request1.chunk() [future, Ok, Some] | provenance | MaD:30 | | test.rs:30:10:30:25 | request1.chunk() [future, Ok, Some] | test.rs:30:10:30:31 | await ... [Ok, Some] | provenance | | | test.rs:30:10:30:31 | await ... [Ok, Some] | test.rs:30:10:30:32 | TryExpr [Some] | provenance | | -| test.rs:30:10:30:32 | TryExpr [Some] | test.rs:30:10:30:41 | ... .unwrap() | provenance | MaD:20 | +| test.rs:30:10:30:32 | TryExpr [Some] | test.rs:30:10:30:41 | ... .unwrap() | provenance | MaD:23 | | test.rs:31:15:31:25 | Some(...) [Some] | test.rs:31:20:31:24 | chunk | provenance | | | test.rs:31:20:31:24 | chunk | test.rs:32:14:32:18 | chunk | provenance | | -| test.rs:31:29:31:36 | request1 | test.rs:31:29:31:44 | request1.chunk() [future, Ok, Some] | provenance | MaD:27 | +| test.rs:31:29:31:36 | request1 | test.rs:31:29:31:44 | request1.chunk() [future, Ok, Some] | provenance | MaD:30 | | test.rs:31:29:31:44 | request1.chunk() [future, Ok, Some] | test.rs:31:29:31:50 | await ... [Ok, Some] | provenance | | | test.rs:31:29:31:50 | await ... [Ok, Some] | test.rs:31:29:31:51 | TryExpr [Some] | provenance | | | test.rs:31:29:31:51 | TryExpr [Some] | test.rs:31:15:31:25 | Some(...) [Some] | provenance | | @@ -105,24 +109,24 @@ edges | test.rs:67:31:67:42 | send_request | test.rs:67:24:67:51 | sender.send_request(...) [future, Ok] | provenance | Src:MaD:2 | | test.rs:68:11:68:18 | response | test.rs:68:10:68:18 | &response | provenance | | | test.rs:155:13:155:22 | mut stream | test.rs:162:17:162:22 | stream | provenance | | -| test.rs:155:26:155:53 | ...::connect | test.rs:155:26:155:62 | ...::connect(...) [Ok] | provenance | Src:MaD:3 | +| test.rs:155:26:155:53 | ...::connect | test.rs:155:26:155:62 | ...::connect(...) [Ok] | provenance | Src:MaD:4 | | test.rs:155:26:155:62 | ...::connect(...) [Ok] | test.rs:155:26:155:63 | TryExpr | provenance | | | test.rs:155:26:155:63 | TryExpr | test.rs:155:13:155:22 | mut stream | provenance | | -| test.rs:162:17:162:22 | stream | test.rs:162:29:162:39 | [post] &mut buffer [&ref] | provenance | MaD:17 | +| test.rs:162:17:162:22 | stream | test.rs:162:29:162:39 | [post] &mut buffer [&ref] | provenance | MaD:18 | | test.rs:162:29:162:39 | [post] &mut buffer [&ref] | test.rs:162:34:162:39 | [post] buffer | provenance | | | test.rs:162:34:162:39 | [post] buffer | test.rs:165:15:165:20 | buffer | provenance | | | test.rs:162:34:162:39 | [post] buffer | test.rs:166:14:166:19 | buffer | provenance | | | test.rs:165:15:165:20 | buffer | test.rs:165:14:165:20 | &buffer | provenance | | -| test.rs:166:14:166:19 | buffer | test.rs:166:14:166:22 | buffer[0] | provenance | MaD:8 | +| test.rs:166:14:166:19 | buffer | test.rs:166:14:166:22 | buffer[0] | provenance | MaD:9 | | test.rs:174:13:174:22 | mut stream | test.rs:182:58:182:63 | stream | provenance | | -| test.rs:174:26:174:61 | ...::connect_timeout | test.rs:174:26:174:105 | ...::connect_timeout(...) [Ok] | provenance | Src:MaD:4 | +| test.rs:174:26:174:61 | ...::connect_timeout | test.rs:174:26:174:105 | ...::connect_timeout(...) [Ok] | provenance | Src:MaD:5 | | test.rs:174:26:174:105 | ...::connect_timeout(...) [Ok] | test.rs:174:26:174:106 | TryExpr | provenance | | | test.rs:174:26:174:106 | TryExpr | test.rs:174:13:174:22 | mut stream | provenance | | | test.rs:182:21:182:30 | mut reader | test.rs:185:27:185:32 | reader | provenance | | -| test.rs:182:34:182:64 | ...::new(...) | test.rs:182:34:182:74 | ... .take(...) | provenance | MaD:18 | +| test.rs:182:34:182:64 | ...::new(...) | test.rs:182:34:182:74 | ... .take(...) | provenance | MaD:21 | | test.rs:182:34:182:74 | ... .take(...) | test.rs:182:21:182:30 | mut reader | provenance | | -| test.rs:182:58:182:63 | stream | test.rs:182:34:182:64 | ...::new(...) | provenance | MaD:32 | -| test.rs:185:27:185:32 | reader | test.rs:185:44:185:52 | [post] &mut line [&ref] | provenance | MaD:16 | +| test.rs:182:58:182:63 | stream | test.rs:182:34:182:64 | ...::new(...) | provenance | MaD:36 | +| test.rs:185:27:185:32 | reader | test.rs:185:44:185:52 | [post] &mut line [&ref] | provenance | MaD:17 | | test.rs:185:44:185:52 | [post] &mut line [&ref] | test.rs:185:49:185:52 | [post] line | provenance | | | test.rs:185:49:185:52 | [post] line | test.rs:192:35:192:38 | line | provenance | | | test.rs:192:35:192:38 | line | test.rs:192:34:192:38 | &line | provenance | | @@ -130,30 +134,53 @@ edges | test.rs:224:9:224:24 | mut tokio_stream | test.rs:236:18:236:29 | tokio_stream | provenance | | | test.rs:224:9:224:24 | mut tokio_stream | test.rs:252:19:252:30 | tokio_stream | provenance | | | test.rs:224:9:224:24 | mut tokio_stream | test.rs:275:19:275:30 | tokio_stream | provenance | | -| test.rs:224:28:224:57 | ...::connect | test.rs:224:28:224:66 | ...::connect(...) [future, Ok] | provenance | Src:MaD:5 | +| test.rs:224:28:224:57 | ...::connect | test.rs:224:28:224:66 | ...::connect(...) [future, Ok] | provenance | Src:MaD:6 | | test.rs:224:28:224:66 | ...::connect(...) [future, Ok] | test.rs:224:28:224:72 | await ... [Ok] | provenance | | | test.rs:224:28:224:72 | await ... [Ok] | test.rs:224:28:224:73 | TryExpr | provenance | | | test.rs:224:28:224:73 | TryExpr | test.rs:224:9:224:24 | mut tokio_stream | provenance | | -| test.rs:232:17:232:28 | tokio_stream | test.rs:232:35:232:46 | [post] &mut buffer1 [&ref] | provenance | MaD:33 | +| test.rs:232:17:232:28 | tokio_stream | test.rs:232:35:232:46 | [post] &mut buffer1 [&ref] | provenance | MaD:37 | | test.rs:232:35:232:46 | [post] &mut buffer1 [&ref] | test.rs:232:40:232:46 | [post] buffer1 | provenance | | | test.rs:232:40:232:46 | [post] buffer1 | test.rs:239:15:239:21 | buffer1 | provenance | | | test.rs:232:40:232:46 | [post] buffer1 | test.rs:240:14:240:20 | buffer1 | provenance | | -| test.rs:236:18:236:29 | tokio_stream | test.rs:236:36:236:47 | [post] &mut buffer2 [&ref] | provenance | MaD:19 | +| test.rs:236:18:236:29 | tokio_stream | test.rs:236:36:236:47 | [post] &mut buffer2 [&ref] | provenance | MaD:22 | | test.rs:236:36:236:47 | [post] &mut buffer2 [&ref] | test.rs:236:41:236:47 | [post] buffer2 | provenance | | | test.rs:236:41:236:47 | [post] buffer2 | test.rs:243:15:243:21 | buffer2 | provenance | | | test.rs:236:41:236:47 | [post] buffer2 | test.rs:244:14:244:20 | buffer2 | provenance | | | test.rs:239:15:239:21 | buffer1 | test.rs:239:14:239:21 | &buffer1 | provenance | | -| test.rs:240:14:240:20 | buffer1 | test.rs:240:14:240:23 | buffer1[0] | provenance | MaD:8 | +| test.rs:240:14:240:20 | buffer1 | test.rs:240:14:240:23 | buffer1[0] | provenance | MaD:9 | | test.rs:243:15:243:21 | buffer2 | test.rs:243:14:243:21 | &buffer2 | provenance | | -| test.rs:244:14:244:20 | buffer2 | test.rs:244:14:244:23 | buffer2[0] | provenance | MaD:8 | -| test.rs:252:19:252:30 | tokio_stream | test.rs:252:41:252:51 | [post] &mut buffer [&ref] | provenance | MaD:34 | +| test.rs:244:14:244:20 | buffer2 | test.rs:244:14:244:23 | buffer2[0] | provenance | MaD:9 | +| test.rs:252:19:252:30 | tokio_stream | test.rs:252:41:252:51 | [post] &mut buffer [&ref] | provenance | MaD:38 | | test.rs:252:41:252:51 | [post] &mut buffer [&ref] | test.rs:252:46:252:51 | [post] buffer | provenance | | | test.rs:252:46:252:51 | [post] buffer | test.rs:259:27:259:32 | buffer | provenance | | | test.rs:259:27:259:32 | buffer | test.rs:259:26:259:32 | &buffer | provenance | | -| test.rs:275:19:275:30 | tokio_stream | test.rs:275:45:275:55 | [post] &mut buffer [&ref] | provenance | MaD:35 | +| test.rs:275:19:275:30 | tokio_stream | test.rs:275:45:275:55 | [post] &mut buffer [&ref] | provenance | MaD:39 | | test.rs:275:45:275:55 | [post] &mut buffer [&ref] | test.rs:275:50:275:55 | [post] buffer | provenance | | | test.rs:275:50:275:55 | [post] buffer | test.rs:282:27:282:32 | buffer | provenance | | | test.rs:282:27:282:32 | buffer | test.rs:282:26:282:32 | &buffer | provenance | | +| test.rs:332:9:332:18 | mut client | test.rs:333:22:333:27 | client | provenance | | +| test.rs:332:22:332:50 | ...::new | test.rs:332:22:332:75 | ...::new(...) [Ok] | provenance | Src:MaD:3 | +| test.rs:332:22:332:75 | ...::new(...) [Ok] | test.rs:332:22:332:84 | ... .unwrap() | provenance | MaD:26 | +| test.rs:332:22:332:84 | ... .unwrap() | test.rs:332:9:332:18 | mut client | provenance | | +| test.rs:333:9:333:18 | mut reader | test.rs:334:11:334:16 | reader | provenance | | +| test.rs:333:9:333:18 | mut reader | test.rs:338:22:338:27 | reader | provenance | | +| test.rs:333:9:333:18 | mut reader | test.rs:344:22:344:27 | reader | provenance | | +| test.rs:333:9:333:18 | mut reader | test.rs:350:22:350:27 | reader | provenance | | +| test.rs:333:22:333:27 | client | test.rs:333:22:333:36 | client.reader() | provenance | MaD:35 | +| test.rs:333:22:333:36 | client.reader() | test.rs:333:9:333:18 | mut reader | provenance | | +| test.rs:334:11:334:16 | reader | test.rs:334:10:334:16 | &reader | provenance | | +| test.rs:338:22:338:27 | reader | test.rs:338:34:338:44 | [post] &mut buffer [&ref] | provenance | MaD:18 | +| test.rs:338:34:338:44 | [post] &mut buffer [&ref] | test.rs:338:39:338:44 | [post] buffer | provenance | | +| test.rs:338:39:338:44 | [post] buffer | test.rs:339:15:339:20 | buffer | provenance | | +| test.rs:339:15:339:20 | buffer | test.rs:339:14:339:20 | &buffer | provenance | | +| test.rs:344:22:344:27 | reader | test.rs:344:41:344:51 | [post] &mut buffer [&ref] | provenance | MaD:19 | +| test.rs:344:41:344:51 | [post] &mut buffer [&ref] | test.rs:344:46:344:51 | [post] buffer | provenance | | +| test.rs:344:46:344:51 | [post] buffer | test.rs:345:15:345:20 | buffer | provenance | | +| test.rs:345:15:345:20 | buffer | test.rs:345:14:345:20 | &buffer | provenance | | +| test.rs:350:22:350:27 | reader | test.rs:350:44:350:54 | [post] &mut buffer [&ref] | provenance | MaD:20 | +| test.rs:350:44:350:54 | [post] &mut buffer [&ref] | test.rs:350:49:350:54 | [post] buffer | provenance | | +| test.rs:350:49:350:54 | [post] buffer | test.rs:351:15:351:20 | buffer | provenance | | +| test.rs:351:15:351:20 | buffer | test.rs:351:14:351:20 | &buffer | provenance | | | test.rs:373:13:373:15 | tcp | test.rs:374:15:374:17 | tcp | provenance | | | test.rs:373:13:373:15 | tcp | test.rs:380:57:380:59 | tcp | provenance | | | test.rs:373:19:373:36 | ...::connect | test.rs:373:19:373:41 | ...::connect(...) [future, Ok] | provenance | Src:MaD:1 | @@ -169,38 +196,38 @@ edges | test.rs:380:26:380:60 | connector.connect(...) [future, Ok] | test.rs:380:26:380:66 | await ... [Ok] | provenance | | | test.rs:380:26:380:66 | await ... [Ok] | test.rs:380:26:380:67 | TryExpr | provenance | | | test.rs:380:26:380:67 | TryExpr | test.rs:380:13:380:22 | mut reader | provenance | | -| test.rs:380:57:380:59 | tcp | test.rs:380:26:380:60 | connector.connect(...) [future, Ok] | provenance | MaD:24 | +| test.rs:380:57:380:59 | tcp | test.rs:380:26:380:60 | connector.connect(...) [future, Ok] | provenance | MaD:27 | | test.rs:381:15:381:20 | reader | test.rs:381:14:381:20 | &reader | provenance | | | test.rs:386:17:386:26 | mut pinned | test.rs:387:19:387:24 | pinned | provenance | | | test.rs:386:17:386:26 | mut pinned | test.rs:389:30:389:35 | pinned | provenance | | | test.rs:386:17:386:26 | mut pinned [Pin, &ref] | test.rs:387:19:387:24 | pinned [Pin, &ref] | provenance | | | test.rs:386:30:386:50 | ...::new(...) | test.rs:386:17:386:26 | mut pinned | provenance | | | test.rs:386:30:386:50 | ...::new(...) [Pin, &ref] | test.rs:386:17:386:26 | mut pinned [Pin, &ref] | provenance | | -| test.rs:386:39:386:49 | &mut reader [&ref] | test.rs:386:30:386:50 | ...::new(...) | provenance | MaD:21 | -| test.rs:386:39:386:49 | &mut reader [&ref] | test.rs:386:30:386:50 | ...::new(...) [Pin, &ref] | provenance | MaD:22 | +| test.rs:386:39:386:49 | &mut reader [&ref] | test.rs:386:30:386:50 | ...::new(...) | provenance | MaD:24 | +| test.rs:386:39:386:49 | &mut reader [&ref] | test.rs:386:30:386:50 | ...::new(...) [Pin, &ref] | provenance | MaD:25 | | test.rs:386:44:386:49 | reader | test.rs:386:39:386:49 | &mut reader [&ref] | provenance | | | test.rs:387:19:387:24 | pinned | test.rs:387:18:387:24 | &pinned | provenance | | | test.rs:387:19:387:24 | pinned [Pin, &ref] | test.rs:387:18:387:24 | &pinned | provenance | | -| test.rs:389:30:389:35 | pinned | test.rs:389:56:389:66 | [post] &mut buffer [&ref] | provenance | MaD:10 | +| test.rs:389:30:389:35 | pinned | test.rs:389:56:389:66 | [post] &mut buffer [&ref] | provenance | MaD:11 | | test.rs:389:56:389:66 | [post] &mut buffer [&ref] | test.rs:389:61:389:66 | [post] buffer | provenance | | | test.rs:389:61:389:66 | [post] buffer | test.rs:391:23:391:28 | buffer | provenance | | | test.rs:389:61:389:66 | [post] buffer | test.rs:392:23:392:28 | buffer | provenance | | | test.rs:389:61:389:66 | [post] buffer | test.rs:392:23:392:33 | buffer[...] | provenance | | | test.rs:391:23:391:28 | buffer | test.rs:391:22:391:28 | &buffer | provenance | | -| test.rs:392:23:392:28 | buffer | test.rs:392:23:392:33 | buffer[...] | provenance | MaD:8 | +| test.rs:392:23:392:28 | buffer | test.rs:392:23:392:33 | buffer[...] | provenance | MaD:9 | | test.rs:392:23:392:33 | buffer[...] | test.rs:392:22:392:33 | &... | provenance | | -| test.rs:399:63:399:73 | &mut reader [&ref] | test.rs:399:76:399:87 | [post] &mut buffer1 [&ref] | provenance | MaD:14 | +| test.rs:399:63:399:73 | &mut reader [&ref] | test.rs:399:76:399:87 | [post] &mut buffer1 [&ref] | provenance | MaD:15 | | test.rs:399:68:399:73 | reader | test.rs:399:63:399:73 | &mut reader [&ref] | provenance | | | test.rs:399:76:399:87 | [post] &mut buffer1 [&ref] | test.rs:399:81:399:87 | [post] buffer1 | provenance | | | test.rs:399:81:399:87 | [post] buffer1 | test.rs:400:19:400:25 | buffer1 | provenance | | | test.rs:399:81:399:87 | [post] buffer1 | test.rs:400:19:400:40 | buffer1[...] | provenance | | -| test.rs:400:19:400:25 | buffer1 | test.rs:400:19:400:40 | buffer1[...] | provenance | MaD:8 | +| test.rs:400:19:400:25 | buffer1 | test.rs:400:19:400:40 | buffer1[...] | provenance | MaD:9 | | test.rs:400:19:400:40 | buffer1[...] | test.rs:400:18:400:40 | &... | provenance | | -| test.rs:403:31:403:36 | reader | test.rs:403:43:403:54 | [post] &mut buffer2 [&ref] | provenance | MaD:14 | +| test.rs:403:31:403:36 | reader | test.rs:403:43:403:54 | [post] &mut buffer2 [&ref] | provenance | MaD:15 | | test.rs:403:43:403:54 | [post] &mut buffer2 [&ref] | test.rs:403:48:403:54 | [post] buffer2 | provenance | | | test.rs:403:48:403:54 | [post] buffer2 | test.rs:405:19:405:25 | buffer2 | provenance | | | test.rs:403:48:403:54 | [post] buffer2 | test.rs:405:19:405:40 | buffer2[...] | provenance | | -| test.rs:405:19:405:25 | buffer2 | test.rs:405:19:405:40 | buffer2[...] | provenance | MaD:8 | +| test.rs:405:19:405:25 | buffer2 | test.rs:405:19:405:40 | buffer2[...] | provenance | MaD:9 | | test.rs:405:19:405:40 | buffer2[...] | test.rs:405:18:405:40 | &... | provenance | | | test.rs:408:13:408:23 | mut reader2 | test.rs:409:15:409:21 | reader2 | provenance | | | test.rs:408:13:408:23 | mut reader2 | test.rs:413:44:413:50 | reader2 | provenance | | @@ -215,30 +242,30 @@ edges | test.rs:408:13:408:23 | mut reader2 | test.rs:493:31:493:37 | reader2 | provenance | | | test.rs:408:13:408:23 | mut reader2 | test.rs:500:31:500:37 | reader2 | provenance | | | test.rs:408:27:408:61 | ...::new(...) | test.rs:408:13:408:23 | mut reader2 | provenance | | -| test.rs:408:55:408:60 | reader | test.rs:408:27:408:61 | ...::new(...) | provenance | MaD:25 | +| test.rs:408:55:408:60 | reader | test.rs:408:27:408:61 | ...::new(...) | provenance | MaD:28 | | test.rs:409:15:409:21 | reader2 | test.rs:409:14:409:21 | &reader2 | provenance | | | test.rs:413:17:413:26 | mut pinned | test.rs:414:19:414:24 | pinned | provenance | | | test.rs:413:17:413:26 | mut pinned | test.rs:416:26:416:31 | pinned | provenance | | | test.rs:413:17:413:26 | mut pinned [Pin, &ref] | test.rs:414:19:414:24 | pinned [Pin, &ref] | provenance | | | test.rs:413:30:413:51 | ...::new(...) | test.rs:413:17:413:26 | mut pinned | provenance | | | test.rs:413:30:413:51 | ...::new(...) [Pin, &ref] | test.rs:413:17:413:26 | mut pinned [Pin, &ref] | provenance | | -| test.rs:413:39:413:50 | &mut reader2 [&ref] | test.rs:413:30:413:51 | ...::new(...) | provenance | MaD:21 | -| test.rs:413:39:413:50 | &mut reader2 [&ref] | test.rs:413:30:413:51 | ...::new(...) [Pin, &ref] | provenance | MaD:22 | +| test.rs:413:39:413:50 | &mut reader2 [&ref] | test.rs:413:30:413:51 | ...::new(...) | provenance | MaD:24 | +| test.rs:413:39:413:50 | &mut reader2 [&ref] | test.rs:413:30:413:51 | ...::new(...) [Pin, &ref] | provenance | MaD:25 | | test.rs:413:44:413:50 | reader2 | test.rs:413:39:413:50 | &mut reader2 [&ref] | provenance | | | test.rs:414:19:414:24 | pinned | test.rs:414:18:414:24 | &pinned | provenance | | | test.rs:414:19:414:24 | pinned [Pin, &ref] | test.rs:414:18:414:24 | &pinned | provenance | | | test.rs:416:17:416:22 | buffer [Ready, Ok] | test.rs:417:20:417:39 | ...::Ready(...) [Ready, Ok] | provenance | | | test.rs:416:17:416:22 | buffer [Ready, Ok] | test.rs:418:23:418:28 | buffer [Ready, Ok] | provenance | | -| test.rs:416:26:416:31 | pinned | test.rs:416:26:416:54 | pinned.poll_fill_buf(...) [Ready, Ok] | provenance | MaD:9 | +| test.rs:416:26:416:31 | pinned | test.rs:416:26:416:54 | pinned.poll_fill_buf(...) [Ready, Ok] | provenance | MaD:10 | | test.rs:416:26:416:54 | pinned.poll_fill_buf(...) [Ready, Ok] | test.rs:416:17:416:22 | buffer [Ready, Ok] | provenance | | | test.rs:417:20:417:39 | ...::Ready(...) [Ready, Ok] | test.rs:417:32:417:38 | Ok(...) [Ok] | provenance | | | test.rs:417:32:417:38 | Ok(...) [Ok] | test.rs:417:35:417:37 | buf | provenance | | | test.rs:417:35:417:37 | buf | test.rs:419:22:419:24 | buf | provenance | | | test.rs:418:23:418:28 | buffer [Ready, Ok] | test.rs:418:22:418:28 | &buffer | provenance | | | test.rs:423:17:423:23 | buffer2 [Ready, Ok] | test.rs:424:20:424:26 | buffer2 [Ready, Ok] | provenance | | -| test.rs:423:27:423:48 | ...::new(...) | test.rs:423:27:423:71 | ... .poll_fill_buf(...) [Ready, Ok] | provenance | MaD:9 | +| test.rs:423:27:423:48 | ...::new(...) | test.rs:423:27:423:71 | ... .poll_fill_buf(...) [Ready, Ok] | provenance | MaD:10 | | test.rs:423:27:423:71 | ... .poll_fill_buf(...) [Ready, Ok] | test.rs:423:17:423:23 | buffer2 [Ready, Ok] | provenance | | -| test.rs:423:36:423:47 | &mut reader2 [&ref] | test.rs:423:27:423:48 | ...::new(...) | provenance | MaD:21 | +| test.rs:423:36:423:47 | &mut reader2 [&ref] | test.rs:423:27:423:48 | ...::new(...) | provenance | MaD:24 | | test.rs:423:41:423:47 | reader2 | test.rs:423:36:423:47 | &mut reader2 [&ref] | provenance | | | test.rs:424:20:424:26 | buffer2 [Ready, Ok] | test.rs:425:17:425:36 | ...::Ready(...) [Ready, Ok] | provenance | | | test.rs:424:20:424:26 | buffer2 [Ready, Ok] | test.rs:426:27:426:33 | buffer2 [Ready, Ok] | provenance | | @@ -247,7 +274,7 @@ edges | test.rs:425:32:425:34 | buf | test.rs:427:26:427:28 | buf | provenance | | | test.rs:426:27:426:33 | buffer2 [Ready, Ok] | test.rs:426:26:426:33 | &buffer2 | provenance | | | test.rs:437:17:437:22 | buffer | test.rs:438:18:438:23 | buffer | provenance | | -| test.rs:437:26:437:32 | reader2 | test.rs:437:26:437:43 | reader2.fill_buf() [future, Ok] | provenance | MaD:11 | +| test.rs:437:26:437:32 | reader2 | test.rs:437:26:437:43 | reader2.fill_buf() [future, Ok] | provenance | MaD:12 | | test.rs:437:26:437:43 | reader2.fill_buf() [future, Ok] | test.rs:437:26:437:49 | await ... [Ok] | provenance | | | test.rs:437:26:437:49 | await ... [Ok] | test.rs:437:26:437:50 | TryExpr | provenance | | | test.rs:437:26:437:50 | TryExpr | test.rs:437:17:437:22 | buffer | provenance | | @@ -256,64 +283,64 @@ edges | test.rs:444:17:444:26 | mut pinned [Pin, &ref] | test.rs:445:19:445:24 | pinned [Pin, &ref] | provenance | | | test.rs:444:30:444:51 | ...::new(...) | test.rs:444:17:444:26 | mut pinned | provenance | | | test.rs:444:30:444:51 | ...::new(...) [Pin, &ref] | test.rs:444:17:444:26 | mut pinned [Pin, &ref] | provenance | | -| test.rs:444:39:444:50 | &mut reader2 [&ref] | test.rs:444:30:444:51 | ...::new(...) | provenance | MaD:21 | -| test.rs:444:39:444:50 | &mut reader2 [&ref] | test.rs:444:30:444:51 | ...::new(...) [Pin, &ref] | provenance | MaD:22 | +| test.rs:444:39:444:50 | &mut reader2 [&ref] | test.rs:444:30:444:51 | ...::new(...) | provenance | MaD:24 | +| test.rs:444:39:444:50 | &mut reader2 [&ref] | test.rs:444:30:444:51 | ...::new(...) [Pin, &ref] | provenance | MaD:25 | | test.rs:444:44:444:50 | reader2 | test.rs:444:39:444:50 | &mut reader2 [&ref] | provenance | | | test.rs:445:19:445:24 | pinned | test.rs:445:18:445:24 | &pinned | provenance | | | test.rs:445:19:445:24 | pinned [Pin, &ref] | test.rs:445:18:445:24 | &pinned | provenance | | -| test.rs:447:30:447:35 | pinned | test.rs:447:56:447:66 | [post] &mut buffer [&ref] | provenance | MaD:10 | +| test.rs:447:30:447:35 | pinned | test.rs:447:56:447:66 | [post] &mut buffer [&ref] | provenance | MaD:11 | | test.rs:447:56:447:66 | [post] &mut buffer [&ref] | test.rs:447:61:447:66 | [post] buffer | provenance | | | test.rs:447:61:447:66 | [post] buffer | test.rs:448:19:448:24 | buffer | provenance | | | test.rs:447:61:447:66 | [post] buffer | test.rs:450:23:450:28 | buffer | provenance | | | test.rs:447:61:447:66 | [post] buffer | test.rs:450:23:450:33 | buffer[...] | provenance | | | test.rs:448:19:448:24 | buffer | test.rs:448:18:448:24 | &buffer | provenance | | -| test.rs:450:23:450:28 | buffer | test.rs:450:23:450:33 | buffer[...] | provenance | MaD:8 | +| test.rs:450:23:450:28 | buffer | test.rs:450:23:450:33 | buffer[...] | provenance | MaD:9 | | test.rs:450:23:450:33 | buffer[...] | test.rs:450:22:450:33 | &... | provenance | | -| test.rs:457:63:457:74 | &mut reader2 [&ref] | test.rs:457:77:457:88 | [post] &mut buffer1 [&ref] | provenance | MaD:14 | +| test.rs:457:63:457:74 | &mut reader2 [&ref] | test.rs:457:77:457:88 | [post] &mut buffer1 [&ref] | provenance | MaD:15 | | test.rs:457:68:457:74 | reader2 | test.rs:457:63:457:74 | &mut reader2 [&ref] | provenance | | | test.rs:457:77:457:88 | [post] &mut buffer1 [&ref] | test.rs:457:82:457:88 | [post] buffer1 | provenance | | | test.rs:457:82:457:88 | [post] buffer1 | test.rs:458:19:458:25 | buffer1 | provenance | | | test.rs:457:82:457:88 | [post] buffer1 | test.rs:458:19:458:40 | buffer1[...] | provenance | | -| test.rs:458:19:458:25 | buffer1 | test.rs:458:19:458:40 | buffer1[...] | provenance | MaD:8 | +| test.rs:458:19:458:25 | buffer1 | test.rs:458:19:458:40 | buffer1[...] | provenance | MaD:9 | | test.rs:458:19:458:40 | buffer1[...] | test.rs:458:18:458:40 | &... | provenance | | -| test.rs:461:31:461:37 | reader2 | test.rs:461:44:461:55 | [post] &mut buffer2 [&ref] | provenance | MaD:14 | +| test.rs:461:31:461:37 | reader2 | test.rs:461:44:461:55 | [post] &mut buffer2 [&ref] | provenance | MaD:15 | | test.rs:461:44:461:55 | [post] &mut buffer2 [&ref] | test.rs:461:49:461:55 | [post] buffer2 | provenance | | | test.rs:461:49:461:55 | [post] buffer2 | test.rs:462:19:462:25 | buffer2 | provenance | | | test.rs:461:49:461:55 | [post] buffer2 | test.rs:462:19:462:40 | buffer2[...] | provenance | | -| test.rs:462:19:462:25 | buffer2 | test.rs:462:19:462:40 | buffer2[...] | provenance | MaD:8 | +| test.rs:462:19:462:25 | buffer2 | test.rs:462:19:462:40 | buffer2[...] | provenance | MaD:9 | | test.rs:462:19:462:40 | buffer2[...] | test.rs:462:18:462:40 | &... | provenance | | | test.rs:467:17:467:26 | mut pinned | test.rs:468:19:468:24 | pinned | provenance | | | test.rs:467:17:467:26 | mut pinned | test.rs:470:26:470:31 | pinned | provenance | | | test.rs:467:17:467:26 | mut pinned [Pin, &ref] | test.rs:468:19:468:24 | pinned [Pin, &ref] | provenance | | | test.rs:467:30:467:51 | ...::new(...) | test.rs:467:17:467:26 | mut pinned | provenance | | | test.rs:467:30:467:51 | ...::new(...) [Pin, &ref] | test.rs:467:17:467:26 | mut pinned [Pin, &ref] | provenance | | -| test.rs:467:39:467:50 | &mut reader2 [&ref] | test.rs:467:30:467:51 | ...::new(...) | provenance | MaD:21 | -| test.rs:467:39:467:50 | &mut reader2 [&ref] | test.rs:467:30:467:51 | ...::new(...) [Pin, &ref] | provenance | MaD:22 | +| test.rs:467:39:467:50 | &mut reader2 [&ref] | test.rs:467:30:467:51 | ...::new(...) | provenance | MaD:24 | +| test.rs:467:39:467:50 | &mut reader2 [&ref] | test.rs:467:30:467:51 | ...::new(...) [Pin, &ref] | provenance | MaD:25 | | test.rs:467:44:467:50 | reader2 | test.rs:467:39:467:50 | &mut reader2 [&ref] | provenance | | | test.rs:468:19:468:24 | pinned | test.rs:468:18:468:24 | &pinned | provenance | | | test.rs:468:19:468:24 | pinned [Pin, &ref] | test.rs:468:18:468:24 | &pinned | provenance | | | test.rs:470:17:470:22 | buffer [Ready, Ok] | test.rs:471:19:471:24 | buffer [Ready, Ok] | provenance | | | test.rs:470:17:470:22 | buffer [Ready, Ok] | test.rs:472:20:472:39 | ...::Ready(...) [Ready, Ok] | provenance | | -| test.rs:470:26:470:31 | pinned | test.rs:470:26:470:54 | pinned.poll_fill_buf(...) [Ready, Ok] | provenance | MaD:9 | +| test.rs:470:26:470:31 | pinned | test.rs:470:26:470:54 | pinned.poll_fill_buf(...) [Ready, Ok] | provenance | MaD:10 | | test.rs:470:26:470:54 | pinned.poll_fill_buf(...) [Ready, Ok] | test.rs:470:17:470:22 | buffer [Ready, Ok] | provenance | | | test.rs:471:19:471:24 | buffer [Ready, Ok] | test.rs:471:18:471:24 | &buffer | provenance | | | test.rs:472:20:472:39 | ...::Ready(...) [Ready, Ok] | test.rs:472:32:472:38 | Ok(...) [Ok] | provenance | | | test.rs:472:32:472:38 | Ok(...) [Ok] | test.rs:472:35:472:37 | buf | provenance | | | test.rs:472:35:472:37 | buf | test.rs:473:22:473:24 | buf | provenance | | | test.rs:479:17:479:22 | buffer | test.rs:480:18:480:23 | buffer | provenance | | -| test.rs:479:26:479:32 | reader2 | test.rs:479:26:479:43 | reader2.fill_buf() [future, Ok] | provenance | MaD:11 | +| test.rs:479:26:479:32 | reader2 | test.rs:479:26:479:43 | reader2.fill_buf() [future, Ok] | provenance | MaD:12 | | test.rs:479:26:479:43 | reader2.fill_buf() [future, Ok] | test.rs:479:26:479:49 | await ... [Ok] | provenance | | | test.rs:479:26:479:49 | await ... [Ok] | test.rs:479:26:479:50 | TryExpr | provenance | | | test.rs:479:26:479:50 | TryExpr | test.rs:479:17:479:22 | buffer | provenance | | -| test.rs:486:31:486:37 | reader2 | test.rs:486:57:486:65 | [post] &mut line [&ref] | provenance | MaD:13 | +| test.rs:486:31:486:37 | reader2 | test.rs:486:57:486:65 | [post] &mut line [&ref] | provenance | MaD:14 | | test.rs:486:57:486:65 | [post] &mut line [&ref] | test.rs:486:62:486:65 | [post] line | provenance | | | test.rs:486:62:486:65 | [post] line | test.rs:487:19:487:22 | line | provenance | | | test.rs:487:19:487:22 | line | test.rs:487:18:487:22 | &line | provenance | | -| test.rs:493:31:493:37 | reader2 | test.rs:493:49:493:57 | [post] &mut line [&ref] | provenance | MaD:12 | +| test.rs:493:31:493:37 | reader2 | test.rs:493:49:493:57 | [post] &mut line [&ref] | provenance | MaD:13 | | test.rs:493:49:493:57 | [post] &mut line [&ref] | test.rs:493:54:493:57 | [post] line | provenance | | | test.rs:493:54:493:57 | [post] line | test.rs:494:19:494:22 | line | provenance | | | test.rs:494:19:494:22 | line | test.rs:494:18:494:22 | &line | provenance | | -| test.rs:500:31:500:37 | reader2 | test.rs:500:51:500:61 | [post] &mut buffer [&ref] | provenance | MaD:15 | +| test.rs:500:31:500:37 | reader2 | test.rs:500:51:500:61 | [post] &mut buffer [&ref] | provenance | MaD:16 | | test.rs:500:51:500:61 | [post] &mut buffer [&ref] | test.rs:500:56:500:61 | [post] buffer | provenance | | | test.rs:500:56:500:61 | [post] buffer | test.rs:501:19:501:24 | buffer | provenance | | | test.rs:501:19:501:24 | buffer | test.rs:501:18:501:24 | &buffer | provenance | | @@ -449,6 +476,30 @@ nodes | test.rs:275:50:275:55 | [post] buffer | semmle.label | [post] buffer | | test.rs:282:26:282:32 | &buffer | semmle.label | &buffer | | test.rs:282:27:282:32 | buffer | semmle.label | buffer | +| test.rs:332:9:332:18 | mut client | semmle.label | mut client | +| test.rs:332:22:332:50 | ...::new | semmle.label | ...::new | +| test.rs:332:22:332:75 | ...::new(...) [Ok] | semmle.label | ...::new(...) [Ok] | +| test.rs:332:22:332:84 | ... .unwrap() | semmle.label | ... .unwrap() | +| test.rs:333:9:333:18 | mut reader | semmle.label | mut reader | +| test.rs:333:22:333:27 | client | semmle.label | client | +| test.rs:333:22:333:36 | client.reader() | semmle.label | client.reader() | +| test.rs:334:10:334:16 | &reader | semmle.label | &reader | +| test.rs:334:11:334:16 | reader | semmle.label | reader | +| test.rs:338:22:338:27 | reader | semmle.label | reader | +| test.rs:338:34:338:44 | [post] &mut buffer [&ref] | semmle.label | [post] &mut buffer [&ref] | +| test.rs:338:39:338:44 | [post] buffer | semmle.label | [post] buffer | +| test.rs:339:14:339:20 | &buffer | semmle.label | &buffer | +| test.rs:339:15:339:20 | buffer | semmle.label | buffer | +| test.rs:344:22:344:27 | reader | semmle.label | reader | +| test.rs:344:41:344:51 | [post] &mut buffer [&ref] | semmle.label | [post] &mut buffer [&ref] | +| test.rs:344:46:344:51 | [post] buffer | semmle.label | [post] buffer | +| test.rs:345:14:345:20 | &buffer | semmle.label | &buffer | +| test.rs:345:15:345:20 | buffer | semmle.label | buffer | +| test.rs:350:22:350:27 | reader | semmle.label | reader | +| test.rs:350:44:350:54 | [post] &mut buffer [&ref] | semmle.label | [post] &mut buffer [&ref] | +| test.rs:350:49:350:54 | [post] buffer | semmle.label | [post] buffer | +| test.rs:351:14:351:20 | &buffer | semmle.label | &buffer | +| test.rs:351:15:351:20 | buffer | semmle.label | buffer | | test.rs:373:13:373:15 | tcp | semmle.label | tcp | | test.rs:373:19:373:36 | ...::connect | semmle.label | ...::connect | | test.rs:373:19:373:41 | ...::connect(...) [future, Ok] | semmle.label | ...::connect(...) [future, Ok] | @@ -626,6 +677,10 @@ testFailures | test.rs:244:14:244:23 | buffer2[0] | test.rs:224:28:224:57 | ...::connect | test.rs:244:14:244:23 | buffer2[0] | $@ | test.rs:224:28:224:57 | ...::connect | ...::connect | | test.rs:259:26:259:32 | &buffer | test.rs:224:28:224:57 | ...::connect | test.rs:259:26:259:32 | &buffer | $@ | test.rs:224:28:224:57 | ...::connect | ...::connect | | test.rs:282:26:282:32 | &buffer | test.rs:224:28:224:57 | ...::connect | test.rs:282:26:282:32 | &buffer | $@ | test.rs:224:28:224:57 | ...::connect | ...::connect | +| test.rs:334:10:334:16 | &reader | test.rs:332:22:332:50 | ...::new | test.rs:334:10:334:16 | &reader | $@ | test.rs:332:22:332:50 | ...::new | ...::new | +| test.rs:339:14:339:20 | &buffer | test.rs:332:22:332:50 | ...::new | test.rs:339:14:339:20 | &buffer | $@ | test.rs:332:22:332:50 | ...::new | ...::new | +| test.rs:345:14:345:20 | &buffer | test.rs:332:22:332:50 | ...::new | test.rs:345:14:345:20 | &buffer | $@ | test.rs:332:22:332:50 | ...::new | ...::new | +| test.rs:351:14:351:20 | &buffer | test.rs:332:22:332:50 | ...::new | test.rs:351:14:351:20 | &buffer | $@ | test.rs:332:22:332:50 | ...::new | ...::new | | test.rs:374:14:374:17 | &tcp | test.rs:373:19:373:36 | ...::connect | test.rs:374:14:374:17 | &tcp | $@ | test.rs:373:19:373:36 | ...::connect | ...::connect | | test.rs:381:14:381:20 | &reader | test.rs:373:19:373:36 | ...::connect | test.rs:381:14:381:20 | &reader | $@ | test.rs:373:19:373:36 | ...::connect | ...::connect | | test.rs:387:18:387:24 | &pinned | test.rs:373:19:373:36 | ...::connect | test.rs:387:18:387:24 | &pinned | $@ | test.rs:373:19:373:36 | ...::connect | ...::connect | diff --git a/rust/ql/test/library-tests/dataflow/sources/net/test.rs b/rust/ql/test/library-tests/dataflow/sources/net/test.rs index 178f539dc6e..f029ac53805 100644 --- a/rust/ql/test/library-tests/dataflow/sources/net/test.rs +++ b/rust/ql/test/library-tests/dataflow/sources/net/test.rs @@ -330,25 +330,25 @@ fn test_rustls() -> std::io::Result<()> { let server_name = rustls::pki_types::ServerName::try_from("www.example.com").unwrap(); let config_arc = std::sync::Arc::new(config); let mut client = rustls::ClientConnection::new(config_arc, server_name).unwrap(); // $ Alert[rust/summary/taint-sources] - let mut reader = client.reader(); // We cannot resolve the `reader` call because it comes from `Deref`: https://docs.rs/rustls/latest/rustls/client/struct.ClientConnection.html#deref-methods-ConnectionCommon%3CClientConnectionData%3E - sink(&reader); // $ MISSING: hasTaintFlow=config_arc + let mut reader = client.reader(); + sink(&reader); // $ hasTaintFlow=config_arc { let mut buffer = [0u8; 100]; let _bytes = reader.read(&mut buffer)?; - sink(&buffer); // $ MISSING: hasTaintFlow=config_arc + sink(&buffer); // $ hasTaintFlow=config_arc } { let mut buffer = Vec::::new(); let _bytes = reader.read_to_end(&mut buffer)?; - sink(&buffer); // $ MISSING: hasTaintFlow=config_arc + sink(&buffer); // $ hasTaintFlow=config_arc } { let mut buffer = String::new(); let _bytes = reader.read_to_string(&mut buffer)?; - sink(&buffer); // $ MISSING: hasTaintFlow=config_arc + sink(&buffer); // $ hasTaintFlow=config_arc } Ok(()) diff --git a/rust/ql/test/library-tests/sensitivedata/test.rs b/rust/ql/test/library-tests/sensitivedata/test.rs index 0f4965ce285..f8d850beeb8 100644 --- a/rust/ql/test/library-tests/sensitivedata/test.rs +++ b/rust/ql/test/library-tests/sensitivedata/test.rs @@ -287,7 +287,7 @@ fn test_private_info( sink(&info.medical_notes); // $ sensitive=private sink(info.medical_notes[0].as_str()); // $ sensitive=private for n in info.medical_notes.iter() { - sink(n.as_str()); // $ MISSING: sensitive=private + sink(n.as_str()); // $ sensitive=private } sink(info.confidentialMessage.as_str()); // $ sensitive=secret sink(info.confidentialMessage.to_lowercase()); // $ sensitive=secret diff --git a/rust/ql/test/library-tests/type-inference/blanket_impl.rs b/rust/ql/test/library-tests/type-inference/blanket_impl.rs index c139af01c42..b25a0f8cf77 100644 --- a/rust/ql/test/library-tests/type-inference/blanket_impl.rs +++ b/rust/ql/test/library-tests/type-inference/blanket_impl.rs @@ -53,9 +53,9 @@ mod basic_blanket_impl { println!("{x4:?}"); let x5 = S1::duplicate(&S1); // $ target=Clone1duplicate println!("{x5:?}"); - let x6 = S2.duplicate(); // $ MISSING: target=Clone1duplicate + let x6 = S2.duplicate(); // $ target=Clone1duplicate println!("{x6:?}"); - let x7 = (&S2).duplicate(); // $ MISSING: target=Clone1duplicate + let x7 = (&S2).duplicate(); // $ target=Clone1duplicate println!("{x7:?}"); } } diff --git a/rust/ql/test/library-tests/type-inference/dereference.rs b/rust/ql/test/library-tests/type-inference/dereference.rs index 6e803d7eca6..4767e07576f 100644 --- a/rust/ql/test/library-tests/type-inference/dereference.rs +++ b/rust/ql/test/library-tests/type-inference/dereference.rs @@ -102,18 +102,18 @@ fn explicit_box_dereference() { fn implicit_dereference() { // Call method on implicitly dereferenced value let x = MyIntPointer { value: 34i64 }; - let _y = x.is_positive(); // $ MISSING: target=is_positive type=_y:bool + let _y = x.is_positive(); // $ target=is_positive type=_y:bool // Call method on implicitly dereferenced value let x = MySmartPointer { value: 34i64 }; - let _y = x.is_positive(); // $ MISSING: target=is_positive type=_y:bool + let _y = x.is_positive(); // $ target=is_positive type=_y:bool let z = MySmartPointer { value: S(0i64) }; - let z_ = z.foo(); // $ MISSING: target=foo type=z_:TRef.i64 + let z_ = z.foo(); // $ target=foo type=z_:TRef.i64 - let v = Vec::new(); // $ target=new $ MISSING: type=v:T.i32 + let v = Vec::new(); // $ target=new type=v:T.i32 let mut x = MySmartPointer { value: v }; - x.push(0); // $ MISSING: target=push + x.push(0); // $ target=push } mod implicit_deref_coercion_cycle { diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index d367525c7b8..840e17b52ef 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -2902,8 +2902,8 @@ pub mod path_buf { let path3 = path2.unwrap(); // $ target=unwrap type=path3:PathBuf let pathbuf1 = PathBuf::new(); // $ target=new certainType=pathbuf1:PathBuf - let pathbuf2 = pathbuf1.canonicalize(); // $ MISSING: target=canonicalize - let pathbuf3 = pathbuf2.unwrap(); // $ MISSING: target=unwrap type=pathbuf3:PathBuf + let pathbuf2 = pathbuf1.canonicalize(); // $ target=canonicalize + let pathbuf3 = pathbuf2.unwrap(); // $ target=unwrap type=pathbuf3:PathBuf } } diff --git a/rust/ql/test/library-tests/type-inference/type-inference.expected b/rust/ql/test/library-tests/type-inference/type-inference.expected index 19a00442499..a9328488156 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -4608,13 +4608,18 @@ inferType | blanket_impl.rs:55:18:55:25 | ...::_print(...) | | {EXTERNAL LOCATION} | () | | blanket_impl.rs:55:18:55:25 | { ... } | | {EXTERNAL LOCATION} | () | | blanket_impl.rs:55:20:55:21 | x5 | | blanket_impl.rs:6:5:7:14 | S1 | +| blanket_impl.rs:56:13:56:14 | x6 | | blanket_impl.rs:6:5:7:14 | S1 | | blanket_impl.rs:56:18:56:19 | S2 | | blanket_impl.rs:9:5:10:14 | S2 | +| blanket_impl.rs:56:18:56:31 | S2.duplicate() | | blanket_impl.rs:6:5:7:14 | S1 | | blanket_impl.rs:57:18:57:25 | "{x6:?}\\n" | | {EXTERNAL LOCATION} | & | | blanket_impl.rs:57:18:57:25 | "{x6:?}\\n" | TRef | {EXTERNAL LOCATION} | str | | blanket_impl.rs:57:18:57:25 | ...::_print(...) | | {EXTERNAL LOCATION} | () | | blanket_impl.rs:57:18:57:25 | { ... } | | {EXTERNAL LOCATION} | () | +| blanket_impl.rs:57:20:57:21 | x6 | | blanket_impl.rs:6:5:7:14 | S1 | +| blanket_impl.rs:58:13:58:14 | x7 | | blanket_impl.rs:6:5:7:14 | S1 | | blanket_impl.rs:58:18:58:22 | (...) | | {EXTERNAL LOCATION} | & | | blanket_impl.rs:58:18:58:22 | (...) | TRef | blanket_impl.rs:9:5:10:14 | S2 | +| blanket_impl.rs:58:18:58:34 | ... .duplicate() | | blanket_impl.rs:6:5:7:14 | S1 | | blanket_impl.rs:58:19:58:21 | &S2 | | {EXTERNAL LOCATION} | & | | blanket_impl.rs:58:19:58:21 | &S2 | TRef | blanket_impl.rs:9:5:10:14 | S2 | | blanket_impl.rs:58:20:58:21 | S2 | | blanket_impl.rs:9:5:10:14 | S2 | @@ -4622,6 +4627,7 @@ inferType | blanket_impl.rs:59:18:59:25 | "{x7:?}\\n" | TRef | {EXTERNAL LOCATION} | str | | blanket_impl.rs:59:18:59:25 | ...::_print(...) | | {EXTERNAL LOCATION} | () | | blanket_impl.rs:59:18:59:25 | { ... } | | {EXTERNAL LOCATION} | () | +| blanket_impl.rs:59:20:59:21 | x7 | | blanket_impl.rs:6:5:7:14 | S1 | | blanket_impl.rs:68:24:68:24 | x | | {EXTERNAL LOCATION} | i64 | | blanket_impl.rs:68:32:68:32 | y | | blanket_impl.rs:67:5:69:5 | Self [trait Trait1] | | blanket_impl.rs:72:24:72:24 | x | | {EXTERNAL LOCATION} | i64 | @@ -5249,14 +5255,18 @@ inferType | dereference.rs:104:9:104:9 | x | | dereference.rs:5:1:7:1 | MyIntPointer | | dereference.rs:104:13:104:41 | MyIntPointer {...} | | dereference.rs:5:1:7:1 | MyIntPointer | | dereference.rs:104:35:104:39 | 34i64 | | {EXTERNAL LOCATION} | i64 | +| dereference.rs:105:9:105:10 | _y | | {EXTERNAL LOCATION} | bool | | dereference.rs:105:14:105:14 | x | | dereference.rs:5:1:7:1 | MyIntPointer | +| dereference.rs:105:14:105:28 | x.is_positive() | | {EXTERNAL LOCATION} | bool | | dereference.rs:108:9:108:9 | x | | dereference.rs:18:1:20:1 | MySmartPointer | | dereference.rs:108:9:108:9 | x | T | {EXTERNAL LOCATION} | i64 | | dereference.rs:108:13:108:43 | MySmartPointer {...} | | dereference.rs:18:1:20:1 | MySmartPointer | | dereference.rs:108:13:108:43 | MySmartPointer {...} | T | {EXTERNAL LOCATION} | i64 | | dereference.rs:108:37:108:41 | 34i64 | | {EXTERNAL LOCATION} | i64 | +| dereference.rs:109:9:109:10 | _y | | {EXTERNAL LOCATION} | bool | | dereference.rs:109:14:109:14 | x | | dereference.rs:18:1:20:1 | MySmartPointer | | dereference.rs:109:14:109:14 | x | T | {EXTERNAL LOCATION} | i64 | +| dereference.rs:109:14:109:28 | x.is_positive() | | {EXTERNAL LOCATION} | bool | | dereference.rs:111:9:111:9 | z | | dereference.rs:18:1:20:1 | MySmartPointer | | dereference.rs:111:9:111:9 | z | T | dereference.rs:38:1:38:15 | S | | dereference.rs:111:9:111:9 | z | T.T | {EXTERNAL LOCATION} | i64 | @@ -5266,24 +5276,35 @@ inferType | dereference.rs:111:37:111:43 | S(...) | | dereference.rs:38:1:38:15 | S | | dereference.rs:111:37:111:43 | S(...) | T | {EXTERNAL LOCATION} | i64 | | dereference.rs:111:39:111:42 | 0i64 | | {EXTERNAL LOCATION} | i64 | +| dereference.rs:112:9:112:10 | z_ | | {EXTERNAL LOCATION} | & | +| dereference.rs:112:9:112:10 | z_ | TRef | {EXTERNAL LOCATION} | i64 | | dereference.rs:112:14:112:14 | z | | dereference.rs:18:1:20:1 | MySmartPointer | | dereference.rs:112:14:112:14 | z | T | dereference.rs:38:1:38:15 | S | | dereference.rs:112:14:112:14 | z | T.T | {EXTERNAL LOCATION} | i64 | +| dereference.rs:112:14:112:20 | z.foo() | | {EXTERNAL LOCATION} | & | +| dereference.rs:112:14:112:20 | z.foo() | TRef | {EXTERNAL LOCATION} | i64 | | dereference.rs:114:9:114:9 | v | | {EXTERNAL LOCATION} | Vec | | dereference.rs:114:9:114:9 | v | A | {EXTERNAL LOCATION} | Global | +| dereference.rs:114:9:114:9 | v | T | {EXTERNAL LOCATION} | i32 | | dereference.rs:114:13:114:22 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | | dereference.rs:114:13:114:22 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| dereference.rs:114:13:114:22 | ...::new(...) | T | {EXTERNAL LOCATION} | i32 | | dereference.rs:115:13:115:13 | x | | dereference.rs:18:1:20:1 | MySmartPointer | | dereference.rs:115:13:115:13 | x | T | {EXTERNAL LOCATION} | Vec | | dereference.rs:115:13:115:13 | x | T.A | {EXTERNAL LOCATION} | Global | +| dereference.rs:115:13:115:13 | x | T.T | {EXTERNAL LOCATION} | i32 | | dereference.rs:115:17:115:43 | MySmartPointer {...} | | dereference.rs:18:1:20:1 | MySmartPointer | | dereference.rs:115:17:115:43 | MySmartPointer {...} | T | {EXTERNAL LOCATION} | Vec | | dereference.rs:115:17:115:43 | MySmartPointer {...} | T.A | {EXTERNAL LOCATION} | Global | +| dereference.rs:115:17:115:43 | MySmartPointer {...} | T.T | {EXTERNAL LOCATION} | i32 | | dereference.rs:115:41:115:41 | v | | {EXTERNAL LOCATION} | Vec | | dereference.rs:115:41:115:41 | v | A | {EXTERNAL LOCATION} | Global | +| dereference.rs:115:41:115:41 | v | T | {EXTERNAL LOCATION} | i32 | | dereference.rs:116:5:116:5 | x | | dereference.rs:18:1:20:1 | MySmartPointer | | dereference.rs:116:5:116:5 | x | T | {EXTERNAL LOCATION} | Vec | | dereference.rs:116:5:116:5 | x | T.A | {EXTERNAL LOCATION} | Global | +| dereference.rs:116:5:116:5 | x | T.T | {EXTERNAL LOCATION} | i32 | +| dereference.rs:116:5:116:13 | x.push(...) | | {EXTERNAL LOCATION} | () | | dereference.rs:116:12:116:12 | 0 | | {EXTERNAL LOCATION} | i32 | | dereference.rs:143:19:151:5 | { ... } | | {EXTERNAL LOCATION} | () | | dereference.rs:144:17:144:26 | key_to_key | | {EXTERNAL LOCATION} | HashMap | @@ -10781,7 +10802,18 @@ inferType | main.rs:2902:21:2902:34 | path2.unwrap() | | main.rs:2879:5:2879:25 | PathBuf | | main.rs:2904:13:2904:20 | pathbuf1 | | main.rs:2879:5:2879:25 | PathBuf | | main.rs:2904:24:2904:37 | ...::new(...) | | main.rs:2879:5:2879:25 | PathBuf | +| main.rs:2905:13:2905:20 | pathbuf2 | | {EXTERNAL LOCATION} | Result | +| main.rs:2905:13:2905:20 | pathbuf2 | E | {EXTERNAL LOCATION} | () | +| main.rs:2905:13:2905:20 | pathbuf2 | T | main.rs:2879:5:2879:25 | PathBuf | | main.rs:2905:24:2905:31 | pathbuf1 | | main.rs:2879:5:2879:25 | PathBuf | +| main.rs:2905:24:2905:46 | pathbuf1.canonicalize() | | {EXTERNAL LOCATION} | Result | +| main.rs:2905:24:2905:46 | pathbuf1.canonicalize() | E | {EXTERNAL LOCATION} | () | +| main.rs:2905:24:2905:46 | pathbuf1.canonicalize() | T | main.rs:2879:5:2879:25 | PathBuf | +| main.rs:2906:13:2906:20 | pathbuf3 | | main.rs:2879:5:2879:25 | PathBuf | +| main.rs:2906:24:2906:31 | pathbuf2 | | {EXTERNAL LOCATION} | Result | +| main.rs:2906:24:2906:31 | pathbuf2 | E | {EXTERNAL LOCATION} | () | +| main.rs:2906:24:2906:31 | pathbuf2 | T | main.rs:2879:5:2879:25 | PathBuf | +| main.rs:2906:24:2906:40 | pathbuf2.unwrap() | | main.rs:2879:5:2879:25 | PathBuf | | main.rs:2912:14:2912:18 | SelfParam | | {EXTERNAL LOCATION} | & | | main.rs:2912:14:2912:18 | SelfParam | TRef | main.rs:2911:5:2913:5 | Self [trait MyTrait] | | main.rs:2919:14:2919:18 | SelfParam | | {EXTERNAL LOCATION} | & | diff --git a/rust/ql/test/query-tests/security/CWE-022/TaintedPath.expected b/rust/ql/test/query-tests/security/CWE-022/TaintedPath.expected index df7070c966a..2e98dadccfb 100644 --- a/rust/ql/test/query-tests/security/CWE-022/TaintedPath.expected +++ b/rust/ql/test/query-tests/security/CWE-022/TaintedPath.expected @@ -1,7 +1,8 @@ #select | src/main.rs:11:5:11:22 | ...::read_to_string | src/main.rs:7:11:7:19 | file_name | src/main.rs:11:5:11:22 | ...::read_to_string | This path depends on a $@. | src/main.rs:7:11:7:19 | file_name | user-provided value | -| src/main.rs:58:5:58:22 | ...::read_to_string | src/main.rs:50:51:50:59 | file_path | src/main.rs:58:5:58:22 | ...::read_to_string | This path depends on a $@. | src/main.rs:50:51:50:59 | file_path | user-provided value | +| src/main.rs:46:5:46:22 | ...::read_to_string | src/main.rs:38:11:38:19 | file_path | src/main.rs:46:5:46:22 | ...::read_to_string | This path depends on a $@. | src/main.rs:38:11:38:19 | file_path | user-provided value | | src/main.rs:71:5:71:22 | ...::read_to_string | src/main.rs:63:11:63:19 | file_path | src/main.rs:71:5:71:22 | ...::read_to_string | This path depends on a $@. | src/main.rs:63:11:63:19 | file_path | user-provided value | +| src/main.rs:85:5:85:22 | ...::read_to_string | src/main.rs:76:11:76:19 | file_path | src/main.rs:85:5:85:22 | ...::read_to_string | This path depends on a $@. | src/main.rs:76:11:76:19 | file_path | user-provided value | | src/main.rs:99:5:99:22 | ...::read_to_string | src/main.rs:90:11:90:19 | file_path | src/main.rs:99:5:99:22 | ...::read_to_string | This path depends on a $@. | src/main.rs:90:11:90:19 | file_path | user-provided value | | src/main.rs:104:13:104:31 | ...::open | src/main.rs:103:17:103:30 | ...::args | src/main.rs:104:13:104:31 | ...::open | This path depends on a $@. | src/main.rs:103:17:103:30 | ...::args | user-provided value | | src/main.rs:107:13:107:31 | ...::open | src/main.rs:103:17:103:30 | ...::args | src/main.rs:107:13:107:31 | ...::open | This path depends on a $@. | src/main.rs:103:17:103:30 | ...::args | user-provided value | @@ -19,28 +20,36 @@ edges | src/main.rs:9:9:9:17 | file_path | src/main.rs:11:24:11:32 | file_path | provenance | | | src/main.rs:9:21:9:44 | ...::from(...) | src/main.rs:9:9:9:17 | file_path | provenance | | | src/main.rs:9:35:9:43 | file_name | src/main.rs:9:21:9:44 | ...::from(...) | provenance | MaD:9 | -| src/main.rs:9:35:9:43 | file_name | src/main.rs:9:21:9:44 | ...::from(...) | provenance | MaD:14 | +| src/main.rs:9:35:9:43 | file_name | src/main.rs:9:21:9:44 | ...::from(...) | provenance | MaD:15 | | src/main.rs:11:24:11:32 | file_path | src/main.rs:11:5:11:22 | ...::read_to_string | provenance | MaD:6 Sink:MaD:6 | -| src/main.rs:50:51:50:59 | file_path | src/main.rs:52:32:52:40 | file_path | provenance | | -| src/main.rs:52:9:52:17 | file_path [&ref] | src/main.rs:53:21:53:29 | file_path [&ref] | provenance | | -| src/main.rs:52:21:52:41 | ...::new(...) [&ref] | src/main.rs:52:9:52:17 | file_path [&ref] | provenance | | -| src/main.rs:52:31:52:40 | &file_path [&ref] | src/main.rs:52:21:52:41 | ...::new(...) [&ref] | provenance | MaD:13 | -| src/main.rs:52:32:52:40 | file_path | src/main.rs:52:31:52:40 | &file_path [&ref] | provenance | | -| src/main.rs:53:9:53:17 | file_path | src/main.rs:58:24:58:32 | file_path | provenance | | -| src/main.rs:53:21:53:29 | file_path [&ref] | src/main.rs:53:21:53:44 | file_path.canonicalize() [Ok] | provenance | Config | -| src/main.rs:53:21:53:44 | file_path.canonicalize() [Ok] | src/main.rs:53:21:53:53 | ... .unwrap() | provenance | MaD:12 | -| src/main.rs:53:21:53:53 | ... .unwrap() | src/main.rs:53:9:53:17 | file_path | provenance | | -| src/main.rs:58:24:58:32 | file_path | src/main.rs:58:5:58:22 | ...::read_to_string | provenance | MaD:6 Sink:MaD:6 | +| src/main.rs:38:11:38:19 | file_path | src/main.rs:41:52:41:60 | file_path | provenance | | +| src/main.rs:41:9:41:17 | file_path | src/main.rs:46:24:46:32 | file_path | provenance | | +| src/main.rs:41:21:41:62 | public_path.join(...) | src/main.rs:41:9:41:17 | file_path | provenance | | +| src/main.rs:41:38:41:61 | ...::from(...) | src/main.rs:41:21:41:62 | public_path.join(...) | provenance | MaD:13 | +| src/main.rs:41:52:41:60 | file_path | src/main.rs:41:38:41:61 | ...::from(...) | provenance | MaD:9 | +| src/main.rs:41:52:41:60 | file_path | src/main.rs:41:38:41:61 | ...::from(...) | provenance | MaD:15 | +| src/main.rs:46:24:46:32 | file_path | src/main.rs:46:5:46:22 | ...::read_to_string | provenance | MaD:6 Sink:MaD:6 | | src/main.rs:63:11:63:19 | file_path | src/main.rs:66:32:66:40 | file_path | provenance | | | src/main.rs:66:9:66:17 | file_path [&ref] | src/main.rs:71:24:71:32 | file_path [&ref] | provenance | | | src/main.rs:66:21:66:41 | ...::new(...) [&ref] | src/main.rs:66:9:66:17 | file_path [&ref] | provenance | | -| src/main.rs:66:31:66:40 | &file_path [&ref] | src/main.rs:66:21:66:41 | ...::new(...) [&ref] | provenance | MaD:13 | +| src/main.rs:66:31:66:40 | &file_path [&ref] | src/main.rs:66:21:66:41 | ...::new(...) [&ref] | provenance | MaD:14 | | src/main.rs:66:32:66:40 | file_path | src/main.rs:66:31:66:40 | &file_path [&ref] | provenance | | | src/main.rs:71:24:71:32 | file_path [&ref] | src/main.rs:71:5:71:22 | ...::read_to_string | provenance | MaD:6 Sink:MaD:6 | +| src/main.rs:76:11:76:19 | file_path | src/main.rs:79:52:79:60 | file_path | provenance | | +| src/main.rs:79:9:79:17 | file_path | src/main.rs:80:21:80:29 | file_path | provenance | | +| src/main.rs:79:21:79:62 | public_path.join(...) | src/main.rs:79:9:79:17 | file_path | provenance | | +| src/main.rs:79:38:79:61 | ...::from(...) | src/main.rs:79:21:79:62 | public_path.join(...) | provenance | MaD:13 | +| src/main.rs:79:52:79:60 | file_path | src/main.rs:79:38:79:61 | ...::from(...) | provenance | MaD:9 | +| src/main.rs:79:52:79:60 | file_path | src/main.rs:79:38:79:61 | ...::from(...) | provenance | MaD:15 | +| src/main.rs:80:9:80:17 | file_path | src/main.rs:85:24:85:32 | file_path | provenance | | +| src/main.rs:80:21:80:29 | file_path | src/main.rs:80:21:80:44 | file_path.canonicalize() [Ok] | provenance | Config | +| src/main.rs:80:21:80:44 | file_path.canonicalize() [Ok] | src/main.rs:80:21:80:53 | ... .unwrap() | provenance | MaD:12 | +| src/main.rs:80:21:80:53 | ... .unwrap() | src/main.rs:80:9:80:17 | file_path | provenance | | +| src/main.rs:85:24:85:32 | file_path | src/main.rs:85:5:85:22 | ...::read_to_string | provenance | MaD:6 Sink:MaD:6 | | src/main.rs:90:11:90:19 | file_path | src/main.rs:93:32:93:40 | file_path | provenance | | | src/main.rs:93:9:93:17 | file_path [&ref] | src/main.rs:98:21:98:29 | file_path [&ref] | provenance | | | src/main.rs:93:21:93:41 | ...::new(...) [&ref] | src/main.rs:93:9:93:17 | file_path [&ref] | provenance | | -| src/main.rs:93:31:93:40 | &file_path [&ref] | src/main.rs:93:21:93:41 | ...::new(...) [&ref] | provenance | MaD:13 | +| src/main.rs:93:31:93:40 | &file_path [&ref] | src/main.rs:93:21:93:41 | ...::new(...) [&ref] | provenance | MaD:14 | | src/main.rs:93:32:93:40 | file_path | src/main.rs:93:31:93:40 | &file_path [&ref] | provenance | | | src/main.rs:98:9:98:17 | file_path | src/main.rs:99:24:99:32 | file_path | provenance | | | src/main.rs:98:21:98:29 | file_path [&ref] | src/main.rs:98:21:98:44 | file_path.canonicalize() [Ok] | provenance | Config | @@ -82,7 +91,7 @@ edges | src/main.rs:113:39:113:43 | path4 | src/main.rs:113:13:113:37 | ...::open | provenance | MaD:1 Sink:MaD:1 | | src/main.rs:115:9:115:13 | path5 [&ref] | src/main.rs:116:33:116:37 | path5 [&ref] | provenance | | | src/main.rs:115:17:115:44 | ...::new(...) [&ref] | src/main.rs:115:9:115:13 | path5 [&ref] | provenance | | -| src/main.rs:115:38:115:43 | &path1 [&ref] | src/main.rs:115:17:115:44 | ...::new(...) [&ref] | provenance | MaD:13 | +| src/main.rs:115:38:115:43 | &path1 [&ref] | src/main.rs:115:17:115:44 | ...::new(...) [&ref] | provenance | MaD:14 | | src/main.rs:115:39:115:43 | path1 | src/main.rs:115:38:115:43 | &path1 [&ref] | provenance | | | src/main.rs:116:33:116:37 | path5 [&ref] | src/main.rs:116:13:116:31 | ...::open | provenance | MaD:2 Sink:MaD:2 | | src/main.rs:116:33:116:37 | path5 [&ref] | src/main.rs:118:17:118:21 | path5 [&ref] | provenance | | @@ -99,7 +108,7 @@ edges | src/main.rs:170:16:170:29 | ...: ... [&ref] | src/main.rs:174:36:174:43 | path_str [&ref] | provenance | | | src/main.rs:172:9:172:12 | path [&ref] | src/main.rs:173:8:173:11 | path [&ref] | provenance | | | src/main.rs:172:16:172:34 | ...::new(...) [&ref] | src/main.rs:172:9:172:12 | path [&ref] | provenance | | -| src/main.rs:172:26:172:33 | path_str [&ref] | src/main.rs:172:16:172:34 | ...::new(...) [&ref] | provenance | MaD:13 | +| src/main.rs:172:26:172:33 | path_str [&ref] | src/main.rs:172:16:172:34 | ...::new(...) [&ref] | provenance | MaD:14 | | src/main.rs:173:8:173:11 | path [&ref] | src/main.rs:173:13:173:18 | exists | provenance | MaD:3 Sink:MaD:3 | | src/main.rs:173:8:173:11 | path [&ref] | src/main.rs:177:36:177:39 | path [&ref] | provenance | | | src/main.rs:174:36:174:43 | path_str [&ref] | src/main.rs:174:25:174:34 | ...::open | provenance | MaD:2 Sink:MaD:2 | @@ -124,8 +133,9 @@ models | 10 | Summary: <_ as core::iter::traits::iterator::Iterator>::nth; Argument[self].Reference.Element; ReturnValue.Field[core::option::Option::Some(0)]; value | | 11 | Summary: ::unwrap; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value | | 12 | Summary: ::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | -| 13 | Summary: ::new; Argument[0].Reference; ReturnValue.Reference; value | -| 14 | Summary: ::from; Argument[0]; ReturnValue; taint | +| 13 | Summary: ::join; Argument[0]; ReturnValue; taint | +| 14 | Summary: ::new; Argument[0].Reference; ReturnValue.Reference; value | +| 15 | Summary: ::from; Argument[0]; ReturnValue; taint | nodes | src/main.rs:7:11:7:19 | file_name | semmle.label | file_name | | src/main.rs:9:9:9:17 | file_path | semmle.label | file_path | @@ -133,17 +143,13 @@ nodes | src/main.rs:9:35:9:43 | file_name | semmle.label | file_name | | src/main.rs:11:5:11:22 | ...::read_to_string | semmle.label | ...::read_to_string | | src/main.rs:11:24:11:32 | file_path | semmle.label | file_path | -| src/main.rs:50:51:50:59 | file_path | semmle.label | file_path | -| src/main.rs:52:9:52:17 | file_path [&ref] | semmle.label | file_path [&ref] | -| src/main.rs:52:21:52:41 | ...::new(...) [&ref] | semmle.label | ...::new(...) [&ref] | -| src/main.rs:52:31:52:40 | &file_path [&ref] | semmle.label | &file_path [&ref] | -| src/main.rs:52:32:52:40 | file_path | semmle.label | file_path | -| src/main.rs:53:9:53:17 | file_path | semmle.label | file_path | -| src/main.rs:53:21:53:29 | file_path [&ref] | semmle.label | file_path [&ref] | -| src/main.rs:53:21:53:44 | file_path.canonicalize() [Ok] | semmle.label | file_path.canonicalize() [Ok] | -| src/main.rs:53:21:53:53 | ... .unwrap() | semmle.label | ... .unwrap() | -| src/main.rs:58:5:58:22 | ...::read_to_string | semmle.label | ...::read_to_string | -| src/main.rs:58:24:58:32 | file_path | semmle.label | file_path | +| src/main.rs:38:11:38:19 | file_path | semmle.label | file_path | +| src/main.rs:41:9:41:17 | file_path | semmle.label | file_path | +| src/main.rs:41:21:41:62 | public_path.join(...) | semmle.label | public_path.join(...) | +| src/main.rs:41:38:41:61 | ...::from(...) | semmle.label | ...::from(...) | +| src/main.rs:41:52:41:60 | file_path | semmle.label | file_path | +| src/main.rs:46:5:46:22 | ...::read_to_string | semmle.label | ...::read_to_string | +| src/main.rs:46:24:46:32 | file_path | semmle.label | file_path | | src/main.rs:63:11:63:19 | file_path | semmle.label | file_path | | src/main.rs:66:9:66:17 | file_path [&ref] | semmle.label | file_path [&ref] | | src/main.rs:66:21:66:41 | ...::new(...) [&ref] | semmle.label | ...::new(...) [&ref] | @@ -151,6 +157,17 @@ nodes | src/main.rs:66:32:66:40 | file_path | semmle.label | file_path | | src/main.rs:71:5:71:22 | ...::read_to_string | semmle.label | ...::read_to_string | | src/main.rs:71:24:71:32 | file_path [&ref] | semmle.label | file_path [&ref] | +| src/main.rs:76:11:76:19 | file_path | semmle.label | file_path | +| src/main.rs:79:9:79:17 | file_path | semmle.label | file_path | +| src/main.rs:79:21:79:62 | public_path.join(...) | semmle.label | public_path.join(...) | +| src/main.rs:79:38:79:61 | ...::from(...) | semmle.label | ...::from(...) | +| src/main.rs:79:52:79:60 | file_path | semmle.label | file_path | +| src/main.rs:80:9:80:17 | file_path | semmle.label | file_path | +| src/main.rs:80:21:80:29 | file_path | semmle.label | file_path | +| src/main.rs:80:21:80:44 | file_path.canonicalize() [Ok] | semmle.label | file_path.canonicalize() [Ok] | +| src/main.rs:80:21:80:53 | ... .unwrap() | semmle.label | ... .unwrap() | +| src/main.rs:85:5:85:22 | ...::read_to_string | semmle.label | ...::read_to_string | +| src/main.rs:85:24:85:32 | file_path | semmle.label | file_path | | src/main.rs:90:11:90:19 | file_path | semmle.label | file_path | | src/main.rs:93:9:93:17 | file_path [&ref] | semmle.label | file_path [&ref] | | src/main.rs:93:21:93:41 | ...::new(...) [&ref] | semmle.label | ...::new(...) [&ref] | diff --git a/rust/ql/test/query-tests/security/CWE-022/src/main.rs b/rust/ql/test/query-tests/security/CWE-022/src/main.rs index 7acf036bb6b..f686fdf1d95 100644 --- a/rust/ql/test/query-tests/security/CWE-022/src/main.rs +++ b/rust/ql/test/query-tests/security/CWE-022/src/main.rs @@ -30,12 +30,12 @@ fn tainted_path_handler_folder_good(Query(file_path): Query) -> Result, // $ MISSING: Source=remote2 + Query(file_path): Query, // $ Source=remote2 ) -> Result { let public_path = PathBuf::from("/var/www/public_html"); let file_path = public_path.join(PathBuf::from(file_path)); @@ -43,11 +43,11 @@ fn tainted_path_handler_folder_almost_good1( if !file_path.starts_with(public_path) { return Err(Error::from_status(StatusCode::BAD_REQUEST)); } - fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink MISSING: path-injection-checked Alert[rust/path-injection]=remote2 -- we cannot resolve the `join` call above, because it needs a `PathBuf -> Path` `Deref` + fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink path-injection-checked Alert[rust/path-injection]=remote2 } //#[handler] -fn tainted_path_handler_folder_good_simpler(Query(file_path): Query) -> Result { // $ Source=remote6 +fn tainted_path_handler_folder_good_simpler(Query(file_path): Query) -> Result { let public_path = "/var/www/public_html"; let file_path = Path::new(&file_path); let file_path = file_path.canonicalize().unwrap(); @@ -55,7 +55,7 @@ fn tainted_path_handler_folder_good_simpler(Query(file_path): Query) -> if !file_path.starts_with(public_path) { return Err(Error::from_status(StatusCode::BAD_REQUEST)); } - fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink MISSING: path-injection-checked SPURIOUS: Alert[rust/path-injection]=remote6 + fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink path-injection-checked } //#[handler] @@ -73,7 +73,7 @@ fn tainted_path_handler_folder_almost_good1_simpler( //#[handler] fn tainted_path_handler_folder_almost_good2( - Query(file_path): Query, // $ MISSING: Source=remote4 + Query(file_path): Query, // $ Source=remote4 ) -> Result { let public_path = PathBuf::from("/var/www/public_html"); let file_path = public_path.join(PathBuf::from(file_path)); @@ -82,7 +82,7 @@ fn tainted_path_handler_folder_almost_good2( if file_path.starts_with(public_path) { return Err(Error::from_status(StatusCode::BAD_REQUEST)); } - fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink MISSING: path-injection-checked Alert[rust/path-injection]=remote4 -- we cannot resolve the `join` call above, because it needs a `PathBuf -> Path` `Deref` + fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink Alert[rust/path-injection]=remote4 $ MISSING: path-injection-checked } //#[handler] diff --git a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll index f53f15b5a6a..f38be739028 100644 --- a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll +++ b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll @@ -857,10 +857,16 @@ module Make1 Input1> { { private import Input + pragma[nomagic] + private Type getTypeAt(HasTypeTree term, TypePath path) { + relevantConstraint(term, _) and + result = term.getTypeAt(path) + } + /** Holds if the type tree has the type `type` and should satisfy `constraint`. */ pragma[nomagic] private predicate hasTypeConstraint(HasTypeTree term, Type type, Type constraint) { - type = term.getTypeAt(TypePath::nil()) and + type = getTypeAt(term, TypePath::nil()) and relevantConstraint(term, constraint) } @@ -967,36 +973,74 @@ module Make1 Input1> { ) } - pragma[nomagic] - private predicate satisfiesConstraintTypeMention1( - HasTypeTree tt, Type constraint, TypePath path, TypePath pathToTypeParamInSub + pragma[inline] + private predicate satisfiesConstraintTypeMention1Inline( + HasTypeTree tt, TypeAbstraction abs, Type constraint, TypePath path, + TypePath pathToTypeParamInSub ) { - exists(TypeAbstraction abs, TypeMention sub, TypeParameter tp | + exists(TypeMention sub, TypeParameter tp | satisfiesConstraintTypeMention0(tt, constraint, abs, sub, path, tp) and tp = abs.getATypeParameter() and sub.resolveTypeAt(pathToTypeParamInSub) = tp ) } + pragma[nomagic] + private predicate satisfiesConstraintTypeMention1( + HasTypeTree tt, Type constraint, TypePath path, TypePath pathToTypeParamInSub + ) { + satisfiesConstraintTypeMention1Inline(tt, _, constraint, path, pathToTypeParamInSub) + } + + pragma[nomagic] + private predicate satisfiesConstraintTypeMention1Through( + HasTypeTree tt, TypeAbstraction abs, Type constraint, TypePath path, + TypePath pathToTypeParamInSub + ) { + satisfiesConstraintTypeMention1Inline(tt, abs, constraint, path, pathToTypeParamInSub) + } + + pragma[inline] + private predicate satisfiesConstraintTypeNonTypeParamInline( + HasTypeTree tt, TypeAbstraction abs, Type constraint, TypePath path, Type t + ) { + satisfiesConstraintTypeMention0(tt, constraint, abs, _, path, t) and + not t = abs.getATypeParameter() + } + /** * Holds if the type tree at `tt` satisfies the constraint `constraint` * with the type `t` at `path`. */ pragma[nomagic] predicate satisfiesConstraintType(HasTypeTree tt, Type constraint, TypePath path, Type t) { - exists(TypeAbstraction abs | - satisfiesConstraintTypeMention0(tt, constraint, abs, _, path, t) and - not t = abs.getATypeParameter() - ) + satisfiesConstraintTypeNonTypeParamInline(tt, _, constraint, path, t) or exists(TypePath prefix0, TypePath pathToTypeParamInSub, TypePath suffix | satisfiesConstraintTypeMention1(tt, constraint, prefix0, pathToTypeParamInSub) and - tt.getTypeAt(pathToTypeParamInSub.appendInverse(suffix)) = t and + getTypeAt(tt, pathToTypeParamInSub.appendInverse(suffix)) = t and path = prefix0.append(suffix) ) or hasTypeConstraint(tt, constraint, constraint) and - t = tt.getTypeAt(path) + t = getTypeAt(tt, path) + } + + /** + * Holds if the type tree at `tt` satisfies the constraint `constraint` + * through `abs` with the type `t` at `path`. + */ + pragma[nomagic] + predicate satisfiesConstraintTypeThrough( + HasTypeTree tt, TypeAbstraction abs, Type constraint, TypePath path, Type t + ) { + satisfiesConstraintTypeNonTypeParamInline(tt, abs, constraint, path, t) + or + exists(TypePath prefix0, TypePath pathToTypeParamInSub, TypePath suffix | + satisfiesConstraintTypeMention1Through(tt, abs, constraint, prefix0, pathToTypeParamInSub) and + getTypeAt(tt, pathToTypeParamInSub.appendInverse(suffix)) = t and + path = prefix0.append(suffix) + ) } /**