Merge branch 'ruby-framework-grape' of github.com:felickz/codeql into ruby-framework-grape

This commit is contained in:
Chad Bentz
2025-09-15 22:11:38 -04:00
53 changed files with 3209 additions and 242 deletions

View File

@@ -1,4 +1,4 @@
---
category: feature
---
* Added predicates `getTransitiveNumberOfVlaDimensionStmts`, `getTransitiveVlaDimensionStmt`, and `getParentVlaDecl` to `VlaDeclStmt` for handling `VlaDeclStmt`s whose base type defined in terms of an other `VlaDeclStmt` via a `typedef`.
* Added predicates `getTransitiveNumberOfVlaDimensionStmts`, `getTransitiveVlaDimensionStmt`, and `getParentVlaDecl` to `VlaDeclStmt` for handling `VlaDeclStmt`s whose base type is defined in terms of another `VlaDeclStmt` via a `typedef`.

View File

@@ -12,7 +12,7 @@
<example>
<p>In this example, we are incrementing/decrementing the current date by one year when creating a new <code>System.DateTime</code> object. This may work most of the time, but on any given February 29th, the resulting value will be invalid.</p>
<sample src="UnsafeYearConstructionBad.cs" />
<p>To fix this bug, we add/substract years to the current date by calling <code>AddYears</code> method on it.</p>
<p>To fix this bug, we add/subtract years to the current date by calling <code>AddYears</code> method on it.</p>
<sample src="UnsafeYearConstructionGood.cs" />
</example>
<references>

View File

@@ -33,6 +33,18 @@ ConditionGuardNode getLengthLEGuard(Variable index, Variable array) {
)
}
/**
* Gets a condition that checks that `index` is less than `array.length`.
*/
ConditionGuardNode getLengthLTGuard(Variable index, Variable array) {
exists(RelationalComparison cmp | cmp instanceof GTExpr or cmp instanceof LTExpr |
cmp = result.getTest() and
result.getOutcome() = true and
cmp.getGreaterOperand() = arrayLen(array) and
cmp.getLesserOperand() = index.getAnAccess()
)
}
/**
* Gets a condition that checks that `index` is not equal to `array.length`.
*/
@@ -62,7 +74,8 @@ where
elementRead(ea, array, index, bb) and
// and the read is guarded by the comparison
cond.dominates(bb) and
// but the read is not guarded by another check that `index != array.length`
not getLengthNEGuard(index, array).dominates(bb)
// but the read is not guarded by another check that `index != array.length` or `index < array.length`
not getLengthNEGuard(index, array).dominates(bb) and
not getLengthLTGuard(index, array).dominates(bb)
select cond.getTest(), "Off-by-one index comparison against length may lead to out-of-bounds $@.",
ea, "read"

View File

@@ -108,7 +108,7 @@ str.replace(/\.\.\//g, "");
</sample>
<p>
The regular expression attempts to strip out all occurences of <code>/../</code> from <code>str</code>.
The regular expression attempts to strip out all occurrences of <code>/../</code> from <code>str</code>.
This will not work as expected: for the string <code>/./.././</code>, for example, it will remove the single
occurrence of <code>/../</code> in the middle, but the remainder of the string then becomes
<code>/../</code>, which is another instance of the substring we were trying to remove.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Query `js/index-out-of-bounds` no longer produces a false-positive when a strictly-less-than check overrides a previous less-than-or-equal test.

View File

@@ -55,3 +55,11 @@ function badContains(a, elt) {
return true;
return false;
}
// OK - incorrect upper bound, but extra check
function badContains2(a, elt) {
for (let i = 0; i <= a.length; ++i)
if (i < a.length && a[i] === elt)
return true;
return false;
}

View File

@@ -136,7 +136,9 @@ private class GrapeParamsCall extends ParamsCallImpl {
this.getParent+() = api.getADeclaration()
)
}
}/**
}
/**
* A call to `headers` from within a Grape API endpoint or headers block.
* Headers can also be a source of user input.
*/

View File

@@ -19,6 +19,7 @@ ql/rust/ql/src/queries/security/CWE-328/WeakSensitiveDataHashing.ql
ql/rust/ql/src/queries/security/CWE-770/UncontrolledAllocationSize.ql
ql/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql
ql/rust/ql/src/queries/security/CWE-825/AccessInvalidPointer.ql
ql/rust/ql/src/queries/security/CWE-918/RequestForgery.ql
ql/rust/ql/src/queries/summary/LinesOfCode.ql
ql/rust/ql/src/queries/summary/LinesOfUserCode.ql
ql/rust/ql/src/queries/summary/NodesWithTypeAtLengthLimit.ql

View File

@@ -22,6 +22,7 @@ ql/rust/ql/src/queries/security/CWE-770/UncontrolledAllocationSize.ql
ql/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql
ql/rust/ql/src/queries/security/CWE-825/AccessAfterLifetime.ql
ql/rust/ql/src/queries/security/CWE-825/AccessInvalidPointer.ql
ql/rust/ql/src/queries/security/CWE-918/RequestForgery.ql
ql/rust/ql/src/queries/summary/LinesOfCode.ql
ql/rust/ql/src/queries/summary/LinesOfUserCode.ql
ql/rust/ql/src/queries/summary/NodesWithTypeAtLengthLimit.ql

View File

@@ -21,6 +21,7 @@ ql/rust/ql/src/queries/security/CWE-770/UncontrolledAllocationSize.ql
ql/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql
ql/rust/ql/src/queries/security/CWE-825/AccessAfterLifetime.ql
ql/rust/ql/src/queries/security/CWE-825/AccessInvalidPointer.ql
ql/rust/ql/src/queries/security/CWE-918/RequestForgery.ql
ql/rust/ql/src/queries/summary/LinesOfCode.ql
ql/rust/ql/src/queries/summary/LinesOfUserCode.ql
ql/rust/ql/src/queries/summary/NodesWithTypeAtLengthLimit.ql

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added cryptography related models for the `cookie` and `biscotti` crates.

View File

@@ -0,0 +1,7 @@
# Models for the `biscotti` crate.
extensions:
- addsTo:
pack: codeql/rust-all
extensible: sinkModel
data:
- ["<biscotti::crypto::master::Key>::from", "Argument[0]", "credentials-key", "manual"]

View File

@@ -0,0 +1,7 @@
# Models for the `cookie` crate.
extensions:
- addsTo:
pack: codeql/rust-all
extensible: sinkModel
data:
- ["<cookie::secure::key::Key>::from", "Argument[0].Reference", "credentials-key", "manual"]

View File

@@ -9,8 +9,8 @@ extensions:
pack: codeql/rust-all
extensible: sinkModel
data:
- ["<reqwest::async_impl::client::Client>::request", "Argument[1]", "transmission", "manual"]
- ["<reqwest::blocking::client::Client>::request", "Argument[1]", "transmission", "manual"]
- ["<reqwest::async_impl::client::Client>::request", "Argument[1]", "request-url", "manual"]
- ["<reqwest::blocking::client::Client>::request", "Argument[1]", "request-url", "manual"]
- addsTo:
pack: codeql/rust-all
extensible: summaryModel

View File

@@ -45,7 +45,6 @@ extensions:
data:
- ["std::fs::canonicalize", "Argument[0].OptionalStep[normalize-path]", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
- ["std::fs::canonicalize", "Argument[0].OptionalBarrier[normalize-path]", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
- ["<std::path::PathBuf as core::convert::From>::from", "Argument[0]", "ReturnValue", "value", "manual"]
- ["<std::path::PathBuf>::as_path", "Argument[Self]", "ReturnValue.Reference", "value", "manual"]
- ["<std::path::PathBuf>::as_mut_os_string", "Argument[Self].Reference", "ReturnValue.Reference", "value", "manual"]
- ["<std::path::PathBuf>::into_os_string", "Argument[Self]", "ReturnValue", "value", "manual"]

View File

@@ -46,4 +46,5 @@ extensions:
- ["<alloc::string::String as alloc::string::ToString>::to_string", "Argument[self]", "ReturnValue", "taint", "manual"]
- ["<core::str>::parse", "Argument[self]", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
- ["<core::str>::trim", "Argument[self]", "ReturnValue.Reference", "taint", "manual"]
- ["<alloc::string::String as core::convert::From>::from", "Argument[0]", "ReturnValue", "value", "manual"]
# Vec
- ["alloc::vec::from_elem", "Argument[0]", "ReturnValue.Element", "value", "manual"]

View File

@@ -11,6 +11,8 @@ extensions:
- ["<_ as core::convert::Into>::into", "Argument[self].Reference.Element", "ReturnValue.Element", "taint", "manual"]
- ["<alloc::string::String as core::convert::Into>::into", "Argument[self].Element", "ReturnValue.Element", "taint", "manual"]
- ["<alloc::string::String as core::convert::Into>::into", "Argument[self].Reference.Element", "ReturnValue.Element", "taint", "manual"]
# From
- ["<_ as core::convert::From>::from", "Argument[0]", "ReturnValue", "value", "manual"]
# Iterator
- ["<core::result::Result>::iter", "Argument[self].Element", "ReturnValue.Element", "value", "manual"]
- ["<alloc::vec::Vec as value_trait::array::Array>::iter", "Argument[self].Element", "ReturnValue.Element", "value", "manual"]

View File

@@ -648,6 +648,18 @@ final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
override Visibility getVisibility() { result = Impl.super.getVisibility() }
TypeParamItemNode getBlanketImplementationTypeParam() {
result = this.resolveSelfTy() and
// This impl block is not superseded by the expansion of an attribute macro.
not exists(super.getAttributeMacroExpansion())
}
/**
* Holds if this impl block is a blanket implementation. That is, the
* implementation targets a generic parameter of the impl block.
*/
predicate isBlanketImplementation() { exists(this.getBlanketImplementationTypeParam()) }
override predicate hasCanonicalPath(Crate c) { this.resolveSelfTy().hasCanonicalPathPrefix(c) }
/**
@@ -1006,6 +1018,14 @@ final class TypeParamItemNode extends TypeItemNode instanceof TypeParam {
Path getABoundPath() { result = this.getTypeBoundAt(_, _).getTypeRepr().(PathTypeRepr).getPath() }
pragma[nomagic]
ItemNode resolveBound(int index) {
result =
rank[index + 1](int i, int j |
|
resolvePath(this.getTypeBoundAt(i, j).getTypeRepr().(PathTypeRepr).getPath()) order by i, j
)
}
ItemNode resolveABound() { result = resolvePath(this.getABoundPath()) }
/**

View File

@@ -1915,6 +1915,10 @@ private predicate methodCandidateTrait(Type type, Trait trait, string name, int
methodCandidate(type, name, arity, impl)
}
/**
* Holds if `mc` has `rootType` as the root type of the receiver and the target
* method is named `name` and has arity `arity`
*/
pragma[nomagic]
private predicate isMethodCall(MethodCall mc, Type rootType, string name, int arity) {
rootType = mc.getTypeAt(TypePath::nil()) and
@@ -2153,6 +2157,130 @@ private predicate methodCallHasImplCandidate(MethodCall mc, Impl impl) {
else any()
}
private module BlanketImplementation {
private ImplItemNode getPotentialDuplicated(
string fileName, string traitName, int arity, string tpName
) {
tpName = result.getBlanketImplementationTypeParam().getName() and
fileName = result.getLocation().getFile().getBaseName() and
traitName = result.resolveTraitTy().getName() and
arity = result.resolveTraitTy().(Trait).getNumberOfGenericParams()
}
private predicate duplicatedImpl(Impl impl1, Impl impl2) {
exists(string fileName, string traitName, int arity, string tpName |
impl1 = getPotentialDuplicated(fileName, traitName, arity, tpName) and
impl2 = getPotentialDuplicated(fileName, traitName, arity, tpName) and
impl1.getLocation().getFile().getAbsolutePath() <
impl2.getLocation().getFile().getAbsolutePath()
)
}
/**
* Holds if `impl` is a canonical blanket implementation.
*
* Libraries can often occur several times in the database for different
* library versions. This causes the same blanket implementations to exist
* multiple times, and these add no useful information.
*
* We detect these duplicates based on some simple heuristics (same trait
* name, file name, etc.). For these duplicates we select the one with the
* greatest file name (which usually is also the one with the greatest library
* version in the path) as the "canonical" implementation.
*/
private predicate isCanonicalImpl(Impl impl) {
not duplicatedImpl(impl, _) and impl.(ImplItemNode).isBlanketImplementation()
}
/**
* Holds if `impl` is a blanket implementation for a type parameter and
* `traitBound` is the first non-trivial trait bound of that type parameter.
*/
private predicate blanketImplementationTraitBound(ImplItemNode impl, Trait traitBound) {
traitBound =
min(Trait trait, int i |
trait = impl.getBlanketImplementationTypeParam().resolveBound(i) and
// Exclude traits that are known to not narrow things down very much.
not trait.getName().getText() =
[
"Sized", "Clone",
// The auto traits
"Send", "Sync", "Unpin", "UnwindSafe", "RefUnwindSafe"
]
|
trait order by i
)
}
/**
* Holds if `impl` is a relevant blanket implementation that requires the
* trait `traitBound` and provides `f`, a method with name `name` and arity
* `arity`.
*/
private predicate blanketImplementationMethod(
ImplItemNode impl, Trait traitBound, string name, int arity, Function f
) {
isCanonicalImpl(impl) and
blanketImplementationTraitBound(impl, traitBound) and
f.getParamList().hasSelfParam() and
arity = f.getParamList().getNumberOfParams() and
(
f = impl.getAssocItem(name)
or
// If the trait has a method with a default implementation, then that
// target is interesting as well.
not exists(impl.getAssocItem(name)) and
f = impl.resolveTraitTy().getAssocItem(name)
) and
// If the method is already available through one of the trait bounds on the
// type parameter (because they implement the trait targeted by the impl
// block) then ignore it.
not impl.getBlanketImplementationTypeParam().resolveABound().(TraitItemNode).getASuccessor(name) =
f
}
pragma[nomagic]
predicate methodCallMatchesBlanketImpl(
MethodCall mc, Type t, ImplItemNode impl, Trait traitBound, Trait traitImpl, Function f
) {
// Only check method calls where we have ruled out inherent method targets.
// Ideally we would also check if non-blanket method targets have been ruled
// out.
methodCallHasNoInherentTarget(mc) and
exists(string name, int arity |
isMethodCall(mc, t, name, arity) and
blanketImplementationMethod(impl, traitBound, name, arity, f)
) and
traitImpl = impl.resolveTraitTy()
}
private predicate relevantTraitVisible(Element mc, Trait trait) {
methodCallMatchesBlanketImpl(mc, _, _, _, trait, _)
}
module SatisfiesConstraintInput implements SatisfiesConstraintInputSig<MethodCall> {
pragma[nomagic]
predicate relevantConstraint(MethodCall mc, Type constraint) {
exists(Trait traitBound, Trait traitImpl |
methodCallMatchesBlanketImpl(mc, _, _, traitBound, traitImpl, _) and
TraitIsVisible<relevantTraitVisible/2>::traitIsVisible(mc, traitImpl) and
traitBound = constraint.(TraitType).getTrait()
)
}
predicate useUniversalConditions() { none() }
}
predicate hasBlanketImpl(MethodCall mc, Type t, Impl impl, Trait traitBound, Function f) {
SatisfiesConstraint<MethodCall, SatisfiesConstraintInput>::satisfiesConstraintType(mc,
TTrait(traitBound), _, _) and
methodCallMatchesBlanketImpl(mc, t, impl, traitBound, _, f)
}
pragma[nomagic]
Function getMethodFromBlanketImpl(MethodCall mc) { hasBlanketImpl(mc, _, _, _, result) }
}
/** Gets a method from an `impl` block that matches the method call `mc`. */
pragma[nomagic]
private Function getMethodFromImpl(MethodCall mc) {
@@ -2188,6 +2316,8 @@ private Function resolveMethodCallTarget(MethodCall mc) {
// The method comes from an `impl` block targeting the type of the receiver.
result = getMethodFromImpl(mc)
or
result = BlanketImplementation::getMethodFromBlanketImpl(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())

View File

@@ -53,6 +53,6 @@ module CleartextTransmission {
* A sink defined through MaD.
*/
private class ModelsAsDataSink extends Sink {
ModelsAsDataSink() { sinkNode(this, "transmission") }
ModelsAsDataSink() { sinkNode(this, ["transmission", "request-url"]) }
}
}

View File

@@ -0,0 +1,49 @@
/**
* Provides classes and predicates for reasoning about request forgery
* vulnerabilities.
*/
import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.dataflow.FlowSource
private import codeql.rust.Concepts
/**
* Provides default sources, sinks and barriers for detecting request forgery
* vulnerabilities, as well as extension points for adding your own.
*/
module RequestForgery {
/**
* A data flow source for request forgery vulnerabilities.
*/
abstract class Source extends DataFlow::Node { }
/**
* A data flow sink for request forgery vulnerabilities.
*/
abstract class Sink extends QuerySink::Range {
/**
* Gets the name of a part of the request that may be tainted by this sink,
* such as the URL or the host.
*/
override string getSinkType() { result = "RequestForgery" }
}
/**
* A barrier for request forgery vulnerabilities.
*/
abstract class Barrier extends DataFlow::Node { }
/**
* An active threat-model source, considered as a flow source.
*/
private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { }
/**
* A sink for request forgery from model data.
*/
private class ModelsAsDataSink extends Sink {
ModelsAsDataSink() { sinkNode(this, "request-url") }
}
}

View File

@@ -424,21 +424,21 @@ extensions:
pack: codeql/rust-all
extensible: sinkModel
data:
- ["<reqwest::async_impl::client::Client>::delete", "Argument[0]", "transmission", "df-generated"]
- ["<reqwest::async_impl::client::Client>::get", "Argument[0]", "transmission", "df-generated"]
- ["<reqwest::async_impl::client::Client>::head", "Argument[0]", "transmission", "df-generated"]
- ["<reqwest::async_impl::client::Client>::patch", "Argument[0]", "transmission", "df-generated"]
- ["<reqwest::async_impl::client::Client>::post", "Argument[0]", "transmission", "df-generated"]
- ["<reqwest::async_impl::client::Client>::put", "Argument[0]", "transmission", "df-generated"]
- ["<reqwest::async_impl::client::Client>::delete", "Argument[0]", "request-url", "df-generated"]
- ["<reqwest::async_impl::client::Client>::get", "Argument[0]", "request-url", "df-generated"]
- ["<reqwest::async_impl::client::Client>::head", "Argument[0]", "request-url", "df-generated"]
- ["<reqwest::async_impl::client::Client>::patch", "Argument[0]", "request-url", "df-generated"]
- ["<reqwest::async_impl::client::Client>::post", "Argument[0]", "request-url", "df-generated"]
- ["<reqwest::async_impl::client::Client>::put", "Argument[0]", "request-url", "df-generated"]
- ["<reqwest::async_impl::multipart::Form>::into_stream", "Argument[self]", "log-injection", "df-generated"]
- ["<reqwest::async_impl::multipart::Form>::stream", "Argument[self]", "log-injection", "df-generated"]
- ["<reqwest::async_impl::request::RequestBuilder>::multipart", "Argument[0]", "log-injection", "df-generated"]
- ["<reqwest::blocking::client::Client>::delete", "Argument[0]", "transmission", "df-generated"]
- ["<reqwest::blocking::client::Client>::get", "Argument[0]", "transmission", "df-generated"]
- ["<reqwest::blocking::client::Client>::head", "Argument[0]", "transmission", "df-generated"]
- ["<reqwest::blocking::client::Client>::patch", "Argument[0]", "transmission", "df-generated"]
- ["<reqwest::blocking::client::Client>::post", "Argument[0]", "transmission", "df-generated"]
- ["<reqwest::blocking::client::Client>::put", "Argument[0]", "transmission", "df-generated"]
- ["<reqwest::blocking::client::Client>::delete", "Argument[0]", "request-url", "df-generated"]
- ["<reqwest::blocking::client::Client>::get", "Argument[0]", "request-url", "df-generated"]
- ["<reqwest::blocking::client::Client>::head", "Argument[0]", "request-url", "df-generated"]
- ["<reqwest::blocking::client::Client>::patch", "Argument[0]", "request-url", "df-generated"]
- ["<reqwest::blocking::client::Client>::post", "Argument[0]", "request-url", "df-generated"]
- ["<reqwest::blocking::client::Client>::put", "Argument[0]", "request-url", "df-generated"]
- ["<reqwest::blocking::multipart::Form>::into_reader", "Argument[self]", "log-injection", "df-generated"]
- ["<reqwest::blocking::multipart::Form>::reader", "Argument[self]", "log-injection", "df-generated"]
- ["<reqwest::blocking::multipart::Reader as std::io::Read>::read", "Argument[self]", "log-injection", "df-generated"]
@@ -450,9 +450,9 @@ extensions:
- ["<reqwest::blocking::response::Response>::text_with_charset", "Argument[self]", "pointer-access", "df-generated"]
- ["<reqwest::connect::ConnectorService as tower_service::Service>::call", "Argument[0]", "log-injection", "df-generated"]
- ["<reqwest::error::Error>::new", "Argument[1]", "pointer-access", "df-generated"]
- ["reqwest::blocking::get", "Argument[0]", "transmission", "df-generated"]
- ["reqwest::blocking::get", "Argument[0]", "request-url", "df-generated"]
- ["reqwest::blocking::wait::timeout", "Argument[1]", "pointer-access", "df-generated"]
- ["reqwest::get", "Argument[0]", "transmission", "df-generated"]
- ["reqwest::get", "Argument[0]", "request-url", "df-generated"]
- addsTo:
pack: codeql/rust-all
extensible: sourceModel

View File

@@ -0,0 +1,4 @@
---
category: newQuery
---
* Added a new query, `rust/request-forgery`, for detecting server-side request forgery vulnerabilities.

View File

@@ -0,0 +1,48 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Directly incorporating user input into an HTTP request without validating the
input can facilitate server-side request forgery (SSRF) attacks. In these
attacks, the server may be tricked into making a request to an unintended API
endpoint or resource.
If the server is connected to an internal network, attackers can bypass security
boundaries to target internal services.
Forged requests can execute unintended actions, leak data if redirected to an
external server, or compromise the server if responses are handled insecurely.
</p>
</overview>
<recommendation>
<p>
To guard against SSRF attacks, you should avoid putting user-provided input
directly into a request URL. Instead, maintain a list of authorized URLs on the
server; then choose from that list based on the input provided. Alternatively,
ensure requests constructed from user input are limited to a particular host or
a more restrictive URL prefix.
</p>
</recommendation>
<example>
<p>
The following example shows an HTTP request parameter being used directly to
form a new request without validating the input, which facilitates SSRF attacks.
It also shows how to remedy the problem by validating the user input against a
known fixed string.
</p>
<sample src="RequestForgery.rs" />
</example>
<references>
<li>
<a href="https://owasp.org/www-community/attacks/Server_Side_Request_Forgery">OWASP Server Side Request Forgery</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,38 @@
/**
* @name Server-side request forgery
* @description Making a network request with user-controlled data in the URL allows for request forgery attacks.
* @kind path-problem
* @problem.severity error
* @security-severity 9.1
* @precision high
* @id rust/request-forgery
* @tags security
* external/cwe/cwe-918
*/
private import rust
private import codeql.rust.dataflow.TaintTracking
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.security.RequestForgeryExtensions
/**
* A taint-tracking configuration for detecting request forgery vulnerabilities.
*/
module RequestForgeryConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RequestForgery::Source }
predicate isSink(DataFlow::Node sink) { sink instanceof RequestForgery::Sink }
predicate isBarrier(DataFlow::Node barrier) { barrier instanceof RequestForgery::Barrier }
predicate observeDiffInformedIncrementalMode() { any() }
}
module RequestForgeryFlow = TaintTracking::Global<RequestForgeryConfig>;
import RequestForgeryFlow::PathGraph
from RequestForgeryFlow::PathNode source, RequestForgeryFlow::PathNode sink
where RequestForgeryFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "The URL of this request depends on a $@.", source.getNode(),
"user-provided value"

View File

@@ -0,0 +1,39 @@
// BAD: Endpoint handler that makes requests based on user input
async fn vulnerable_endpoint_handler(req: Request) -> Result<Response> {
// This request is vulnerable to SSRF attacks as the user controls the
// entire URL
let response = reqwest::get(&req.user_url).await;
match response {
Ok(resp) => {
let body = resp.text().await.unwrap_or_default();
Ok(Response {
message: "Success".to_string(),
data: body,
})
}
Err(_) => Err("Request failed")
}
}
// GOOD: Validate user input against an allowlist
async fn secure_endpoint_handler(req: Request) -> Result<Response> {
// Allow list of specific, known-safe URLs
let allowed_hosts = ["api.example.com", "trusted-service.com"];
if !allowed_hosts.contains(&req.user_url) {
return Err("Untrusted domain");
}
// This request is safe as the user input has been validated
let response = reqwest::get(&req.user_url).await;
match response {
Ok(resp) => {
let body = resp.text().await.unwrap_or_default();
Ok(Response {
message: "Success".to_string(),
data: body,
})
}
Err(_) => Err("Request failed")
}
}

View File

@@ -22,6 +22,7 @@ private import codeql.rust.security.AccessInvalidPointerExtensions
private import codeql.rust.security.CleartextLoggingExtensions
private import codeql.rust.security.CleartextStorageDatabaseExtensions
private import codeql.rust.security.CleartextTransmissionExtensions
private import codeql.rust.security.RequestForgeryExtensions
private import codeql.rust.security.LogInjectionExtensions
private import codeql.rust.security.SqlInjectionExtensions
private import codeql.rust.security.TaintedPathExtensions

View File

@@ -1005,12 +1005,15 @@ readStep
| main.rs:458:5:458:11 | mut_arr | file://:0:0:0:0 | element | main.rs:458:5:458:14 | mut_arr[1] |
| main.rs:459:13:459:19 | mut_arr | file://:0:0:0:0 | element | main.rs:459:13:459:22 | mut_arr[1] |
| main.rs:461:10:461:16 | mut_arr | file://:0:0:0:0 | element | main.rs:461:10:461:19 | mut_arr[0] |
| main.rs:467:24:467:33 | [post] receiver for source(...) | file://:0:0:0:0 | &ref | main.rs:467:24:467:33 | [post] source(...) |
| main.rs:468:9:468:20 | TuplePat | file://:0:0:0:0 | tuple.0 | main.rs:468:10:468:13 | cond |
| main.rs:468:9:468:20 | TuplePat | file://:0:0:0:0 | tuple.1 | main.rs:468:16:468:19 | name |
| main.rs:468:25:468:29 | names | file://:0:0:0:0 | element | main.rs:468:9:468:20 | TuplePat |
| main.rs:470:41:470:67 | [post] \|...\| ... | main.rs:467:9:467:20 | captured default_name | main.rs:470:41:470:67 | [post] default_name |
| main.rs:470:44:470:55 | [post] receiver for default_name | file://:0:0:0:0 | &ref | main.rs:470:44:470:55 | [post] default_name |
| main.rs:470:44:470:55 | this | main.rs:467:9:467:20 | captured default_name | main.rs:470:44:470:55 | default_name |
| main.rs:471:18:471:18 | [post] receiver for n | file://:0:0:0:0 | &ref | main.rs:471:18:471:18 | [post] n |
| main.rs:494:13:494:13 | [post] receiver for a | file://:0:0:0:0 | &ref | main.rs:494:13:494:13 | [post] a |
| main.rs:495:13:495:13 | [post] receiver for b | file://:0:0:0:0 | &ref | main.rs:495:13:495:13 | [post] b |
| main.rs:496:18:496:18 | [post] receiver for b | file://:0:0:0:0 | &ref | main.rs:496:18:496:18 | [post] b |
| main.rs:507:10:507:11 | vs | file://:0:0:0:0 | element | main.rs:507:10:507:14 | vs[0] |
@@ -1110,8 +1113,11 @@ storeStep
| main.rs:455:27:455:27 | 2 | file://:0:0:0:0 | element | main.rs:455:23:455:31 | [...] |
| main.rs:455:30:455:30 | 3 | file://:0:0:0:0 | element | main.rs:455:23:455:31 | [...] |
| main.rs:458:18:458:27 | source(...) | file://:0:0:0:0 | element | main.rs:458:5:458:11 | [post] mut_arr |
| main.rs:467:24:467:33 | source(...) | file://:0:0:0:0 | &ref | main.rs:467:24:467:33 | receiver for source(...) |
| main.rs:470:41:470:67 | default_name | main.rs:467:9:467:20 | captured default_name | main.rs:470:41:470:67 | \|...\| ... |
| main.rs:470:44:470:55 | default_name | file://:0:0:0:0 | &ref | main.rs:470:44:470:55 | receiver for default_name |
| main.rs:471:18:471:18 | n | file://:0:0:0:0 | &ref | main.rs:471:18:471:18 | receiver for n |
| main.rs:494:13:494:13 | a | file://:0:0:0:0 | &ref | main.rs:494:13:494:13 | receiver for a |
| main.rs:495:13:495:13 | b | file://:0:0:0:0 | &ref | main.rs:495:13:495:13 | receiver for b |
| main.rs:496:18:496:18 | b | file://:0:0:0:0 | &ref | main.rs:496:18:496:18 | receiver for b |
| main.rs:505:15:505:24 | source(...) | file://:0:0:0:0 | element | main.rs:505:14:505:34 | [...] |

View File

@@ -73,6 +73,18 @@ multipleCallTargets
| test.rs:977:14:977:29 | ...::_print(...) |
| test.rs:979:27:979:36 | ...::_print(...) |
| test.rs:980:28:980:41 | ...::_print(...) |
| test_futures_io.rs:45:27:45:84 | ...::read(...) |
| test_futures_io.rs:49:27:49:51 | reader.read(...) |
| test_futures_io.rs:83:22:83:39 | reader2.fill_buf() |
| test_futures_io.rs:103:27:103:85 | ...::read(...) |
| test_futures_io.rs:107:27:107:52 | reader2.read(...) |
| test_futures_io.rs:125:22:125:39 | reader2.fill_buf() |
| test_futures_io.rs:132:27:132:62 | reader2.read_until(...) |
| test_futures_io.rs:139:27:139:54 | reader2.read_line(...) |
| test_futures_io.rs:146:27:146:58 | reader2.read_to_end(...) |
| test_futures_io.rs:152:32:152:46 | reader2.lines() |
| test_futures_io.rs:153:14:153:32 | lines_stream.next() |
| test_futures_io.rs:154:32:154:50 | lines_stream.next() |
| web_frameworks.rs:13:14:13:22 | a.as_str() |
| web_frameworks.rs:13:14:13:23 | a.as_str() |
| web_frameworks.rs:14:14:14:24 | a.as_bytes() |

View File

@@ -309,28 +309,28 @@ async fn test_tokio_stdin() -> Result<(), Box<dyn std::error::Error>> {
let mut stdin = tokio::io::stdin(); // $ Alert[rust/summary/taint-sources]
let mut buffer = [0u8; 100];
let _bytes = stdin.read(&mut buffer).await?;
sink(&buffer); // $ MISSING: hasTaintFlow -- we cannot resolve the `read` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(&buffer); // $ hasTaintFlow
}
{
let mut stdin = tokio::io::stdin(); // $ Alert[rust/summary/taint-sources]
let mut buffer = Vec::<u8>::new();
let _bytes = stdin.read_to_end(&mut buffer).await?;
sink(&buffer); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_to_end` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(&buffer); // $ hasTaintFlow
}
{
let mut stdin = tokio::io::stdin(); // $ Alert[rust/summary/taint-sources]
let mut buffer = String::new();
let _bytes = stdin.read_to_string(&mut buffer).await?;
sink(&buffer); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_to_string` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(&buffer); // $ hasTaintFlow
}
{
let mut stdin = tokio::io::stdin(); // $ Alert[rust/summary/taint-sources]
let mut buffer = [0; 100];
stdin.read_exact(&mut buffer).await?;
sink(&buffer); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_exact` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(&buffer); // $ hasTaintFlow
}
{
@@ -339,17 +339,17 @@ async fn test_tokio_stdin() -> Result<(), Box<dyn std::error::Error>> {
let v2 = stdin.read_i16().await?;
let v3 = stdin.read_f32().await?;
let v4 = stdin.read_i64_le().await?;
sink(v1); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_u8` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(v2); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_i16` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(v3); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_f32` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(v4); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_i64_le` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(v1); // $ hasTaintFlow
sink(v2); // $ hasTaintFlow
sink(v3); // $ hasTaintFlow
sink(v4); // $ hasTaintFlow
}
{
let mut stdin = tokio::io::stdin(); // $ Alert[rust/summary/taint-sources]
let mut buffer = bytes::BytesMut::new();
stdin.read_buf(&mut buffer).await?;
sink(&buffer); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_buf` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(&buffer); // $ hasTaintFlow
}
// --- async reading from stdin (BufReader) ---
@@ -357,7 +357,7 @@ async fn test_tokio_stdin() -> Result<(), Box<dyn std::error::Error>> {
{
let mut reader = tokio::io::BufReader::new(tokio::io::stdin()); // $ Alert[rust/summary/taint-sources]
let data = reader.fill_buf().await?;
sink(&data); // $ MISSING: hasTaintFlow -- we cannot resolve the `fill_buf` call above, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
sink(&data); // $ hasTaintFlow
}
{
@@ -370,31 +370,31 @@ async fn test_tokio_stdin() -> Result<(), Box<dyn std::error::Error>> {
let mut buffer = String::new();
let mut reader = tokio::io::BufReader::new(tokio::io::stdin()); // $ Alert[rust/summary/taint-sources]
reader.read_line(&mut buffer).await?;
sink(&buffer); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_line` call above, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
sink(&buffer); // $ hasTaintFlow
}
{
let mut buffer = Vec::<u8>::new();
let mut reader = tokio::io::BufReader::new(tokio::io::stdin()); // $ Alert[rust/summary/taint-sources]
reader.read_until(b',', &mut buffer).await?;
sink(&buffer); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_until` call above, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
sink(buffer[0]); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_until` call above, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
sink(&buffer); // $ hasTaintFlow
sink(buffer[0]); // $ hasTaintFlow
}
{
let mut reader_split = tokio::io::BufReader::new(tokio::io::stdin()).split(b','); // $ Alert[rust/summary/taint-sources]
sink(reader_split.next_segment().await?.unwrap()); // $ MISSING: hasTaintFlow -- we cannot resolve the `split` call above, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
sink(reader_split.next_segment().await?.unwrap()); // $ hasTaintFlow
while let Some(chunk) = reader_split.next_segment().await? {
sink(chunk); // $ MISSING: hasTaintFlow
sink(chunk); // $ hasTaintFlow
}
}
{
let reader = tokio::io::BufReader::new(tokio::io::stdin()); // $ Alert[rust/summary/taint-sources]
let mut lines = reader.lines();
sink(lines.next_line().await?.unwrap()); // $ MISSING: hasTaintFlow -- we cannot resolve the `lines` call above, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
sink(lines.next_line().await?.unwrap()); // $ hasTaintFlow
while let Some(line) = lines.next_line().await? {
sink(line); // $ MISSING: hasTaintFlow
sink(line); // $ hasTaintFlow
}
}
@@ -583,25 +583,25 @@ async fn test_tokio_file() -> std::io::Result<()> {
{
let mut buffer = [0u8; 100];
let _bytes = file.read(&mut buffer).await?;
sink(&buffer); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(&buffer); // $ hasTaintFlow="file.txt"
}
{
let mut buffer = Vec::<u8>::new();
let _bytes = file.read_to_end(&mut buffer).await?;
sink(&buffer); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read_to_end` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(&buffer); // $ hasTaintFlow="file.txt"
}
{
let mut buffer = String::new();
let _bytes = file.read_to_string(&mut buffer).await?;
sink(&buffer); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read_to_string` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(&buffer); // $ hasTaintFlow="file.txt"
}
{
let mut buffer = [0; 100];
file.read_exact(&mut buffer).await?;
sink(&buffer); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read_exact` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(&buffer); // $ hasTaintFlow="file.txt"
}
{
@@ -609,16 +609,16 @@ async fn test_tokio_file() -> std::io::Result<()> {
let v2 = file.read_i16().await?;
let v3 = file.read_f32().await?;
let v4 = file.read_i64_le().await?;
sink(v1); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read_u8` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(v2); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read_i16` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(v3); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read_f32` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(v4); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read_i64_le` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(v1); // $ hasTaintFlow="file.txt"
sink(v2); // $ hasTaintFlow="file.txt"
sink(v3); // $ hasTaintFlow="file.txt"
sink(v4); // $ hasTaintFlow="file.txt"
}
{
let mut buffer = bytes::BytesMut::new();
file.read_buf(&mut buffer).await?;
sink(&buffer); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read_buf` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(&buffer); // $ hasTaintFlow="file.txt"
}
// --- OpenOptions ---
@@ -627,7 +627,7 @@ async fn test_tokio_file() -> std::io::Result<()> {
let mut f1 = tokio::fs::OpenOptions::new().open("f1.txt").await?; // $ Alert[rust/summary/taint-sources]
let mut buffer = [0u8; 1024];
let _bytes = f1.read(&mut buffer).await?;
sink(&buffer); // $ MISSING: hasTaintFlow="f1.txt"
sink(&buffer); // $ hasTaintFlow="f1.txt"
}
// --- misc operations ---
@@ -775,8 +775,8 @@ async fn test_tokio_tcpstream(case: i64) -> std::io::Result<()> {
sink(buffer1[0]); // $ hasTaintFlow=address
println!("buffer2 = {:?}", buffer2);
sink(&buffer2); // $ MISSING: hasTaintFlow=address -- we cannot resolve the `read` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(buffer2[0]); // $ MISSING: hasTaintFlow=address -- we cannot resolve the `read` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(&buffer2); // $ hasTaintFlow=address
sink(buffer2[0]); // $ hasTaintFlow=address
let buffer_string = String::from_utf8_lossy(&buffer2[..n2]);
println!("string = {}", buffer_string);

View File

@@ -43,12 +43,12 @@ 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?; // 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
sink(&buffer1[..bytes_read1]); // $ 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`
sink(&buffer2[..bytes_read2]); // $ MISSING: hasTaintFlow=url
sink(&buffer2[..bytes_read2]); // $ hasTaintFlow=url
}
let mut reader2 = futures::io::BufReader::new(reader);
@@ -81,7 +81,7 @@ async fn test_futures_rustls_futures_io() -> io::Result<()> {
{
// using the `AsyncBufReadExt::fill_buf` extension method (higher-level)
let buffer = reader2.fill_buf().await?; // we cannot resolve the `fill_buf` call, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
sink(buffer); // $ MISSING: hasTaintFlow=url
sink(buffer); // $ hasTaintFlow=url
}
{
@@ -101,11 +101,11 @@ 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?; // 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
sink(&buffer1[..bytes_read1]); // $ 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`
sink(&buffer2[..bytes_read2]); // $ MISSING: hasTaintFlow=url
sink(&buffer2[..bytes_read2]); // $ hasTaintFlow=url
}
{
@@ -123,28 +123,28 @@ async fn test_futures_rustls_futures_io() -> io::Result<()> {
{
// using the `AsyncBufReadExt::fill_buf` extension method (higher-level)
let buffer = reader2.fill_buf().await?; // we cannot resolve the `fill_buf` call, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
sink(buffer); // $ MISSING: hasTaintFlow=url
sink(buffer); // $ hasTaintFlow=url
}
{
// using the `AsyncBufReadExt::read_until` extension method
let mut line = Vec::new();
let _bytes_read = reader2.read_until(b'\n', &mut line).await?; // we cannot resolve the `read_until` call, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
sink(&line); // $ MISSING: hasTaintFlow=url
sink(&line); // $ hasTaintFlow=url
}
{
// using the `AsyncBufReadExt::read_line` extension method
let mut line = String::new();
let _bytes_read = reader2.read_line(&mut line).await?; // we cannot resolve the `read_line` call, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
sink(&line); // $ MISSING: hasTaintFlow=url
sink(&line); // $ hasTaintFlow=url
}
{
// using the `AsyncBufReadExt::read_to_end` extension method
let mut buffer = Vec::with_capacity(1024);
let _bytes_read = reader2.read_to_end(&mut buffer).await?; // we cannot resolve the `read` call, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
sink(&buffer); // $ MISSING: hasTaintFlow=url
sink(&buffer); // $ hasTaintFlow=url
}
{

View File

@@ -1,6 +1,6 @@
models
| 1 | Summary: <alloc::string::String as core::convert::From>::from; Argument[0].Reference; ReturnValue; value |
| 2 | Summary: <alloc::string::String as core::convert::From>::from; Argument[0]; ReturnValue; value |
| 1 | Summary: <_ as core::convert::From>::from; Argument[0]; ReturnValue; value |
| 2 | Summary: <alloc::string::String as core::convert::From>::from; Argument[0].Reference; ReturnValue; value |
| 3 | Summary: <alloc::string::String as core::ops::arith::Add>::add; Argument[self]; ReturnValue; value |
| 4 | Summary: <alloc::string::String>::as_str; Argument[self]; ReturnValue; value |
| 5 | Summary: <core::str>::as_str; Argument[self]; ReturnValue; value |

View File

@@ -30,7 +30,7 @@ fn int_div(
) -> Result<i32> // $ item=my::Result $ item=i32
{
if y == 0 {
return Err("Div by zero".to_string()); // $ item=Err
return Err("Div by zero".to_string()); // $ item=Err item=to_string
}
Ok(x / y) // $ item=Ok
}

View File

@@ -0,0 +1,161 @@
// Tests for method resolution targeting blanket trait implementations
mod basic_blanket_impl {
#[derive(Debug, Copy, Clone)]
struct S1;
trait Clone1 {
fn clone1(&self) -> Self;
}
trait Duplicatable {
fn duplicate(&self) -> Self
where
Self: Sized;
}
impl Clone1 for S1 {
// S1::clone1
fn clone1(&self) -> Self {
*self // $ target=deref
}
}
// Blanket implementation for all types that implement Display and Clone
impl<T: Clone1> Duplicatable for T {
// Clone1duplicate
fn duplicate(&self) -> Self {
self.clone1() // $ target=clone1
}
}
pub fn test_basic_blanket() {
let x = S1.clone1(); // $ target=S1::clone1
println!("{x:?}");
let y = S1.duplicate(); // $ target=Clone1duplicate
println!("{y:?}");
}
}
mod extension_trait_blanket_impl {
// This tests:
// 1. A trait that is implemented for a type parameter
// 2. An extension trait
// 3. A blanket implementation of the extension trait for a type parameter
trait Flag {
fn read_flag(&self) -> bool;
}
trait TryFlag {
fn try_read_flag(&self) -> Option<bool>;
}
impl<Fl> TryFlag for Fl
where
Fl: Flag,
{
fn try_read_flag(&self) -> Option<bool> {
Some(self.read_flag()) // $ target=read_flag
}
}
trait TryFlagExt: TryFlag {
// TryFlagExt::try_read_flag_twice
fn try_read_flag_twice(&self) -> Option<bool> {
self.try_read_flag() // $ target=try_read_flag
}
}
impl<T: TryFlag> TryFlagExt for T {}
trait AnotherTryFlag {
// AnotherTryFlag::try_read_flag_twice
fn try_read_flag_twice(&self) -> Option<bool>;
}
struct MyTryFlag {
flag: bool,
}
impl TryFlag for MyTryFlag {
// MyTryFlag::try_read_flag
fn try_read_flag(&self) -> Option<bool> {
Some(self.flag) // $ fieldof=MyTryFlag
}
}
struct MyFlag {
flag: bool,
}
impl Flag for MyFlag {
// MyFlag::read_flag
fn read_flag(&self) -> bool {
self.flag // $ fieldof=MyFlag
}
}
struct MyOtherFlag {
flag: bool,
}
impl AnotherTryFlag for MyOtherFlag {
// MyOtherFlag::try_read_flag_twice
fn try_read_flag_twice(&self) -> Option<bool> {
Some(self.flag) // $ fieldof=MyOtherFlag
}
}
fn test() {
let my_try_flag = MyTryFlag { flag: true };
let result = my_try_flag.try_read_flag_twice(); // $ target=TryFlagExt::try_read_flag_twice
let my_flag = MyFlag { flag: true };
// Here `TryFlagExt::try_read_flag_twice` is a target since there is a
// blanket implementaton of `TryFlag` for `Flag`.
let result = my_flag.try_read_flag_twice(); // $ MISSING: target=TryFlagExt::try_read_flag_twice
let my_other_flag = MyOtherFlag { flag: true };
// Here `TryFlagExt::try_read_flag_twice` is _not_ a target since
// `MyOtherFlag` does not implement `TryFlag`.
let result = my_other_flag.try_read_flag_twice(); // $ target=MyOtherFlag::try_read_flag_twice
}
}
pub mod sql_exec {
// a highly simplified model of `MySqlConnection.execute` in SQLx
trait Connection {}
trait Executor {
fn execute1(&self);
fn execute2<E>(&self, query: E);
}
impl<T: Connection> Executor for T {
fn execute1(&self) {
println!("Executor::execute1");
}
fn execute2<E>(&self, _query: E) {
println!("Executor::execute2");
}
}
struct MySqlConnection {}
impl Connection for MySqlConnection {}
pub fn f() {
let c = MySqlConnection {}; // $ certainType=c:MySqlConnection
c.execute1(); // $ target=execute1
MySqlConnection::execute1(&c); // $ MISSING: target=execute1
c.execute2("SELECT * FROM users"); // $ target=execute2
c.execute2::<&str>("SELECT * FROM users"); // $ target=execute2
MySqlConnection::execute2(&c, "SELECT * FROM users"); // $ MISSING: target=execute2
MySqlConnection::execute2::<&str>(&c, "SELECT * FROM users"); // $ MISSING: target=execute2
}
}

View File

@@ -101,7 +101,7 @@ fn test_assoc_type(obj: &dyn AssocTrait<i64, AP = bool>) {
pub fn test() {
test_basic_dyn_trait(&MyStruct { value: 42 }); // $ target=test_basic_dyn_trait
test_generic_dyn_trait(&GenStruct {
value: "".to_string(),
value: "".to_string(), // $ target=to_string
}); // $ target=test_generic_dyn_trait
test_poly_dyn_trait(); // $ target=test_poly_dyn_trait
test_assoc_type(&GenStruct { value: 100 }); // $ target=test_assoc_type

View File

@@ -365,7 +365,7 @@ mod method_non_parametric_trait_impl {
fn type_bound_type_parameter_impl<TP: MyTrait<S1>>(thing: TP) -> S1 {
// The trait bound on `TP` makes the implementation of `ConvertTo` valid
thing.convert_to() // $ MISSING: target=T::convert_to
thing.convert_to() // $ target=T::convert_to
}
pub fn f() {
@@ -437,7 +437,7 @@ mod method_non_parametric_trait_impl {
let x = get_snd_fst(c); // $ type=x:S1 target=get_snd_fst
let thing = MyThing { a: S1 };
let i = thing.convert_to(); // $ MISSING: type=i:S1 target=T::convert_to
let i = thing.convert_to(); // $ type=i:S1 target=T::convert_to
let j = convert_to(thing); // $ type=j:S1 target=convert_to
}
}
@@ -1376,7 +1376,7 @@ mod method_call_type_conversion {
let t = x7.m1(); // $ target=m1 type=t:& type=t:&T.S2
println!("{:?}", x7);
let x9: String = "Hello".to_string(); // $ certainType=x9:String
let x9: String = "Hello".to_string(); // $ certainType=x9:String target=to_string
// Implicit `String` -> `str` conversion happens via the `Deref` trait:
// https://doc.rust-lang.org/std/string/struct.String.html#deref.
@@ -2569,43 +2569,6 @@ pub mod pattern_matching_experimental {
}
}
pub mod exec {
// a highly simplified model of `MySqlConnection.execute` in SQLx
trait Connection {}
trait Executor {
fn execute1(&self);
fn execute2<E>(&self, query: E);
}
impl<T: Connection> Executor for T {
fn execute1(&self) {
println!("Executor::execute1");
}
fn execute2<E>(&self, _query: E) {
println!("Executor::execute2");
}
}
struct MySqlConnection {}
impl Connection for MySqlConnection {}
pub fn f() {
let c = MySqlConnection {}; // $ certainType=c:MySqlConnection
c.execute1(); // $ MISSING: target=execute1
MySqlConnection::execute1(&c); // $ MISSING: target=execute1
c.execute2("SELECT * FROM users"); // $ MISSING: target=execute2
c.execute2::<&str>("SELECT * FROM users"); // $ MISSING: target=execute2
MySqlConnection::execute2(&c, "SELECT * FROM users"); // $ MISSING: target=execute2
MySqlConnection::execute2::<&str>(&c, "SELECT * FROM users"); // $ MISSING: target=execute2
}
}
pub mod path_buf {
// a highly simplified model of `PathBuf::canonicalize`
@@ -2655,6 +2618,7 @@ pub mod path_buf {
mod closure;
mod dereference;
mod dyn_type;
mod blanket_impl;
fn main() {
field_access::f(); // $ target=f
@@ -2683,7 +2647,6 @@ fn main() {
macros::f(); // $ target=f
method_determined_by_argument_type::f(); // $ target=f
tuples::f(); // $ target=f
exec::f(); // $ target=f
path_buf::f(); // $ target=f
dereference::test(); // $ target=test
pattern_matching::test_all_patterns(); // $ target=test_all_patterns

View File

@@ -1,4 +1,143 @@
inferType
| blanket_impl.rs:8:19:8:23 | SelfParam | | file://:0:0:0:0 | & |
| blanket_impl.rs:8:19:8:23 | SelfParam | &T | blanket_impl.rs:7:5:9:5 | Self [trait Clone1] |
| blanket_impl.rs:12:22:12:26 | SelfParam | | file://:0:0:0:0 | & |
| blanket_impl.rs:12:22:12:26 | SelfParam | &T | blanket_impl.rs:11:5:15:5 | Self [trait Duplicatable] |
| blanket_impl.rs:19:19:19:23 | SelfParam | | file://:0:0:0:0 | & |
| blanket_impl.rs:19:19:19:23 | SelfParam | &T | blanket_impl.rs:4:5:5:14 | S1 |
| blanket_impl.rs:19:34:21:9 | { ... } | | blanket_impl.rs:4:5:5:14 | S1 |
| blanket_impl.rs:20:13:20:17 | * ... | | blanket_impl.rs:4:5:5:14 | S1 |
| blanket_impl.rs:20:14:20:17 | self | | file://:0:0:0:0 | & |
| blanket_impl.rs:20:14:20:17 | self | &T | blanket_impl.rs:4:5:5:14 | S1 |
| blanket_impl.rs:27:22:27:26 | SelfParam | | file://:0:0:0:0 | & |
| blanket_impl.rs:27:22:27:26 | SelfParam | &T | blanket_impl.rs:25:10:25:18 | T |
| blanket_impl.rs:27:37:29:9 | { ... } | | blanket_impl.rs:25:10:25:18 | T |
| blanket_impl.rs:28:13:28:16 | self | | file://:0:0:0:0 | & |
| blanket_impl.rs:28:13:28:16 | self | &T | blanket_impl.rs:25:10:25:18 | T |
| blanket_impl.rs:28:13:28:25 | self.clone1() | | blanket_impl.rs:25:10:25:18 | T |
| blanket_impl.rs:33:13:33:13 | x | | blanket_impl.rs:4:5:5:14 | S1 |
| blanket_impl.rs:33:17:33:18 | S1 | | blanket_impl.rs:4:5:5:14 | S1 |
| blanket_impl.rs:33:17:33:27 | S1.clone1() | | blanket_impl.rs:4:5:5:14 | S1 |
| blanket_impl.rs:34:18:34:24 | "{x:?}\\n" | | file://:0:0:0:0 | & |
| blanket_impl.rs:34:18:34:24 | "{x:?}\\n" | &T | {EXTERNAL LOCATION} | str |
| blanket_impl.rs:34:18:34:24 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments |
| blanket_impl.rs:34:18:34:24 | MacroExpr | | {EXTERNAL LOCATION} | Arguments |
| blanket_impl.rs:34:20:34:20 | x | | blanket_impl.rs:4:5:5:14 | S1 |
| blanket_impl.rs:35:13:35:13 | y | | blanket_impl.rs:4:5:5:14 | S1 |
| blanket_impl.rs:35:17:35:18 | S1 | | blanket_impl.rs:4:5:5:14 | S1 |
| blanket_impl.rs:35:17:35:30 | S1.duplicate() | | blanket_impl.rs:4:5:5:14 | S1 |
| blanket_impl.rs:36:18:36:24 | "{y:?}\\n" | | file://:0:0:0:0 | & |
| blanket_impl.rs:36:18:36:24 | "{y:?}\\n" | &T | {EXTERNAL LOCATION} | str |
| blanket_impl.rs:36:18:36:24 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments |
| blanket_impl.rs:36:18:36:24 | MacroExpr | | {EXTERNAL LOCATION} | Arguments |
| blanket_impl.rs:36:20:36:20 | y | | blanket_impl.rs:4:5:5:14 | S1 |
| blanket_impl.rs:47:22:47:26 | SelfParam | | file://:0:0:0:0 | & |
| blanket_impl.rs:47:22:47:26 | SelfParam | &T | blanket_impl.rs:46:5:48:5 | Self [trait Flag] |
| blanket_impl.rs:51:26:51:30 | SelfParam | | file://:0:0:0:0 | & |
| blanket_impl.rs:51:26:51:30 | SelfParam | &T | blanket_impl.rs:50:5:52:5 | Self [trait TryFlag] |
| blanket_impl.rs:58:26:58:30 | SelfParam | | file://:0:0:0:0 | & |
| blanket_impl.rs:58:26:58:30 | SelfParam | &T | blanket_impl.rs:54:10:54:11 | Fl |
| blanket_impl.rs:58:49:60:9 | { ... } | | {EXTERNAL LOCATION} | Option |
| blanket_impl.rs:58:49:60:9 | { ... } | T | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:59:13:59:34 | Some(...) | | {EXTERNAL LOCATION} | Option |
| blanket_impl.rs:59:13:59:34 | Some(...) | T | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:59:18:59:21 | self | | file://:0:0:0:0 | & |
| blanket_impl.rs:59:18:59:21 | self | &T | blanket_impl.rs:54:10:54:11 | Fl |
| blanket_impl.rs:59:18:59:33 | self.read_flag() | | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:65:32:65:36 | SelfParam | | file://:0:0:0:0 | & |
| blanket_impl.rs:65:32:65:36 | SelfParam | &T | blanket_impl.rs:63:5:68:5 | Self [trait TryFlagExt] |
| blanket_impl.rs:65:55:67:9 | { ... } | | {EXTERNAL LOCATION} | Option |
| blanket_impl.rs:65:55:67:9 | { ... } | T | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:66:13:66:16 | self | | file://:0:0:0:0 | & |
| blanket_impl.rs:66:13:66:16 | self | &T | blanket_impl.rs:63:5:68:5 | Self [trait TryFlagExt] |
| blanket_impl.rs:66:13:66:32 | self.try_read_flag() | | {EXTERNAL LOCATION} | Option |
| blanket_impl.rs:66:13:66:32 | self.try_read_flag() | T | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:74:32:74:36 | SelfParam | | file://:0:0:0:0 | & |
| blanket_impl.rs:74:32:74:36 | SelfParam | &T | blanket_impl.rs:72:5:75:5 | Self [trait AnotherTryFlag] |
| blanket_impl.rs:83:26:83:30 | SelfParam | | file://:0:0:0:0 | & |
| blanket_impl.rs:83:26:83:30 | SelfParam | &T | blanket_impl.rs:77:5:79:5 | MyTryFlag |
| blanket_impl.rs:83:49:85:9 | { ... } | | {EXTERNAL LOCATION} | Option |
| blanket_impl.rs:83:49:85:9 | { ... } | T | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:84:13:84:27 | Some(...) | | {EXTERNAL LOCATION} | Option |
| blanket_impl.rs:84:13:84:27 | Some(...) | T | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:84:18:84:21 | self | | file://:0:0:0:0 | & |
| blanket_impl.rs:84:18:84:21 | self | &T | blanket_impl.rs:77:5:79:5 | MyTryFlag |
| blanket_impl.rs:84:18:84:26 | self.flag | | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:94:22:94:26 | SelfParam | | file://:0:0:0:0 | & |
| blanket_impl.rs:94:22:94:26 | SelfParam | &T | blanket_impl.rs:88:5:90:5 | MyFlag |
| blanket_impl.rs:94:37:96:9 | { ... } | | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:95:13:95:16 | self | | file://:0:0:0:0 | & |
| blanket_impl.rs:95:13:95:16 | self | &T | blanket_impl.rs:88:5:90:5 | MyFlag |
| blanket_impl.rs:95:13:95:21 | self.flag | | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:105:32:105:36 | SelfParam | | file://:0:0:0:0 | & |
| blanket_impl.rs:105:32:105:36 | SelfParam | &T | blanket_impl.rs:99:5:101:5 | MyOtherFlag |
| blanket_impl.rs:105:55:107:9 | { ... } | | {EXTERNAL LOCATION} | Option |
| blanket_impl.rs:105:55:107:9 | { ... } | T | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:106:13:106:27 | Some(...) | | {EXTERNAL LOCATION} | Option |
| blanket_impl.rs:106:13:106:27 | Some(...) | T | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:106:18:106:21 | self | | file://:0:0:0:0 | & |
| blanket_impl.rs:106:18:106:21 | self | &T | blanket_impl.rs:99:5:101:5 | MyOtherFlag |
| blanket_impl.rs:106:18:106:26 | self.flag | | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:111:13:111:23 | my_try_flag | | blanket_impl.rs:77:5:79:5 | MyTryFlag |
| blanket_impl.rs:111:27:111:50 | MyTryFlag {...} | | blanket_impl.rs:77:5:79:5 | MyTryFlag |
| blanket_impl.rs:111:45:111:48 | true | | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:112:13:112:18 | result | | {EXTERNAL LOCATION} | Option |
| blanket_impl.rs:112:13:112:18 | result | T | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:112:22:112:32 | my_try_flag | | blanket_impl.rs:77:5:79:5 | MyTryFlag |
| blanket_impl.rs:112:22:112:54 | my_try_flag.try_read_flag_twice() | | {EXTERNAL LOCATION} | Option |
| blanket_impl.rs:112:22:112:54 | my_try_flag.try_read_flag_twice() | T | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:114:13:114:19 | my_flag | | blanket_impl.rs:88:5:90:5 | MyFlag |
| blanket_impl.rs:114:23:114:43 | MyFlag {...} | | blanket_impl.rs:88:5:90:5 | MyFlag |
| blanket_impl.rs:114:38:114:41 | true | | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:117:22:117:28 | my_flag | | blanket_impl.rs:88:5:90:5 | MyFlag |
| blanket_impl.rs:119:13:119:25 | my_other_flag | | blanket_impl.rs:99:5:101:5 | MyOtherFlag |
| blanket_impl.rs:119:29:119:54 | MyOtherFlag {...} | | blanket_impl.rs:99:5:101:5 | MyOtherFlag |
| blanket_impl.rs:119:49:119:52 | true | | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:122:13:122:18 | result | | {EXTERNAL LOCATION} | Option |
| blanket_impl.rs:122:13:122:18 | result | T | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:122:22:122:34 | my_other_flag | | blanket_impl.rs:99:5:101:5 | MyOtherFlag |
| blanket_impl.rs:122:22:122:56 | my_other_flag.try_read_flag_twice() | | {EXTERNAL LOCATION} | Option |
| blanket_impl.rs:122:22:122:56 | my_other_flag.try_read_flag_twice() | T | {EXTERNAL LOCATION} | bool |
| blanket_impl.rs:132:21:132:25 | SelfParam | | file://:0:0:0:0 | & |
| blanket_impl.rs:132:21:132:25 | SelfParam | &T | blanket_impl.rs:131:5:134:5 | Self [trait Executor] |
| blanket_impl.rs:133:24:133:28 | SelfParam | | file://:0:0:0:0 | & |
| blanket_impl.rs:133:24:133:28 | SelfParam | &T | blanket_impl.rs:131:5:134:5 | Self [trait Executor] |
| blanket_impl.rs:133:31:133:35 | query | | blanket_impl.rs:133:21:133:21 | E |
| blanket_impl.rs:137:21:137:25 | SelfParam | | file://:0:0:0:0 | & |
| blanket_impl.rs:137:21:137:25 | SelfParam | &T | blanket_impl.rs:136:10:136:22 | T |
| blanket_impl.rs:138:22:138:41 | "Executor::execute1\\n" | | file://:0:0:0:0 | & |
| blanket_impl.rs:138:22:138:41 | "Executor::execute1\\n" | &T | {EXTERNAL LOCATION} | str |
| blanket_impl.rs:138:22:138:41 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments |
| blanket_impl.rs:138:22:138:41 | MacroExpr | | {EXTERNAL LOCATION} | Arguments |
| blanket_impl.rs:141:24:141:28 | SelfParam | | file://:0:0:0:0 | & |
| blanket_impl.rs:141:24:141:28 | SelfParam | &T | blanket_impl.rs:136:10:136:22 | T |
| blanket_impl.rs:141:31:141:36 | _query | | blanket_impl.rs:141:21:141:21 | E |
| blanket_impl.rs:142:22:142:41 | "Executor::execute2\\n" | | file://:0:0:0:0 | & |
| blanket_impl.rs:142:22:142:41 | "Executor::execute2\\n" | &T | {EXTERNAL LOCATION} | str |
| blanket_impl.rs:142:22:142:41 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments |
| blanket_impl.rs:142:22:142:41 | MacroExpr | | {EXTERNAL LOCATION} | Arguments |
| blanket_impl.rs:151:13:151:13 | c | | blanket_impl.rs:146:5:146:29 | MySqlConnection |
| blanket_impl.rs:151:17:151:34 | MySqlConnection {...} | | blanket_impl.rs:146:5:146:29 | MySqlConnection |
| blanket_impl.rs:153:9:153:9 | c | | blanket_impl.rs:146:5:146:29 | MySqlConnection |
| blanket_impl.rs:154:35:154:36 | &c | | file://:0:0:0:0 | & |
| blanket_impl.rs:154:35:154:36 | &c | &T | blanket_impl.rs:146:5:146:29 | MySqlConnection |
| blanket_impl.rs:154:36:154:36 | c | | blanket_impl.rs:146:5:146:29 | MySqlConnection |
| blanket_impl.rs:156:9:156:9 | c | | blanket_impl.rs:146:5:146:29 | MySqlConnection |
| blanket_impl.rs:156:20:156:40 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
| blanket_impl.rs:156:20:156:40 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
| blanket_impl.rs:157:9:157:9 | c | | blanket_impl.rs:146:5:146:29 | MySqlConnection |
| blanket_impl.rs:157:28:157:48 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
| blanket_impl.rs:157:28:157:48 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
| blanket_impl.rs:158:35:158:36 | &c | | file://:0:0:0:0 | & |
| blanket_impl.rs:158:35:158:36 | &c | &T | blanket_impl.rs:146:5:146:29 | MySqlConnection |
| blanket_impl.rs:158:36:158:36 | c | | blanket_impl.rs:146:5:146:29 | MySqlConnection |
| blanket_impl.rs:158:39:158:59 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
| blanket_impl.rs:158:39:158:59 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
| blanket_impl.rs:159:43:159:44 | &c | | file://:0:0:0:0 | & |
| blanket_impl.rs:159:43:159:44 | &c | &T | blanket_impl.rs:146:5:146:29 | MySqlConnection |
| blanket_impl.rs:159:44:159:44 | c | | blanket_impl.rs:146:5:146:29 | MySqlConnection |
| blanket_impl.rs:159:47:159:67 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
| blanket_impl.rs:159:47:159:67 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
| closure.rs:6:13:6:22 | my_closure | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:6:13:6:22 | my_closure | dyn(Args) | file://:0:0:0:0 | (T_2) |
| closure.rs:6:13:6:22 | my_closure | dyn(Args).0(2) | {EXTERNAL LOCATION} | bool |
@@ -624,10 +763,13 @@ inferType
| dyn_type.rs:103:28:105:5 | &... | | file://:0:0:0:0 | & |
| dyn_type.rs:103:28:105:5 | &... | &T | dyn_type.rs:10:1:13:1 | dyn GenericGet |
| dyn_type.rs:103:28:105:5 | &... | &T | dyn_type.rs:33:1:36:1 | GenStruct |
| dyn_type.rs:103:28:105:5 | &... | &T.A | {EXTERNAL LOCATION} | String |
| dyn_type.rs:103:28:105:5 | &... | &T.dyn(A) | {EXTERNAL LOCATION} | String |
| dyn_type.rs:103:29:105:5 | GenStruct {...} | | dyn_type.rs:33:1:36:1 | GenStruct |
| dyn_type.rs:103:29:105:5 | GenStruct {...} | A | {EXTERNAL LOCATION} | String |
| dyn_type.rs:104:16:104:17 | "" | | file://:0:0:0:0 | & |
| dyn_type.rs:104:16:104:17 | "" | &T | {EXTERNAL LOCATION} | str |
| dyn_type.rs:104:16:104:29 | "".to_string() | | {EXTERNAL LOCATION} | String |
| dyn_type.rs:107:21:107:45 | &... | | file://:0:0:0:0 | & |
| dyn_type.rs:107:21:107:45 | &... | &T | dyn_type.rs:15:1:19:1 | dyn AssocTrait |
| dyn_type.rs:107:21:107:45 | &... | &T | dyn_type.rs:33:1:36:1 | GenStruct |
@@ -1260,8 +1402,10 @@ inferType
| main.rs:439:21:439:37 | MyThing {...} | | main.rs:224:5:227:5 | MyThing |
| main.rs:439:21:439:37 | MyThing {...} | A | main.rs:235:5:236:14 | S1 |
| main.rs:439:34:439:35 | S1 | | main.rs:235:5:236:14 | S1 |
| main.rs:440:13:440:13 | i | | main.rs:235:5:236:14 | S1 |
| main.rs:440:17:440:21 | thing | | main.rs:224:5:227:5 | MyThing |
| main.rs:440:17:440:21 | thing | A | main.rs:235:5:236:14 | S1 |
| main.rs:440:17:440:34 | thing.convert_to() | | main.rs:235:5:236:14 | S1 |
| main.rs:441:13:441:13 | j | | main.rs:235:5:236:14 | S1 |
| main.rs:441:17:441:33 | convert_to(...) | | main.rs:235:5:236:14 | S1 |
| main.rs:441:28:441:32 | thing | | main.rs:224:5:227:5 | MyThing |
@@ -3187,14 +3331,22 @@ inferType
| main.rs:1706:13:1709:13 | Vec2 {...} | | main.rs:1586:5:1591:5 | Vec2 |
| main.rs:1707:20:1707:23 | self | | main.rs:1586:5:1591:5 | Vec2 |
| main.rs:1707:20:1707:25 | self.x | | {EXTERNAL LOCATION} | i64 |
| main.rs:1707:20:1707:33 | ... \| ... | | {EXTERNAL LOCATION} | NonZero |
| main.rs:1707:20:1707:33 | ... \| ... | | {EXTERNAL LOCATION} | i64 |
| main.rs:1707:20:1707:33 | ... \| ... | T | {EXTERNAL LOCATION} | i64 |
| main.rs:1707:29:1707:31 | rhs | | main.rs:1586:5:1591:5 | Vec2 |
| main.rs:1707:29:1707:33 | rhs.x | | {EXTERNAL LOCATION} | NonZero |
| main.rs:1707:29:1707:33 | rhs.x | | {EXTERNAL LOCATION} | i64 |
| main.rs:1707:29:1707:33 | rhs.x | T | {EXTERNAL LOCATION} | i64 |
| main.rs:1708:20:1708:23 | self | | main.rs:1586:5:1591:5 | Vec2 |
| main.rs:1708:20:1708:25 | self.y | | {EXTERNAL LOCATION} | i64 |
| main.rs:1708:20:1708:33 | ... \| ... | | {EXTERNAL LOCATION} | NonZero |
| main.rs:1708:20:1708:33 | ... \| ... | | {EXTERNAL LOCATION} | i64 |
| main.rs:1708:20:1708:33 | ... \| ... | T | {EXTERNAL LOCATION} | i64 |
| main.rs:1708:29:1708:31 | rhs | | main.rs:1586:5:1591:5 | Vec2 |
| main.rs:1708:29:1708:33 | rhs.y | | {EXTERNAL LOCATION} | NonZero |
| main.rs:1708:29:1708:33 | rhs.y | | {EXTERNAL LOCATION} | i64 |
| main.rs:1708:29:1708:33 | rhs.y | T | {EXTERNAL LOCATION} | i64 |
| main.rs:1714:25:1714:33 | SelfParam | | file://:0:0:0:0 | & |
| main.rs:1714:25:1714:33 | SelfParam | &T | main.rs:1586:5:1591:5 | Vec2 |
| main.rs:1714:36:1714:38 | rhs | | main.rs:1586:5:1591:5 | Vec2 |
@@ -3532,9 +3684,13 @@ inferType
| main.rs:1857:26:1857:30 | 33i64 | | {EXTERNAL LOCATION} | i64 |
| main.rs:1857:26:1857:38 | ... & ... | | {EXTERNAL LOCATION} | i64 |
| main.rs:1857:34:1857:38 | 34i64 | | {EXTERNAL LOCATION} | i64 |
| main.rs:1858:13:1858:21 | i64_bitor | | {EXTERNAL LOCATION} | NonZero |
| main.rs:1858:13:1858:21 | i64_bitor | | {EXTERNAL LOCATION} | i64 |
| main.rs:1858:13:1858:21 | i64_bitor | T | {EXTERNAL LOCATION} | i64 |
| main.rs:1858:25:1858:29 | 35i64 | | {EXTERNAL LOCATION} | i64 |
| main.rs:1858:25:1858:37 | ... \| ... | | {EXTERNAL LOCATION} | NonZero |
| main.rs:1858:25:1858:37 | ... \| ... | | {EXTERNAL LOCATION} | i64 |
| main.rs:1858:25:1858:37 | ... \| ... | T | {EXTERNAL LOCATION} | i64 |
| main.rs:1858:33:1858:37 | 36i64 | | {EXTERNAL LOCATION} | i64 |
| main.rs:1859:13:1859:22 | i64_bitxor | | {EXTERNAL LOCATION} | i64 |
| main.rs:1859:26:1859:30 | 37i64 | | {EXTERNAL LOCATION} | i64 |
@@ -4922,89 +5078,49 @@ inferType
| main.rs:2566:26:2566:43 | "Nested boxed: {}\\n" | &T | {EXTERNAL LOCATION} | str |
| main.rs:2566:26:2566:59 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments |
| main.rs:2566:26:2566:59 | MacroExpr | | {EXTERNAL LOCATION} | Arguments |
| main.rs:2578:21:2578:25 | SelfParam | | file://:0:0:0:0 | & |
| main.rs:2578:21:2578:25 | SelfParam | &T | main.rs:2577:5:2580:5 | Self [trait Executor] |
| main.rs:2579:24:2579:28 | SelfParam | | file://:0:0:0:0 | & |
| main.rs:2579:24:2579:28 | SelfParam | &T | main.rs:2577:5:2580:5 | Self [trait Executor] |
| main.rs:2579:31:2579:35 | query | | main.rs:2579:21:2579:21 | E |
| main.rs:2583:21:2583:25 | SelfParam | | file://:0:0:0:0 | & |
| main.rs:2583:21:2583:25 | SelfParam | &T | main.rs:2582:10:2582:22 | T |
| main.rs:2584:22:2584:41 | "Executor::execute1\\n" | | file://:0:0:0:0 | & |
| main.rs:2584:22:2584:41 | "Executor::execute1\\n" | &T | {EXTERNAL LOCATION} | str |
| main.rs:2584:22:2584:41 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments |
| main.rs:2584:22:2584:41 | MacroExpr | | {EXTERNAL LOCATION} | Arguments |
| main.rs:2587:24:2587:28 | SelfParam | | file://:0:0:0:0 | & |
| main.rs:2587:24:2587:28 | SelfParam | &T | main.rs:2582:10:2582:22 | T |
| main.rs:2587:31:2587:36 | _query | | main.rs:2587:21:2587:21 | E |
| main.rs:2588:22:2588:41 | "Executor::execute2\\n" | | file://:0:0:0:0 | & |
| main.rs:2588:22:2588:41 | "Executor::execute2\\n" | &T | {EXTERNAL LOCATION} | str |
| main.rs:2588:22:2588:41 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments |
| main.rs:2588:22:2588:41 | MacroExpr | | {EXTERNAL LOCATION} | Arguments |
| main.rs:2597:13:2597:13 | c | | main.rs:2592:5:2592:29 | MySqlConnection |
| main.rs:2597:17:2597:34 | MySqlConnection {...} | | main.rs:2592:5:2592:29 | MySqlConnection |
| main.rs:2599:9:2599:9 | c | | main.rs:2592:5:2592:29 | MySqlConnection |
| main.rs:2600:35:2600:36 | &c | | file://:0:0:0:0 | & |
| main.rs:2600:35:2600:36 | &c | &T | main.rs:2592:5:2592:29 | MySqlConnection |
| main.rs:2600:36:2600:36 | c | | main.rs:2592:5:2592:29 | MySqlConnection |
| main.rs:2602:9:2602:9 | c | | main.rs:2592:5:2592:29 | MySqlConnection |
| main.rs:2602:20:2602:40 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
| main.rs:2602:20:2602:40 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
| main.rs:2603:9:2603:9 | c | | main.rs:2592:5:2592:29 | MySqlConnection |
| main.rs:2603:28:2603:48 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
| main.rs:2603:28:2603:48 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
| main.rs:2604:35:2604:36 | &c | | file://:0:0:0:0 | & |
| main.rs:2604:35:2604:36 | &c | &T | main.rs:2592:5:2592:29 | MySqlConnection |
| main.rs:2604:36:2604:36 | c | | main.rs:2592:5:2592:29 | MySqlConnection |
| main.rs:2604:39:2604:59 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
| main.rs:2604:39:2604:59 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
| main.rs:2605:43:2605:44 | &c | | file://:0:0:0:0 | & |
| main.rs:2605:43:2605:44 | &c | &T | main.rs:2592:5:2592:29 | MySqlConnection |
| main.rs:2605:44:2605:44 | c | | main.rs:2592:5:2592:29 | MySqlConnection |
| main.rs:2605:47:2605:67 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
| main.rs:2605:47:2605:67 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
| main.rs:2615:36:2617:9 | { ... } | | main.rs:2612:5:2612:22 | Path |
| main.rs:2616:13:2616:19 | Path {...} | | main.rs:2612:5:2612:22 | Path |
| main.rs:2619:29:2619:33 | SelfParam | | file://:0:0:0:0 | & |
| main.rs:2619:29:2619:33 | SelfParam | &T | main.rs:2612:5:2612:22 | Path |
| main.rs:2619:59:2621:9 | { ... } | | {EXTERNAL LOCATION} | Result |
| main.rs:2619:59:2621:9 | { ... } | E | file://:0:0:0:0 | () |
| main.rs:2619:59:2621:9 | { ... } | T | main.rs:2624:5:2624:25 | PathBuf |
| main.rs:2620:13:2620:30 | Ok(...) | | {EXTERNAL LOCATION} | Result |
| main.rs:2620:13:2620:30 | Ok(...) | E | file://:0:0:0:0 | () |
| main.rs:2620:13:2620:30 | Ok(...) | T | main.rs:2624:5:2624:25 | PathBuf |
| main.rs:2620:16:2620:29 | ...::new(...) | | main.rs:2624:5:2624:25 | PathBuf |
| main.rs:2627:39:2629:9 | { ... } | | main.rs:2624:5:2624:25 | PathBuf |
| main.rs:2628:13:2628:22 | PathBuf {...} | | main.rs:2624:5:2624:25 | PathBuf |
| main.rs:2637:18:2637:22 | SelfParam | | file://:0:0:0:0 | & |
| main.rs:2637:18:2637:22 | SelfParam | &T | main.rs:2624:5:2624:25 | PathBuf |
| main.rs:2637:34:2641:9 | { ... } | | file://:0:0:0:0 | & |
| main.rs:2637:34:2641:9 | { ... } | &T | main.rs:2612:5:2612:22 | Path |
| main.rs:2639:33:2639:43 | ...::new(...) | | main.rs:2612:5:2612:22 | Path |
| main.rs:2640:13:2640:17 | &path | | file://:0:0:0:0 | & |
| main.rs:2640:13:2640:17 | &path | &T | main.rs:2612:5:2612:22 | Path |
| main.rs:2640:14:2640:17 | path | | main.rs:2612:5:2612:22 | Path |
| main.rs:2645:13:2645:17 | path1 | | main.rs:2612:5:2612:22 | Path |
| main.rs:2645:21:2645:31 | ...::new(...) | | main.rs:2612:5:2612:22 | Path |
| main.rs:2646:13:2646:17 | path2 | | {EXTERNAL LOCATION} | Result |
| main.rs:2646:13:2646:17 | path2 | E | file://:0:0:0:0 | () |
| main.rs:2646:13:2646:17 | path2 | T | main.rs:2624:5:2624:25 | PathBuf |
| main.rs:2646:21:2646:25 | path1 | | main.rs:2612:5:2612:22 | Path |
| main.rs:2646:21:2646:40 | path1.canonicalize() | | {EXTERNAL LOCATION} | Result |
| main.rs:2646:21:2646:40 | path1.canonicalize() | E | file://:0:0:0:0 | () |
| main.rs:2646:21:2646:40 | path1.canonicalize() | T | main.rs:2624:5:2624:25 | PathBuf |
| main.rs:2647:13:2647:17 | path3 | | main.rs:2624:5:2624:25 | PathBuf |
| main.rs:2647:21:2647:25 | path2 | | {EXTERNAL LOCATION} | Result |
| main.rs:2647:21:2647:25 | path2 | E | file://:0:0:0:0 | () |
| main.rs:2647:21:2647:25 | path2 | T | main.rs:2624:5:2624:25 | PathBuf |
| main.rs:2647:21:2647:34 | path2.unwrap() | | main.rs:2624:5:2624:25 | PathBuf |
| main.rs:2649:13:2649:20 | pathbuf1 | | main.rs:2624:5:2624:25 | PathBuf |
| main.rs:2649:24:2649:37 | ...::new(...) | | main.rs:2624:5:2624:25 | PathBuf |
| main.rs:2650:24:2650:31 | pathbuf1 | | main.rs:2624:5:2624:25 | PathBuf |
| main.rs:2661:5:2661:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo |
| main.rs:2662:5:2662:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo |
| main.rs:2662:20:2662:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo |
| main.rs:2662:41:2662:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo |
| main.rs:2678:5:2678:15 | ...::f(...) | | {EXTERNAL LOCATION} | trait Future |
| main.rs:2578:36:2580:9 | { ... } | | main.rs:2575:5:2575:22 | Path |
| main.rs:2579:13:2579:19 | Path {...} | | main.rs:2575:5:2575:22 | Path |
| main.rs:2582:29:2582:33 | SelfParam | | file://:0:0:0:0 | & |
| main.rs:2582:29:2582:33 | SelfParam | &T | main.rs:2575:5:2575:22 | Path |
| main.rs:2582:59:2584:9 | { ... } | | {EXTERNAL LOCATION} | Result |
| main.rs:2582:59:2584:9 | { ... } | E | file://:0:0:0:0 | () |
| main.rs:2582:59:2584:9 | { ... } | T | main.rs:2587:5:2587:25 | PathBuf |
| main.rs:2583:13:2583:30 | Ok(...) | | {EXTERNAL LOCATION} | Result |
| main.rs:2583:13:2583:30 | Ok(...) | E | file://:0:0:0:0 | () |
| main.rs:2583:13:2583:30 | Ok(...) | T | main.rs:2587:5:2587:25 | PathBuf |
| main.rs:2583:16:2583:29 | ...::new(...) | | main.rs:2587:5:2587:25 | PathBuf |
| main.rs:2590:39:2592:9 | { ... } | | main.rs:2587:5:2587:25 | PathBuf |
| main.rs:2591:13:2591:22 | PathBuf {...} | | main.rs:2587:5:2587:25 | PathBuf |
| main.rs:2600:18:2600:22 | SelfParam | | file://:0:0:0:0 | & |
| main.rs:2600:18:2600:22 | SelfParam | &T | main.rs:2587:5:2587:25 | PathBuf |
| main.rs:2600:34:2604:9 | { ... } | | file://:0:0:0:0 | & |
| main.rs:2600:34:2604:9 | { ... } | &T | main.rs:2575:5:2575:22 | Path |
| main.rs:2602:33:2602:43 | ...::new(...) | | main.rs:2575:5:2575:22 | Path |
| main.rs:2603:13:2603:17 | &path | | file://:0:0:0:0 | & |
| main.rs:2603:13:2603:17 | &path | &T | main.rs:2575:5:2575:22 | Path |
| main.rs:2603:14:2603:17 | path | | main.rs:2575:5:2575:22 | Path |
| main.rs:2608:13:2608:17 | path1 | | main.rs:2575:5:2575:22 | Path |
| main.rs:2608:21:2608:31 | ...::new(...) | | main.rs:2575:5:2575:22 | Path |
| main.rs:2609:13:2609:17 | path2 | | {EXTERNAL LOCATION} | Result |
| main.rs:2609:13:2609:17 | path2 | E | file://:0:0:0:0 | () |
| main.rs:2609:13:2609:17 | path2 | T | main.rs:2587:5:2587:25 | PathBuf |
| main.rs:2609:21:2609:25 | path1 | | main.rs:2575:5:2575:22 | Path |
| main.rs:2609:21:2609:40 | path1.canonicalize() | | {EXTERNAL LOCATION} | Result |
| main.rs:2609:21:2609:40 | path1.canonicalize() | E | file://:0:0:0:0 | () |
| main.rs:2609:21:2609:40 | path1.canonicalize() | T | main.rs:2587:5:2587:25 | PathBuf |
| main.rs:2610:13:2610:17 | path3 | | main.rs:2587:5:2587:25 | PathBuf |
| main.rs:2610:21:2610:25 | path2 | | {EXTERNAL LOCATION} | Result |
| main.rs:2610:21:2610:25 | path2 | E | file://:0:0:0:0 | () |
| main.rs:2610:21:2610:25 | path2 | T | main.rs:2587:5:2587:25 | PathBuf |
| main.rs:2610:21:2610:34 | path2.unwrap() | | main.rs:2587:5:2587:25 | PathBuf |
| main.rs:2612:13:2612:20 | pathbuf1 | | main.rs:2587:5:2587:25 | PathBuf |
| main.rs:2612:24:2612:37 | ...::new(...) | | main.rs:2587:5:2587:25 | PathBuf |
| main.rs:2613:24:2613:31 | pathbuf1 | | main.rs:2587:5:2587:25 | PathBuf |
| main.rs:2625:5:2625:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo |
| main.rs:2626:5:2626:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo |
| main.rs:2626:20:2626:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo |
| main.rs:2626:41:2626:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo |
| main.rs:2642:5:2642:15 | ...::f(...) | | {EXTERNAL LOCATION} | trait Future |
| pattern_matching.rs:13:26:133:1 | { ... } | | {EXTERNAL LOCATION} | Option |
| pattern_matching.rs:13:26:133:1 | { ... } | T | file://:0:0:0:0 | () |
| pattern_matching.rs:14:9:14:13 | value | | {EXTERNAL LOCATION} | Option |

View File

@@ -18,30 +18,31 @@ edges
| src/main.rs:7:11:7:19 | file_name | src/main.rs:9:35:9:43 | file_name | provenance | |
| 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:13 |
| 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: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:44 | file_path.canonicalize() [Ok] | provenance | Config |
| 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:12 |
| 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:44 | file_path.canonicalize() [Ok] | src/main.rs:53:21:53:53 | ... .unwrap() | provenance | MaD:11 |
| 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: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:12 |
| 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: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: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:44 | file_path.canonicalize() [Ok] | provenance | Config |
| 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:12 |
| 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: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:44 | file_path.canonicalize() [Ok] | src/main.rs:98:21:98:53 | ... .unwrap() | provenance | MaD:11 |
| src/main.rs:98:21:98:44 | file_path.canonicalize() [Ok] | src/main.rs:98:21:98:53 | ... .unwrap() | provenance | MaD:12 |
| src/main.rs:98:21:98:53 | ... .unwrap() | src/main.rs:98:9:98:17 | file_path | provenance | |
| src/main.rs:99:24:99:32 | file_path | src/main.rs:99:5:99:22 | ...::read_to_string | provenance | MaD:6 Sink:MaD:6 |
| src/main.rs:103:9:103:13 | path1 | src/main.rs:104:33:104:37 | path1 | provenance | |
@@ -58,39 +59,39 @@ edges
| src/main.rs:103:9:103:13 | path1 | src/main.rs:123:37:123:41 | path1 | provenance | |
| src/main.rs:103:9:103:13 | path1 | src/main.rs:123:37:123:49 | path1.clone() | provenance | MaD:8 |
| src/main.rs:103:17:103:30 | ...::args | src/main.rs:103:17:103:32 | ...::args(...) [element] | provenance | Src:MaD:7 |
| src/main.rs:103:17:103:32 | ...::args(...) [element] | src/main.rs:103:17:103:39 | ... .nth(...) [Some] | provenance | MaD:9 |
| src/main.rs:103:17:103:39 | ... .nth(...) [Some] | src/main.rs:103:17:103:48 | ... .unwrap() | provenance | MaD:10 |
| src/main.rs:103:17:103:32 | ...::args(...) [element] | src/main.rs:103:17:103:39 | ... .nth(...) [Some] | provenance | MaD:10 |
| src/main.rs:103:17:103:39 | ... .nth(...) [Some] | src/main.rs:103:17:103:48 | ... .unwrap() | provenance | MaD:11 |
| src/main.rs:103:17:103:48 | ... .unwrap() | src/main.rs:103:9:103:13 | path1 | provenance | |
| src/main.rs:104:33:104:37 | path1 | src/main.rs:104:33:104:45 | path1.clone() | provenance | MaD:8 |
| src/main.rs:104:33:104:45 | path1.clone() | src/main.rs:104:13:104:31 | ...::open | provenance | MaD:2 Sink:MaD:2 |
| src/main.rs:106:9:106:13 | path2 | src/main.rs:107:33:107:37 | path2 | provenance | |
| src/main.rs:106:17:106:52 | ...::canonicalize(...) [Ok] | src/main.rs:106:17:106:61 | ... .unwrap() | provenance | MaD:11 |
| src/main.rs:106:17:106:52 | ...::canonicalize(...) [Ok] | src/main.rs:106:17:106:61 | ... .unwrap() | provenance | MaD:12 |
| src/main.rs:106:17:106:61 | ... .unwrap() | src/main.rs:106:9:106:13 | path2 | provenance | |
| src/main.rs:106:39:106:43 | path1 | src/main.rs:106:39:106:51 | path1.clone() | provenance | MaD:8 |
| src/main.rs:106:39:106:51 | path1.clone() | src/main.rs:106:17:106:52 | ...::canonicalize(...) [Ok] | provenance | Config |
| src/main.rs:107:33:107:37 | path2 | src/main.rs:107:13:107:31 | ...::open | provenance | MaD:2 Sink:MaD:2 |
| src/main.rs:109:9:109:13 | path3 | src/main.rs:110:35:110:39 | path3 | provenance | |
| src/main.rs:109:17:109:54 | ...::canonicalize(...) [future, Ok] | src/main.rs:109:17:109:60 | await ... [Ok] | provenance | |
| src/main.rs:109:17:109:60 | await ... [Ok] | src/main.rs:109:17:109:69 | ... .unwrap() | provenance | MaD:11 |
| src/main.rs:109:17:109:60 | await ... [Ok] | src/main.rs:109:17:109:69 | ... .unwrap() | provenance | MaD:12 |
| src/main.rs:109:17:109:69 | ... .unwrap() | src/main.rs:109:9:109:13 | path3 | provenance | |
| src/main.rs:109:41:109:45 | path1 | src/main.rs:109:41:109:53 | path1.clone() | provenance | MaD:8 |
| src/main.rs:109:41:109:53 | path1.clone() | src/main.rs:109:17:109:54 | ...::canonicalize(...) [future, Ok] | provenance | Config |
| src/main.rs:110:35:110:39 | path3 | src/main.rs:110:13:110:33 | ...::open | provenance | MaD:4 Sink:MaD:4 |
| src/main.rs:112:9:112:13 | path4 | src/main.rs:113:39:113:43 | path4 | provenance | |
| src/main.rs:112:17:112:58 | ...::canonicalize(...) [future, Ok] | src/main.rs:112:17:112:64 | await ... [Ok] | provenance | |
| src/main.rs:112:17:112:64 | await ... [Ok] | src/main.rs:112:17:112:73 | ... .unwrap() | provenance | MaD:11 |
| src/main.rs:112:17:112:64 | await ... [Ok] | src/main.rs:112:17:112:73 | ... .unwrap() | provenance | MaD:12 |
| src/main.rs:112:17:112:73 | ... .unwrap() | src/main.rs:112:9:112:13 | path4 | provenance | |
| src/main.rs:112:45:112:49 | path1 | src/main.rs:112:45:112:57 | path1.clone() | provenance | MaD:8 |
| src/main.rs:112:45:112:57 | path1.clone() | src/main.rs:112:17:112:58 | ...::canonicalize(...) [future, Ok] | provenance | Config |
| 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:12 |
| 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: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:36 | path5.canonicalize() [Ok] | provenance | Config |
| src/main.rs:118:9:118:13 | path6 | src/main.rs:119:33:119:37 | path6 | provenance | |
| src/main.rs:118:17:118:36 | path5.canonicalize() [Ok] | src/main.rs:118:17:118:45 | ... .unwrap() | provenance | MaD:11 |
| src/main.rs:118:17:118:36 | path5.canonicalize() [Ok] | src/main.rs:118:17:118:45 | ... .unwrap() | provenance | MaD:12 |
| src/main.rs:118:17:118:45 | ... .unwrap() | src/main.rs:118:9:118:13 | path6 | provenance | |
| src/main.rs:119:33:119:37 | path6 | src/main.rs:119:13:119:31 | ...::open | provenance | MaD:2 Sink:MaD:2 |
| src/main.rs:122:27:122:31 | path1 | src/main.rs:122:27:122:39 | path1.clone() | provenance | MaD:8 |
@@ -101,15 +102,15 @@ 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:12 |
| 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: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 |
| src/main.rs:177:36:177:39 | path [&ref] | src/main.rs:177:25:177:34 | ...::open | provenance | MaD:2 Sink:MaD:2 |
| src/main.rs:185:9:185:13 | path1 | src/main.rs:186:18:186:22 | path1 | provenance | |
| src/main.rs:185:17:185:30 | ...::args | src/main.rs:185:17:185:32 | ...::args(...) [element] | provenance | Src:MaD:7 |
| src/main.rs:185:17:185:32 | ...::args(...) [element] | src/main.rs:185:17:185:39 | ... .nth(...) [Some] | provenance | MaD:9 |
| src/main.rs:185:17:185:39 | ... .nth(...) [Some] | src/main.rs:185:17:185:48 | ... .unwrap() | provenance | MaD:10 |
| src/main.rs:185:17:185:32 | ...::args(...) [element] | src/main.rs:185:17:185:39 | ... .nth(...) [Some] | provenance | MaD:10 |
| src/main.rs:185:17:185:39 | ... .nth(...) [Some] | src/main.rs:185:17:185:48 | ... .unwrap() | provenance | MaD:11 |
| src/main.rs:185:17:185:48 | ... .unwrap() | src/main.rs:185:9:185:13 | path1 | provenance | |
| src/main.rs:186:17:186:22 | &path1 [&ref] | src/main.rs:170:16:170:29 | ...: ... [&ref] | provenance | |
| src/main.rs:186:18:186:22 | path1 | src/main.rs:186:17:186:22 | &path1 [&ref] | provenance | |
@@ -122,11 +123,12 @@ models
| 6 | Sink: std::fs::read_to_string; Argument[0]; path-injection |
| 7 | Source: std::env::args; ReturnValue.Element; commandargs |
| 8 | Summary: <_ as core::clone::Clone>::clone; Argument[self].Reference; ReturnValue; value |
| 9 | Summary: <_ as core::iter::traits::iterator::Iterator>::nth; Argument[self].Element; ReturnValue.Field[core::option::Option::Some(0)]; value |
| 10 | Summary: <core::option::Option>::unwrap; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value |
| 11 | Summary: <core::result::Result>::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value |
| 12 | Summary: <std::path::Path>::new; Argument[0].Reference; ReturnValue.Reference; value |
| 13 | Summary: <std::path::PathBuf as core::convert::From>::from; Argument[0]; ReturnValue; value |
| 9 | Summary: <_ as core::convert::From>::from; Argument[0]; ReturnValue; value |
| 10 | Summary: <_ as core::iter::traits::iterator::Iterator>::nth; Argument[self].Element; ReturnValue.Field[core::option::Option::Some(0)]; value |
| 11 | Summary: <core::option::Option>::unwrap; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value |
| 12 | Summary: <core::result::Result>::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value |
| 13 | Summary: <std::path::Path>::new; Argument[0].Reference; ReturnValue.Reference; value |
| 14 | Summary: <std::path::PathBuf as core::convert::From>::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 |

View File

@@ -12,12 +12,14 @@ multipleCallTargets
| sqlx.rs:67:26:67:48 | unsafe_query_1.as_str() |
| sqlx.rs:69:30:69:52 | unsafe_query_2.as_str() |
| sqlx.rs:70:30:70:52 | unsafe_query_3.as_str() |
| sqlx.rs:71:30:71:52 | unsafe_query_4.as_str() |
| sqlx.rs:75:25:75:45 | safe_query_1.as_str() |
| sqlx.rs:76:25:76:45 | safe_query_2.as_str() |
| sqlx.rs:77:25:77:45 | safe_query_3.as_str() |
| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() |
| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() |
| sqlx.rs:81:29:81:51 | unsafe_query_3.as_str() |
| sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() |
| sqlx.rs:84:25:84:49 | prepared_query_1.as_str() |
| sqlx.rs:85:25:85:49 | prepared_query_1.as_str() |
| sqlx.rs:87:29:87:53 | prepared_query_1.as_str() |

View File

@@ -2,6 +2,7 @@
| sqlx.rs:77:13:77:23 | ...::query | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:77:13:77:23 | ...::query | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value |
| sqlx.rs:78:13:78:23 | ...::query | sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:78:13:78:23 | ...::query | This query depends on a $@. | sqlx.rs:47:22:47:35 | ...::args | user-provided value |
| sqlx.rs:80:17:80:27 | ...::query | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:80:17:80:27 | ...::query | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value |
| sqlx.rs:82:17:82:27 | ...::query | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:82:17:82:27 | ...::query | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value |
edges
| sqlx.rs:47:9:47:18 | arg_string | sqlx.rs:53:27:53:36 | arg_string | provenance | |
| sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:47:22:47:37 | ...::args(...) [element] | provenance | Src:MaD:3 |
@@ -11,6 +12,7 @@ edges
| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | provenance | MaD:10 |
| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | provenance | MaD:10 |
| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:54:27:54:39 | remote_string | provenance | |
| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:59:17:59:72 | MacroExpr | provenance | |
| sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | provenance | Src:MaD:2 |
| sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | sqlx.rs:48:25:48:78 | ... .unwrap() | provenance | MaD:7 |
| sqlx.rs:48:25:48:78 | ... .unwrap() | sqlx.rs:48:25:48:85 | ... .text() [Ok] | provenance | MaD:11 |
@@ -38,6 +40,15 @@ edges
| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | provenance | MaD:9 |
| sqlx.rs:54:26:54:39 | &remote_string [&ref] | sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | provenance | |
| sqlx.rs:54:27:54:39 | remote_string | sqlx.rs:54:26:54:39 | &remote_string [&ref] | provenance | |
| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:82:29:82:42 | unsafe_query_4 | provenance | |
| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | provenance | MaD:9 |
| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | provenance | MaD:5 |
| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | provenance | MaD:9 |
| sqlx.rs:59:9:59:15 | res | sqlx.rs:59:17:59:72 | { ... } | provenance | |
| sqlx.rs:59:17:59:72 | ...::format(...) | sqlx.rs:59:9:59:15 | res | provenance | |
| sqlx.rs:59:17:59:72 | ...::must_use(...) | sqlx.rs:56:9:56:22 | unsafe_query_4 | provenance | |
| sqlx.rs:59:17:59:72 | MacroExpr | sqlx.rs:59:17:59:72 | ...::format(...) | provenance | MaD:12 |
| sqlx.rs:59:17:59:72 | { ... } | sqlx.rs:59:17:59:72 | ...::must_use(...) | provenance | MaD:13 |
| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | provenance | MaD:9 |
| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | provenance | MaD:5 |
| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | provenance | MaD:9 |
@@ -45,6 +56,11 @@ edges
| sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | sqlx.rs:77:13:77:23 | ...::query | provenance | MaD:1 Sink:MaD:1 |
| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | sqlx.rs:78:13:78:23 | ...::query | provenance | MaD:1 Sink:MaD:1 |
| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | sqlx.rs:80:17:80:27 | ...::query | provenance | MaD:1 Sink:MaD:1 |
| sqlx.rs:82:29:82:42 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() [&ref] | provenance | MaD:9 |
| sqlx.rs:82:29:82:42 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() [&ref] | provenance | MaD:5 |
| sqlx.rs:82:29:82:42 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() [&ref] | provenance | MaD:9 |
| sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | sqlx.rs:82:17:82:27 | ...::query | provenance | MaD:1 Sink:MaD:1 |
| sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() [&ref] | sqlx.rs:82:17:82:27 | ...::query | provenance | MaD:1 Sink:MaD:1 |
models
| 1 | Sink: sqlx_core::query::query; Argument[0]; sql-injection |
| 2 | Source: reqwest::blocking::get; ReturnValue.Field[core::result::Result::Ok(0)]; remote |
@@ -86,6 +102,12 @@ nodes
| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | semmle.label | unsafe_query_2 [&ref] |
| sqlx.rs:54:26:54:39 | &remote_string [&ref] | semmle.label | &remote_string [&ref] |
| sqlx.rs:54:27:54:39 | remote_string | semmle.label | remote_string |
| sqlx.rs:56:9:56:22 | unsafe_query_4 | semmle.label | unsafe_query_4 |
| sqlx.rs:59:9:59:15 | res | semmle.label | res |
| sqlx.rs:59:17:59:72 | ...::format(...) | semmle.label | ...::format(...) |
| sqlx.rs:59:17:59:72 | ...::must_use(...) | semmle.label | ...::must_use(...) |
| sqlx.rs:59:17:59:72 | MacroExpr | semmle.label | MacroExpr |
| sqlx.rs:59:17:59:72 | { ... } | semmle.label | { ... } |
| sqlx.rs:77:13:77:23 | ...::query | semmle.label | ...::query |
| sqlx.rs:77:25:77:36 | safe_query_3 | semmle.label | safe_query_3 |
| sqlx.rs:77:25:77:45 | safe_query_3.as_str() | semmle.label | safe_query_3.as_str() |
@@ -94,4 +116,8 @@ nodes
| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | semmle.label | unsafe_query_1.as_str() [&ref] |
| sqlx.rs:80:17:80:27 | ...::query | semmle.label | ...::query |
| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | semmle.label | unsafe_query_2.as_str() [&ref] |
| sqlx.rs:82:17:82:27 | ...::query | semmle.label | ...::query |
| sqlx.rs:82:29:82:42 | unsafe_query_4 | semmle.label | unsafe_query_4 |
| sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | semmle.label | unsafe_query_4.as_str() |
| sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() [&ref] | semmle.label | unsafe_query_4.as_str() [&ref] |
subpaths

View File

@@ -79,7 +79,7 @@ async fn test_sqlx_mysql(url: &str, enable_remote: bool) -> Result<(), sqlx::Err
if enable_remote {
let _ = sqlx::query(unsafe_query_2.as_str()).execute(&pool).await?; // $ sql-sink Alert[rust/sql-injection]=remote1
let _ = sqlx::query(unsafe_query_3.as_str()).execute(&pool).await?; // $ sql-sink MISSING: Alert[rust/sql-injection]=remote1
let _ = sqlx::query(unsafe_query_4.as_str()).execute(&pool).await?; // $ sql-sink MISSING: Alert[rust/sql-injection]=remote1
let _ = sqlx::query(unsafe_query_4.as_str()).execute(&pool).await?; // $ sql-sink Alert[rust/sql-injection]=remote1
}
let _ = sqlx::query(prepared_query_1.as_str()).bind(const_string).execute(&pool).await?; // $ sql-sink
let _ = sqlx::query(prepared_query_1.as_str()).bind(arg_string).execute(&pool).await?; // $ sql-sink

View File

@@ -51,10 +51,10 @@ edges
| main.rs:33:50:33:57 | password | main.rs:33:23:33:57 | MacroExpr | provenance | |
| main.rs:35:33:35:35 | url | main.rs:35:12:35:18 | request | provenance | MaD:2 Sink:MaD:2 |
models
| 1 | Sink: <reqwest::async_impl::client::Client>::post; Argument[0]; transmission |
| 2 | Sink: <reqwest::async_impl::client::Client>::request; Argument[1]; transmission |
| 3 | Sink: <reqwest::blocking::client::Client>::request; Argument[1]; transmission |
| 4 | Sink: reqwest::blocking::get; Argument[0]; transmission |
| 1 | Sink: <reqwest::async_impl::client::Client>::post; Argument[0]; request-url |
| 2 | Sink: <reqwest::async_impl::client::Client>::request; Argument[1]; request-url |
| 3 | Sink: <reqwest::blocking::client::Client>::request; Argument[1]; request-url |
| 4 | Sink: reqwest::blocking::get; Argument[0]; request-url |
| 5 | Summary: <core::result::Result>::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value |
| 6 | Summary: <url::Url>::parse; Argument[0].Reference; ReturnValue.Field[core::result::Result::Ok(0)]; taint |
| 7 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint |

View File

@@ -12,60 +12,87 @@
| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:51:31:51:48 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:51:31:51:48 | ...::new | a key |
| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:51:31:51:48 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:51:31:51:48 | ...::new | a key |
| test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:74:23:74:44 | ...::new_from_slice | This hard-coded value is used as $@. | test_cipher.rs:74:23:74:44 | ...::new_from_slice | a key |
| test_cookie.rs:17:29:17:29 | 0 | test_cookie.rs:17:29:17:29 | 0 | test_cookie.rs:18:16:18:24 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:18:16:18:24 | ...::from | a key |
| test_cookie.rs:21:29:21:29 | 0 | test_cookie.rs:21:29:21:29 | 0 | test_cookie.rs:22:16:22:24 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:22:16:22:24 | ...::from | a key |
| test_cookie.rs:38:29:38:31 | 0u8 | test_cookie.rs:38:29:38:31 | 0u8 | test_cookie.rs:42:14:42:32 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:42:14:42:32 | ...::from | a key |
| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:53:14:53:32 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:53:14:53:32 | ...::from | a key |
edges
| test_cipher.rs:18:9:18:14 | const1 [&ref, element] | test_cipher.rs:19:73:19:78 | const1 [&ref, element] | provenance | |
| test_cipher.rs:18:28:18:36 | &... [&ref, element] | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | provenance | |
| test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | test_cipher.rs:18:28:18:36 | &... [&ref, element] | provenance | |
| test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | provenance | |
| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:2 Sink:MaD:2 Sink:MaD:2 |
| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:4 Sink:MaD:4 Sink:MaD:4 |
| test_cipher.rs:19:73:19:78 | const1 [&ref, element] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | provenance | MaD:7 |
| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 |
| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 |
| test_cipher.rs:19:73:19:78 | const1 [&ref, element] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 |
| test_cipher.rs:25:9:25:14 | const4 [&ref, element] | test_cipher.rs:26:66:26:71 | const4 [&ref, element] | provenance | |
| test_cipher.rs:25:28:25:36 | &... [&ref, element] | test_cipher.rs:25:9:25:14 | const4 [&ref, element] | provenance | |
| test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | test_cipher.rs:25:28:25:36 | &... [&ref, element] | provenance | |
| test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | provenance | |
| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:2 Sink:MaD:2 Sink:MaD:2 |
| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:4 Sink:MaD:4 Sink:MaD:4 |
| test_cipher.rs:26:66:26:71 | const4 [&ref, element] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | provenance | MaD:7 |
| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 |
| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 |
| test_cipher.rs:26:66:26:71 | const4 [&ref, element] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 |
| test_cipher.rs:29:9:29:14 | const5 [&ref, element] | test_cipher.rs:30:95:30:100 | const5 [&ref, element] | provenance | |
| test_cipher.rs:29:28:29:36 | &... [&ref, element] | test_cipher.rs:29:9:29:14 | const5 [&ref, element] | provenance | |
| test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | test_cipher.rs:29:28:29:36 | &... [&ref, element] | provenance | |
| test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | provenance | |
| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 |
| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 |
| test_cipher.rs:30:95:30:100 | const5 [&ref, element] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | provenance | MaD:7 |
| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:4 Sink:MaD:4 Sink:MaD:4 |
| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:6 Sink:MaD:6 Sink:MaD:6 |
| test_cipher.rs:30:95:30:100 | const5 [&ref, element] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 |
| test_cipher.rs:37:9:37:14 | const7 | test_cipher.rs:38:74:38:79 | const7 | provenance | |
| test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:9:37:14 | const7 | provenance | |
| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:2 Sink:MaD:2 |
| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:4 Sink:MaD:4 |
| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:7 |
| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:3 Sink:MaD:3 |
| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:5 Sink:MaD:5 |
| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:10 |
| test_cipher.rs:38:74:38:79 | const7 | test_cipher.rs:38:73:38:79 | &const7 [&ref] | provenance | |
| test_cipher.rs:41:9:41:14 | const8 [&ref] | test_cipher.rs:42:73:42:78 | const8 [&ref] | provenance | |
| test_cipher.rs:41:28:41:76 | &... [&ref] | test_cipher.rs:41:9:41:14 | const8 [&ref] | provenance | |
| test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:28:41:76 | &... [&ref] | provenance | |
| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:2 Sink:MaD:2 |
| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:4 Sink:MaD:4 |
| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:7 |
| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:3 Sink:MaD:3 |
| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:5 Sink:MaD:5 |
| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:10 |
| test_cipher.rs:50:9:50:15 | const10 [element] | test_cipher.rs:51:75:51:81 | const10 [element] | provenance | |
| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | provenance | Src:MaD:6 |
| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | provenance | Src:MaD:8 |
| test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | test_cipher.rs:50:9:50:15 | const10 [element] | provenance | |
| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:2 Sink:MaD:2 Sink:MaD:2 |
| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:4 Sink:MaD:4 Sink:MaD:4 |
| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:7 |
| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 |
| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 |
| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 |
| test_cipher.rs:51:75:51:81 | const10 [element] | test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | provenance | |
| test_cipher.rs:73:9:73:14 | const2 [&ref, element] | test_cipher.rs:74:46:74:51 | const2 [&ref, element] | provenance | |
| test_cipher.rs:73:18:73:26 | &... [&ref, element] | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | provenance | |
| test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | test_cipher.rs:73:18:73:26 | &... [&ref, element] | provenance | |
| test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | provenance | |
| test_cipher.rs:74:46:74:51 | const2 [&ref, element] | test_cipher.rs:74:23:74:44 | ...::new_from_slice | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 |
| test_cookie.rs:17:9:17:14 | array1 [element] | test_cookie.rs:18:27:18:32 | array1 [element] | provenance | |
| test_cookie.rs:17:28:17:34 | [0; 64] [element] | test_cookie.rs:17:9:17:14 | array1 [element] | provenance | |
| test_cookie.rs:17:29:17:29 | 0 | test_cookie.rs:17:28:17:34 | [0; 64] [element] | provenance | |
| test_cookie.rs:18:26:18:32 | &array1 [&ref, element] | test_cookie.rs:18:16:18:24 | ...::from | provenance | MaD:7 Sink:MaD:7 |
| test_cookie.rs:18:27:18:32 | array1 [element] | test_cookie.rs:18:26:18:32 | &array1 [&ref, element] | provenance | |
| test_cookie.rs:21:9:21:14 | array2 [element] | test_cookie.rs:22:27:22:32 | array2 [element] | provenance | |
| test_cookie.rs:21:28:21:34 | [0; 64] [element] | test_cookie.rs:21:9:21:14 | array2 [element] | provenance | |
| test_cookie.rs:21:29:21:29 | 0 | test_cookie.rs:21:28:21:34 | [0; 64] [element] | provenance | |
| test_cookie.rs:22:26:22:32 | &array2 [&ref, element] | test_cookie.rs:22:16:22:24 | ...::from | provenance | MaD:7 Sink:MaD:7 |
| test_cookie.rs:22:27:22:32 | array2 [element] | test_cookie.rs:22:26:22:32 | &array2 [&ref, element] | provenance | |
| test_cookie.rs:38:9:38:14 | array2 [element] | test_cookie.rs:42:34:42:39 | array2 [element] | provenance | |
| test_cookie.rs:38:18:38:37 | ...::from(...) [element] | test_cookie.rs:38:9:38:14 | array2 [element] | provenance | |
| test_cookie.rs:38:28:38:36 | [0u8; 64] [element] | test_cookie.rs:38:18:38:37 | ...::from(...) [element] | provenance | MaD:9 |
| test_cookie.rs:38:29:38:31 | 0u8 | test_cookie.rs:38:28:38:36 | [0u8; 64] [element] | provenance | |
| test_cookie.rs:42:34:42:39 | array2 [element] | test_cookie.rs:42:14:42:32 | ...::from | provenance | MaD:2 Sink:MaD:2 |
| test_cookie.rs:49:9:49:14 | array3 [element] | test_cookie.rs:53:34:53:39 | array3 [element] | provenance | |
| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | provenance | MaD:11 |
| test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | test_cookie.rs:49:9:49:14 | array3 [element] | provenance | |
| test_cookie.rs:53:34:53:39 | array3 [element] | test_cookie.rs:53:14:53:32 | ...::from | provenance | MaD:2 Sink:MaD:2 |
models
| 1 | Sink: <_ as crypto_common::KeyInit>::new_from_slice; Argument[0]; credentials-key |
| 2 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyInit>::new; Argument[0]; credentials-key |
| 3 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyInit>::new; Argument[1]; credentials-iv |
| 4 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyIvInit>::new; Argument[0]; credentials-key |
| 5 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyIvInit>::new; Argument[1]; credentials-iv |
| 6 | Source: core::mem::zeroed; ReturnValue.Element; constant-source |
| 7 | Summary: <generic_array::GenericArray>::from_slice; Argument[0].Reference; ReturnValue.Reference; value |
| 2 | Sink: <biscotti::crypto::master::Key>::from; Argument[0]; credentials-key |
| 3 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyInit>::new; Argument[0]; credentials-key |
| 4 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyInit>::new; Argument[1]; credentials-iv |
| 5 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyIvInit>::new; Argument[0]; credentials-key |
| 6 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyIvInit>::new; Argument[1]; credentials-iv |
| 7 | Sink: <cookie::secure::key::Key>::from; Argument[0].Reference; credentials-key |
| 8 | Source: core::mem::zeroed; ReturnValue.Element; constant-source |
| 9 | Summary: <_ as core::convert::From>::from; Argument[0]; ReturnValue; value |
| 10 | Summary: <generic_array::GenericArray>::from_slice; Argument[0].Reference; ReturnValue.Reference; value |
| 11 | Summary: alloc::vec::from_elem; Argument[0]; ReturnValue.Element; value |
nodes
| test_cipher.rs:18:9:18:14 | const1 [&ref, element] | semmle.label | const1 [&ref, element] |
| test_cipher.rs:18:28:18:36 | &... [&ref, element] | semmle.label | &... [&ref, element] |
@@ -119,4 +146,27 @@ nodes
| test_cipher.rs:73:20:73:22 | 0u8 | semmle.label | 0u8 |
| test_cipher.rs:74:23:74:44 | ...::new_from_slice | semmle.label | ...::new_from_slice |
| test_cipher.rs:74:46:74:51 | const2 [&ref, element] | semmle.label | const2 [&ref, element] |
| test_cookie.rs:17:9:17:14 | array1 [element] | semmle.label | array1 [element] |
| test_cookie.rs:17:28:17:34 | [0; 64] [element] | semmle.label | [0; 64] [element] |
| test_cookie.rs:17:29:17:29 | 0 | semmle.label | 0 |
| test_cookie.rs:18:16:18:24 | ...::from | semmle.label | ...::from |
| test_cookie.rs:18:26:18:32 | &array1 [&ref, element] | semmle.label | &array1 [&ref, element] |
| test_cookie.rs:18:27:18:32 | array1 [element] | semmle.label | array1 [element] |
| test_cookie.rs:21:9:21:14 | array2 [element] | semmle.label | array2 [element] |
| test_cookie.rs:21:28:21:34 | [0; 64] [element] | semmle.label | [0; 64] [element] |
| test_cookie.rs:21:29:21:29 | 0 | semmle.label | 0 |
| test_cookie.rs:22:16:22:24 | ...::from | semmle.label | ...::from |
| test_cookie.rs:22:26:22:32 | &array2 [&ref, element] | semmle.label | &array2 [&ref, element] |
| test_cookie.rs:22:27:22:32 | array2 [element] | semmle.label | array2 [element] |
| test_cookie.rs:38:9:38:14 | array2 [element] | semmle.label | array2 [element] |
| test_cookie.rs:38:18:38:37 | ...::from(...) [element] | semmle.label | ...::from(...) [element] |
| test_cookie.rs:38:28:38:36 | [0u8; 64] [element] | semmle.label | [0u8; 64] [element] |
| test_cookie.rs:38:29:38:31 | 0u8 | semmle.label | 0u8 |
| test_cookie.rs:42:14:42:32 | ...::from | semmle.label | ...::from |
| test_cookie.rs:42:34:42:39 | array2 [element] | semmle.label | array2 [element] |
| test_cookie.rs:49:9:49:14 | array3 [element] | semmle.label | array3 [element] |
| test_cookie.rs:49:23:49:25 | 0u8 | semmle.label | 0u8 |
| test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | semmle.label | ...::from_elem(...) [element] |
| test_cookie.rs:53:14:53:32 | ...::from | semmle.label | ...::from |
| test_cookie.rs:53:34:53:39 | array3 [element] | semmle.label | array3 [element] |
subpaths

View File

@@ -8,3 +8,5 @@ qltest_dependencies:
- base64 = { version = "0.22.1" }
- getrandom = { version = "0.3.1" }
- getrandom2 = { package = "getrandom", version = "0.2.15" }
- cookie = { version = "0.18.1", features = ["signed", "private"] }
- biscotti = { version = "0.4.3" }

View File

@@ -0,0 +1,58 @@
use cookie::{CookieJar, SignedJar, PrivateJar, Key};
// --- tests ---
fn test_cookie_jar(array_var: &[u8]) {
let mut jar = CookieJar::new();
let key_generate = Key::generate(); // good
_ = jar.signed_mut(&key_generate);
_ = jar.private_mut(&key_generate);
let key_var = Key::from(array_var); // good
_ = jar.signed_mut(&key_var);
_ = jar.private_mut(&key_var);
let array1: [u8; 64] = [0; 64]; // $ Alert[rust/hard-coded-cryptographic-value]
let key1 = Key::from(&array1); // $ Sink
_ = jar.signed_mut(&key1);
let array2: [u8; 64] = [0; 64]; // $ Alert[rust/hard-coded-cryptographic-value]
let key2 = Key::from(&array2); // $ Sink
_ = jar.private_mut(&key2);
}
fn test_biscotti_crypto(array_var: &[u8]) {
let mut config1 = biscotti::ProcessorConfig::default();
let crypto_rules1 = biscotti::config::CryptoRule {
cookie_names: vec!["name".to_string()],
algorithm: biscotti::config::CryptoAlgorithm::Signing,
key: biscotti::Key::generate(), // good
fallbacks: vec![],
};
config1.crypto_rules.push(crypto_rules1);
let processor1: biscotti::Processor = config1.into();
let mut config2 = biscotti::ProcessorConfig::default();
let array2 = Vec::from([0u8; 64]); // $ Alert[rust/hard-coded-cryptographic-value]
let crypto_rules2 = biscotti::config::CryptoRule {
cookie_names: vec!["name".to_string()],
algorithm: biscotti::config::CryptoAlgorithm::Signing,
key: biscotti::Key::from(array2), // $ Sink
fallbacks: vec![],
};
config2.crypto_rules.push(crypto_rules2);
let processor2: biscotti::Processor = config2.into();
let mut config3 = biscotti::ProcessorConfig::default();
let array3 = vec![0u8; 64]; // $ Alert[rust/hard-coded-cryptographic-value]
let crypto_rules3 = biscotti::config::CryptoRule {
cookie_names: vec!["name".to_string()],
algorithm: biscotti::config::CryptoAlgorithm::Signing,
key: biscotti::Key::from(array3), // $ Sink
fallbacks: vec![],
};
config3.crypto_rules.push(crypto_rules3);
let processor3: biscotti::Processor = config3.into();
}

View File

@@ -0,0 +1,3 @@
multipleCallTargets
| request_forgery_tests.rs:30:36:30:51 | user_url.as_str() |
| request_forgery_tests.rs:30:36:30:52 | user_url.as_str() |

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,105 @@
#select
| request_forgery_tests.rs:8:24:8:35 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:8:24:8:35 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
| request_forgery_tests.rs:8:24:8:35 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:8:24:8:35 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
| request_forgery_tests.rs:17:25:17:36 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:17:25:17:36 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
| request_forgery_tests.rs:21:25:21:36 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:21:25:21:36 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
| request_forgery_tests.rs:25:25:25:36 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:25:25:25:36 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
| request_forgery_tests.rs:31:29:31:40 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:31:29:31:40 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
| request_forgery_tests.rs:31:29:31:40 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:31:29:31:40 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
| request_forgery_tests.rs:37:37:37:48 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:37:37:37:48 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
| request_forgery_tests.rs:37:37:37:48 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:37:37:37:48 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
edges
| request_forgery_tests.rs:4:5:4:14 | res | request_forgery_tests.rs:16:27:16:49 | { ... } | provenance | |
| request_forgery_tests.rs:4:5:4:14 | res | request_forgery_tests.rs:20:27:20:57 | { ... } | provenance | |
| request_forgery_tests.rs:4:5:4:14 | res | request_forgery_tests.rs:24:27:24:70 | { ... } | provenance | |
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:8:38:8:45 | user_url | provenance | |
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:8:38:8:45 | user_url | provenance | |
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:16:27:16:49 | MacroExpr | provenance | |
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:20:27:20:57 | MacroExpr | provenance | |
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:24:27:24:70 | MacroExpr | provenance | |
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:31:43:31:50 | user_url | provenance | |
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:31:43:31:50 | user_url | provenance | |
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:37:51:37:58 | user_url | provenance | |
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:37:51:37:58 | user_url | provenance | |
| request_forgery_tests.rs:8:37:8:45 | &user_url [&ref] | request_forgery_tests.rs:8:24:8:35 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
| request_forgery_tests.rs:8:37:8:45 | &user_url [&ref] | request_forgery_tests.rs:8:24:8:35 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
| request_forgery_tests.rs:8:38:8:45 | user_url | request_forgery_tests.rs:8:37:8:45 | &user_url [&ref] | provenance | |
| request_forgery_tests.rs:8:38:8:45 | user_url | request_forgery_tests.rs:8:37:8:45 | &user_url [&ref] | provenance | |
| request_forgery_tests.rs:16:13:16:15 | url | request_forgery_tests.rs:17:39:17:41 | url | provenance | |
| request_forgery_tests.rs:16:27:16:49 | ...::format(...) | request_forgery_tests.rs:4:5:4:14 | res | provenance | |
| request_forgery_tests.rs:16:27:16:49 | ...::must_use(...) | request_forgery_tests.rs:16:13:16:15 | url | provenance | |
| request_forgery_tests.rs:16:27:16:49 | MacroExpr | request_forgery_tests.rs:16:27:16:49 | ...::format(...) | provenance | MaD:291 |
| request_forgery_tests.rs:16:27:16:49 | { ... } | request_forgery_tests.rs:16:27:16:49 | ...::must_use(...) | provenance | MaD:10629 |
| request_forgery_tests.rs:17:38:17:41 | &url [&ref] | request_forgery_tests.rs:17:25:17:36 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
| request_forgery_tests.rs:17:39:17:41 | url | request_forgery_tests.rs:17:38:17:41 | &url [&ref] | provenance | |
| request_forgery_tests.rs:20:13:20:15 | url | request_forgery_tests.rs:21:39:21:41 | url | provenance | |
| request_forgery_tests.rs:20:27:20:57 | ...::format(...) | request_forgery_tests.rs:4:5:4:14 | res | provenance | |
| request_forgery_tests.rs:20:27:20:57 | ...::must_use(...) | request_forgery_tests.rs:20:13:20:15 | url | provenance | |
| request_forgery_tests.rs:20:27:20:57 | MacroExpr | request_forgery_tests.rs:20:27:20:57 | ...::format(...) | provenance | MaD:291 |
| request_forgery_tests.rs:20:27:20:57 | { ... } | request_forgery_tests.rs:20:27:20:57 | ...::must_use(...) | provenance | MaD:10629 |
| request_forgery_tests.rs:21:38:21:41 | &url [&ref] | request_forgery_tests.rs:21:25:21:36 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
| request_forgery_tests.rs:21:39:21:41 | url | request_forgery_tests.rs:21:38:21:41 | &url [&ref] | provenance | |
| request_forgery_tests.rs:24:13:24:15 | url | request_forgery_tests.rs:25:39:25:41 | url | provenance | |
| request_forgery_tests.rs:24:27:24:70 | ...::format(...) | request_forgery_tests.rs:4:5:4:14 | res | provenance | |
| request_forgery_tests.rs:24:27:24:70 | ...::must_use(...) | request_forgery_tests.rs:24:13:24:15 | url | provenance | |
| request_forgery_tests.rs:24:27:24:70 | MacroExpr | request_forgery_tests.rs:24:27:24:70 | ...::format(...) | provenance | MaD:291 |
| request_forgery_tests.rs:24:27:24:70 | { ... } | request_forgery_tests.rs:24:27:24:70 | ...::must_use(...) | provenance | MaD:10629 |
| request_forgery_tests.rs:25:38:25:41 | &url [&ref] | request_forgery_tests.rs:25:25:25:36 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
| request_forgery_tests.rs:25:39:25:41 | url | request_forgery_tests.rs:25:38:25:41 | &url [&ref] | provenance | |
| request_forgery_tests.rs:31:42:31:50 | &user_url [&ref] | request_forgery_tests.rs:31:29:31:40 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
| request_forgery_tests.rs:31:42:31:50 | &user_url [&ref] | request_forgery_tests.rs:31:29:31:40 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
| request_forgery_tests.rs:31:43:31:50 | user_url | request_forgery_tests.rs:31:42:31:50 | &user_url [&ref] | provenance | |
| request_forgery_tests.rs:31:43:31:50 | user_url | request_forgery_tests.rs:31:42:31:50 | &user_url [&ref] | provenance | |
| request_forgery_tests.rs:37:50:37:58 | &user_url [&ref] | request_forgery_tests.rs:37:37:37:48 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
| request_forgery_tests.rs:37:50:37:58 | &user_url [&ref] | request_forgery_tests.rs:37:37:37:48 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
| request_forgery_tests.rs:37:51:37:58 | user_url | request_forgery_tests.rs:37:50:37:58 | &user_url [&ref] | provenance | |
| request_forgery_tests.rs:37:51:37:58 | user_url | request_forgery_tests.rs:37:50:37:58 | &user_url [&ref] | provenance | |
nodes
| request_forgery_tests.rs:4:5:4:14 | res | semmle.label | res |
| request_forgery_tests.rs:4:5:4:14 | res | semmle.label | res |
| request_forgery_tests.rs:4:5:4:14 | res | semmle.label | res |
| request_forgery_tests.rs:5:29:5:36 | user_url | semmle.label | user_url |
| request_forgery_tests.rs:5:29:5:36 | user_url | semmle.label | user_url |
| request_forgery_tests.rs:8:24:8:35 | ...::get | semmle.label | ...::get |
| request_forgery_tests.rs:8:24:8:35 | ...::get | semmle.label | ...::get |
| request_forgery_tests.rs:8:37:8:45 | &user_url [&ref] | semmle.label | &user_url [&ref] |
| request_forgery_tests.rs:8:37:8:45 | &user_url [&ref] | semmle.label | &user_url [&ref] |
| request_forgery_tests.rs:8:38:8:45 | user_url | semmle.label | user_url |
| request_forgery_tests.rs:8:38:8:45 | user_url | semmle.label | user_url |
| request_forgery_tests.rs:16:13:16:15 | url | semmle.label | url |
| request_forgery_tests.rs:16:27:16:49 | ...::format(...) | semmle.label | ...::format(...) |
| request_forgery_tests.rs:16:27:16:49 | ...::must_use(...) | semmle.label | ...::must_use(...) |
| request_forgery_tests.rs:16:27:16:49 | MacroExpr | semmle.label | MacroExpr |
| request_forgery_tests.rs:16:27:16:49 | { ... } | semmle.label | { ... } |
| request_forgery_tests.rs:17:25:17:36 | ...::get | semmle.label | ...::get |
| request_forgery_tests.rs:17:38:17:41 | &url [&ref] | semmle.label | &url [&ref] |
| request_forgery_tests.rs:17:39:17:41 | url | semmle.label | url |
| request_forgery_tests.rs:20:13:20:15 | url | semmle.label | url |
| request_forgery_tests.rs:20:27:20:57 | ...::format(...) | semmle.label | ...::format(...) |
| request_forgery_tests.rs:20:27:20:57 | ...::must_use(...) | semmle.label | ...::must_use(...) |
| request_forgery_tests.rs:20:27:20:57 | MacroExpr | semmle.label | MacroExpr |
| request_forgery_tests.rs:20:27:20:57 | { ... } | semmle.label | { ... } |
| request_forgery_tests.rs:21:25:21:36 | ...::get | semmle.label | ...::get |
| request_forgery_tests.rs:21:38:21:41 | &url [&ref] | semmle.label | &url [&ref] |
| request_forgery_tests.rs:21:39:21:41 | url | semmle.label | url |
| request_forgery_tests.rs:24:13:24:15 | url | semmle.label | url |
| request_forgery_tests.rs:24:27:24:70 | ...::format(...) | semmle.label | ...::format(...) |
| request_forgery_tests.rs:24:27:24:70 | ...::must_use(...) | semmle.label | ...::must_use(...) |
| request_forgery_tests.rs:24:27:24:70 | MacroExpr | semmle.label | MacroExpr |
| request_forgery_tests.rs:24:27:24:70 | { ... } | semmle.label | { ... } |
| request_forgery_tests.rs:25:25:25:36 | ...::get | semmle.label | ...::get |
| request_forgery_tests.rs:25:38:25:41 | &url [&ref] | semmle.label | &url [&ref] |
| request_forgery_tests.rs:25:39:25:41 | url | semmle.label | url |
| request_forgery_tests.rs:31:29:31:40 | ...::get | semmle.label | ...::get |
| request_forgery_tests.rs:31:29:31:40 | ...::get | semmle.label | ...::get |
| request_forgery_tests.rs:31:42:31:50 | &user_url [&ref] | semmle.label | &user_url [&ref] |
| request_forgery_tests.rs:31:42:31:50 | &user_url [&ref] | semmle.label | &user_url [&ref] |
| request_forgery_tests.rs:31:43:31:50 | user_url | semmle.label | user_url |
| request_forgery_tests.rs:31:43:31:50 | user_url | semmle.label | user_url |
| request_forgery_tests.rs:37:37:37:48 | ...::get | semmle.label | ...::get |
| request_forgery_tests.rs:37:37:37:48 | ...::get | semmle.label | ...::get |
| request_forgery_tests.rs:37:50:37:58 | &user_url [&ref] | semmle.label | &user_url [&ref] |
| request_forgery_tests.rs:37:50:37:58 | &user_url [&ref] | semmle.label | &user_url [&ref] |
| request_forgery_tests.rs:37:51:37:58 | user_url | semmle.label | user_url |
| request_forgery_tests.rs:37:51:37:58 | user_url | semmle.label | user_url |
subpaths

View File

@@ -0,0 +1,2 @@
query: queries/security/CWE-918/RequestForgery.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -0,0 +1,5 @@
use test::request_forgery_tests;
fn main() {
request_forgery_tests::start();
}

View File

@@ -0,0 +1,5 @@
qltest_cargo_check: true
qltest_dependencies:
- reqwest = { version = "0.12.23", features = ["blocking", "json"] }
- tokio = { version = "1.0", features = ["full"] }
- poem = { version = "3.1.12", features = ["server"] }

View File

@@ -0,0 +1,63 @@
mod poem_server {
use poem::{handler, web::Query, Route, Server};
#[handler]
async fn endpoint(Query(user_url): Query<String>, // $ Source=user_url
) -> String {
// BAD: The user can control the entire URL
let response = reqwest::get(&user_url).await; // $ Alert[rust/request-forgery]=user_url
// If this example is actually executed, forward the response text
if let Ok(resp) = response {
return resp.text().await.unwrap_or_default();
}
// BAD: The user can control a prefix of the URL
let url = format!("{}/resource", user_url);
let _response = reqwest::get(&url).await; // $ Alert[rust/request-forgery]=user_url
// BAD: The user can control a prefix of the URL - only the protocol is restricted
let url = format!("https://{}/resource", user_url);
let _response = reqwest::get(&url).await; // $ Alert[rust/request-forgery]=user_url
// GOOD: The user can only control a suffix after the hostname, this is likely ok
let url = format!("https://hostname.com/resource/{}", user_url);
let _response = reqwest::get(&url).await; // $ SPURIOUS: Alert[rust/request-forgery]=user_url
let allowed_hosts = ["api.example.com", "trusted-service.com"];
// GOOD: The URL is guaranteed to be in the allowlist
if allowed_hosts.contains(&user_url.as_str()) {
let _response = reqwest::get(&user_url).await; // $ SPURIOUS: Alert[rust/request-forgery]=user_url
}
if let Ok(url) = reqwest::Url::parse(&user_url) {
if let Some(host) = url.host_str() {
if allowed_hosts.contains(&host) {
let _response = reqwest::get(&user_url).await; // $ SPURIOUS: Alert[rust/request-forgery]=user_url
}
}
}
"".to_string()
}
// Function to create the Poem application
pub async fn create_app() -> Result<(), Box<dyn std::error::Error>> {
let app = Route::new().at("/fetch", poem::get(endpoint));
Server::new(poem::listener::TcpListener::bind("127.0.0.1:8080"))
.run(app)
.await?;
Ok(())
}
}
/// Start the Poem web application
pub fn start() {
tokio::runtime::Runtime::new()
.unwrap()
.block_on(poem_server::create_app())
.unwrap();
}

View File

@@ -919,6 +919,15 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
signature module SatisfiesConstraintInputSig<HasTypeTreeSig HasTypeTree> {
/** Holds if it is relevant to know if `term` satisfies `constraint`. */
predicate relevantConstraint(HasTypeTree term, Type constraint);
/**
* Holds if constraints that are satisfied through conditions that are
* universally quantified type parameters should be used. Such type
* parameters might have type parameter constraints, and these are _not_
* checked. Hence using these represent a trade-off between too many
* constraints and too few constraints being satisfied.
*/
default predicate useUniversalConditions() { any() }
}
module SatisfiesConstraint<
@@ -961,6 +970,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
TypeMention constraintMention
) {
exists(Type type | hasTypeConstraint(tt, type, constraint) |
useUniversalConditions() and
not exists(countConstraintImplementations(type, constraint)) and
conditionSatisfiesConstraintTypeAt(abs, condition, constraintMention, _, _) and
resolveTypeMentionRoot(condition) = abs.getATypeParameter() and