Glossary

Memory safety

What is memory safety?

Memory safety, in computer science and software development, relates to the quality of a programming language or system.

Memory safety guarantees that software cannot interact with or modify memory in ways that might result in memory-related errors or vulnerabilities. Memory safety plays an important role in maintaining the security and reliability of software applications.

Important elements of memory safety include (but are not limited to):

  • Preventing buffer overflows

Programming languages and runtime environments that prioritize memory safety stop buffer overflows. A buffer overflow is when a program writes data past the limits of a memory buffer (for example, an array), which can compromise data, crash programs, or even empower malicious actors to execute arbitrary code.

  • Getting rid of dangling pointers

Memory safety mechanisms remove dangling pointers (pointers that point to memory locations that have been deallocated or released).

  • Validating null pointers

Memory-safe languages commonly include checks to prevent null or uninitialized pointers from being dereferenced. Dereferencing null pointers can provoke program crashes and undefined behavior.

Which languages are best for memory safety?

Languages and systems that prioritize memory safety include Rust, Ada/Spark, Java, C#, and Python. These languages offer functionalities and mechanisms that prevent the likelihood of memory-related errors and vulnerabilities, making them suitable for crafting dependable and secure software.

Languages like C and C++ provide greater manual control over memory management but require developers to be more vigilant to ensure memory safety. Contemporary iterations of C and C++ have introduced safer alternatives and libraries to mitigate memory-related issues.

Memory-safe languages are only just appearing in the world of embedded software, which is dominated by C and C++. For embedded systems, it is often more efficient to look for hardware safety mechanisms such as fine-grained memory protection. Capability Hardware Enhanced RISC Instructions (CHERI), for example, provides fine-grained memory protection and can mitigate up to 70% of C/C++-related memory vulnerabilities.

It is worth noting that there is a fundamental difference between languages translated to native code and languages translated to code run by an interpreter. The native translation is what the embedded world needs because of resource constraints. Interpreted languages have an advantage in memory safety by design, as the interpreter can also handle this – but it costs more resources and performance then. The processor industry is still working on finding a middle ground here.

Getting started with Codasip