mirror of
https://github.com/github/codeql.git
synced 2026-04-26 17:25:19 +02:00
Merge pull request #19995 from hvitved/rust/disambiguate-assoc-function-calls
Rust: Disambiguate associated function calls
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Call resolution for calls to associated functions has been improved, so it now disambiguates the targets based on type information at the call sites (either type information about the arguments or about the expected return types).
|
||||
@@ -13,6 +13,7 @@ private import codeql.rust.elements.Resolvable
|
||||
*/
|
||||
module Impl {
|
||||
private import rust
|
||||
private import codeql.rust.internal.TypeInference as TypeInference
|
||||
|
||||
pragma[nomagic]
|
||||
Resolvable getCallResolvable(CallExprBase call) {
|
||||
@@ -27,7 +28,7 @@ module Impl {
|
||||
*/
|
||||
class CallExprBase extends Generated::CallExprBase {
|
||||
/** Gets the static target of this call, if any. */
|
||||
Callable getStaticTarget() { none() } // overridden by subclasses, but cannot be made abstract
|
||||
final Function getStaticTarget() { result = TypeInference::resolveCallTarget(this) }
|
||||
|
||||
override Expr getArg(int index) { result = this.getArgList().getArg(index) }
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ private import codeql.rust.elements.PathExpr
|
||||
module Impl {
|
||||
private import rust
|
||||
private import codeql.rust.internal.PathResolution as PathResolution
|
||||
private import codeql.rust.internal.TypeInference as TypeInference
|
||||
|
||||
pragma[nomagic]
|
||||
Path getFunctionPath(CallExpr ce) { result = ce.getFunction().(PathExpr).getPath() }
|
||||
@@ -37,15 +36,6 @@ module Impl {
|
||||
class CallExpr extends Generated::CallExpr {
|
||||
override string toStringImpl() { result = this.getFunction().toAbbreviatedString() + "(...)" }
|
||||
|
||||
override Callable getStaticTarget() {
|
||||
// If this call is to a trait method, e.g., `Trait::foo(bar)`, then check
|
||||
// if type inference can resolve it to the correct trait implementation.
|
||||
result = TypeInference::resolveMethodCallTarget(this)
|
||||
or
|
||||
not exists(TypeInference::resolveMethodCallTarget(this)) and
|
||||
result = getResolvedFunction(this)
|
||||
}
|
||||
|
||||
/** Gets the struct that this call resolves to, if any. */
|
||||
Struct getStruct() { result = getResolvedFunction(this) }
|
||||
|
||||
|
||||
@@ -40,6 +40,9 @@ module Impl {
|
||||
/** Gets the trait targeted by this call, if any. */
|
||||
abstract Trait getTrait();
|
||||
|
||||
/** Holds if this call targets a trait. */
|
||||
predicate hasTrait() { exists(this.getTrait()) }
|
||||
|
||||
/** Gets the name of the method called if this call is a method call. */
|
||||
abstract string getMethodName();
|
||||
|
||||
@@ -59,12 +62,7 @@ module Impl {
|
||||
Expr getReceiver() { result = this.getArgument(TSelfArgumentPosition()) }
|
||||
|
||||
/** Gets the static target of this call, if any. */
|
||||
Function getStaticTarget() {
|
||||
result = TypeInference::resolveMethodCallTarget(this)
|
||||
or
|
||||
not exists(TypeInference::resolveMethodCallTarget(this)) and
|
||||
result = this.(CallExpr).getStaticTarget()
|
||||
}
|
||||
Function getStaticTarget() { result = TypeInference::resolveCallTarget(this) }
|
||||
|
||||
/** Gets a runtime target of this call, if any. */
|
||||
pragma[nomagic]
|
||||
@@ -78,23 +76,44 @@ module Impl {
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if the call expression dispatches to a method. */
|
||||
private predicate callIsMethodCall(CallExpr call, Path qualifier, string methodName) {
|
||||
exists(Path path, Function f |
|
||||
path = call.getFunction().(PathExpr).getPath() and
|
||||
f = resolvePath(path) and
|
||||
f.getParamList().hasSelfParam() and
|
||||
qualifier = path.getQualifier() and
|
||||
path.getSegment().getIdentifier().getText() = methodName
|
||||
private predicate callHasQualifier(CallExpr call, Path path, Path qualifier) {
|
||||
path = call.getFunction().(PathExpr).getPath() and
|
||||
qualifier = path.getQualifier()
|
||||
}
|
||||
|
||||
private predicate callHasTraitQualifier(CallExpr call, Trait qualifier) {
|
||||
exists(RelevantPath qualifierPath |
|
||||
callHasQualifier(call, _, qualifierPath) and
|
||||
qualifier = resolvePath(qualifierPath) and
|
||||
// When the qualifier is `Self` and resolves to a trait, it's inside a
|
||||
// trait method's default implementation. This is not a dispatch whose
|
||||
// target is inferred from the type of the receiver, but should always
|
||||
// resolve to the function in the trait block as path resolution does.
|
||||
not qualifierPath.isUnqualified("Self")
|
||||
)
|
||||
}
|
||||
|
||||
private class CallExprCall extends Call instanceof CallExpr {
|
||||
CallExprCall() { not callIsMethodCall(this, _, _) }
|
||||
/** Holds if the call expression dispatches to a method. */
|
||||
private predicate callIsMethodCall(
|
||||
CallExpr call, Path qualifier, string methodName, boolean selfIsRef
|
||||
) {
|
||||
exists(Path path, Function f |
|
||||
callHasQualifier(call, path, qualifier) and
|
||||
f = resolvePath(path) and
|
||||
path.getSegment().getIdentifier().getText() = methodName and
|
||||
exists(SelfParam self |
|
||||
self = f.getParamList().getSelfParam() and
|
||||
if self.isRef() then selfIsRef = true else selfIsRef = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class CallExprCall extends Call instanceof CallExpr {
|
||||
CallExprCall() { not callIsMethodCall(this, _, _, _) }
|
||||
|
||||
override string getMethodName() { none() }
|
||||
|
||||
override Trait getTrait() { none() }
|
||||
override Trait getTrait() { callHasTraitQualifier(this, result) }
|
||||
|
||||
override predicate implicitBorrowAt(ArgumentPosition pos, boolean certain) { none() }
|
||||
|
||||
@@ -103,22 +122,23 @@ module Impl {
|
||||
}
|
||||
}
|
||||
|
||||
private class CallExprMethodCall extends Call instanceof CallExpr {
|
||||
class CallExprMethodCall extends Call instanceof CallExpr {
|
||||
Path qualifier;
|
||||
string methodName;
|
||||
boolean selfIsRef;
|
||||
|
||||
CallExprMethodCall() { callIsMethodCall(this, qualifier, methodName) }
|
||||
CallExprMethodCall() { callIsMethodCall(this, qualifier, methodName, selfIsRef) }
|
||||
|
||||
/**
|
||||
* Holds if this call must have an explicit borrow for the `self` argument,
|
||||
* because the corresponding parameter is `&self`. Explicit borrows are not
|
||||
* needed when using method call syntax.
|
||||
*/
|
||||
predicate hasExplicitSelfBorrow() { selfIsRef = true }
|
||||
|
||||
override string getMethodName() { result = methodName }
|
||||
|
||||
override Trait getTrait() {
|
||||
result = resolvePath(qualifier) and
|
||||
// When the qualifier is `Self` and resolves to a trait, it's inside a
|
||||
// trait method's default implementation. This is not a dispatch whose
|
||||
// target is inferred from the type of the receiver, but should always
|
||||
// resolve to the function in the trait block as path resolution does.
|
||||
qualifier.toString() != "Self"
|
||||
}
|
||||
override Trait getTrait() { callHasTraitQualifier(this, result) }
|
||||
|
||||
override predicate implicitBorrowAt(ArgumentPosition pos, boolean certain) { none() }
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
private import rust
|
||||
private import codeql.rust.elements.internal.generated.MethodCallExpr
|
||||
private import codeql.rust.internal.PathResolution
|
||||
private import codeql.rust.internal.TypeInference
|
||||
|
||||
/**
|
||||
* INTERNAL: This module contains the customizable definition of `MethodCallExpr` and should not
|
||||
@@ -23,8 +21,6 @@ module Impl {
|
||||
* ```
|
||||
*/
|
||||
class MethodCallExpr extends Generated::MethodCallExpr {
|
||||
override Function getStaticTarget() { result = resolveMethodCallTarget(this) }
|
||||
|
||||
private string toStringPart(int index) {
|
||||
index = 0 and
|
||||
result = this.getReceiver().toAbbreviatedString()
|
||||
|
||||
@@ -425,6 +425,8 @@ final class TraitTypeAbstraction extends TypeAbstraction, Trait {
|
||||
result.(TypeParamTypeParameter).getTypeParam() = this.getGenericParamList().getATypeParam()
|
||||
or
|
||||
result.(AssociatedTypeTypeParameter).getTrait() = this
|
||||
or
|
||||
result.(SelfTypeParameter).getTrait() = this
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ private import codeql.rust.frameworks.stdlib.Stdlib
|
||||
private import codeql.rust.frameworks.stdlib.Builtins as Builtins
|
||||
private import codeql.rust.elements.Call
|
||||
private import codeql.rust.elements.internal.CallImpl::Impl as CallImpl
|
||||
private import codeql.rust.elements.internal.CallExprImpl::Impl as CallExprImpl
|
||||
|
||||
class Type = T::Type;
|
||||
|
||||
@@ -522,6 +523,15 @@ private Type inferPathExprType(PathExpr pe, TypePath path) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the explicit type qualifier of the call `ce`, if any. */
|
||||
private Type getTypeQualifier(CallExpr ce, TypePath path) {
|
||||
exists(PathExpr pe, TypeMention tm |
|
||||
pe = ce.getFunction() and
|
||||
tm = pe.getPath().getQualifier() and
|
||||
result = tm.resolveTypeAt(path)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A matching configuration for resolving types of call expressions
|
||||
* like `foo::bar(baz)` and `foo.bar(baz)`.
|
||||
@@ -724,8 +734,6 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
|
||||
}
|
||||
}
|
||||
|
||||
private import codeql.rust.elements.internal.CallExprImpl::Impl as CallExprImpl
|
||||
|
||||
final class Access extends Call {
|
||||
pragma[nomagic]
|
||||
Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
|
||||
@@ -761,17 +769,13 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
|
||||
or
|
||||
// The `Self` type is supplied explicitly as a type qualifier, e.g. `Foo::<Bar>::baz()`
|
||||
apos = TArgumentAccessPosition(CallImpl::TSelfArgumentPosition(), false, false) and
|
||||
exists(PathExpr pe, TypeMention tm |
|
||||
pe = this.(CallExpr).getFunction() and
|
||||
tm = pe.getPath().getQualifier() and
|
||||
result = tm.resolveTypeAt(path)
|
||||
)
|
||||
result = getTypeQualifier(this, path)
|
||||
}
|
||||
|
||||
Declaration getTarget() {
|
||||
result = resolveMethodCallTarget(this) // mutual recursion; resolving method calls requires resolving types and vice versa
|
||||
or
|
||||
result = CallExprImpl::getResolvedFunction(this)
|
||||
result = resolveFunctionCallTarget(this) // potential mutual recursion; resolving some associated function calls requires resolving types
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1220,15 +1224,28 @@ private Type inferForLoopExprType(AstNode n, TypePath path) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Type inferCastExprType(CastExpr ce, TypePath path) {
|
||||
result = ce.getTypeRepr().(TypeMention).resolveTypeAt(path)
|
||||
}
|
||||
|
||||
final class MethodCall extends Call {
|
||||
MethodCall() { exists(this.getReceiver()) }
|
||||
|
||||
private Type getReceiverTypeAt(TypePath path) {
|
||||
result = inferType(super.getReceiver(), path)
|
||||
or
|
||||
result = getTypeQualifier(this, path)
|
||||
}
|
||||
|
||||
/** Gets the type of the receiver of the method call at `path`. */
|
||||
Type getTypeAt(TypePath path) {
|
||||
if this.receiverImplicitlyBorrowed()
|
||||
if
|
||||
this.receiverImplicitlyBorrowed() or
|
||||
this.(CallImpl::CallExprMethodCall).hasExplicitSelfBorrow()
|
||||
then
|
||||
exists(TypePath path0, Type t0 |
|
||||
t0 = inferType(super.getReceiver(), path0) and
|
||||
t0 = this.getReceiverTypeAt(path0) and
|
||||
(
|
||||
path0.isCons(TRefTypeParameter(), path)
|
||||
or
|
||||
@@ -1256,7 +1273,7 @@ final class MethodCall extends Call {
|
||||
t0.(StructType).asItemNode() instanceof StringStruct and
|
||||
result.(StructType).asItemNode() instanceof Builtins::Str
|
||||
)
|
||||
else result = inferType(super.getReceiver(), path)
|
||||
else result = this.getReceiverTypeAt(path)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1349,8 +1366,6 @@ private predicate implSiblingCandidate(
|
||||
// contains the same `impl` block so considering both would give spurious
|
||||
// siblings).
|
||||
not exists(impl.getAttributeMacroExpansion()) and
|
||||
// We use this for resolving methods, so exclude traits that do not have methods.
|
||||
exists(Function f | f = trait.getASuccessor(_) and f.getParamList().hasSelfParam()) and
|
||||
selfTy = impl.getSelfTy() and
|
||||
rootType = selfTy.resolveType()
|
||||
}
|
||||
@@ -1385,42 +1400,49 @@ private predicate implSiblings(TraitItemNode trait, Impl impl1, Impl impl2) {
|
||||
pragma[nomagic]
|
||||
private predicate implHasSibling(Impl impl, Trait trait) { implSiblings(trait, impl, _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate functionTypeAtPath(Function f, int pos, TypePath path, Type type) {
|
||||
exists(TypeMention tm | type = tm.resolveTypeAt(path) |
|
||||
tm = f.getParam(pos).getTypeRepr()
|
||||
or
|
||||
pos = -1 and
|
||||
tm = f.getRetType().getTypeRepr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a type parameter of `trait` occurs in the method with the name
|
||||
* `methodName` at the `pos`th parameter at `path`.
|
||||
* Holds if type parameter `tp` of `trait` occurs in the function with the name
|
||||
* `functionName` at the `pos`th parameter at `path`.
|
||||
*
|
||||
* The special position `-1` refers to the return type of the function, which
|
||||
* is sometimes needed to disambiguate associated function calls like
|
||||
* `Default::default()` (in this case, `tp` is the special `Self` type parameter).
|
||||
*/
|
||||
bindingset[trait]
|
||||
pragma[inline_late]
|
||||
private predicate traitTypeParameterOccurrence(
|
||||
TraitItemNode trait, string methodName, int pos, TypePath path
|
||||
TraitItemNode trait, Function f, string functionName, int pos, TypePath path, TypeParameter tp
|
||||
) {
|
||||
exists(Function f | f = trait.getASuccessor(methodName) |
|
||||
f.getParam(pos).getTypeRepr().(TypeMention).resolveTypeAt(path) =
|
||||
trait.(TraitTypeAbstraction).getATypeParameter()
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[f, pos, path]
|
||||
pragma[inline_late]
|
||||
private predicate methodTypeAtPath(Function f, int pos, TypePath path, Type type) {
|
||||
f.getParam(pos).getTypeRepr().(TypeMention).resolveTypeAt(path) = type
|
||||
f = trait.getAssocItem(functionName) and
|
||||
functionTypeAtPath(f, pos, path, tp) and
|
||||
tp = trait.(TraitTypeAbstraction).getATypeParameter()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if resolving the method `f` in `impl` with the name `methodName`
|
||||
* Holds if resolving the function `f` in `impl` with the name `functionName`
|
||||
* requires inspecting the types of applied _arguments_ in order to determine
|
||||
* whether it is the correct resolution.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate methodResolutionDependsOnArgument(
|
||||
Impl impl, string methodName, Function f, int pos, TypePath path, Type type
|
||||
private predicate functionResolutionDependsOnArgument(
|
||||
ImplItemNode impl, string functionName, Function f, int pos, TypePath path, Type type
|
||||
) {
|
||||
/*
|
||||
* As seen in the example below, when an implementation has a sibling for a
|
||||
* trait we find occurrences of a type parameter of the trait in a method
|
||||
* trait we find occurrences of a type parameter of the trait in a function
|
||||
* signature in the trait. We then find the type given in the implementation
|
||||
* at the same position, which is a position that might disambiguate the
|
||||
* method from its siblings.
|
||||
* function from its siblings.
|
||||
*
|
||||
* ```rust
|
||||
* trait MyTrait<T> {
|
||||
@@ -1442,9 +1464,10 @@ private predicate methodResolutionDependsOnArgument(
|
||||
|
||||
exists(TraitItemNode trait |
|
||||
implHasSibling(impl, trait) and
|
||||
traitTypeParameterOccurrence(trait, methodName, pos, path) and
|
||||
methodTypeAtPath(getMethodSuccessor(impl, methodName), pos, path, type) and
|
||||
f = getMethodSuccessor(impl, methodName)
|
||||
traitTypeParameterOccurrence(trait, _, functionName, pos, path, _) and
|
||||
functionTypeAtPath(f, pos, path, type) and
|
||||
f = impl.getAssocItem(functionName) and
|
||||
pos >= 0
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1484,11 +1507,12 @@ private Function getMethodFromImpl(MethodCall mc) {
|
||||
name = mc.getMethodName() and
|
||||
result = getMethodSuccessor(impl, name)
|
||||
|
|
||||
not methodResolutionDependsOnArgument(impl, _, _, _, _, _)
|
||||
not functionResolutionDependsOnArgument(impl, name, _, _, _, _)
|
||||
or
|
||||
exists(int pos, TypePath path, Type type |
|
||||
methodResolutionDependsOnArgument(impl, name, result, pos, path, type) and
|
||||
inferType(mc.getPositionalArgument(pos), path) = type
|
||||
functionResolutionDependsOnArgument(impl, name, result, pos, pragma[only_bind_into](path),
|
||||
type) and
|
||||
inferType(mc.getPositionalArgument(pos), pragma[only_bind_into](path)) = type
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1499,6 +1523,162 @@ private Function getTraitMethod(ImplTraitReturnType trait, string name) {
|
||||
result = getMethodSuccessor(trait.getImplTraitTypeRepr(), name)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Function resolveMethodCallTarget(MethodCall mc) {
|
||||
// The method comes from an `impl` block targeting the type of the receiver.
|
||||
result = getMethodFromImpl(mc)
|
||||
or
|
||||
// The type of the receiver is a type parameter and the method comes from a
|
||||
// trait bound on the type parameter.
|
||||
result = getTypeParameterMethod(mc.getTypeAt(TypePath::nil()), mc.getMethodName())
|
||||
or
|
||||
// The type of the receiver is an `impl Trait` type.
|
||||
result = getTraitMethod(mc.getTypeAt(TypePath::nil()), mc.getMethodName())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate assocFuncResolutionDependsOnArgument(Function f, Impl impl, int pos) {
|
||||
functionResolutionDependsOnArgument(impl, _, f, pos, _, _) and
|
||||
not f.getParamList().hasSelfParam()
|
||||
}
|
||||
|
||||
private class FunctionCallExpr extends CallImpl::CallExprCall {
|
||||
ItemNode getResolvedFunction() { result = CallExprImpl::getResolvedFunction(this) }
|
||||
|
||||
/**
|
||||
* Holds if the target of this call is ambigous, and type information is required
|
||||
* to disambiguate.
|
||||
*/
|
||||
predicate isAmbigous() {
|
||||
this.hasTrait()
|
||||
or
|
||||
assocFuncResolutionDependsOnArgument(this.getResolvedFunction(), _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a target candidate of this ambigous call, which belongs to `impl`.
|
||||
*
|
||||
* In order for the candidate to be a match, the argument type at `pos` must be
|
||||
* checked against the type of the function at the same position.
|
||||
*
|
||||
* `resolved` is the corresponding function resolved through path resolution.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
Function getAnAmbigousCandidate(ImplItemNode impl, int pos, Function resolved) {
|
||||
resolved = this.getResolvedFunction() and
|
||||
(
|
||||
exists(TraitItemNode trait |
|
||||
trait = this.getTrait() and
|
||||
result.implements(resolved) and
|
||||
result = impl.getAnAssocItem()
|
||||
|
|
||||
assocFuncResolutionDependsOnArgument(result, impl, pos)
|
||||
or
|
||||
exists(TypeParameter tp | traitTypeParameterOccurrence(trait, resolved, _, pos, _, tp) |
|
||||
pos >= 0
|
||||
or
|
||||
// We only check that the context of the call provides relevant type information
|
||||
// when no argument can
|
||||
not traitTypeParameterOccurrence(trait, resolved, _, any(int pos0 | pos0 >= 0), _, tp)
|
||||
)
|
||||
)
|
||||
or
|
||||
result = resolved and
|
||||
assocFuncResolutionDependsOnArgument(result, impl, pos)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `getAnAmbigousCandidate`, ranks the positions to be checked.
|
||||
*/
|
||||
Function getAnAmbigousCandidateRanked(ImplItemNode impl, int pos, Function f, int rnk) {
|
||||
pos = rank[rnk + 1](int pos0 | result = this.getAnAmbigousCandidate(impl, pos0, f) | pos0)
|
||||
}
|
||||
}
|
||||
|
||||
private newtype TAmbigousAssocFunctionCallExpr =
|
||||
MkAmbigousAssocFunctionCallExpr(FunctionCallExpr call, Function resolved, int pos) {
|
||||
exists(call.getAnAmbigousCandidate(_, pos, resolved))
|
||||
}
|
||||
|
||||
private class AmbigousAssocFunctionCallExpr extends MkAmbigousAssocFunctionCallExpr {
|
||||
FunctionCallExpr call;
|
||||
Function resolved;
|
||||
int pos;
|
||||
|
||||
AmbigousAssocFunctionCallExpr() { this = MkAmbigousAssocFunctionCallExpr(call, resolved, pos) }
|
||||
|
||||
pragma[nomagic]
|
||||
Type getTypeAt(TypePath path) {
|
||||
result = inferType(call.(CallExpr).getArg(pos), path)
|
||||
or
|
||||
pos = -1 and
|
||||
result = inferType(call, path)
|
||||
}
|
||||
|
||||
string toString() { result = call.toString() }
|
||||
|
||||
Location getLocation() { result = call.getLocation() }
|
||||
}
|
||||
|
||||
private module AmbigousAssocFuncIsInstantiationOfInput implements
|
||||
IsInstantiationOfInputSig<AmbigousAssocFunctionCallExpr>
|
||||
{
|
||||
pragma[nomagic]
|
||||
predicate potentialInstantiationOf(
|
||||
AmbigousAssocFunctionCallExpr ce, TypeAbstraction impl, TypeMention constraint
|
||||
) {
|
||||
exists(FunctionCallExpr call, Function resolved, Function cand, int pos |
|
||||
ce = MkAmbigousAssocFunctionCallExpr(call, resolved, pos) and
|
||||
cand = call.getAnAmbigousCandidate(impl, pos, resolved)
|
||||
|
|
||||
constraint = cand.getParam(pos).getTypeRepr()
|
||||
or
|
||||
pos = -1 and
|
||||
constraint = cand.getRetType().getTypeRepr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target of `call`, where resolution does not rely on type inference.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private ItemNode resolveUnambigousFunctionCallTarget(FunctionCallExpr call) {
|
||||
result = call.getResolvedFunction() and
|
||||
not call.isAmbigous()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Function resolveAmbigousFunctionCallTargetFromIndex(FunctionCallExpr call, int index) {
|
||||
exists(Impl impl, int pos, Function resolved |
|
||||
IsInstantiationOf<AmbigousAssocFunctionCallExpr, AmbigousAssocFuncIsInstantiationOfInput>::isInstantiationOf(MkAmbigousAssocFunctionCallExpr(call,
|
||||
resolved, pos), impl, _) and
|
||||
result = call.getAnAmbigousCandidateRanked(impl, pos, resolved, index)
|
||||
|
|
||||
index = 0
|
||||
or
|
||||
result = resolveAmbigousFunctionCallTargetFromIndex(call, index - 1)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target of `call`, where resolution relies on type inference.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private Function resolveAmbigousFunctionCallTarget(FunctionCallExpr call) {
|
||||
result =
|
||||
resolveAmbigousFunctionCallTargetFromIndex(call,
|
||||
max(int index | result = call.getAnAmbigousCandidateRanked(_, _, _, index)))
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private ItemNode resolveFunctionCallTarget(FunctionCallExpr call) {
|
||||
result = resolveUnambigousFunctionCallTarget(call)
|
||||
or
|
||||
result = resolveAmbigousFunctionCallTarget(call)
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
private import codeql.rust.internal.CachedStages
|
||||
@@ -1527,18 +1707,12 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a method that the method call `mc` resolves to, if any. */
|
||||
/** Gets a function that `call` resolves to, if any. */
|
||||
cached
|
||||
Function resolveMethodCallTarget(MethodCall mc) {
|
||||
// The method comes from an `impl` block targeting the type of the receiver.
|
||||
result = getMethodFromImpl(mc)
|
||||
Function resolveCallTarget(Call call) {
|
||||
result = resolveMethodCallTarget(call)
|
||||
or
|
||||
// The type of the receiver is a type parameter and the method comes from a
|
||||
// trait bound on the type parameter.
|
||||
result = getTypeParameterMethod(mc.getTypeAt(TypePath::nil()), mc.getMethodName())
|
||||
or
|
||||
// The type of the receiver is an `impl Trait` type.
|
||||
result = getTraitMethod(mc.getTypeAt(TypePath::nil()), mc.getMethodName())
|
||||
result = resolveFunctionCallTarget(call)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
@@ -1660,6 +1834,8 @@ private module Cached {
|
||||
result = inferIndexExprType(n, path)
|
||||
or
|
||||
result = inferForLoopExprType(n, path)
|
||||
or
|
||||
result = inferCastExprType(n, path)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1685,9 +1861,9 @@ private module Debug {
|
||||
result = inferType(n, path)
|
||||
}
|
||||
|
||||
Function debugResolveMethodCallTarget(Call mce) {
|
||||
mce = getRelevantLocatable() and
|
||||
result = resolveMethodCallTarget(mce)
|
||||
Function debugResolveCallTarget(Call c) {
|
||||
c = getRelevantLocatable() and
|
||||
result = resolveCallTarget(c)
|
||||
}
|
||||
|
||||
predicate debugInferImplicitSelfType(SelfParam self, TypePath path, Type t) {
|
||||
@@ -1705,6 +1881,11 @@ private module Debug {
|
||||
tm.resolveTypeAt(path) = type
|
||||
}
|
||||
|
||||
Type debugInferAnnotatedType(AstNode n, TypePath path) {
|
||||
n = getRelevantLocatable() and
|
||||
result = inferAnnotatedType(n, path)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private int countTypesAtPath(AstNode n, TypePath path, Type t) {
|
||||
t = inferType(n, path) and
|
||||
|
||||
@@ -1,19 +1,10 @@
|
||||
multipleCallTargets
|
||||
| proc_macro.rs:6:18:6:61 | ...::from(...) |
|
||||
| proc_macro.rs:7:15:7:58 | ...::from(...) |
|
||||
| proc_macro.rs:15:5:17:5 | ...::new(...) |
|
||||
| proc_macro.rs:16:12:16:16 | ...::to_tokens(...) |
|
||||
| proc_macro.rs:22:15:22:58 | ...::from(...) |
|
||||
| proc_macro.rs:25:5:28:5 | ...::new(...) |
|
||||
| proc_macro.rs:26:10:26:12 | ...::to_tokens(...) |
|
||||
| proc_macro.rs:27:10:27:16 | ...::to_tokens(...) |
|
||||
| proc_macro.rs:38:15:38:64 | ...::from(...) |
|
||||
| proc_macro.rs:41:5:49:5 | ...::new(...) |
|
||||
| proc_macro.rs:41:5:49:5 | ...::new(...) |
|
||||
| proc_macro.rs:41:5:49:5 | ...::new(...) |
|
||||
| proc_macro.rs:41:5:49:5 | ...::new(...) |
|
||||
| proc_macro.rs:42:16:42:26 | ...::to_tokens(...) |
|
||||
| proc_macro.rs:44:27:44:30 | ...::to_tokens(...) |
|
||||
| proc_macro.rs:46:18:46:28 | ...::to_tokens(...) |
|
||||
multiplePathResolutions
|
||||
| macro_expansion.rs:1:5:1:14 | proc_macro |
|
||||
|
||||
@@ -117,6 +117,11 @@ edges
|
||||
| main.rs:228:11:228:14 | [post] self [&ref, MyInt] | main.rs:227:19:227:27 | SelfParam [Return] [&ref, MyInt] | provenance | |
|
||||
| main.rs:228:25:228:27 | rhs [MyInt] | main.rs:228:25:228:33 | rhs.value | provenance | |
|
||||
| main.rs:228:25:228:33 | rhs.value | main.rs:228:10:228:14 | [post] * ... [MyInt] | provenance | |
|
||||
| main.rs:235:14:235:18 | SelfParam [&ref, MyInt] | main.rs:236:12:236:15 | self [&ref, MyInt] | provenance | |
|
||||
| main.rs:236:9:236:22 | &... [&ref] | main.rs:235:38:237:5 | { ... } [&ref] | provenance | |
|
||||
| main.rs:236:10:236:22 | ... .value | main.rs:236:9:236:22 | &... [&ref] | provenance | |
|
||||
| main.rs:236:11:236:15 | * ... [MyInt] | main.rs:236:10:236:22 | ... .value | provenance | |
|
||||
| main.rs:236:12:236:15 | self [&ref, MyInt] | main.rs:236:11:236:15 | * ... [MyInt] | provenance | |
|
||||
| main.rs:242:9:242:9 | a [MyInt] | main.rs:244:13:244:13 | a [MyInt] | provenance | |
|
||||
| main.rs:242:13:242:38 | MyInt {...} [MyInt] | main.rs:242:9:242:9 | a [MyInt] | provenance | |
|
||||
| main.rs:242:28:242:36 | source(...) | main.rs:242:13:242:38 | MyInt {...} [MyInt] | provenance | |
|
||||
@@ -140,6 +145,15 @@ edges
|
||||
| main.rs:261:35:261:35 | b [MyInt] | main.rs:227:30:227:39 | ...: MyInt [MyInt] | provenance | |
|
||||
| main.rs:261:35:261:35 | b [MyInt] | main.rs:261:27:261:32 | [post] &mut a [&ref, MyInt] | provenance | |
|
||||
| main.rs:262:10:262:10 | a [MyInt] | main.rs:262:10:262:16 | a.value | provenance | |
|
||||
| main.rs:270:9:270:9 | a [MyInt] | main.rs:272:28:272:28 | a [MyInt] | provenance | |
|
||||
| main.rs:270:13:270:39 | MyInt {...} [MyInt] | main.rs:270:9:270:9 | a [MyInt] | provenance | |
|
||||
| main.rs:270:28:270:37 | source(...) | main.rs:270:13:270:39 | MyInt {...} [MyInt] | provenance | |
|
||||
| main.rs:272:9:272:9 | c | main.rs:273:10:273:10 | c | provenance | |
|
||||
| main.rs:272:13:272:29 | * ... | main.rs:272:9:272:9 | c | provenance | |
|
||||
| main.rs:272:14:272:29 | ...::deref(...) [&ref] | main.rs:272:13:272:29 | * ... | provenance | |
|
||||
| main.rs:272:27:272:28 | &a [&ref, MyInt] | main.rs:235:14:235:18 | SelfParam [&ref, MyInt] | provenance | |
|
||||
| main.rs:272:27:272:28 | &a [&ref, MyInt] | main.rs:272:14:272:29 | ...::deref(...) [&ref] | provenance | |
|
||||
| main.rs:272:28:272:28 | a [MyInt] | main.rs:272:27:272:28 | &a [&ref, MyInt] | provenance | |
|
||||
| main.rs:289:18:289:21 | SelfParam [MyInt] | main.rs:289:48:291:5 | { ... } [MyInt] | provenance | |
|
||||
| main.rs:293:26:293:37 | ...: MyInt [MyInt] | main.rs:293:49:295:5 | { ... } [MyInt] | provenance | |
|
||||
| main.rs:299:9:299:9 | a [MyInt] | main.rs:301:50:301:50 | a [MyInt] | provenance | |
|
||||
@@ -297,6 +311,12 @@ nodes
|
||||
| main.rs:228:11:228:14 | [post] self [&ref, MyInt] | semmle.label | [post] self [&ref, MyInt] |
|
||||
| main.rs:228:25:228:27 | rhs [MyInt] | semmle.label | rhs [MyInt] |
|
||||
| main.rs:228:25:228:33 | rhs.value | semmle.label | rhs.value |
|
||||
| main.rs:235:14:235:18 | SelfParam [&ref, MyInt] | semmle.label | SelfParam [&ref, MyInt] |
|
||||
| main.rs:235:38:237:5 | { ... } [&ref] | semmle.label | { ... } [&ref] |
|
||||
| main.rs:236:9:236:22 | &... [&ref] | semmle.label | &... [&ref] |
|
||||
| main.rs:236:10:236:22 | ... .value | semmle.label | ... .value |
|
||||
| main.rs:236:11:236:15 | * ... [MyInt] | semmle.label | * ... [MyInt] |
|
||||
| main.rs:236:12:236:15 | self [&ref, MyInt] | semmle.label | self [&ref, MyInt] |
|
||||
| main.rs:242:9:242:9 | a [MyInt] | semmle.label | a [MyInt] |
|
||||
| main.rs:242:13:242:38 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] |
|
||||
| main.rs:242:28:242:36 | source(...) | semmle.label | source(...) |
|
||||
@@ -320,6 +340,15 @@ nodes
|
||||
| main.rs:261:35:261:35 | b [MyInt] | semmle.label | b [MyInt] |
|
||||
| main.rs:262:10:262:10 | a [MyInt] | semmle.label | a [MyInt] |
|
||||
| main.rs:262:10:262:16 | a.value | semmle.label | a.value |
|
||||
| main.rs:270:9:270:9 | a [MyInt] | semmle.label | a [MyInt] |
|
||||
| main.rs:270:13:270:39 | MyInt {...} [MyInt] | semmle.label | MyInt {...} [MyInt] |
|
||||
| main.rs:270:28:270:37 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:272:9:272:9 | c | semmle.label | c |
|
||||
| main.rs:272:13:272:29 | * ... | semmle.label | * ... |
|
||||
| main.rs:272:14:272:29 | ...::deref(...) [&ref] | semmle.label | ...::deref(...) [&ref] |
|
||||
| main.rs:272:27:272:28 | &a [&ref, MyInt] | semmle.label | &a [&ref, MyInt] |
|
||||
| main.rs:272:28:272:28 | a [MyInt] | semmle.label | a [MyInt] |
|
||||
| main.rs:273:10:273:10 | c | semmle.label | c |
|
||||
| main.rs:289:18:289:21 | SelfParam [MyInt] | semmle.label | SelfParam [MyInt] |
|
||||
| main.rs:289:48:291:5 | { ... } [MyInt] | semmle.label | { ... } [MyInt] |
|
||||
| main.rs:293:26:293:37 | ...: MyInt [MyInt] | semmle.label | ...: MyInt [MyInt] |
|
||||
@@ -367,6 +396,7 @@ subpaths
|
||||
| main.rs:244:13:244:13 | a [MyInt] | main.rs:220:12:220:15 | SelfParam [MyInt] | main.rs:220:42:223:5 | { ... } [MyInt] | main.rs:244:13:244:17 | ... + ... [MyInt] |
|
||||
| main.rs:252:9:252:9 | a [MyInt] | main.rs:220:12:220:15 | SelfParam [MyInt] | main.rs:220:42:223:5 | { ... } [MyInt] | main.rs:254:13:254:20 | a.add(...) [MyInt] |
|
||||
| main.rs:261:35:261:35 | b [MyInt] | main.rs:227:30:227:39 | ...: MyInt [MyInt] | main.rs:227:19:227:27 | SelfParam [Return] [&ref, MyInt] | main.rs:261:27:261:32 | [post] &mut a [&ref, MyInt] |
|
||||
| main.rs:272:27:272:28 | &a [&ref, MyInt] | main.rs:235:14:235:18 | SelfParam [&ref, MyInt] | main.rs:235:38:237:5 | { ... } [&ref] | main.rs:272:14:272:29 | ...::deref(...) [&ref] |
|
||||
| main.rs:301:50:301:50 | a [MyInt] | main.rs:289:18:289:21 | SelfParam [MyInt] | main.rs:289:48:291:5 | { ... } [MyInt] | main.rs:301:30:301:54 | ...::take_self(...) [MyInt] |
|
||||
| main.rs:306:55:306:55 | b [MyInt] | main.rs:293:26:293:37 | ...: MyInt [MyInt] | main.rs:293:49:295:5 | { ... } [MyInt] | main.rs:306:30:306:56 | ...::take_second(...) [MyInt] |
|
||||
testFailures
|
||||
@@ -393,6 +423,7 @@ testFailures
|
||||
| main.rs:245:10:245:16 | c.value | main.rs:242:28:242:36 | source(...) | main.rs:245:10:245:16 | c.value | $@ | main.rs:242:28:242:36 | source(...) | source(...) |
|
||||
| main.rs:255:10:255:16 | d.value | main.rs:252:28:252:36 | source(...) | main.rs:255:10:255:16 | d.value | $@ | main.rs:252:28:252:36 | source(...) | source(...) |
|
||||
| main.rs:262:10:262:16 | a.value | main.rs:259:28:259:37 | source(...) | main.rs:262:10:262:16 | a.value | $@ | main.rs:259:28:259:37 | source(...) | source(...) |
|
||||
| main.rs:273:10:273:10 | c | main.rs:270:28:270:37 | source(...) | main.rs:273:10:273:10 | c | $@ | main.rs:270:28:270:37 | source(...) | source(...) |
|
||||
| main.rs:302:10:302:10 | c | main.rs:299:28:299:36 | source(...) | main.rs:302:10:302:10 | c | $@ | main.rs:299:28:299:36 | source(...) | source(...) |
|
||||
| main.rs:307:10:307:10 | c | main.rs:305:28:305:37 | source(...) | main.rs:307:10:307:10 | c | $@ | main.rs:305:28:305:37 | source(...) | source(...) |
|
||||
| main.rs:317:10:317:10 | a | main.rs:316:13:316:21 | source(...) | main.rs:317:10:317:10 | a | $@ | main.rs:316:13:316:21 | source(...) | source(...) |
|
||||
|
||||
@@ -270,7 +270,7 @@ fn test_operator_overloading() {
|
||||
let a = MyInt { value: source(27) };
|
||||
// The line below is what the prefix `*` desugars to.
|
||||
let c = *Deref::deref(&a);
|
||||
sink(c); // $ MISSING: hasValueFlow=27
|
||||
sink(c); // $ hasValueFlow=27
|
||||
|
||||
let a = MyInt { value: source(28) };
|
||||
let c = *a;
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
| main.rs:266:5:266:10 | ... *= ... | main.rs:227:5:229:5 | fn mul_assign |
|
||||
| main.rs:267:5:267:17 | sink(...) | main.rs:5:1:7:1 | fn sink |
|
||||
| main.rs:270:28:270:37 | source(...) | main.rs:1:1:3:1 | fn source |
|
||||
| main.rs:272:14:272:29 | ...::deref(...) | main.rs:235:5:237:5 | fn deref |
|
||||
| main.rs:273:5:273:11 | sink(...) | main.rs:5:1:7:1 | fn sink |
|
||||
| main.rs:275:28:275:37 | source(...) | main.rs:1:1:3:1 | fn source |
|
||||
| main.rs:276:13:276:14 | * ... | main.rs:235:5:237:5 | fn deref |
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
multipleCallTargets
|
||||
| main.rs:532:10:532:21 | ...::from(...) |
|
||||
| main.rs:538:10:538:21 | ...::from(...) |
|
||||
@@ -529,7 +529,7 @@ fn conversions() {
|
||||
|
||||
sink(a as i64); // $ hasTaintFlow=50
|
||||
sink(a.into()); // $ MISSING: hasValueFlow=50
|
||||
sink(i64::from(a)); // $ hasTaintFlow=50
|
||||
sink(i64::from(a)); // $ MISSING: hasTaintFlow=50 -- we cannot resolve the `impl<T> From<T> for T` implementation
|
||||
|
||||
let b: i32 = source(51) as i32;
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ multipleCallTargets
|
||||
| test.rs:737:30:737:43 | ...::_print(...) |
|
||||
| test.rs:752:14:752:43 | ...::_print(...) |
|
||||
| test.rs:766:14:766:34 | ...::_print(...) |
|
||||
| test.rs:777:23:777:80 | ...::try_from(...) |
|
||||
| test.rs:806:50:806:66 | ...::from(...) |
|
||||
| test.rs:806:50:806:66 | ...::from(...) |
|
||||
| test.rs:808:14:808:31 | ...::_print(...) |
|
||||
@@ -74,14 +73,11 @@ multipleCallTargets
|
||||
| test.rs:883:14:883:29 | ...::_print(...) |
|
||||
| test.rs:885:27:885:36 | ...::_print(...) |
|
||||
| test.rs:886:28:886:41 | ...::_print(...) |
|
||||
| test_futures_io.rs:25:23:25:80 | ...::try_from(...) |
|
||||
| test_futures_io.rs:35:26:35:63 | pinned.poll_read(...) |
|
||||
| test_futures_io.rs:62:22:62:50 | pinned.poll_fill_buf(...) |
|
||||
| test_futures_io.rs:69:23:69:67 | ... .poll_fill_buf(...) |
|
||||
| test_futures_io.rs:93:26:93:63 | pinned.poll_read(...) |
|
||||
| test_futures_io.rs:116:22:116:50 | pinned.poll_fill_buf(...) |
|
||||
| test_futures_io.rs:145:26:145:49 | ...::with_capacity(...) |
|
||||
| web_frameworks.rs:40:5:40:26 | ...::write_str(...) |
|
||||
| web_frameworks.rs:40:5:40:26 | ...::write_str(...) |
|
||||
| web_frameworks.rs:101:14:101:23 | a.as_str() |
|
||||
| web_frameworks.rs:102:14:102:25 | a.as_bytes() |
|
||||
|
||||
@@ -42,8 +42,8 @@ async fn test_futures_rustls_futures_io() -> io::Result<()> {
|
||||
{
|
||||
// using the `AsyncReadExt::read` extension method (higher-level)
|
||||
let mut buffer1 = [0u8; 64];
|
||||
let bytes_read1 = futures::io::AsyncReadExt::read(&mut reader, &mut buffer1).await?;
|
||||
sink(&buffer1[..bytes_read1]); // $ hasTaintFlow=url
|
||||
let bytes_read1 = futures::io::AsyncReadExt::read(&mut reader, &mut buffer1).await?; // we cannot resolve the `read` call, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer1[..bytes_read1]); // $ MISSING: hasTaintFlow=url
|
||||
|
||||
let mut buffer2 = [0u8; 64];
|
||||
let bytes_read2 = reader.read(&mut buffer2).await?; // we cannot resolve the `read` call, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
@@ -100,8 +100,8 @@ async fn test_futures_rustls_futures_io() -> io::Result<()> {
|
||||
{
|
||||
// using the `AsyncReadExt::read` extension method (higher-level)
|
||||
let mut buffer1 = [0u8; 64];
|
||||
let bytes_read1 = futures::io::AsyncReadExt::read(&mut reader2, &mut buffer1).await?;
|
||||
sink(&buffer1[..bytes_read1]); // $ hasTaintFlow=url
|
||||
let bytes_read1 = futures::io::AsyncReadExt::read(&mut reader2, &mut buffer1).await?; // we cannot resolve the `read` call, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer1[..bytes_read1]); // $ MISSING: hasTaintFlow=url
|
||||
|
||||
let mut buffer2 = [0u8; 64];
|
||||
let bytes_read2 = reader2.read(&mut buffer2).await?; // we cannot resolve the `read` call, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
multipleCallTargets
|
||||
| main.rs:118:9:118:11 | f(...) |
|
||||
| proc_macro.rs:6:16:6:59 | ...::from(...) |
|
||||
| proc_macro.rs:7:19:7:62 | ...::from(...) |
|
||||
| proc_macro.rs:9:5:11:5 | ...::new(...) |
|
||||
| proc_macro.rs:10:10:10:12 | ...::to_tokens(...) |
|
||||
multiplePathResolutions
|
||||
| main.rs:626:3:626:12 | proc_macro |
|
||||
| main.rs:632:7:632:16 | proc_macro |
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
multipleCallTargets
|
||||
| dereference.rs:61:15:61:24 | e1.deref() |
|
||||
| main.rs:2096:13:2096:31 | ...::from(...) |
|
||||
| main.rs:2097:13:2097:31 | ...::from(...) |
|
||||
| main.rs:2098:13:2098:31 | ...::from(...) |
|
||||
| main.rs:2104:13:2104:31 | ...::from(...) |
|
||||
| main.rs:2105:13:2105:31 | ...::from(...) |
|
||||
| main.rs:2106:13:2106:31 | ...::from(...) |
|
||||
| main.rs:2142:21:2142:43 | ...::from(...) |
|
||||
| main.rs:2186:13:2186:31 | ...::from(...) |
|
||||
| main.rs:2187:13:2187:31 | ...::from(...) |
|
||||
| main.rs:2188:13:2188:31 | ...::from(...) |
|
||||
| main.rs:2194:13:2194:31 | ...::from(...) |
|
||||
| main.rs:2195:13:2195:31 | ...::from(...) |
|
||||
| main.rs:2196:13:2196:31 | ...::from(...) |
|
||||
|
||||
@@ -2042,6 +2042,80 @@ mod method_determined_by_argument_type {
|
||||
}
|
||||
}
|
||||
|
||||
trait MyFrom<T> {
|
||||
// MyFrom::my_from
|
||||
fn my_from(value: T) -> Self;
|
||||
}
|
||||
|
||||
impl MyFrom<i64> for i64 {
|
||||
// MyFrom<i64>::my_from
|
||||
fn my_from(value: i64) -> Self {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
impl MyFrom<bool> for i64 {
|
||||
// MyFrom<bool>::my_from
|
||||
fn my_from(value: bool) -> Self {
|
||||
if value { 1 } else { 0 }
|
||||
}
|
||||
}
|
||||
|
||||
trait MyFrom2<T> {
|
||||
// MyFrom2::my_from2
|
||||
fn my_from2(value: T, x: Self) -> ();
|
||||
}
|
||||
|
||||
impl MyFrom2<i64> for i64 {
|
||||
// MyFrom2<i64>::my_from2
|
||||
fn my_from2(value: i64, _: Self) -> () {
|
||||
value;
|
||||
}
|
||||
}
|
||||
|
||||
impl MyFrom2<bool> for i64 {
|
||||
// MyFrom2<bool>::my_from2
|
||||
fn my_from2(value: bool, _: Self) -> () {
|
||||
if value {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
trait MySelfTrait {
|
||||
// MySelfTrait::f1
|
||||
fn f1(x: Self) -> i64;
|
||||
|
||||
// MySelfTrait::f2
|
||||
fn f2(x: Self) -> Self;
|
||||
}
|
||||
|
||||
impl MySelfTrait for i64 {
|
||||
// MySelfTrait<i64>::f1
|
||||
fn f1(x: Self) -> i64 {
|
||||
x + 1
|
||||
}
|
||||
|
||||
// MySelfTrait<i64>::f2
|
||||
fn f2(x: Self) -> Self {
|
||||
x + 1
|
||||
}
|
||||
}
|
||||
|
||||
impl MySelfTrait for bool {
|
||||
// MySelfTrait<bool>::f1
|
||||
fn f1(x: Self) -> i64 {
|
||||
0
|
||||
}
|
||||
|
||||
// MySelfTrait<bool>::f2
|
||||
fn f2(x: Self) -> Self {
|
||||
x
|
||||
}
|
||||
}
|
||||
|
||||
pub fn f() {
|
||||
let x: i64 = 73;
|
||||
x.my_add(5i64); // $ method=MyAdd<i64>::my_add
|
||||
@@ -2051,6 +2125,22 @@ mod method_determined_by_argument_type {
|
||||
S(1i64).my_add(S(2i64)); // $ method=S::my_add1
|
||||
S(1i64).my_add(3i64); // $ MISSING: method=S::my_add2
|
||||
S(1i64).my_add(&3i64); // $ method=S::my_add3
|
||||
|
||||
let x = i64::my_from(73i64); // $ method=MyFrom<i64>::my_from
|
||||
let y = i64::my_from(true); // $ method=MyFrom<bool>::my_from
|
||||
let z: i64 = MyFrom::my_from(73i64); // $ method=MyFrom<i64>::my_from
|
||||
i64::my_from2(73i64, 0i64); // $ method=MyFrom2<i64>::my_from2
|
||||
i64::my_from2(true, 0i64); // $ method=MyFrom2<bool>::my_from2
|
||||
MyFrom2::my_from2(73i64, 0i64); // $ method=MyFrom2<i64>::my_from2
|
||||
|
||||
i64::f1(73i64); // $ method=MySelfTrait<i64>::f1
|
||||
i64::f2(73i64); // $ method=MySelfTrait<i64>::f2
|
||||
bool::f1(true); // $ method=MySelfTrait<bool>::f1
|
||||
bool::f2(true); // $ method=MySelfTrait<bool>::f2
|
||||
MySelfTrait::f1(73i64); // $ method=MySelfTrait<i64>::f1
|
||||
MySelfTrait::f2(73i64); // $ method=MySelfTrait<i64>::f2
|
||||
MySelfTrait::f1(true); // $ method=MySelfTrait<bool>::f1
|
||||
MySelfTrait::f2(true); // $ method=MySelfTrait<bool>::f2
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
||||
multipleCallTargets
|
||||
| src/main.rs:8:21:8:44 | ...::from(...) |
|
||||
| src/main.rs:19:21:19:44 | ...::from(...) |
|
||||
| src/main.rs:25:23:25:59 | ...::from(...) |
|
||||
| src/main.rs:26:38:26:61 | ...::from(...) |
|
||||
| src/main.rs:39:23:39:59 | ...::from(...) |
|
||||
| src/main.rs:40:38:40:61 | ...::from(...) |
|
||||
| src/main.rs:52:23:52:59 | ...::from(...) |
|
||||
| src/main.rs:53:38:53:61 | ...::from(...) |
|
||||
@@ -1,11 +1,11 @@
|
||||
#select
|
||||
| src/main.rs:10:5:10:22 | ...::read_to_string | src/main.rs:6:11:6:19 | file_name | src/main.rs:10:5:10:22 | ...::read_to_string | This path depends on a $@. | src/main.rs:6:11:6:19 | file_name | user-provided value |
|
||||
edges
|
||||
| src/main.rs:6:11:6:19 | file_name | src/main.rs:8:35:8:43 | file_name | provenance | |
|
||||
| src/main.rs:6:11:6:19 | file_name | src/main.rs:8:35:8:53 | file_name as String | provenance | |
|
||||
| src/main.rs:8:9:8:17 | file_path | src/main.rs:10:24:10:32 | file_path | provenance | |
|
||||
| src/main.rs:8:21:8:44 | ...::from(...) | src/main.rs:8:9:8:17 | file_path | provenance | |
|
||||
| src/main.rs:8:35:8:43 | file_name | src/main.rs:8:21:8:44 | ...::from(...) | provenance | MaD:2 |
|
||||
| src/main.rs:8:35:8:43 | file_name | src/main.rs:8:21:8:44 | ...::from(...) | provenance | MaD:2 |
|
||||
| src/main.rs:8:21:8:54 | ...::from(...) | src/main.rs:8:9:8:17 | file_path | provenance | |
|
||||
| src/main.rs:8:35:8:53 | file_name as String | src/main.rs:8:21:8:54 | ...::from(...) | provenance | MaD:2 |
|
||||
| src/main.rs:8:35:8:53 | file_name as String | src/main.rs:8:21:8:54 | ...::from(...) | provenance | MaD:2 |
|
||||
| src/main.rs:10:24:10:32 | file_path | src/main.rs:10:5:10:22 | ...::read_to_string | provenance | MaD:1 Sink:MaD:1 |
|
||||
models
|
||||
| 1 | Sink: std::fs::read_to_string; Argument[0]; path-injection |
|
||||
@@ -13,8 +13,8 @@ models
|
||||
nodes
|
||||
| src/main.rs:6:11:6:19 | file_name | semmle.label | file_name |
|
||||
| src/main.rs:8:9:8:17 | file_path | semmle.label | file_path |
|
||||
| src/main.rs:8:21:8:44 | ...::from(...) | semmle.label | ...::from(...) |
|
||||
| src/main.rs:8:35:8:43 | file_name | semmle.label | file_name |
|
||||
| src/main.rs:8:21:8:54 | ...::from(...) | semmle.label | ...::from(...) |
|
||||
| src/main.rs:8:35:8:53 | file_name as String | semmle.label | file_name as String |
|
||||
| src/main.rs:10:5:10:22 | ...::read_to_string | semmle.label | ...::read_to_string |
|
||||
| src/main.rs:10:24:10:32 | file_path | semmle.label | file_path |
|
||||
subpaths
|
||||
|
||||
@@ -5,8 +5,8 @@ use std::{fs, path::Path, path::PathBuf};
|
||||
fn tainted_path_handler_bad(
|
||||
Query(file_name): Query<String>, // $ Source=remote1
|
||||
) -> Result<String> {
|
||||
let file_path = PathBuf::from(file_name);
|
||||
// BAD: This could read any file on the filesystem.
|
||||
let file_path = PathBuf::from(file_name as String); // TODO: Remove `as String` when type inference handles patterns
|
||||
// BAD: This could read any file on the filesystem.
|
||||
fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink Alert[rust/path-injection]=remote1
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user