Memory safety is necessary, not sufficient

Governments and standards bodies are starting to push for “memory‑safe” programming languages, but developers argue this is only one piece of the software security puzzle. Commenters contrast Rust, Go, Swift, Java, C and C++ on issues like undefined behavior, data races, FFI, tooling and package ecosystems, noting that Rust greatly reduces memory corruption but still permits other serious bugs and unsafe escape hatches. Many see memory safety requirements as welcome progress, yet emphasize the need for broader approaches — from better language and type-system design to sandboxing, formal methods and more disciplined supply-chain practices.

Government policy and memory-safe languages

  • US FY24 NDAA directs DoD to adopt NSA guidance on memory-safe languages and tools; NSA examples include C#, Go, Java, Ruby, Rust, Swift.
  • Unclear whether EU legislation has similar explicit memory-safety language; one EU impact assessment mentions Rust and Go but not requirements.
  • Some expect future procurement rules to enforce stricter vetting of software, potentially including memory-safety criteria and import controls.

Rust, “unsafe”, and comparison with other languages

  • Rust’s unsafe is seen as more containable than typical FFI/unsafe in Java/Swift: the type system lets you build safe abstractions with strong lifetime and usage guarantees.
  • However, unsafe still reintroduces C-like undefined behavior if invariants are violated; bugs can be subtle and propagate far.
  • There’s disagreement on whether Rust overall reduces total defects or just shifts them from memory bugs to logic/panic-style failures; some call for formal studies.
  • Swift is highlighted as converging toward Rust-like ownership/borrowing and as a candidate “TypeScript for C++” via tight C++ interop.
  • Go and managed languages are noted as long-time providers of memory safety but with different tradeoffs (GC, type system limitations, concurrency quirks).

Memory safety vs overall correctness

  • Many argue memory safety is necessary but not sufficient: logic bugs, SQL injection, path traversal, crypto mistakes, and deserialization issues remain across languages, including Rust.
  • Some worry about “panic culture” and overuse of crashing instead of graceful recovery, especially in non-security-critical contexts.

Undefined behavior, C/C++, and optimization

  • Large subthreads debate C’s UB:
    • One side: UB is essential for high optimization (pointer provenance, aliasing, etc.).
    • Other side: many UB cases could be defined with modest performance loss; modern compilers are “adversarial” and too complex.
  • Historical context: C’s design favored ease of compiler implementation and portability over safety and completeness; this helped it spread but left a legacy of unsafety.
  • Flags like -fno-strict-aliasing and similar are discussed as partial mitigations, at the cost of non-standard dialects and some performance.

Data races and security

  • Distinction made between:
    • Low-level data races (non-atomic concurrent memory access) and
    • Higher-level race conditions (TOCTOU, distributed races).
  • Several claim in-process data races are not yet a major exploited class compared to classic memory corruption; others note kernel and race-based exploits and argue we shouldn’t normalize UB just because it’s rare.
  • Some question why languages can’t define data races to yield “one of the written values”; replies cite tearing, compiler rematerialization, and lost optimizations.

Sandboxing, capabilities, and dependencies

  • Growing concern over huge dependency trees and supply-chain risk; desire for ways to sandbox libraries inside a process.
  • Proposed mechanisms: language-level sandboxes (e.g., Java SecurityManager, GraalVM isolates), WebAssembly, and object-capability models where access to resources (filesystem, network) is explicitly passed as capabilities.

Python and other “memory-safe” languages caveats

  • Python is usually labeled memory-safe, but participants note:
    • FFI (ctypes, C extensions) easily breaks safety.
    • Even pure Python can trigger interpreter memory errors via crafted bytecode or low-level APIs; fixing this would require significant verification machinery.
  • General consensus: “memory-safe language” is a pragmatic label meaning “safe in normal use,” not an absolute guarantee.

Future language directions and C++ successors

  • Four “C++ successor” strategies identified: do nothing, add safety within compatibility, break compatibility but stay unsafe, or break compatibility and be memory-safe by default.
  • Some question half-measures: if you’re breaking compatibility anyway, why not go fully memory-safe-by-default?
  • There is perceived design space for systems languages that are memory-safe by default but make very different choices than Rust (stdlib scope, error handling, syntax, concurrency model, allocation policies, linking, package management).