Rust: Remove restriction that blanket(-like) impls must have a constraint

This commit is contained in:
Tom Hvitved
2026-01-15 10:04:03 +01:00
parent 06b99b2ce9
commit fd309d6e49
8 changed files with 217 additions and 84 deletions

View File

@@ -5,7 +5,10 @@
private import rust
private import codeql.rust.Concepts
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowSummary
private import codeql.rust.internal.PathResolution
private import codeql.rust.internal.typeinference.Type
private import codeql.rust.internal.typeinference.TypeMention
/**
* A call to the `starts_with` method on a `Path`.
@@ -297,3 +300,30 @@ class Vec extends Struct {
/** Gets the type parameter representing the element type. */
TypeParam getElementTypeParam() { result = this.getGenericParamList().getTypeParam(0) }
}
// Blanket implementations currently don't have a canonical path, so we cannot
// use models-as-data for this model.
private class ReflexiveFrom extends SummarizedCallable::Range {
ReflexiveFrom() {
exists(ImplItemNode impl |
impl.resolveTraitTy().(Trait).getCanonicalPath() = "core::convert::From" and
this = impl.getAnAssocItem() and
impl.isBlanketImplementation() and
this.getParam(0)
.getTypeRepr()
.(TypeMention)
.resolveType()
.(TypeParamTypeParameter)
.getTypeParam() = impl.getTypeParam(0)
)
}
override predicate propagatesFlow(
string input, string output, boolean preservesValue, string model
) {
input = "Argument[0]" and
output = "ReturnValue" and
preservesValue = true and
model = "ReflexiveFrom"
}
}

View File

@@ -126,7 +126,7 @@ module SatisfiesBlanketConstraint<
/**
* Holds if the argument type `at` satisfies the first non-trivial blanket
* constraint of `impl`.
* constraint of `impl`, or if there are no non-trivial constraints of `impl`.
*/
pragma[nomagic]
predicate satisfiesBlanketConstraint(ArgumentType at, ImplItemNode impl) {
@@ -135,6 +135,11 @@ module SatisfiesBlanketConstraint<
SatisfiesBlanketConstraintInput::relevantConstraint(ato, impl, traitBound) and
SatisfiesBlanketConstraint::satisfiesConstraintType(ato, TTrait(traitBound), _, _)
)
or
exists(TypeParam blanketTypeParam |
hasBlanketCandidate(at, impl, _, blanketTypeParam) and
not hasFirstNonTrivialTraitBound(blanketTypeParam, _)
)
}
/**

View File

@@ -58,12 +58,26 @@ private predicate implSiblings(TraitItemNode trait, Impl impl1, Impl impl2) {
)
}
pragma[nomagic]
private predicate isBlanketImpl(ImplItemNode impl, Trait trait) {
impl.isBlanketImplementation() and
trait = impl.resolveTraitTy()
}
/**
* Holds if `impl` is an implementation of `trait` and if another implementation
* exists for the same type.
*/
pragma[nomagic]
private predicate implHasSibling(Impl impl, Trait trait) { implSiblings(trait, impl, _) }
private predicate implHasSibling(ImplItemNode impl, Trait trait) {
implSiblings(trait, impl, _)
or
exists(ImplItemNode other |
isBlanketImpl(impl, trait) and
isBlanketImpl(other, trait) and
impl != other
)
}
/**
* Holds if type parameter `tp` of `trait` occurs in the function `f` with the name

View File

@@ -356,7 +356,7 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
string toString() { result = call.toString() + " [arg " + pos + "]" }
}
private module ArgIsInstantiationOfInput implements
private module ArgIsInstantiationOfToIndexInput implements
IsInstantiationOfInputSig<CallAndPos, AssocFunctionType>
{
pragma[nomagic]
@@ -389,7 +389,7 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
}
private module ArgIsInstantiationOfToIndex =
ArgIsInstantiationOf<CallAndPos, ArgIsInstantiationOfInput>;
ArgIsInstantiationOf<CallAndPos, ArgIsInstantiationOfToIndexInput>;
pragma[nomagic]
private predicate argsAreInstantiationsOfToIndex(
@@ -413,4 +413,24 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
rnk = max(int r | toCheckRanked(i, f, _, r))
)
}
pragma[nomagic]
private predicate argsAreNotInstantiationsOf0(
Input::Call call, FunctionPosition pos, ImplOrTraitItemNode i
) {
ArgIsInstantiationOfToIndex::argIsNotInstantiationOf(MkCallAndPos(call, pos), i, _, _)
}
/**
* Holds if _some_ argument of `call` has a type that is not an instantiation of the
* type of the corresponding parameter of `f` inside `i`.
*/
pragma[nomagic]
predicate argsAreNotInstantiationsOf(Input::Call call, ImplOrTraitItemNode i, Function f) {
exists(FunctionPosition pos |
argsAreNotInstantiationsOf0(call, pos, i) and
call.hasTargetCand(i, f) and
Input::toCheck(i, f, pos, _)
)
}
}

View File

@@ -1289,6 +1289,13 @@ private class BorrowKind extends TBorrowKind {
}
}
// for now, we do not handle ambiguous targets when one of the types is itself
// a constrained type parameter; we should be checking the constraints in this case
private predicate typeCanBeUsedForDisambiguation(Type t) {
not t instanceof TypeParameter or
t.(TypeParamTypeParameter).getTypeParam() = any(TypeParam tp | not exists(tp.getATypeBound()))
}
/**
* Provides logic for resolving calls to methods.
*
@@ -2384,10 +2391,7 @@ private module MethodResolution {
exists(TypePath path, Type t0 |
FunctionOverloading::functionResolutionDependsOnArgument(i, f, pos, path, t0) and
t.appliesTo(f, i, pos) and
// for now, we do not handle ambiguous targets when one of the types it iself
// a type parameter; we should be checking the constraints on that type parameter
// in this case
not t0 instanceof TypeParameter
typeCanBeUsedForDisambiguation(t0)
)
}
@@ -2746,7 +2750,7 @@ private module NonMethodResolution {
* Gets the blanket function that this call may resolve to, if any.
*/
pragma[nomagic]
private NonMethodFunction resolveCallTargetBlanketCand(ImplItemNode impl) {
NonMethodFunction resolveCallTargetBlanketCand(ImplItemNode impl) {
exists(string name |
this.hasNameAndArity(pragma[only_bind_into](name), _) and
ArgIsInstantiationOfBlanketParam::argIsInstantiationOf(MkCallAndBlanketPos(this, _), impl, _) and
@@ -2761,12 +2765,11 @@ private module NonMethodResolution {
predicate hasTrait() { exists(this.getTrait()) }
pragma[nomagic]
NonMethodFunction resolveAssocCallTargetCand(ImplItemNode i) {
NonMethodFunction resolveCallTargetNonBlanketCand(ImplItemNode i) {
not this.hasTrait() and
result = this.getPathResolutionResolved() and
result = i.getASuccessor(_)
or
result = this.resolveCallTargetBlanketCand(i)
result = i.getASuccessor(_) and
FunctionOverloading::functionResolutionDependsOnArgument(_, result, _, _, _)
}
AstNode getNodeAt(FunctionPosition pos) {
@@ -2798,6 +2801,21 @@ private module NonMethodResolution {
trait = this.getTrait()
}
/**
* Holds if this call has no compatible non-blanket target, and it has some
* candidate blanket target.
*/
pragma[nomagic]
predicate hasNoCompatibleNonBlanketTarget() {
this.resolveCallTargetBlanketLikeCandidate(_, _, _, _) and
not exists(this.resolveCallTargetViaPathResolution()) and
forall(ImplOrTraitItemNode i, Function f |
this.(NonMethodArgsAreInstantiationsOfNonBlanketInput::Call).hasTargetCand(i, f)
|
NonMethodArgsAreInstantiationsOfNonBlanket::argsAreNotInstantiationsOf(this, i, f)
)
}
/**
* Gets the target of this call, which can be resolved using only path resolution.
*/
@@ -2816,7 +2834,9 @@ private module NonMethodResolution {
result = this.resolveCallTargetBlanketCand(i) and
not FunctionOverloading::functionResolutionDependsOnArgument(_, result, _, _, _)
or
NonMethodArgsAreInstantiationsOf::argsAreInstantiationsOf(this, i, result)
NonMethodArgsAreInstantiationsOfBlanket::argsAreInstantiationsOf(this, i, result)
or
NonMethodArgsAreInstantiationsOfNonBlanket::argsAreInstantiationsOf(this, i, result)
}
pragma[nomagic]
@@ -2855,7 +2875,11 @@ private module NonMethodResolution {
) {
exists(NonMethodCall fc, FunctionPosition pos |
fcp = MkCallAndBlanketPos(fc, pos) and
fc.resolveCallTargetBlanketLikeCandidate(impl, pos, blanketPath, blanketTypeParam)
fc.resolveCallTargetBlanketLikeCandidate(impl, pos, blanketPath, blanketTypeParam) and
// Only apply blanket implementations when no other implementations are possible;
// this is to account for codebases that use the (unstable) specialization feature
// (https://rust-lang.github.io/rfcs/1210-impl-specialization.html)
(fc.hasNoCompatibleNonBlanketTarget() or not impl.isBlanketImplementation())
)
}
}
@@ -2890,37 +2914,24 @@ private module NonMethodResolution {
private module ArgIsInstantiationOfBlanketParam =
ArgIsInstantiationOf<CallAndBlanketPos, ArgIsInstantiationOfBlanketParamInput>;
private module NonMethodArgsAreInstantiationsOfInput implements ArgsAreInstantiationsOfInputSig {
private module NonMethodArgsAreInstantiationsOfBlanketInput implements
ArgsAreInstantiationsOfInputSig
{
predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t) {
t.appliesTo(f, i, pos) and
(
exists(Type t0 |
// for now, we do not handle ambiguous targets when one of the types it iself
// a type parameter; we should be checking the constraints on that type parameter
// in this case
not t0 instanceof TypeParameter
|
FunctionOverloading::functionResolutionDependsOnArgument(i, f, pos, _, t0)
or
traitFunctionDependsOnPos(_, _, pos, t0, i, f)
)
exists(Type t0 | typeCanBeUsedForDisambiguation(t0) |
FunctionOverloading::functionResolutionDependsOnArgument(i, f, pos, _, t0)
or
// match against the trait function itself
exists(Trait trait |
FunctionOverloading::traitTypeParameterOccurrence(trait, f, _, pos, _,
TSelfTypeParameter(trait))
)
traitFunctionDependsOnPos(_, _, pos, t0, i, f)
)
}
class Call extends NonMethodCall {
final class Call extends NonMethodCall {
Type getArgType(FunctionPosition pos, TypePath path) {
result = inferType(this.getNodeAt(pos), path)
}
predicate hasTargetCand(ImplOrTraitItemNode i, Function f) {
f = this.resolveAssocCallTargetCand(i)
or
predicate hasTraitResolvedCand(ImplOrTraitItemNode i, Function f) {
exists(TraitItemNode trait, NonMethodFunction resolved, ImplItemNode i1, Function f1 |
this.hasTraitResolved(trait, resolved) and
traitFunctionDependsOnPos(trait, resolved, _, _, i1, f1)
@@ -2932,11 +2943,45 @@ private module NonMethodResolution {
i = trait
)
}
predicate hasTargetCand(ImplOrTraitItemNode i, Function f) {
f = this.resolveCallTargetBlanketCand(i)
or
this.hasTraitResolvedCand(i, f) and
BlanketImplementation::isBlanketLike(i, _, _)
}
}
}
private module NonMethodArgsAreInstantiationsOf =
ArgsAreInstantiationsOf<NonMethodArgsAreInstantiationsOfInput>;
private module NonMethodArgsAreInstantiationsOfBlanket =
ArgsAreInstantiationsOf<NonMethodArgsAreInstantiationsOfBlanketInput>;
private module NonMethodArgsAreInstantiationsOfNonBlanketInput implements
ArgsAreInstantiationsOfInputSig
{
predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t) {
NonMethodArgsAreInstantiationsOfBlanketInput::toCheck(i, f, pos, t)
or
// match against the trait function itself
t.appliesTo(f, i, pos) and
exists(Trait trait |
FunctionOverloading::traitTypeParameterOccurrence(trait, f, _, pos, _,
TSelfTypeParameter(trait))
)
}
class Call extends NonMethodArgsAreInstantiationsOfBlanketInput::Call {
predicate hasTargetCand(ImplOrTraitItemNode i, Function f) {
f = this.resolveCallTargetNonBlanketCand(i)
or
this.hasTraitResolvedCand(i, f) and
not BlanketImplementation::isBlanketLike(i, _, _)
}
}
}
private module NonMethodArgsAreInstantiationsOfNonBlanket =
ArgsAreInstantiationsOf<NonMethodArgsAreInstantiationsOfNonBlanketInput>;
}
abstract private class TupleLikeConstructor extends Addressable {

View File

@@ -2,22 +2,24 @@ models
| 1 | Summary: <& as core::ops::deref::Deref>::deref; Argument[self].Reference; ReturnValue; value |
| 2 | Summary: <_ as alloc::string::ToString>::to_string; Argument[self].Reference; ReturnValue; taint |
| 3 | Summary: <_ as core::convert::From>::from; Argument[0]; ReturnValue; taint |
| 4 | Summary: <_ as core::ops::deref::Deref>::deref; Argument[self].Reference; ReturnValue.Reference; taint |
| 5 | Summary: <_ as core::ops::index::Index>::index; Argument[self].Reference.Element; ReturnValue.Reference; value |
| 6 | Summary: <alloc::boxed::Box as core::ops::deref::Deref>::deref; Argument[self].Reference.Field[alloc::boxed::Box(0)]; ReturnValue.Reference; value |
| 7 | Summary: <alloc::boxed::Box>::new; Argument[0]; ReturnValue.Field[alloc::boxed::Box(0)]; value |
| 8 | Summary: <alloc::string::String as core::ops::deref::Deref>::deref; Argument[self]; ReturnValue; value |
| 9 | Summary: <core::i64 as core::convert::From>::from; Argument[0]; ReturnValue; taint |
| 10 | Summary: <core::option::Option>::unwrap; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value |
| 11 | Summary: <core::option::Option>::unwrap_or; Argument[0]; ReturnValue; value |
| 12 | Summary: <core::option::Option>::unwrap_or; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value |
| 13 | Summary: <core::option::Option>::unwrap_or_else; Argument[0].ReturnValue; ReturnValue; value |
| 14 | Summary: <core::option::Option>::unwrap_or_else; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value |
| 15 | Summary: <core::result::Result>::err; Argument[self].Field[core::result::Result::Err(0)]; ReturnValue.Field[core::option::Option::Some(0)]; value |
| 16 | Summary: <core::result::Result>::expect; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value |
| 17 | Summary: <core::result::Result>::expect_err; Argument[self].Field[core::result::Result::Err(0)]; ReturnValue; value |
| 18 | Summary: <core::result::Result>::ok; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue.Field[core::option::Option::Some(0)]; value |
| 19 | Summary: <core::result::Result>::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value |
| 4 | Summary: <_ as core::convert::Into>::into; Argument[self].Element; ReturnValue.Element; taint |
| 5 | Summary: <_ as core::convert::Into>::into; Argument[self].Reference.Element; ReturnValue.Element; taint |
| 6 | Summary: <_ as core::ops::deref::Deref>::deref; Argument[self].Reference; ReturnValue.Reference; taint |
| 7 | Summary: <_ as core::ops::index::Index>::index; Argument[self].Reference.Element; ReturnValue.Reference; value |
| 8 | Summary: <alloc::boxed::Box as core::ops::deref::Deref>::deref; Argument[self].Reference.Field[alloc::boxed::Box(0)]; ReturnValue.Reference; value |
| 9 | Summary: <alloc::boxed::Box>::new; Argument[0]; ReturnValue.Field[alloc::boxed::Box(0)]; value |
| 10 | Summary: <alloc::string::String as core::ops::deref::Deref>::deref; Argument[self]; ReturnValue; value |
| 11 | Summary: <core::i64 as core::convert::From>::from; Argument[0]; ReturnValue; taint |
| 12 | Summary: <core::option::Option>::unwrap; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value |
| 13 | Summary: <core::option::Option>::unwrap_or; Argument[0]; ReturnValue; value |
| 14 | Summary: <core::option::Option>::unwrap_or; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value |
| 15 | Summary: <core::option::Option>::unwrap_or_else; Argument[0].ReturnValue; ReturnValue; value |
| 16 | Summary: <core::option::Option>::unwrap_or_else; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value |
| 17 | Summary: <core::result::Result>::err; Argument[self].Field[core::result::Result::Err(0)]; ReturnValue.Field[core::option::Option::Some(0)]; value |
| 18 | Summary: <core::result::Result>::expect; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value |
| 19 | Summary: <core::result::Result>::expect_err; Argument[self].Field[core::result::Result::Err(0)]; ReturnValue; value |
| 20 | Summary: <core::result::Result>::ok; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue.Field[core::option::Option::Some(0)]; value |
| 21 | Summary: <core::result::Result>::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value |
edges
| main.rs:23:9:23:9 | s | main.rs:24:10:24:10 | s | provenance | |
| main.rs:23:9:23:9 | s | main.rs:26:12:26:12 | x | provenance | |
@@ -45,8 +47,8 @@ edges
| main.rs:82:5:82:5 | l | main.rs:83:10:83:10 | l | provenance | |
| main.rs:115:9:115:9 | i [Box(0)] | main.rs:116:11:116:11 | i [Box(0)] | provenance | |
| main.rs:115:13:115:31 | ...::new(...) [Box(0)] | main.rs:115:9:115:9 | i [Box(0)] | provenance | |
| main.rs:115:22:115:30 | source(...) | main.rs:115:13:115:31 | ...::new(...) [Box(0)] | provenance | MaD:7 |
| main.rs:116:11:116:11 | i [Box(0)] | main.rs:116:10:116:11 | * ... | provenance | MaD:6 |
| main.rs:115:22:115:30 | source(...) | main.rs:115:13:115:31 | ...::new(...) [Box(0)] | provenance | MaD:9 |
| main.rs:116:11:116:11 | i [Box(0)] | main.rs:116:10:116:11 | * ... | provenance | MaD:8 |
| main.rs:123:9:123:9 | a [tuple.0] | main.rs:124:10:124:10 | a [tuple.0] | provenance | |
| main.rs:123:13:123:26 | TupleExpr [tuple.0] | main.rs:123:9:123:9 | a [tuple.0] | provenance | |
| main.rs:123:14:123:22 | source(...) | main.rs:123:13:123:26 | TupleExpr [tuple.0] | provenance | |
@@ -129,17 +131,17 @@ edges
| main.rs:278:9:278:10 | s1 [Some] | main.rs:279:10:279:11 | s1 [Some] | provenance | |
| main.rs:278:14:278:29 | Some(...) [Some] | main.rs:278:9:278:10 | s1 [Some] | provenance | |
| main.rs:278:19:278:28 | source(...) | main.rs:278:14:278:29 | Some(...) [Some] | provenance | |
| main.rs:279:10:279:11 | s1 [Some] | main.rs:279:10:279:20 | s1.unwrap() | provenance | MaD:10 |
| main.rs:279:10:279:11 | s1 [Some] | main.rs:279:10:279:20 | s1.unwrap() | provenance | MaD:12 |
| main.rs:283:9:283:10 | s1 [Some] | main.rs:284:10:284:11 | s1 [Some] | provenance | |
| main.rs:283:14:283:29 | Some(...) [Some] | main.rs:283:9:283:10 | s1 [Some] | provenance | |
| main.rs:283:19:283:28 | source(...) | main.rs:283:14:283:29 | Some(...) [Some] | provenance | |
| main.rs:284:10:284:11 | s1 [Some] | main.rs:284:10:284:24 | s1.unwrap_or(...) | provenance | MaD:12 |
| main.rs:287:23:287:32 | source(...) | main.rs:287:10:287:33 | s2.unwrap_or(...) | provenance | MaD:11 |
| main.rs:284:10:284:11 | s1 [Some] | main.rs:284:10:284:24 | s1.unwrap_or(...) | provenance | MaD:14 |
| main.rs:287:23:287:32 | source(...) | main.rs:287:10:287:33 | s2.unwrap_or(...) | provenance | MaD:13 |
| main.rs:291:9:291:10 | s1 [Some] | main.rs:292:10:292:11 | s1 [Some] | provenance | |
| main.rs:291:14:291:29 | Some(...) [Some] | main.rs:291:9:291:10 | s1 [Some] | provenance | |
| main.rs:291:19:291:28 | source(...) | main.rs:291:14:291:29 | Some(...) [Some] | provenance | |
| main.rs:292:10:292:11 | s1 [Some] | main.rs:292:10:292:32 | s1.unwrap_or_else(...) | provenance | MaD:14 |
| main.rs:295:31:295:40 | source(...) | main.rs:295:10:295:41 | s2.unwrap_or_else(...) | provenance | MaD:13 |
| main.rs:292:10:292:11 | s1 [Some] | main.rs:292:10:292:32 | s1.unwrap_or_else(...) | provenance | MaD:16 |
| main.rs:295:31:295:40 | source(...) | main.rs:295:10:295:41 | s2.unwrap_or_else(...) | provenance | MaD:15 |
| main.rs:299:9:299:10 | s1 [Some] | main.rs:301:14:301:15 | s1 [Some] | provenance | |
| main.rs:299:14:299:29 | Some(...) [Some] | main.rs:299:9:299:10 | s1 [Some] | provenance | |
| main.rs:299:19:299:28 | source(...) | main.rs:299:14:299:29 | Some(...) [Some] | provenance | |
@@ -150,16 +152,16 @@ edges
| main.rs:308:32:308:45 | Ok(...) [Ok] | main.rs:308:9:308:10 | r1 [Ok] | provenance | |
| main.rs:308:35:308:44 | source(...) | main.rs:308:32:308:45 | Ok(...) [Ok] | provenance | |
| main.rs:309:9:309:11 | o1a [Some] | main.rs:311:10:311:12 | o1a [Some] | provenance | |
| main.rs:309:28:309:29 | r1 [Ok] | main.rs:309:28:309:34 | r1.ok() [Some] | provenance | MaD:18 |
| main.rs:309:28:309:29 | r1 [Ok] | main.rs:309:28:309:34 | r1.ok() [Some] | provenance | MaD:20 |
| main.rs:309:28:309:34 | r1.ok() [Some] | main.rs:309:9:309:11 | o1a [Some] | provenance | |
| main.rs:311:10:311:12 | o1a [Some] | main.rs:311:10:311:21 | o1a.unwrap() | provenance | MaD:10 |
| main.rs:311:10:311:12 | o1a [Some] | main.rs:311:10:311:21 | o1a.unwrap() | provenance | MaD:12 |
| main.rs:314:9:314:10 | r2 [Err] | main.rs:316:28:316:29 | r2 [Err] | provenance | |
| main.rs:314:32:314:46 | Err(...) [Err] | main.rs:314:9:314:10 | r2 [Err] | provenance | |
| main.rs:314:36:314:45 | source(...) | main.rs:314:32:314:46 | Err(...) [Err] | provenance | |
| main.rs:316:9:316:11 | o2b [Some] | main.rs:318:10:318:12 | o2b [Some] | provenance | |
| main.rs:316:28:316:29 | r2 [Err] | main.rs:316:28:316:35 | r2.err() [Some] | provenance | MaD:15 |
| main.rs:316:28:316:29 | r2 [Err] | main.rs:316:28:316:35 | r2.err() [Some] | provenance | MaD:17 |
| main.rs:316:28:316:35 | r2.err() [Some] | main.rs:316:9:316:11 | o2b [Some] | provenance | |
| main.rs:318:10:318:12 | o2b [Some] | main.rs:318:10:318:21 | o2b.unwrap() | provenance | MaD:10 |
| main.rs:318:10:318:12 | o2b [Some] | main.rs:318:10:318:21 | o2b.unwrap() | provenance | MaD:12 |
| main.rs:322:9:322:10 | s1 [Ok] | main.rs:325:14:325:15 | s1 [Ok] | provenance | |
| main.rs:322:32:322:45 | Ok(...) [Ok] | main.rs:322:9:322:10 | s1 [Ok] | provenance | |
| main.rs:322:35:322:44 | source(...) | main.rs:322:32:322:45 | Ok(...) [Ok] | provenance | |
@@ -169,11 +171,11 @@ edges
| main.rs:335:9:335:10 | s1 [Ok] | main.rs:336:10:336:11 | s1 [Ok] | provenance | |
| main.rs:335:32:335:45 | Ok(...) [Ok] | main.rs:335:9:335:10 | s1 [Ok] | provenance | |
| main.rs:335:35:335:44 | source(...) | main.rs:335:32:335:45 | Ok(...) [Ok] | provenance | |
| main.rs:336:10:336:11 | s1 [Ok] | main.rs:336:10:336:22 | s1.expect(...) | provenance | MaD:16 |
| main.rs:336:10:336:11 | s1 [Ok] | main.rs:336:10:336:22 | s1.expect(...) | provenance | MaD:18 |
| main.rs:339:9:339:10 | s2 [Err] | main.rs:341:10:341:11 | s2 [Err] | provenance | |
| main.rs:339:32:339:46 | Err(...) [Err] | main.rs:339:9:339:10 | s2 [Err] | provenance | |
| main.rs:339:36:339:45 | source(...) | main.rs:339:32:339:46 | Err(...) [Err] | provenance | |
| main.rs:341:10:341:11 | s2 [Err] | main.rs:341:10:341:26 | s2.expect_err(...) | provenance | MaD:17 |
| main.rs:341:10:341:11 | s2 [Err] | main.rs:341:10:341:26 | s2.expect_err(...) | provenance | MaD:19 |
| main.rs:350:9:350:10 | s1 [A] | main.rs:352:11:352:12 | s1 [A] | provenance | |
| main.rs:350:14:350:39 | ...::A(...) [A] | main.rs:350:9:350:10 | s1 [A] | provenance | |
| main.rs:350:29:350:38 | source(...) | main.rs:350:14:350:39 | ...::A(...) [A] | provenance | |
@@ -222,13 +224,13 @@ edges
| main.rs:430:16:430:33 | [...] [element] | main.rs:430:9:430:12 | arr1 [element] | provenance | |
| main.rs:430:23:430:32 | source(...) | main.rs:430:16:430:33 | [...] [element] | provenance | |
| main.rs:431:9:431:10 | n1 | main.rs:432:10:432:11 | n1 | provenance | |
| main.rs:431:14:431:17 | arr1 [element] | main.rs:431:14:431:20 | arr1[2] | provenance | MaD:5 |
| main.rs:431:14:431:17 | arr1 [element] | main.rs:431:14:431:20 | arr1[2] | provenance | MaD:7 |
| main.rs:431:14:431:20 | arr1[2] | main.rs:431:9:431:10 | n1 | provenance | |
| main.rs:434:9:434:12 | arr2 [element] | main.rs:435:14:435:17 | arr2 [element] | provenance | |
| main.rs:434:16:434:31 | [...; 10] [element] | main.rs:434:9:434:12 | arr2 [element] | provenance | |
| main.rs:434:17:434:26 | source(...) | main.rs:434:16:434:31 | [...; 10] [element] | provenance | |
| main.rs:435:9:435:10 | n2 | main.rs:436:10:436:11 | n2 | provenance | |
| main.rs:435:14:435:17 | arr2 [element] | main.rs:435:14:435:20 | arr2[4] | provenance | MaD:5 |
| main.rs:435:14:435:17 | arr2 [element] | main.rs:435:14:435:20 | arr2[4] | provenance | MaD:7 |
| main.rs:435:14:435:20 | arr2[4] | main.rs:435:9:435:10 | n2 | provenance | |
| main.rs:444:9:444:12 | arr1 [element] | main.rs:445:15:445:18 | arr1 [element] | provenance | |
| main.rs:444:16:444:33 | [...] [element] | main.rs:444:9:444:12 | arr1 [element] | provenance | |
@@ -249,9 +251,9 @@ edges
| main.rs:470:5:470:11 | [post] mut_arr [element] | main.rs:473:10:473:16 | mut_arr [element] | provenance | |
| main.rs:470:18:470:27 | source(...) | main.rs:470:5:470:11 | [post] mut_arr [element] | provenance | |
| main.rs:471:9:471:9 | d | main.rs:472:10:472:10 | d | provenance | |
| main.rs:471:13:471:19 | mut_arr [element] | main.rs:471:13:471:22 | mut_arr[1] | provenance | MaD:5 |
| main.rs:471:13:471:19 | mut_arr [element] | main.rs:471:13:471:22 | mut_arr[1] | provenance | MaD:7 |
| main.rs:471:13:471:22 | mut_arr[1] | main.rs:471:9:471:9 | d | provenance | |
| main.rs:473:10:473:16 | mut_arr [element] | main.rs:473:10:473:19 | mut_arr[0] | provenance | MaD:5 |
| main.rs:473:10:473:16 | mut_arr [element] | main.rs:473:10:473:19 | mut_arr[0] | provenance | MaD:7 |
| main.rs:496:9:496:9 | s | main.rs:497:10:497:10 | s | provenance | |
| main.rs:496:25:496:26 | source(...) | main.rs:496:9:496:9 | s | provenance | |
| main.rs:505:9:505:9 | a | main.rs:506:13:506:13 | a | provenance | |
@@ -263,26 +265,26 @@ edges
| main.rs:506:13:506:13 | a | main.rs:506:13:506:25 | a.to_string() | provenance | MaD:2 |
| main.rs:506:13:506:25 | a.to_string() | main.rs:506:9:506:9 | b | provenance | |
| main.rs:507:9:507:9 | c | main.rs:512:10:512:10 | c | provenance | |
| main.rs:507:13:507:13 | b | main.rs:507:13:507:28 | b.parse() [Ok] | provenance | MaD:4 |
| main.rs:507:13:507:13 | b | main.rs:507:13:507:28 | b.parse() [Ok] | provenance | MaD:8 |
| main.rs:507:13:507:28 | b.parse() [Ok] | main.rs:507:13:507:37 | ... .unwrap() | provenance | MaD:19 |
| main.rs:507:13:507:13 | b | main.rs:507:13:507:28 | b.parse() [Ok] | provenance | MaD:6 |
| main.rs:507:13:507:13 | b | main.rs:507:13:507:28 | b.parse() [Ok] | provenance | MaD:10 |
| main.rs:507:13:507:28 | b.parse() [Ok] | main.rs:507:13:507:37 | ... .unwrap() | provenance | MaD:21 |
| main.rs:507:13:507:37 | ... .unwrap() | main.rs:507:9:507:9 | c | provenance | |
| main.rs:508:9:508:9 | d | main.rs:513:10:513:10 | d | provenance | |
| main.rs:508:18:508:18 | b | main.rs:508:18:508:26 | b.parse() [Ok] | provenance | MaD:4 |
| main.rs:508:18:508:18 | b | main.rs:508:18:508:26 | b.parse() [Ok] | provenance | MaD:8 |
| main.rs:508:18:508:26 | b.parse() [Ok] | main.rs:508:18:508:35 | ... .unwrap() | provenance | MaD:19 |
| main.rs:508:18:508:18 | b | main.rs:508:18:508:26 | b.parse() [Ok] | provenance | MaD:6 |
| main.rs:508:18:508:18 | b | main.rs:508:18:508:26 | b.parse() [Ok] | provenance | MaD:10 |
| main.rs:508:18:508:26 | b.parse() [Ok] | main.rs:508:18:508:35 | ... .unwrap() | provenance | MaD:21 |
| main.rs:508:18:508:35 | ... .unwrap() | main.rs:508:9:508:9 | d | provenance | |
| main.rs:517:9:517:10 | vs [element] | main.rs:519:10:519:11 | vs [element] | provenance | |
| main.rs:517:9:517:10 | vs [element] | main.rs:523:14:523:15 | vs [element] | provenance | |
| main.rs:517:14:517:34 | [...] [element] | main.rs:517:9:517:10 | vs [element] | provenance | |
| main.rs:517:15:517:24 | source(...) | main.rs:517:14:517:34 | [...] [element] | provenance | |
| main.rs:519:10:519:11 | vs [element] | main.rs:519:10:519:14 | vs[0] | provenance | MaD:5 |
| main.rs:519:10:519:11 | vs [element] | main.rs:519:10:519:14 | vs[0] | provenance | MaD:7 |
| main.rs:523:9:523:9 | v | main.rs:524:14:524:14 | v | provenance | |
| main.rs:523:14:523:15 | vs [element] | main.rs:523:9:523:9 | v | provenance | |
| main.rs:542:9:542:18 | mut vs_mut [element] | main.rs:544:10:544:15 | vs_mut [element] | provenance | |
| main.rs:542:22:542:42 | [...] [element] | main.rs:542:9:542:18 | mut vs_mut [element] | provenance | |
| main.rs:542:23:542:32 | source(...) | main.rs:542:22:542:42 | [...] [element] | provenance | |
| main.rs:544:10:544:15 | vs_mut [element] | main.rs:544:10:544:18 | vs_mut[0] | provenance | MaD:5 |
| main.rs:544:10:544:15 | vs_mut [element] | main.rs:544:10:544:18 | vs_mut[0] | provenance | MaD:7 |
| main.rs:554:9:554:9 | a | main.rs:559:10:559:10 | a | provenance | |
| main.rs:554:13:554:22 | source(...) | main.rs:554:9:554:9 | a | provenance | |
| main.rs:555:9:555:9 | b | main.rs:560:15:560:15 | b | provenance | |
@@ -296,12 +298,20 @@ edges
| main.rs:560:15:560:15 | b | main.rs:560:14:560:15 | &b | provenance | |
| main.rs:562:11:562:15 | c_ref [&ref] | main.rs:562:10:562:15 | * ... | provenance | MaD:1 |
| main.rs:566:9:566:9 | a | main.rs:568:10:568:17 | a as i64 | provenance | |
| main.rs:566:9:566:9 | a | main.rs:569:10:569:10 | a | provenance | |
| main.rs:566:9:566:9 | a | main.rs:570:20:570:20 | a | provenance | |
| main.rs:566:18:566:27 | source(...) | main.rs:566:9:566:9 | a | provenance | |
| main.rs:569:10:569:10 | a | main.rs:569:10:569:17 | a.into() | provenance | MaD:4 |
| main.rs:569:10:569:10 | a | main.rs:569:10:569:17 | a.into() | provenance | MaD:5 |
| main.rs:570:20:570:20 | a | main.rs:570:10:570:21 | ...::from(...) | provenance | ReflexiveFrom |
| main.rs:572:9:572:9 | b | main.rs:574:10:574:17 | b as i64 | provenance | |
| main.rs:572:9:572:9 | b | main.rs:575:10:575:10 | b | provenance | |
| main.rs:572:9:572:9 | b | main.rs:576:20:576:20 | b | provenance | |
| main.rs:572:18:572:27 | source(...) | main.rs:572:9:572:9 | b | provenance | |
| main.rs:575:10:575:10 | b | main.rs:575:10:575:17 | b.into() | provenance | MaD:4 |
| main.rs:575:10:575:10 | b | main.rs:575:10:575:17 | b.into() | provenance | MaD:5 |
| main.rs:576:20:576:20 | b | main.rs:576:10:576:21 | ...::from(...) | provenance | MaD:3 |
| main.rs:576:20:576:20 | b | main.rs:576:10:576:21 | ...::from(...) | provenance | MaD:9 |
| main.rs:576:20:576:20 | b | main.rs:576:10:576:21 | ...::from(...) | provenance | MaD:11 |
nodes
| main.rs:19:10:19:18 | source(...) | semmle.label | source(...) |
| main.rs:23:9:23:9 | s | semmle.label | s |
@@ -630,9 +640,15 @@ nodes
| main.rs:566:9:566:9 | a | semmle.label | a |
| main.rs:566:18:566:27 | source(...) | semmle.label | source(...) |
| main.rs:568:10:568:17 | a as i64 | semmle.label | a as i64 |
| main.rs:569:10:569:10 | a | semmle.label | a |
| main.rs:569:10:569:17 | a.into() | semmle.label | a.into() |
| main.rs:570:10:570:21 | ...::from(...) | semmle.label | ...::from(...) |
| main.rs:570:20:570:20 | a | semmle.label | a |
| main.rs:572:9:572:9 | b | semmle.label | b |
| main.rs:572:18:572:27 | source(...) | semmle.label | source(...) |
| main.rs:574:10:574:17 | b as i64 | semmle.label | b as i64 |
| main.rs:575:10:575:10 | b | semmle.label | b |
| main.rs:575:10:575:17 | b.into() | semmle.label | b.into() |
| main.rs:576:10:576:21 | ...::from(...) | semmle.label | ...::from(...) |
| main.rs:576:20:576:20 | b | semmle.label | b |
subpaths
@@ -707,5 +723,8 @@ testFailures
| main.rs:561:14:561:18 | c_ref | main.rs:556:13:556:22 | source(...) | main.rs:561:14:561:18 | c_ref | $@ | main.rs:556:13:556:22 | source(...) | source(...) |
| main.rs:562:10:562:15 | * ... | main.rs:556:13:556:22 | source(...) | main.rs:562:10:562:15 | * ... | $@ | main.rs:556:13:556:22 | source(...) | source(...) |
| main.rs:568:10:568:17 | a as i64 | main.rs:566:18:566:27 | source(...) | main.rs:568:10:568:17 | a as i64 | $@ | main.rs:566:18:566:27 | source(...) | source(...) |
| main.rs:569:10:569:17 | a.into() | main.rs:566:18:566:27 | source(...) | main.rs:569:10:569:17 | a.into() | $@ | main.rs:566:18:566:27 | source(...) | source(...) |
| main.rs:570:10:570:21 | ...::from(...) | main.rs:566:18:566:27 | source(...) | main.rs:570:10:570:21 | ...::from(...) | $@ | main.rs:566:18:566:27 | source(...) | source(...) |
| main.rs:574:10:574:17 | b as i64 | main.rs:572:18:572:27 | source(...) | main.rs:574:10:574:17 | b as i64 | $@ | main.rs:572:18:572:27 | source(...) | source(...) |
| main.rs:575:10:575:17 | b.into() | main.rs:572:18:572:27 | source(...) | main.rs:575:10:575:17 | b.into() | $@ | main.rs:572:18:572:27 | source(...) | source(...) |
| main.rs:576:10:576:21 | ...::from(...) | main.rs:572:18:572:27 | source(...) | main.rs:576:10:576:21 | ...::from(...) | $@ | main.rs:572:18:572:27 | source(...) | source(...) |

View File

@@ -566,13 +566,13 @@ fn conversions() {
let a: i64 = source(50);
sink(a as i64); // $ hasTaintFlow=50
sink(a.into()); // $ MISSING: hasValueFlow=50
sink(i64::from(a)); // $ MISSING: hasTaintFlow=50 -- we cannot resolve the `impl<T> From<T> for T` implementation
sink(a.into()); // $ SPURIOUS: hasTaintFlow=50 $ MISSING: hasValueFlow=50 -- it is not possible to define a value-preserving summary for `into` since it depends on which `from` function is called
sink(i64::from(a)); // $ hasValueFlow=50
let b: i32 = source(51) as i32;
sink(b as i64); // $ hasTaintFlow=51
sink(b.into()); // $ MISSING: hasTaintFlow=51
sink(b.into()); // $ hasTaintFlow=51
sink(i64::from(b)); // $ hasTaintFlow=51
}

View File

@@ -2595,7 +2595,7 @@ mod tuples {
let i: i64 = pair.0; // $ fieldof=Tuple2
let j: bool = pair.1; // $ fieldof=Tuple2
let pair = [1, 1].into(); // $ type=pair:(T_2) type=pair:T0.i32 type=pair:T1.i32 MISSING: target=into
let pair = [1, 1].into(); // $ type=pair:(T_2) type=pair:T0.i32 type=pair:T1.i32 target=into
match pair {
(0, 0) => print!("unexpected"),
_ => print!("expected"),