Rust’s Hidden Dangers: Unsafe, Embedded, and FFI Risks
March 24, 2025

Rust is recognized for its memory safety features, but even with its robust compiler checks, there are risks associated with unsafe code, embedded development, and interactions with C/C++. This blog post explores the top memory safety issues and runtime errors in Rust and provides actionable insights to mitigate these risks.
According to the Rudra paper when analyzing the RustSec Advisory Database, over 50% of reported security advisories in Rust crates involve memory safety issues from 2016 to 2021.
Data from the Rust Foundation (2024) reveals that “nearly 20% of all crates have at least one instance of the unsafe keyword”, and almost 35% of the crates ecosystem depends on the “unsafe” keyword.
Key Takeaways:
- Unsafe Rust adds features that bypass the compiler’s safety guarantees, making manual verification crucial to preventing memory safety violations.
- Embedded Rust has no support for the standard library (“std”) and relies on a “core” library instead, requiring careful handling of memory allocation and custom implementations of the panic!() macro.
- Hybrid Rust/C/C++ projects introduce additional risks at FFI boundaries, making rigorous analysis a necessity to avoid undefined behavior.
Rust’s Safety Promise—And Its Caveats
Rust is celebrated for its robust memory safety guarantees, but these guarantees come with boundaries. While safe Rust ensures that the compiler enforces strict memory safety, unsafe Rust hands that responsibility back to the developer.
Rust’s unsafe code blocks delegate memory safety to the developer, assuming that the code has been thoroughly checked and validated. This part of the code is prone to runtime errors and memory safety issues if not handled correctly.
The compiler assumes that unsafe Rust behavior has been properly vetted, which can lead to undefined behavior if not managed carefully
For projects using Rust in embedded systems, another layer of complexity emerges. Embedded Rust operates in environments where “std” is unavailable (use of “no_std”), meaning developers must work with “core” and implement custom memory management, custom concurrency and defining their own panic!() macro.
The challenges grow even steeper in hybrid Rust/C/C++ projects, where Rust’s strict type system meets the looser conventions of C. Issues such as dangling pointers, type mismatches, and undefined behavior from C code can undermine Rust’s safety guarantees unless handled meticulously.
The Perils of Unsafe Rust
Unsafe Rust is a necessity: it enables critical low-level operations, such as hardware access and system calls, that safe Rust cannot perform. However, misuse of unsafe Rust can introduce serious memory safety issues and security vulnerabilities. Some of the most common issues in unsafe Rust include:
- Null Pointer Dereferences
- Incorrect Use of Lifetimes
- Use-After-Free Errors
- Dangling Pointers
- Uninitialized Memory Access
- Manual Memory Management Bugs
Because unsafe Rust bypasses some compiler checks, developers must be extremely cautious when writing and reviewing such code. Tools like Clippy (a Rust linter) and Miri (an interpreter for detecting undefined behavior) can help, but they are limited in scope and cannot analyze hybrid Rust/C/C++ interactions.
Embedded Rust: No Standard Library, No Panic!?
For developers working in embedded Rust, “std” is unavailable, meaning that memory allocation must be handled manually using “core”. This also means that the panic!() macro, designed to handle unexpected errors, is absent by default and must be explicitly implemented by the developer.
The lack of “std” and conventional memory management functions makes embedded Rust development more error-prone, particularly when dealing with concurrency, data races, and missing libraries.
Hybrid Rust/C/C++: A Dangerous Mix
While Rust offers strong safety features, FFI (Foreign Function Interface) boundaries with C and C++ introduce critical risks. Indeed Rust’s ability to interact with the C ABI allows for seamless integration with C/C++ code. However, this also means that any memory corruption in C can affect Rust programs. The wrapping layer between C and Rust must be carefully managed to ensure type safety and prevent data corruption.
Memory safety issues in C/C++ code can propagate to Rust, leading to runtime errors and security vulnerabilities.
Issues that arise in hybrid Rust/C/C++ codebases include:
- Undefined Behavior: C/C++ code can trigger issues like double-free errors, which Rust cannot prevent unless the FFI boundary is carefully controlled.
- Type Mismatches: Rust’s strict typing system often clashes with C’s loose conventions, leading to crashes or data corruption if pointers or structs are misaligned.
- Thread Safety Violations: C/C++ code with unchecked multithreading can introduce data races when called from Rust, negating Rust’s concurrency guarantees.
The industry consensus, particularly in embedded and safety-critical applications, is to minimize unsafe blocks and rigorously audit C/C++ dependencies.
Best Practices for Memory Safety
To ensure memory safety in Rust, especially when dealing with unsafe code, embedded development, and interfacing with C/C++, follow these best practices:
- Minimize Unsafe Code: Use unsafe code when necessary. Ensure that unsafe code blocks are thoroughly reviewed and tested.
- Use Analysis Tools: Tools like Clippy, Miri and Sanitizers can help identify potential memory safety issues in Rust code.
- Audit C/C++ Dependencies: When interfacing with C/C++ code, rigorously audit C/C++ dependencies to prevent memory safety issues and runtime errors.
- Implement Custom Panic Handling: In embedded development, implement a custom panic!() macro to handle panics and by detecting such unwanted behaviors during development.
- Leverage Community Wisdom: Engage with the Rust community to stay updated on best practices and tools for ensuring memory safety. The Rustonomicon book and Rustsec.org are valuable resources for learning about unsafe Rust and security advisories.
How TrustInSoft Analyzer Mitigates These Risks
To help teams navigate these challenges, TrustInSoft has launched Rust Code Analysis Services, leveraging exhaustive analysis techniques to detect runtime errors and memory safety issues in both pure Rust and hybrid Rust/C/C++ codebases. Unlike existing tools like Clippy or Miri, TrustInSoft provides:
- Seamless, Expert-Led Analysis Rust Audit: your source code is formal verified using TrustInSoft Analyzer, ensuring runtime errors and memory safety issues are eliminated.
- Hybrid code analysis capable of examining Rust, C, and C++ together, making it ideal for projects integrating legacy or third-party C libraries.
- Cybersecurity-focused analysis that prevents memory safety issues, use-after-free errors, and buffer overflows in Rust projects.
Conclusion: Stay Safe, Analyze Your Rust Code
Rust is an incredibly powerful language for building secure and efficient software, but only when its boundaries are respected. Developers using unsafe Rust, embedded Rust, or hybrid Rust/C/C++ through FFI calls must be vigilant about potential pitfalls.
To ensure memory safety and security in Rust projects, teams should follow best practices and incorporate TrustInSoft solutions as part of their daily toolset. Don’t leave safety to chance: contact us.