---
title: 'LiteRSan: Rust Memory-Safety Sanitizer'
url: https://www.emergentmind.com/topics/litersan
type: topic
---

# LiteRSan: Rust Memory-Safety Sanitizer

LiteRSan is a compiler-based memory-safety sanitizer for Rust that targets the gap between Rust’s language-level safety guarantees and the residual vulnerability surface introduced by `unsafe` code. It combines Rust-specific static analysis with lightweight runtime metadata checks, identifies only those pointers whose dereferences may violate memory safety, and selectively instruments them with the necessary spatial or temporal checks. In the formulation of "LiteRSan: Lightweight Memory Safety Via Rust-specific Program Analysis and Selective Instrumentation" [2509.16389], the system is explicitly positioned against ASan-based Rust sanitizers such as ERASan and RustSan, with the claim that Rust ownership, borrowing, scoping, and compiler-inserted safety checks can be exploited to avoid broad over-instrumentation while also detecting bug classes that generic ASan mechanisms miss.

## 1. Problem setting and motivation

Rust is a memory-safe language, but it permits the use of unsafe code, which bypasses compiler-enforced safety checks and can introduce memory vulnerabilities [2509.16389]. This creates a specific sanitization problem: a practical detector must handle unsafe Rust without discarding the precision that Rust’s ownership and lifetime model already provides.

The paper argues that prior Rust sanitizers inherit a C/C++-centric design through AddressSanitizer. ASan-based approaches such as ERASan and RustSan still rely on generic LLVM/SVF-style pointer analysis and classic ASan runtime mechanisms including red zones, shadow memory, and quarantine. According to the paper, this combination produces three limitations. First, generic alias analysis is too conservative for Rust, because ownership and borrowing sharply constrain aliasing; as a result, many pointers are treated as risky even when the compiler already guarantees safety. Second, the runtime machinery remains heavyweight in both time and memory. Third, ASan’s detection model is incomplete for Rust-specific failure modes: large overflows can bypass red zones, use-after-free may be missed if freed memory is reallocated after quarantine, and ownership-based temporal bugs such as cases involving `mem::forget` fall outside ASan’s native model [2509.16389].

LiteRSan is proposed to address these issues simultaneously. Its stated design is to perform Rust-specific static analysis that is aware of pointer lifetimes, identify only risky pointers, and then selectively instrument those pointers with compact metadata checks rather than broad object-level poisoning or shadow-state mechanisms.

## 2. Risk model and pointer taxonomy

LiteRSan organizes the Rust memory-safety problem around a pointer classification scheme. A **risky pointer** is defined as a pointer whose dereferences may violate memory safety. Within that set, a pointer is **spatially risky** if it bypasses Rust’s spatial enforcement, and **temporally risky** if it may outlive its referenced object. Some pointers can be both spatially and temporally risky [2509.16389].

A further distinction is the **exposed raw pointer**: a raw pointer directly used in unsafe code and therefore bypassing Rust’s safety guarantees. This distinction is operationally important. The paper emphasizes that not all raw pointers require identical treatment, because many occur inside safe abstractions and are not directly dereferenced in unsafe contexts. LiteRSan therefore avoids treating all raw pointers or all aliases as equally suspicious.

This taxonomy maps directly onto the classes of runtime checks that LiteRSan emits. Spatially risky pointers are associated with bounds and initialization validity; temporally risky pointers are associated with lifetime and ownership validity. The paper’s presentation implies that this split is not merely descriptive but structural: it determines both what metadata must be maintained and where instrumentation is inserted. A plausible implication is that LiteRSan’s overhead reduction depends as much on this classification granularity as on the later runtime implementation.

## 3. Rust-specific static analysis

LiteRSan’s static analysis has two major roles: restricting analysis scope to executable code and identifying exactly which pointers are spatially or temporally risky [2509.16389].

The first stage is **reachability analysis**. Starting from the entry point, LiteRSan recursively follows direct calls, address-taken functions, and indirect call targets. This prunes dead code and reduces analysis cost.

For spatial risk, LiteRSan modifies `rustc` code generation so that raw-pointer-related instructions in LLVM IR are annotated during MIR-to-LLVM lowering. The metadata includes `!rawptr` for raw-pointer-related instructions and `!unsafe` for instructions originating in unsafe code. The system uses MIR type information to detect raw-pointer values such as `*const T` and `*mut T`, and then tags the corresponding LLVM instructions. After that, it filters raw pointers to retain only **exposed raw pointers**, namely those directly used in unsafe code. The paper also identifies a small set of unsafe standard-library APIs that can break spatial safety even without explicit raw-pointer arithmetic. The listed Type (2) APIs are `unchecked_add/sub/mul/neg`, `forward_unchecked`, `backward_unchecked`, `unchecked_shl/shr`, and `set_len`; these are manually identified and handled individually.

For temporal risk, LiteRSan introduces a Rust-specific, inter-procedural, flow-sensitive, lifetime-aware taint analysis. An exposed raw pointer is treated as a taint source. From that source, the analysis tracks all pointers derived from it that still remain valid in scope and may refer to the same object. The paper defines a **pointer derivation instruction** as any operation that produces a new pointer from an existing one by assignment, computation, store/load propagation, or inter-procedural transfer via calls and returns.

The taint analysis distinguishes two raw-pointer source categories. **T1 raw pointers** are created from an already-owned object, such as `Vec::as_ptr()`, and require both backward and forward propagation. **T2 raw pointers** are created for a freshly allocated object and require only forward propagation. For T1 pointers, LiteRSan traces backward along the derivation chain to reconstruct ownership history, but stops propagation when ownership has been transferred or an earlier owner has been invalidated. Forward propagation then marks valid derived pointers as temporally risky if they still reference the same object.

Inter-procedural propagation handles direct calls by flowing taint from actual arguments to formal parameters and from callee returns back to callers. Indirect calls are resolved conservatively with type-based call-target analysis. The implementation is described as worklist-based, with caching of unresolved derivations and DFS-style propagation over transitive derivation chains. The paper’s central methodological claim is that this derivation- and lifetime-aware propagation is more precise than traditional may-alias reasoning in Rust because it respects ownership transfers, scoping, and invalidation.

## 4. Runtime metadata and selective instrumentation

LiteRSan’s runtime is built around compact metadata attached only to selected pointers rather than broad shadow-memory instrumentation [2509.16389]. For **spatially risky pointers**, the system tracks three fields: **Capacity**, **Initialized length**, and **Offset**. Capacity is the maximum number of elements allowed in the object, initialized length records how much of the object is initialized, and offset represents the current element index or byte offset. The metadata is stored in a separate metadata map rather than in the pointer itself.

Spatial metadata is inferred by walking backward from a risky pointer to its **root pointer** and extracting allocation-site information. The paper identifies two cases. In the **direct case**, the root points to a container such as `Vec<T>` or array `[T; N]`, where length or capacity are directly available. In the **indirect case**, the root passes through abstractions such as `Box<T>` or `Rc<T>`, which do not directly carry useful spatial metadata, so LiteRSan backtracks to the underlying allocation. Pointer arithmetic determines the offset field.

For **temporally risky pointers**, LiteRSan maintains metadata for **may-alias relationships** and **ownership**. Pointers that may refer to the same object are grouped into sets, and owner pointers are identified as the ones responsible for deallocation. The runtime uses two maps: a **reverse map** from a tainted pointer back to its taint source, and a **forward map** from each taint source to shared temporal metadata. Owner detection is based on pointer types and `Drop` implementations, with smart pointers such as `Box` and `Rc` treated as owners when they manage deallocation.

Instrumentation is organized into five classes:

- **I1**: pointer activation / metadata initialization  
- **I2**: spatial metadata update  
- **I3**: pointer deactivation / temporal metadata update  
- **I4**: spatial safety checks  
- **I5**: temporal safety checks  

For spatially risky pointers, LiteRSan inserts I1 at definition sites, I2 at pointer arithmetic and container-modification sites, and I4 at pointer arithmetic and dereference sites. For temporally risky pointers, it inserts I1 at definition sites, I5 at dereference sites, and I3 at deallocation sites; the paper specifies that I5 must occur before I3 at deallocation sites to avoid misreporting double-free. Pointers that are not risky themselves but carry spatial metadata receive I1 at definition and I2 on arithmetic or container updates.

The runtime checks are deliberately simple. At dereference or arithmetic sites, the spatial check verifies nullness, whether `Offset <= InitializedLength`, and whether `Offset <= Capacity`. Exceeding initialized length is reported as **use-before-initialization**; exceeding capacity is reported as **out-of-bounds**. At dereference or deallocation sites, the temporal check consults temporal metadata to determine whether the pointer is dangling. Dereferencing a dangling pointer is reported as **UAF**, and deallocating a dangling pointer is reported as **double-free**.

## 5. Compiler integration and implementation pipeline

LiteRSan is implemented on top of **LLVM-14** and uses a customized **rustc 1.64 nightly** [2509.16389]. The compiler modifications extend MIR-to-LLVM lowering and specifically alter `codegen-ssa` and `codegen-llvm` so that custom LLVM metadata is emitted for raw-pointer-related instructions.

The paper describes the overall pipeline as:

1. Rust source to MIR  
2. MIR lowered to LLVM IR with custom raw-pointer annotations  
3. LiteRSan static analysis  
4. Selective instrumentation  
5. Optimized compilation  
6. Runtime checking  

A notable implementation detail is the decision to insert instrumentation before optimization so that metadata is not lost, while still compiling the final binary with `-O3` for realistic performance evaluation. This establishes LiteRSan as a compiler-integrated sanitizer rather than a source-level transformation or an external binary rewrite.

Relative to ASan-retrofitting systems, this implementation strategy is closely aligned with Rust semantics. The system does not merely suppress a subset of ASan checks; it introduces a Rust-specific analysis and metadata model at the compiler level. This suggests that LiteRSan’s reduction in overhead is tied to early semantic filtering rather than only to a more efficient runtime.

## 6. Evaluation, overheads, and bug-detection behavior

The evaluation uses **28 benchmarks**: **26 crates from crates.io** and **2 real applications**, **servo** and **ripgrep**. Each benchmark is run **20 times**, and mean overheads are reported [2509.16389]. The paper compares LiteRSan against ERASan and RustSan, and also introduces **Semi-LiteRSan**, which reuses LiteRSan’s risky-pointer identification but retains ASan runtime checks in order to isolate the contribution of LiteRSan’s lightweight metadata.

| Measure | LiteRSan | Comparator values |
|---|---:|---:|
| Runtime overhead | 18.84% | ERASan 152.05%; RustSan 183.50%; Semi-LiteRSan 70.04% |
| Memory overhead | 0.81% | ERASan 739.27%; RustSan 861.98%; Semi-LiteRSan 443.90% |
| Compilation overhead | 97.21% | ERASan 1635.35%; RustSan 1193.31% |

The paper reports geometric mean runtime overheads of **18.84%** for LiteRSan, **152.05%** for ERASan, and **183.50%** for RustSan. It reports geometric mean memory overheads of **0.81%**, **739.27%**, and **861.98%**, respectively. Compilation overheads are **97.21%** for LiteRSan, **1635.35%** for ERASan, and **1193.31%** for RustSan. The corresponding reductions attributed to LiteRSan are **87.61%** versus ERASan and **89.73%** versus RustSan in runtime overhead, **94.06%** versus ERASan and **91.85%** versus RustSan in compile-time overhead, with the paper attributing the memory reduction mainly to avoiding ASan shadow memory and red zones. It also notes that ERASan and RustSan both timed out on **servo** and hit a segmentation fault on **ripgrep**, while LiteRSan completed successfully.

Bug-detection results are reported on RustSec vulnerabilities. LiteRSan detects **all 20 most recent bugs** in the main table and **55 vulnerabilities total** when combined with older cases in the appendix: **21 UAF**, **3 double-free**, **21 OOB**, **7 use-before-initialization**, and **3 null-pointer dereference**. The paper states that LiteRSan detects all of them with **100% accuracy** in the evaluation. ASan-based tools miss four bugs in the reported set: **two out-of-bounds bugs**, **one use-before-initialization bug**, and **one use-after-free bug**.

Two case studies illustrate the claimed difference in detection model. In **`vm-memory`**, a slice-like abstraction allows an internal pointer to refer outside a logical region while remaining within a larger allocated object. ASan misses this because red zones surround object boundaries rather than logical sub-bounds, whereas LiteRSan catches it through per-pointer tracking of capacity, initialized length, and offset. In **`tracing`**, a vulnerability involving `mem::forget` leaves pointers logically dangling without a conventional heap-free event. ASan misses the bug because no heap-free updates shadow memory; LiteRSan catches it because ownership state is tracked, and once the owner is forgotten or dropped, associated pointers are marked dangling.

The **Semi-LiteRSan** ablation is especially informative. Its geometric mean runtime overhead is **70.04%**, and its memory overhead is **443.90%**. The paper uses this to argue that the final gains come from two sources in combination: precise risky-pointer identification reduces unnecessary instrumentation, and the lightweight metadata-based runtime further cuts runtime and memory cost.

## 7. Scope, limitations, and relation to prior sanitization models

LiteRSan is explicitly limited to memory safety. The paper states that it does **not** cover type-conversion bugs such as `transmute`, cross-language memory bugs originating in C/C++ libraries behind FFI, or non-memory-safety bugs such as races and logic errors [2509.16389]. It is therefore not a full semantic correctness checker.

Within its intended scope, the paper’s central claim is architectural. LiteRSan replaces generic alias analysis and heavyweight ASan machinery with Rust-specific static analysis plus compact per-pointer metadata. Its key innovation is the observation that Rust ownership and lifetimes already eliminate a large number of memory-access risks, so sanitization should focus on the remaining risky pointers rather than instrumenting memory broadly. This leads to a different relationship between compiler semantics and runtime checking than in ASan-based designs.

A common misconception is that Rust’s memory-safety guarantees make sanitization largely unnecessary. The paper rejects that view by focusing on `unsafe` code and by showing that ownership-aware temporal bugs and logical spatial violations remain detectable targets. Another misconception is that selective instrumentation in Rust can be obtained simply by suppressing some ASan checks. LiteRSan’s comparison with ERASan and RustSan indicates a stronger claim: the decisive difference is not only how many checks are emitted, but whether the analysis reasons in terms of Rust-visible ownership transfers, lifetime structure, and exposed raw-pointer use.

In that sense, LiteRSan is best understood as a Rust-aware sanitizer that reasons like Rust rather than like C.

Source: https://www.emergentmind.com/topics/litersan