Rust: Add data flow tests for collections

This commit is contained in:
Tom Hvitved
2025-12-01 14:06:59 +01:00
parent 09461e9cb6
commit e72c8acb6c
5 changed files with 235 additions and 1 deletions

View File

@@ -31,7 +31,12 @@ private module FlowTestImpl implements InputSig<Location, RustDataFlow> {
private string getSourceArgString(DataFlow::Node src) {
defaultSource(src) and
result = src.asExpr().(Call).getPositionalArgument(0).toString()
exists(Expr arg | arg = src.asExpr().(Call).getPositionalArgument(0) |
not arg instanceof ArrayListExpr and
result = arg.toString()
or
result = arg.(ArrayListExpr).getExpr(0).toString()
)
or
sourceNode(src, _) and
result =

View File

@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "test"
version = "0.0.1"

View File

@@ -0,0 +1,92 @@
models
| 1 | Summary: <& as core::ops::deref::Deref>::deref; Argument[self].Reference; ReturnValue; value |
edges
| main.rs:15:13:15:13 | s | main.rs:16:20:16:20 | s | provenance | |
| main.rs:15:17:15:25 | source(...) | main.rs:15:13:15:13 | s | provenance | |
| main.rs:16:13:16:15 | arr [element] | main.rs:17:14:17:16 | arr [element] | provenance | |
| main.rs:16:19:16:24 | [s; 5] [element] | main.rs:16:13:16:15 | arr [element] | provenance | |
| main.rs:16:20:16:20 | s | main.rs:16:19:16:24 | [s; 5] [element] | provenance | |
| main.rs:17:14:17:16 | arr [element] | main.rs:17:14:17:19 | arr[2] | provenance | |
| main.rs:20:13:20:19 | mut arr | main.rs:21:14:21:19 | arr[0] | provenance | |
| main.rs:20:23:20:33 | source(...) | main.rs:20:13:20:19 | mut arr | provenance | |
| main.rs:24:13:24:13 | s | main.rs:25:20:25:20 | s | provenance | |
| main.rs:24:17:24:25 | source(...) | main.rs:24:13:24:13 | s | provenance | |
| main.rs:25:13:25:15 | arr [element] | main.rs:26:18:26:20 | arr [element] | provenance | |
| main.rs:25:19:25:21 | [...] [element] | main.rs:25:13:25:15 | arr [element] | provenance | |
| main.rs:25:20:25:20 | s | main.rs:25:19:25:21 | [...] [element] | provenance | |
| main.rs:26:13:26:13 | x | main.rs:27:18:27:18 | x | provenance | |
| main.rs:26:18:26:20 | arr [element] | main.rs:26:13:26:13 | x | provenance | |
| main.rs:30:13:30:15 | arr | main.rs:32:18:32:18 | x | provenance | |
| main.rs:30:19:30:29 | source(...) | main.rs:30:13:30:15 | arr | provenance | |
| main.rs:37:9:37:11 | [post] arr [element] | main.rs:38:14:38:16 | arr [element] | provenance | |
| main.rs:37:18:37:26 | source(...) | main.rs:37:9:37:11 | [post] arr [element] | provenance | |
| main.rs:38:14:38:16 | arr [element] | main.rs:38:14:38:19 | arr[0] | provenance | |
| main.rs:63:18:63:22 | SelfParam [&ref, S] | main.rs:63:56:65:9 | { ... } [&ref, S] | provenance | |
| main.rs:82:13:82:13 | s | main.rs:83:19:83:19 | s | provenance | |
| main.rs:82:17:82:25 | source(...) | main.rs:82:13:82:13 | s | provenance | |
| main.rs:83:13:83:13 | s [S] | main.rs:85:16:85:16 | s [S] | provenance | |
| main.rs:83:17:83:20 | S(...) [S] | main.rs:83:13:83:13 | s [S] | provenance | |
| main.rs:83:19:83:19 | s | main.rs:83:17:83:20 | S(...) [S] | provenance | |
| main.rs:85:15:85:25 | * ... [S] | main.rs:85:14:85:28 | ... .0 | provenance | |
| main.rs:85:16:85:16 | s [S] | main.rs:63:18:63:22 | SelfParam [&ref, S] | provenance | |
| main.rs:85:16:85:16 | s [S] | main.rs:85:16:85:25 | s.index(...) [&ref, S] | provenance | |
| main.rs:85:16:85:25 | s.index(...) [&ref, S] | main.rs:85:15:85:25 | * ... [S] | provenance | MaD:1 |
| main.rs:94:10:94:10 | [post] s [S] | main.rs:95:14:95:14 | s [S] | provenance | |
| main.rs:94:10:94:23 | [post] s.index_mut(...) [&ref, S] | main.rs:94:10:94:10 | [post] s [S] | provenance | |
| main.rs:94:27:94:38 | S(...) [S] | main.rs:94:10:94:23 | [post] s.index_mut(...) [&ref, S] | provenance | |
| main.rs:94:29:94:37 | source(...) | main.rs:94:27:94:38 | S(...) [S] | provenance | |
| main.rs:95:14:95:14 | s [S] | main.rs:95:14:95:16 | s.0 | provenance | |
nodes
| main.rs:15:13:15:13 | s | semmle.label | s |
| main.rs:15:17:15:25 | source(...) | semmle.label | source(...) |
| main.rs:16:13:16:15 | arr [element] | semmle.label | arr [element] |
| main.rs:16:19:16:24 | [s; 5] [element] | semmle.label | [s; 5] [element] |
| main.rs:16:20:16:20 | s | semmle.label | s |
| main.rs:17:14:17:16 | arr [element] | semmle.label | arr [element] |
| main.rs:17:14:17:19 | arr[2] | semmle.label | arr[2] |
| main.rs:20:13:20:19 | mut arr | semmle.label | mut arr |
| main.rs:20:23:20:33 | source(...) | semmle.label | source(...) |
| main.rs:21:14:21:19 | arr[0] | semmle.label | arr[0] |
| main.rs:24:13:24:13 | s | semmle.label | s |
| main.rs:24:17:24:25 | source(...) | semmle.label | source(...) |
| main.rs:25:13:25:15 | arr [element] | semmle.label | arr [element] |
| main.rs:25:19:25:21 | [...] [element] | semmle.label | [...] [element] |
| main.rs:25:20:25:20 | s | semmle.label | s |
| main.rs:26:13:26:13 | x | semmle.label | x |
| main.rs:26:18:26:20 | arr [element] | semmle.label | arr [element] |
| main.rs:27:18:27:18 | x | semmle.label | x |
| main.rs:30:13:30:15 | arr | semmle.label | arr |
| main.rs:30:19:30:29 | source(...) | semmle.label | source(...) |
| main.rs:32:18:32:18 | x | semmle.label | x |
| main.rs:37:9:37:11 | [post] arr [element] | semmle.label | [post] arr [element] |
| main.rs:37:18:37:26 | source(...) | semmle.label | source(...) |
| main.rs:38:14:38:16 | arr [element] | semmle.label | arr [element] |
| main.rs:38:14:38:19 | arr[0] | semmle.label | arr[0] |
| main.rs:63:18:63:22 | SelfParam [&ref, S] | semmle.label | SelfParam [&ref, S] |
| main.rs:63:56:65:9 | { ... } [&ref, S] | semmle.label | { ... } [&ref, S] |
| main.rs:82:13:82:13 | s | semmle.label | s |
| main.rs:82:17:82:25 | source(...) | semmle.label | source(...) |
| main.rs:83:13:83:13 | s [S] | semmle.label | s [S] |
| main.rs:83:17:83:20 | S(...) [S] | semmle.label | S(...) [S] |
| main.rs:83:19:83:19 | s | semmle.label | s |
| main.rs:85:14:85:28 | ... .0 | semmle.label | ... .0 |
| main.rs:85:15:85:25 | * ... [S] | semmle.label | * ... [S] |
| main.rs:85:16:85:16 | s [S] | semmle.label | s [S] |
| main.rs:85:16:85:25 | s.index(...) [&ref, S] | semmle.label | s.index(...) [&ref, S] |
| main.rs:94:10:94:10 | [post] s [S] | semmle.label | [post] s [S] |
| main.rs:94:10:94:23 | [post] s.index_mut(...) [&ref, S] | semmle.label | [post] s.index_mut(...) [&ref, S] |
| main.rs:94:27:94:38 | S(...) [S] | semmle.label | S(...) [S] |
| main.rs:94:29:94:37 | source(...) | semmle.label | source(...) |
| main.rs:95:14:95:14 | s [S] | semmle.label | s [S] |
| main.rs:95:14:95:16 | s.0 | semmle.label | s.0 |
subpaths
| main.rs:85:16:85:16 | s [S] | main.rs:63:18:63:22 | SelfParam [&ref, S] | main.rs:63:56:65:9 | { ... } [&ref, S] | main.rs:85:16:85:25 | s.index(...) [&ref, S] |
testFailures
#select
| main.rs:17:14:17:19 | arr[2] | main.rs:15:17:15:25 | source(...) | main.rs:17:14:17:19 | arr[2] | $@ | main.rs:15:17:15:25 | source(...) | source(...) |
| main.rs:21:14:21:19 | arr[0] | main.rs:20:23:20:33 | source(...) | main.rs:21:14:21:19 | arr[0] | $@ | main.rs:20:23:20:33 | source(...) | source(...) |
| main.rs:27:18:27:18 | x | main.rs:24:17:24:25 | source(...) | main.rs:27:18:27:18 | x | $@ | main.rs:24:17:24:25 | source(...) | source(...) |
| main.rs:32:18:32:18 | x | main.rs:30:19:30:29 | source(...) | main.rs:32:18:32:18 | x | $@ | main.rs:30:19:30:29 | source(...) | source(...) |
| main.rs:38:14:38:19 | arr[0] | main.rs:37:18:37:26 | source(...) | main.rs:38:14:38:19 | arr[0] | $@ | main.rs:37:18:37:26 | source(...) | source(...) |
| main.rs:85:14:85:28 | ... .0 | main.rs:82:17:82:25 | source(...) | main.rs:85:14:85:28 | ... .0 | $@ | main.rs:82:17:82:25 | source(...) | source(...) |
| main.rs:95:14:95:16 | s.0 | main.rs:94:29:94:37 | source(...) | main.rs:95:14:95:16 | s.0 | $@ | main.rs:94:29:94:37 | source(...) | source(...) |

View File

@@ -0,0 +1,12 @@
/**
* @kind path-problem
*/
import rust
import utils.test.InlineFlowTest
import DefaultFlowTest
import TaintFlow::PathGraph
from TaintFlow::PathNode source, TaintFlow::PathNode sink
where TaintFlow::flowPath(source, sink)
select sink, source, sink, "$@", source, source.toString()

View File

@@ -0,0 +1,118 @@
fn source<T>(s: T) -> T {
s
}
fn sink(s: i64) {
println!("{}", s);
}
mod arrays {
use crate::*;
use std::ops::Index;
use std::ops::IndexMut;
pub fn f() {
let s = source(0);
let arr = [s; 5];
sink(arr[2]); // $ hasValueFlow=0
sink(*arr.index(2)); // $ MISSING: hasValueFlow=0
let mut arr = source([1]);
sink(arr[0]); // $ hasTaintFlow=1
sink(*arr.index(0)); // $ MISSING: hasTaintFlow=1
let s = source(2);
let arr = [s];
for x in arr {
sink(x); // $ hasValueFlow=2
}
let arr = source([3]);
for x in arr {
sink(x); // $ hasTaintFlow=3
}
let mut arr = [0];
sink(arr[0]);
arr[0] = source(4);
sink(arr[0]); // $ hasValueFlow=4
let mut arr = [0];
sink(arr[0]);
*arr.index_mut(0) = source(5);
sink(arr[0]); // $ MISSING: hasValueFlow=5 -- needs generalized reverse flow
let mut arr = [0];
arr[0] += source(6);
sink(arr[0]); // $ MISSING: hasTaintFlow=6
}
}
mod indexers {
use crate::*;
use std::ops::AddAssign;
use std::ops::Index;
use std::ops::IndexMut;
#[derive(Debug)]
struct S<T>(T);
impl<T> Index<usize> for S<T> {
type Output = S<T>; // `T` would be a better choice here, but that requires generalized reverse flow for the test to pass
fn index(&self, index: usize) -> &Self::Output {
self
}
}
impl<T> IndexMut<usize> for S<T> {
// `Self::Output` is not yet handled, so use `S<T>` for now
fn index_mut(&mut self, index: usize) -> &mut S<T> {
self
}
}
impl std::ops::AddAssign for S<i64> {
fn add_assign(&mut self, other: Self) {
self.0 += other.0;
}
}
pub fn f() {
let s = source(0);
let s = S(s);
sink(s[0].0); // $ MISSING: hasValueFlow=0
sink((*s.index(0)).0); // $ hasValueFlow=0
let mut s = S(0);
sink(s.0);
s[0] = S(source(1));
sink(s.0); // $ MISSING: hasValueFlow=1
let mut s = S(0);
sink(s.0);
*s.index_mut(0) = S(source(2));
sink(s.0); // $ hasValueFlow=2
let mut s = S(0i64);
sink(s.0);
s[0] += S(source(3));
sink(s.0); // $ MISSING: hasTaintFlow=3
let mut s = S(0i64);
sink(s.0);
*s.index_mut(0) += S(source(5));
s[0] += S(source(5));
sink(s.0); // $ MISSING: hasTaintFlow=5
let mut s = S(0i64);
sink(s.0);
(*s.index_mut(0)).add_assign(S(source(6)));
sink(s.0); // $ MISSING: hasTaintFlow=6
}
}
fn main() {
arrays::f();
indexers::f();
}