Tech Blog
Software Engineering
Safe Programming Languages for ATM Systems
Rust Lang

Safe Programming Languages for ATM Systems

Introduction

⚠️ This post is an early draft; expect updates.

The primary mission of Air Traffic Management (ATM) systems is to guarantee safe separation between aircraft. As the European airspace becomes more congested and interconnected, and traffic volumes continue to rise, ATM systems face growing pressure to safely manage flights while responding in real time to thousands of concurrent events with minimal latency. Because a loss of separation can result in serious hazards, ATM systems fall squarely within the safety-critical systems domain.

This is the first post in a series exploring software engineering best practices for implementing safety-critical ATM systems. It introduces the general concepts behind safe programming languages, while subsequent posts will examine specific languages such as C/C++, Ada, and Rust. The intended audience includes:

  • Software engineers seeking a deeper understanding of safety-critical ATM systems.
  • Organizations aiming to obtain approval as a Design or Production Organization (DPO) from the European Union Aviation Safety Agency (EASA).

Why Safe Languages Matter

In the ATM environment outlined in the previous section, the choice of the programming language is not merely a technical decision — it is central to building resilient, mission-critical, and safety-critical ATM systems. In other words, while programming language selection often provokes strong opinions — sometimes bordering on religious wars — in the context of ATM systems it must be guided first and foremost by safety considerations.

Before diving further into programming languages, it is worthwile clarifying the distinction between mission-critical and safety-critical systems:

  • Mission-critical systems are those whose failure would prevent an organization from achieving its essential objectives. Downtime or errors may cause severe disruption or financial loss, but there is no immediate danger to human life. In the ATM domain, a Flight Data Processing (FDP) system is a good example of a mission-critical system. Its failure will cause severe operational disruptions, but it does not directly endanger human life

  • Safety-critical systems are those whose failure could directly result in injury, loss of life, or significant environmental harm. Again in the ATM domain, a Surveillance Data Processing System (SDPS) is safety-critical: a failure or design flaw could lead to a loss of separation between aircraft, creating a real risk of collision.

What makes a Language "Safe"?

No programming language is inherently safe by default. As illustrated below, a “safe language” typically refers to a restricted safe subset of the language, specified by coding standards that define the permitted constructs and syntax to constrain program behavior — for example, prohibiting recursion, disallowing self-modifying code, or enforcing limits such as a maximum number of lines per function.

Rust Lang

Figure 1: Reliable Software is built using a language subset defined by code standards, an execution environment and the accompanying toolset

Finally, the coding standards must be paired with an execution environment and the accompanying toolset — including qualified compilers, verification frameworks, and static analysis tools. The ultimate goal is to apply a structured approach to specifying, implementing, and verifying software (and the system as a whole), ensuring that the final system demonstrably meets stringent safety, reliability, and assurance levels.

Memory Safety

Memory safety is increasingly taking center stage in the design of safety-critical systems, because as a general trend across all domains, most software failures — including security vulnerabilities — can be traced back to manual memory management errors. Some common risks associated with manual memory management include:

  • Buffer overflows — out-of-bounds writes that corrupt adjacent memory
  • Dangling pointer dereferences — accessing the address of an object after it has been freed
  • Null pointer dereferences — accessing an object that has not been properly initialized
  • Double free — releasing the same memory location more than once, leading to corruption or crashes
  • Memory leak — failing to return memory, which eventually results in memory exhaustion

C and C++ are good examples of unsafe languages, where the problems outlined above, can result in critical software failures. Other languages such as Java, implement memory safety by removing manual memory management altogether, and introducing automatic mechanisms for reclaiming unused memory through a garbage collector. Unfortunately, a garbage collector introduces non-determinism (the exact timing of memory reclamation is unknown), which can be an issue in safety-critical systems, where unpredictable pauses can lead to latency spikes that violate real-time constraints.

Concurrency and Parallelism Safety

Concurrent programming refers to different parts of a program executing independently, while parallel programming involves executing multiple parts at the same time. Whenever a program runs tasks concurrently or in parallel, a new class of issues, often hard to diagnose can arise, including:

  • Race conditions — when the outcome depends on the timing or order of execution.
  • Deadlocks — when two or more tasks wait indefinitely for each other’s resources.
  • Data corruption — when shared data is modified by multiple tasks without proper synchronization.

Programming Language Paradigms

  • OOP
  • Functional

Modular Architectures

Another essential aspect of ATM systems — and of complex systems in general — is modularity. This means the ability to decompose the system into independent, testable modules that interact through well-defined interfaces. Some languages, such as Rust, encourage modularity through constructs like crates. Others, such as C++, lack a native concept of modules altogether.

  • Architecture
  • Cohesion
  • Coupling
  • Testability

Toolsets

  • Qualified compilers (ensuring that the compiler generates the intended code)
  • Static analysis tools
  • Software verification tools

Which Language for Your Next Project?

tbd

Epilogue: Why not Java, Go, C# and TypeScript?

Let me state right from the outset that you cannot build a safety-critical system in any of the languages mentioned in this section, simply because no formalized safe language subset specification exists. Another difference is that Java, Go, C# and TypeScript (and, in fact, any virtual machine–based language) rely on a garbage collector for memory management. Although a garbage collector improves memory safety, it also introduces non-determinism, which is not acceptable in safety-critical systems.