Rust: Deref as taint step

This commit is contained in:
Tom Hvitved
2025-09-01 20:36:57 +02:00
parent 45d6fc04ce
commit 5b51bb2ef0
6 changed files with 198 additions and 162 deletions

View File

@@ -41,13 +41,15 @@ module RustTaintTracking implements InputSig<Location, RustDataFlow> {
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 |

View File

@@ -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<HardcodedCryptographicValueConfig>;

View File

@@ -1,10 +1,11 @@
models
| 1 | Summary: <alloc::string::String as core::convert::From>::from; Argument[0]; ReturnValue; value |
| 2 | Summary: <alloc::string::String as core::ops::arith::Add>::add; Argument[self]; ReturnValue; value |
| 3 | Summary: <alloc::string::String>::as_str; Argument[self]; ReturnValue; value |
| 4 | Summary: <core::str>::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: <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 |
| 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 |
| 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(...) |

View File

@@ -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 |

View File

@@ -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: <alloc::boxed::Box>::as_mut_ptr; Argument[0].Reference.Reference; ReturnValue.Reference; value |
| 2 | Summary: <alloc::boxed::Box>::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

View File

@@ -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<i64> = Box::new(7); // b1 owns the memory for '50'
let p1 = Box::as_ptr(&b1); // b1 still owns the memory
let b1: Box<i64> = 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 p1: *const i64;
let p2: *const i64;
let p3: *mut i64;
{
let b1: Box<i64> = Box::new(1);
p1 = Box::into_raw(b1); // now owned by p1
{
let b1: Box<i64> = Box::new(1);
p1 = Box::into_raw(b1); // now owned by p1
let b2: Box<i64> = Box::new(2);
p2 = Box::as_ptr(&b2); // still owned by b2
let b2: Box<i64> = Box::new(2);
p2 = Box::as_ptr(&b2); // $ Source[rust/access-after-lifetime-ended]=b2 -- still owned by b2
let mut b3: Box<i64> = Box::new(3);
p3 = Box::as_mut_ptr(&mut b3); // still owned by b3
let mut b3: Box<i64> = 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 {
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"
}
}
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<i64> = Box::new(6); // b1 owns the memory
let p1 = Box::into_raw(b1); // now p1 owns the memory
let b1: Box<i64> = 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::<i32>().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::<i32>()
.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();
}