How Memory Safety Works
Sric and Rust are both memory-safe languages without GC, but they differ significantly. Rust performs safety checks at compile time, while Sric checks memory safety at runtime. Rust's safety mechanisms impose many coding restrictions, forcing users to write complex and inefficient code. In contrast, Sric's safety mechanisms are transparent, requiring no extra effort to achieve memory safety. Sric's memory safety checks have minimal overhead, and by default, safety checks are disabled in Release mode, where performance matches hand-written C++ code.
Memory safety encompasses many aspects. Issues like array out-of-bounds, null pointers, and uninitialized pointers can be addressed with simple checks. Thanks to the ownership mechanism, problems like memory leaks and double-free are also eliminated. Thus, the core challenge of memory safety is detecting dangling pointers. In Sric, non-ownership pointers handle the primary task of memory detection.
In Sric, a non-ownership pointer is a "fat pointer," which includes the actual pointer and a verification code, among other details. The object's memory also contains an identical verification code. When a pointer is created, its verification code matches the object's. When memory is released, this code is set to 0. Each time the pointer is used, the verification codes of the pointer and the object are compared. If they differ, it indicates the object's memory has been freed. An error is reported immediately, preventing the issue from propagating, making it easy to locate the problem.
Although the principle is straightforward, several challenges must be addressed: handling derived pointers (pointers to the middle of memory rather than the start), managing memory arrays, distinguishing between heap and stack allocations, and dealing with non-cooperative objects (e.g., C++ classes with no space for verification codes). Fortunately, Sric has resolved most of these issues.
Address Sanitizer is also used for memory safety detection. However, it cannot detect cases where freed memory is reallocated to another object. Additionally, Address Sanitizer incurs significant memory and runtime overhead, lacks cross-platform compatibility, and requires recompilation of third-party libraries. In comparison, Sric's checks are more comprehensive, with negligible runtime overhead and no platform limitations.