From 5b51bb2ef0c92075dd9029b61471d7c8eddf9de4 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 1 Sep 2025 20:36:57 +0200 Subject: [PATCH] Rust: Deref as taint step --- .../dataflow/internal/TaintTrackingImpl.qll | 14 +- .../CWE-798/HardcodedCryptographicValue.ql | 6 - .../strings/inline-taint-flow.expected | 34 ++- .../security/CWE-022/TaintedPath.expected | 6 + .../CWE-825/AccessAfterLifetime.expected | 32 +- .../test/query-tests/security/CWE-825/main.rs | 278 +++++++++--------- 6 files changed, 203 insertions(+), 167 deletions(-) diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/TaintTrackingImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/TaintTrackingImpl.qll index 0ae6aacb430d..b702c514c1ab 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/TaintTrackingImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/TaintTrackingImpl.qll @@ -41,13 +41,15 @@ module RustTaintTracking implements InputSig { succ.asExpr() = index ) or - // Although data flow through collections is modeled using stores/reads, - // we also allow taint to flow out of a tainted collection. This is - // needed in order to support taint-tracking configurations where the - // source is a collection. - exists(SingletonContentSet cs | - RustDataFlow::readStep(pred, cs, succ) and + // Although data flow through collections and references is modeled using + // stores/reads, we also allow taint to flow out of a tainted collection + // or reference. + // This is needed in order to support taint-tracking configurations where + // the source is a collection or reference. + exists(SingletonContentSet cs | RustDataFlow::readStep(pred, cs, succ) | cs.getContent() instanceof ElementContent + or + cs.getContent() instanceof ReferenceContent ) or exists(FormatArgsExprCfgNode format | succ.asExpr() = format | diff --git a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql index cd0dca79119b..f5a43c5419c6 100644 --- a/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql +++ b/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql @@ -39,12 +39,6 @@ module HardcodedCryptographicValueConfig implements DataFlow::ConfigSig { // case like `[0, 0, 0, 0]`) isSource(node) } - - predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { - // flow out from reference content at sinks. - isSink(node) and - c.getAReadContent() instanceof ReferenceContent - } } module HardcodedCryptographicValueFlow = TaintTracking::Global; diff --git a/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected b/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected index a33303c2bc2a..be270de025fe 100644 --- a/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected +++ b/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected @@ -1,10 +1,11 @@ models -| 1 | Summary: ::from; Argument[0]; ReturnValue; value | -| 2 | Summary: ::add; Argument[self]; ReturnValue; value | -| 3 | Summary: ::as_str; Argument[self]; ReturnValue; value | -| 4 | Summary: ::as_str; Argument[self]; ReturnValue; value | -| 5 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint | -| 6 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value | +| 1 | Summary: ::from; Argument[0].Reference; ReturnValue; value | +| 2 | Summary: ::from; Argument[0]; ReturnValue; value | +| 3 | Summary: ::add; Argument[self]; ReturnValue; value | +| 4 | Summary: ::as_str; Argument[self]; ReturnValue; value | +| 5 | Summary: ::as_str; Argument[self]; ReturnValue; value | +| 6 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint | +| 7 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value | edges | main.rs:26:9:26:9 | s | main.rs:27:19:27:25 | s[...] | provenance | | | main.rs:26:13:26:22 | source(...) | main.rs:26:9:26:9 | s | provenance | | @@ -15,46 +16,47 @@ edges | main.rs:32:9:32:10 | s1 | main.rs:35:14:35:15 | s1 | provenance | | | main.rs:32:14:32:23 | source(...) | main.rs:32:9:32:10 | s1 | provenance | | | main.rs:35:9:35:10 | s4 | main.rs:38:10:38:11 | s4 | provenance | | -| main.rs:35:14:35:15 | s1 | main.rs:35:14:35:20 | ... + ... | provenance | MaD:2 | +| main.rs:35:14:35:15 | s1 | main.rs:35:14:35:20 | ... + ... | provenance | MaD:3 | | main.rs:35:14:35:20 | ... + ... | main.rs:35:9:35:10 | s4 | provenance | | | main.rs:51:9:51:10 | s1 | main.rs:52:27:52:28 | s1 | provenance | | | main.rs:51:14:51:29 | source_slice(...) | main.rs:51:9:51:10 | s1 | provenance | | | main.rs:52:9:52:10 | s2 | main.rs:53:10:53:11 | s2 | provenance | | | main.rs:52:14:52:29 | ...::from(...) | main.rs:52:9:52:10 | s2 | provenance | | | main.rs:52:27:52:28 | s1 | main.rs:52:14:52:29 | ...::from(...) | provenance | MaD:1 | +| main.rs:52:27:52:28 | s1 | main.rs:52:14:52:29 | ...::from(...) | provenance | MaD:2 | | main.rs:63:9:63:9 | s | main.rs:64:16:64:16 | s | provenance | | -| main.rs:63:9:63:9 | s | main.rs:64:16:64:25 | s.as_str() | provenance | MaD:3 | | main.rs:63:9:63:9 | s | main.rs:64:16:64:25 | s.as_str() | provenance | MaD:4 | +| main.rs:63:9:63:9 | s | main.rs:64:16:64:25 | s.as_str() | provenance | MaD:5 | | main.rs:63:13:63:22 | source(...) | main.rs:63:9:63:9 | s | provenance | | -| main.rs:64:16:64:16 | s | main.rs:64:16:64:25 | s.as_str() | provenance | MaD:3 | | main.rs:64:16:64:16 | s | main.rs:64:16:64:25 | s.as_str() | provenance | MaD:4 | +| main.rs:64:16:64:16 | s | main.rs:64:16:64:25 | s.as_str() | provenance | MaD:5 | | main.rs:68:9:68:9 | s | main.rs:70:34:70:61 | MacroExpr | provenance | | | main.rs:68:9:68:9 | s | main.rs:73:34:73:59 | MacroExpr | provenance | | | main.rs:68:13:68:22 | source(...) | main.rs:68:9:68:9 | s | provenance | | | main.rs:70:9:70:18 | formatted1 | main.rs:71:10:71:19 | formatted1 | provenance | | | main.rs:70:22:70:62 | ...::format(...) | main.rs:70:9:70:18 | formatted1 | provenance | | -| main.rs:70:34:70:61 | MacroExpr | main.rs:70:22:70:62 | ...::format(...) | provenance | MaD:5 | +| main.rs:70:34:70:61 | MacroExpr | main.rs:70:22:70:62 | ...::format(...) | provenance | MaD:6 | | main.rs:73:9:73:18 | formatted2 | main.rs:74:10:74:19 | formatted2 | provenance | | | main.rs:73:22:73:60 | ...::format(...) | main.rs:73:9:73:18 | formatted2 | provenance | | -| main.rs:73:34:73:59 | MacroExpr | main.rs:73:22:73:60 | ...::format(...) | provenance | MaD:5 | +| main.rs:73:34:73:59 | MacroExpr | main.rs:73:22:73:60 | ...::format(...) | provenance | MaD:6 | | main.rs:76:9:76:13 | width | main.rs:77:34:77:74 | MacroExpr | provenance | | | main.rs:76:17:76:32 | source_usize(...) | main.rs:76:9:76:13 | width | provenance | | | main.rs:77:9:77:18 | formatted3 | main.rs:78:10:78:19 | formatted3 | provenance | | | main.rs:77:22:77:75 | ...::format(...) | main.rs:77:9:77:18 | formatted3 | provenance | | -| main.rs:77:34:77:74 | MacroExpr | main.rs:77:22:77:75 | ...::format(...) | provenance | MaD:5 | +| main.rs:77:34:77:74 | MacroExpr | main.rs:77:22:77:75 | ...::format(...) | provenance | MaD:6 | | main.rs:82:9:82:10 | s1 | main.rs:86:18:86:25 | MacroExpr | provenance | | | main.rs:82:9:82:10 | s1 | main.rs:87:18:87:32 | MacroExpr | provenance | | | main.rs:82:14:82:23 | source(...) | main.rs:82:9:82:10 | s1 | provenance | | | main.rs:86:10:86:16 | res | main.rs:86:18:86:25 | { ... } | provenance | | | main.rs:86:18:86:25 | ...::format(...) | main.rs:86:10:86:16 | res | provenance | | | main.rs:86:18:86:25 | ...::must_use(...) | main.rs:86:10:86:26 | MacroExpr | provenance | | -| main.rs:86:18:86:25 | MacroExpr | main.rs:86:18:86:25 | ...::format(...) | provenance | MaD:5 | -| main.rs:86:18:86:25 | { ... } | main.rs:86:18:86:25 | ...::must_use(...) | provenance | MaD:6 | +| main.rs:86:18:86:25 | MacroExpr | main.rs:86:18:86:25 | ...::format(...) | provenance | MaD:6 | +| main.rs:86:18:86:25 | { ... } | main.rs:86:18:86:25 | ...::must_use(...) | provenance | MaD:7 | | main.rs:87:10:87:16 | res | main.rs:87:18:87:32 | { ... } | provenance | | | main.rs:87:18:87:32 | ...::format(...) | main.rs:87:10:87:16 | res | provenance | | | main.rs:87:18:87:32 | ...::must_use(...) | main.rs:87:10:87:33 | MacroExpr | provenance | | -| main.rs:87:18:87:32 | MacroExpr | main.rs:87:18:87:32 | ...::format(...) | provenance | MaD:5 | -| main.rs:87:18:87:32 | { ... } | main.rs:87:18:87:32 | ...::must_use(...) | provenance | MaD:6 | +| main.rs:87:18:87:32 | MacroExpr | main.rs:87:18:87:32 | ...::format(...) | provenance | MaD:6 | +| main.rs:87:18:87:32 | { ... } | main.rs:87:18:87:32 | ...::must_use(...) | provenance | MaD:7 | nodes | main.rs:26:9:26:9 | s | semmle.label | s | | main.rs:26:13:26:22 | source(...) | semmle.label | source(...) | diff --git a/rust/ql/test/query-tests/security/CWE-022/TaintedPath.expected b/rust/ql/test/query-tests/security/CWE-022/TaintedPath.expected index 79a98e594e3f..25f92e390de8 100644 --- a/rust/ql/test/query-tests/security/CWE-022/TaintedPath.expected +++ b/rust/ql/test/query-tests/security/CWE-022/TaintedPath.expected @@ -45,12 +45,18 @@ edges | 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 | | +| src/main.rs:103:9:103:13 | path1 | src/main.rs:104:33:104:45 | path1.clone() | provenance | MaD:8 | | src/main.rs:103:9:103:13 | path1 | src/main.rs:106:39:106:43 | path1 | provenance | | +| src/main.rs:103:9:103:13 | path1 | src/main.rs:106:39:106:51 | path1.clone() | provenance | MaD:8 | | src/main.rs:103:9:103:13 | path1 | src/main.rs:109:41:109:45 | path1 | provenance | | +| src/main.rs:103:9:103:13 | path1 | src/main.rs:109:41:109:53 | path1.clone() | provenance | MaD:8 | | src/main.rs:103:9:103:13 | path1 | src/main.rs:112:45:112:49 | path1 | provenance | | +| src/main.rs:103:9:103:13 | path1 | src/main.rs:112:45:112:57 | path1.clone() | provenance | MaD:8 | | src/main.rs:103:9:103:13 | path1 | src/main.rs:115:39:115:43 | path1 | provenance | | | src/main.rs:103:9:103:13 | path1 | src/main.rs:122:27:122:31 | path1 | provenance | | +| src/main.rs:103:9:103:13 | path1 | src/main.rs:122:27:122:39 | path1.clone() | provenance | MaD:8 | | 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 | diff --git a/rust/ql/test/query-tests/security/CWE-825/AccessAfterLifetime.expected b/rust/ql/test/query-tests/security/CWE-825/AccessAfterLifetime.expected index 25f8643f0732..0010127c5bbb 100644 --- a/rust/ql/test/query-tests/security/CWE-825/AccessAfterLifetime.expected +++ b/rust/ql/test/query-tests/security/CWE-825/AccessAfterLifetime.expected @@ -22,6 +22,7 @@ | lifetime.rs:667:14:667:17 | ref1 | lifetime.rs:655:11:655:25 | &raw const str2 | lifetime.rs:667:14:667:17 | ref1 | Access of a pointer to $@ after its lifetime has ended. | lifetime.rs:651:7:651:10 | str2 | str2 | | lifetime.rs:789:12:789:13 | p1 | lifetime.rs:781:9:781:19 | &my_local10 | lifetime.rs:789:12:789:13 | p1 | Access of a pointer to $@ after its lifetime has ended. | lifetime.rs:779:6:779:15 | my_local10 | my_local10 | | lifetime.rs:808:23:808:25 | ptr | lifetime.rs:798:9:798:12 | &val | lifetime.rs:808:23:808:25 | ptr | Access of a pointer to $@ after its lifetime has ended. | lifetime.rs:796:6:796:8 | val | val | +| main.rs:64:23:64:24 | p2 | main.rs:44:26:44:28 | &b2 | main.rs:64:23:64:24 | p2 | Access of a pointer to $@ after its lifetime has ended. | main.rs:43:13:43:14 | b2 | b2 | edges | deallocation.rs:148:6:148:7 | p1 | deallocation.rs:151:14:151:15 | p1 | provenance | | | deallocation.rs:148:6:148:7 | p1 | deallocation.rs:158:14:158:15 | p1 | provenance | | @@ -163,7 +164,7 @@ edges | lifetime.rs:443:6:443:7 | p1 | lifetime.rs:446:13:446:14 | p1 | provenance | | | lifetime.rs:443:6:443:7 | p1 | lifetime.rs:450:2:450:10 | return p1 | provenance | | | lifetime.rs:443:23:443:44 | ...::from_ref(...) | lifetime.rs:443:6:443:7 | p1 | provenance | | -| lifetime.rs:443:42:443:43 | r1 | lifetime.rs:443:23:443:44 | ...::from_ref(...) | provenance | MaD:1 | +| lifetime.rs:443:42:443:43 | r1 | lifetime.rs:443:23:443:44 | ...::from_ref(...) | provenance | MaD:3 | | lifetime.rs:450:2:450:10 | return p1 | lifetime.rs:454:11:454:29 | get_ptr_from_ref(...) | provenance | | | lifetime.rs:450:2:450:10 | return p1 | lifetime.rs:460:13:460:31 | get_ptr_from_ref(...) | provenance | | | lifetime.rs:454:6:454:7 | p1 | lifetime.rs:459:13:459:14 | p1 | provenance | | @@ -212,8 +213,21 @@ edges | lifetime.rs:798:9:798:12 | &val | lifetime.rs:798:2:798:12 | return ... | provenance | | | lifetime.rs:802:6:802:8 | ptr | lifetime.rs:808:23:808:25 | ptr | provenance | | | lifetime.rs:802:12:802:24 | get_pointer(...) | lifetime.rs:802:6:802:8 | ptr | provenance | | +| main.rs:18:9:18:10 | p1 [&ref] | main.rs:21:19:21:20 | p1 | provenance | | +| main.rs:18:9:18:10 | p1 [&ref] | main.rs:29:19:29:20 | p1 | provenance | | +| main.rs:18:14:18:29 | ...::as_ptr(...) [&ref] | main.rs:18:9:18:10 | p1 [&ref] | provenance | | +| main.rs:18:26:18:28 | &b1 | main.rs:18:14:18:29 | ...::as_ptr(...) [&ref] | provenance | MaD:2 | +| main.rs:44:9:44:10 | p2 [&ref] | main.rs:51:23:51:24 | p2 | provenance | | +| main.rs:44:9:44:10 | p2 [&ref] | main.rs:64:23:64:24 | p2 | provenance | | +| main.rs:44:14:44:29 | ...::as_ptr(...) [&ref] | main.rs:44:9:44:10 | p2 [&ref] | provenance | | +| main.rs:44:26:44:28 | &b2 | main.rs:44:14:44:29 | ...::as_ptr(...) [&ref] | provenance | MaD:2 | +| main.rs:47:9:47:10 | p3 [&ref] | main.rs:52:23:52:24 | p3 | provenance | | +| main.rs:47:14:47:37 | ...::as_mut_ptr(...) [&ref] | main.rs:47:9:47:10 | p3 [&ref] | provenance | | +| main.rs:47:30:47:36 | &mut b3 | main.rs:47:14:47:37 | ...::as_mut_ptr(...) [&ref] | provenance | MaD:1 | models -| 1 | Summary: core::ptr::from_ref; Argument[0]; ReturnValue; value | +| 1 | Summary: ::as_mut_ptr; Argument[0].Reference.Reference; ReturnValue.Reference; value | +| 2 | Summary: ::as_ptr; Argument[0].Reference.Reference; ReturnValue.Reference; value | +| 3 | Summary: core::ptr::from_ref; Argument[0]; ReturnValue; value | nodes | deallocation.rs:148:6:148:7 | p1 | semmle.label | p1 | | deallocation.rs:148:30:148:38 | &raw const my_buffer | semmle.label | &raw const my_buffer | @@ -440,4 +454,18 @@ nodes | lifetime.rs:802:6:802:8 | ptr | semmle.label | ptr | | lifetime.rs:802:12:802:24 | get_pointer(...) | semmle.label | get_pointer(...) | | lifetime.rs:808:23:808:25 | ptr | semmle.label | ptr | +| main.rs:18:9:18:10 | p1 [&ref] | semmle.label | p1 [&ref] | +| main.rs:18:14:18:29 | ...::as_ptr(...) [&ref] | semmle.label | ...::as_ptr(...) [&ref] | +| main.rs:18:26:18:28 | &b1 | semmle.label | &b1 | +| main.rs:21:19:21:20 | p1 | semmle.label | p1 | +| main.rs:29:19:29:20 | p1 | semmle.label | p1 | +| main.rs:44:9:44:10 | p2 [&ref] | semmle.label | p2 [&ref] | +| main.rs:44:14:44:29 | ...::as_ptr(...) [&ref] | semmle.label | ...::as_ptr(...) [&ref] | +| main.rs:44:26:44:28 | &b2 | semmle.label | &b2 | +| main.rs:47:9:47:10 | p3 [&ref] | semmle.label | p3 [&ref] | +| main.rs:47:14:47:37 | ...::as_mut_ptr(...) [&ref] | semmle.label | ...::as_mut_ptr(...) [&ref] | +| main.rs:47:30:47:36 | &mut b3 | semmle.label | &mut b3 | +| main.rs:51:23:51:24 | p2 | semmle.label | p2 | +| main.rs:52:23:52:24 | p3 | semmle.label | p3 | +| main.rs:64:23:64:24 | p2 | semmle.label | p2 | subpaths diff --git a/rust/ql/test/query-tests/security/CWE-825/main.rs b/rust/ql/test/query-tests/security/CWE-825/main.rs index 5f66313ae85e..8d1f2a421469 100644 --- a/rust/ql/test/query-tests/security/CWE-825/main.rs +++ b/rust/ql/test/query-tests/security/CWE-825/main.rs @@ -7,197 +7,201 @@ mod lifetime; use lifetime::*; fn use_the_heap() { - let _a = Box::new(0x7FFFFFFF); - let _b = Box::new(0x7FFFFFFF); + let _a = Box::new(0x7FFFFFFF); + let _b = Box::new(0x7FFFFFFF); } // --- boxes --- pub fn test_boxes_into() { - let b1: Box = Box::new(7); // b1 owns the memory for '50' - let p1 = Box::as_ptr(&b1); // b1 still owns the memory + let b1: Box = Box::new(7); // b1 owns the memory for '50' + let p1 = Box::as_ptr(&b1); // b1 still owns the memory - unsafe { - let v1 = *p1; // GOOD - println!(" v1 = {v1}"); - } + unsafe { + let v1 = *p1; // GOOD + println!(" v1 = {v1}"); + } - let v2 = Box::into_inner(b1); // b1 is explicitly freed here, thus p1 is dangling - println!(" v2 = {v2}"); + let v2 = Box::into_inner(b1); // b1 is explicitly freed here, thus p1 is dangling + println!(" v2 = {v2}"); - unsafe { - let v3 = *p1; // $ MISSING: Alert - println!(" v3 = {v3} (!)"); // corrupt in practice - } + unsafe { + let v3 = *p1; // $ MISSING: Alert + println!(" v3 = {v3} (!)"); // corrupt in practice + } } pub fn test_boxes_1(mode: i32) { - let p1: *const i64; - let p2: *const i64; - let p3: *mut i64; - - { - let b1: Box = Box::new(1); - p1 = Box::into_raw(b1); // now owned by p1 - - let b2: Box = Box::new(2); - p2 = Box::as_ptr(&b2); // still owned by b2 - - let mut b3: Box = Box::new(3); - p3 = Box::as_mut_ptr(&mut b3); // still owned by b3 - - unsafe { - let v1 = *p1; // GOOD - let v2 = *p2; // GOOD - let v3 = *p3; // GOOD - println!(" v1 = {v1}"); - println!(" v2 = {v2}"); - println!(" v3 = {v3}"); - *p3 = 4; - } - } // (b2, b3 go out of scope, thus p2, p3 are dangling) - - unsafe { - if mode == 0 { - // reads - let v4 = *p1; // GOOD - let v5 = *p2; // $ MISSING: Alert - let v6 = *p3; // $ MISSING: Alert - println!(" v4 = {v4}"); - println!(" v5 = {v5} (!)"); // corrupt in practice - println!(" v6 = {v6} (!)"); // corrupt in practice - } - if mode == 10 { - // write - *p3 = 5; // $ MISSING: Alert - use_the_heap(); // "malloc: Heap corruption detected" - } - } + let p1: *const i64; + let p2: *const i64; + let p3: *mut i64; + + { + let b1: Box = Box::new(1); + p1 = Box::into_raw(b1); // now owned by p1 + + let b2: Box = Box::new(2); + p2 = Box::as_ptr(&b2); // $ Source[rust/access-after-lifetime-ended]=b2 -- still owned by b2 + + let mut b3: Box = Box::new(3); + p3 = Box::as_mut_ptr(&mut b3); // still owned by b3 + + unsafe { + let v1 = *p1; // GOOD + let v2 = *p2; // GOOD + let v3 = *p3; // GOOD + println!(" v1 = {v1}"); + println!(" v2 = {v2}"); + println!(" v3 = {v3}"); + *p3 = 4; + } + } // (b2, b3 go out of scope, thus p2, p3 are dangling) + + unsafe { + if mode == 0 { + // reads + let v4 = *p1; // GOOD + let v5 = *p2; // $ Alert[rust/access-after-lifetime-ended]=b2 + let v6 = *p3; // $ MISSING: Alert + println!(" v4 = {v4}"); + println!(" v5 = {v5} (!)"); // corrupt in practice + println!(" v6 = {v6} (!)"); // corrupt in practice + } + if mode == 10 { + // write + *p3 = 5; // $ MISSING: Alert + use_the_heap(); // "malloc: Heap corruption detected" + } + } } pub fn test_boxes_2() { - let b1: Box = Box::new(6); // b1 owns the memory - let p1 = Box::into_raw(b1); // now p1 owns the memory + let b1: Box = Box::new(6); // b1 owns the memory + let p1 = Box::into_raw(b1); // now p1 owns the memory - unsafe { - let _b2 = Box::from_raw(p1); // now _b2 owns the memory + unsafe { + let _b2 = Box::from_raw(p1); // now _b2 owns the memory - let v1 = *p1; // GOOD - println!(" v1 = {v1}"); - } // (_b2 goes out of scope, thus the memory is freed and p1 is dangling) + let v1 = *p1; // GOOD + println!(" v1 = {v1}"); + } // (_b2 goes out of scope, thus the memory is freed and p1 is dangling) - unsafe { - let v2 = *p1; // $ MISSING: Alert - println!(" v2 = {v2} (!)"); // corrupt in practice - } + unsafe { + let v2 = *p1; // $ MISSING: Alert + println!(" v2 = {v2} (!)"); // corrupt in practice + } } // --- main --- fn main() { - let mode = std::env::args().nth(1).unwrap_or("0".to_string()).parse::().unwrap_or(0); - // mode = which test cases to explore (0 should be safe; some will crash / segfault). - println!("mode = {mode}"); + let mode = std::env::args() + .nth(1) + .unwrap_or("0".to_string()) + .parse::() + .unwrap_or(0); + // mode = which test cases to explore (0 should be safe; some will crash / segfault). + println!("mode = {mode}"); - println!("test_boxes_into:"); - test_boxes_into(); + println!("test_boxes_into:"); + test_boxes_into(); - println!("test_boxes_1:"); - test_boxes_1(mode); + println!("test_boxes_1:"); + test_boxes_1(mode); - println!("test_boxes_2:"); - test_boxes_2(); + println!("test_boxes_2:"); + test_boxes_2(); - // --- + // --- - println!("test_alloc:"); - test_alloc(mode); + println!("test_alloc:"); + test_alloc(mode); - println!("test_alloc_array:"); - test_alloc_array(mode); + println!("test_alloc_array:"); + test_alloc_array(mode); - println!("test_libc:"); - test_libc(); + println!("test_libc:"); + test_libc(); - println!("test_ptr_invalid:"); - test_ptr_invalid(mode); + println!("test_ptr_invalid:"); + test_ptr_invalid(mode); - println!("test_drop:"); - test_drop(); + println!("test_drop:"); + test_drop(); - println!("test_ptr_drop:"); - test_ptr_drop(mode); + println!("test_ptr_drop:"); + test_ptr_drop(mode); - println!("test_qhelp_tests:"); - test_qhelp_examples(); + println!("test_qhelp_tests:"); + test_qhelp_examples(); - println!("test_vec_reserve:"); - test_vec_reserve(); + println!("test_vec_reserve:"); + test_vec_reserve(); - // --- + // --- - println!("test_local_dangling:"); - test_local_dangling(); + println!("test_local_dangling:"); + test_local_dangling(); - println!("test_local_in_scope:"); - test_local_in_scope(mode); + println!("test_local_in_scope:"); + test_local_in_scope(mode); - println!("test_static:"); - test_static(mode); + println!("test_static:"); + test_static(mode); - println!("test_call_contexts:"); - test_call_contexts(); + println!("test_call_contexts:"); + test_call_contexts(); - println!("test_call_contexts_rec:"); - test_call_contexts_rec(); + println!("test_call_contexts_rec:"); + test_call_contexts_rec(); - println!("test_loop:"); - test_loop(); + println!("test_loop:"); + test_loop(); - println!("test_enums:"); - test_enums(); + println!("test_enums:"); + test_enums(); - println!("test_recursive_enums:"); - test_recursive_enums(); + println!("test_recursive_enums:"); + test_recursive_enums(); - println!("test_ptr_to_struct:"); - test_ptr_to_struct(mode); + println!("test_ptr_to_struct:"); + test_ptr_to_struct(mode); - println!("test_ptr_from_ref:"); - test_ptr_from_ref(); + println!("test_ptr_from_ref:"); + test_ptr_from_ref(); - println!("test_rc:"); - test_rc(); + println!("test_rc:"); + test_rc(); - println!("test_closures:"); - test_closures(); + println!("test_closures:"); + test_closures(); - println!("test_async:"); - test_async(); + println!("test_async:"); + test_async(); - println!("test_lifetime_annotations:"); - test_lifetime_annotations(); + println!("test_lifetime_annotations:"); + test_lifetime_annotations(); - println!("test_implicit_derefs:"); - test_implicit_derefs(); + println!("test_implicit_derefs:"); + test_implicit_derefs(); - println!("test_members:"); - test_members(); + println!("test_members:"); + test_members(); - println!("test_enum_members:"); - test_enum_members(); + println!("test_enum_members:"); + test_enum_members(); - println!("test_macros:"); - test_macros(); + println!("test_macros:"); + test_macros(); - println!("test_unsafe_function:"); - unsafe { - test_unsafe_function(); - } + println!("test_unsafe_function:"); + unsafe { + test_unsafe_function(); + } - println!("test_lifetimes_example_bad:"); - test_lifetimes_example_bad(); + println!("test_lifetimes_example_bad:"); + test_lifetimes_example_bad(); - println!("test_lifetimes_example_good:"); - test_lifetimes_example_good(); + println!("test_lifetimes_example_good:"); + test_lifetimes_example_good(); }