Skip to content

Rust: Model clone #18676

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 7, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions rust/ql/lib/codeql/rust/Frameworks.qll
Original file line number Diff line number Diff line change
@@ -4,3 +4,4 @@

private import codeql.rust.frameworks.rustcrypto.RustCrypto
private import codeql.rust.frameworks.Sqlx
private import codeql.rust.frameworks.stdlib.Clone
21 changes: 21 additions & 0 deletions rust/ql/lib/codeql/rust/frameworks/stdlib/Clone.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/** A model for `clone` on the `Clone` trait. */

private import rust
private import codeql.rust.dataflow.FlowSummary

/** A `clone` method. */
final class CloneCallable extends SummarizedCallable::Range {
CloneCallable() {
// NOTE: The function target may not exist in the database, so we base this
// on method calls.
exists(MethodCallExpr c |
c.getNameRef().getText() = "clone" and
c.getArgList().getNumberOfArgs() = 0 and
this = c.getResolvedCrateOrigin() + "::_::" + c.getResolvedPath()
)
}

final override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self]" and output = "ReturnValue" and preservesValue = true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
models
| 1 | Summary: lang:core; <crate::option::Option>::unwrap; Argument[self].Variant[crate::option::Option::Some(0)]; ReturnValue; value |
| 2 | Summary: lang:core; <crate::result::Result>::unwrap; Argument[self].Variant[crate::result::Result::Ok(0)]; ReturnValue; value |
edges
| main.rs:13:9:13:9 | a [Some] | main.rs:14:10:14:10 | a [Some] | provenance | |
| main.rs:13:9:13:9 | a [Some] | main.rs:15:13:15:13 | a [Some] | provenance | |
| main.rs:13:13:13:28 | Some(...) [Some] | main.rs:13:9:13:9 | a [Some] | provenance | |
| main.rs:13:18:13:27 | source(...) | main.rs:13:13:13:28 | Some(...) [Some] | provenance | |
| main.rs:14:10:14:10 | a [Some] | main.rs:14:10:14:19 | a.unwrap(...) | provenance | MaD:1 |
| main.rs:15:9:15:9 | b [Some] | main.rs:16:10:16:10 | b [Some] | provenance | |
| main.rs:15:13:15:13 | a [Some] | main.rs:15:13:15:21 | a.clone(...) [Some] | provenance | |
| main.rs:15:13:15:21 | a.clone(...) [Some] | main.rs:15:9:15:9 | b [Some] | provenance | |
| main.rs:16:10:16:10 | b [Some] | main.rs:16:10:16:19 | b.unwrap(...) | provenance | MaD:1 |
| main.rs:20:9:20:9 | a [Ok] | main.rs:21:10:21:10 | a [Ok] | provenance | |
| main.rs:20:9:20:9 | a [Ok] | main.rs:22:13:22:13 | a [Ok] | provenance | |
| main.rs:20:31:20:44 | Ok(...) [Ok] | main.rs:20:9:20:9 | a [Ok] | provenance | |
| main.rs:20:34:20:43 | source(...) | main.rs:20:31:20:44 | Ok(...) [Ok] | provenance | |
| main.rs:21:10:21:10 | a [Ok] | main.rs:21:10:21:19 | a.unwrap(...) | provenance | MaD:2 |
| main.rs:22:9:22:9 | b [Ok] | main.rs:23:10:23:10 | b [Ok] | provenance | |
| main.rs:22:13:22:13 | a [Ok] | main.rs:22:13:22:21 | a.clone(...) [Ok] | provenance | |
| main.rs:22:13:22:21 | a.clone(...) [Ok] | main.rs:22:9:22:9 | b [Ok] | provenance | |
| main.rs:23:10:23:10 | b [Ok] | main.rs:23:10:23:19 | b.unwrap(...) | provenance | MaD:2 |
| main.rs:27:9:27:9 | a | main.rs:28:10:28:10 | a | provenance | |
| main.rs:27:9:27:9 | a | main.rs:29:13:29:13 | a | provenance | |
| main.rs:27:13:27:22 | source(...) | main.rs:27:9:27:9 | a | provenance | |
| main.rs:29:9:29:9 | b | main.rs:30:10:30:10 | b | provenance | |
| main.rs:29:13:29:13 | a | main.rs:29:13:29:21 | a.clone(...) | provenance | |
| main.rs:29:13:29:21 | a.clone(...) | main.rs:29:9:29:9 | b | provenance | |
| main.rs:42:13:42:13 | w [Wrapper.n] | main.rs:43:15:43:15 | w [Wrapper.n] | provenance | |
| main.rs:42:17:42:41 | Wrapper {...} [Wrapper.n] | main.rs:42:13:42:13 | w [Wrapper.n] | provenance | |
| main.rs:42:30:42:39 | source(...) | main.rs:42:17:42:41 | Wrapper {...} [Wrapper.n] | provenance | |
| main.rs:43:15:43:15 | w [Wrapper.n] | main.rs:44:13:44:28 | Wrapper {...} [Wrapper.n] | provenance | |
| main.rs:43:15:43:15 | w [Wrapper.n] | main.rs:46:17:46:17 | w [Wrapper.n] | provenance | |
| main.rs:44:13:44:28 | Wrapper {...} [Wrapper.n] | main.rs:44:26:44:26 | n | provenance | |
| main.rs:44:26:44:26 | n | main.rs:44:38:44:38 | n | provenance | |
| main.rs:46:13:46:13 | u [Wrapper.n] | main.rs:47:15:47:15 | u [Wrapper.n] | provenance | |
| main.rs:46:17:46:17 | w [Wrapper.n] | main.rs:46:17:46:25 | w.clone(...) [Wrapper.n] | provenance | |
| main.rs:46:17:46:25 | w.clone(...) [Wrapper.n] | main.rs:46:13:46:13 | u [Wrapper.n] | provenance | |
| main.rs:47:15:47:15 | u [Wrapper.n] | main.rs:48:13:48:28 | Wrapper {...} [Wrapper.n] | provenance | |
| main.rs:48:13:48:28 | Wrapper {...} [Wrapper.n] | main.rs:48:26:48:26 | n | provenance | |
| main.rs:48:26:48:26 | n | main.rs:48:38:48:38 | n | provenance | |
nodes
| main.rs:13:9:13:9 | a [Some] | semmle.label | a [Some] |
| main.rs:13:13:13:28 | Some(...) [Some] | semmle.label | Some(...) [Some] |
| main.rs:13:18:13:27 | source(...) | semmle.label | source(...) |
| main.rs:14:10:14:10 | a [Some] | semmle.label | a [Some] |
| main.rs:14:10:14:19 | a.unwrap(...) | semmle.label | a.unwrap(...) |
| main.rs:15:9:15:9 | b [Some] | semmle.label | b [Some] |
| main.rs:15:13:15:13 | a [Some] | semmle.label | a [Some] |
| main.rs:15:13:15:21 | a.clone(...) [Some] | semmle.label | a.clone(...) [Some] |
| main.rs:16:10:16:10 | b [Some] | semmle.label | b [Some] |
| main.rs:16:10:16:19 | b.unwrap(...) | semmle.label | b.unwrap(...) |
| main.rs:20:9:20:9 | a [Ok] | semmle.label | a [Ok] |
| main.rs:20:31:20:44 | Ok(...) [Ok] | semmle.label | Ok(...) [Ok] |
| main.rs:20:34:20:43 | source(...) | semmle.label | source(...) |
| main.rs:21:10:21:10 | a [Ok] | semmle.label | a [Ok] |
| main.rs:21:10:21:19 | a.unwrap(...) | semmle.label | a.unwrap(...) |
| main.rs:22:9:22:9 | b [Ok] | semmle.label | b [Ok] |
| main.rs:22:13:22:13 | a [Ok] | semmle.label | a [Ok] |
| main.rs:22:13:22:21 | a.clone(...) [Ok] | semmle.label | a.clone(...) [Ok] |
| main.rs:23:10:23:10 | b [Ok] | semmle.label | b [Ok] |
| main.rs:23:10:23:19 | b.unwrap(...) | semmle.label | b.unwrap(...) |
| main.rs:27:9:27:9 | a | semmle.label | a |
| main.rs:27:13:27:22 | source(...) | semmle.label | source(...) |
| main.rs:28:10:28:10 | a | semmle.label | a |
| main.rs:29:9:29:9 | b | semmle.label | b |
| main.rs:29:13:29:13 | a | semmle.label | a |
| main.rs:29:13:29:21 | a.clone(...) | semmle.label | a.clone(...) |
| main.rs:30:10:30:10 | b | semmle.label | b |
| main.rs:42:13:42:13 | w [Wrapper.n] | semmle.label | w [Wrapper.n] |
| main.rs:42:17:42:41 | Wrapper {...} [Wrapper.n] | semmle.label | Wrapper {...} [Wrapper.n] |
| main.rs:42:30:42:39 | source(...) | semmle.label | source(...) |
| main.rs:43:15:43:15 | w [Wrapper.n] | semmle.label | w [Wrapper.n] |
| main.rs:44:13:44:28 | Wrapper {...} [Wrapper.n] | semmle.label | Wrapper {...} [Wrapper.n] |
| main.rs:44:26:44:26 | n | semmle.label | n |
| main.rs:44:38:44:38 | n | semmle.label | n |
| main.rs:46:13:46:13 | u [Wrapper.n] | semmle.label | u [Wrapper.n] |
| main.rs:46:17:46:17 | w [Wrapper.n] | semmle.label | w [Wrapper.n] |
| main.rs:46:17:46:25 | w.clone(...) [Wrapper.n] | semmle.label | w.clone(...) [Wrapper.n] |
| main.rs:47:15:47:15 | u [Wrapper.n] | semmle.label | u [Wrapper.n] |
| main.rs:48:13:48:28 | Wrapper {...} [Wrapper.n] | semmle.label | Wrapper {...} [Wrapper.n] |
| main.rs:48:26:48:26 | n | semmle.label | n |
| main.rs:48:38:48:38 | n | semmle.label | n |
subpaths
testFailures
#select
| main.rs:14:10:14:19 | a.unwrap(...) | main.rs:13:18:13:27 | source(...) | main.rs:14:10:14:19 | a.unwrap(...) | $@ | main.rs:13:18:13:27 | source(...) | source(...) |
| main.rs:16:10:16:19 | b.unwrap(...) | main.rs:13:18:13:27 | source(...) | main.rs:16:10:16:19 | b.unwrap(...) | $@ | main.rs:13:18:13:27 | source(...) | source(...) |
| main.rs:21:10:21:19 | a.unwrap(...) | main.rs:20:34:20:43 | source(...) | main.rs:21:10:21:19 | a.unwrap(...) | $@ | main.rs:20:34:20:43 | source(...) | source(...) |
| main.rs:23:10:23:19 | b.unwrap(...) | main.rs:20:34:20:43 | source(...) | main.rs:23:10:23:19 | b.unwrap(...) | $@ | main.rs:20:34:20:43 | source(...) | source(...) |
| main.rs:28:10:28:10 | a | main.rs:27:13:27:22 | source(...) | main.rs:28:10:28:10 | a | $@ | main.rs:27:13:27:22 | source(...) | source(...) |
| main.rs:30:10:30:10 | b | main.rs:27:13:27:22 | source(...) | main.rs:30:10:30:10 | b | $@ | main.rs:27:13:27:22 | source(...) | source(...) |
| main.rs:44:38:44:38 | n | main.rs:42:30:42:39 | source(...) | main.rs:44:38:44:38 | n | $@ | main.rs:42:30:42:39 | source(...) | source(...) |
| main.rs:48:38:48:38 | n | main.rs:42:30:42:39 | source(...) | main.rs:48:38:48:38 | n | $@ | main.rs:42:30:42:39 | source(...) | source(...) |
12 changes: 12 additions & 0 deletions rust/ql/test/library-tests/dataflow/modeled/inline-flow.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* @kind path-problem
*/

import rust
import utils.test.InlineFlowTest
import DefaultFlowTest
import ValueFlow::PathGraph

from ValueFlow::PathNode source, ValueFlow::PathNode sink
where ValueFlow::flowPath(source, sink)
select sink, source, sink, "$@", source, source.toString()
58 changes: 58 additions & 0 deletions rust/ql/test/library-tests/dataflow/modeled/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@

fn source(i: i64) -> i64 {
1000 + i
}

fn sink(s: i64) {
println!("{}", s);
}

// Flow through `clone` methods

fn option_clone() {
let a = Some(source(88));
sink(a.unwrap()); // $ hasValueFlow=88
let b = a.clone();
sink(b.unwrap()); // $ hasValueFlow=88
}

fn result_clone() {
let a: Result<i64, i64> = Ok(source(37));
sink(a.unwrap()); // $ hasValueFlow=37
let b = a.clone();
sink(b.unwrap()); // $ hasValueFlow=37
}

fn i64_clone() {
let a = source(12);
sink(a); // $ hasValueFlow=12
let b = a.clone();
sink(b); // $ hasValueFlow=12
}

mod my_clone {
use super::{source, sink};

#[derive(Clone)]
struct Wrapper {
n: i64
}

pub fn wrapper_clone() {
let w = Wrapper { n: source(73) };
match w {
Wrapper { n: n } => sink(n) // $ hasValueFlow=73
}
let u = w.clone();
match u {
Wrapper { n: n } => sink(n) // $ hasValueFlow=73
}
}
}

fn main() {
option_clone();
result_clone();
i64_clone();
my_clone::wrapper_clone();
}