High-integrity software plays critical roles in telecommunications, transportation, defense systems, industrial automation, and power management. Because human lives may be lost and tremendous economic costs may result if the software fails, the development of high-integrity software adopts practices that impose greater rigor on the software development processes. This rigor includes documentation of system requirements, architecture, design, test plan, and source code; development accountability audit trails; independent peer review of all development artifacts; full traceability analysis; and extensive test coverage. The goal of this increased rigor is to assure correct operation and reliability of the software.
As computer automation expands its reach and influence, the size and complexity of high-integrity software is expanding as well. To deal with the increased development workload resulting from the ever-expanding role of high-integrity software, military and aerospace industries are leading the way towards the use of a safety-critical subset of the Java programming language to help increase developer productivity and reduce the maintenance costs associated with high-integrity software.
The appeal of high-integrity Java derives from many factors, including an abundance of skilled developers, high-quality development tools, and off-the-shelf reusable software components. The design of a safety-critical Java profile involves many tradeoffs between the need to subset from traditional Java in order to enable cost-effective certification audits, and the desire to support all of the Java features that contribute to Java’s fundamental appeal as a programming language.
Among the objectives addressed in a proposed safety-critical Java profile is an ability to automate the analysis of Java source code prior to execution in order to establish increased confidence that the software will run reliably. The analysis would have the ability to determine the amounts of memory and CPU time that will be function reliably and within specified timing constraints. The analysis also has the ability to prove that many common run-time errors that might manifest in traditional real-time Java programs will never occur in properly constructed safety-critical Java components. Besides increasing the reliability of deployed high-integrity software components, this analysis also serves as the foundation for modular composition of independently developed software components.
During the past year, Aonix (San Diego, CA) has been experimenting with use of the proposed source code analysis technologies. To date, we have analyzed over 20,000 lines of Java code. Much of this code was ported from traditional Java applications. Some of the code was originally developed for deployment with the Real-Time Specification for Java. Other code was specifically authored for deployment in safety-critical systems.
One of the questions asked by this experimental research is whether the restrictions imposed by the source code analysis system are compatible with the requirements of typical safety-critical software. Clearly, there are many perfectly legal and even “correct” Java programs that do not satisfy the strict set of rules that are enforced by the safety-critical source code analysis system. However, for a large class of the problems that require high-integrity solutions, Aonix’s research has demonstrated that the source code analysis technique is fully compatible with the software solutions that are appropriate for that domain.
Preserving Key Java Benefits
Various parties have worked with the Open Group for a number of years to establish a standard for safety-critical Java. Recently, this activity has resulted in submission of a Java Specification Request (JSR) to the Java Community Process (JCP). The JCP has assigned JSR number 302 to this particular topic. Although the final form that the specification will take is not yet settled, the prevailing ideas that have guided the work to date are described here.
A recent study (“An Empirical Study of Programming Language Trends”, IEEE Software, May/June 2005) predicts that by the year 2008, the Java language will be almost twice as popular as C++. In decreasing order of correlation, the statistical analysis on which this prediction is based lists the following factors: (1) portability, (2) extensibility, (3) generality, and (6) reliability. In designing a safety-critical Java subset, we consider it essential to preserve these key Java strengths. Factor 4, simplicity, and 5, implementability, had negative correlations, meaning that the software engineering community tends to favor languages that are not necessarily simple or easy to implement.
Developers of safety-critical Java software value portability because this facilitates easy reuse of off-the-shelf software components, reuse of software from previously deployed safety-critical projects, and because it allows software engineers to develop and test their code on fast and memory-rich desktop computers.
We consider the extensibility and generality factors mentioned in the study above to be aspects of a broader benefit, which we characterize as scalability. Scalability is measured in multiple dimensions. Small software systems need to evolve incrementally into larger software systems, without requiring changes, new analysis, or re-certification of existing software components. Software must scale from single processor platforms to multi-processor platforms. And software written to comply with stringent safety certification standards should integrate cleanly within systems that do not have safety certification requirements.
As a high-level programming language, Java encourages early detection of programming errors and supports run-time detection and containment of errors. Most developers find that code deployed in the Java language is much more reliable than code implemented in C or C++. Java code performs stronger compile-time type checking, stronger integration consistency checking through byte-code verification, and it performs various integrity checks at runtime to prevent array subscript errors and dereferencing of null pointers.
Discarding Bells & Whistles
A number of traditional Java features are considered inappropriate for safety-critical systems. Though automatic garbage collection can be configured for hard, real-time operation, the complexity of the real-time garbage collection system and the application analysis on which proofs of hard, real-time operation must be based are difficult and costly to develop and maintain. The consensus among safety-critical experts is that it is safer and more economical to use alternative temporary memory allocation techniques than to attempt certification of hard, real-time garbage collectors. The safety-critical Java profile proposes to use a safe subset of the Real- Time Specification for Java’s (RTSJ) scoped-memory abstraction.
Most of the standard class libraries make various assumptions regarding the presence of automatic garbage collection. These standard libraries are in general not compatible with scoped-memory allocation strategies. Instead, the safety-critical profile will standardize a small subset of the standard Java libraries.
Dynamic class loading is a powerful capability in traditional Java, but its use is not appropriate for the highest levels of safety certification.
Enhancing Java for Safety
Certain issues that are of critical significance to safety-critical developers are largely ignored by the traditional Java language definition. Among the capabilities that are being contemplated for standardization in the safety-critical Java specification are: Portable access to hardware devices through device port and interrupt handling abstractions; special byte-code verification requirements to assure that the use of scoped-memory allocation protocols does not result in illegal assignments which could potentially result in dangling pointers; static analysis techniques to automatically determine maximum stack requirements for particular threads, and maximum execution times for particular code sequences; and analysis of interclass dependencies integrated with static ahead-of-time compilation and static initialization of classes to eliminate startup race conditions and to assure fast deterministic boot up.
Though the official standards for safety-critical Java are not yet final, Aonix already has begun to experiment with some of the proposed technologies. Figure 1 provides a schematic diagram of the experimental development environment.
Software engineers use standard Java 5.0 syntax to develop their safety-critical Java software components. Specific annotations are placed into the source code using the Java 5.0 meta-data annotation system. The standard Eclipse Java source code compiler translates the source code to traditional Java class files.
The Eclipse development environment automatically invokes the PERC Pico verifier to enforce that the Java program uses only capabilities that are appropriate for the safety-critical subset and that there is consistency between declared annotated interface definition, the method implementation, and all invocations of the method. If the Pico verifier encounters verification errors, these are reported immediately within the Eclipse development environment so that the programmer can address the problem within the source code. Note that the byte-code verification is performed one class at a time, without requiring the complete program to be completed or assembled.
In our own experiments, we have found that code compiled with this system runs up to three times faster than code implemented by traditional optimizing Java compilers. The code runs faster because there is no need for the run-time overhead that is typically required in the implementation of garbage collection and the RTSJ’s scoped-memory protocol enforcement. More importantly, the code’s CPU time and memory requirements are more deterministic and the run-time environment is much simpler because there is no automatic garbage collection or dynamic class loading support. All of this makes analysis and safety certification of the deployed software system much more manageable.
Because the safety-critical run-time environment is much simpler than a traditional Java run-time environment, it is straightforward to combine safety-critical Java code with legacy safety-critical components written in Ada, C, and C++. A special protocol has been designed to allow efficient and robust integration of safety-critical Java code with traditional Java code for deployment in mission-critical systems that do not require full safety certification. As such, this technology represents a more efficient and safer alternative to use of the traditional Java Native Interface (JNI) protocol. The various interactions between software components are illustrated in Figure 2.
By enforcing specific restrictions on the use of the Java language, it is possible to develop and deploy safety-critical and other high-integrity software. Standards are being established now to assure portability and interoperability. These standards promise to deliver traditional Java benefits to the safety-critical development community.