Memory Safety for a program is defined as it being impossible for the program to corrupt memory. Therefore, the safe subset of D consists only of programming language features that are guaranteed to never result in memory corruption. See this article for a rationale.
Memory-safe code cannot use certain language features, such as:
- Casts that break the type system.
- Modification of pointer values.
- Taking the address of a local variable or function parameter.
There are three categories of functions from the perspective of memory safety:
@system functions may perform any operation legal from the perspective of the language including inherently memory unsafe operations like returning pointers to expired stackframes. These functions may not be called directly from @safe functions.
@trusted functions have all the capabilities of @system functions but may be called from @safe functions. For this reason they should be very limited in the scope of their use. Typical uses of @trusted functions include wrapping system calls that take buffer pointer and length arguments separately so that @safe` functions may call them with arrays.
@safe functions have a number of restrictions on what they may do and are intended to disallow operations that may cause memory corruption. See @safe functions.
These attributes may be inferred when the compiler has the function body available, such as with templates.
Array bounds checks are necessary to enforce memory safety, so these are enabled (by default) for @safe code even in -release mode.
The function parameter attributes return and scope are used to track what happens to low-level pointers passed to functions. Such pointers include: raw pointers, arrays, this, classes, ref parameters, delegate/lazy parameters, and aggregates containing a pointer.
scope ensures that no references to the pointed-to object are retained, in global variables or pointers passed to the function (and recursively to other functions called in the function), as a result of calling the function. Variables in the function body and parameter list that are scope may have their allocations elided as a result.
return indicates that either the return value of the function or the first parameter is a pointer derived from the return parameter or any other parameters also marked return. For constructors, return applies to the (implicitly returned) this reference. For void functions, return applies to the first parameter iff it is ref; this is to support UFCS, property setters and non-member functions (e.g. put used like put(dest, source)).
These attributes may appear after the formal parameter list, in which case they apply either to a method's this parameter, or to a free function's first parameter iff it is ref. return or scope is ignored when applied to a type that is not a low-level pointer.
Memory safety does not imply that code is portable, uses only sound programming practices, is free of byte order dependencies, or other bugs. It is focussed only on eliminating memory corruption possibilities.