Chapter 6.1. Dangling Pointer Detection
Rust uses ownership-based resource management (OBRM) and automatically deallocates unused resources without a garbage collector. This approach can potentially lead to premature memory deallocation, resulting in use-after-free or double-free errors. A significant portion of these bugs is related to the unwinding path, making them difficult to detect through testing or dynamic analysis. For more details, please refer to the SafeDrop paper published in TOSEM.
The implementation lives at rapx/src/check/safedrop/.
PoC
Below is a toy example demonstrating a Rust program with a use-after-free bug. The Data object is automatically dropped once the program exits the inner block scope of main. Accessing ptr after this point triggers a use-after-free error.
struct Data { value: Box<i32>, } impl Data { fn new(value: i32) -> Data { Data { value: Box::new(value) } } fn print_value(&self) { println!("Value: {}", self.value); } } fn main() { let ptr: *const Data; { let data = Data::new(42); ptr = &data as *const Data; } // data is automatically dropped here, leaving ptr dangling. unsafe { (*ptr).print_value(); // use-after-free. } }
Usage
To detect such bugs, navigate to the project directory and execute:
cargo rapx check -f
RAPx outputs a warning message in yellow if bugs are detected:
21:49|RAP-FRONT|WARN|: Use after free detected in function "main"
21:49|RAP-FRONT|WARN|: Location: src/main.rs:27:9: 27:20 (#0)
21:49|RAP-FRONT|WARN|: Location: src/main.rs:27:9: 27:34 (#0)
Mechanism
SafeDrop performs two essential steps for dangling pointer detection:
1. Alias Preparation
The MOP-based alias analysis is run first to compute alias summaries for all functions. SafeDropGraph wraps the alias analysis's AliasGraph as a member and reuses its Value, AliasBlockFacts, and MopFnAliasPairs types. However, SafeDropGraph implements its own path-sensitive alias_bb and alias_bbcall methods that layer drop-aware logic (drop record synchronisation, use-after-free checks, and drop-info clearing) on top of AliasGraph's core assign_alias and merge_alias operations. The precomputed alias summaries identify which function parameters and return values may alias, enabling inter-procedural drop tracking without re-analyzing callees.
Key data structures from the alias analysis reused by SafeDrop:
AliasGraph: WrapsPathGraphfor CFG topology and path enumeration, plus alias-specific state (values,alias_sets,block_facts).Value: Represents program places (locals and field projections) with drop metadata (may_drop,need_drop).AliasBlockFacts: Per-block assignment records and constant values.MopAliasPair/MopFnAliasPairs: Alias results annotated with drop information.
2. Path-Sensitive Bug Detection
SafeDrop traverses each enumerated execution path of a target function, performing drop analysis at each program point:
-
Drop Event Tracking: At each basic block, the analysis identifies which values are dropped at that point. Drop points are determined from MIR's explicit
TerminatorKind::Dropterminators and known drop function calls (e.g.,drop_in_place).StorageDeadstatements and implicit drop scopes are not currently tracked. -
Alias Propagation: Using the alias sets built during path traversal, the analysis propagates drop information through alias relationships. If
aaliasesbandais dropped, thenbis considered dangling. -
Dangling Use Detection: At each program point where a value is used (read, written, or passed to a function), the analysis checks whether any alias of that value has already been dropped along the current path.
-
Inter-procedural Drop Propagation: When a function call drops one of its arguments (e.g.,
drop_in_place, or a consuming call), SafeDrop consults the callee's alias summary and the caller's argument-to-alias mapping to determine which caller-side values become dangling after the call. -
Return Value Checking: Return values that alias with dropped locals are also flagged, catching cases where a function returns a dangling pointer to a deallocated local.
The path sensitivity is critical: by analyzing each CFG path independently, SafeDrop avoids the over-approximation that would occur if all paths were merged at join points. For example, if a value is dropped on one branch but not another, path-sensitive analysis correctly reports the bug only on the path where the drop occurs, while a path-insensitive analysis might produce false positives on the other branch or false negatives by ignoring the drop.
Source Structure
The safedrop/ module is organized as follows:
| File | Purpose |
|---|---|
mod.rs | Module entry point, Safedrop analysis struct with Analysis impl |
safedrop.rs | Core detection logic: path-sensitive drop tracking and dangling access detection |
alias.rs | Reuses AliasGraph from alias analysis; provides drop-aware alias tracking |
drop.rs | Drop point identification: determines where each value is dropped along a path |
bug_records.rs | Bug record data structures and warning formatting |
graph.rs | SafeDrop-specific graph extensions on top of AliasGraph |
corner_case.rs | Special-case handling for known patterns |
Reference
The feature is based on our SafeDrop paper, published in TOSEM:
@article{cui2023safedrop,
title={SafeDrop: Detecting memory deallocation bugs of rust programs via static data-flow analysis},
author={Mohan Cui, Chengjun Chen, Hui Xu, and Yangfan Zhou},
journal={ACM Transactions on Software Engineering and Methodology},
volume={32}, number={4}, pages={1--21}, year={2023},
publisher={ACM New York, NY, USA}
}