Use of the C++ Programming Language in Safety Critical...
Transcript of Use of the C++ Programming Language in Safety Critical...
Use of the C++ Programming Language
in Safety Critical Systems
Flight Lieutenant Derek W. Reinhardt
This report is submitted to satisfy the project requirements of the
Masters of Science in Safety-Critical Systems Engineering
at the Department of Computer Science
September 2004
Number of words = 43,104, as indicated by the Microsoft Word ‘word count’ tool. The count
includes the Title Page, Preliminaries, Report Body and References. Appendixes 1 to 16 contain
design evidence that is included for completeness and has not been included in the word count.
i
Abstract
The use of software for high integrity and safety critical applications is continuing to rapidly grow.
However, concerns are often raised because of the potentially disastrous consequences of a failure
of the software. C++ is a popular computer programming language, and thus there has been recent
interest in exploring its use for high integrity and safety critical applications. Likewise the object-
oriented paradigm is now widely used in the commercial and industrial sectors. C++ implements an
interpretation of this paradigm and there is now interest to move the paradigm into the safety critical
domain.
A number of reasons have been identified as to why the unrestricted use of the C++ language is not
suitable for high integrity and safety critical applications. However a subset of the language may
provide the restrictions necessary to make C++ suitable. The High Integrity C++ (HICPP) Coding
Standard [PRG03] has been identified as a suitable starting point for examining a safer C++ subset.
HICPP has been examined in the context of known C++ behaviours, best practice (problems and
solutions), and against a currently accepted definition of a safe programming language. It has also
been assessed in relation to the guidelines defined in the Handbook for Object-Oriented Technology
in Aviation [OOT04]. A number of additional rules and guidelines have been defined to address
identified deficiencies in HICPP and thus define a safer C++ subset.
A Goal Structuring Notation (GSN) pattern for justifying the selection of a programming language
for safety critical systems has been developed. The GSN pattern has been evaluated against the
safer C++ subset. Through this evaluation it has also been possible to demonstrate how a safety
critical project utilising C++ might instantiate such a safety argument. A method is also proposed to
evaluate its accuracy and applicability to other programming languages, and to real world projects.
This project has concluded that it is possible to use C++ to write software for use in high integrity
and safety critical applications. This may be achieved though the use of the safer C++ subset
(HICPP and additional rules) and a number of software tools for enforcement, static analysis and
dynamic testing. In conjunction, some degree of manual code reviews and design inspection are
also required. The project has also identified a few areas where improved tool support would better
facilitate safety critical software development in C++.
ii
Acknowledgments
The completion of this project would not have been possible without the help of many people.
I would like to thank the Royal Australian Air Force for their support, sponsorship and for giving
me the chance to pursue this degree in England.
I would like to thank my project supervisor, Richard Hawkins, for his invaluable guidance and
advice throughout the project. This thanks is further extended to Tim Kelly for his role in
overseeing Richard as my project supervisor.
I would also like to thank Clive Pygott and his group at QinetiQ for providing a valuable conduit
for discussion.
I would like to thank The Programming Research Group, and in particular Tony Coomber, for
providing me documentation, discussion opportunities and advice on their High Integrity C++
(HICPP) Coding Standard Manual. In addition I would like to thank them for providing a full
working copy of the QA C++ Source Code Analyser for use throughout my project.
I would like to thank Gimpel Software, for providing a full working copy of PC-Lint and the
associated documentation for use throughout my project.
I would like to thank Advantage Technical Consulting, and in particular Andy Hodgkinson, for
providing me documentation and advice on MALPAS.
I would like to thank IPL Information Processing Ltd for providing allowing me access to a full
working copy of Cantata++ and the associated documentation for use throughout my project.
Finally I would like to thank my family and friends for their love and support always.
iii
Table of Contents
Abstract.................................................................................................................................................i
Acknowledgments................................................................................................................................ii
Table of Contents ...............................................................................................................................iii
List of Tables ....................................................................................................................................... v
List of Figures .................................................................................................................................... vi
1 Introduction.................................................................................................................................1
1.1 Background......................................................................................................................................... 1
1.2 Safety Critical Systems and Software............................................................................................... 1
1.3 Project Aim, Background and Motivation....................................................................................... 2
1.4 Project Scope....................................................................................................................................... 3
1.5 Report Structure and Layout ............................................................................................................ 3
2 Literature Review ........................................................................................................................5
2.1 The C++ Programming Language .................................................................................................... 5
2.2 Programming Languages and Safety Critical Software ............................................................... 14
2.3 Programming Languages and Safety Standards ........................................................................... 22
2.4 Object-Oriented Technology in Safety Critical Systems .............................................................. 27
2.5 C in Safety Critical Systems ............................................................................................................ 28
2.6 C++ in Safety Critical Systems........................................................................................................ 30
2.7 Alternatives to C++ in Safety Critical Systems.............................................................................. 35
2.8 Software Safety Case Arguments.................................................................................................... 36
2.9 Verification and Validation of Safety Critical Software............................................................... 38
2.10 Summary of Literature Review .................................................................................................. 39
3 Analysis of the C++ Language .................................................................................................40
3.1 Identification of C++ Behaviour Ambiguities................................................................................ 40
3.2 Identification of C++ Best Practice, Problems and Solutions....................................................... 41
3.3 Identification of OOTiA Recommendations .................................................................................. 41
3.4 Summary and Direction................................................................................................................... 42
4 Development and Enforcement of a Safer C++ Subset ...........................................................43
4.1 Assessment of the High Integrity C++ Coding Standard.............................................................. 43
4.2 Development of Additional Rules.................................................................................................... 45
4.3 Rules and Guidelines Not Referenced in the Assessment ............................................................. 51
4.4 Enforcement of C++ Rules and Guidelines .................................................................................... 53
4.5 Summary of Definition of Safer C++ Subset.................................................................................. 57
5 Arguments for Programming Language Selection..................................................................58
5.1 GSN Argument for Programming Language Selection ................................................................ 58
5.2 Summary of GSN Argument for Programming Language Selection .......................................... 67
iv
6 Evaluation of Safer C++ Subset and Safety Arguments .........................................................68
6.1 Evaluation of Safer C++ Subset Against GSN Argument ............................................................ 68
6.2 Evaluation of Safer C++ Subset Against Safe Language Criteria ............................................... 76
6.3 Proposal for Evaluating the GSN Argument ................................................................................. 82
7 Conclusions and Further Work................................................................................................85
7.1 Findings and Traceability to the Project’s Aims ........................................................................... 85
7.2 Further Work ................................................................................................................................... 87
References .........................................................................................................................................88
Appendix 1 – HICPP Coverage of Industrial Strength C++ Items................................................1-1
Appendix 2 – HICPP Coverage of Effective C++ Items.................................................................2-1
Appendix 3 – HICPP Coverage of More Effective C++ Items.......................................................3-1
Appendix 4 – HICPP Coverage of Effective STL Items.................................................................4-1
Appendix 5 – HICPP Coverage of C++ Gotchas ............................................................................5-1
Appendix 6 – HICPP Coverage of Exceptional C++ Items............................................................6-1
Appendix 7 – HICPP Coverage of OOTiA Guidelines ...................................................................7-1
Appendix 8 – Unspecified Behaviour (C++ Language) .................................................................8-1
Appendix 9 – Unspecified Behaviour (C++ STL) ...........................................................................9-1
Appendix 10 – Undefined Behaviour (C++ Language)................................................................10-1
Appendix 11 – Undefined Behaviour (C++ STL) .........................................................................11-1
Appendix 12 – Implementation-Defined Behaviour (C++ Lang) ................................................12-1
Appendix 13 – Implementation-Defined Behaviour (C++ STL)..................................................13-1
Appendix 14 – Indeterminate Behaviour (C++ Language)..........................................................14-1
Appendix 15 – Rule and Guideline Enforcement Required.........................................................15-1
Appendix 16 – Programming Language Selection Pattern..........................................................16-1
v
List of Tables
Table 1: Ratings of Language Characteristics [Law97] .................................................................................................. 16
Table 2: Support Tools and Programming Language – Part 3, Table A.3 [IEC98] ........................................................ 24
Table 3: Detailed Design – Part 3, Table A.4 [IEC98] .................................................................................................... 24
Table 4: Design and Coding Standards – Part 3, Table B.1 [IEC98].............................................................................. 25
Table 5: C++ Language Unspecified Behaviour (partial extract from Appendix 8) ....................................................... 40
Table 6: Industrial Strength C++ Items (partial extract from Appendix 1) ..................................................................... 41
Table 7: OOTiA Guidelines (partial extract from Appendix 7) ........................................................................................ 42
Table 8: HICPP Coverage of Industrial Strength C++ Items (partial extract from Appendix 1) .................................... 43
Table 9: HICPP Coverage of Industrial Strength C++ Items (partial extract from Appendix 1) .................................... 56
Table 1-1: HICPP Coverage of Industrial Strength C++ Item .......................................................................... Appendix 1
Table 2-1: HICPP Coverage of Effective C++ Items......................................................................................... Appendix 2
Table 3-1: HICPP Coverage of More Effective C++ Items ............................................................................... Appendix 3
Table 4-1: HICPP Coverage of Effective STL Items .......................................................................................... Appendix 4
Table 5-1: HICPP Coverage of C++ Gotchas ................................................................................................... Appendix 5
Table 6-1: HICPP Coverage of Exceptional C++ Items.................................................................................... Appendix 6
Table 7-1: HICPP Coverage of OOTiA Guidelines............................................................................................ Appendix 7
Table 8-1: C++ Language Unspecified Behaviour [BSI03] .............................................................................. Appendix 8
Table 9-1: C++ STL Unspecified Behaviour [BSI03]........................................................................................ Appendix 9
Table 10-1: C++ Language Undefined Behaviour [BSI03]............................................................................. Appendix 10
Table 11-1: C++ STL Undefined Behaviour [BSI03] ...................................................................................... Appendix 11
Table 12-1: C++ Language Implementation-Defined Behaviour [BSI03] ...................................................... Appendix 12
Table 13-1: C++ STL Implementation-Defined Behaviour [BSI03] ................................................................ Appendix 13
Table 14-1: C++ Language Indeterminate Behaviour [BSI03] ....................................................................... Appendix 14
Table 16-1: Programming Language Selection Pattern................................................................................... Appendix 16
vi
List of Figures
Figure 1: Evolution of Programming Languages [Ver03] ................................................................................................. 7
Figure 2: Single Inheritance............................................................................................................................................... 9
Figure 3: Multiple Inheritance ........................................................................................................................................... 9
Figure 4: Complications of Multiple Inheritance ............................................................................................................. 10
Figure 5: Defined Safer C++ Subset [PRG03] ................................................................................................................ 34
Figure 6: Better representation of a Safer C++ Subset ................................................................................................... 35
Figure 7: Goal .................................................................................................................................................................. 36
Figure 8: Evidence ........................................................................................................................................................... 36
Figure 9: Strategies .......................................................................................................................................................... 36
Figure 10: Assumptions / Justifications............................................................................................................................ 36
Figure 11: Context............................................................................................................................................................ 36
Figure 12: Solved By / In Context Of................................................................................................................................ 36
Figure 13: GSN Process Overview [HRM04] .................................................................................................................. 37
Figure 14: Key to GSN Extensions [HRM04] .................................................................................................................. 37
Figure 15: Top Level Argument (partial extract from Figure 16-1)................................................................................. 60
Figure 16: Correct Implementation Argument (partial extract from Figure 16-1) .......................................................... 60
Figure 17: Error Prevention Argument (partial extract from Figure 16-2)..................................................................... 61
Figure 18: Run-time Error Argument (partial extract from Figure 16-4)........................................................................ 61
Figure 19: Definition Argument (extract from Figure 16-5) ............................................................................................ 62
Figure 20: Common Error Sources Argument (extract from Figure 16-7) ...................................................................... 64
Figure 21: Error Detection Argument (extract from Figure 16-3)................................................................................... 65
Figure 22: Static Analysis Argument (extract from Figure 16-10)................................................................................... 66
Figure 23: Dynamic Testing Argument (extract from Figure 16-11) ............................................................................... 67
Figure 16-1: Top-Level Argument.................................................................................................................Appendix 16-1
Figure 16-2: Error Prevention Argument......................................................................................................Appendix 16-2
Figure 16-3: Error Detection Argument........................................................................................................Appendix 16-2
Figure 16-4: Run-Time Error Argument .......................................................................................................Appendix 16-3
Figure 16-5: Definition Argument.................................................................................................................Appendix 16-3
Figure 16-6: Behaviours Subset Argument....................................................................................................Appendix 16-4
Figure 16-7: Common Error Sources Argument ...........................................................................................Appendix 16-4
Figure 16-8: Other Error Sources Argument ................................................................................................Appendix 16-5
Figure 16-9: Strongly Typed Argument.........................................................................................................Appendix 16-5
Figure 16-10: Static Analysis Argument........................................................................................................Appendix 16-6
Figure 16-11: Dynamic Testing Argument ....................................................................................................Appendix 16-6
1
1 Introduction
1.1 Background
The use of software for high integrity and safety critical applications is rapidly growing. While
many of these applications still exist purely within the defence or space industries, there are also
many applications that interact with the general population. The anti-lock braking system (ABS) in
the modern car, the control and signalling systems used on the railway networks, and the fly-by-
wire systems in modern commercial aircraft are a couple of examples of such systems. In fact, on a
daily basis it is difficult for many people to avoid coming into contact with systems that are
controlled by software. Such a scenario presents a number of issues.
Firstly, concerns are often raised because of the potentially disastrous consequences of a failure of
software resident within safety critical applications. Thus it is crucial that the underlying design
principles for safety critical systems are not compromised and that the systems can be shown to be
acceptably safe.
Secondly, with this growth, the number of people involved with the development of these systems
has increased proportionally. This has resulted in an influx of mainstream software technologies
into the safety critical domain. Furthermore, it is arguable that traditional high integrity languages
are becoming obsolete, and that there is interest within industry to move to more commercial
development environments [Wic98]. Some developers are complaining that it is not practical to
perform safety critical development in languages they can not recruit sufficient competent
programmers for [Wic98]. C++ is a popular computer programming language, which is touted to be
both widely used and understood. Most computing graduates from universities will have had at least
some exposure to the language regardless of the chosen teaching language at the particular
institution from which they graduated. There is also a plethora of tools and development
environments available to support the language. Thus there has been recent interest in exploring its
use for high integrity and safety critical applications.
1.2 Safety Critical Systems and Software
To assist with defining the aim of this project, it is first worthwhile establishing a good definition
for safety critical systems, high integrity systems, and safety critical software. For the purposes of
this report the terms safety critical systems and high integrity systems shall be used synonymously.
This is because of the seemingly interchangeable use of both terms throughout the literature
examined in Section 2.
[Bar02] defines high integrity systems as “systems for which failure can cause loss of life, injury,
environmental damage, or financial loss … the cost of failure is not tolerable or affordable.” This
definition focuses on the outcomes of failure. [IPL96] offers a slightly reworded definition of a
safety critical system as “a system where human safety is dependent on the correct operation of the
system.”
In a similar theme and considering software specifically, [MoD97] states that safety critical
software is “software that relates to the safety critical function or system, ie. software of the highest
safety integrity level (S4), the failure of which could cause the highest risk to human life.” [IPL96]
points out though that safety must always be considered with respect to the whole system (ie. safety
is a system issue [Dou98]). Thus in addition to the software, the computer hardware, other
electronic and electrical hardware, mechanical hardware, developers, operators and users must also
be considered [IPL96].
2
While on the topic of definitions, it is also worth considering the terms safety and reliability.
[Dou98] points out that safety is not reliability! A reliable system does not fail very often, but if it
does fail it makes no guarantees about what will happen. On the other hand, a safe system can fail
frequently, even though this is probably undesirable, but provided that it fails in a safe way, the
system is still safe.
When developing systems that have a potential to impact upon safety, software or otherwise,
[IPL96] describes a number of questions that should be addressed through the development of the
system. The answers to these questions should be documented as part of the safety case for the
system. These are as follows.
• Can it present hazards to safety?
• What can be done to reduce the hazards to an acceptable level?
• How can it be verified that the developed system is safe?
It is also important to consider the approaches and philosophies commonly adopted for the
development of safety critical systems. [IPL96] describes two distinct philosophies for the
specification and design of safety critical systems:
• “To specify and design a ‘perfect’ system, which cannot go wrong because there are no faults
in it, and to prove that there are no faults in it.” Such a philosophy lends itself to the formal
mathematical proof of design correctness being established. For large, complex systems, this
may be difficult.
• “To aim for the first philosophy, but to accept that mistakes may have been made, and to
include error detection and recovery capabilities to prevent errors from actually causing a
hazard to safety.” This means that within the software it is able to check that inputs are valid
(pre-conditions), to trap errors within the routine (assertions and proofs), and to ensure the
outputs are safe (post-conditions). At a higher level, one part of the system can independently
check that the rest of the system is behaving correctly, and vice versa.
These questions and design philosophies shall be reflected upon throughout the project.
1.3 Project Aim, Background and Motivation
The aim of this project is examine the use of the C++ programming language in the context of
safety critical systems. There is a significant amount of opinion that says that safety critical systems
in C++ are not feasible [Wic98]. But what are really the concerns? There may be inherent conflicts
of interest in some of these opinions as often the same organisations offering opinions also market
tools for their advocated language. Thus they would be at some financial advantage to have the
language that their tools support to be deemed suitable for safety critical systems.
This project endeavours to examine justifiable evidence relating to the use of C++ in safety critical
systems. This project has specifically sought answers to the following questions.
• Can the C++ programming language be used for the development of safety critical systems?
• If the C++ programming language as a whole is not suitable for safety critical systems, then
can constraints and restrictions be placed on the language (ie. language sub-setting) to permit
its use? What would these constraints and restrictions be? Can they be appropriately defined?
Are they sufficient?
3
• What tools are currently available to support the development of safety critical software using
the C++ programming language? Do the tools support verification of the software’s safety?
• What do the applicable safety standards say and could C++ be justified within the context of
these standards? How could justification be achieved?
1.4 Project Scope
This project is centred towards answering the questions defined in Section 1.3 and hence
determining if C++ can be used for safety critical system development. A number of these questions
are significant in scope. In order to facilitate the completion of the project in the allocated
timeframe, several limitations have had to be placed on the scope of the project.
Two distinct approaches have been employed in examining C++ for safety critical systems. The
first has been to examine C++ behaviours, best practice (problems and solutions) and paradigm
related issues. These have been examined in the context of C++ as a whole language, with due
consideration to subsetting as required. Although several subsets were identified, this project has
restricted its specific examination of a C++ subset to the High Integrity C++ (HICPP) Coding
Standard as defined in [PRG03]. It is not possible to consider more subsets in detail due to the scale
of analysis required for each subset. HICPP was identified early within the project lifecycle as
having many of the qualities required of a safer C++ subset and thus it shall form a central part in
this project.
The second approach has been to develop a justification argument for the selection of programming
language based on the material reviewed in the literature review. This material includes academic
papers, commercial literature and standards. The project has limited the examination of safety
standards to IEC61508, RTCA/DO178B, Defence Standard 00-55 Issue 2 and Defence Standard
00-56 Issue 3.
The evaluation phase of the project works to bring together the two approaches and evaluate the
adequacy of the approaches in relation to each other. Both approaches and the evaluation shall form
the basis on which the conclusions are to be stated.
This project has examined the role that the tools QA C++, PC-Lint / FlexeLint, Cantata++ and
MALPAS can play in high integrity C++ software development. It is not possible to consider every
other tool that might be available. However the project shall examine a mechanism for arguing the
role that potentially any C++ tool can play in the development of high integrity C++ software.
1.5 Report Structure and Layout
This report presents the research, analysis, investigation, evaluation, conclusions and
recommendations of the project and is structured as follows.
Section 2 presents a review of literature deemed relevant to the context of the project. The review
examined the C++ programming language, programming languages in relation to safety critical
software and relevant standards, object oriented technology in safety critical software, and
applications to date involving C++ in the safety critical domain.
Section 3 presents an examination of properties of the C++ programming language and examines
why a subset might improve the safety associated with the use of C++. Unspecified, undefined,
implementation-defined and indeterminate behaviours of C++ are identified. In addition best
practice, problems and solutions, in C++ are also identified. Finally guidance in relation to the use
of the object-oriented paradigm is also identified.
4
Section 4 presents an assessment and identifies deficiencies of the HICPP coding standard against
the properties identified in Section 3. From this a safer C++ subset is defined. The automatic
enforcement of these rules and guidelines is also examined.
Section 5 presents the development of a justification argument pattern for the selection of a
programming language for a safety critical system.
Section 6 presents an evaluation of the safer C++ subset against the justification of programming
selection pattern. It also details an evaluation of the safer C++ subset against identified criteria for a
safe programming language. Further evaluations are proposed for evaluating the argument pattern
against existing safety cases and design documentation, as well as evaluating the safer C++ subset
within the context of safety critical projects.
Section 7 presents the conclusions and recommendations from the project. It also details proposals
for future work considered necessary as a result of observations made during the project.
Appendix 1 - 6 presents the results of the C++ best practice, problems and solutions assessment.
Appendix 7 presents the results of the OOTiA guidelines assessment.
Appendix 8 - 14 presents the results of the unspecified, undefined, implementation-defined and
indeterminate behaviours C++ assessment.
Appendix 15 presents a list of the rule and guideline enforcement required.
Appendix 16 presents a safety case pattern for arguing the selection of a particular programming
language for a safety critical system.
5
2 Literature Review
2.1 The C++ Programming Language
The C++ programming language is one of the most popular programming languages available to
programmers today. It is generally known throughout programming circles as an expressive multi-
paradigm programming language that is powerful for solving demanding problems. In its ANSI/ISO
standardised form it is also portable across different hardware architectures. Unfortunately though,
if C++ is used without discipline it can lead to code that is “incomprehensible, unmaintainable,
inextensible, inefficient, and just plain wrong” [Mey98]. In fact some might claim that it is too
complex for all but a few to master. For these reasons and more, advocates of languages such as
Ada and Java rarely have positive comments to associate with C++.
C++ has features that make it suitable for writing the smallest of command line utilities (eg. < 1,000
lines of code), right up to very large-scale complex software systems (eg. > 1,000,000 lines of
code). The language also implements an interpretation of the object-oriented paradigm that has
helped programmers to increase software productivity, quality and re-useability [Dei94].
C++, along with Ada and Java, are third generation programming languages according to [Law97].
[Sch03] describes C++, along with C and Java as middle level languages. The lowest level,
practically useable language is assembly language. Languages such as Ada, Modula-2, and Pascal
are high-level languages. Because it is a middle level language C++ should not be considered less
powerful than the high level languages. It is middle level because it combines the best aspects of
high-level languages, while still allowing the programmer the control and flexibility of assembly
language [Sch03]. This strengthens its suitability for system-level programming such as the
development of operating systems, interpreters, compilers, and device drivers.
C++ is a structured language, as is Ada, Pascal, Java, C and Modula-2. A structured language
allows for the separation, and encapsulation of code and data. This allows programmers using one
module to only require knowledge of an interface. The programmer does not need to know how the
interface is specifically implemented. In fact the implementation may be changed, and so long as
there are no changes to the interface, then the modules accessing the functionality described by the
interface need not change. There are a few specific characteristics of C++ interfaces that may be
exceptions to this case but generally the principle is the same. [Sch03] also points out that C++ is
not strictly a block-structured language. This is because it does not permit the declaration of
procedures or functions within other procedures or functions.
This section examines the ancestry of the C++ programming language to gain an appreciation of the
influences that have worked to mould the C++ of today. Such an appreciation is important when
later considering C++ in the context of safety critical software. The section also briefly examines
the ANSI/ISO standardisation that, while many years in the coming, has been welcomed across the
C++ community.
2.1.1 Ancestry of the C++ Programming Language
In the world before C++, primal computer chaos reigned! Well, maybe there is no need to be quite
so melodramatic, but its development has certainly been born out of a rapid expansion in diversity
of computer-programming languages. As time passed, languages combined, evolved and matured.
Some languages prospered, while others vanished. This section now examines the ancestry that is
responsible for producing the C++ language as it is today.
Prior to the 1940s, computers were programmed by being ‘hard-wired’. This meant that links or
switches were set by the programmer to instruct the computer as to what operation to perform
6
[Lou93]. While at the time this was suitable enough for the complexity of computers available, it
was soon to become an outdated and inefficient technique.
In the 1940s John von Neumann came up with the idea that rather than ‘hard-wiring’ a computer’s
operation, it should instead use a series of codes or instructions stored as data to determine the
operations performed [Lou93]. Thus we saw the birth, at least in concept, of machine code - the
language of the machines. Unfortunately, the language of the machines did not equate easily to the
languages of people. Hence there was a need for further evolution of this concept. In fact such an
idea can be closely related to [Lou93]’s definition that a programming language is “a notional
system for describing computation in machine-readable and human-readable form.”
The first creditable advance in a human readable form of a computer programming language was
assembly language. Assembly language provided a means of providing names for instructions, data
and locations. This meant the programmers no longer had to face the insanity of long strings of
hexadecimal digits (0..9 and A..F, eg. FE26) or worse still binary digits (0 or 1, eg.
00101110110101011). However, assembly language is very machine dependant and has only a low
level of abstraction [Lou93]. Hence the reference to it being a low-level language. It can also be
difficult to both write and then subsequently understand [Lou93].
In an effort to reduce the level of machine dependency and increase a programmer’s ability to write
concise, understandable instructions the notion of a higher level of abstraction (high-level language)
was realised [Lou93]. In 1945, the German K. Zuse, inventor of the Z3 computer, also worked on
defining an evolved language for the Z3 [Sur04]. However little evidence and few documents still
exist. The late 1950s saw the birth of the first truly high-level programming languages including
Fortran, Cobol and Lisp. In fact most modern programming languages can trace at least some aspect
of their language definition to these early languages. Figure 1 shows a graphical representation of
the evolution of most modern programming languages and how their origins can be traced back to
these first high level languages.
According to [Ver03], Fortran is the earliest high level language from which C++ has evolved.
Fortran, which stands for FORmula TRANslation system, was first developed in 1954 and is a
language dedicated to scientific-numeric purposes [Ver03]. It was developed by John Backus and
other researchers at IBM [Sur04]. Fortran continued to evolve with numerous versions being
released (Fortran I, II, III, IV, 66, 77, 90 and 95). It is still used today for programming scientific
and mathematical applications.
Algol (ALGOrithmical Language) (1958) was designed to be the successor of Fortran by an
international consortium of computer scientist specialists. Although ALGOL didn’t succeed in
replacing Fortran, in fact [Sur04] suggests that no compiler can be found, this language is credited
as having a major impact on the evolution of programming languages [Ver03].
In the early 1960s the Combined Programming Language (CPL) was developed by Cambridge and
London Universities [Ver03]. Developed using some functional language properties in combination
with the Algol60 definition, the language was developed to supposedly cope with all possible kinds
of problems [Ver03], perhaps a little like Ada was in more recent times. However, much of the
language was never implemented.
During a visit to the Massachusetts Institute of Technology in 1967, Martin Richards (Cambridge
University) created a simplified version of CPL called Basic CPL (BCPL) [Ver03]. This language
was used up until the late 1980s at numerous establishments including Cambridge and Oxford
Universities [Ver03].
7
Figure 1: Evolution of Programming Languages [Ver03]
In 1969 Ken Thompson at Bell Labs decided Unix needed a system programming language. Ken
Thompson created B, a trimmed down version of BCPL (which in itself was a simplified version of
CPL) to fit into the 8Kb of RAM on the DEC PDP-7. No other programs, except B itself, were ever
written in the language for this machine [Ver03]. When Bell Labs acquired a new DEC PDP-11
with 24Kb RAM, the B language was ported to this new machine. Many programs were written in
B for this machine, however it also exposed a number of inadequacies of B’s semantic model
[Ver03].
In 1971, the B language was expanded by Dennis Ritchie and the name was changed to C (after a
intermediate stint as New B, or NB) [Ver03]. In the years to follow the language was further
expanded, several times. Not only was the Unix kernel completely re-written in C, but the language
was also ported to numerous other platforms [Ver03]. The popularity among programmers grew and
the language was to be ANSI standardised from 1983 to 1989, and again in 1999. It has been one of
the most popular programming languages of all times and has been used to develop software from
operating systems to word-processors, games to computer animations in movies, and about
everything in between.
8
Throughout the time that CPL and BCPL were being developed, the Simula (SIMULAtion)
language was also being developed [Ver03]. Built on a number of features of Algol, it was
principally designed for simulation and modelling purposes, but was also later extended as a
general-purpose language [Ver03]. Although it was never really successful [Ver03], it was the first
object-oriented language and introduced classes, inheritance and objects [Sur04].
Before moving onto describing object-oriented programming in further detail, and then
subsequently covering the development of C++ from C and Simula, it is worth highlighting a few
points about Figure 1.
It can be seen that there have been many other programming languages developed than those that
directly led to the development of C or C++. So why are there so many programming languages?
[Pri03] describes that every language is a trade-off among a number of competing pressures.
Importantly [Pri03] also states that “notation is important.” Thus, the closer the language to the
problem domain, the easier it is for programmers to be able to produce elegant and comprehendible
solutions [Pri03]. This will be important when the problem domain of safety critical systems is
considered.
While Figure 1 does indeed highlight the birth date for the languages it covers, and the previous
influences on a language’s development, it is important to note that the diagram does not clearly
indicate the lifetime of the languages. Many of the languages are still in use today, and some of the
languages have even evolved within themselves over that time.
2.1.2 Object-Oriented Programming
Before discussing the object-oriented aspects of the C++ language it is first worthwhile to briefly
discuss some general principles of the object-oriented paradigm. Object-oriented programming
addresses two significant issues in software design: the need to reuse software components, and the
need to maintain independence of these different components [Lou93]. [Lou93] lists five basic ways
that a software component can be modified for reuse: extension, restriction, redefinition,
abstraction, and polymorphism. These are the key attributes of an object-oriented programming
language. However, the goal of object-oriented programming is not only to allow the reuse of
software components. It also allows restrictions, or protection mechanisms, to be placed on access
to the internal details of a software component.
2.1.2.1 Objects, Classes, Instance Variables and Methods
There are a number of basic components of an object-oriented programming language: objects,
classes, instance variables and methods. An object is “something that occupies memory and has
(modifiable) state” [Lou93]. According to [OOT04] it contains both code (functions) and data
(structures). The state of an object is internal or local to the object itself and is represented by
instance variables, which are local variables declared as part of the object [Lou93]. An object can be
declared by creating an instantiation of the local state and methods, which is otherwise known as a
class. A class is similar to a data type, but it also includes a definition of the functionality that may
be enacted on its data type. [OOT04] defines a class as “a set of objects that share the same
attributes, methods, relationships, and semantics – they share a common structure and behaviour.”
Each object (instantiated from a given class) contains a set of functions and procedures through
which the local state can be assessed and changed [Lou93]. These functions and procedures are
known as methods.
2.1.2.2 Abstraction, Encapsulation & Modularity
“Abstraction denotes the essential characteristics of an object that distinguishes it from all other
objects and thus provides crisply defined conceptual boundaries” [OOT04]. The object is the device
9
that supports encapsulation, as it is the mechanism that binds code (functionality and behaviour)
and the data (attributes) it manipulates together [Sch03]. The encapsulation also prevents outside
interference and misuse of the code and data within an object [Sch03]. Modularity entails the
partitioning of a program into logically separated and defined components. Abstraction,
encapsulation and modularity work together to support the object-oriented paradigm.
2.1.2.3 Typing and Polymorphism
[OOT04] cites a definition of typing as the “enforcement of the class of an object, such that objects
of different types may not be interchanged, or at most they may be interchanged only in very
restrictive ways.” Another concept that is closely related to typing is polymorphism. Polymorphism
allows one interface to control access to a general class of actions [Sch03]. Thus for the calling
function, the interface is less complex. It allows the programmer to write programs in a general
fashion to process a wide variety of existing and importantly yet to be specified related classes. The
specific action is determined by the class or type of the data being used. In some cases, the
polymorphism may occur at compile-time, but for others the polymorphism may be required to
occur at run-time.
2.1.2.4 Inheritance and Class Hierarchy
Inheritance is “the process by which one object can acquire the properties of another object”
[Sch03]. [Dei94] provides the following definition: “inheritance is a form of software re-useability
in which new classes are created from existing classes by absorbing their attributes and behaviours
and embellishing these with new capabilities the new classes require.” Through inheritance it
becomes possible to construct a class hierarchy of abstractions. For example a class B can inherit
some or all of the instance variables and methods of another class A (Figure 2). Class B is called the
sub-class or derived class of A, and class A is the base class, parent class or super class of B.
Inheritance is traditionally expressed as the is-a relationship.
class A
class B (inherits A)
Figure 2: Single Inheritance
In the case examined above, we have what is called single inheritance, since the sub-class only
inherits from one parent class. Some languages permit multiple inheritance. Thus is it possible that
a class may inherit from two or more parent classes (Figure 3).
class A class B
class C (inherits A,B)
Figure 3: Multiple Inheritance
Multiple inheritance is a powerful technique, but it can also be the source of numerous
complications. In particular it is possible that methods may be inherited in more than one way. For
example, in Figure 4 a method from class A is inherited by class D in two different ways. This
makes it difficult to resolve references to methods. What if for example, class B redefines a method
of A?
10
class A
class B (inherits A) class C (inherits A)
class D (inherits B,C)
Figure 4: Complications of Multiple Inheritance
Some languages such as Smalltalk and Java are restricted to single inheritance to avoid such
complications. C++ does permit multiple inheritance, and thus these problems will need to be
considered.
2.1.2.5 Dynamic Binding
If a method in a base class is defined as virtual, then that method is always available for objects of
the class, but the implementation is specific for each different derived class. Virtual methods are
sometimes also called deferred [Lou93]. The appropriate method is then invoked for each object
depending dynamically on which derived class the object belongs to. This is dynamic binding and
[Lou93] states that “dynamic binding is one of the main sources of power on an object-oriented
language.” Languages that strictly adhere to the object-oriented paradigm offer only dynamic
binding [Lou93]. However, most object-oriented languages tend to offer both static and dynamic
binding of methods [Lou93]. For example, if a method is declared as non-virtual then static binding
applies, whereas dynamic binding applies to virtual methods.
2.1.3 Development of the C++ Programming Language
C++ began as an enhanced or expanded version of C and was first invented by Bjarne Stoustrup in
1979 at Bell Laboratories, New Jearsey [Str00]. Bjarne’s motivation was that he wanted to add the
object-oriented facilities from Simula into the C language [Ver03]. In fact C++ was originally titled
‘C with classes’ [Dei94]. In conjunction with introducing these features, C++ also remains a
superset of C [Dei94]. Thus programmers can still use a C++ compiler to compiler C programs.
Although C++ contains the C language, [Sch03] points out that not all the features provided by C
are used when writing good C++ programs. For example the C++ I/O system is substantially
different to the C I/O system, though both are available to the programmer. The preprocessor is
another example.
[Dew3] points out that the terminology used when discussing C++ is slightly different to the object-
oriented paradigm described in Section 2.1.2. In C++ there are data members, member functions
and abstract classes, instead of instance variables, methods and (pure) virtual base classes. The C++
terminology shall be used in this report whenever specific C++ issues are being addressed.
C++ has undergone a number of major revisions since it was conceived [Str00]. The first revision
was in 1985 and the second was in 1990. The third and most recent revision occurred as part of the
standardisation of the language. A joint ANSI (American National Standards Institute) and ISO
(International Standards Organisation) standardisation committee was formed and in 1994 released
the first draft of the proposed standard. After what was a longer period than what many expected,
caused partially by the introduction of the Standard Template Library (STL) into the language, the
C++ (ANSI/ISO) standard was officially released in 1998 and is known as Standard C++. [BSI03]
defines Standard C++ and incorporates technical corrigendum No. 1.
11
Some recent programming languages have descended from C++. These include Java, which largely
borrows the syntax of C++, but also places some refinement on pointers and memory management.
C# also draws its origins from C++ and is the main language of the .NET environment.
2.1.4 Reasons For Programming In C++
Section 2.1 mentions that the C++ programming language has become immensely popular. A
number of reasons for its popularity, summarised from advocates of the language, are as follows.
• [Sch03] describes C++ as the “universal language of programming.” [Sch03] supports this by
suggesting that it is common for algorithms or techniques to be first described using the C++
syntax. Many academic institutions also teach courses entirely within C++. In fact [Sch03]
also prophesises that C++ “will remain the pre-eminent language for the development of high-
performance software well into the foreseeable future.”
• C++ gives good support for high speed, low-level, input/output operations, which are
essential to many embedded applications. C++ is designed to generate smaller and less RAM-
intensive code than may other high-level languages. It also allows a programmer access to
some features that allow low-level control.
• C++ also remains a superset of C [Dei94]. Thus programmers can still use a C++ compiler to
compile C programs. C++ was originally designed with the intention that many C
programmers would in time migrate to using the language. In fact [Dei94] prophesied that by
the mid-1990s most major C programming environments would have converted to C++. It is
debatable as to whether this has actually occurred. C++ contains stronger type checking than
C. In fact the container classes provided in the Standard Template Library (STL) means that
programmers can move to safer alternatives for implementing types such as Strings, Arrays,
Lists and Queues. No longer is the programmer required to develop their own or rely on
existing (manual) pointer based implementations.
• C++ allows for the expression of abstract ideas through its implementation of the object-
oriented paradigm. C++ supports both single and multiple inheritance, though multiple
inheritance should not be used without appropriate considerations. C+ supports good software
engineering practices that that makes it more appropriate than those languages that don’t. C++
helps to promote software re-use. C++ can also be easily linked with modules programmed in
other languages such as C and assembler.
• The popularity of C++ has resulted in the wide availability of tools to support C++
development. Tools include compilers, development environments, static analysis tools,
coding style and rule checkers, dynamic test harness generators, and test point generators, to
name a few. Also a number of modelling packages are capable of auto-generating C++ code.
• C++ has been ANSI/ISO standardised.
Reiterating from Section 1.1, many of these reasons contribute to this project’s motivation for
determining if C++ can be used for the development of safety critical systems.
2.1.5 Best Practice, Problems and Solutions in C++
[Mey98] states that while “learning the fundamentals of a programming language is one thing,
learning how to design and program ‘effective’ programs is something else entirely.” [Mey98] goes
on to point out that this is especially true of C++ due to its “uncommon range of power and
expressiveness.” [Dew03] states that effective programming in C++ involves intelligent
12
coordination of many disparate areas. So how does a programmer master learning to design and
program ‘effective’ C++ while coming to grips with these many disparate areas? Because the C++
language is immensely popular, the volume of literature available on the language and its
application is immense. A significant subset of this literature specifically addresses the issues of
problems and solutions in C++ design and programming. In fact C++ in almost unique in the
number of textbooks available on such topics. Non C++ advocates might argue that this is because
of the principle number of flaws in the language.
The following sections review a number of significant C++ texts whose importance will be revealed
in Section 2.6.4. While a number of these texts present similar or overlapping material each has a
significant proportion of unique material so as justify its worth. The texts considered have been
highlighted because their discussion goes further than the many C++ reference texts available (eg.
[Str00] and [Sch03]). While these texts (referring to [Str00] and [Sch03]) are comprehensive guides
to the language, they tend not to provide specifics of problems and mis-interpretations of language
features.
The following sections are intended to highlight the coverage and knowledge available in published
literature on C++. Together these texts represent a very comprehensive and respected collection of
C++ programming knowledge. However, it would be unreasonably to assume their coverage is
complete. While they all point out more than a handful of areas where an un-supervised
programmer may get caught out, importantly they also highlight numerous solutions to dealing with
such problems.
2.1.5.1 Industrial Strength C++ [Hen97]
[Hen97] defines a C++ coding standard that they suggest is valid and useable for most C++
programmers. The text is intended to act as a good starting point for any organisation wishing to
produce a programming standard. Its origins can be traced back to an original a programming
standard written for a project in 1990 at Ellemtel Telecommunications Systems Laboratories in
Sweden [Hen97]. Interest in the programming standard by Bjarne Stroustrup, the initial inventor of
C++, resulted in it being freely available in 1992. Since the document was written C++ has changed
numerous times. [Hen97] represents the published form of a significant revision of the original
programming standard document that takes into account much of the ANSI/ISO standardisation.
The advice given by [Hen97] is divided into rules and recommendations. These are grouped under
the following list of categories:
• Naming
• Organising the Code
• Comments
• Control Flow
• Object Life Cycle
• Conversions
• The Class Interface
• New and Delete
• Static Objects
• Object-Oriented Programming
• Assertions
• Error Handling
• Parts of C++ to Avoid
• Size of Executables
• Portability
• Style
13
2.1.5.2 Effective C++ [Mey98], More Effective C++ [Mey96], Effective STL [Mey01]
[Mey98], [Mey96], and [Mey01] are a series of C++ books by Scott Meyers that are aimed at
teaching the C++ programmer how to improve their programs and designs. These texts are widely
referenced by literature within the C++ community. Both experienced and inexperienced
programmers alike are likely to be awakened to many situations to which they were previously (and
probably blissfully) unaware. In recent times their intent and structure has been mirrored in
producing an ‘Effective’ Java textbook.
[Mey98] contains 50 specific suggestions on how to improve C++ programs and designs. It is a
revised edition of a text of the same titled published a number of years prior. [Mey98] offers advice
on general design strategies, as well as the specifics of particular language features. [Mey98] covers
issues relating to:
• Shifting from C to C++
• Constructors, Destructors and Assignment
Operators
• Inheritance and Object Oriented Design
• Memory Management
• Classes and Functions: Design,
Declaration and Implementation
• Other Miscellany of the Language
Interestingly [Mey98] states that although his initial interest was in programming rules that could be
automatically enforced, there were limitations to such an approach. Thus instead [Mey98] was
produced. This was due to the difficulty in formalising the guidelines and the number of significant
exceptions. These limitations may be important when enforcement of rules is later addressed.
[Mey96] contains 35 additional (to [Mey98]) specific suggestions on how to improve C++
programs and designs. The text is focused more on the most recent language features to be added to
the C++ standard, as well as the more advanced programming techniques [Mey96]. [Mey96] covers
issues relating to:
• Basics
• Operators
• Exceptions
• Efficiency
• Techniques
• Other Miscellany of the Language
[Mey01] contains 50 specific ways to improve the use of the Standard Template Library (STL). The
STL provides general-purpose, template classes and functions that implement commonly used
algorithms and data structures [Sch03]. The STL is constructed from template classes to allow them
to be applied to nearly any type of data [Sch03]. However, the STL is a complex piece of software
engineering, and a programmer must have a complete understanding of the C++ language to fully
harness the STL. Most C++ programming books provide an introduction and a guide to using the
STL. [Mey01] differs in that it assumes the reader knows about the STL. Instead the focus is on
how to avoid the pitfalls and use the STL ‘effectively’. [Mey01] covers issues relating to:
• Containers
• Vector and String
• Associative Containers
• Iterators
• Algorithms
• Functors, Function Classes, & Functions.
• Programming with the STL
14
2.1.5.3 Exceptional C++ [Sut00]
[Sut00] shows by example how a programmer should go about sound software engineering in C++.
Firstly a C++ problem or puzzle is presented to the reader to ponder over. This is then followed by a
description and explanation of the one or more possible solutions to the problem. In doing so a
number of programming guidelines are highlighted to the reader. Some of the material published in
this text has been derived from the ‘Guru of the Week’ on the internet newsgroup
comp.lang.c++.moderated.
[Sut00] presents 47 puzzles, programming problems and solutions and covers issues relating to:
• Generic Programming and the C++
Standard Library
• Exception Safety Issues and Techniques
• Class Design and Inheritance
• Compiler Firewalls and the Pimpl Idiom
• Name Lookup, Namespaces, and the
Interface Principle
• Memory Management
• Traps, Pitfalls and Anti-idioms
• Other Miscellaneous Topics
2.1.5.4 C++ Gotchas [Dew03]
[Dew03] details 99 gotchas of the C++ programming language. [Dew03] defines C++ gotchas as
“common and preventable problems in C++ programming and design.” As well as presenting the
gotchas, [Dew03] also highlights that the “careful, accurate use of patterns and patterns terminology
in design and documentation clarifies code and helps prevent gotchas from occurring”. [Dew03]
describes some of these patterns. [Dew03] covers gotchas relating to:
• C++ Basics and Syntax
• The Preprocessor
• Conversions
• Initialisation
• Memory and Resource Management
• Polymorphism
• Class Design
• Hierarchy Design
[Dew03] describes that there are numerous nuances of the C++ language. It is these nuances that are
often misunderstood by programmers and thus can frequently lead to the gotchas described by
[Dew03]. However, [Dew03] also suggests that the inclusion of these nuances in the language is
deliberate, as expert programmers engaging in advanced programming and design often find uses
for them.
2.2 Programming Languages and Safety Critical Software
Despite a lack of certainty as to whether an accident has ever been contributed to the choice of
programming language [Wic98], the programming language is central to the role of translating the
intended design into actual computer code to run on the target system. Even with a safe design, it is
possible to affect the system’s safety depending on how the software is written [Dou98]. If the
system safety analysis has resulted in a set of derived safety requirements, and these requirements
must be met by the implementation, or the error detected and the system failed to a safe state, then
the programming language plays a critical role in correctly implementing such requirements. If
design flaws are introduced because of the language choice then this is clearly unacceptable. In
addition it would also be beneficial that where possible the language itself might be able to detect
flawed designs.
15
This section considers the characteristics of programming languages from numerous perspectives
and then sets about defining practical criteria against which a language can be assessed to determine
as to if it is likely to facilitate the correct implementation of the design and be deemed ‘safe’.
2.2.1 Good Programming Languages
Before considering what makes one programming language safer than another it is firstly worth
considering what makes a programming language a good programming language. After all, it is not
uncommon for one programmer during a debate with another programmer to raise the point,
perhaps even in a rather childish manner, that one particular programming language is better than
another is. But on what grounds is this being assessed? [Law97] comments that “unskilled
programmers can write bad code in any language, but a good language facilitates the production of
good code by skilled programmers.” Defining the properties of a good programming language also
makes it possible to examine the relationship between ‘good’ and ‘safe’ programming languages.
[Law97] describes a number of criteria for a good programming language.
• “Its definition should be independent of any particular hardware or operating system.”
Portability can be compromised if a language is not independent of a particular platform. This
is likely to limit the hardware and software options both for the original system and for future
upgrades.
• “Its definition should be standardised, and compiler implementations should comply with the
standard.” Unique solutions can result if compiler implementations do not comply with the
standard language definition.
• “Its compiler implementations should be commensurate with the current state of technology.”
In addition the compiler implementation should match the current language standard if the
language has been standardised. A compiler that does not meet these criteria may produce
substandard code. It may not also implement key language features.
• “It should support software engineering technology, discouraging or prohibiting poor
practices, and promoting or supporting maintenance activities.” Poor code characteristics can
lead to extended development times. In addition this can make both testing and maintenance
difficult.
• “It should effectively support the application domain(s) of interest.” Poor support for the
application domain may make the development of a clear solution difficult. This can also
have an impact on performance characteristics of the code.
• “It should support the required level of system reliability and safety.” The system is likely to
perform below expectations if the reliability is less than desired. It is also likely to become
much more costly across its lifetime. Human life and property can be at risk if safety is
compromised.
• “Appropriate software engineering-based support tools and environments should be
available.” Developer productivity and system quality can be compromised if there is a lack
of appropriate tool support.
[Law97] also describes language specific characteristics that are important. These are described in
Table 1 along with the associated ratings for numerous languages. The intention is that for a given
application a weighting is determined based on which language characteristics are deemed most
important. These weightings are then factored into an overall rating for each language. This rating
can be then used to assess the languages which are most suitable for the given application.
16
Language Generation 3GL 2GL
Language Characteristic
Weig
ht
4GL
or
5GL
Ada95 C
C++
COBOL
FORTRAN
Java
Smallta
lk
Assem
bly
Clarity of source code 5 9 5 6 7 5 8 9 1
Complexity management 2 9 5 6 2 4 7 6 2
Concurrency support 0 8 0 0 0 0 7 2 2
Distributed system support 0 5 0 0 0 0 7 0 0
Maintainability 5 9 2 7 2 2 9 7 0
Mixed language support 0 8 5 7 0 5 5 3 0
Object-oriented programming support 0 10 0 10 0 0 10 10 0
Portability 1 8 5 7 3 3 9 3 1
Real-time support 0 7 7 7 0 5 0 0 5
Reliability 3 9 1 5 3 1 8 3 0
Re-useability 1 8 3 8 3 3 8 8 1
Safety 0 6 0 3 0 0 4 0 0
Standardisation 1 10 5 5 5 5 8 3 0
Support for modern engineering methods 3 9 1 7 1 1 9 7 0
Overall Language Rating
Table 1: Ratings of Language Characteristics [Law97]
Interestingly, [Law97] has identified that safety is a key feature of a good programming language.
But it is also just one of fourteen characteristics, and thus for most non-safety critical applications
its influence is likely to play little role in determining the language selection. Interesting, there
seems to be less focus on safety for 4GL and 5GL languages. [Law97] defines that a measure of the
safety of a programming language is the “extent to which inherent language features support the
construction of safety critical systems, yielding systems that are fault-tolerant, fail-safe, or robust in
the face of systematic failures.” Reflecting on this in relation to the language criteria shortly to be
expressed in Section 2.2.3 indicates that design also plays a role in safety. Finally it should follow
that a programming language for safety critical systems should be strong with respect to this safety
definition, but to be practical it should also satisfy a significant proportion of the good
programming language features.
[Law97] also identifies software-engineering considerations that also play a role in language
selection. A further means of refining the language selection is presented in [Law97] based on the
following factors.
• Method and Process
• Metrics and Measurement
• Application Domains
• Software-Reuse
• Re-engineering
• Development Environment and Tools
• Education and Training
Thus it is evident that a good language is not merely considered the sum of its characteristics. In
addition the external environment in which the language is applied also plays a critical role in the
language’s fitness for purpose.
2.2.2 Choice of Programming Languages for Use in Safety-Critical Systems
Section 2.2.1 examined the criteria for a good programming language, noting that such a definition
is always impacted upon by the context of the application. For safety-critical software the context is
the safety critical system. For example, it was earlier highlighted that [MoD97] states that safety
17
critical software is “software that relates to the safety critical function or system, ie. software of the
highest safety integrity level (S4), the failure of which could cause the highest risk to human life.”
There are a number of factors to consider when considering a language for a safety critical system.
• Language choice: including the functional characteristics [Sto96], logical soundness and
simplicity [Bar02], expressive power [Bar02], security [Bar02] and standardisation [Hat94].
• Availability of compile-time checking and run-time checking [Dou98];
• Exceptions versus error codes [Dou98];
• Bounded space and time requirements [Bar02];
• Use of ‘safe’ language subsets [Dou98];
• The availability and quality of support tools [Sto96]; and
• The expertise available within the development team [Sto96].
Some programmers, especially those working with embedded applications, dismiss run-time
checking because of the performance overhead. Though perhaps a safe design should cater for this
performance overhead by specifying appropriately resourced hardware. [Dou98] points out that a
programmer should “make it right before you make it fast.” In considering these factors, it is also
worth considering if some programming features are more prone to problems than others. [IPL96]
details a number of reasons why some programming language features are more prone to problems
than others:
• Programmers may be prone to making errors when using the feature;
• Compilers may be prone to poor or incorrect implementation of the feature;
• Programs written using the feature may be difficult to analyse, test or prove; and
• The feature may introduce implementation dependencies, reducing portability.
[IPL96] also details a number of specific language features which are prone to causing problems
and discourages their use:
• Pointers
• Dynamic Memory Allocation and
De-allocation
• Unstructured Programming
• Variant Data
• Procedural or Function Parameters
• Multiple Entry and Exit Points
• Implicit Declaration and Implicit
Initialisation
• Recursion
• Concurrency and Interrupts
[Hat94] also defines characteristics of languages relating to empirically determined behaviour.
These parts of the language are typically well defined, but seem to cause problems. In addition the
abuse may not be obvious.
18
• Errors of Misplacement: relates to instances whereby semantically correct portions of code
are placed in the wrong place within a block structure, and thus resulting in behaviour that
may be unpredictable.
• Errors of Omission and Addition: relates to instances whereby the omission or addition of a
symbol or character results in another legal but unintended language construct. Some
languages combat such problems by creating language symbols that are not closely related.
• Floating Point Misbehaviour: relates to the indeterminate behaviour that often arises when
comparing floating point numbers.
• Unexpected Behaviour: relates to those features of the language that although legal do not
follow assumed language conventions, or are frequently misunderstood by programmers. A
common example of such a feature is the evaluation order and precedence within expressions.
Despite the rather long list of traps that it would seem there are for programmers to fall into,
[IPL96] also states however that “in some circumstances the careful and constrained use of features
such as multiple exits, pointers, recursion, concurrency and interrupts, can actually reduce
complexity and enhance reliability.” [IPL96] also describes a number of features of languages that
also increase reliability. These include:
• Strong Typing
• Run-Time Constraint Checking –
including Arithmetic Exceptions,
Overflow, Validity of Pointer Addresses,
or Array Bounds.
• Parameter Checking
• Block Structure and Modular
Programming
[Dou98] also suggests that strong compile-time checking, support for encapsulation and abstraction,
and exception handling are features that increased reliability. Noting of course the earlier
differences in the definition of reliability and safety.
In an effort to formalise the selection criteria for a safe language, [Cul91] identifies a list of
questions that should be addressed when choosing a language:
• Can the control flow be totally determined and that the program cannot jump to an arbitrary
location (ie. there are no wild jumps)?
• Are there language features that prevent overwrites of an arbitrary storage location?
• Are the semantics of the language sufficiently defined for the translation process such that
static code analysis is feasible?
• Is there a rigorous model of mathematical operations (ie. integer and floating point
arithmetic) in the language standard?
• Are there procedures for checking that the program obeys the model of arithmetic when
running in the target environment?
• Are there sufficient means of preventing misuse of variables through strong data typing?
• If the software detects a malfunction at run-time, are there mechanisms (ie. exception
handlers) to ensure recovery?
19
• Does a safe subset of the language exist which is defined to have properties that satisfy these
requirements more adequately than the full language?
• Are there facilities in the language to guard against running out or the exhaustion of memory
at run-time (eg. to prevent stack and heap overflows)?
• Does the language provide facilities for the separate compilation of modules, with type
checking across the module boundaries?
• Is the language well understood by programmers and designers to ensure confidence in the
resultant software?
[IPL96] states that “there are no commonly available programming languages which provide all of
the good language features, while not providing any of the bad language features.” [IPL96] then
proposes that the means of reducing the impact of the bad language features is to use a language
subset. A subset then consists of using the good features of a language, while the bad features are
either not included or their impact is controlled [IPL96]. For some languages the subset may simply
be a subset of the language’s grammar, for others the subset may also need to address features and
functionality of the language. The use of the subset will either require the programmers to be
disciplined in their use of the language. Alternatively, and perhaps more desirably is to use software
tools to enforce the language subset. Though, generalised rules may pose problems to this approach.
[Hat94] defines a number of areas relating to specific language features that should at the very least
be mitigated or controlled when defining a safe language subset. The aim is to ensure that the
language subset has a defined, predictable behaviour.
• Unspecified or Undefined Behaviour: relates to legal (and illegal) language features about
which the standard declines to specify;
• Implementation-Defined Behaviour: relates to language features whose implementation,
although defined, is allowed to vary from implementation to implementation;
• Locale Specific Behaviour: relates to issues that are region or equipment specific; and
• Accidentally Defined Behaviour: relates to language features that exhibit strange behaviour
because the standardisation committee was ‘having a bad day’.
A comparison of computer programming languages described in [Sto96] shows that a subset
provides a considerable safety improvement when compared to the its parent language. It is for this
reason that [Sto96] states that “subsets … are preferred for all safety-critical applications.” Of
course, the safety case for the safety critical system should be then prepared to justify the choice of
the language, use of the subset, or any deviations from the subset [IPL96].
2.2.3 Requirements of Safe Programming Languages
Section 2.2.2 examines a number of factors that might impact upon the selection of a programming
language for use in the development of a safety-critical system. From these factors it is possible to
go about defining the criteria for assessing if a programming language can be deemed to present the
least risk to correctly implementing the design.
[Kwo03] summarises from numerous sources, including some of those covered in Section 2.2.2,
and proposes a set of requirements of programming languages for the development of high integrity
systems. [Kwo03] states “it is important to note that that this collection of criteria is neither
20
complete nor authoritative, but it attempts to amalgamate many different requirements into a
balanced and informative framework for the assessment of programming languages.” An inspection
of the criteria defined by [Kwo03] against those defined in Section 2.2.2 reveals that [Kwo03] is
comprehensive. It incorporates essential safety criteria, but also reflects other characteristics of
good programming languages including reliability. Thus a set of criteria is established. It is
important to note that the criteria does not explicitly list any paradigm (eg. object-oriented) criteria.
Instead it sets about defining the general goals that should be achieved. Object-oriented restrictions
to support these criteria are examined in Section 2.4.
[Kwo03] proposes two levels of criteria for an assessment of programming languages: Mandatory
Requirements (M) and Desirable Requirements (D). The following sections explain the criteria.
2.2.3.1 Syntactical / Semantic Requirements (M)
• Type Safety / Strong Typing Rules: Implicit type conversions must not be allowed as they
detrimentally influence the level of program safety [Kwo03]. Type conversions are known to
influence the safety of control flow, and the use of memory (stack, heap). In addition, all data
types (including user specified types) should be analysable prior to the program being
executed (eg. statically at compile-time) [Kwo03]. Such a characteristic is often reflected in
type safe or strongly typed languages. Many languages define explicit type conversion rules
or operators. These should be clearly specified within the language standard or definition
[Kwo03]. They should be used judiciously and only when absolutely necessary. The language
should also include means of avoiding access types or pointers [Kwo03].
• Side Effects in Expression / Operator Precedence Levels / Initial Values: There should be no
side-effects of expressions (time-dependant or otherwise) that can result in a program
behaving ambiguously or unpredictably [Kwo03]. The operator precedence levels must be
unambiguously defined in the language standard or definition [Kwo03]. The implicit
initialisation of variables should not be permitted as it can cause the unintended behaviour of
software [Kwo03].
• Modularity / Structures: In order to ensure the complexity of the software is manageable, the
language should include mechanisms to structure and modularise the code both syntactically
(blocks and scopes) and semantically (clear interfaces) [Kwo03]. Wild or unbounded jumps
between scopes or modules should be disallowed. [Kwo03]. Separate compilation of modules
should be possible [Kwo03].
• Formal Semantics / International Standards: The language should be defined in an
(international) standard such that the benefits of the development of compilers, tools and user
training can be harnessed [Kwo03]. The definition should include the sufficient formal
definition of semantics such that verification techniques can be applied to the language
[Kwo03].
• Well-understood: In order to best facilitate the correct implementation of a programming
solution the programming language should be simple, well understood, easy to adopt, and
easy to implement [Kwo03]. Well-understood semantics and syntaxes can also help in the
production of quality, cost effective software [Kwo03].
• Support for Domain Specific or Embedded Applications: As safety critical systems are often
implemented in terms of embedded systems, then the language needs to have a robust means
for controlling memory, I/O devices and other hardware [Kwo03].
21
• Concurrency / Parallel Processing: The language should include support for multi-tasking or
multi-threading to ensure that it can easily be used to model real world problems [Kwo03].
The language should facilitate the programmer some control over the scheduling as well as
one or more means for straightforward communication and synchronisation between
tasks/threads [Kwo03]. Concurrency brings with it a number of complexities in program
analysis and verification and as such mechanisms should be available within the language to
bound complexities such as blocking [Kwo03].
2.2.3.2 Application of Verification Techniques / Predicability (M)
• Functional Predicability: Software for use in safety critical systems must be proven to be
functionally predictable in its behaviour [Kwo03]. The following analysis techniques are both
applicable and necessary: control flow analysis, data flow analysis, information flow analysis,
symbolic execution, and formal code verification [Kwo03].
• Temporal Predicability / Timing Analysis: In addition to functioning correctly, programs
should also be able to guarantee a predictable, timely behaviour [Kwo03]. It must be possible
to determine a Worst Case Execution Time (WCET) for each process such that all aspects of
schedulability can be analysed [Kwo03].
• Resource Usage Analysis: The uses of resources such as memory (stack or heap), and other
resources shall be analysable [Kwo03]. The use of such resources shall be such that errors
shall not occur [Kwo03].
2.2.3.3 Language Processors / Run-time Environment / Tools (M)
• Certified Language Translators / Run-time Environments: The compilers and other tools used
in the translation of the program code into machine code play a critical role in ensuring the
safety of the software. Thus they need to have a high level of assurance associated with them
[Kwo03]. Compilers and other tools (including run-time environments) should be formally
certified by an authoritative or trusted organisation [Kwo03]. Traceability should be
established between low level code and source code [Kwo03].
• Run-time Support / Environment Issues: Libraries (and other additional code) should be
deterministic, predictable and analysable in terms of functionality, behaviour and timeliness
[Kwo03]. These factors should be accurately known if the library is to be included. The
implementation dependencies should be eliminated where possible, and minimised where
necessary [Kwo03].
2.2.3.4 Syntactical / Semantic Requirements (D)
• Exception Handling / Failure Behaviour: The graceful degradation or recovery from any sort
of error that occurs is considered important particularly for safety critical systems. As such,
[Kwo03] specifies that a “robust and analysable run-time error detection and handling
mechanisms should exist.” Furthermore, there should be a means by which the programmer
can specify the failure behaviour [Kwo03].
• Model of Mathematics: The mathematical model within the language should be rigorously
defined [Kwo03]. Specifically, [Kwo03] states that “a model of both integer and floating
point arithmetic should be defined within the language standard.” In addition, some level of
checking of arithmetic should occur at run-time [Kwo03].
• Support for User Documentation: Comments embedded with the software can improve
readability and maintainability [Kwo03]. Furthermore some language processors may be able
22
to detect logical errors or to obtain extra information from formally structured comments and
as such [Kwo03] specifically details that the language should include a means of capturing the
programmers intentions within the comments of the source code.
• Support for a Range of Static Types Including Sub-types and Enumeration Types: Dynamic
types are more difficult to check than static types [Kwo03]. Enumeration types can also help
reduce errors by limiting the number and value that a given type can be legitimately assigned.
• Coding Style Guidelines: Coding style guidelines work to enforce the practice of
programming in a particular language by promoting conformance to well-established software
engineering principles [Kwo03].
• Support for Abstraction and Information Hiding: The employment of abstraction and
information hiding techniques is considered good software engineering practice. Such
techniques can help reduce the apparent software complexity and these can also be beneficial
in software design, development, testing and maintenance [Kwo03].
• Assertion Checking: User defined assertions can be used to check specific conditions. These
may be checked statically during development (compile-time). Alternatively, the assertions
may be checked dynamically during execution (run-time). While the means of defining and
dealing with assertions both statically and dynamically may vary, both are considered
desirable characteristics of a language [Kwo03].
2.2.3.5 Language Processors / Run-time Environment / Tools (D)
• Certified (Static/Dynamic) Analysis Tools: Analysis tools can be used to check for errors such
as race conditions and deadlocks [Kwo03]. In order to gain confidence in the results of such
analysis, it is imperative that these tools be certified to some degree.
• Interface to Other Languages: The language should include a means of interfacing functions
or libraries written in other programming languages to programs written in this language
[Kwo03]. These functions and libraries may have been developed in other high level
languages, however there is often a requirement to also interface functions or libraries written
using low level languages.
• Code Optimisation: There are numerous means and tools that can be used to optimise
software code and thus improve the efficiency of the code. These optimisations should not
“alter the semantics of correct programs”, likewise they should not “compromise the
application of analysis techniques” [Kwo03].
• Code Portability: The diversity of platforms on which software may execute makes it
desirable to have software code that can be directly portable without necessitating subsequent
analysis [Kwo03].
2.3 Programming Languages and Safety Standards
The certification of safety critical systems often requires the use of appropriate standards and
guidelines. Safety standards are often particular to industry or government sectors, engineering
disciplines, or a combination of both. The following sections examine a number of standards that
are considered to be the most relevant to software in the safety critical domain. Note that there are
other safety standards that relate to software, but these will not be specifically examined here. The
intention is to establish an understanding of the programming language (and associated)
requirements of these standards such that they can be later examined in the context of the C++
23
programming language. There are many common themes between the guidance presented in a
number of these standards and the language features presented in Section 2.2.2. Such a fact suggests
that there is widespread agreement on language features that can impact upon safety.
2.3.1 Safety Integrity Levels (SILs)
Firstly, because a number of the standards deal with Safety Integrity Levels (SILs), it is worth
defining them. SILs are often the source of much confusion and thus it is worth firstly clarifying a
few important points. The purpose of SILs is to define a set of levels that corresponds to a
probability figure (or range) representing the required level of protection against failure. Depending
on the standard in which the SIL is defined this may be a qualitative or quantitative value. This
safety integrity level is then used to guide the formation of the development processes and controls.
Guiding factors include the degree of rigour and scrutiny to be applied.
Numerous safety standards refer to SILs. IEC 61508 [IEC98] and Defence Standard 00-55
[MoD97] refer to SILs of levels 1 to 4, with 4 being the level of the highest integrity. In contrast,
RTCA/DO178B [RTC92] defines software levels A to E, with A being the level of the highest
integrity.
It is important to recognise that the definition of the various integrity levels can vary between
standards and the reader should refer to the specific standard for the appropriate definition. One can
not simply directly convert from one integrity level in one standard to the corresponding level from
another standard. Instead, the specific requirements of the standard needs to be assessed against the
techniques and methods applied to the given project.
2.3.2 IEC 61508 – Functional Safety: Safety Related Systems
IEC 61508 addresses the functional safety of electrical/electronic/programmable electronic safety-
related systems. The standard is considered an international standard and is not specific to a single
industry (ie. it is a generic standard). The intention is that the standard will form the basis on which
other industry specific standards will be built [Sto96]. The standard adopts a risk based approach to
the determination of safety level requirements. Part 3 of the standard specifically relates to software.
In addition, Annex C of Part 7 of the standard gives an overview of techniques and measures for
achieving software safety integrity. The requirements of this standard are by far the most detailed
and prescriptive of either of the other standards considered. In fact [Hat94] points out that the draft
to this standard was the “most comprehensive assessment of the requirements for safety-related
software” that had been seen at that time.
[IEC98] details that the programming language shall:
• “have a translator/compiler which has either a certificate of validation to a recognised national
or international standard, or it shall be assessed to establish its fitness for purpose”;
• “be completely and unambiguously defined or restricted to unambiguously defined features”;
• “match the characteristics of the application”;
• “contain features that facilitate the detection of programming mistakes” and
• “support features that match the design method”.
[IEC98] goes on to state that should the above not be able to be satisfied, then a justification for an
alternate language shall be documented, in which controls for the shortcomings of the language are
identified. The following tables extracted from [IEC98] represent the most significant specific
24
guidance given in relation to the selection of the programming language. The reader is encouraged
to refer to [IEC98] for specific descriptions of each of the items presented, as it is not the intention
to reproduce the material here. Table 2, Table 3, and Table 4 details the most relevant guidance on
programming languages presented in [IEC98]. Each technique or measure in Table 2, Table 3, and
Table 4 is annotated with a recommendation for safety integrity levels 1 to 4. These
recommendations are as follows.
• HR: “the technique or measure is highly recommended for this safety integrity level.”
• R: “the technique or measure is recommended for this safety integrity level as a lower
recommendation to a HR recommendation.”
• ---: “the technique or measure has no recommendation for or against being used.”
Table 2: Support Tools and Programming Language – Part 3, Table A.3 [IEC98]
Table 3: Detailed Design – Part 3, Table A.4 [IEC98]
25
Table 4: Design and Coding Standards – Part 3, Table B.1 [IEC98]
The programming language should also provide for a block structure, translation time checking, and
run-time type and array bound checking [IEC98]. In addition the language should encourage the use
of small and manageable software modules, restriction of access to data in specific software
modules, definition of variable sub-ranges, and any other type of error limiting constructs [IEC98].
If there are real-time constraints, then the language should also provide exceptions/interrupt
handling. Table 4 is a little unique in [IEC98] as it uses the terminology ‘no’ or ‘limited use of’ to
prohibit potentially dangerous language features. Other tables in [IEC98] recommend rather than
limiting the use of techniques.
[IEC98] also provides recommendations for specific programming languages. This advice covers
Ada, Modula-2, Pascal, and Fortran 77, including subsets of each of these to name but a few. The
standard also highly recommends C with subset and coding standard, AND use of static analysis
tools [IEC98]. Importantly [IEC98] does not specifically advocate C++, nor does it prohibit it.
Interestingly, [IEC98] states that “at the time of developing this standard, it is not clear whether
object-oriented languages are to be preferred to other conventional ones.”
2.3.3 RTCA/DO178B – Software Considerations in Airborne Systems
RTCA/DO-178B was written to address a rapid increase in the use of software in airborne systems
in the civilian aviation sector. The standard is aimed at manufacturers seeking certification by their
relevant aviation authorities.
RTCA/DO-178B details that the manufacturer should have software code standards to define the
programming languages and/or defined subset, methods, rules and tools to be used to code the
software [RTC92]. “For a programming language, reference the data that unambiguously defines
the syntax, the control behaviour and side-effects of the language” [RTC92]. [RTC92] also suggests
that there may be a requirement to limit the use of some features of the language, but does not go
into how this might be achieved. There is no specific mention of particular programming languages,
and as such the standard does not prohibit the use of any languages.
RTCA/DO-178B also details that the manufacturer should have software design standards. These
are pretty closely related to the software code standards mentioned above in that the design
standards are used to define the methods, rules, and tools to be used to develop the software
architecture and low-level requirements [RTC92]. [RTC92] details that conditions should be placed
on scheduling, the use of interrupts, event driven architectures, dynamic tasking, re-entry, global
data, and exception handling. In addition, the constraints should be placed on the design including
the exclusion of recursion, dynamic objects, data aliases, and compacted expressions. [RTC92] also
defines a number of complexity restrictions including the maximum level of nested calls or
26
conditional structures, use of unconditional branches, and number of entry/exit points. The standard
also addresses issues such as naming conventions, stylistic issues, and the use of design, translation,
and coding tools. The standard does offers some guidance on the use of the programming language
and the verification and use of the compiler [RTC92].
Largely the standard relies on engineers taking a disciplined approach to software. Because of this,
[Hat94] criticises RTCA/DO178B for avoiding software measures and for not mandating
quantitative terms for evaluating software reliability. However, [Sto96] references a report that
concludes that RTCA/DO178B is a mature standard that has much to recommend it.
RTCA/DO178B is widely used throughout the international community despite its age. Thus there
are likely to be many manufacturers that may be interested in the certification of systems
programmed using C++ in relation to the standard.
2.3.4 Defence Standard 00-55 – Safety Critical Software in Defence Equipment
Defence Standard 00-55 Issue 2 addresses requirements for safety related software in defence
equipment for the United Kingdom’s Ministry of Defence (MoD).
[MoD97] details that the software should be programmed using a high level language or a pre-
defined subset of a high level language. The language should be strongly typed, block structured,
have a formally defined syntax, and exhibit predictable program execution [MoD97]. Furthermore,
[MoD97] specifies that the choice of programming language shall be justified in the Software
Safety Case. Coding practices should also be established, and in the case where a language subset is
utilised, then it should be defined and the means of enforcing it should also be addressed.
[MoD97] also details that the semantics of the language need to be well defined and that both static
and dynamic checks are required. The language should also be traceable between the formal design
and the execution of statements in the language. [MoD97] describes that this can be achieved if the
language has accepted formal semantics and a proof theory in terms of the formal method in use or
in terms of a proof obligation generator. [Sto96] points out that this standard sets itself apart from
the other standards examined here in that it mandates the use of formal methods.
The only exception to the stipulated use of high level languages is for limited use of assembly code
in sections of the code where high level languages are not suitable or in very small applications
[MoD97]. There is no stipulation of specific languages, though Ada is mentioned briefly in some of
the latter application and techniques examples in Part 2 of the standard.
[MoD97] suggests that at lower SILs, language selection criteria other than integrity alone may
have a greater influence than at higher SILs. For example tool support, performance and portability
may be more desirable criteria. [MoD97] also provides some guidance on the selection of use of the
compilation and tool sets.
It should be noted that at the time of writing this report, the draft Defence Standard 00-56 Issue 3
[MoD04] states that it supersedes Defence Standard 00-55 Issue 2. Defence Standard 00-56 Issue 3
is a goal based standard, not a prescriptive standard as was 00-55 Issue 2. Some references are made
to the choice of programming languages in relation to the demonstration of good practice, and the
selection of evidence types. Rather than prescriptively mandating certain languages or language
characteristics, the standard leaves the justification of the language’s safety to the developers of the
safety case. Thus the developers must present a justifiable argument for the language selection and
there is scope for a means to be examined through which this can be achieved. This is further
explored in Section 2.8.
27
2.4 Object-Oriented Technology in Safety Critical Systems
Section 2.2.3 mentions that the language paradigm was only covered by the language criteria as far
as its contribution to the other criteria. Thus there is motivation to consider how the paradigm, and
particularly how object-oriented programming, might contribute to these criteria. Object-oriented
programming has grown into an immensely popular programming paradigm in recent times.
Modern languages including Ada95, C++, and Java all contain object-oriented features. To date,
there has been little application of the object-oriented paradigm to safety-critical applications,
though it is presently the focus of much attention. The following sections examine some of the
problems surrounding object-oriented programming in safety critical systems, as well as current
guidance on mitigating these problems.
2.4.1 Concerns Over Object-Oriented Technology in Safety Critical Systems
In a similar theme to those features of traditional programming languages that are known to be error
prone, there are also numerous challenges relating to the object-oriented paradigm. The challenges
of using object-oriented technology within safety critical systems that require rigorous verification
and certification are non-trivial [Bar02]. “The object-oriented model severely conflicts with the
highly static model that is required in high integrity systems to meet the goals of time and memory
boundedness assurance, and of determinism in data transformation due to code operation.” [Bar02].
The following sections now examine some of the principle concerns.
2.4.1.1 Constructors and Destructors
The creation and destruction of objects has the potential to impact upon being able to statically
prove the time and memory constraints of a given system (ie. the lifetime of an object should be
able to be statically determined by the scope in which it is created) [Bar02]. For example, there are
issues relating to the need to create objects in dynamically-allocated memory that can result in
associated non-determinism regarding heap fragmentation, exhaustion and compactions, as well as
unbounded heap allocation times [Bar02]. In addition the correct initialisation (construction) of an
object is also important. Garbage collectors that are used in numerous object-oriented languages
introduce overheads and unpredictability into the finalisation of objects [Bar02].
2.4.1.2 Hierarchy and Inheritance
Interface contracts can be violated if a subclass operation overrides an operation in a superclass and
then fails to conform to the original pre-conditions and post-conditions of the superclass operation
(Liskov/Wing substitution principle) [Bar02]. In fact [Bar02] points out that the major risk of
inheriting operations is “not understanding the pre-conditions associated with the use of the
operation, and not abiding with those pre-conditions in the context of the subclass.”
Multiple inheritance also introduces problems both in terms of ambiguity of semantics and of
implementation complexity.
2.4.1.3 Polymorphism and Dynamic Dispatching
Polymorphism and dynamic dispatching undermine certain aspects of static analysis [Bar02]. This
is because the actual object that is represented by a polymorphic object can only be determined at
run-time. This interferes with data and information flow analysis [Bar02]. In addition control flow
analysis can be undermined because the operation to be called by dynamic dispatching is only
known at run-time [Bar02]. These issues do not only undermine static analysis, they also impact
traditional testing methods also. [Bar02] also highlights that polymorphism and dynamic
dispatching also impact upon schedulability and response time analysis, model checking and object-
code coverage analysis.
28
2.4.1.4 Obscurity
[Bar02] states that “the creation of large class hierarchies can result in obscurity in determining the
provenance of an inherited operation at the point of call.” In addition, inheritance may also hide
from users restrictions and implicit semantics of particular operations [Bar02].
2.4.1.5 Dead-code/Deactivated Code
[Bar02] describes that object-oriented programs are very susceptible to generating deactivated code.
When all subclasses that inherit a particular superclass override a given operation, then it is possible
that there may be no instances of calls to that superclass operation in a program. Thus, while this
operation’s code is still resident with the object, this code may never called and thus constitutes
dead or deactivated code. Because is may never be called, it is unlikely and difficult to test and thus
it may be difficult to gain confidence that it cannot have any impact on run-time behaviour of the
program. For a system where there are many fully overridden operations, then this has a major
impact on reaching code coverage targets.
2.4.2 Handbook for Object-Oriented Technology in Aviation (OOTiA)
There has been some effort made to address the problems described in Section 2.4.1 across the
aviation community. The Handbook for Object-Oriented Technology in Aviation (OOTiA) is
presently in draft form for public comment. The purpose of the handbook is to “identify key issues
and provide some ways to address these issues when using OOT in safety critical aviation products”
[OOT04]. It specifically attempts to address compliance with the objectives of RTCA/DO-178B
which was not written with object-oriented technology in mind [OOT04]. The handbook is the
result of the collaboration of the FAA, National Aeronautics and Space Administration (NASA),
other government organisations, academia, international certification authorities, avionics
manufacturers, and aircraft manufacturers. It is important to note that the handbook does not
constitute FAA policy or guidance, and nor is it intended to be an endorsement of OOT [OOT04].
[OOT04] presents guidelines in the following key areas:
• Single Inheritance and Dynamic Dispatch
• Multiple Inheritance
• Templates
• Inlining
• Type Conversion
• Overloading and Method Resolution
• Dead and Deactivated Code, and Re-Use
• Object-Oriented Tools
• Traceability
• Structural Coverage
Given the breadth of government, industry and intellect that has contributed to the production of the
handbook, it is likely that it represents a comprehensive and accurate examination of issues relating
to object-oriented technology at this time. The handbook is yet to address language specific issues.
Thus it would be worthwhile to explore the OOTiA guidelines within the specific context of the
C++ programming language.
2.5 C in Safety Critical Systems
Because the C programming language is a subset of the C++ programming language, it is
worthwhile to explore the use of C in safety-critical systems. The intention is to seek an
understanding of some of the issues that may also relate to the C++ language.
29
An informal survey conducted by [Row94] examined the use of languages in safety-critical projects
across a number of industries. The survey made no distinction between different levels of integrity,
nor did it identify the specific use of any language subsets [Sto96]. [Row94] points out a number of
safety-critical projects that used C and these are as follows. Note that this survey is now ten years
old and that the use of the language has most certainly changed since then.
• Aviation and space applications – including Honeywell’s aircraft navigation data loader, some
sub-systems of the NASA space station, some systems developed by Rockwell Space Systems
Division, and Teledyne’s aircraft flight data recorder;
• Numerous automotive systems – the release of the MISRA C guidelines in 1998 has arguably
widened the use of the language for such systems; and
• Baxter’s left ventricular heart-assist.
The C programming language is also widely used in numerous military electronic warfare software
applications, and military developmental flight test establishments.
[Cha04] points out that great care needs to be exercised when using C within safety critical systems.
In fact [MIS98] details a number of concerns and problems relating to its use and thus concludes,
“the full C language should not be used for programming safety-related systems.” However
[MIS98] also points out the language is very mature, and well analysed and supported in practice.
Thus [MIS98] reasons that with appropriate constraints, then the language can be applied to safety-
critical systems. [MIS98] then provides a set of such constraints (ie. a subset) for the C language
that is otherwise known as MISRA C. This subset consists of required and advisory rules. All of the
provisions described in [MIS98] are to be adopted for MISRA Integrity Level 2 and 3, but they
make no recommendations for MISRA Integrity Level 4.
Despite the documented examples of the C language’s presence in such systems, there is also much
opposition to its use. For example, an anonymous C expert states in [Cha04] that “MISRA C is a
shack built on a swamp.” [Cha04] goes on colourfully to say that C90 (or even C99) “is a swamp
that cannot be drained.” In addition the MISRA C rules are ambiguous [Cha04].
There have been attempts to develop an annotated C subset for the C90 programming language
(SPADE C) akin to SPARK for Ada [Cha04]. SPADE C did not succeed, nor where the results
widely publicised [Cha04].
[Cha04] argues that MISRA C cannot be deemed best practice, especially given the presence of
languages like Eiffel and SPARK. However [Cha04] also states not to “give up on MISRA C! It
may be a shack built on a swamp, but it’s the best shack you’ve got!”
The MISRA C guidelines recommend seriously considering other languages in preference to
MISRA C for safety critical software [MIS98]. In fact [MIS98] takes care to point out that they are
not trying to promote the use of the C language for such applications, but instead to promote the
safest possible use of the language.
Thus it would seem that there are problems with the C language for the highest integrity systems.
But this may not necessarily transpose onto the C++ language. Despite C being a direct subset of
the C++ language, there are also features of the C language that should not be used in well-written
C++ code. The following section now examines C++ and safety critical systems.
30
2.6 C++ in Safety Critical Systems
Section 2.1.4 outlined a number of reasons that C++ may be selected as the language of choice for a
particular application. We shall now consider what use C++ has seen to date in safety-critical
systems, the motivation for using C++ for safety critical systems, and what is the likely way ahead
for using C++ in safety critical systems in the future. The following sections also examine a number
of perceptions relating to the use of C++ in safety critical systems.
2.6.1 Previous Use of C++ In Safety-Critical Systems
As mentioned in Section 2.5, an informal survey conducted by [Row94] examined the use of
languages in safety-critical projects across a number of industries. [Row94] points out a number of
safety-critical projects that used C++ and these are as follows. Note that this survey is now ten years
old and that the use of the language has most certainly changed since then, especially given the
standardisation of C++ in 1998.
• Space shuttle experiment (March 1994);
• Northrup B2 bomber control system; and
• Automotive systems (numerous, including diesel engine controls).
Thus it can be seen that at least for the cases listed above that there has been some past application
of the C++ programming language to safety critical systems. From this we may draw a number of
conclusions. Firstly, there has been some interest to see the language employed in the safety critical
field. Secondly, so far there has been no real application evidence from which to conclude that C++
is not suitable for safety critical applications.
2.6.2 Perceptions and Opinions on C++ and Safety
As few discussions on any topic are often free from perceptions and opinion it is worth now
examining some perceptions and opinions on C++ and safety. [Wic98] presents a moderated
discussion on C++. The following generic language perceptions and opinions are extracted from
[Wic98].
• The impact of the programming language is significant. Safety critical software should not be
written in languages designed for other purposes.
• The programming language must be able to be shown to represent the design.
• It is unreasonable to assume that every programmer in the language is an expert.
• Object-oriented programming languages are hard to test.
• The language should support the possibility of mathematical verification of algorithms and
implementations against requirements. Achieving the error rates required for safety critical
software requires different methods, not just the same methods with more care.
• Choosing a language because it is ‘states-of-the-art’ or because it is ‘better specified’ is too
narrower a basis for such a decision. An assessment considering all factors is the appropriate
approach.
31
• Programmers can write good and bad code regardless of the language. Programmers are likely
to write higher quality software in a language they know well, using tools they know well, for
applications that they understand.
• There is little evidence to suggest that there is any correlation between safety incidents and
the programming language.
[Wic98] also presents the following C++ specific perceptions and opinions.
• It is hard to show that there are no storage leaks in a C++ program. Areas of the language
relating to the order of execution are undefined and as such it is difficult to guarantee
predictable execution. The typing in C++ is too weak. C++ is not state of the art!
• The C++ language lacks consistency owing to the fact that is was defined to contain the
features that many people wanted. It is not clear that there can be well-defined semantics for
C++.
• Before C++ can be considered there needs to be a well-defined subset, guidelines along the
lines of MISRA C produced, and improved training and education for developers. C++ is
unlikely to be the cheapest, quickest, or most successful approach.
• The tool-sets for C++ are mature, and in some cases code can be automatically generated
from specifications. The tools, knowledge base, and experience surrounding C++ gives it
tremendous advantages in many areas over other languages – advantages that translate into
safer systems. Tool sets are created for C++ before they are written for many other languages.
These tools make it easier to spot mistakes, write code with fewer bugs in the first place and
to test code.
• C++ promotes certain design considerations that assist in safety critical applications. Modular
code makes unit review and testing manageable. Integration and system testing can be easier
with well-defined objects and methods.
• C++ is a very reasonable choice for developing a safety critical system in a small house of
trusted engineers. C++ has too much of a following to be ignored.
Discussion about the suitability of C++ for use in safety critical systems is not limited to [Wic98].
Numerous other sources also debate the topic. These are as follows.
• [Law97] provides an assessment of numerous languages against a formulated set of good
language criteria (refer to Section 2.2.1). With respect to safety, C++ was rated 3/10, Java
4/10 and Ada95 6/10. It is important to note that no specific subsets were covered in the
assessment.
• [DDC04] states that "there is a huge reluctance to move to C++ and it’s not because of the
language, it’s because of the structure around the language. There are so many variants of C
and C++ … so even though you may settle on the same C++ language, the coding standards
that go with it are always different.”
• [Sto96] states that “within the safety-critical community it is generally agreed that in
applications where safety is concerned unstructured assembly language and C or C++ should
not be used.”
32
• [Sto96] advises that “companies not yet committed to a programming language would be well
advised to strongly consider adopting Ada for all projects requiring a high integrity, with a
suitable subset being used for the most critical applications.” However, what about a company
or organisation that has programmers with many years of C++ experience? It is possible for
experienced programmers to re-train to a new programming language in a period of weeks.
Though arguably it may be many months before they reach the level of competency that they
had with their previous language. In addition, many programmers learn by example and it
may be unsuitable to be re-training the programmers onto the new language at the same time
or immediately preceding work on a safety critical project.
• [IPL96] suggests that C++, like C depends too heavily on pointers. Perhaps because of this
perceived dependency, [IPL96] does not consider the constrained use of pointers (ie. a subset)
within the C++ language.
From the comments presented above it is clear that there is division within the safety community of
the use of C++ for such applications. However, a number of the comments presented seem to be
motivated by ignorance of the C++ language, rather than on the merits or shortcomings of the
language itself. Many of the comments also fail to recognise that it may be possible to develop a
safer subset of C++ that is mostly free from the concerns raised. These comments shall be addressed
towards the conclusion of this report to ascertain if the work from this project has resulted in
disproving or supporting any of them.
2.6.3 Subsets of the C++ Programming Language
Some of the discussions in the previous section focussed on the use of a subset of the C++
programming language. Interestingly, [MoD97] points out that “currently all ‘real’ languages have
features which are undefined, poorly defined or implementation based. ‘Real’ languages also have
constructs that are difficult or impossible to analyse. Until a ‘safe’ language has been developed it is
inevitable that a language subset will be used …. in order to ensure that the program execution will
be both predictable and verifiable.” Also [Cul91] concluded that a “code of practice, designed to
enforce a subset of the chosen language, is an essential element when implementing safety-critical
software.”
However it is possible that for some languages it may not be possible to define a safe subset. For
example, [Mey98] describes that for C++ his initial interest was in “developing programming rules
that could be automatically enforced.” However he realised that the “majority of guidelines used by
good C++ programmers are too difficult to formalise or have too many important exceptions to be
blindly enforced by a program.” But does this prevent us from creating a workable subset? What
instead if a subset could be defined and then tools used to warn the programmer about cases where
one of these important exceptions comes into play. That way, the programmer would be aware of
the scenario and could then consciously choose to heed the tool’s warning or dismiss it with
cautious and conscious justifiable reasoning.
Numerous subsets of the C++ programming language have been defined. Though specific
subsetting in relation to safety is not widespread. For example, the subsets that were identified are
[PRG03]’s High Integrity C++ Coding Standard Manual and the Embedded C++ subset (EC++)
[ECP04]. Though technically Embedded C++’s main focus is not safety, but instead performance,
efficiency and code size. Recalling the notion to get it right before we make it fast, then EC++ is
probably not the best choice to begin with when examining safety.
The High Integrity C++ (HICPP) Coding Standard Manual is the most significant work that could
be identified in defining a safer C++ subset. This is examined in the following section.
33
2.6.4 The High Integrity C++ (HICPP) Coding Standard Manual
The High Integrity C++ (HICPP) Coding Standard [PRG03] sets out to define a set of rules and
guidelines for the production of C++ code that is portable, readable, clear and unambiguous. The set
of rules and guidelines are intended to be applied to the ANSI/ISO C++ standard that is described in
[BSI03]. [PRG03] states that the guiding principles in producing the standard are “maintenance,
portability, readability and safety.”
The aim of HICPP is to enforce the current best practice in C++ development. It is based upon the
guidance presented in seven prominent C++ publications: [Str00], the C++ Standard which is also
presented in [BSI03], the first edition of [Mey98], [Mey96], [Mey01], [Hen97], and [Sut00]. Recall
that these texts were reviewed in Section 2.1.5.
There are a total of 158 rules and 39 guidelines. Due to the mutually exclusive nature of a number
of the rules and guideline, the intention is that only a subset of the rules and guidelines given by
[PRG03] be selected (ie. a subset of the subset). Each rule or guideline lists a brief justification for
its inclusion, as well as any exceptions to the rules and references to any texts that motivated the
inclusion of the rule or guidelines. They are grouped into the following categories.
• General: relates to management of the standard and compiler configuration (1 rule and
1 guideline);
• Class: relates to class protection mechanisms, constructors, assignment operators and
destructors, inlining, constant class members, conversion operators, inheritance, object
oriented design, and operator overloading (40 rules and 6 guidelines);
• Complexity: relates to limiting excessive complexity and number of static program paths
(3 rules);
• Control Flow: relates to ensuring intended control flow structures, boolean expressions, wild
jumps, and entry and exit points (11 rules and 1 guideline);
• Constants: relates to effectively using constants, and preventing misinterpretations of
constants (5 rules and 1 guideline);
• Conversions: addresses conversion and casting issues (7 rules and 1 guideline);
• Declarations and Definitions: relates to the structure, scope, language restrictions of variable,
type and object declarations and definitions (14 rules and 10 guidelines);
• Exceptions: relates to dealing with the C++ exception handler, including throwing and
catching exceptions (3 rules and 3 guidelines);
• Expressions: relates to the general use of expressions, including layout, precedence, and
operators (18 rules and 3 guidelines);
• Functions: relates to naming conventions, namespaces, pass by reference and pass by value,
const types and references, return values, inlining, and overloading (9 rules);
• Memory Management: relates to overloaded functions, new and delete (8 rules);
• Portability: relates to avoiding implementation defined behaviour (5 rules and 2 guidelines);
34
• Pre-processor: relates to commenting, character specifics, text alignment, conditional
compilation and file inclusion, macros, digraphs and trigraphs (14 rules and 4 guidelines);
• Structures, Unions and Enumerations: relates to variant structures, values of enumerators, and
casting. (4 rules);
• Templates: relates to template conversions, conflicts, and their appropriate use (3 rules and
1 guideline); and
• Standard Template Library (STL): relates to using the STL containers and associated features
(14 rules and 7 guidelines).
Interestingly, the number of rules is significantly greater when compared to the MISRA C standard
that defined 127 rules for that subset. Perhaps this reflects the greater complexity of object-oriented
programming languages.
In order to make it possible to avoid known problems with C++ and thus reduce the incidence of
errors, the requirements detailed by [PRG03] express:
• “Restrictions on the use of the language constructs or library functions that are not completely
defined by the ISO C++ Standard”;
• “Restrictions on language constructs that permit varied compiler interpretation”;
• “Restrictions of the use of the language constructs or library functions that are known to be
frequently misunderstood or misused by programmers thereby leading to errors”; and
• “Restrictions on the use of language constructs that inhibit the capabilities of static analysis”.
Figure 5 presents a graphical representation of the impact of subsetting on the C++ language.
Figure 5: Defined Safer C++ Subset [PRG03]
While Figure 5 is certainly accurate it fails to capture a number of important issues relating to
subsetting the C++ language. A better way to convey the meaning of an safer C++ subset is as
follows (Figure 6). Firstly the C++ grammar must be limited to restrict keywords that lead to unsafe
behaviour. However it should be noted that due to the many behaviours of the C++ language, a
limitation in the grammar alone is not sufficient to satisfy our requirements for a safe subset. Thus
within the limited grammar, the functionality or features must also be limited to a subset of those
that are well-defined. In some cases this requires the explicit use of C++ key-words to appropriately
define the behaviour. Thus only through these restrictions can we hope to arrive at a safer C++
35
subset whose constructs are well defined, singular in contextual interpretation, well understood and
compatible with rigorous static analysis.
Scope of
ISO C++
Defined, safer
subset of
ISO C++
grammer and
features
Subset of
ISO C++
grammer
Figure 6: Better representation of a Safer C++ Subset
Given the strong ties between HICPP and C++ best practice, there is little value in attempting to re-
invent another C++ subset. Instead it is worthwhile for this project to explore just how safe HICPP
is, and what (if required) else needs to be done to allow the use of C++ for safety critical systems.
In addition, given the number of rules and guidelines, it is clearly beyond expectation of a typical
programmer to be able to self-discipline oneself such that the rules can be followed. Thus it is also
worth exploring the availability and use of tools to support this activity.
2.7 Alternatives to C++ in Safety Critical Systems
[Cha04] discusses alternatives to MISRA C and quickly dismisses C++: “No! Please don’t go
there!” Real-Time Java receives similar treatment. Eiffel receives some praise from [Cha04] in that
it is a good language design, but unfortunately it is not suitable for small, embedded hard real-time
systems. [Cha04] them moves on to consider Ada95. [Cha04] states that it is “Excellent, but full
language is too large.” Ada is the preferred language for the implementation of safety critical
software because it can be used effectively within the constraints identified by [IPL96].
[Cha04] proposes SPARK, the SPADE Ada Kernel, as a high integrity subset of Ada95 that is
suitable for high integrity, small, embedded, and hard real-time systems. The SPARK annotations
help to enforce a design-by-contract methodology and also enable comprehensive and efficient
static analysis [Cha04]. Importantly [Cha04] states that “SPARK is entirely unambiguous.” [IPL96]
suggests that the SPARK subset is the most popular Ada subset. [Cha04] boasts that SPARK
programs are 100% statically free from: data flow errors, aliasing effects, side-effects, evaluation-
order effects, and all erroneous or implementation-defined behaviour. Also, given the almost zero
run-time library overhead, SPARK programs can be small enough to work in small, embedded, and
hard real-time systems [Cha04]. [Cha04] boasts both that SPARK has “met all the most stringent
software standards in the world” and that it “does represent best practice.”
It is easily possible to dedicate more than a few paragraphs to discussing the advantages of SPARK
for high integrity systems. However, the focus of this project is not to further explore the benefits of
using SPARK for high integrity systems. If a given organisation has already chosen SPARK as their
language then they will no doubt already be aware of its suitability. Readers wishing to know more
about SPARK are recommended to get a copy of [Bar03].
Instead, this project focuses on trying to determine if C++ is suitable, or can be made suitable for
use in high integrity safety critical systems.
36
2.8 Software Safety Case Arguments
A number of the standards covered in Section 2.3 detailed that the selection of programming
language in the safety critical system should be justified and that a safety case should be produced.
Thus it is worth examining what a safety case is and what means could be used to argue justification
of the selection of programming language.
[HRM04] describes that the purpose of a safety case is to provide “a justification that a system or
equipment is safe to be used or deployed” in a given context. The safety case also contributes to risk
reduction [HRM04]. A safety case normally consists of two elements. Firstly a higher level
argument presents the principles on which the safety is base and identifies the safety requirements
[HRM04]. Secondly the safety case will provide supporting evidence for the higher level argument
[HRM04]. A software safety case is the element of a systems safety case that argues the safety of
the software component of the system. Importantly the software safety case should recognise that
the software does not exist in isolation to the remainder of the system and that the software’s
interaction with the hardware and other elements of the system are critical. [HRM04] makes an
important distinction that the safety case is the totality of the safety justification AND all of the
supporting material. Supporting material might include testing reports, validation reports, relevant
design information, etc [HRM04]. The safety case report is the document that presents all of the key
components of the safety case and reference all supporting documentation [HRM04].
There are numerous means of presenting a safety argument within a safety case. [HRM04]
describes safety arguments in Textual / Tabular forms, Traceability Matrices, Claim Structures,
Adelard’s Claims-Argument-Evidence notation, Bayesian Belief Networks and Goal Structuring
Notation (GSN). [HRM04] states that “GSN is one of the most expressive, well founded and tested
of these techniques” and thus GSN shall be used for this project.
2.8.1 Goal Structuring Notation (GSN)
[HRM04] describes the purpose of a goal structure is to show how goals (Figure 7) are broken
down into sub-goals, and eventually supported by evidence (solutions) (Figure 8) whilst making
clear the strategies (Figure 9) adopted, the rationale for the approach (assumptions, justifications)
(Figure 10) and the context (Figure 11) in which goals are stated. Goals, strategies and evidence are
linked using the ‘solved by’ connector (Figure 12) and assumptions, justifications and contexts are
linked to goals and strategies using the ‘in context of’ connector (also Figure 12)
Figure 7: GoalFigure 8: Evidence
Figure 9: Strategies
A/J
Figure 10: Assumptions /
Justifications
Figure 11: Context
Figure 12: Solved By / In Context Of
[HRM04] also identifies a six step process (Figure 13) to assist with developing a safety argument
using GSN. For full details and examples of the process refer to [HRM04].
37
Figure 13: GSN Process Overview [HRM04]
[HRM04] also describes the concept of safety case patterns. The intention is to capture successful
argument approaches that can be re-used between the safety cases. In order to extend GSN to
represent generalised arguments a number of additional symbols are added (Figure 14).
Element to be instantiated. Option to be taken.
Structure to be developed.
n
Multiple (n) instantiations required.
Element to be instantiated and
developed.
0/1 instantiations required.
Figure 14: Key to GSN Extensions [HRM04]
2.8.2 GSN Software Safety Arguments
[CAS04] presents several patterns for arguing the safety of software within a safety critical system.
Patterns presented include arguments over product and process, hazards and requirements, and
functional vs non-functional properties. These arguments address both positive and negative aspects
of system behaviour [CAS04]. However, [CAS04] also identifies problems with these approaches.
The main problem stems from these arguments creating a discontinuity in the safety case [CAS04].
This is because the system argument has a product focus, and the software argument has a process
focus [CAS04]. In moving to a product oriented approach for software, [CAS04] goes on to develop
an evidence-base framework for software arguments. The main element of this argument relates to
demonstrating that the software contributions to system level hazards are either absent or are
handled [CAS04]. This is demonstrated by showing that all causes of hazardous software failure
mode are acceptable [CAS04]. [CAS04] identifies five categories of hazardous software failure
mode. These are:
• Omission: the value is never provided;
• Commission: a value is provided when it is not required (ie. a perfectly functioning service
would have done nothing);
• Early: the value is provided before the time (either real time, or relative to some other action)
at which it is required;
• Late: the value is provided after the time at which it is required; and
38
• Value: the timing is correct, but the value delivered is incorrect.
The patterns described above do not directly address the justification of programming as part of the
safety argument. Thus there is a need to investigate how the language selection might be related
with such arguments.
2.9 Verification and Validation of Safety Critical Software
Section 2.2.2 briefly mentions that the availability and quality of support tools will impact upon the
language selection. This fact has inherently wider implications that may seem obvious and as such it
is worth dedicating this section to discussing support tools and their roles. Firstly though, a couple
of definitions.
Static analysis: is the analysis of source code before it is executed. Techniques include control flow
analysis, data flow analysis, symbolic execution, and checking the source code against a formal
mathematical specification. [Bar02] suggests that by using a combination of static analysis
techniques, a variety of properties can be guaranteed about a program. An example of a well-known
tool that performs such analysis is the SPARK Examiner (for Ada).
Dynamic testing: involves the execution of the source code against numerous test cases at various
levels of integration (ie. from the smallest routine, up to the system as a whole). Because software is
complex, it is impossible to be able to execute test cases for all possible inputs and outputs. Thus
techniques such as equivalence partitioning, boundary value analysis, and structural testing are
applied to give specified levels of dynamic test coverage. An example of a tool that support
dynamic testing and coverage analysis is Cantata++ (for C++).
[Bar02] states that a “key aspect in certification of a high integrity system is the ability to validate
the correctness of the system before it enters service.” Traditionally dynamic testing has been
extensively used following the initial development to gain confidence in the correct operation of the
system. However, [Bar02] points out that these techniques can be expensive for a number of
reasons. Firstly, dynamic testing tends to find faults late in the development lifecycle. Secondly, the
number of tests required to achieve the desired confidence and full code coverage within a
representation of the operational context can be unsurmountable.
Thus, there is motivation to use static analysis to verify software. In fact it is mandated by
[MoD97]. Static analysis has the advantage that if a program property is shown to hold, then it is
going to hold for all scenarios [Bar02]. This is often not the case for dynamic testing. In addition if
a language subset is used then there are likely to be static checkers required to ensure compliance
with the language subset.
Given the requirement for static checking, the programming language must support such a
mechanism [Bar02]. [Bar02] defines that the language should have properties that facilitate both
static and dynamic checking with tools within a reasonable time. Any rules (subsets) applied must
also be tool checkable to be practical. Also individual components should be amenable to analysis
so that checking may be performed at all levels of integration [Bar02], and without invalidating any
previous static analysis conducted. It is too late to benefit from static analysis if the program can
only be analysed once it is fully constructed [Bar02]. For a given system, and programming
language used to implement that system, it is important to highlight that showing the risks have
been reduced acceptably will involve a combination of both static and dynamic techniques.
Because of the heavy reliance on tools, be they compilers, static analysers, or dynamic testers,
thought must be given also to the verification and validation of the tools being used to verify and
validate the safety critical software. Each of the standards identified in Section 2.3 presents
39
guidance on the use of tools within safety critical projects. This shall not be the focus of this project,
but it is important to be aware of when specific tools are discussed in relation to C++.
2.10 Summary of Literature Review
A broad range of literature relating to the project has been reviewed.
Section 2.1 has examined the C++ programming language, including its use and origins and
properties of the object-oriented paradigm. Comprehensive sources of C++ best practice, problems
and solutions have been identified.
Section 2.2 has examined programming languages in the context of safety critical software. A set of
criteria have been identified in Section 2.2.3 for assessing the safety of programming languages that
shall form part of the evaluation of this project. These criteria were selected because they were
deemed to be comprehensive.
Section 2.3 has examined programming languages in the context of the safety standards. Language
properties defined by the standards have been identified. A need has been identified for a means to
justify the selection of programming language for safety critical systems.
Section 2.4 has examined object-oriented technology in the context of safety critical systems. In
particular the Handbook for Object-Oriented Technology in Aviation [OOT04] has been identified.
Section 2.5 has examined C in the context of safety critical systems. The intention has been to
highlight issues that may also surface when looking at C++ in the context of safety critical systems.
Section 2.6 has examined C++ in the context of safety critical systems. Perceptions and opinions
relating to C++ and safety critical systems have been presented to provide background to the kinds
of issues that this project is likely to have to address. Importantly the High Integrity C++ (HICPP)
Coding Standard [PRG03] has been identified as an appropriate starting point for defining a safer
C++ subset.
Section 2.7 has examined alternatives to C++ for safety critical systems. Specifically Ada and
SPARK are examined. Importantly, this emphasises that this project does not intend to advocate
C++ as the most suitable software critical language, but instead to identify if C++ be used.
Section 2.8 has examined the purpose of the safety case and a means of clearly presenting the safety
arguments contained within the safety case. Specifically Goal Structuring Notation (GSN) has been
described. Patterns for software safety arguments have also been reviewed. An absence of a pattern
to justify the selection of programming language provides motivation for one to be developed as
part of this project. There is potential for this to be linked to the justification required by the
standards in Section 2.3.
Finally, Section 2.9 has examined some verification and validation issues relating to safety critical
software and the relationship this has to the tools used to support the programming language.
40
3 Analysis of the C++ Language
Section 2 has identified numerous attributes of safer programming languages. Thus to consider if
C++ can be used in the safety critical context it is important to develop an understanding of some of
these criteria specifically in relation to the C++ programming language. Sections 3.1 to 3.3 examine
some of the fundamental aspects of these criteria, and then Section 3.4 moves to identify a means of
dealing with the issues identified.
3.1 Identification of C++ Behaviour Ambiguities
Section 2.2.2 details that unspecified, undefined, implementation-defined, and other definition
related behaviours should be identified, mitigated and controlled. This section focuses on
identifying those behaviours in C++.
Appendixes 8 to 14 present a list of all the identified unspecified, undefined, implementation-
defined and indeterminate behaviours of the C++ programming language. Table 5 (below) shows an
example of several unspecified behaviours. These behaviours were extracted directly (ie. directly
quoted) from [BSI03] and are referenced by both page number and chapter/section number. The
behaviours were identified through a series of keyword searches using words such as unspecified,
undefined, indeterminate, implementation and various lexically correct variations of these words.
It is fairly evident from the significant number of entries in these tables that there is a substantial
amount of such behaviour in the C++ programming language. These behaviours provide much
opportunity for safety related problems to arise in C++. Thus in order to be able to argue that there
is a safe way to employ the C++ language for safety critical applications, then these behaviours will
need to be controlled. This will be considered in Section 3.4.
Page Item / Description
48 3.7.3.1 Allocation Functions (para 2)
The order, contiguity, and initial value of storage allocated by successive calls to an allocation function is
unspecified.
65 5 Expressions (para 4) – Order of Evaluation
The order of evaluation of operands of individual operators and sub-expressions of individual expressions,
and the order in which side effects take place is unspecified. The precedence of operators is not directly
specified, but it can be derived from the syntax.
i = v[i++]; //the behaviour is unspecifiedi = 7, i++, i++; //i becomes 9
i = ++i + 1; //the behaviour is unspecifiedi = i + 1; // the value of i is incremented
72 5.2.8 Type Identification (para 1)
The result of a typeid expression is an lvalue of static type const std::type_info and dynamic type
const std::type_info or const name where name is an implementation-defined class derived from
std::type_info which preserves the behaviour described in 18.5.1. The lifetime of the object referred to by
lvalue extends to the end of the program. Whether or not the destructor is called for the type_info object at
the end of the program is unspecified.
75 5.2.9 Static Cast (para 7)
A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is
unchanged if the original value is within the range of enumeration values. Otherwise the resulting
enumeration value is unspecified.
Table 5: C++ Language Unspecified Behaviour (partial extract from Appendix 8)
41
3.2 Identification of C++ Best Practice, Problems and Solutions
Simply being able to control the unspecified, undefined, indeterminate and implementation-defined
behaviours of C++ is insufficient to make the language safer in the context of safety critical
systems. The correct employment of the language is also critical to ensuring safety.
Section 2.1.5 details a number of published C++ texts that identify numerous cases of best practice,
problems and solutions. This advice is broad in its coverage and considers issues from individual
language constructs that are prone to misunderstanding or misuse through to higher level design
issues and programmer skills. Each of the individual items/rules/guidelines presented by these texts
have been directly extracted and are summarised in Appendixes 1 to 6. Table 6 (below) shows an
example of the Industrial Strength C++ items. In total these appendixes cover 438
items/rules/guidelines relating to the production of C++ code. While there are certainly other texts
that also present items/rules/guidelines on the production of C++ code, it is beyond reasonable
expectation for this project to be able to cover all of them. The texts that have been selected are
widely acknowledged in the C++ community and for that reason are assumed to represent quality
advice on the production of C++ code. There is also substantial overlap between the advice
provided by these texts. Thus one may conclude that for the most part the coverage of these texts of
C++ best practice, problems and solutions is substantial. There is still the possibility that problems
are not identified here, but these shall be addressed in Section 5.1.1.
Industrial Strength C++ Item
Rule 8.1 Delete should only be used with new.
Rule 8.2 Delete[] should only be used with new[].
Rule 8.3 Do not access a pointer or reference to a deleted object.
Rec 8.4 Do not delete this.
Rec 8.5 If you overloaded operator new for a class, you should have overloaded operator delete.
Rec 8.6 Customise the memory management for a class if memory management is an unacceptably large part
of the allocation and deallocation of free store objects of that class.
Rec 9.1 Objects with static storage duration should be declared only within the scope of a class, function, or
anonymous namespace.
Rec 9.2 Document how static objects are initialised.
Rule 10.1 Declare data members private.
Rec 10.2 If a member function returns a pointer or reference, you should document how it should be used and
how long it is valid.
Rec 10.3 Selection statements (if-else and switch) should be used when the control flow depends on an object’s
value; dynamic binding should be used when the control flow depends on the object’s type.
Rule 10.4 A public base class must have either a public virtual destructor or a protected destructor.
Rule 10.5 If you derive from more than one base class with the same parent, that parent should be a virtual base
class.
Rec 10.6 Specify classes using preconditions, postconditions, exceptions, and class invariants.
Rec 10.7 Use C++ to describe preconditions, postconditions, exceptions and class invariants.
Rec 10.8 It should be possible to use a pointer or reference to an object of a derived class whenever a pointer or
reference to public base class object is used.
Rec 10.9 Document the interface of template parameters.
Table 6: Industrial Strength C++ Items (partial extract from Appendix 1)
3.3 Identification of OOTiA Recommendations
Although C++ is technically a multi-paradigm language, it is in its object-oriented form that this
project has focussed. Section 2.4.1 detailed a number of concerns relating to the use of object-
oriented technology in safety critical applications. Section 2.4.2 identifies that [OOT04] provides
advice on mitigating such problems with the paradigm. Each of the rules and guidelines presented
by [OOT04] has been directly extracted and summarised in Appendix 7. Table 7 (below) shows an
example of several OOTiA guidelines. [OOT04] also presents a number of recommendations
relating to achieving DO-178B compliance for software utilising object-oriented technology. These
42
(sections 3.10 – 3.12 in Volume 3 of [OOT04]) haven’t been covered in this section because they
are beyond the scope of safe language criteria.
OOTiA Guideline
3.3 Single Inheritance and Dynamic Dispatch
3.3.4 Inheritance with Overriding
Simple overriding rule: An operation may redefine an inherited operation, and a method may implement an operation
so long as changes to its signature guarantee substitutability.
Accidental override rule: To ensure that overriding is always intentional rather than accidental, design and code
inspections should consider whether locally defined features are intended to override inherited features with a
matching signature.
Simple dispatch rule: When an operation is invoked on an object, a method associated with the operation in its run
time class should be executed. This rule applies to all calls except explicit calls to superclass methods, which should
be addressed as described by the Method Extension guidelines.
Complete initialisation rule: Each attribute must be initialised to a value consistent with the class invariant by the
class.
Initialisation dispatch rule: No overridden method should be called during the initialisation (construction) of an
object.
Dispatch time rule: All dispatch times should be bounded and deterministic.
Object code traceability rule: Everywhere concerns about source code to object code traceability and timing analysis
dictate, the compiler vendor may be asked to provide evidence of deterministic, bounded mapping of the dispatched
call. If the evidence is not available from the compiler vendor, it may be necessary to examine the structure of the
compiler-generated code and data structures (e.g. method tables) at the point of call.
Table 7: OOTiA Guidelines (partial extract from Appendix 7)
3.4 Summary and Direction
Even a brief inspection of many of the items identified in Section 3.1 to 3.3 reveals many problems
and pitfalls from which it is possible to conclude that the unrestricted use of the C++ language is
not suitable for high integrity and safety critical applications. However this prognosis does not
discount the possibility that these issues may be able to be controlled. A subset of the language may
provide the restrictions necessary to make C++ safer. Section 2.6.4 identified the High Integrity
C++ (HICPP) Coding Standard Manual [PRG03] as defining a set of rules and guidelines for the
production of C++ code that is portable, readable, clear and unambiguous. Specifically in order to
avoid problems with C++ and thus reduce the incidence of errors, the requirements detailed by
[PRG03] express:
• Restrictions on the use of the language constructs or library functions that are not completely
defined by the ISO C++ Standard – ie. the unspecified, undefined and indeterminate
behaviours identified in Section 3.1.
• Restrictions on language constructs that permit varied compiler interpretation – ie. the
unspecified and implementation-defined behaviours identified in Section 3.1.
• Restrictions on language constructs or library functions that are known to be frequently
misunderstood or misused by programmers thereby leading to errors – ie. the best practice,
problems and solutions identified in Section 3.2 and the guidelines relating to object oriented
technology identified in Section 3.3.
HICPP seems to address the issues identified in Sections 3.1 to 3.3. However the number of issues
presented is large and a number of them are complex. Thus there is no assurance that HICPP’s
coverage is complete and there is a need to conduct a full check. Section 4.1 will fully consider the
HICPP coding standard in relation to the issues and items/rules/guidelines identified in Sections 3.1
to 3.3.
43
4 Development and Enforcement of a Safer C++ Subset
Section 3.4 states that the number of issues presented is large and a number of them are complex.
Thus there is no assurance that the High Integrity C++ (HICPP) Coding Standard’s coverage is
complete and there is a need to conduct a full check. Section 4.1 considers the HICPP coding
standard in relation to the issues and items/rules/guidelines identified in Sections 3.1 to 3.3. Where
relevant, deficiencies in the HICPP rules and guidelines have been identified. In Section 4.2 a set of
additional rules and guidelines has then been developed to address the identified deficiencies.
Section 4.3 identifies and reasons about those rules that were not referenced in Sections 4.1 and 4.2.
With a complete set of rules and guidelines now fully defined, Section 4.4 examines how these rules
and guidelines can be enforced.
4.1 Assessment of the High Integrity C++ Coding Standard
In Section 3 a set of issues and behaviours was established against which to assess HICPP. They
included C++ behaviours, best practice C++, and the OOTiA recommendations. This section
describes the assessment of HICPP. The results are presented in the column labelled ‘Control’ of
the tables shown in Appendixes 1 – 14. An example of these results for a small set of the Industrial
Strength C++ items is shown in Table 8.
Industrial Strength C++ Item Control
Rule 8.1 Delete should only be used with new. Rule 12.3 (direct)
Rule 8.2 Delete[] should only be used with new[]. Rule 12.3 (direct)
Rule 8.3 Do not access a pointer or reference to a deleted object. Rule 12.8 (avoids)
Rec 8.4 Do not delete this. New Rule (4)
Rec 8.5 If you overloaded operator new for a class, you should have overloaded
operator delete.
Rule 12.6 (direct)
Rec 8.6 Customise the memory management for a class if memory management is
an unacceptably large part of the allocation and deallocation of free store
objects of that class.
Efficiency
Rec 9.1 Objects with static storage duration should be declared only within the
scope of a class, function, or anonymous namespace.
Rule 8.1.1 (direct)
Rule 8.1.2 (direct)
Rule 8.2.2 (direct)
Guideline 6.6 (supports)
Rec 9.2 Document how static objects are initialised. Rule 8.2.2 (direct)
Guideline 8.3.2 (avoids)
Maintenance
Rule 10.1 Declare data members private. Rule 3.4.1 (direct)
Rec 10.2 If a member function returns a pointer or reference, you should document
how it should be used and how long it is valid.
Maintenance
Rec 10.3 Selection statements (if-else and switch) should be used when the control
flow depends on an object’s value; dynamic binding should be used when
the control flow depends on the object’s type.
Software Engineering –
Object Oriented Design
Rule 10.4 A public base class must have either a public virtual destructor or a
protected destructor.
Rule 3.3.2 (direct)
Guideline 17.7 (direct)
Rule 10.5 If you derive from more than one base class with the same parent, that
parent should be a virtual base class.
Rule 3.3.15 (direct)
Rec 10.6 Specify classes using preconditions, postconditions, exceptions, and class
invariants.
Software Engineering –
Object Oriented Design
Rec 10.7 Use C++ to describe preconditions, postconditions, exceptions and class
invariants.
Software Engineering –
Object Oriented Design
Rec 10.8 It should be possible to use a pointer or reference to an object of a derived
class whenever a pointer or reference to public base class object is used.
Rule 3.3.3 (direct)
ISO C++ defines
Rec 10.9 Document the interface of template parameters. Maintenance
Table 8: HICPP Coverage of Industrial Strength C++ Items (partial extract from Appendix 1)
44
Where a rule or guideline was determined to be applicable in mitigating or avoiding a given
problem then that rule or guideline reference would be annotated in the ‘Control’ column. In some
cases it was possible to obtain a direct mapping between an item/rule/guideline from the literature
and the rule or guideline in HICPP. In other cases a combination of rules were required to work
together to collectively avoid and/or mitigate the item/rule/guideline from the literature. Each of the
rule or guideline entries in the ‘Control’ column are bracket annotated with the keyword ‘direct’,
‘avoids’ or ‘supports’. The ‘direct’ annotation means that the rule or guideline applies directly to
mitigating the problem. The ‘avoids’ annotation means that the existence of the rule or guideline
creates a scenario through which the problem will generally be avoided. The ‘supports’ annotation
means that the rule or guideline applies in a generally supporting manner for mitigating or avoiding
the problem.
In cases where the rules or guidelines could not be applied to fully mitigate or avoid the problem,
the residual problem could be mitigated or avoided through the application of a number of general
design principles or other means. In such cases a number of category labels were used and they are
presented in the list below. As the evaluation was carried out it became clear that a number of the
issues presented were non-specific to the language, a higher-level software engineering issue, or
related to the quality of the programmers. It is mostly difficult and nearly impossible to define rules
to cover these items, as they are specific to the type of problem being solved. Thus it is not possible
to fully detach the language selection from the system’s context. This is a very important outcome
and will be examined further in Sections 5.1.
• Software Engineering – Requirements: The correct and unambiguous specification of
requirements works to mitigate or avoid the scenario. If the requirements are poorly specified
it may be difficult to avoid problems.
• Software Engineering – Analysis: An appropriate level of analysis of the problem and
solution works to mitigate or avoid the scenario. The software should be designed to ensure
that it is compatible with static analysis.
• Software Engineering – Design: The development of a ‘good’ design works to mitigate or
avoid the scenario. For example, attempting to solve a problem in a way that works against
the paradigm or intent of the language constructs may lead to a ‘poor’ design.
• Software Engineering – Object Oriented Design: The development of a ‘good’ object oriented
design works to mitigate or avoid the scenario. This includes the numerous object oriented
design rules and guidelines presented in [PRG03], but also encompasses fundamental design
issues relating to the context of the problem being solved. In particular the development of an
appropriate class hierarchy, appropriate use of abstraction and inheritance and application of
software engineering methods is critical to achieving a good object oriented design.
• Software Engineering – Exception Design: The development of appropriate exception class
hierarchy and exception class mechanics works to mitigate or avoid the scenario.
• Software Engineering – Verification: These items are related to the verification of the
software. They should be considered during the design such that the software is designed to
be tested, but are not considered to present language specific safety issues.
• Maintenance: These items relate to producing software that is maintainable. This does not
only relate to the ease of finding and understanding sections of the code, but also to ensuring
that there is minimum likelihood of the maintainers introducing errors during maintenance
activities.
45
• Programmer Skill: The employment of programmers with good C++ skills as well as a good
knowledge of software in the safety domain works to mitigate or avoid these problems.
Furthermore a broad understanding of likely language and design related problems is also
essential.
• Programmer Attitude: The employment of C++ programmers, regardless of their level of
skill, with inappropriate attitudes towards software in the safety domain is likely to negatively
impact upon the overall safety of the system. Programmers with the correct attitude will
mitigate these problems. Thus programmers should be recruited that have an awareness of
software safety issues, are familiar with common problems within the C++ language, are
aware of the impact of the unrestricted use of the language and are willing to promote a safe
design at all levels.
• ISO C++ defines: The item is clarified by the C++ standard and relates to a problem that
arose due to varied compiler implementations or interpretation prior to the release of the
official standard. Presuming that a fully ISO compliant compiler is used these issues will not
present any problems. Availability of ISO compilers is considered in Section 6.1.1 and
6.2.3.1.
Finally where neither the rules, guidelines or categories presented above were considered sufficient
to mitigate or avoid the problem then a new rule or guideline annotation was made (eg. Rule 1 or
Guideline 2). New rules use an integer for labelling, whereas the rules and guidelines from HICPP
use a decimal labelling system.
An inspection of the results of the activity reveals that the HICPP’s overall coverage of the issues
has been quite comprehensive. However there was a significant proportion whereby no reference to
a HICPP rule was possible and one of the pre-defined category labels was used. This means that
producing a safe design in C++ is more than just enforcing a subset. It also means that the design
must be matched to the intent of the language constructs and the language must suit the domain and
application. This means it may be difficult to detach the language selection from the design
(functional properties of the system).
There have been a number of areas identified whereby further rules or guidelines are required.
These areas relate to both the base language and the standard template library (STL). The new rules
and guidelines are described in Section 4.2.
4.2 Development of Additional Rules
From the work described in Section 4.1, numerous deficiencies were identified that are best
addressed through the addition of new rules or guidelines to [PRG03]. The following sections
describe the rules and guidelines. They have been grouped under similar headings to the rules and
guidelines presented in [PRG03] to allow them to be correlated to [PRG03].
4.2.1 General (HICPP 3.1)
Rule 1 – Always return stream references from operator << and operator >>.
Justification: operator << and operator >> should return a reference to the stream in order to permit
chaining.
Reference: [Sut00] Item 20
46
4.2.2 Constructors and Destructors (HICPP 3.2)
Rule 2 – Do not use or pass this in constructor initialiser lists.
Justification: Until the constructor has completed, the object pointed to by this is not fully
constructed. Calling a member function in a member initialisation list can result in the member
function trying to access uninitialised members of the class.
Exception: Use the this pointer to access the value or any subobjects during the construction of a
const object. Other means of accessing the value of the object can result in unspecified behaviour.
Reference: [Hen97] Rec 5.7, [BSI03] 12.6.2 , [BSI03] 12
Rule 3 – Do not assume constructor arguments will or will not be evaluated prior to the
allocation of the object occurring.
Justification: It is unspecified whether the allocation function is called before or after evaluating the
constructor arguments, but before entering the constructor. It is also unspecified whether the
arguments to a constructor are evaluated if the allocation function returns the null pointer or exits
using an exception.
Reference: [BSI03] 5.3.4
4.2.3 Object Oriented Design (HICPP 3.4)
Rule 4 – Do not delete this.
Justification: It is rarely correct for an object to commit suicide and can be an indication of poor
object oriented design. Allowing functions to delete this can lead to undefined behaviour if the
object is subsequently accessed when returning from the function.
Reference: [Hen 97] Rec 8.4
Rule 5 – Avoid using type identification information.
Justification: The header <typeinfo> defines a type associated with type information generated by
the implementation. Thus a program using such features may not be portable. The presence of type-
based control structures in a program can be an indication of a poor object-oriented design.
Implement type-based decisions with dynamic binding and not with type-based conditional control
structures.
Reference: [BSI03] 5.2.8
4.2.4 Complexity (HICPP 4)
Rule 6 – Avoid recursion.
Justification: Recursion makes code difficult to understand and analyse. It also makes the
determination of resource usage difficult. Also, if control re-enters a declaration recursively while
the object is being initialised, the behaviour is undefined.
Reference: [BSI03] 6.7
47
4.2.5 Control Flow (HICPP 5)
Rule 7 – Do not perform equality comparisons on pointers to virtual functions.
Justification: Do not make equality comparisons of pointers to virtual functions as this can result in
unspecified behaviour.
Reference: [BSI03] 5.10
4.2.6 Declarations and Definitions (HICPP 8)
Rule 8 – Do not self-initialise variables.
Justification: Initialising a variable in terms of itself is likely to lead to undefined behaviour.
int var = 12;{
double var = var; // undefined behaviour!// ...
Reference: [Dew03] Gotcha #21
Rule 9 – Constants declared in pure abstract classes should not involve run-time computation.
Justification: Constants whose values are computed at run-time require the generation of code to
perform the computation and assignment. This conflicts with the definition of an interface which is
not permitted to have code or data.
Reference: [OOT04] 3.4.4
Rule 10 – Do not attempt to create a null reference.
Justification: Attempting to create a null reference by binding it to the object obtained by de-
referencing a null pointer causes undefined behaviour and thus should not be attempted.
Reference: [BSI03] 8.3.2
4.2.7 Exceptions (HICPP 9)
Rule 11 – Constructors of types thrown as exceptions should not themselves throw exceptions.
Justification: If such a constructor throws an exception, then the original exception is lost and
forgotten and there is thus no way of dealing with the original problem. For copy constructors, the
exception object is copied to an area of memory managed by the exception handling system before
leaving the scope in which the throw is done. Terminate() is called if the copy fails.
Reference: [Hen97] Rec 12.6, [BSI03] 15.5.1
Rule 12 - If a function isn’t going to handle (or translate or deliberately absorb) an exception,
it should allow the exception to propagate up to a caller that can handle it.
Justification: In a template, if exceptions are thrown they should be propagated seemlessly through
to the caller because the caller is in a better position to know the context of the exception.
Reference: [Sut00] Item 8
48
Rule 13 – Do not rely on the lifetime of temporary exception objects.
Justification: The memory held by the temporary object can be deallocated by the implementation
any time after the last handler being executed for the exception exists, by any means other than
throw.
Reference: [BSI03] 15.1
Rule 14 – Never refer to any non-static member or base class of an object in an exception
handler for a function try block of a constructor or destructor for that object.
Justification: Referring to any non-static member or base class of an object in an exception handler
for a function try block of a constructor or destructor for that object results in undefined behaviour.
Reference: [BSI03] 15.3
4.2.8 Memory Management (HICPP 12)
Guideline 15 – Use stack objects instead of heap based objects where possible.
Justification: Whenever possible, objects should be created on the stack instead of with new. Stack
objects are less expensive to create and the risk of a memory leak occurring is substantially less,
especially if exception safe classes are used. Objects should be created with new only if the lifetime
is to be controlled outside the function creating the object. Objects should not be created with new
merely for the convenience of gaining access to a pointer to the object. Each heap based object must
always be accessible through either a static pointer or an object on the stack that owns the object.
Reference: [Hen97] Rec 12.9
Guideline 16 – Be prepared for out of memory conditions.
Justification: When operator new can’t allocate the requested memory, an exception is thrown. To
ensure the out of memory condition is handled in a controlled manner, then the program should be
prepared to handle memory allocation failures.
Reference: [Mey98] Item 7
Rule 17 – Do not make a request for the allocation of a zero or negatively sized object.
Justification: The effect of the allocation for negatively sized object has undefined behaviour. De-
referencing a pointer returned from a request for a zero sized object is also undefined.
Reference: [BSI03] 3.7.3.1, 5.3.4
4.2.9 Portability (HICPP 13)
Guideline 18 – Avoid linking to languages other than C++ or C.
Justification: The characteristics of linkage to other languages has undefined and implementation
defined characteristics associated with it and should thus be avoided. Section 1.6 in [PRG03] also
states “the embedding of code, written in languages other than C++, within C++ code is forbidden
unless accompanied by a written justification for its use.”
Reference: [BSI03] 5.2.2
49
4.2.10 Pre-Processor (HICPP 14)
Rule 19 – Do not use the pre-processor # operator and ## operator.
Justification: If the replacement that results from such operations is not a valid character string or
pre-processing token then the behaviour is undefined.
Reference: [BSI03] 16.3.2, 16.3.3
Rule 20 – Ensure that the digit sequence for the # line pre-processing directive is > 0 and
< 32768.
Justification: If the digit sequence specifies a number outside this range then the behaviour is
undefined.
Reference: [BSI03] 16.4
4.2.11 Standard Template Library (HICPP 17)
Guideline 21 - Choose carefully among erasing options.
Justification: The correct choice of erase option depends on how the objects to erase are identified,
the type of container the objects are stored in, and what else is to be done while erasing the objects.
[Mey01] recommends the following:
• To eliminate all objects in a container that have a particular value: if the container is a vector,
string or deque, use the erase remove idiom; if the container is a list, use list::remove; if the
container is a standard associative container, use its erase member function.
• To eliminate all objects in a container that satisfy a particular predicate: if the container is a
vector, string, or deque, use the erase-remove_if idiom; if the container is a list, use
list::remove_if; if the container is a standard associative container, use remove_copy_if and
swap, or write a loop to walk the container elements, being sure to postincrement the iterator
when it is passed to erase.
• To do something inside the loop (in addition to erasing objects): if the container is a standard
sequence container, write a loop to walk the container elements, being sure to update the
iterator with erase’s return value each time it is called; if the container is a standard
associative container, write a loop to walk the container elements, being sure to post-
increment the iterator when it is passed to erase.
Reference: [Mey01] Item 9
Guideline 22 – Ensure allocator conventions and restrictions are conformed to.
Justification: [Mey01] provides the following guidance for writing a custom allocator:
• Make the allocator a template, with the template parameter T representing the type of objects
for which memory is being allocated.
• Provide the typedefs pointer and reference, but always have pointer be T* and reference be T&.
• Never give allocators per-object state. In general, allocators should have no non-static
members.
50
• Remember that an allocator’s allocate member functions are passed the number of objects for
which memory is required, not the number of bytes needed. Also remember that these
functions return T* pointers (via the pointer typedef), even though no T objects have yet been
constructed.
• Be sure to provide the nested rebind template on which standard containers depend.
• All allocators of the same type must be equivalent.
Reference: [Mey01] Item 10, 11
Guideline 23 - Specify comparison types for associative containers of pointers and iterators.
Justification: Standard associative containers of pointers will be sorted by the values of the pointers.
If this is undesirable then create a ‘functor’ class to serve as a comparison type.
Reference: [Mey01] Item 20
Rule 24 - Make sure destination ranges are big enough.
Justification: Whenever an algorithm requiring the specification of a destination range is used,
ensure that the destination range is big enough already or is increased in size as the algorithm runs.
To increase the size as you go, use insert iterators, such as ostream_iterators or those returned by
back_inserter, front_inserter, or inserter.
Reference: [Mey01] Item 30
Rule 25 - Avoid remove-like algorithms on containers of pointers.
Justification: Standard remove-like algorithms can result in memory leaks when used on containers
of pointers. Instead manually implement such activities by reference counting smart pointers,
manual deletion and nullification of pointer prior to invoking remove-like algorithm.
Reference: [Mey01] Item 33
Rule 26 – Never dereference an invalid iterator.
Justification: When using iterators, there are a number of issues to be aware of.
1. Valid values: Is the iterator dereferenceable? For example, writing *e.end() is a programming
error.
2. Valid lifetimes: Is the iterator still valid since last being used? Has it been invalidated by
some operation since it was obtained?
3. Valid ranges: Is the pair of iterators a valid range? Is first really before (or equal to) last? Do
both point into the same container?
4. Illegal builtin manipulation: Is the code trying to modify a temporary of builtin type? For
example, --e.end().
Reference: [Sut00] Item 1, [BSI03] 24.5.3
51
Rule 27 – Always check and ensure compliance with the pre-conditions for STL functions.
Justification: The behaviour of STL functions is only guaranteed if the function arguments and state
meet the defined pre-conditions for the function. If an argument to a function has an invalid range
or the pre-conditions are not met in any other way then the behaviour is undefined.
Reference: [BSI03] 17.4.3.2, 17.4.3.7, 21.3.4, 23.2.2.4, 26.3.2.1, 26.3.2.2, 26.3.2.3, 26.3.2.6,
26.3.2.7, 26.3.3.1, 26.3.3.2, 26.3.6, 26.3.9.2, 26.3.9.3, 27.4.3.2, 27.4.4.1, 27.7.1.3, 27.8.1.1,
27.8.1.4,
Rule 28 – Only use the macro offsetof in <cstddef> with non-static POD types.
Justification: The macro offsetof in <cstddef> only accepts types of POD structure and POD
union. The result of applying the offsetof macro to a field that is a static data member or a function
member is undefined.
Reference: [BSI03] 18.1
Rule 29 – Do not use iterators to hold singular values.
Justification: The results of most expressions that involve singular values in iterators is undefined.
Reference: [BSI03] 24.1
Rule 30 – Operations on types used with the complex and valarray classes shall not throw
exceptions.
Justification: If any operation on type T throws an exception the effects are undefined.
Reference: [BSI03] 26.1
Rule 31 – No user defined function should call the imbue function.
Justification: If any user function calls imbue, the behaviour is undefined.
Reference: [BSI03] 27.1.1
Rule 32 – Avoid using operator[] to access STL containers, use iterators instead.
Justification: Operator[] does not include bounds checking.
Reference: [BSI03] 17.4.3.7, 21.3.4.
4.3 Rules and Guidelines Not Referenced in the Assessment
There are a number of HICPP rules and guidelines that were not referenced in the assessment
described by Section 4.1. This raises the obvious question: why is the rule or guideline is present in
HICPP if it is not used to enforce a C++ behaviour or best practice? To answer this question, each
of these rules or guidelines is listed below with the reasoning for its inclusion in HICPP despite
being absent from the references in this assessment. In most cases these rules and guidelines
improve readability and maintainability.
52
Rule 2.1 – Thoroughly document in the code any deviation from a standard rule.
Reasoning: This rule is required for the management and documentation of code produced with the
subset.
Guideline 3.1.12 – Provide an output operator (‘operator<<’) for ostream for all classes.
Reasoning: This rule is useful for debugging and testing of code.
Rule 3.3.16 – Explicitly declare polymorphic member functions virtual in a derived class.
Reasoning: This rule improves class documentation.
Rule 5.3 – Avoid conditional expressions that always have the same result.
Reasoning: This rule relates to good programming and design practice and does not explicitly
address individual language issues.
Rule 10.5 – Always discard the result of an assignment operator.
Reasoning: This rule relates to avoiding the possibility of mistaking the assignment operation with a
comparison operation. This is due to the lexical similarity between ‘=’ and ‘==’. This rule works to
avoid programmer errors of misplacement, omission and addition.
Rule 10.10 – Avoid statements that have no side effects.
Reasoning: This rule improves code readability and maintainability.
Rule 10.16 – Do not use the increment operator (‘++’) on a variable of type ‘bool’.
Reasoning: This is deprecated in the ISO C++ standard and the rule is possibly redundant given that
HICPP subsets the ISO C++ standard.
Rule 10.19 – Do not use the comma operator.
Reasoning: This rule improves code readability and maintainability.
Rule 11.1 – All functions that have the same name should have similar behaviour, varying
only in the number and/or types of parameters.
Reasoning: This rule improves code readability and maintainability.
Guideline 14.2 – Do not use tab characters in source files.
Reasoning: This rule improves readability and maintainability across different editing
environments.
Guideline 14.3 – Write pre-processor directives to begin in column 1 with no whitespace
between the ‘#’ and the pre-processor directive.
Reasoning: This rule improves readability and maintainability.
53
Guideline 14.4 – Write pre-processor directives to begin in column 1 with whitespace between
the ‘#’ and the pre-processor directive representing nesting in pre-processor conditionals.
Reasoning: This rule improves readability and maintainability.
Rule 14.18 – Do not use digraphs or trigraphs.
Reasoning: This rule works to prevent mis-translation and confusion between potentially similar
sets of character strings.
Rule 15.3 – Do not rely on the value of an enumerator.
Reasoning: This rule improves readability and maintainability.
4.4 Enforcement of C++ Rules and Guidelines
Having deduced that the HICPP coding standard plus the additional rules and guidelines defined in
Section 4.2 has been deemed sufficient to promote the development of high integrity C++ code, it is
then necessary to examine how well these rules and guidelines lend themselves to enforcement, and
in particular auto-enforcement. Auto-enforcement is necessary if C++ is to be used in other than
trivial high integrity software development. This is because it is impractical for the large number of
rules and guidelines to be manually enforced.
A number of tools have been assessed with respect to their auto-enforcement capabilities of the
rules and guidelines (both HICPP and additional rules and guidelines defined in Section 4.2). Note
that the focus has been on being able to enforce the rules and guidelines statically (ie. at or before
compile time). Static enforcement was identified as being necessary in Section 2.9. The results of
the assessment are presented in the last column (labelled ‘Enforced’) of the tables shown in
Appendixes 1 – 14. An example of these results for a small set of the Industrial Strength C++ items
is shown in Table 9 (Section 4.4.5). Note that the item/rule/guideline from the literature (columns 1
and/or 2 of these tables) against which one or more particular rules or guidelines from HICPP was
annotated (labelled ‘Control’) was used to provide a contextual basis for considering if the tools can
provide auto-enforcement of the rule or guideline. Thus aspects of any given rule or guideline
(‘Control’) that didn’t work to mitigate or avoid the particular item/rule/guideline from the literature
(columns 1 and/or 2) were not considered for that annotated instance of the rule or guideline.
A number of widely used C++ analysis tools have been identified for this evaluation. The
assessment was limited to these tools for enforcing the set of rules and guidelines and for
contributing to the static analysis and dynamic testing requirements.
4.4.1 QA C++
The Programming Research Group (PRG) has developed the QA C++ tool for auto-enforcing the
HICPP coding standard and for analysing source code (deep flow static analyser). Version 2.0 of
the tool used throughout this assessment provides over 800 warning and error messages. QA C++
analyses source code to identify dangerous usage of the C++ language. Source code is identified
which is non-portable, difficult to maintain, overly complex, or written in any way that is likely to
cause problems [PRG04]. The tool will also identify language usage which is not compliant with
the ISO C++ standard or which is classified as giving rise to unspecified, undefined or
implementation-defined behaviour. In addition [PRG04] describes QA C++ to also provides the
following features:
• 8 function-based, 10 file-based, and 8 class-based code metrics which provide a quantifiable
measure of numerous code attributes;
54
• function structure diagrams to provide an insight into control flow, relationship diagrams to
demonstrate function calling, global referencing, include file trees, class hierarchies, and class
implementation details;
• demographic analysis to provide an overall assessment of code quality against industry
benchmarks; and
• cross-module analysis capability, delivering memory allocation mismatches, function
recursion, and other global issues.
4.4.2 PC-Lint / FlexeLint
Gimpel Software has developed the PC-Lint / FlexeLint diagnostic tool for C and C++. The tool
currently provides a substantial number of checks relating to both C and C++ in release version
8.00. PC-Lint / FlexeLint detection capabilities include expression analysis, order of evaluation
problems, loss of precision, signed/unsigned mismatches, unusual constants, suspicious
comparisons, unusual indentation, suspicious truncation, unintended name hiding, suspicious
initialisation, inappropriate use of pointers to auto variables and macro irregularities [Gim01]. PC-
Lint / FlexeLint provides stricter type-checking than the C++ base language [Gim01]. A recent
addition to PC-Lint / FlexeLint is its value tracking features.
4.4.3 MALPAS
MALPAS is not explicitly a C++ tool. MALPAS is a rigorous verification tool that will reveal
program structure, examine functionality in detail, and check conformance with the specification
[ATC03]. MALPAS has been used to improve system integrity, demonstrate to regulatory bodies
and customers that programs are error free, and to produce safety critical software more cost
effectively [ATC03].
[ATC03] describes that MALPAS applies the following analysis techniques:
• Control Flow Analysis – identifies unstructured control flow in a program;
• Data Use Analysis – identifies all the inputs and outputs of each procedure to reveal data
handling errors;
• Information Flow Analysis – each procedure is analysed to deduce the information on which
its outputs depend;
• Path Assessor – all possible paths through the program are analysed and the number of paths
through the code is reported for each procedure;
• Semantic Analysis – re-expresses the complete semantics of the procedure in a formal
mathematical notation to check for discrepancies between the program’s behaviour and its
specification; and
• Compliance Analysis – supports a formal proof that a procedure’s preconditions, and
postconditions hold and behave in accordance with the specification.
MALPAS works by firstly translating the source code into the MALPAS Intermediate Language
(IL). The MALPAS analysis is then conducted on the program expressed in the MALPAS IL. Thus
MALPAS can conceivably be applied to programs of any programming language. There is
presently no automatic translation available for C++ into the MALPAS IL, but it is believed that it
would be possible to develop such a translator. There are generic object-oriented mappings
55
available for the MALPAS IL that permit the manual translation of C++ into the MALPAS IL.
Manual translation of C++ into the MALPAS IL may be time consuming for a project of other than
trivial size.
4.4.4 Cantata++
Cantata++ provides facilities for dynamic testing, coverage analysis, and static analysis [IPL98].
[IPL98] states that the benefits of Cantata++’s approach to testing are improved productivity,
documentation, repeatability, maintainability and quality.
Cantata++’s dynamic testing facilities can be used to execute the software under test in order to
verify its compliance with requirements [IPL98]. These tests can be carried out at unit, integration
and system level. The dynamic testing features of Cantata++ include the test harness, checking
values and data, exception and template testing, simulating external software, timing analysis, and
test re-use. Cantata++ is capable of handling test cases generated using both functional (black-box)
or structural (white-box) techniques [IPL98]. Cantata++ is capable of checking for both expected
behaviour (positive testing) and unexpected behaviour (negative testing).
Cantata++’s coverage analysis can be used to measure the proportion of software exercised by the
aforementioned dynamic testing. The metrics may be viewed both as non object-oriented coverage
measures, or using Cantata++’s object-oriented coverage reporting facilities [IPL98]. Cantata++
supports statement coverage, decision (or branch) coverage, boolean expression coverage, call pair
(call/return) coverage, call coverage, and modified condition / decision coverage (MC/DC).
Cantata++’s static analysis facilities are limited to the gathering and reporting of metrics on the
code [IPL98]. This relates to the enforcement of coding standards, measurement of code complexity
and structure, and object-oriented metrics assessment.
4.4.5 Evaluation of Rules
Given that QA C++ has been specifically developed for enforcing HICPP, then it shall be the first
tool considered. Note that PC-Lint / FlexeLint has only been considered where QA C++ has been
assessed to not provide a complete detection and enforcement capability. Thus there may be a
significant proportion of rules and guidelines that may be detected by PC-Lint / FlexeLint that
won’t be identified. Time constraints on the project meant that a limit had to be placed on the scope
of the assessment. Section 7.2 shall identify this as an area worth considering for further work.
Where QA C++ was determined to be applicable in enforcing the rules and guidelines applicable to
a particular item then ‘QAC++’ would be annotated in the ‘Enforced’ column (Table 9). In some
cases it was possible to obtain a direct mapping between the rules and the tool’s enforcement
capabilities. However there were other cases where QA C++ was only assessed to provide a partial
enforcement of particular rules or guidelines. In this case the annotation ‘QAC++ partial’ was used.
Where QA C++ was assessed to provide insufficient enforcement then PC-Lint / FlexeLint was
assessed to determine if it could be used to supplement the rule and guideline enforcement. The
annotations ‘PC-Lint’ and ‘PC-Lint partial’ have been used to indicate full or partial PC-Lint
coverage of the rules and guidelines respectively. Note that in some cases a rule or guideline would
be annotated with both ‘QAC++ partial’ and ‘PC-Lint partial’. In none of the cases examined did
this then equate to a full auto-enforcement capability. Thus two partial enforcements don’t equate to
a full enforcement.
If neither QA C++ or PC-Lint / Flexi-Lint were assessed to provide direct enforcement of a given
rule or guideline then the annotation ‘No auto’ was used to indicate that there was no automatic
56
enforcement available from these two tools. To enforce such cases other tools would need to be
sought, or manual checks and controls would need to be employed.
Industrial Strength C++ Item Control Enforced
Rule 8.1 Delete should only be used with new. Rule 12.3 (direct) QAC++
Rule 8.2 Delete[] should only be used with new[]. Rule 12.3 (direct) QAC++
Rule 8.3 Do not access a pointer or reference to a deleted object. Rule 12.8 (avoids) QAC++ partial
PC-Lint partial
Rec 8.4 Do not delete this. New Rule (4) QAC++
Rec 8.5 If you overloaded operator new for a class, you should
have overloaded operator delete.
Rule 12.6 (direct) QAC++
Rec 8.6 Customise the memory management for a class if
memory management is an unacceptably large part of the
allocation and deallocation of free store objects of that
class.
Efficiency
Rec 9.1 Objects with static storage duration should be declared
only within the scope of a class, function, or anonymous
namespace.
Rule 8.1.1 (direct)
Rule 8.1.2 (direct)
Rule 8.2.2 (direct)
Guideline 6.6 (supports)
QAC++
QAC++
QAC++
No auto
Rec 9.2 Document how static objects are initialised. Rule 8.2.2 (direct)
Guideline 8.3.2 (avoids)
Maintenance
QAC++
No auto
Rule 10.1 Declare data members private. Rule 3.4.1 (direct) QAC++
Rec 10.2 If a member function returns a pointer or reference, you
should document how it should be used and how long it
is valid.
Maintenance
Rec 10.3 Selection statements (if-else and switch) should be used
when the control flow depends on an object’s value;
dynamic binding should be used when the control flow
depends on the object’s type.
Software Engineering –
Object Oriented Design
Rule 10.4 A public base class must have either a public virtual
destructor or a protected destructor.
Rule 3.3.2 (direct)
Guideline 17.7 (direct)
QAC++
No auto
Rule 10.5 If you derive from more than one base class with the
same parent, that parent should be a virtual base class.
Rule 3.3.15 (direct) QAC++
Rec 10.6 Specify classes using preconditions, postconditions,
exceptions, and class invariants.
Software Engineering –
Object Oriented Design
Malpas
Rec 10.7 Use C++ to describe preconditions, postconditions,
exceptions and class invariants.
Software Engineering –
Object Oriented Design
Rec 10.8 It should be possible to use a pointer or reference to an
object of a derived class whenever a pointer or reference
to public base class object is used.
Rule 3.3.3 (direct)
ISO C++ defines
QAC++
Rec 10.9 Document the interface of template parameters. Maintenance
Table 9: HICPP Coverage of Industrial Strength C++ Items (partial extract from Appendix 1)
Because MALPAS and Cantata++ are not used to enforce rules, but are instead analysis and testing
tools, they are not widely referenced in the tables in Appendixes 1 to 14. They are predominantly
used in supporting the work conducted in Sections 5 and 6.
The results of the assessment shall now be considered. To summarise briefly, the capability of these
tools for auto-enforcing the HICPP and additional rules and guidelines relating to C++ best practice
and OOTiA recommendations is substantial. However, complete auto-enforcement of every rule
and guideline is not possible with these tools. Less substantially, but still significant, are the tools’
capability for auto-enforcing the HICPP and additional rules and guidelines relating to the
unspecified, undefined, implementation-defined and indeterminate behaviours.
The capability of these tools for auto-enforcing the standard template library (STL) related rules and
guidelines is extremely limited. This relates to both the C++ STL best practice, problems and
solutions, as well as the unspecified, undefined and implementation-defined behaviours. Thus there
57
is a need for the range of checks provided by QA C++ or PC-Lint / FlexeLint to be expanded with
respect to the STL rules and guidelines. Alternatively other tools are required to be identified or
developed. An auto-enforcement capability for the STL related rules and guidelines is particular
important as it provides the primary means of mitigating the base language array bounds problems.
QA C++ provides a significant proportion of the total enforcement capability, noting the limitations
placed on the PC-Lint / FlexeLint assessment. However there are a small number of cases where
PC-Lint / FlexeLint’s detection capabilities differ slightly to QA C++ and these are responsible for
those rules and guidelines against which it provides further enforcement.
It is probably also appropriate to raise the issue of rules and guidelines that don’t lend themselves to
enforcement. These are the types of rules and guidelines that often draw the sternest criticism due to
their potential ambiguity. Though it is arguably better to include a rule or guideline that only applies
in certain cases and is not auto-enforceable than to ignore such a possibility. The rules or guidelines
may not lend themselves to auto-enforcement because the rule or guideline does not lend itself to
static detection or because the rule or guideline relates to the higher level design development. In
such cases this should be highlighted and some level of traceability established between the static
analysis deficiencies and the dynamic test coverage. In addition there is scope for the development
of tools to detect unsafe higher level designs. QA C++ provides some capability for graphically
representing the class hierarchy and describing other higher level design issues. However these
diagrams and reports still require manual inspection to assess their correctness.
The rules and guidelines (shown in Appendix 15) are the most significant in lacking an auto-
enforcement capability. For each rule an assessment is made to determine if the case is statically or
dynamically detectable (or both in some cases). Each rule has also been assessed as to if it
represents a design issue, coding level detectable issue or is related to the coding environment. The
combination of these assessments will determine the likelihood that the rule can be auto-enforced.
Those rules or guidelines assessed as requiring enforcement of a design related issue (in particular
dynamic, but also applies to some static cases) will be the most difficult to provide a tool to auto-
enforce. These are numerous among those presented below and represent an area where auto-
enforcement is immature. It also works to identify those items that require specific design review,
or dynamic tests included as part of the test program.
4.5 Summary of Definition of Safer C++ Subset
Section 4.1 has examined HICPP against C++ behaviours, best practice (problems and solutions)
and the OOTiA recommendations. From this Section 4.2 has identified deficiencies in HICPP and
has developed additional rules and guidelines to address these deficiencies. This combination of the
HICPP rules and guidelines and the addition rules and guidelines shall be known as the safer C++
subset. Section 4.3 has identified and reasoned about those rules within HICPP that were not
referenced in the assessment. Finally Section 4.4 has examined the enforcement of the rules and
guidelines of the safer C++ subset.
58
5 Arguments for Programming Language Selection
A number of the standards covered in Section 2.3 detailed that the selection of programming
language for a safety critical system should be justified and that a safety case should be produced.
Thus it is worth examining what means could be used to argue justification for the selection of
programming language within the context of a system’s safety case. Section 2 examined a broad
range of literature and standards that provide guidance relating to the selection of a programming
language for a safety critical system. Generally, individual sources presented guidance as an
unrelated set of language criteria. An inspection of this guidance revealed numerous themes within
the totality of this information. The identified themes include:
• Only the completely and unambiguously defined aspects of the programming language should
be used. Ambiguously and poorly defined aspects of the language should be avoided.
• The language must support recognised software engineering principles. Such principles
include strongly typed features, a modular and structured approach, abstraction, encapsulation
and information hiding.
• The language must be well understood by programmers and developers and this must support
the correct implementation of the design.
• The language’s implementation of its paradigm and features must support the design method,
domain, and application.
• The language must lend itself to static analysis and dynamic testing, the totality of which is
sufficient to provide confidence in the safety of the software.
• High quality, certified or verified language translators, analysis and support tools must be
available for the language.
These themes certainly seem relevant, but they lack an important component that is required when
constructing a justifiable argument. The themes lack ‘why’ they are important. Thus a particular
focus of the argument construction will be in determining ‘why’ these factors make a programming
language suitable. The construction of the argument is also going to serve as an evaluation of these
criteria. For example, if criteria are stipulated, but are found to not be required to form a justifiable
argument, then are they useful criteria? Likewise, are there deficiencies in the criteria that prevent a
justifiable argument being made?
Section 5.1 examines the construction of an argument for justifying the selection of a programming
language. The argument presented here is evaluated in Section 6.1.
5.1 GSN Argument for Programming Language Selection
An argument pattern has been developed and is presented in Appendix 16. Goal Structuring
Notation (GSN) was identified in Section 2.8 as a suitable tool for developing and expressing the
argument. This section describes the activity of developing the pattern and should be read in
conjunction with the pattern in Appendix 16 (Figures 16-1 to 16-11). The pattern is intended to be
applied to the justification of potentially any programming language. The pattern has also been
developed to ensure coverage of the criteria specified in IEC 61508, DO-178B, and Defence
Standard 00-55 Issue 2. Thus its structure has been deliberately developed to be flexible.
59
The first step of the GSN process, as described by [HRM04], is to identify and define the top-level
goal. Thus the overall objective of the argument must be established. This is important because if it
doesn’t contain the right aim, then the argument may be difficult to satisfy. Section 1.2 identified
safety as a system property. This is important as it highlights that, while the selection of the
programming language can certainly contribute to the safety of the system, it is unreasonable to
conclude that in isolation a programming language is safe. Hence, defining a top level goal as
‘{Lang X} is acceptably safe’ or ‘{Lang X} is acceptably safe for {System Y}’ is not appropriate.
There should be a goal stating ‘{System Y} is acceptably safe’, but this does not belong in the
language justification.
A programming language can certainly introduce errors into a design, as can it introduce
unnecessary complexity into the implementation of an otherwise simple design. Thus it seems
reasonable that these are the properties that an argument should conclude a programming language
shouldn’t have. Furthermore, arguing the safety of the design is not the responsibility of an
argument centred on the selection of the programming language. This is the realm of the software
design safety argument that, because safety is a system property, will be embedded within an
overall system safety argument. The system safety argument also includes such factors as hardware,
environment, people, processes and standards. Thus, assuming that the software design, and the
system for that matter, is shown to be acceptably safe, then it follows that the programming
language selection should primarily be concerned with correctly implementing the acceptably safe
design. Hence, the top level goal is established as ‘{Lang X} supports the correct implementation of
{System Y}’s software design’. In some respects this is related to the Software Fault Free Pattern in
[HRM04].
Having established the top level goal (Figure 15 below), the next step is to define the basis on
which that goal is being stated. A programming language does not exist in isolation, nor does it
implement the design itself – though that would be a useful feature. Code in a given programming
language will always be written either by programmers or by tools that were written by
programmers. Thus a programming language’s ability to correctly implement a design is not only a
function of its own properties, but also on the programmers using it and the tools (translators,
environments, analysis and test, etc) supporting it. Furthermore, the role of the programming
language does not cease the moment the system enters service. Systems change, and the
programming language must also correctly support the system through these changes and
throughout its operational lifetime. This leads us to the three main strategies employed in the
argument (Figure 15). These are as follows.
• S1 – Argument over {Lang X} supporting the correct implementation of the design during
initial development and during {SystemY}’s operational lifetime.
• S2 – Argument over the programmers’ roles in correctly implementing {System Y}’ssoftware design.
• S3 – Argument over the tools’ roles in correctly implementing {System Y}’s software design.
S1 is certainly to be the bulk of the argument. However, the importance of S2 and S3 is supported
by their inclusion at this high level within the goal structure. S1 can be logically divided into two
supporting goals relating to the correct implementation during initial development (G1.1) AND the
correct implementation over the system’s operational lifetime (G1.2). G1.2 is supported by a
number of goals, but the emphasis is on identifying those features of the language that can support
the communication of the original programmers’ intentions to the future maintainers. For example,
user documentation and comments (G1.2.1), and coding style guidelines for consistency and
maintenance (G1.2.2) are considered the minimum required (see Figure 16-1).
60
G.TOP
{LangX} supports the
correct implementation of
{SystemY}'s software
design
C.TOP.2
{SystemY} definition
G1.2
{LangX} features support
maintaining the
implementation over
{SystemY}'s operational
lifetime
S1
Argument over {LangX}
supporting the correct
implementation of the
design during initial
development and during
{SystemY}'s operational
lifetime
G1.1
{LangX} supports the
correct implementation of
the design during initial
development of {SystemY}
G2.1
{LangX} is well understood
by the programmers and
this supports the correct
implementation of the
design
S2
Argument over the
programmers' roles in
correctly implementing
{SystemY}'s software
design
S3
Argument over the tools'
roles in correctly
implementing
{SystemY}'s software
design
G3.1
Tools for development in
{LangX} support the
correct implementation of
{SystemY}'s software
design
A.TOP
{SystemY}'s software
design is shown to be
acceptably safe
elsewhere A
C.TOP.1
{LangX} definition
Figure 15: Top Level Argument (partial extract from Figure 16-1)
Correctly implementing the design during the initial development (G1.1) reduces to two diverse
relationships (Figure 16 below). The language must have features suitable to implement the design
(S1.1B). For example, if the design is a multi-threaded design, and the language only supports
single threaded applications, then there may be problems. Likewise if the language requires
interfaces to modules written for the application in other languages, and it doesn’t support them,
then the language is also probably the wrong choice. Furthermore, there must be a means of
preventing AND/OR detecting all errors made in the implementation of the design (S1.1A).
Detecting errors as it is described here is concerned with detecting the errors during analysis or
testing of the system, and prior to any operational testing or operational release. This is different to
the notion of run-time error detection and handling which is included as part of the error prevention
argument (G1.1A.1). This is because this has been classified as a means of actually preventing fatal
run-time errors during system operation (ie. it gives the software the option of recovering or failing
safe). Note the use of the AND/OR conjunction. This is important because, depending on the
language, the balance of prevention (G1.1A.1) and detection (G1.1A.2) may vary. The pattern
supports this notion with the n-of-2 option symbol. These two goals also relate to the choice of
design philosophy identified in Section 1.2. The remainder of the argument is focussed on
supporting these two goals (G1.1A.1 and G1.1A.2).
G1.1
{LangX} supports the
correct implementation of
the design during initial
development of {SystemY}
S1.1A
Argument over means of
preventing and/or
detecting errors
S1.1B
Argument over features
required by {LangX} in
order to implement the
design
G1.1A.1
Occurrences of errors in
the implementation of the
design in {LangX} are
prevented
G1.1A.2
Occurrences of errors in
the implementation of the
design in {LangX} are
detected
G1.1B
{LangX} supports
{FeatureZ} that is required
in order to correctly
implement the design
n-of-2
n
Figure 16: Correct Implementation Argument (partial extract from Figure 16-1)
61
5.1.1 Supporting Goal G1.1A.1 (in Appendix 16 Figure 16-2)
G1.1A.1 is defined as ‘Occurrences of errors in the implementation of the design in {Lang X} are
prevented’ (Figure 17 below). Now presuming that the programmers’ are actually capable of
writing code that will compile (ie. is grammatically correct – A1.1A.1), and the compiler is the least
bit useful at pointing out grammatically incorrect source code, then that leaves two places that
errors could occur in the implementation of the design. Thus, the argument should be focussed to
prevent these errors.
G1.1A.1.2
Occurrences of run-time
errors in the
implementation of the
design are prevented
S1.1A.1
Argument over
instances at which
errors that might occur
in the implementation of
the design
G1.1A.1
Occurrences of errors in
the implementation of the
design in {LangX} are
prevented
G1.1A.1.1
Errors are not introduced
in the translation of the
implementation (source
code) into executables
A1.1A.1
Source code is
grammatically correct
A
Figure 17: Error Prevention Argument (partial extract from Figure 16-2)
Errors that may manifest themselves at run-time should not have been introduced in the
implementation of the design (G1.1A.1.2 –Figure 18 below). These may be caused by either aspects
of the language which behave unpredictably (S1.1A.1.2A), despite the programmers understanding
of them, or aspects of the language which get used incorrectly because they are error prone or
because programmers don’t understand them properly (S1.1A.1.2B). Sections 5.1.1.1 and 5.1.1.2
further address the development of these strategies. Also, errors should not be introduced in the
translation of the implementation (source code) into executables (G1.1A.1.1 – see Figure 16-2).
This is out of the programmers’ control and responsibility lies with the translator (compiler). Thus it
is important to be able to reason that errors are either absent from the translator (G1.1A.1.1.1), or
are known and can be avoided (G1.1A.1.1.2). Supporting these goals may be more difficult than it
would seem. To show that errors are absent from a translator then the translator must have been
subjected to some form of formal verification. Alternatively, showing that all errors are known in a
translator can be equally as difficult, especially if the translator is not widely used.
G1.1A.1.2B.1
Sources of commonly
introduced run-time errors
are identified and avoided
G1.1A.1.2B.2
{LangX} supports the
application of design
techniques that avoid and
mitigate run-time errors
G1.1A.1.2
Occurrences of run-time
errors in the
implementation of the
design are prevented
S1.1A.1.2B
Argument over means of
avoiding, mitigating,
detecting and handling
non-definition related
errors at run-time
G1.1A.1.2A.1
Only completely and
unambiguously defined
aspects of {LangX} are
used for {System Y}
S1.1A.1.2A
Argument that no errors,
omissions or
inconsistencies relating
to {LangX}'s definition
will contribute to run-
time errors in the
implementation of the
design
C1.1A.1.2A
{LangX} definition
G1.1A.1.2B.3
{LangX} supports a robust
run-time error detection
(or exception) system and
handling mechanism
Figure 18: Run-time Error Argument (partial extract from Figure 16-4)
62
5.1.1.1 Arguing strategy S1.1A.1.2A (Definition Related Errors – Appendix 16 Figure 16-4)
Language behaviour is a function of the language definition. Thus one strategy of supporting
G1.1A.1.2 would be to argue that no language definition issues will contribute to run-time errors in
the implementation of the design (S1.1A.1.2A → G1.1A.1.2A.1 – Figure 19). There should only be
one definition of the language (S1.1A.1.2A.1A – Figure 19), as multiple definitions of the same
language works against the programmer’s chances of understanding the language. The best means
of ensuring only one language definition is for the language to be internationally standardised
(G1.1A.1.2A.1A.1 and G1.1A.1.2A.1A.2).
Even if there is only one definition of the language, then it may not be complete. This identifies the
second strategy (S1.1A.1.2A.1B – Figure 19). Language definition standards, even international
ones, are littered with unspecified, undefined, indeterminate and implementation-defined
references. Thus, either the language definition’s completeness must be ascertained
(G1.1A.1.2A.1B.1), which is rare, or those behaviours that are not completely and unambiguously
defined must be restricted through some form of subset (G1.1A.1.2A.1B.2 – Figure 16-6).
G1.1A.1.2A.1A.1
Base language of
{LangX} has been
internationally
standardised
S1.1A.1.2A.1A
Argument that the
standardisation of
{LangX} eliminates
ambiguities relating to
variations in definition
G1.1A.1.2A.1B.1
{LangX} has no
unspecified, undefined,
indeterminate and
implementation defined
behaviours
G1.1A.1.2A.1B.2
A subset of {LangX}
sufficiently restricts the
unspecified, undefined,
indeterminate and
implementation defined
behaviours of {LangX}
G1.1A.1.2A.1A.2
Library support for
{LangX} has been
internationally
standardised
G1.1A.1.2A.1
Only completely and
unambiguously defined
features of {LangX} used
for {System Y}
S1.1A.1.2A.1B
Argument that only the
completely and
unambiguously defined
features of {LangX} are
to be used
Figure 19: Definition Argument (extract from Figure 16-5)
5.1.1.2 Arguing strategy S1.1A.1.2B (Non-definition Related Errors – Figure 16-4)
S1.1A.1.2B is defined as “Argument over means of avoiding, mitigating, detecting and handling
non-definition related errors” (Figure 18). This is perhaps the most difficult aspect of the entire
language argument. This is because it is difficult to truly ascertain just what errors programmers are
likely to make. Thus the argument must use a number of diverse argument approaches in order to
provide confidence that G1.1A.1.2 will be supported. One approach is to claim that a lot is known
about a language, its problems, and that it is possible to address these problems (G1.1A.1.2B.1). In
some respects this is reflective of the work conducted for C++ in Sections 3 and 4. But how are
errors that are not known about prevented? After all, to argue across all errors, the argument needs
to include both known and unknown errors. To support this it is possible to also claim that the
language can support design techniques that avoid and mitigate run-time errors (G1.1A.1.2B.2) and
that should an error occur, even an unknown one, then it could be detected and handled
(G1.1A.2B.3). Because the error has been successfully detected at run-time and there is a
predictable mechanism for the software to recover or fail safe then it is no longer considered an
error through which the timing, resource usage and functionality of the software becomes
unpredictable.
63
Thus to support G1.1A.1.2B.1, the main types of errors must be identified. In turn these sources of
errors could be related to those features of, or restrictions on, the language that prevent such errors
(Figure 20). Hence, a list of the types of errors that can occur in software is required. Recalling that
software is composed of data and the operations on that data, then it follows that errors could be
resident in either of these. An error in the data (ie. data related) is straight forward to comprehend,
but an error in an operation is going to be caused either because the data is in error (also data
related), or because the sequence of sub-operations comprising the overall operation is changed
(control flow related). Note also that software must execute on real world hardware. Thus these
external influences have the potential to inflict errors upon the software. For example, resources are
related to a finite number of hardware elements (resource availability related), and real world
hardware does not execute instructions instantaneously (ie. timing is a property). Timing properties,
although hardware related, also are impacted by the sequence of operations within the software
(control flow related). Finally it is also possible for certain instructions to be in error and for the
hardware to cease operating (run-time exception / abnormal program termination), operate
incorrectly (run-time exception / control flow related), or for the system to be reset (control flow
related) or recover (run-time exception / control flow related). Thus the list of the types of errors
that can occur in software becomes:
• Data Related: a variable, memory location, or object contains an incorrect or invalid valuedue to the occurrence of an error.
• Control Flow Related: the path of execution through the code is changed because of the
occurrence of the error and thus the operations on the data are changed.
• Run-time Exceptions / Abnormal Program Termination: a specific instruction cannot be
executed or executes unpredictably due to the occurrence of the error. For many languages the
run-time system may either terminate the program (undesirable), or the system may be left
hanging (also undesirable).
• Resource Availability: the occurrence of the error has impacted upon the ability of the system
to make appropriate resources available to the system.
G1.1A.1.2B.1 is defined as ‘Sources of commonly introduced run-time errors are identified and
avoided” (Figure 20). By arguing across each of the error types identified above, the goal can be
supported. A programming language has properties. Software engineers often find names for groups
of these properties that include such things as typing (G.TYPE), variable initialisation
(G.VARIABLES), mathematical model (G.MATH), paradigm (G.PARADIGM), side effects in
expression (G.SIDE), scopes, blocks and jumps (G.JUMPS), and memory model (G.MEMORY).
Another property of a programming language is just how prone its syntax is to typos
(G.MISTAKES). Each of these properties can lead to one or more of the error types (data, control
run-time exception / abnormal program termination, resource availability). Thus each error type
must be argued over all the language properties that can relate to that particular error type. Figure
20 shows the complex relationships between these properties.
For new programming languages and advanced software / hardware relationships, it may be
possible that errors may not totally lend themselves to classifications under data related, control
flow related, run-time exception/abnormal termination related, and resource availability related.
Thus G1.1A.1.2B.1.5 (Figure 16-8) provides a means of arguing that such errors are known about
and can be restricted.
64
G.SIDE_EFFECT.1
{LangX} is not prone to
side effects in expression
G.MISTAKES
{LangX} has features to
facilitate the detection of
programming typos and
unintentional mistakes
G.JUMPS.1
{LangX} supports a
modular, structured
approach (restrictions on
jumps between scopes)
G.VARIABLES.1
Declaration and
initialisation of variables is
explicit
G.TYPE.1
{LangX} is strongly typed
to ensure type safety and
to avoid type related
errors at run-time
G.VARIABLES
Uninitialised and implicitly
initialised variables that
are a likely source of error
at run-time are avoided
G.SIDE_EFFECT
Side effects in expression
that are a likely source of
error at run-time are
avoided
G.MISTAKES
Unintentional
programming mistakes
that are a likely source of
run-time error are avoided
S1.1A.1.2B.1
Argument across the
identified sources of
commonly introduced
run-time errors
G.JUMPS
Jumps between scopes
that are a likely source of
error in an implementation
of a design are avoided
G.TYPE
Type related features that
are a likely source of error
at run-time are avoided
G.PARADIGM.1
{LangX}'s implementation
of the paradigm's features
is error free
G1.1A.1.2B.1
Sources of commonly
introduced run-time errors
are identified and avoided
J1.1A.1.2B.1
Identified sources of
commonly introduced
run-time error are
adequate
G.PARADIGM
Paradigm related sources
of commonly introduced
run-time errors are
avoided
G1.1A.1.2B.1.1
Data related sources of
commonly introduced run-
time errors in an
implementation are
restricted
G1.1A.1.2B.1.2
Control flow related
sources of commonly
introduced run-time errors
in an implementation are
restricted
G1.1A.1.2B.1.4
Resource availability
related sources of
commonly introduced run-
time errors in an
implementation are
restricted
G.MEMORY
Memory allocation/
deallocation activities that
are a likely cause of error
in an implementation of a
design are avoided.
G.MEMORY.1
{LangX} is not prone to
memory leaks
G.MATH
Mathematical operations
and results that are a
likely source of error at
run-time are avoided
G.MATH.1
{LangX} is not prone to
invalid mathematical
operations and results
G1.1A.1.2B.1.5
Other sources of
commonly introduced run-
time errors in an
implementation of a
design are restricted
G1.1A.1.2B.1.3
Run-time exceptions
leading to abnormal
program termination in an
implementation are
restricted
J
Generic language argument
shall address all relationships.
Some relationships may be
simplified in relation to the
specific design context of
{SystemY}.
Figure 20: Common Error Sources Argument (extract from Figure 16-7)
5.1.2 Supporting Goal G1.1A.2 (Detecting Errors – in Appendix 16 Figure 16-3)
G1.1A.2 is defined as “Occurrences of errors in the implementation of the design in {Lang X} are
detected” (Figure 21). Similarly to arguing G1.1, this goal may be supported through two diverse
arguments. Primarily, there must be a means of showing that errors in the implementation of the
design would be detected through some form of analysis and verification (S1.1A.2A). Recognising
that analysis and verification can be satisfied with either static analysis, dynamic testing, or ideally
a combination of both, the important point that needs to be established is that the totality of these
activities provides sufficient confidence that all necessary properties of the software implementation
have been revealed. Noting the numerous benefits of static analysis detailed in Section 2.9, the
pattern seeks to promote the use of static analysis to analyse and verify a significant proportion of
the implementation of the design (G1.1A.2A.1). The word “significant” has been used as it
indicates a substantial amount of static analysis, but recognises that rarely can static analysis be
used in isolation. Dynamic testing must then be sought to complement the static analysis (ie. make
total the analysis and verification) (G1.1A.2A.2).
Returning to supporting the goal G1.1A.2. The secondary aspect is to argue that it may also be
possible to argue that the language has features that actually facilitate the detection of errors in the
design or in the implementation of the design (S1.1A.2B). This seeks to alleviate some of the
pressures on the analysis and verification activities. As a minimum these features should include
restricting the complexity of the implementation (G1.1A.2B.1), as complex implementations are
rarely correct, and using abstraction and information hiding to detect operations that may violate
data integrity (G1.1A.2B.2). For example, the hiding of the internal state of an object, and allowing
access only through specified functions or methods, will detect problems of external modules
attempting to directly access the object’s internal state.
65
ref. Figure P-9G1.1A.2B.1
{LangX} has features to
restrict and manage
complexity
S1.1A.2B
Argument over types of
implementation features
that facilitate the
detection of errors in the
design
G1.1A.2A.2
{LangX} lends itself to
dynamic testing to
complement the static
analysis
S1.1A.2A
Argument to show that
errors in the design
would be detected
though analysing and
verifying the
implementation in
{LangX}
G1.1A.2A.1
{LangX} lends itself to a
significant proportion of
static analysis
G1.1A.2B.2
{LangX} supports
abstraction and
information hiding
G1.1A.2
Occurrences of errors in
the implementation of the
design in {LangX} are
detected
G1.1A.2B.3
{LangX} supports other
features that facilitate the
detection of errors in the
design
Figure 21: Error Detection Argument (extract from Figure 16-3)
5.1.2.1 Supporting Goal G1.1A.2A.1 (Static Analysis – Appendix 16 Figure 16-10)
G1.1A.2A.1 is defined as ‘{Lang X} lends itself to a significant proportion of static analysis’
(Figure 22). This leads to the question of what is required of a language in order to perform static
analysis. To support this goal, it is necessary to argue a number of things. Firstly, unless necessary
for the design, it is vital to limit those features which inhibit static analysis (S1.1A.2A.1A). As a
minimum such features include limiting dynamic variables (G1.1A.2A.1A.1), interrupts
(G1.1A.2A.1A.2), and recursion (G1.1A.2A.1A.3). If necessary, then the use of such features shall
be specifically justified for the design. For example, while the recursive implementation of an
algorithm may appear simple in the source code, the truth is that it is rarely going to be more
efficient (due to repeated numbers of function calls and the associated overhead) than it’s iterative
equivalent. Its resource usage is also going to be difficult to analyse. Thus justification should be
based on clarity, correctness, performance, efficiency, analysability, and testability, not just
convenience.
Secondly, it is necessary to argue that the language is statically predictable where required
(S1.1A.2A.1B). As a minimum the aspects that should be statically analysable are the resource
usage behaviour (G1.1A.2A.1B.1), the temporal behaviour (G1.1A.2A.1B.2), and the functional
behaviour (G1.1A.2A.1B.3) of the language. Ascertaining these behaviours will adequately
demonstrate the absence of the error types listed in Section 5.1.1.2. A valid means or a combination
thereof (indicated by the n-of-4/5 option) for statically analysing functional behaviour includes
control, data and information flow analysis (G1.1A.2A.1B.3.1), precondition, postcondition and
invariant analysis (G1.1A.2A.1B.3.2), formal code verification (G1.1A.2A.1B.3.3) and symbolic
execution (G1.1A.2B.1B.3.4). The pattern also provides flexibility for arguing other appropriate
means of satisfying these goals.
Finally in achieving G1.1A.2A.1, the strategy must also be cognisant of what the relevant standards
specify in relation to static analysis (S1.1A.2A.1C). Some standards are particularly prescriptive
with regards to the types of analysis to be performed. Thus it would be undesirable to apportion the
static analysis and dynamic testing such that, although total in coverage, the testing does not meet
the relevant standards. If standards are goal based, then the argument provides the flexibility to
argue alternate apportionment.
66
G1.1A.2A.1A.1
Use of dynamic variables
is restricted except where
justifiably necessary
G1.1A.2A.1B.3.1
{LangX} lends itself to
control flow, data flow, and
information flow analysis
G1.1A.2A.1B.1
{LangX}'s run-time
resource usage is
analysable and
predictable
G1.1A.2A.1A.3
Use of recursion is
restricted except where
justifiably necessary
G1.1A.2A.1A.2
Use of interrupts is
restricted except where
justifiably necessary
G1.1A.2A.1A
{LangX} features that
inhibit the capabilities of
static analysis are
restricted
G1.1A.2A.1B.3.2
{LangX} support the use of
assertions/annotations in
analysing preconditions,
postconditions and
invariants
G1.1A.2A.1
{LangX} lends itself to a
significant proportion of
static analysis
S1.1A.2A.1A
Argument over a
restriction on those
features of {LangX} that
inhibit static analysis
G1.1A.2A.1B.3.4
{LangX} lends itself to
symbolic execution
G1.1A.2A.1B.2
{LangX}'s temporal
behaviour is analysable
and predictable
G1.1A.2A.1B.3
{LangX}'s functional
behaviour is analysable
and predictable
G1.1A.2A.1B.3.3
{LangX} lends itself to
formal code verification
(formal methods)
S1.1A.2A.1B
Argument that {LangX}
is predictable and that it
lends itself to static
analysis
S1.1A.2A.1C
Argument that static
analysis of {LangX}
meets the relevant
standards
G1.1A.2A.1C
Static analysis of {LangX}
meets the relevant
standards
C1.1A.2A.1
Definition of "significant
proportion"
C1.1A.2A.1C
Identified relevant
standards
G1.1A.2A.1A.4
Use of other {LangX}
constructs that inhibit the
capabilities of static
analysis is restricted
S1.1A.2A.1B.3
Argument over means of
analysing {LangX}'s
functional behaviour
n-of-4/5
G1.1A.2A.1B.3.5
Other means of analysing
{LangX}'s functional
behaviour are used
Figure 22: Static Analysis Argument (extract from Figure 16-10)
5.1.2.2 Supporting Goal G1.1A.2A.2 (Dynamic Testing – Appendix 16 Figure 16-11)
G1.1A.2A.2 is defined as ‘{Lang X} lends itself to dynamic testing to complement the static
analysis’ (Figure 23 below). To support this goal, it is necessary to argue that the appropriate
aspects of the language’s behaviour are dynamically testable (S1.1A.2A.2A). Appropriate aspects to
dynamically test will be based on the coverage and limitations of the statically analysable aspects of
the language. This provides context for supporting this strategy (C1.1A.2A.2A). As a minimum the
aspects that should be dynamically testable are the temporal behaviour (G1.1A.2A.2A.1), the
resource usage behaviour (G1.1A.2A.2A.2) and the functional behaviour (G1.1A.2A.2A.3) of the
language.
In achieving G1.1A.2A.2, the strategy must also be cognisant of what the relevant standards specify
in relation to dynamic testing (S1.1A.2A.2B). Some standards are particularly prescriptive with
regards to the types and numbers of tests to be performed. Thus, reiterating what was stated for
static analysis apportionment, it would be undesirable to apportion the static analysis and dynamic
testing such that, although total in coverage, the testing does not meet the relevant standards. If
standards are goal based, then the argument provides the flexibility to argue alternate
apportionment.
67
G1.1A.2A.2
{LangX} lends itself to
dynamic testing to
complement the static
analysis
G1.1A.2A.2A.2
{LangX}'s run-time
resource usage is testable
and predictable
G1.1A.2A.2A.1
{LangX}'s temporal
behaviour is testable and
predictable
G1.1A.2A.2A.3
{LangX}'s functional
behaviour is testable and
predictable
S1.1A.2A.2B
Argument that dynamic
testing of {LangX} meets
the relevant standards
G1.1A.2A.2B
Dynamic testing of
{LangX} meets the
relevant standards
S1.1A.2A.2A
Argument that
appropriate aspects of
{LangX}'s behaviour are
dynamically testable.
C1.1A.2A.2A
Identified coverage and
limitations of the statically
analysable aspects of
{LangX}
C1.1A.2A.2B
Identified relevant
standards
Figure 23: Dynamic Testing Argument (extract from Figure 16-11)
5.2 Summary of GSN Argument for Programming Language Selection
Section 5 has presented the development and definition of an argument for justifying the
programming language selection for safety critical systems. The argument has been developed to
incorporate reasoned inclusion of those language criteria reviewed in Section 2.2.
In fact, all of the criteria from Section 2.2 and the themes derived from these criteria (Section 5)
have been found to be necessary in the construction of the goal structure. Also there were no
specific deficiencies in the criteria required to support such an argument.
The argument has now developed the ‘why’ that was previously not evident directly from the
criteria. Section 6.1 seeks to evaluate the validity and usefulness of the pattern.
68
6 Evaluation of Safer C++ Subset and Safety Arguments
Section 4 established a safer C++ subset (HICPP coding standard and additional rules and
guidelines). Section 5 developed a means of arguing the justification of the language selection. This
section now presents several evaluations of the material developed in each of these preceding
sections.
Section 6.1 examines the safer C++ subset against the justification of programming language
selection pattern. Section 6.2 examines the safer C++ subset against the safe language criteria
established in Section 2.2.3. Section 6.3 examines proposals for further evaluating the safety
arguments associated with programming language selection in general, and the safety arguments
associated with the specific selection of the C++ programming language for safety critical systems.
The intention of these evaluations is to identify any deficiencies in either the safer C++ subset or
with the justification of programming language selection argument pattern and how these might be
addressed.
6.1 Evaluation of Safer C++ Subset Against GSN Argument
Section 5.1 developed a safety case pattern for the justification of the selection of programming
language for safety critical systems. The pattern is presented in Appendix 16. Given that this project
has principally concerned itself with an examination of C++ in the context of safety critical
systems, it is worthwhile to evaluate this pattern against the safer C++ subset developed in Sections
3 and 4. The aim of the evaluation is to uncover deficiencies in either the pattern or the safer C++
subset with respect to each other. Note that because many aspects of the pattern require knowledge
of the specific system and design context, instantiation of these goals may be limited to discussion
as to if it is possible to satisfy these goals for C++ and how this might be approached.
Evidence in support of many of the following goals is provided through reference to specific rules
within the safer C++ subset. It is important to note that the rules require enforcement either through
tools or manually. Enforcement of the rules and guidelines was addressed in Section 4.4.
6.1.1 Translator Goals – Figure 16-2
6.1.1.1 G1.1A.1.1.1.1 – Formally Proven / Fully Verified Compiler
Supporting this goal relies on specific system design information relating to the target processor and
environment. It is also related to satisfaction of the chosen language standardisation
(G1.1A.1.2A.1A.1 and G1.1A.1.2A.1A.2) goals. Section 6.1.2 discusses that the C++ language has
been ANSI/ISO standardised. Fully verified and/or formally proven C++ compilers are not widely
available at this time. In addition, many compilers are yet to achieve full ANSI/ISO compliance.
Numerous organisations exist that can offer certification services for a compiler against the
ANSI/ISO C++ standard and these may offer a means of satisfying this goal.
6.1.1.2 G1.1A.1.1.2.1 and G1.1A.1.1.2.2 – Translation Error Avoidance
Supporting this goal relies on specific system design information relating to the target processor and
environment. C++ compilers are becoming more widely available for many target systems, due
mainly to C++ popularity in the commercial sector. These compilers are well documented and
identified problems are widely reported on numerous internet newsgroups and compiler developer’s
websites. It is possible to support G1.1A.1.1.2.1 through providing evidence derived from such
sources. A specific coding standard would then need to be developed for the project to limit the use
of those known sources of error in translation. This could be used as evidence to support
G1.1A.1.1.2.2.
69
6.1.2 Language Standardisation Goals – Figure 16-5
6.1.2.1 G1.1A.1.2A.1A.1 and G1.1A.1.2A.1A.2 – International Standardisation
The C++ base language and standard template library (STL) has been internationally ANSI/ISO
standardised [BSI03]. Reference to [BSI03] should be considered sufficient evidence to support
these goals for C++. Several rules in the safer C++ subset provide restrictions of common features
that are not actually part of ISO C++, but get commonly used in implementations regardless. These
are Rules 6.4, 8.3.1, 10.16, 17.1, & 17.8.
6.1.3 Language Behaviour Goals – Figures 16-5, 16-6
6.1.3.1 G1.1A.1.2A.1B.1 – Fully Defined Behaviour
The C++ language definition [BSI03] contains many references to unspecified, undefined,
indeterminate and implementation-defined behaviour. Thus this goal cannot be supported and
G1.1A.1.2A.1B.2 must instead be supported.
6.1.3.2 G1.1A.1.2A.1B.2 – Restricted Behaviour
Unspecified (G1.1A.1.2A.1B.2.2), undefined (G1.1A.1.2A.1B.2.1), indeterminate
(G1.1A.1.2A.1B.2.4), and implementation-defined (G1.1A.1.2A.1B.2.3) behaviours of C++ are
restricted through the safer C++ subset. Appendixes 8 – 14 have identified a complete list of these
behaviours and also list those rules applicable to restricting these C++ behaviours. Appendixes 8 –
14 would be suitable as evidence for supporting these goals.
6.1.4 Strongly Typed Goals – Figure 16-9
6.1.4.1 G1.1A.1.2B.1.1.1.1.1.1 – Implicit Conversions
Evidence is required to support this goal that shows that implicit conversions do not occur.
Although C++ supports numerous cases of implicit conversions, the following rules and guidelines
prohibit implicit conversions in C++ and thus support strong typing: Rules 3.1.10, 3.1.11, 3.2.3,
3.5.4, 7.8, 8.3.5, & 16.1 and Guidelines 8.4.13, 10.7, & 17.21.
6.1.4.2 G1.1A.1.2B.1.1.1.1.1.2 – Explicit Conversions
Evidence is required to support this goal that shows that explicit conversions only occur when
justified and desired. C++ supports numerous cases of explicit conversions, and the following rules
and guidelines control the use of explicit conversions in C++ and thus support strong typing: Rules
3.1.2, 3.3.3, 3.3.4, 7.1, 7.3-7.7, & 15.4 and Guideline 7.2.
6.1.4.3 G1.1A.1.2B.1.1.1.1.2.1 – Array Bounds Checking
Evidence is required to support this goal that shows that all accesses to arrays are demonstrably
within the bounds of the array. Although C++ arrays lack array bounds checking and enforcement,
the following rules support array type structures with adequate array bounds checking and thus
support strong typing: Rules 8.4.8, 8.4.9, 10.2, & 24.
6.1.4.4 G1.1A.1.2B.1.1.1.1.2.2 – Access Types and Pointers
Evidence is required to support this goal that shows that access types and pointers are only used
where justifiably necessary. C++ provides both pointer and reference access types. The programmer
is not forced to use such types, but certain designs and/or STL features may require their use.
Software designers and programmers should limit the use of these types to those aspects of the
design where their use is necessary and justifiable. Guideline 8.4.10 supports a restriction on access
types in support of strong typing.
70
6.1.4.5 G1.1A.1.2B.1.1.1.1.3.1 – Support for Static Types
Evidence is required to support this goal that shows that C++ supports static types including sub-
types and enumerations. C++ supports subtypes through public inheritance [BSI03]. C++ also
includes direct support for an enumeration primitive type [BSI03]. The following rules and
guidelines place restrictions on C++ types to strengthen their static characteristics: Rule 15.1 and
Guidelines 3.4.7, & 8.4.6.
6.1.4.6 G1.1A.1.2B.1.1.1.1.3.2 – Statically Analysable
Evidence is required to support this goal that shows that C++ types are statically analysable. With
the exception of access and pointer types, C++ POD types are statically analysable. Some uses of
access and pointer types are also statically analysable. Rule 15.1 places a restriction on C++ types
to improve static analysability. C++ class types support the use of polymorphism and dynamic
binding. Such mechanisms aren’t always statically analysable and evidence of appropriate other
tests (dynamic) should be identified to address the deficiencies and reveal the software properties
that would otherwise be revealed through static analysis.
6.1.4.7 G1.1A.1.2B.1.1.1.1.4 – Run Time Checking
Evidence is required to support this goal that shows that run-time checking is carried out on C++
types at run-time. The fact that G1.1A.1.2B.1.1.1.1.1 and G1.1A.1.2B.1.1.1.1.2 are adequately
supported means that evidence is only required to demonstrate that types remain within their ranges
and do not overflow or underflow. Although the C++ run-time machine does not usually support
overflow/underflow checking, these activities can be achieved through appropriate design and
application of defensive programming techniques (G1.1A.1.2B.2A.1 – defensive programming
goal) or assertion checking (G1.1A.1.2B.2A.2).
6.1.5 Sources of Run-time Error Goals – Figures 16-7, 16-8
6.1.5.1 G.VARIABLES.1 – Variable Declaration and Initialisation
Evidence is required to support this goal that shows that variable declaration and initialisation is
explicit. C++ supports a wide range of variable declaration and initialisation expressions.
Restrictions are required if this goal is to be supported. The following rules and guidelines support
explicit variable declaration and initialisation: Rules 3.1.2, 8.2.1, 8.2.2, 8.3.3 – 8.3.5, 8.4.2 – 8.4.4,
8.4.11, 11.7, 14.17 & 15.2 and Guideline 8.1.1 – 8.1.3, 8.2.3, 8.2.4, & 8.4.13.
6.1.5.2 G.MATH.1 – Mathematical Operations and Results
Evidence is required to support this goal that shows that mathematical operations and results are
valid. [BSI03] adequately defines the C++ mathematical model. Ambiguities in operator precedence
levels are known (Appendix 8 – 14) and can be avoided. Of particular interest are the appropriate
detection and handling of divide-by-zero and other similar errors. Detection of these activities can
be achieved through appropriate design and application of defensive programming techniques
(G1.1A.1.2B.2A.1 – defensive programming goal) or assertion checking (G1.1A.1.2B.2A.2). C++
also supports linking the manual detection of such cases to the exception handling mechanism. The
following rules and guidelines also support a rigorous mathematical model: Rules 5.2, 5.3, 10.17
and Guideline 10.18.
6.1.5.3 G.PARADIGM.1 – Paradigm Related Errors
Evidence is required to support this goal that shows that C++’s mechanics of the object-oriented
paradigm does not introduce errors into the design. The following rules and guidelines provide
restrictions to eliminate paradigm related errors and also promote conformance to the OOTiA
recommendations: Rule 3.1.3 – 3.1.8, 3.1.13, 3.2.1 – 3.2.3, 3.3.1 – 3.3.3, 3.3.5 – 3.3.15, 3.4.1 –
71
3.4.6, 3.5.1 – 3.5.3, 8.3.3, 8.4.3, 8.4.11, 11.4, 11.5, 11.8, 11.9, 12.1, 16.3, 17.5, 4, 5, & 9 and
Guidelines 3.1.7, 3.1.9, 3.2.4, 3.4.7, 3.5.5, & 16.4
6.1.5.4 G.MISTAKES.1 – Unintentional Mistakes and Typos
Evidence is required to support this goal that shows that unintentional mistakes and typos are
prevented. C++ has traditionally been criticised that the lexically similar nature of many of its
constructs means that a single incorrect character can result in grammatically parsable code.
Development environments that utilise control structure diagrams (CSD) provide a graphical means
of detection many of these problems. Most C++ development environments support features such as
these. CSD is an algorithmic level diagram intended to improve the comprehensibility of source
code by clearly depicting control constructs, control paths, and the overall structure of each program
unit. CSD is particularly efficient at highlighting incorrect use of blocks and brackets and braces. It
also colour-codes keywords, variables, and literals to allow the programmer to visually detect
programming errors as they type. Coding style can also be used to prevent such errors. The
following rules and guidelines support the detection of unintentional mistakes and typos: Rules 6.1,
6.2, 10.5 – 10.6, 10.21, 14.5, 14.12 – 14.15, 14.17 – 14.18, 17.13 – 17.15, 17.17, 1, & 26 and
Guidelines 14.7, 17.21, 21, 23.
6.1.5.5 G.SIDE_EFFECT.1 – Side Effects in Expression
Evidence is required to support this goal that shows that side effects in expressions are intended.
Appendix 8 – 14 identifies side effects in expression for which [BSI03] is ambiguous. These are
known and can be avoided. The following rules and guidelines support the elimination of side
effects in expression: Rule 3.1.6, 3.5.1, 10.3 – 10.6, 10.8 – 10.10, 16.2, & 17.17 and Guideline 10.7.
6.1.5.6 G.JUMPS.1 – Modular and Structured Approach / Jump Restrictions
Evidence is required to support this goal that shows that C++ is modular and structured, and that
jumps between scopes are restricted. C++ supports functions, objects, separate compilation and
defines scoping properties associated with each of these structures to promote modularity. Although
C++ supports numerous unrestricted scope jumping mechanisms, the following rules place
restrictions on jumps between scopes and also promote the correct use of modularity: Rule 5.1, 5.4
– 5.6, 5.8, 5.9, 5.11, 5.12, 11.2.
6.1.5.7 G.MEMORY.1 – Memory Leaks
Evidence is required to support this goal that shows that opportunities for memory leaks in C++ are
restricted. The manual dynamic allocation/deallocation features of C++ make the language prone to
memory leaks. The following rules and guidelines place restrictions of memory and resource
activities to prevent memory leaks: Rules 3.1.3, 3.1.5, 3.2.5, 12.2 – 12.8, 17.9, 15, 17 & 25 and
Guidelines 9.5, 9.6, 16, & 22.
6.1.6 Avoiding, Mitigating, Detecting and Handling Goals – Figure 16-4
6.1.6.1 G1.1A.1.2B.2A.1 – Defensive Programming
Evidence is required to support this goal that shows that C++ supports defensive programming
techniques. C++ provides support for many common defensive programming techniques. These
may be dealt with through traditional conditional statements, or through linkage to the C++
exception handling mechanism. Preference would be for the latter. Rule 10.17 and Guideline 10.18
also support defensive programming. Local coding standards and design practices should promote
defensive programming techniques.
72
6.1.6.2 G1.1A.1.2B.2A.2 – Assertions
Evidence is required to support this goal that shows that C++ supports the use of assertions. C++
permits various forms of assertion checking. Assertions can be hard coded into the actual software
and coupled with the run-time exception mechanism. Alternatively the <cassert> library provides
the assert macro. There are some limitations to using the assert macro and these are addressed by
the Rule 10.17.
6.1.6.3 G1.1A.1.2B.2B.1 – Design Patterns
[Gam95] presents designs patterns for object oriented software. Many of these patterns are
presented in C++. Reference to the existence of these patterns and their use as part of the system
design would be suitable to support this goal. It is important to highlight that the patterns have not
been verified with respect to the safer C++ subset and would require some validation work. There is
scope for a catalogue of safer C++ subset validated design patterns to be created.
6.1.6.4 G1.1A.1.2B.2B.2 – Code Reuse
Evidence is required to support this goal that shows that C++ supports the reuse of existing code.
C++ promotes code reuse through its mechanisms for separate compilation, standard library,
templates, objects, inheritance, and linkages with other languages to name a few. Rule 17.2
emphasises that the C++ standard libraries should be used in preference to hand coded versions
where possible.
6.1.6.5 G1.1A.1.2B.3 – Exception Detection and Handling
Evidence is required to support this goal that shows that C++ has an exception detection and
handling mechanism. C++ provides an exception handling system whereby exceptions are thrown
by type and not value. The following rules and guidelines places restrictions on the exception
handling system to make it robust: Rules 9.1 – 9.3, 11 – 13 and Guidelines 9.4 – 9.6,
6.1.7 Static Analysis Goals – Figure 16-10
6.1.7.1 G1.1A.2A.1A.1 – Dynamic Variables
C++ supports the use of both static and dynamic variables and objects. It is up to a design to restrict
the use of dynamic variables to those areas of the software where they are necessary. In situations
where they are used the limits of static analysis are to be specifically noted and the deficiency
deliberately addressed through dynamic testing.
6.1.7.2 G1.1A.2A.1A.2 – Interrupts
C++ support the use of interrupts. It is up to a design to restrict the use of interrupts to those areas
of the software design where they are necessary. In situations where they are used the limits of
static analysis are to be specifically noted and the deficiency deliberately addressed through
dynamic testing.
6.1.7.3 G1.1A.2A.1A.3 – Recursion
C++ supports recursion. It is up to a design to restrict the use of interrupts to those areas of the
software design where they are necessary. In situations where they are used the limits of static
analysis are to be specifically noted and the deficiency deliberately addressed through dynamic
testing. Rule 6 and Guideline 6.6 restrict the use of recursion to allow this goal to be satisfied.
6.1.7.4 G1.1A.2A.1B.1 – Resource Usage Behaviour
Evidence is required to support this goal that shows that aspects of C++ resource usage behaviour
are statically analysable. The use of dynamic objects in C++ makes this difficult to carry out for
73
those portions of the design. QA C++ and MALPAS static analysis can be used to infer some
properties about C++ resource usage. The deficiencies in meeting this goal shall be addressed
through the dynamic resource usage behaviour goal (G1.1A.2A.2A.2).
6.1.7.5 G1.1A.2A.1B.2 – Temporal Behaviour
Evidence is required to support this goal that shows that aspects of C++ temporal behaviour are
statically analysable. QA C++ and MALPAS static analysis can be used to infer some properties
about C++ timing behaviour. The deficiencies in meeting this goal shall be addressed through the
dynamic timing behaviour goal (G1.1A.2A.2A.1).
6.1.7.6 G1.1A.2A.1B.3.1 – Control, Data and Information Flow
Evidence is required to support this goal that shows that aspects of C++’s function behaviour are
analysable through control, data and information flow analysis. MALPAS is capable of providing
static control, data and information flow analysis. The value tracking features of PC-Lint also
provide some limited capability in support of this goal.
6.1.7.7 G1.1A.2A.1B.3.2 – Assertions / Annotations
Evidence is required to support this goal that shows that aspects of C++’s function behaviour are
analysable through static assertion and annotation checking. Although not specifically a C++ tool,
MALPAS can be used to check pre-conditions, post-conditions and function invariants against the
interface definitions.
6.1.7.8 G1.1A.2A.1B.3.3 – Formal Code Verification
Evidence is required to support this goal that shows that aspects of C++’s function behaviour are
analysable through formal code verification. Although not specifically a C++ tool, MALPAS can be
used to provide formal code verification. Alternatively, generic object oriented mapping can be
used to permit the manual application of formal methods to C++ code.
6.1.7.9 G1.1A.2A.1B.3.4 – Symbolic Execution
Evidence is required to support this goal that shows that aspects of C++’s functional behaviour are
analysable through symbolic execution. Most C++ development environments provide a host a
debugging tools that are capable of symbolic execution of C++ source code. One of C++’s strengths
is the availability of debugging tools. These tools are dependent on the platform and environment.
6.1.7.10 G1.1A.2A.1C - Standards
IEC 61508, Defence Standard 00-55 and RTCA/DO-178B all specify requirements for static
analysis. Those standards that are applicable to the given project shall be identified. MALPAS is
recognised as providing the full range of static analysis techniques mandated in Defence Standard
00-55, IEC 61508 and RTCA/DO-178B. QA C++ has not been officially validated to Defence
Standard 00-55 [Coo04]. PC-Lint / FlexeLint has not been associated with these types of standards
to date.
6.1.8 Dynamic Testing Goals – Figure 16-11
6.1.8.1 G1.1A.2A.2A.1, G1.1A.2A.2A.2, and G1.1A.2A.2A.3 – Temporal / Resource /Functional
Tools such as Cantata++ can be used to dynamically test the temporal, run-time resource and
functional behaviour of programs developed in C++. Many other tools also exist to support such
testing activities in C++, although they have not been specifically identified or examined in this
74
project. It is believed that Cantata++ is capable of addressing the deficiencies in static resource
usage and timing behaviours analysis.
6.1.8.2 G1.1A.2A.2B - Standards
[IPL03] states that “Cantata++ can be used to enable a software development to meet many of the
verification and testing requirements of IEC 61508.” The safety critical development standards used
also included consideration of those used for the European Fighter Aircraft, and Defence Standards
00-55 and 00-56.
6.1.9 Error Prevention Feature Goals – Figure 16-3
6.1.9.1 G1.1A.2B.1 – Complexity
Evidence is required to support this goal that unnecessarily complex portions of code are identified.
QA C++ and Cantata++ provide a means of assessing C++ code complexity through the reporting
of various software code metrics. Rules 4.1 – 4.3 limit the complexity of the source code and thus
also support this goal.
6.1.9.2 G1.1A.2B.2 – Abstraction and Information Hiding
Evidence is required to support this goal that C++ supports abstraction and information hiding
features to assign with error detection. The object oriented paradigm implemented by C++ supports
abstraction and information hiding. Separate compilation of C++ translation units promotes the
detection of errors within individual translation units.
6.1.10 Implementation Features Goals – Figure 16-1
6.1.10.1 G1.1B – Interfacing to Other Languages
C++ supports interfacing to other languages, however the behaviour associated with such
functionality is implementation defined. 1.6 in [PRG03] states “the embedding of code, written in
languages other than C++, within C++ is forbidden unless accompanied by a written justification
for its use.” In addition, Guideline 18 recommends that interfaces to language other than C be
avoided anyway.
6.1.11 Maintainability Goals – Figure 16-1
6.1.11.1 G1.2.1 – User Documentation and Comments
C++ provides two notations in which comments can be embedded within the source code. Rule 14.1
prohibits the use of the C style comments. C++ style comments are wholly suitable for comments
embedded within the code and this supports the instantiation of this goal. Further evidence would be
required to show that coding and design practices support appropriate documentation of the
implementation. QA C++ provides a means of generating class hierarchy diagrams and function call
diagrams in support of this.
6.1.11.2 G1.2.2 – Coding Style Guidelines
Projects should define a set of coding style guidelines that addresses issues such as layout, naming
conventions, local environment restrictions, etc. QA C++ can be configured and using post-analysis
it is possible to apply a high degree of automatic enforcement to a company coding standard
(company-specific rules such as a naming convention). The following rules and guidelines also
work to improve readability and maintainability:. Rules 2.1, 3.1.1, 3.3.16, 8.4.1, 8.4.4, 8.4.6, 8.4.7,
10.1, 10.19 – 10.20, 11.1, 11.3, & 15.3 and Guidelines 3.1.12, 6.6, 8.3.2, 8.4.12, 14.2 – 14.4.
75
6.1.12 Development Team Expertise Goal – Figure 16-1
6.1.12.1 G2.1.1 – Development Team Expertise / Programmer Experience
This goal can only be satisfied through explicit reference to the people employed within the
development team for the project. Programmers should have a full appreciation of the safety
considerations associated with writing software in C++. One means of achieving this would to
ensure programmers are familiarised with the work presented in the entirety of this report.
Furthermore, a demonstrated appreciation of many of the texts referenced in the reference section of
this report would be useful evidence.
6.1.13 Tool Quality, Validation and Certification Goal – Figure 16-1
6.1.13.1 G3.1.1 – Tool Quality, Validation and Certification
Evidence is required to show that the tools cited in satisfying the other goals within the GSN pattern
are of a high quality, validated or certified. The following paragraphs identify those tool quality,
validation and certification issues that are known about the tools that may work towards supporting
this goal. Other tools related to context specific development environments shall also be considered
in support this goal.
• The Programming Research Group uses the Perennial Test Suit for checking the ISO C++
conformance of the QA C++ parser and the Boost library (version 1.3 for QA C++ 2.0) for
C++ parsing [Coo04]. The Programming Research Group have a coding standard in place
which is enforced with QA C++ itself [Coo04]. They believe that this puts them at Capability
Maturity Model Level 2, however they have not sought formal assessment yet. QA C++ has
not been officially validated to Defence Standard 00-55 [Coo04]. HICPP Coding Standard has
been given the tick in the box by TUV Germany [Coo04].
• Gimpel Software is not certified by any outside organisations. The following passage is
quoted directly from [Gim04] and relates to the quality of released versions of PC-Lint /
FlexeLint.
“We also employ extensive quality assurance procedures. Before we release a new version of
PC-lint, we do thorough in-house testing of the software. This includes testing both PC-lint
functionality and options. We have a standard test suite that we use in-house. We have a beta
testing period of at least six months, during which the product is tested by both current users
and new users. Finally, we have a large customer base and an active online discussion forum
to ensure a low incidence of miscellaneous errors.”
• MALPAS is widely used in the security, aerospace, defence, nuclear power and transport
industries [ATC03]. It has been applied to safety, security, mission and business critical
applications [ATC03].
• Cantata++ has been produced under IPL’s rigorous ISO9001TickIT Quality Management
System [IPL98]. “The product is itself fully tested at the unit, task, and system level” [IPL98].
[IPL03] states that “Cantata++ can be used to enable a software development to meet many of
the verification and testing requirements of IEC 61508.” [IPL03] also states that “the tools
have been produced to a high standard, such that their use for dynamic testing will not
compromise the safety and integrity of the software being tested.” According to [IPL03],
Cantata++ is in widespread use. Formal methods were not used in the specification of
Cantata++ [IPL03]. The safety critical development standards used included consideration of
those used for the European Fighter Aircraft, and Defence Standards 00-55 and 00-56.
76
6.1.14 Summary of Evaluation Findings
The evaluation has shown that it is possible to provide reasonable evidence in support of the
justification of programming language selection for C++. The safer C++ subset is critical to the
activity as are a number of these tools (QA C++, MALPAS, Cantata++). PC-Lint was less essential
to the process, but should probably be considered a useful diverse check to QA C++.
There were a number of rules and guidelines that didn’t directly support the goals in the pattern.
These goals related to improving efficiency and thus are not required to support safer C++
development. The rule and guidelines supporting efficiency are Rules 11.5, 11.8, 17.6, &17.19 and
Guidelines 5.7, 17.3 – 17.4, 17.10, & 17.18. Thus it is possible to assume that the justification of
programming language selection pattern is sufficient within the scope of the kind of attributes
required to make C++ safer.
There were not any specific goals that could not be supported. There were weaknesses in the
availability of C++ specific tools for supporting static analysis (particularly resource and timing
analysis). MALPAS does not yet have a C++ translator for it and as such the static analysis is going
to be a large task. QA C++ is in the early days of providing formal code verification features.
However these deficiencies could be addressed through appropriate dynamic testing using
Cantata++. Exposure of QA C++ and PC-Lint to some of the standards covered in this thesis has
been limited to date.
Because there was no specific design context against which to carry out this evaluation, a number of
goals still required further investigation into their instantiation. Section 6.3 outlines approaches as
to how such evaluations might be conducted.
6.2 Evaluation of Safer C++ Subset Against Safe Language Criteria
This section examines the safer C++ subset defined by the HICPP coding standard and the
additional rules defined in Section 4.2. For comparison purposes, each mandatory criteria has been
rated using the specific rating definitions presented in [Kwo03]. The ratings in [Kwo03] are on a
scale of Rating 1 (best, safest) to Rating 3 (poorest). Subsections are annotated with an (M) or (D)
to represent mandatory and desirable requirements. Desirable criteria were not numerically rated in
[Kwo03] and as such they shall not be rated here either. Much of the information presented here is a
reflection of the information presented in the previous section. The duplication of information is
worthwhile as it serves as confirmation of the relationship between the safe language criteria and
the GSN pattern developed in Section 5.
6.2.1 Syntactical / Semantic Requirements (M)
6.2.1.1 Type Safety / Strong Typing Rules
C++ is a relatively, strongly typed language. However the flexibility of some features actually work
against type safety. Implicit conversions are not allowed for Plain Old Data (POD) (ie. primitive)
types. However, C++ permits implicit conversions between objects of class type. There is also
potential for a less experienced programmer to inadvertently enact these implicit conversions. The
use of the HICPP coding standard places restrictions to prevent implicit type conversions occurring.
C++ provides a number of explicit type conversion mechanisms that are defined in the C++
standard. The use of the HICPP coding standard places restrictions on the use of these conversions
to improve type safety.
C++ arrays lack array bounds checking and enforcement. Overloading operator[] with index range
checking improves the safety of arrays. Making classes of scalers and overloading the assignment
operator allows additional range and value checking. The use of vector and deque rather than the
77
base language array primitive helps to enforce array bounds checking. However there is some doubt
as to whether certain implementations of these types are statically analysable. Many of the container
types defined in the STL perform their own dynamic allocation and deallocation and this may also
prevent them being statically analysed.
C++ provides both pointer and reference access types. The programmer is not forced to use such
types. However, much of the STL and many of the most useful features of objects and classes
utilise these access types. These types present challenges to the static analysis of software. Software
designers and programmers should limit the use of these types to those aspects of the design where
their use is necessary and justifiable.
C++ supports multiple inheritance and conversions up and down the inheritance hierarchy. The use
of the HICPP coding standard places restrictions to prevent type slicing and other inheritance
related problems occurring.
Rating: 2. Strongly typed, but some types are analysable only at run-time.
The development of a design that avoids aspects of the types that are analysable only at run-time
could be given Rating: 1. Strongly typed, statically analysable.
6.2.1.2 Side Effects In Expressions / Operator Precedence Levels / Initial Values
Side effects in expression can occur with numerous C++ language features. The C++ standard
explicitly annotates if such side effects are defined or at the discretion of the compiler
implementors. The operator precedence levels are also defined in the C++ standard, but they are not
always intuitive to the programmer. C++ provides means of default initialising certain types and
also implicitly initialises certain types. The use of the HICPP coding standard and the additional
rules defined in Section 4.2 places restrictions on these aspects of the language and ensures that the
code is not impacted due to unfounded assumptions about expression side effects, operator
precedence levels and initial values.
Rating: 1. All of the specifics are satisfied.
6.2.1.3 Modularity / Structures
In C++, programs can be organised as objects that consists of data and the functions that operate on
that data. Such language features promote modularity and structured programming. Abstract classes
can be used to define semantically clear interfaces and provide relative separation of interface from
implementation. The correct use of classes to facilitate abstraction and encapsulation also promotes
modular and structured programming. Access to members (data and functions) can be controlled
with the use of access specifiers (public, protected and private). Separate compilation is also
possible.
Blocks and scopes are well defined by the C++ standard. However, C++ does provide some
mechanisms that allow wild or unbounded jumps between scopes. The use of the HICPP coding
standard and the additional rules defined in Section 4.2 places restrictions on these aspects of the
language. C++ also provides numerous language features for controlling the program flow,
including standard conditional control structures (eg. if, else, while, & switch) and an exception
handling mechanism.
Rating: 1. The language provides rich and precise means of structuring programs, and programs can
be maintained in terms of modules and objects.
78
6.2.1.4 Formal Semantics / International Standards
C++ was ANSI / ISO Standardised in 1998 [BSI03]. The standard formally defines the semantics of
the language. It also defines those parts of the language that are unspecified, undefined,
implementation-defined, and indeterminate. The use of the HICPP coding standard and the new
rules proposed in Section 4.2 control the unspecified, undefined, implementation-defined, and
indeterminate behaviours.
Rating: 1. An internationally standardised formal definition exists.
6.2.1.5 Well Understood
Section 2.1.5 identified the wide availability of published textbooks relating to the development of
software in C++. Specifically a number of textbooks were identified that identify C++ best practice,
problems and solutions. These books are widely referenced by the C++ community. There is
substantial agreement on problems and solutions between these texts and this supports the notion
that C++ is well understood.
C++ is widely taught in educational institutions. C++ is also widely used in numerous commercial
and industrial sectors. C++ has seen some use in the military domain also.
While only a number of tools have been considered throughout this project, a large number of
development and support tools are available for many aspects of C++ development. There are some
deficiencies in the availability of formal proof tools for C++.
Rating: 1. The language is well understood, and there are many trained developers and designers.
6.2.1.6 Support For Domain Specific or Embedded Applications
In Section 2.1, C++ was described as a middle level language as it combines the best aspects of
high level languages, while still allowing the programmer the control and flexibility of assembly
language. For this reason, C++ has been widely used as a systems programming language. Thus the
language naturally supports embedded applications. Many hardware manufacturers provide C or
C++ interface libraries with their processors and development packages. C++ programs can be
linked seamlessly with C modules where required. A number of modelling packages can also
automatically generate C++ code from high-level mathematical models for compilation on an
embedded system.
C++ provides a large number of language constructs and features that permit the language to be
successfully applied to a broad range of applications. Care must be taken to ensure the correct
language features are applied to the solution as it is possible to produce a poor (and potentially
unsafe) program if language features are used out of context.
Rating: 1. The language naturally supports embedded applications.
6.2.1.7 Concurreny / Parallel Processing
The C++ standard (base language and STL) does not define any high level concurrency or multi-
threaded features. C++ does provide an exception handling mechanism, however this still exists
within a single thread of execution. Some of the low level features of C++ allows access to
interrupts and thus the programmer is free to develop their own concurrency support. In addition
numerous commercial libraries are available that provide support for concurrency. However these
are unlikely to have been validated with respect to any particular safety criteria.
Rating: 2. Only limited support is provided at the language-level, but external libraries or run-time
systems can be utilised.
79
6.2.2 Application of Verification Techniques / Predicability (M)
6.2.2.1 Functional Predicability
Numerous tools are available for C++ that support control, data, and information flow analysis. For
example QA C++ and PC-Lint / FlexeLint both provide some support for these techniques. C++
debugging tools that support symbolic execution are also widely available with most development
environments. Some tools, such as MALPAS, are available that support formal code verification,
however direct input of C++ code into such tools is not yet supported. For example MALPAS does
not presently provide an automatic translation mechanism for translating C++ into the MALPAS
intermediate language. This does not prevent manual translation of C++ code into the MALPAS
intermediate language, though this will be time consuming.
Rating: 1. All techniques specified or feasible alternatives can be utilised.
6.2.2.2 Temporal Predicability / Timing Analysis
It is possible to determine tightly bounded execution times for C++ code. C++ was developed to
allow highly efficient execution of C++ code with minimal run-time overheads. C++’s single
threaded execution and manual memory management features avoids problems associated with
determining execution times for multi-threaded applications and garbage collectors. While the
implementation of many of the features of the STL are not presented to the user, it is possible to
establish accurate worst case execution times for these functions.
Rating: 1. Tightly bounded execution times can be obtained.
6.2.2.3 Resource Usage Analysis
C++ supports both stack (global, local, static / non-static) and heap based allocation of memory.
There are some ambiguities associated with static allocation across translation units in C++.
However the use of the HICPP coding standard and the additional rules defined in Section 4.2
places restrictions to prevent such situations. Thus finite resource usage analysis is possible for C++
stack based memory allocation.
Dynamic memory allocation is traditionally difficult to analyse. However through the use of the
HICPP coding standard and the additional rules defined in Section 4.2 controls and safeguards can
be placed on the dynamic allocation and deallocation of memory such that out of memory or low
resource situations can be dealt with safely. Numerous tools are also available to help analyse and
test dynamic memory allocation in C++.
Rating: 1. Exact predicability of the specifics is possible.
6.2.3 Language Processors / Run-Time Environment Tools (M)
6.2.3.1 Certified Language Translators / Run-Time Environments
Numerous software bodies offer compiler certification services for C++ compilers. Compilers that
are certified against the C++ standard are becoming more widely available. However many
commonly available compilers also support their own customisations to the C++ standard.
Compilers developed prior to C++ standardisation often contain varying interpretations of C++
language and STL features. These should not be used. In addition there is much scope still for C++
compilers to be formally verified. The wide use of C++ compilers helps to provide confidence from
use. Intelligently applied dynamic testing can work to provide confidence that bugs are not
introduced by the compiler.
80
Many C++ development environments and tools are widely available. They are also widely used
and thus it is possible to argue increased confidence from use.
Rating: 2. Language translators may contain several known errors or malfunctions that are well
documented, but they will not affect the development of high integrity software.
6.2.3.2 Run-Time Support / Environment Issues
In the interest of execution efficiency, C++ only provides a minimal run-time overhead. Thus the
impact on functional and timing analysis is minimal. The functionality of the STL is defined by the
C++ standard. While the implementation of many of the features of the STL are not presented to the
user, it is possible to establish accurate execution times for these functions through testing.
Rating: 1. There is concrete information on the functional and temporal behaviours of all libraries
and run-time system.
6.2.4 Syntactical / Semantic Requirements (D)
6.2.4.1 Exception Handling / Failure Behaviour
C++ provides a built-in exception handling mechanism. C++ extends the exception handling
capabilities beyond that of other languages as C++ exceptions are handled by type rather than value.
Thus it is possible to create hierarchies of exception classes and catch the exception by thrown
subclass type. Uncaught exceptions can become problematic as they may result in the program
terminating. The HICPP coding standard and additional rules defined in Section 4.2 place
restrictions on the use of exceptions and exception class design in order to promote predictable
exception and failure behaviour.
6.2.4.2 Model of Mathematics
C++ provides a well defined set of integer and floating point data types. The use of the HICPP
coding standard and the additional rules defined in Section 4.2 ensures the type safety of these data
types. They also promote the correct use of mathematical operations associated with these types.
In addition the STL also provides more complex mathematical structures and operations including
complex numbers through its numerics libraries. While there are numerous unspecified, undefined
and implementation-defined behaviours associated with some of these types, they can be controlled
through the use of the HICPP coding standard and the additional rules defined in Section 4.2.
6.2.4.3 Support for User Documentation
C++ supports both C and C++ style comments. The C style comments are banned in HICPP, but the
C++ comments are ample for fully documenting the source code. In addition, some C++ tools, such
as PC-Lint / FlexeLint, use commands embedded within C++ style comments to control the tool’s
analysis of the source code.
6.2.4.4 Support For A Range Of Static Types Including Subtypes and Enumeration Types
C++ supports enumeration types. Subtypes of POD types can be emulated with additional overhead.
Subtyping of class types is supported in C++ through inheritance. The use of the HICPP coding
standard and the additional rules defined in Section 4.2 ensures the safety of these data types.
6.2.4.5 Coding Style Guidelines
The HICPP coding standard and the additional rules defined in Section 4.2 not only subset the C++
language, they also offer rules and guidelines relating to producing documented, readable and
81
maintainable code. In addition, further guidance on producing readable and maintainable code is
presented is several of the texts examined in Section 2.1.5.
6.2.4.6 Support For Abstraction and Information Hiding
C++’s implementation of the object-oriented paradigm supports abstraction through templates,
inheritance, and abstract classes (with virtual members). C++ also provides access specifiers
(public, protected and private) to allow information hiding within objects.
6.2.4.7 Assertion Checking
C++ permits various forms of assertion checking. Assertions can be hard coded into the actual
software and coupled with the run-time exception mechanism. Alternatively the <cassert> library
provides the assert macro. There are some limitations to using the assert macro and these are
addressed by the HICPP coding standard.
Although not specifically a C++ tool, MALPAS can be used to check pre-conditions, post-
conditions and function invariants against the interface definitions.
6.2.5 Language Processors / Run-Time Environment Tools (D)
6.2.5.1 Certified (Static/Dynamic) Analysis Tools
A large number of analysis tools have been developed to assist in debugging and analysing C++
programs. However, most of them are not certified by reliable bodies or standards. A number of
standards also permit the use of tools where increased confidence from previous use has been
established. Section 6.1.13 examined the quality of QA C++, PC-Lint / FlexeLint, Cantata++ and
MALPAS.
6.2.5.2 Interface To Other Languages
C++ provides many features for interfacing to other programming languages. However many of
these features are specific to the platform or implementation. The HICPP coding standard and the
additional rules defined in Section 4.2 place restrictions on the use of interfacing C++ code to other
languages to limit the external language interface mechanics that are unspecified or
implementation-defined. This results in recommending avoiding linkage to languages other than C.
6.2.5.3 Code Optimisation
Many C++ compilers apply optimisation techniques to the code they are translating. In many cases
the C++ standard leaves the creation of temporary objects and optimisations to the compiler
implementors. It is complex to statically analyse optimised machine code in relation to high level
source code. Some compilers provide means of turning off the optimisations. However even with
optimisations turned off a small number of optimisations will still be applied during compilation.
Optimisation makes the compiler and tool validation complex and difficult.
6.2.5.4 Code Portability
The C++ programming language is designed to be a portable language. However, an inspection of
the C++ standard [BSI03] reveals a large number of unspecified or implementation-defined
behaviours. Appendixes 8 to 14 list in detail these behaviours. The HICPP coding standard and the
additional rules defined in Section 4.2 place sufficient restrictions on these behaviours to ensure
portability.
82
6.2.6 Summary and Comparison with Other Languages
Within the mandatory criteria the safer C++ subset was assessed to be of the best rating (Rating 1)
for all except for three criteria that received Rating 2. The first two relate to type safety and to
concurrency. These two criteria can be controlled through the system design and can thus
conceptually achieve a Rating 1 for specific designs. The third criteria relates to certified language
translators. Compilers that are certified against the C++ standard are becoming more widely
available. In addition, C++ compilers are generally no less certified than the bulk of other language
translators available.
C++ was also assessed favourably across the desirable criteria. While some weaknesses were
identified, there are practical means of avoiding or preventing them.
C++ rated substantially better as a safe language than did Java as evaluated by [Kwo03]. A
worthwhile activity would be to also evaluate Ada and SPARK using the same system. Thus it
would be possible to establish a common baseline comparison of programming languages for high
integrity systems. The evaluation may also be applied to numerous other language subsets.
6.3 Proposal for Evaluating the GSN Argument
Section 5.1 described the development of a pattern for arguing the selection of a programming
language for a safety critical system. The pattern is presented in Appendix 16. Section 6.3.1 details
a proposal for evaluating the correctness and applicability of the pattern.
Section 6.1 described the evaluation of the pattern developed in Section 5.1 for the C++
programming language. Section 6.3.2 details a proposal for evaluating the finding of Section 6.1 as
it is applied to a project.
Both evaluations are presented as proposals since there was insufficient time during the project to
actually carry out the evaluations. This should not detract from their importance in establishing C++
as a safety critical programming language. Both of the proposals should be considered a high
priority in future work.
6.3.1 Proposal for Evaluating the Pattern Against Existing Software Safety Cases
A number of existing software safety cases should be assembled along with their relevant design
documentation. Ideally safety cases should be selected such that a cross section of commonly used
programming languages are subject to the evaluation. For example a set of projects developed in
Ada, SPARK, and C would be a suitable cross section. It is unlikely at this time that there are many
safety cases available for systems involving the use of C++. However if such safety cases can be
obtained, then their inclusion should be mandatory.
The essence of the evaluation is to attempt to instantiate the pattern from the evidence already
available in an existing software safety case and associated design documentation. This provides the
opportunity to examine the following questions:
• Has the existing safety case appropriately justified the programming language selection, even
if they haven’t specifically argued it?
• Are there deficiencies in the existing safety case where this pattern suggests that additional
evidence should be assembled? Furthermore does this pattern help to identify where the
language selection for an existing system is inappropriate or unjustifiable?
83
• Is there evidence and goals suggested by the existing safety case that are not covered by the
pattern? What are they, should they be included in the pattern, and how could the pattern be
reworked to include them?
• Are there issues that might prevent this pattern being instantiated that may require the pattern
to be reworked? In particular what aspects of the pattern are not lending themselves to
instantiation? How might the pattern be reworked? How could the reworked pattern be
validated?
• Are there techniques and tools not used in justifying the language selection that that would
have improved the justification?
• Are there techniques and tools used in justifying the language selection that are not
compatible with the pattern in its present form?
There is a substantial amount of work involved in conducting this evaluation.
6.3.2 Proposal for Evaluating the Pattern on C++ Projects
A series of real world engineering projects shall be identified where the C++ programming
language suits the domain and application. The projects shall also be safety critical. The risks
presented by conducting the evaluation first time around on a very high risk project are probably
significant. Discussions with industry have revealed that some companies have begun developing
software in C++ for safety critical projects with a low inherent risk. Thus an ideal starting point for
this evaluation would be on a project of similarly low risk. Subsequent to establishing confidence at
this level of criticality, then the same evaluation should be applied iteratively to a future series of
projects with a goal of gradually increasing safety criticality. The goal is to eventually evaluate one
or more projects of substantial safety criticality.
The software shall be developed using the language subset, tools, techniques and processes
described by the evaluation presented in Section 6.1. Applicable safety standards shall be defined
for the project, but at the very least these should include a subset of IEC61508, DO178B, Defence
Standard 00-55 Issue 2 and Defence Standard 00-56 Issues 3.
The essence of the evaluation is to attempt to fully instantiate the pattern throughout development
of the safety case for the project. This provides the opportunity to examine the following questions:
• Can the use of C++ be justified for the project? Can this justification be successfully argued
using a full instantiation of the partially instantiated pattern? What additional evidence is
required to fully instantiate the argument?
• Are deficiencies emerging in the project where the instantiation of this pattern suggests that
additional evidence should be assembled? Furthermore does this partial instantiation help to
identify where the C++ language selection is inappropriate or unjustifiable?
• Are there issues that might prevent the argument being fully instantiated that may require the
underlying pattern to be reworked? In particular what aspects of the argument are not lending
themselves to instantiation? How might the instantiation and pattern be reworked? How could
the reworked instantiation and pattern be validated?
• Was the enforcement of the HICPP coding standard and the additional rules and guidelines
presented in Section 4.2 practical in the context of the project? Was the level of auto-
enforcement sufficient?
84
• How well did the design translate into C++ and were methods or techniques identified that
assisted with the translation of design into source code? Was there scope for validated design
patterns to improve the safety of the design in the context of the application and domain?
• Are there techniques and tools presented in the partial instantiation of the pattern that were not
compatible with the project?
• Are there techniques and tools used in justifying the language selection that have not been
instantiated in the partial instantiation so far? What are they?
• Does the tool set and techniques suggested by the partial instantiation make development in
C++ feasible, economical and safe?
It will be too late if answers to these questions are not sought until the conclusion of the project.
Thus, throughout each of the project milestones (conceptual, preliminary, critical design reviews,
etc.) an assessment shall be carried out to assess if the desired safety is actually being achieved.
This may be in the form of a risk assessment (risk being a function of severity and likelihood), a
hazard analysis, or other acceptable study, but should be compatible with the nature of the project.
The aim of such an assessment is to ensure problems are identified early while there still may be
time and resources to address the problem. In some cases the outcome may be that more tools or
checks are required with respect to the C++ language. Alternatively, a problem may be identified
that requires a different language to C++ to be used.
There is a substantial amount of work involved in conducting this evaluation. Such an evaluation
would require a close relationship with a number of industry projects and may present some level of
workload burden on these projects.
85
7 Conclusions and Further Work
The aim of this project was to examine the use of the C++ programming language in the context of
safety critical systems. This project endeavoured to examine justifiable evidence relating to the use
of C++ in safety critical systems. This project has specifically sought answers to the following
questions.
• Can the C++ programming language be used for the development of safety critical systems?
• If the C++ programming language as a whole is not suitable for safety critical systems, then
can constraints and restrictions be placed on the language (ie. language sub-setting) to permit
its use? What would these constraints and restrictions be? Can they be appropriately defined?
Are they sufficient?
• What tools are currently available to support the development of safety critical software using
the C++ programming language? Do the tools support verification of the software’s safety?
• What do the applicable safety standards say and could C++ be justified within the context of
these standards? How could justification be achieved?
7.1 Findings and Traceability to the Project’s Aims
This section presents the projects findings in relation to the project’s aims. Each of the aims is listed
along with the relevant findings.
Can the C++ programming language be used for the development of safety critical systems?
Section 3 has identified behaviours and problems in C++ that make the unconstrained use of the
language unsuitable for use in safety critical systems. However, there are few languages that can be
used un-constrained in the safety critical domain, and thus there was cause to consider subsets of
the C++ programming language.
If the C++ programming language as a whole is not suitable for safety critical systems, then can
constraints and restrictions be placed on the language (ie. language sub-setting) to permit its use?
Because Section 3 has identified behaviours and problems in C++, it is possible to reason that these
behaviours and problems can be controlled. Section 4 conducted a complete assessment of all
known behaviours and problems with respect to their constrainability. In doing this Section 4
identifies that it is important to match the programming language to the design, domain and
application. Of particular note, object-oriented design patterns have been identified as one means of
addressing such an issue.
What would these constraints and restrictions be? Can they be appropriately defined? Are they
sufficient?
Section 3 identifies the High Integrity C++ (HICPP) Coding Standard as a suitable starting point
for defining these constraints and restrictions, and thus developing a safer C++ subset. Section 4
has evaluated HICPP against a comprehensive set of C++ behaviours and problems to determine
the extent of its coverage. Deficiencies have been identified and new rules developed to address
them. The enforcement of the safer C++ subset (HICPP and additionally defined rules and
guidelines) has also been examined and the subset is believed to be largely enforceable. There is
still some scope for QA C++ to provide improved enforcement of numerous rules and guidelines,
particularly those that are STL related.
86
What tools are currently available to support the development of safety critical software using the
C++ programming language?
There are many C++ tools on the market today. To allow completion of the project within allocated
timeframe, the number of tools considered was restricted. Section 4 has identified QA C++, PC-Lint
/ FlexeLint, Cantata++ and MALPAS as tools suitable to support safety critical software
development using the C++ programming language. It is important to note that the certifiability of
these tools was only briefly examined and that future work is needed to ascertain this.
The project has also identified a few areas where improved tool support would better facilitate
safety critical software development in C++. Within the set of tools considered for this project,
there were weaknesses in the availability of C++ specific tools for supporting static analysis
(particularly resource and timing analysis). MALPAS does not yet have a C++ translator for it and
as such the static analysis is going to be large task. QA C++ is in the early days of providing formal
code verification features. However these deficiencies could be addressed through appropriate
dynamic testing using Cantata++. Exposure of QA C++ and PC-Lint to some of the standards
covered in this thesis has been limited to date.
Do the tools support verification of the software’s safety?
Section 5 has proposed a safety argument that could be used to argue the selection of programming
language for safety critical systems. A significant component of this argument has been to argue
that the language and tools supporting the language support the top-level claim. Successful support
of the top-level claim can be interpreted as an indication that the tools support verification of the
software’s safety.
What do the applicable safety standards say and could C++ be justified within the context of these
standards?
The programming language criteria have been identified in Section 2.3 of this report. The main
point to be derived from the criteria is that the language selection needs to be justified within the
context of the safety critical system to which it is being employed. In addition, any prescriptive
elements of these standards with regards to language selection have been incorporated into a means
of justifying programming language selection (Section 5.1). The pattern has also been kept flexible
to permit justification of language criteria under other standards.
How could justification be achieved?
Section 5 has proposed a safety argument that could be used to argue the selection of programming
language for safety critical systems. The underlying argument has been constructed based on the
information contained in these standards, as well as other identified criteria associated with safe
language selection.
Section 6 has shown that it is possible to provide reasonable evidence in support of the justification
of programming language selection for C++. The safer C++ subset is critical to the activity as are a
number of these tools (QA C++, MALPAS, Cantata++). PC-Lint was less essential to the process,
but should probably be considered a useful diverse check to QA C++. Thus it is possible to assume
that the justification of programming language selection pattern is sufficient within the scope of the
kind of attributes required to make C++ safer.
In addition to the project’s aims, this project has also identified the most pertinent concerns in
relation to the use of the C++ programming language for safety critical systems (Section 2.6.2). In
seeking answers to the questions posed by this project, it is also believed that many of the
87
perceptions and opinions have been addressed through the evaluation of the safer C++ subset
against the language criteria conducted in Section 6.2
This project has concluded that it is possible to use C++ to write software for use in high integrity
and safety critical applications. This may be achieved though the use of the safer C++ subset
(HICPP and additional rules) and a number of software tools for enforcement, static analysis and
dynamic testing. In conjunction, some degree of manual code reviews and design inspection are
also required. The project has also identified a few areas where improved tool support would better
facilitate safety critical software development in C++.
7.2 Further Work
While this project has shown that C++ can indeed be used for safety critical systems, it is immature
in the safety domain at this time. A number of activities are required in order to develop safety
maturity for C++ and these are as follows.
• C++ needs some further exposure to the safety critical environment at higher levels of
integrity.
• Further development is needed with respect to the auto-enforcement of the safer C++ subset.
(HICPP coding standard and additional rules defined in Section 4.2). The current rules and
guidelines are largely enforceable, but there are some significant deficiencies also. There is
also scope for different means of enforcement to be developed to assist with enforcing more
ambiguous rules.
• C++ tools should be identified or developed to address the identified tool deficiencies. This is
particularly important for some of the static analysis deficiencies.
• This project only examined the use of PC-Lint / Flexi-Lint for those areas where QA C++ was
identified not to provide full coverage. Thus a useful activity would be to conduct an audit of
PC-Lint / FlexeLint’s detection capabilities against all the items identified in this project.
Such an audit would provide a good indication on which areas PC-Lint can provide diverse
detection of problems.
• There is scope for existing object-oriented design patterns, and specifically those with
documented C++ implementations, to be validated with respect to the safer C++ subset. This
may be one means of providing developers with the right building blocks in which to
correctly implement a design.
• The justification of programming selection argument requires further evaluation. Two means
of performing this have been proposed in Section 6.3.
• Other languages, such as Ada and SPARK, should be evaluated against the safe language
criteria to establish a common baseline comparison of programming languages for high
integrity systems.
• The argument structures should be widely circulated to both the C++ and safety communities.
This will enable the work to be scrutinised and criticised such that an indication of the
industry’s acceptance can be gained.
88
References
[ATC03] Advantange Technical Consulting, “MALPAS – Advanced Software Analysis and
Verification – Introductory Guide”, Surrey: Advantage Technical Consulting, 2003.
[Bar02] J. Barnes, B. Dobbing and R. Chapman, “On the Principled Design of Object Oriented
Programming Languages for High Integrity Systems”, Praxis Critical Systems Limited,
presented at the 2nd NASA/FAA Object Oriented Technology in Aviation Workshop,
2002.
[Bar03] J. Barnes, “High Integrity Software: The SPARK Approach to Safety and Security”,
Great Britain: Addison-Wesley, 2003.
[BSI03] British Standards Institute, “The C++ Standard: Incorporating Technical Corrigendum
1”, England: John Wiley & Sons, 2003.
[CAS04] Department of Computer Science, “CAS: Computers and Software & ISA”, Lecture
Notes, University of York, 2004.
[Cha04] R. Chapman, “MISRA C at SIL4? Perspectives and Alternatives”, Praxis Critical
Systems Limited, United Kingdom, March 2004.
[Coo04] Email: T. Coomber of Programming Research Group to D. Reinhardt, “RE: QAC++ and
Standards”, 9 August 2004.
[Cul91] W.J. Cullyer, S.J. Goodenough and B.A. Wichmann, “The choice of computer
languages for use in safety-critical systems”, published in the Software Engineering
Journal, March 1991.
[DDC04] DDC-I Inc., “Ada Helps Boeing Cut Cost On Commanche”, DDI-C Inc.,
http://www.ddci.com/programs_rah66.shtml, 2004, Accessed 09 July 2004.
[Dei94] H.M Deitel and P.J. Deitel, “C: How to Program”, Second Edition, New Jersey:
Prentice Hall, 1994.
[Dew03] S.C. Dewhurst, “C++ Gotchas: Avoiding Common Problems in Coding and Design”,
Boston: Addison-Wesley, 2003.
[Dou98] B.P. Douglass, “Safety-Critical Systems Design”, I-Logix, http://www-md.e-
technik.uni-rostock.de/ma/gol/ilogix/scritd.pdf, 1998, Accessed 07 June 2004.
[ECP04] The Embedded C++ Technical Committee, “The Embedded C++”,
http://www.caravan.net/ec2plus/, 2004, Accessed 04 September 2004.
[Gam95] E. Gamma, R. Helm, R. Johnson, J. Vlissides, “Design Patterns – Elements of Reusable
Object-Oriented Software”, Massachusetts: Addison-Wesley, 1995.
[Gim01] Gimpel Software, “Reference Manual for PC-Lint/FlexeLint”, Collegeville
USA:Gimpel Software, July 2001.
[Gim04] Email: A. Gimpel of Gimpel Software to D. Reinhardt, “Quality Assurance
Procedures”, 09 August 2004.
89
[Hat95] L. Hatton, “Safer C: Developing Software for High-integrity and Safety-critical
Systems”, United Kingdom: McGraw-Hill, 1995.
[Hen97] M. Henricson and E. Nyquist, “Industrial Strength C++: Rules and Recommendations”,
New Jersey: Prentice Hall, 1997.
[HRM04] Department of Computer Science, “HRM: Hazard & Risk Management & Safety
Cases”, Lecture Notes, University of York, 2004.
[IEC98] International Electrotechnical Commission, “IEC 61508: Functional Safety of
Electrical/Electronic/Programmable Electronic Safety-Related Systems”, Switzerland,
1998.
[IPL03] IPL Information Processing Limited, “IPL Testing Tools and IEC 61508”, Bath: IPL
Information Processing Limited, 2003.
[IPL96] IPL Information Processing Limited, “An Introduction to Safety-Critical Systems”,
Bath: IPL Information Processing Limited, 01 August 1996.
[IPL98] IPL Information Processing Limited, “Cantata C++ - Technical Brief”, Bath: IPL
Information Processing Limited, 17 December 1998.
[Kwo03] J. Kwon, A. Wellings, and S. King, “Assessment of the Java Programming Language
for Use In High Integrity Systems”, University of York, ACM SIGPLAN Notices, April
2003.
[Law97] P.K. Lawlis, “Guidelines For Choosing A Computer Language: Support For The
Visionary Organization, 2nd Edition”, C.J. Kemp Systems Inc, August 1997.
[Lou93] K.C. Louden, “Programming Languages: Principles and Practice”, Boston: PWS
Publishing, 1993.
[Mey01] S. Meyers, “Effective STL: 50 Specific Ways to Improve Your Use of the Standard
Template Library”, Indianapolis: Addison-Wesley, 2001.
[Mey96] S. Meyers, “More Effective C++: 35 New Ways to Improve Your Programs and
Designs”, Indianapolis: Addison-Wesley, 1996.
[Mey98] S. Meyers, “Effective C++, Second Edition: 50 Specific Ways to Improve Your
Programs and Designs”, Indianapolis: Addison-Wesley, 1998.
[MIS98] The Motor Industry Software Reliability Association (MISRA), “Guidelines For The
Use Of The C Language In Vehicle Based Software”, Nuneaton: Motor Industry
Research Association, April 1998.
[MoD97] Ministry of Defence, “Defence Standard 00-55 Issue 2: Requirements for Safety Related
Software in Defence Equipment”, Great Britain, 1 August 1997.
[MoD04] Ministry of Defence, “Defence Standard 00-56 Issue 3 (Final Draft): Safety
Management Requirements for Defence Systems”, Great Britain, 30 January 2004.
[OOT04] Federal Aviation Administration (FAA), “Handbook for Object-Oriented Technology in
Aviation (OOTiA) – Draft vPC.0”, http://www.faa.gov/certification/aircraft/, 30
January 2004, Accessed 07 June 2004.
90
[PRG03] The Programming Research Group, “High-Integrity C++ Coding Standard Manual:
Version 2.1”, http://www.programmingresearch.com, 24 October 2003.
[PRG04] The Programming Research Group, “QA C++ User Guide – Version 2.0”, The
Programming Research Group, 2004.
[Pri03] CS109 Lecture Notes, “Evolution of Programming Languages”,
http://www.cs.princeton.edu/courses/archive/fall03/cs109/lect06a.pdf, 2003, Accessed
07 June 2004.
[Row94] R. Rowe, “Safety Critical Systems Computer Language Survey Results”,
http://vl.fmnet.info/safety/lang-survey.html, 1994, Accessed: 07 June 2004.
[RTC92] RTCA Inc., “RTCA/DO-178B: Software Considerations in Airborne Systems and
Equipment Certification”, Washington D.C.: RTCA Inc., 1992.
[Sch03] H. Schildt, “C++: The Complete Reference”, Fourth Edition, Berkeley: McGraw-
Hill/Osborne, 2003.
[Sto96] N. Storey, “Safety Critical Computer Systems”, Great Britain: Prentice Hall, 1996.
[Str00] B. Stroustrup, “The C++ Programming Language”, Addison-Wesley, 2000.
[Sur04] D.G. Sureau, “History and Evolution of Programming Languages”,
http://www.scriptol.org/history.php, May 2004, Accessed 07 June 2004.
[Sut00] H. Sutter, “Exceptional C++: 47 Engineering Puzzles, Programming Problems, and
Solutions”, Indianapolis: Addison-Wesley, 2000.
[Wic98] B. Wichmann, “Moderated Discussion on C++ and Safety”, Safety Critical Mailing
List, http://www.cs.york.ac.uk/hise/sclist/cplussafety.html, 20 Mar 1998, Accessed: 07
June 2004.
[Ver03] A. Verkeyn, “History of Programming Languages”, Ghent University,
http://faramir.rug.ac.be/courses/soot1/dungeon/histlang.html, 23 October 2003,
Accessed: 01 June 2004.
1-1
Appendix 1 – HICPP Coverage of Industrial Strength C++ Items
The following table details the HICPP coverage of the items presented in Industrial Strength C++
[Hen97].
Industrial Strength C++ Item Control Enforced
Rec 1.1 Use meaningful names Maintenance
Rec 1.2 Use English names for identifiers Maintenance
Rec 1.3 Be consistent when naming functions, types, variables,
and constants.
Maintenance
Rec. 1.4 Only namespace should be global. Rule 8.2.2 (direct) QAC++
Rec 1.5 Do not use global using declarations and using directives
inside header files.
Guideline 8.2.3 (direct)
Guideline 8.2.4 (direct)
QAC++
QAC++
Rec 1.6 Prefixes should be used to group macros. Maintenance
Rec 1.7 Group related files by using a common prefix in the
filename.
Maintenance
Rule 1.8 Do not use identifiers that contain two or more
underscores in a row.
Maintenance
Rule 1.9 Do not use identifiers that begin with an underscore. Maintenance
Rule 2.1 Each header file should be self-contained. Guideline 8.1.1 (direct)
Guideline 8.1.2 direct)
Guideline 8.1.3 (direct)
QAC++
QAC++
QAC++
Rule 2.2 Avoid unnecessary inclusion. Guideline 8.1.1 (direct)
Guideline 8.1.2 (direct)
Guideline 8.1.3 (direct)
Rule 14.11 (direct)
QAC++
QAC++
QAC++
QAC++
Rule 2.3 Enclose all code in header files within include guards. Rule 14.11 (direct) QAC++
Rec. 2.4 Definitions for inline member functions should be placed
in a separate file.
Guideline 8.1.2 (direct)
Guideline 3.1.7 (avoids)
QAC++
QAC++
Rec 2.5 Definitions for all template functions of a class should be
placed in a separate file.
Guideline 8.1.3 (direct) QAC++
Rec 3.1 Each file should contain a single copyright comment. Maintenance
Rec 3.2 Each file should contain a comment with a short
description of the file content.
Maintenance
Rec 3.3 Every file should declare a local constant string that
identified the file.
Maintenance
Rec 3.4 Use // for comments. Rule 14.1 (direct) QAC++
Rec 3.5 All comments should be written in English Maintenance
Rule 4.1 Do not change a loop variable inside a for loop block. Rule 5.5 (direct)
Rule 5.6 (direct)
QAC++
QAC++
Rec 4.2 Update loop variables close to where the loop condition
is specified.
Maintenance
Rec 4.3 All flow control primitives (if, else, while, for, do,
switch, and case) should be followed by a block, even if
it is empty.
Rule 5.1 (direct) QAC++
Rec 4.4 Statements following a case label should be terminated
by a statement that exits the switch statement.
Rule 5.4 (direct) QAC++
Rec 4.5 All switch statements should have a default clause. Rule 5.11 (direct) QAC++
Rule 4.6 Use break and continue instead of goto. Rule 5.8 (direct) QAC++
Rec 4.7 Do not have overly complex functions. Rule 4.1 (direct)
Rule 4.2 (direct)
Rule 4.3 (direct)
QAC++
QAC++
QAC++
Rec 5.1 Declare and initialise variables close to where they are
used.
Rule 8.4.4 (direct)
Maintenance
No auto
Rec 5.2 If possible, initialise variables at the point of declaration. Rule 8.4.3 (direct) QAC++
Rec 5.3 Declare each variable in a separate declaration statement. Rule 8.4.2 (direct) QAC++
Rec 5.4 Literals should be used only in the definition of constants
and enumerations.
Rule 10.1 (direct) QAC++
1-2
Industrial Strength C++ Item Control Enforced
Rec 5.5 Initialise all data members. Rule 3.2.1 (direct)
Rule 8.4.3 (direct)
QAC++
QAC++
Rule 5.6 Let the order in the initialiser list be the same as the
order of declaration in the header file: first base classes,
then data members.
Rule 3.2.2 (direct) QAC++
Rec 5.7 Do not use or pass this in constructor initialiser lists. New Rule (2) QAC++
Rec 5.8 Avoid unnecessary copy of objects that are costly to
copy.
Rule 11.4 (avoids) QAC++
Rule 5.9 A function must never return, or in any other way give
access to, reference or pointers to local variables outside
the scope in which they are declared.
Rule 11.7 (direct) QAC++
Rec 5.10 If objects of a class should never be copied, then the
copy constructor and the copy assignment operator
should be declared private and not implemented.
Rule 3.1.3 (direct) QAC++
Rec 5.11 A class that manages resources should declare a copy
constructor, a copy assignment operator, and a
destructor.
Rule 3.1.3 (direct)
Rule 3.1.13 (direct)
QAC++
QAC++
Rule 5.12 Copy assignment operators should be protected from
doing destructive actions if an object is assigned to itself.
Rule 3.1.5 (direct) QAC++
Rec 6.1 Use explicit rather than implicit type conversions. Rule 3.1.11 (direct)
Rule 3.2.3
Guideline 7.2 (direct)
Rule 7.8 (direct)
Guideline 10.7 (direct)
QAC++
QAC++
QAC++
QAC++
QAC++
Rec 6.2 Use the new cast operators (dynamic_cast, const_cast,
reinterpret_cast, and static_cast) instead of the old-style
casts, unless portability is an issue.
Rule 7.1 (direct) QAC++
Rec 6.3 Do not cast away const. Rule 7.4 (direct) QAC++
Rule 6.4 Declare a data member mutable if it must be modified by
a const member function.
Rule 3.1.8 (avoids)
Rule 7.4 (avoids)
QAC++
QAC++
Rec 7.1 Make simple functions inline. Rule 11.8 (direct)
Rule 3.1.6 (direct)
QAC++
QAC++
Rule 7.2 Do not declare virtual member functions as inline. Rule 11.8
Rule 3.1.6
QAC++
QAC++
Rec 7.3 Pass arguments of built-in types by value unless the
function should modify them.
Rule 11.5 (direct) No auto
Rec 7.4 Use a parameter of pointer type only if the function
stores the address or passes it to a function that does.
Rule 11.4 (direct) QAC++
Rec 7.5 Pass arguments of class types by reference or pointer. Rule 11.4 (direct) QAC++
Rule 7.6 Pass arguments of class types by reference or pointer if
the class is meant as a public base class.
Rule 11.4 (direct)
Rule 11.5 (direct)
Software Engineering –
Object Oriented Design
QAC++
PC-Lint partial
Rule 7.7 The copy assignment operator should return a non-const
reference to the object assigned to.
Rule 3.1.5 (direct) QAC++
Rule 7.8 A pointer or reference parameter should be declared
const if the function does not change the object bound to
it.
Rule 11.4 (direct)
Rule 11.5 (direct)
QAC++
PC-Lint partial
Rule 7.9 The copy constructor and copy assignment operator
should always have a const reference as a parameter.
Rule 3.1.5 (direct) QAC++
Rule 7.10 Use only const char-pointers to access string literals. ISO C++ defines
Rule 7.11 A member function that does not change the state of a
program should be declared const.
Rule 3.1.8 (direct) QAC++
Rule 7.12 A member function that gives non-const access to the
representation of an object must not be declared as const.
Rule 3.4.2 (direct)
Rule 3.4.3 (direct)
QAC++
QAC++
Rule 7.13 Do not let const member functions change the state of
the program.
Rule 3.1.8 (direct) QAC++
Rule 7.14 All variants of an overloaded member function should be
used for the same purpose and have similar behaviour.
Rule 3.5.2 (direct)
Rule 3.5.3 (direct)
No auto
QAC++
1-3
Industrial Strength C++ Item Control Enforced
Rec 7.15 If you overload one out of a closely-related set of
operators, then you should overload the whole set and
preserve the same invariants that exist for built in types.
Rule 3.5.2 (direct)
Rule 3.5.3 (direct)
Maintenance
Software Engineering –
Object Oriented Design
No auto
QAC++ partial
PC-Lint partial
Rule 7.16 In a derived class, if you need to override one of a set of
base class’s overloaded virtual member functions, then
you should override the whole set, or use using-
declarations to bring all of the functions in the same base
class into the scope of the derived class.
Rule 3.3.5 (direct)
Rule 3.3.11 (direct)
QAC++
QAC++
Rule 7.17 Supply default arguments with the function’s declaration
in the header file, not with the function’s definition in the
implementation file.
Rule 3.3.12 (direct)
Rule 12.1 (avoids)
Maintenance
QAC++
No auto
Rec 7.18 One-argument constructors should be declared explicit. Rule 3.2.3 (direct)
Rule 7.8 (avoids)
QAC++
QAC++
Rec 7.19 Do not use conversion functions. Rule 3.1.10 (direct)
Rule 3.1.11 (direct)
QAC++
QAC++
Rule 8.1 Delete should only be used with new. Rule 12.3 (direct) QAC++
Rule 8.2 Delete[] should only be used with new[]. Rule 12.3 (direct) QAC++
Rule 8.3 Do not access a pointer or reference to a deleted object. Rule 12.8 (avoids) QAC++ partial
PC-Lint partial
Rec 8.4 Do not delete this. New Rule (4) QAC++
Rec 8.5 If you overloaded operator new for a class, you should
have overloaded operator delete.
Rule 12.6 (direct) QAC++
Rec 8.6 Customise the memory management for a class if
memory management is an unacceptably large part of the
allocation and deallocation of free store objects of that
class.
Efficiency
Rec 9.1 Objects with static storage duration should be declared
only within the scope of a class, function, or anonymous
namespace.
Rule 8.1.1 (direct)
Rule 8.1.2 (direct)
Rule 8.2.2 (direct)
Guideline 6.6 (supports)
QAC++
QAC++
QAC++
No auto
Rec 9.2 Document how static objects are initialised. Rule 8.2.2 (direct)
Guideline 8.3.2 (avoids)
Maintenance
QAC++
No auto
Rule 10.1 Declare data members private. Rule 3.4.1 (direct) QAC++
Rec 10.2 If a member function returns a pointer or reference, you
should document how it should be used and how long it
is valid.
Maintenance
Rec 10.3 Selection statements (if-else and switch) should be used
when the control flow depends on an object’s value;
dynamic binding should be used when the control flow
depends on the object’s type.
Software Engineering –
Object Oriented Design
Rule 10.4 A public base class must have either a public virtual
destructor or a protected destructor.
Rule 3.3.2 (direct)
Guideline 17.7 (direct)
QAC++
No auto
Rule 10.5 If you derive from more than one base class with the
same parent, that parent should be a virtual base class.
Rule 3.3.15 (direct) QAC++
Rec 10.6 Specify classes using preconditions, postconditions,
exceptions, and class invariants.
Software Engineering –
Object Oriented Design
Malpas
Rec 10.7 Use C++ to describe preconditions, postconditions,
exceptions and class invariants.
Software Engineering –
Object Oriented Design
Rec 10.8 It should be possible to use a pointer or reference to an
object of a derived class whenever a pointer or reference
to public base class object is used.
Rule 3.3.3 (direct)
ISO C++ defines
QAC++
Rec 10.9 Document the interface of template parameters. Maintenance
Rule 11.1 Do not let assertions change the state of the program. Rule 10.8 (direct) No auto
Rec 11.2 Remove all assertions from production code. Rule 10.8 (direct)
Efficiency
No auto
1-4
Industrial Strength C++ Item Control Enforced
Rec 12.1 Check for all errors reported from functions. Guideline 9.4 (direct)
Software Engineering –
Exception Design
No auto
Rec 12.2 Use exception handling instead of status values and error
codes.
Guideline 9.4 (direct)
Software Engineering –
Exception Design
No auto
Rec 12.3 Throw exceptions only when a function fails to do what
it is expected to do.
Guideline 9.4 (direct)
Software Engineering –
Exception Design
No auto
Rec 12.4 Do not throw exceptions as a way of reporting
uncommon values from a function.
Guideline 9.4 (direct)
Software Engineering –
Exceptions Design
No auto
Rule 12.5 Do not let destructors called during stack unwinding
throw exceptions.
Rule 9.1 (avoids) QAC++
Rec 12.6 Constructors of types thrown as exceptions should not
themselves throw exceptions.New Rule (11) QAC++
Rec 12.7 Use objects to manage resources. Software Engineering –
Object Oriented Design
and Exception Design
Rule 12.8 A resource managed by an object must be released by the
object’s destructor.
Rule 3.2.5 (direct) QAC++ partial
PC-Lint partial
Rec 12.9 Use stack objects instead of free store objects. New Guideline (15)
Rec 12.10 Before letting any exceptions propagate out of a member
function, make certain that the class invariant holds and,
if possible, leave the state of the object unchanged.
Guideline 9.5 (direct)
Guideline 9.6 (direct)
Rule 9.1 (direct)
Software Engineering –
Object Oriented Design
and Exception Design
No auto
No auto
QAC++
Rec 12.11 Throw only objects of class type. Rule 9.2 (direct) QAC++
Rec 12.12 Group related exception types by using inheritance. Rule 9.2 (direct)
Software Engineering –
Object Oriented Design
and Exception Design
QAC++
Rec 12.13 Catch only objects by reference. Rule 9.3 (direct) QAC++
Rule 12.14 Always catch exceptions the user is not supposed to
know about.
Software Engineering –
Exception Design
Rec 12.15 Do not catch exceptions you are not supposed to know
about.
Software Engineering –
Exception Design
Rec 12.16 Use exception specifications to declare which exceptions
might be thrown from a function.
Guideline 9.4 (direct)
Software Engineering –
Exception Design
QAC++ partial
Rec 13.1 Use new and delete instead of malloc, calloc, realloc, and
free.
Rule 12.2 (direct)
Rule 17.1 (direct)
QAC++
QAC++
Rule 13.2 Use the iostream library instead of C-style I/O. Rule 17.1 (direct)
Rule 17.2 (direct)
QAC++
No auto
Rule 13.3 Do not use setjmp() and longjmp(). Rule 17.1 (direct)
Rule 17.2 (direct)
QAC++
No auto
Rec 13.4 Use overloaded functions and chained function calls
instead of functions with an unspecified number of
arguments.
Rule 4.3 (direct) QAC++
Rule 13.5 Do not use macros instead of constants, enums,
functions, or type definitions.
Rule 14.17 (avoids)
Rule 14.14 (avoids)
Rule 14.15 (direct)
QAC++
QAC++
QAC++
Rec 13.6 Use an array class instead of built-in arrays. Rule 8.4.8 (direct)
Rule 8.4.9 (direct)
Rule 17.9 (direct)
QAC++
QAC++
No auto
Rec 13.7 Do not use unions. Rule 15.1 (direct) QAC++
1-5
Industrial Strength C++ Item Control Enforced
Rec 14.1 Avoid duplicated code and data. Rule 3.1.6 (avoids)
Rule 11.8 (avoids)
Software Engineering –
Object Oriented Design
QAC++
QAC++
Rule 14.2 When a public base class has a virtual destructor, each
derived class has a virtual destructor.
Rule 3.3.2 (direct)
Rule 3.1.13 (direct)
QAC++
QAC++
Rule 15.1 Do not depend on undefined, unspecified, or
implementation-defined parts of the language.
Refer to Appendixes 8 -
14
Rule 15.2 Do not depend on extensions to the language or standard
library.
Guideline 13.2 (direct)
Rule 13.4 (direct)
PC-Lint partial
QAC++
Rec 15.3 Make nonportable code easy to find and replace. Maintenance
Rule 15.4 Headers supplied by the implementation should go in <>
brackets; all other headers should go in “” quotes.
Rule 14.9 (direct) QAC++
Rec 15.5 Do not specify absolute directory names in include
directives.
Rule 14.10 (direct) QAC++
Rec 15.6 Include file names should always be treated as case-
sensitive.
Rule 14.12 (direct) QAC++
Rule 15.7 Do not make assumptions about the size and layout in
memory of an object.
Rule 13.6 (direct)
Software Engineering -
Design
QAC++
Rule 15.8 Do not cast a pointer to a shorter quantity to a pointer to
a longer quantity.
Rule 13.7 (direct) QAC++
Rec 15.9 If possible, use plain int to store, pass, or return integer
values.
Efficiency
Rule 15.10 Make sure all conversions from a value of one type to
another narrower type do not slice off significant data.
Rule 3.3.3 (direct)
Rule 7.1 (direct)
Guideline 7.2 (direct)
Rule 11.4 (direct)
Rule 17.5 (direct)
QAC++
QAC++
QAC++
QAC++
No auto
Rec 15.11 Use typedefs or classes to hide representation of
application-specified data types.
Guideline 8.4.6 (direct)
Rule 15.2 (avoids)
Software Engineering –
Object Oriented Design
No auto
QAC++
Rec 15.12 Always prefix global names (such as externally visible
classes, functions, variables, constants, typedefs, and
enums) if namespace is not supported by the compiler.
Fully compliant ISO
C++ compiler only
Rec 15.13 Use macros to prevent unsupported keywords. Fully compliant ISO
C++ compiler only
Rec 15.14 Do not reuse variables declared inside a for loop. ISO C++ defines
Rec. 15.15 Only one include directive should be needed when using
a template.
Guideline 8.1.3 (direct) QAC++
Rec 15.16 Do not rely on partial instantiations of templates Rule 16.3 (direct) No auto
Rec 15.17 Do not rely on the lifetime of temporaries. ISO C++ defines
Rec 15.18 Do not use pragmas. Rule 13.4 (direct) QAC++
Rule 15.19 Always return a value from main(). ISO C++ defines
Rec 15.20 Do not depend on the order of evaluation of arguments to
a function.
Rule 10.3 (direct) QAC++
A.1 Do not mix coding styles within a group of closely
related classes.
Maintenance
A.2 In names that consist of more than one word, the words
are written together and each word other than the first
begins with an uppercase letter.
Maintenance
A.3 The names of classes, typedefs, and enumerated types
should begin with uppercase letters.
Maintenance
A.4 The names of variables and functions should begin with
lowercase letters.
Maintenance
A.5 Let data members have an M suffix. Maintenance
A.6 The names of macros should be uppercase. Maintenance
1-6
Industrial Strength C++ Item Control Enforced
A.7 The name of an include guard should be the name of the
header file, with all illegal characters replaced by
underscores and all letters converted to uppercase.
Rule 14.11 (direct)
Maintenance
QAC++
A.8 Do not use letters that can be mistaken for digits, and
vice versa.
Rule 8.4.1 (direct) QAC++
A.9 Header files should have the extension .hh. Maintenance
A.10 Inline definition files should have the extension .icc. Maintenance
Guideline 3.1.7 QAC++
A.11 The names of parameters to functions should be
specified in the function declaration if the type name is
insufficient to describe the parameter.
Rule 11.3 (direct)
Maintenance
QAC++
A.12 Always provide an access specifier for base classes and
data members.
Rule 3.1.1 (direct) QAC++
A.13 The public, protected and private sections of a class
should be declared in that order.
Rule 3.1.1 (direct) QAC++
A.14 The keyword struct should be used only for a C-style
struct.
Rule 15.2 (direct) QAC++
A.15 Define inline member functions outside the class
definition.
Rule 3.1.6 (direct)
Guideline 3.1.7 (direct)
QAC++
QAC++
A.16 Write unary operators together with their operands. Guideline 8.4.12 (direct) No auto
A.17 Write access operators together with their operands. Maintenance
A.18 Do not access static members with . or ->. Maintenance
Table 1-1: HICPP Coverage of Industrial Strength C++ Items
2-1
Appendix 2 – HICPP Coverage of Effective C++ Items
The following table details the HICPP coverage of the items presented in Effective C++ [Mey98].
Effective C++ Item Control Enforced
Item 1 Prefer const and inline to #define. Rule 8.4.11 (direct)
Rule 14.17 (direct)
PC-Lint partial
QAC++
Item 2 Prefer <iostream> to <stdio.h>. Rule 17.1 (direct) QAC++
Item 3 Prefer new and delete to malloc and free. Rule 12.2 (direct) QAC++
Item 4 Prefer C++ style comments. Rule 14.1 (direct) QAC++
Item 5 Use the same form in corresponding uses of new and delete. Rule 12.3 (direct) QAC++
Item 6 Use delete on pointer members in destructors. Rule 3.2.5 (direct) PC-Lint partial
QAC++ partial
Item 7 Be prepared for out-of-memory conditions. New Guideline (16)
Software Engineering -
Design
No auto
Item 8 Adhere to convention when writing operator new and
operator delete.
Rule 12.6 (direct)
Rule 12.7 (direct)
Rule 3.5.2 (direct)
QAC++
QAC++
No auto
Item 9 Avoid hiding the “normal” form of new. Rule 3.3.11 (direct)
Rule 8.2.1 (avoids)
QAC++
QAC++
Item 10 Write operator delete if you write operator new. Rule 12.6 (direct) QAC++
Item 11 Declare a copy constructor and an assignment operator for
classes with dynamically allocated memory.
Rule 3.1.3 (direct)
Rule 3.1.13 (direct
QAC++
QAC++
Item 12 Prefer initialisation to assignment in constructors. Rule 3.1.2 (direct)
Rule 3.2.1 (direct)
Efficiency
QAC++
QAC++
Item 13 List members in an initialisation list in the order in which
they are declared.
Rule 3.2.2 (direct) QAC++
Item 14 Make sure base classes have virtual functions. Rule 3.3.2 (direct)
Software Engineering –
Object Oriented Design
QAC++
Item 15 Have operator= return a reference to *this. Rule 3.1.5 (direct)
Rule 3.5.2 (direct)
QAC++
No auto
Item 16 Assign all data members in operators. Rule 3.1.5 (direct) QAC++
Item 17 Check for assignment to self in operator=. Rule 3.1.5 (direct) QAC++
Item 18 Strive for class interfaces that are complete and minimal. Rule 3.1.11 (direct)
Rule 3.1.13 (direct)
Guideline 3.5.5 (direct)
Software Engineering –
Object Oriented Design
QAC++
QAC++
QAC++
Item 19 Differentiate among member functions, non-member
functions, and friend functions.
Rule 3.5.4 (direct)
Software Engineering –
Object Oriented Design
QAC++
Item 20 Avoid data members in the public interface. Rule 3.4.1 (direct) QAC++
Item 21 Use const whenever possible. Rule 3.1.8 (direct)
Rule 3.4.2 (direct)
Rule 3.4.3 (direct)
Rule 3.5.3 (direct)
Rule 8.4.11 (direct)
QAC++
QAC++
QAC++
QAC++
PC-Lint partial
Item 22 Prefer pass-by-reference to pass-by-value. Rule 3.5.3 (direct)
Rule 11.4 (direct)
QAC++
QAC++
Item 23 Don’t try to return a reference when you must return an
object.
Rule 3.5.3 (direct)
Rule 11.7 (direct)
QAC++
QAC++
Item 24 Choose carefully between function overloading and
parameter defaulting.
Rule 3.3.12 (direct)
Rule 12.1 (direct)
Software Engineering -
Design
QAC++
PC-Lint partial
Item 25 Avoid overloading on a pointer and a numeric type. Rule 11.9 (direct) QAC++
2-2
Effective C++ Item Control Enforced
Item 26 Guard against potential ambiguity. Programmer Skill
Item 27 Explicitly disallow use of implicitly generated member
functions you don’t want.
Rule 3.1.10 (direct)
Rule 3.1.11 (direct)
Rule 3.1.13 (direct)
Rule 3.2.3 (direct)
QAC++
QAC++
QAC++
QAC++
Item 28 Partition the global namespace. Rule 8.2.2 (direct)
Guideline 8.2.3 (direct)
Guideline 8.2.4 (direct)
Software Engineering -
Design
QAC++
QAC++
QAC++
Item 29 Avoid returning “handles” to internal data. Rule 3.4.2 (direct)
Rule 3.4.3 (direct)
Rule 11.7 (direct)
Rule 12.5 (direct)
QAC++
QAC++
QAC++
No auto
Item 30 Avoid member functions that return non-const pointers or
references to members less accessible than themselves.
Rule 3.4.2 (direct)
Rule 3.4.3 (direct)
QAC++
QAC++
Item 31 Never return a reference to a local object or to a
dereferenced pointer initialised by new within the function.
Rule 12.5 (direct)
Rule 11.7 (direct)
No auto
QAC++
Item 32 Postpone variable definitions as long as possible. Maintenance
Efficiency
Item 33 Use inlining judiciously. Rule 3.1.6 (direct)
Guideline 3.1.7 (direct)
Rule 11.8 (direct)
QAC++
QAC++
QAC++
Item 34 Minimise compilation dependencies between files. Guideline 8.1.1 (direct)
Guideline 8.1.2 (direct)
Guideline 8.1.3 (direct)
Rule 14.5 (direct)
Rule 14.13 (direct)
QAC++
QAC++
QAC++
QAC++
QAC++
Item 35 Make sure public inheritance models “isa”. Rule 3.3.1 (direct) QAC++
Item 36 Differentiate between inheritance of interface and
inheritance of implementation.
Rule 3.3.1 (direct)
Software Engineering –
Object Oriented Design
QAC++
Item 37 Never redefine an inherited nonvirtual function. Rule 3.3.11 (direct) QAC++
Item 38 Never redefine an inherited default parameter value. Rule 3.3.12 (direct) QAC++
Item 39 Avoid casts down the inherited hierarchy. Rule 3.3.3 (direct) QAC++
Item 40 Model “has-a” or “is-implemented-in-terms-of” through
layering.
Rule 3.3.1 (direct)
Guideline 16.4 (direct)
Software Engineering –
Object Oriented Design
QAC++
No auto
Item 41 Differentiate between inheritance and templates. Guideline 16.4 (direct)
Software Engineering –
Object Oriented Design
No auto
Item 42 Use private inheritance judiciously. Rule 3.3.1 (avoids) QAC++
Item 43 Use multiple inheritance judiciously. Rule 3.3.15 (direct)
Rule 3.4.6 (direct)
Software Engineering –
Object Oriented Design
QAC++
No auto
Item 44 Say what you mean, understand what you’re saying. Programmer Skill
Item 45 Know what functions C++ silently writes and calls. Programmer Skill
Item 46 Prefer compile-time and link-time errors to run-time errors. Software Engineering -
Design
Use of a Subset
Item 47 Ensure that non-local static objects are initialised before
they are used.
Rule 8.2.2 (avoids)
Guideline 6.6 (direct)
QAC++
No auto
Item 48 Pay attention to compiler warnings. Programmer Attitude
Programmer Skill
Item 49 Familiarise yourself with the standard library. Programmer Skill
Item 50 Improve your understanding of C++ Programmer Skill
Table 2-1: HICPP Coverage of Effective C++ Items
3-1
Appendix 3 – HICPP Coverage of More Effective C++ Items
The following table details the HICPP coverage of the items presented in More Effective C++
[Mey96].
More Effective C++ Item Control Enforced
Item 1 Distinguish between pointers and references. Software Engineering
Item 2 Prefer C++ style casts. Rule 7.1 QAC++
Item 3 Never treat arrays polymorphically. Rule 8.4.9 (avoids)
Rule 17.9 (avoids)
Rule 3.3.3 (direct)
Software Engineering –
Object Oriented Design
QAC++
No auto
QAC++
Item 4 Avoid gratuitous default constructors. Software Engineering –
Object Oriented Design
Programmer Skill
Efficiency
Item 5 Be wary of user-defined conversion functions. Rule 3.1.10 (direct)
Rule 3.1.11 (direct)
QAC++
QAC++
Item 6 Distinguish between prefix and postfix forms of increment
and decrement operators.
Software Engineering -
Design
Programmer Skill
Item 7 Never overload &&, ||, or ,. Rule 3.5.1 (direct) QAC++
Item 8 Understand the different meanings of new and delete. Programmer Skill
Item 9 Use destructors to prevent resource leaks. Rule 3.2.5 (direct)
Guideline 9.5 (direct)
Rule 12.3 (direct)
Guideline 17.21 (direct)
QAC++ partial
PC-Lint partial
No auto
QAC++
No auto
Item 10 Prevent resource leaks in constructors. Guideline 9.5 (direct)
Guideline 17.21 (direct)
No auto
No auto
Item 11 Prevent exceptions from leaving destructors. Rule 9.1 (direct) QAC++
Item 12 Understand how throwing an exception differs from passing
a parameter or calling a virtual function.
Rule 8.4.3 (direct)
Programmer Skill
QAC++
Item 13 Catch exceptions by reference. Rule 9.3 (direct) QAC++
Item 14 Use exception specifications judiciously. Programmer Skill
Software Engineering –
Exception Design
Guideline 9.6 (direct) No auto
Item 15 Understand the costs of exception handling. Software Engineering –
Exception Design
Programmer Skill
Efficiency
Item 16 Remember the 80-20 rule. Efficiency
Item 17 Consider using lazy evaluation. Efficiency
Item 18 Amortize the cost of expected computations. Efficiency
Item 19 Understand the origins of temporary objects. Efficiency
Programmer Skill PC-Lint partial
Item 20 Facilitate the return value optimisation. Efficiency
Item 21 Overload to avoid implicit type conversions. Guideline 10.7 (direct)
Efficiency
QAC++
Item 22 Consider using op= instead of stand alone op. Efficiency
Item 23 Consider alternatives to libraries Efficiency
Rule 17.1 (direct) QAC++
Item 24 Understand the costs of virtual functions, multiple
inheritance, virtual base classes, and RTTI.
Efficiency
Programmer Skill
Item 25 Virtualising constructors and non-member functions. Software Engineering –
Object Oriented Design
3-2
More Effective C++ Item Control Enforced
Item 26 Limiting the number of objects in a class. Software Engineering –
Object Oriented Design
Item 27 Requiring or prohibiting heap-based objects. Software Engineering -
Design
Item 28 Smart pointers. Software Engineering -
Design
Rule 16.1 (avoids) QAC++
Item 29 Reference counting. Software Engineering –
Object Oriented Design
Item 30 Proxy classes. Software Engineering –
Object Oriented Design
Item 31 Making functions virtual with respect to more than one
object.
Software Engineering –
Object Oriented Design
Item 32 Program in the future tense. Rules and Guidelines
HICPP
Software Engineering -
Design
Item 33 Make non-leaf classes abstract. Rule 3.3.14 (direct)
Rule 3.4.5 (direct)
QAC++
QAC++
Item 34 Understand how to combine C++ and C in the same
program.
Programmer Skill
Software Engineering –
Design
Item 35 Familiarise yourself with the language standard. Programmer Skill
Table 3-1: HICPP Coverage of More Effective C++ Items
4-1
Appendix 4 – HICPP Coverage of Effective STL Items
The following table details the HICPP coverage of the items presented in Effective STL [Mey01].
Effective STL Item Control Enforced
Item 1 Choose your containers with care. Programmer Skill
Software Engineering –
Design and Efficiency
Item 2 Beware the illusion of container-independent code. Programmer Skill
Software Engineering –
Design
Item 3 Make copying cheap and correct for objects in containers. Guideline 17.3 (direct)
Guideline 17.4 (direct)
Rule 17.5 (direct)
No auto
No auto
No auto
Item 4 Call empty instead of checking size() against zero. Rule 17.6 (direct) No auto
Item 5 Prefer range member functions to their single-element
counterparts.
Software Engineering –
Design and Efficiency
Item 6 Be alert for C++’s most vexing parse. Programmer Skill
Item 7 When using containers of newed pointers, remember to
delete the pointers before the container is destroyed.
Rule 17.5 (direct)
Rule 3.2.5 (direct)
No auto
No auto
Item 8 Never create containers of auto_ptrs. Rule 17.8 (direct) No auto
Item 9 Choose carefully among erasing options. New Guideline (21)
Software Engineering –
Design
Programmer Skill
No auto
Item 10 Be aware of allocator conventions and restrictions. New Guideline (22)
Software Engineering –
Design
Programmer Skill
No auto
Item 11 Understand the legitimate uses of custom allocators. New Guideline (22)
Software Engineering –
Design
Programmer Skill
No auto
Item 12 Have realistic expectations about the thread safety of STL
containers.
Software Engineering –
Design
Item 13 Prefer vector and string to dynamically allocated arrays. Rule 17.9 (direct) No auto
Item 14 Use reserve to avoid unnecessary re-allocations. Rule 17.10 (avoid) No auto
Item 15 Be aware of variations in string implementations. Rule 13.6 (direct)
Programmer Skill
Software Engineering –
Design
QAC++ partial
Item 16 Know how to pass vector and string data to legacy APIs. Rule 17.11 (direct)
Rule 17.12 (direct)
No auto
No auto
Item 17 Use “the swap trick” to trim excess capacity. Software Engineering –
Design
Efficiency
Item 18 Avoid using vector<bool>. Rule 17.13 (direct) No auto
Item 19 Understand the difference between equality and equivalence. Programmer Skill
Software Engineering –
Design
No auto
Item 20 Specify comparison types for associative containers of
pointers.New Guideline (23)
Software Engineering -
Design
Programmer Skill
No auto
Item 21 Always have comparison functions return false for equal
values.
Rule 17.14 (direct) No auto
Item 22 Avoid in-place key modification in set and multiset. Rule 17.15 (direct) No auto
Item 23 Consider replacing associative containers with sorted
vectors.
Software Engineering –
Design and Efficiency
4-2
Effective STL Item Control Enforced
Item 24 Choose carefully between map::operator[] and map::insert
when efficiency is important..
Programmer Skill
Software Engineering –
Design
Item 25 Familiarise yourself with the non-standard hashed
containers.
Not part of ISO C++
Item 26 Prefer iterator to const_iterator, reverse_iterator, and
const_reverse_iterator.
Guideline 17.16
(direct)
No auto
Item 27 Use distance and advance to convert a container’s
const_iterators to iterators.
Guideline 17.16
(direct)
No auto
Item 28 Understand how to use a reverse_iterator’s base iterator. Rule 17.17 (direct) No auto
Item 29 Consider istreambuf_iterators for character-by-character
input.
Software Engineering –
Design
Efficiency
Item 30 Make sure destination ranges are big enough. Guideline 17.10
(avoid)
Programmer Skill
New Rule (24)
No auto
No auto
Item 31 Know your sorting options. Programmer Skill
Item 32 Follow remove-like algorithms by erase if you really want to
remove something.
Programmer Skill
Item 33 Be wary of remove-like algorithms on containers of
pointers.New Rule (25) No auto
Item 34 Note which algorithms expected sort ranges. Programmer Skill
Software Engineering –
Design
Item 35 Implement simple case-insensitive string comparisons via
mismatch or lexicographical_compare.
Software Engineering –
Design
Item 36 Understand the proper implementation of copy_if. Not in ISO C++
Item 37 Use accumulate or for_each to summarise ranges. Software Engineering –
Design
Item 38 Design functor classes for pass-by-value. Software Engineering –
Design
Item 39 Make predicates pure functions. Rule 17.17 (direct) No auto
Item 40 Make functor classes adaptable. Software Engineering –
Design
Maintenance
Item 41 Understand the reasons for ptr_fun, mem_fun, and
mem_fun_ref.
Programmer Skill
Item 42 Make sure less<T> means operator<. Software Engineering –
Design
Maintenance
Item 43 Prefer algorithm calls to hand-written loops. Guideline 17.18
(direct)
No auto
Item 44 Prefer member functions to algorithms with the same names. Rule 17.19 (direct) No auto
Item 45 Distinguish amount count, find, binary_search, lower_upper,
upper_bound, and equal_range.
Software Engineering –
Design
Item 46 Consider function objects instead of functions as algorithm
parameters.
Programmer Skill
Efficiency
Software Engineering –
Design
Item 47 Avoid producing write only code. Maintenance
Software Engineering –
Design
Item 48 Always #include the proper headers. Rule 17.20 (direct) No auto
Item 49 Learn to decipher STL-related compiler diagnostics. Programmer Skill
Item 50 Familiarise yourself with the STL-related web-sites. Programmer Skill
Table 4-1: HICPP Coverage of Effective STL Items
5-1
Appendix 5 – HICPP Coverage of C++ Gotchas
The following table details the HICPP coverage of the items presented in C++ Gotchas [Dew03].
C++ Gotchas Item Control Enforced
Item 1 Excessive Commenting Rule 14.1 (direct)
Maintenance
QAC++ partial
PC-Lint partial
Item 2 Magic Numbers Rule 14.17 (direct)
Maintenance
QAC++
Item 3 Global Variables Rule 8.2.2 (direct)
Guideline 6.6 (direct)
QAC++
No auto
Item 4 Failure to Distinguish Overloading from Default
Initialisation
Rule 12.1 (direct)
Programmer Skill
QAC++ partial
PC-Lint partial
Item 5 Misunderstanding References Software Engineering –
Design
Programmer Skill
Item 6 Misunderstanding Const Programmer Skill
Item 7 Ignorance of Base Language Subtleties Rule 5.1 (direct)
Rule 5.4 (direct)
Rule 10.20 (direct)
Programmer Skill
QAC++
QAC++
QAC++
Item 8 Failure to Distinguish Access and Visibility Guideline 8.1.1 (direct)
Guideline 8.1.2 (direct)
Guideline 8.1.3 (direct)
Software Engineering –
Object Oriented Design
Programmer Skill
Maintenance
QAC++
QAC++
QAC++
Item 9 Use Bad Language Rule 14.16 (direct)
Programmer Skill
QAC++
Item 10 Ignorance of Idiom Rule 3.1.3 (direct)
Rule 3.1.13 (direct)
Guideline 17.21 (avoids)
Programmer Skill
QAC++
QAC++
No auto
Item 11 Unnecessary Cleverness Rule 8.4.1 (direct)
Rule 8.4.2 (direct)
Rule 8.4.4 (direct)
Programmer Attitude
Maintenance
QAC++
QAC++
No auto
Item 12 Adolescent Behaviour Programmer Attitude
Item 13 Array/Initialiser Confusion Rule 8.4.9 (direct)
Rule 10.2 (direct)
Rule 12.3 (direct)
Rule 17.9 (direct)
Programmer Skill
QAC++
QAC++
QAC++
No auto
Item 14 Evaluation Order Indecision Rule 3.5.1 (direct)
Rule 10.3 (direct)
Rule 17.17 (avoids)
QAC++
QAC++
No auto
Item 15 Precedence Problems Rule 10.4 (avoids)
Rule 3.5.1 (direct)
QAC++
QAC++
Item 16 For Statement Debacle Rule 5.5 (direct)
Rule 5.6 (direct)
Guideline 5.7 (direct)
Rule 5.12 (direct)
Rule 8.2.1 (direct)
Rule 8.4.4 (avoids)
QAC++
QAC++
QAC++
QAC++
QAC++
No auto
Item 17 Maximal Munch Problems Rule 10.4 (direct)
Programmer Skill
QAC++
5-2
C++ Gotchas Item Control Enforced
Item 18 Creative Declaration-Specifier Ordering Rule 8.4.11 (direct)
Rule 8.4.12 (direct)
Programmer Skill
Maintenance
PC-Lint partial
QAC++ partial
No auto
Item 19 Function/Object Ambiguity Programmer Skill
Item 20 Migrating Type-Qualifiers Rule 8.4.7 (direct)
Rule 8.4.11 (direct)
Programmer Skill
QAC++
No auto
Item 21 Self Initialisation Rule 8.2.1 (direct)
Rule 8.3.4 (direct)
New Rule 8
QAC++
QAC++
QAC++ partial
Item 22 Static and Extern Types Rule 8.3.1 (direct)
Rule 11.2 (avoids)
QAC++
No auto
Item 23 Operator Function Lookup Anomaly Programmer Skill
Item 24 Operator -> Subtleties Programmer Skill
Item 25 #define Literals Rule 14.17 (direct) QAC++
Item 26 #define Psuedofunctions Guideline 14.7 (direct)
Rule 14.14 (direct)
Rule 14.15 (direct)
QAC++
QAC++
QAC++
Item 27 Overuse of #if Software Engineering –
Design
Programmer Skill
Item 28 Side Effects in Assertions. Rule 10.8 (direct)
Rule 14.14 (avoids)
Rule 14.15 (avoids)
No auto
QAC++
QAC++
Item 29 Converting Through void * Rule 7.1 (direct)
Guideline 7.2 (avoids)
Rule 7.5 (direct)
Rule 7.7 (direct)
QAC++
QAC++
QAC++
QAC++
Item 30 Slicing Rule 3.3.4 (direct)
Rule 17.5 (direct)
Software Engineering –
Object Oriented Design
QAC++
No auto
Item 31 Misunderstanding Pointer-to-Const Conversion Guideline 7.2 (avoids)
Rule 7.4 (direct)
Rule 7.5 (direct)
Programmer Skill
QAC++
QAC++
QAC++
Item 32 Misunderstanding Pointer-to-Pointer-to-Const Conversion Guideline 7.2 (avoids)
Rule 7.4 (direct)
Rule 7.5 (direct)
Programmer Skill
QAC++
QAC++
QAC++
Item 33 Misunderstanding Pointer-to-Pointer-to-Base Conversion. Guideline 7.2 (avoids)
Rule 7.4 (direct)
Rule 7.5 (direct)
Programmer Skill
QAC++
QAC++
QAC++
Item 34 Pointer-to-Multidimensional-Array Problems Rule 8.4.9 (avoids)
Rule 17.9 (direct)
Programmer Skill
QAC++
No auto
Item 35 Unchecked Downcasting Rule 3.3.3 (direct) QAC++
Item 36 Misusing Conversion Operators Guideline 7.2 (avoids)
Rule 3.1.10 (avoids)
Rule 3.1.11 (avoids)
Rule 3.2.3 (direct)
Rule 7.8 (avoids)
Rule 8.3.5 (direct)
Guideline 10.7 (avoids)
QAC++
QAC++
QAC++
QAC++
QAC++
No auto
QAC++
Item 37 Unintended Constructor Conversion Guideline 7.2 (avoids)
Rule 3.2.3 (direct)
QAC++
QAC++
5-3
C++ Gotchas Item Control Enforced
Item 38 Casting under Multiple Inheritance Rule 3.4.6 (avoids)
Rule 7.1 (avoids)
Guideline 7.2 (avoids)
No auto
QAC++
QAC++
Item 39 Casting Incomplete Types Rule 3.1.13 (avoids)
Rule 7.1 (direct)
Guideline 7.2 (direct)
QAC++
QAC++
QAC++
Item 40 Old-Style Casts Rule 7.1 (direct)
Guideline 7.2 (direct)
QAC++
QAC++
Item 41 Static Casts Guideline 7.2 (direct) QAC++
Item 42 Temporary Initialisation of Formal Arguments. Rule 7.8 (direct)
Rule 11.4 (direct)
Rule 11.7 (direct)
Programmer Skill
QAC++
QAC++
QAC++
Item 43 Temporary Lifetime Rule 11.7 (direct) QAC++
Item 44 References and Temporaries Rule 11.7 (direct)
Programmer Skill
QAC++
Item 45 Ambiguity Failure of dynamic_cast Guideline 7.2 (direct) QAC++
Item 46 Misunderstanding Contravariance Guideline 8.4.10 (avoid)
Programmer Skill
QAC++
Item 47 Assignment/Initialisation Confusion. Rule 3.1.2 (direct) QAC++
Item 48 Improperly Scoped Variables. Rule 8.4.2 (direct)
Rule 8.4.3 (avoids)
Rule 8.4.4 (avoids)
QAC++
QAC++
QAC++
Item 49 Failure to Appreciate C++’s Fixation on Copy Operations. Rule 3.1.3 (direct)
Rule 3.1.5 (direct)
Rule 3.1.13 (direct)
Guideline 3.2.4 (direct)
QAC++
QAC++
QAC++
QAC++
Item 50 Bitwise Copy of Class Objects Rule 3.1.3 (direct)
Rule 3.1.5 (direct)
QAC++
QAC++
Item 51 Confusing Initialisation and Assignment in Constructors Rule 3.2.1 (direct)
Rule 3.2.2 (direct)
Programmer Skill
QAC++
QAC++
Item 52 Inconsistent Ordering of the Member Initialisation List Rule 3.2.1
Rule 3.2.2
Item 53 Virtual Base Default Initialisation Rule 3.3.15 (direct)
Rule 3.4.5 (direct)
Rule 3.4.6 (direct)
Rule 7.1 (direct)
Guideline 7.2 (direct)
Software Engineering –
Object Oriented Design
QAC++
QAC++
No auto
QAC++
QAC++ partial
Item 54 Copy Constructor Base Initialisation Rule 3.1.13 (direct) QAC++
Item 55 Runtime Static Initialisation Order Guideline 8.1.1 (direct)
Guideline 8.1.2 (direct)
Rule 8.2.2 (direct)
Guideline 6.6 (direct)
QAC++
QAC++
QAC++
No auto
Item 56 Direct versus Copy Initialisation Rule 3.1.2 (direct)
Programmer Skill
QAC++
Item 57 Direct Argument Initialisation Rule 3.1.2 (direct)
ISO C++ defines
QAC++
Item 58 Ignorance of the Return Value Optimisations Efficiency
Item 59 Initialising a Static Member in a Constructor Guideline 8.1.1 (direct)
Guideline 8.1.2 (direct)
Rule 8.2.2 (avoids)
Rule 8.3.1 (avoids)
Guideline 6.6 (avoids)
Software Engineer –
Object Oriented Design
QAC++
QAC++
QAC++
QAC++
QAC++
Item 60 Failure to Distinguish Scalar and Array Allocation Rule 12.3 (direct) QAC++
5-4
C++ Gotchas Item Control Enforced
Item 61 Checking for Allocation Failure Guideline 9.4 (direct)
New Guideline (16)
Software Engineering –
Design
Programmer Skill
No auto
No auto
Item 62 Replacing Global New and Delete Rule 12.6 (direct)
Rule 12.7 (direct)
Software Engineering –
Object Oriented Design
Efficiency
QAC++
QAC++
Item 63 Confusing Scope and Activation of Member new and delete. Programmer Skill
Item 64 Throwing String Literals Rule 9.2 (direct)
Rule 9.3 (direct)
QAC++
QAC++
Item 65 Improper Exception Mechanics Rule 9.2 (direct)
Rule 9.3 (direct)
Software Engineering –
Exception Design
Programmer Skill
QAC++
QAC++
Item 66 Abusing Local Addresses Rule 11.7 (direct) QAC++
Item 67 Failure to Employ Resource Acquisition Is Initialisation Rule 8.4.3 (direct) QAC++
Item 68 Improper Use of auto_ptr Rule 17.8 (direct)
Guideline 17.21 (direct)
No auto
No auto
Item 69 Type Codes Software Engineering –
Object Oriented Design
Maintenance
QAC++
Item 70 Nonvirtual Base Class Destructor Rule 3.3.2 (avoids) QAC++
Item 71 Hiding Nonvirtual Functions Rule 3.3.11 (direct) QAC++
Item 72 Making Template Methods Too Flexible Guideline 16.4
Software Engineering –
Object Oriented Design
No auto
Item 73 Overloading Virtual Functions Rule 3.3.5 (direct) QAC++
Item 74 Virtual Functions with Default Argument Initialisers Rule 3.3.12 (direct)
Rule 12.1 (avoids)
QAC++
QAC++ partial
PC-Lint partial
Item 75 Calling Virtual Functions in Constructors and Destructors Rule 3.3.13 (direct)
Software Engineering
QAC++
Item 76 Virtual Assignment Software Engineering –
Object Oriented Design
Programmer Skill
Item 77 Failure to Distinguish among Overloading, Overriding, and
Hiding
Programmer Skill
Software Engineering –
Object Oriented Design
Item 78 Failure to Grok Virtual Functions and Overriding Programmer Skill
Software Engineering –
Object Oriented Design
Item 79 Dominance Issues Software Engineering –
Object Oriented Design
Item 80 Get/Set Interfaces Rule 3.1.6 (direct)
Rule 3.4.1 (direct)
Software Engineering –
Object Oriented Design
QAC++
QAC++
Item 81 Const and Reference Data Members Rule 3.4.2 (direct)
Rule 3.4.3 (direct)
Rule 3.1.8 (direct)
Rule 7.4 (avoids)
QAC++
QAC++
QAC++
QAC++
Item 82 Not Understanding the Meaning of Const Member Functions Rule 3.4.2 (direct)
Programmer Skill
QAC++
5-5
C++ Gotchas Item Control Enforced
Item 83 Failure to Distinguish Aggregation and Acquaintance Programmer Skill
Software Engineering –
Object Oriented Design
Item 84 Improper Operator Overloading Rule 3.5.2 (direct)
Rule 3.5.3 (direct)
Software Engineering –
Object Oriented Design
QAC++
QAC++
Item 85 Precedence and Overloading Rule 3.5.1 (direct)
Rule 3.5.2 (direct)
Rule 3.5.3 (direct)
Rule 3.5.4 (direct)
Rule 3.5.5 (direct)
QAC++
QAC++
QAC++
QAC++
QAC++
Item 86 Friend versus Member Operators Rule 3.5.4 (direct)
Software Engineering –
Object Oriented Design
QAC++
Item 87 Problems with Increment and Decrement Programmer Skill
Item 88 Misunderstanding Templated Copy Operations Programmer Skill
Software Engineering –
Object Oriented Design
Item 89 Arrays of Class Objects Rule 8.4.9 (avoids) QAC++
Item 90 Improper Container Substitutability Software Engineering –
Object Oriented Design
Item 91 Failure to Understand Protected Access Rule 3.4.4 (direct)
Programmer Skill
QAC++
Item 92 Public Inheritance for Code Reuse Rule 3.3.1 (direct)
Software Engineering –
Object Oriented Design
QAC++
Item 93 Concrete Public Base Classes Rule 3.4.5 (avoids) QAC++
Item 94 Failure to Employ Degenerate Hierarchies Software Engineering –
Object Oriented Design
Item 95 Overuse of Inheritance Rule 3.3.1 (direct)
Software Engineering –
Object Oriented Design
QAC++
Item 96 Type-Based Control Structures Software Engineering –
Object Oriented Design
Item 97 Cosmic Hierarchies Software Engineering –
Object Oriented Design
Item 98 Asking Personal Questions of an Object Software Engineering –
Object Oriented Design
Programmer Skill
Item 99 Capability Queries Software Engineering –
Object Oriented Design
Table 5-1: HICPP Coverage of C++ Gotchas
6-1
Appendix 6 – HICPP Coverage of Exceptional C++ Items
The following table details the HICPP coverage of the items presented in Exceptional C++ [Sut00].
Exceptional C++ Item Control Enforced
Item 1 Never de-reference an invalid iterator. New Rule (26) No auto
Item 5 Never make exception safety an afterthought. Exception
safety affects a class’s design. It is never “just an
implementation detail”.
Software Engineering –
Exception Design
Item 6 Prefer passing objects by const& instead of passing by
value.
Rule 11.4 (direct)
Rule 11.5 (direct)
QAC++
PC-Lint partial
Prefer precomputing values that won’t change, instead of
recreating objects unnecessarily.
Efficiency
For consistency, always implement post increment in terms
of preincrement, otherwise your users will get surprising
(and often unpleasant) results.
Rule 3.5.2 (direct)
Rule 3.5.3 (direct)
No auto
QAC++
Prefer preincrement. Only use postincrement if you’re going
to use the original value.
Programmer Skill
Watch out for hidden temporaries created by implicit
conversions. One good way to avoid this is to make
constructors explicit when possible and avoid writing
conversion operators.
Rule 3.1.10 (avoids)
Rule 3.1.11 (avoids)
Rule 3.2.3 (avoids)
Programmer Skill
QAC++
QAC++
QAC++
Be aware of object lifetimes. Never, ever, ever return
pointers or references to local automatic objects. They are
completely unuseful because the calling code can’t follow
them, and (what’s worse) the calling code my try.
Rule 11.7 (direct) QAC++
Item 7 Re-use code – especially standard library code – instead of
handcrafting your own. It’s faster, easier and safer.
Rule 17.2 (direct) QAC++
Item 8 If a function isn’t going to handle (or translate or
deliberately absorb) an exception, it should allow the
exception to propagate up to a caller that can handle it.
New Rule (12)
Software Engineering –
Object Oriented Design
QAC++
PC-Lint
Always structure your code so that resources are correctly
freed and data is in a consistent state even in the presence of
an exception.
Guideline 9.5 (direct)
Guideline 9.6 (direct)
No auto
No auto
Observe the canonical exception safety rules: Never allow
an exception to escape from a destructor or from an
overloaded operator delete() or operator delete[](); write
every destructor and deallocation function as though it had
an exception specification of “throw()”.
Rule 9.1 (direct) QAC++
Item 9 Observe the canonical exception safety rules: In each
function, take the code that might emit an exception and do
all the work safety off to the side. Only then, when you
know that the real work has succeeded, should you modify
the program state (and clean up) using only non-throwing
operations.
Guideline 9.5 (direct)
Guideline 9.6 (direct)
Software Engineering –
Object Oriented Design
No auto
No auto
Item 10 Prefer cohesion. Always endeavour to give each piece of
code – each module, each class, each function – a single,
well-defined responsibility.
Guideline 3.1.9 (direct)
Software Engineering –
Object Oriented Design
No auto
“Exception-unsafe” and “poor design” go hand in hand. If a
piece of code isn’t exception safe, that’s generally ok and
can simply be fixed. But if a piece of code cannot be made
exception safe because of its underlying design, that almost
always is a signal of its poor design.
Software Engineering –
Object Oriented Design
Item 11 Understand the basic, strong, and nothrow exception safety
guarantees.
Programmer Skill
Item 13 Observe the canonical exception-safety rules: Always use
the “resource acquisition is initialisation” idiom to isolate
resource ownership and management.
Rule 8.4.3 (direct)
Software Engineering –
Object Oriented Design
QAC++
6-2
Exceptional C++ Item Control Enforced
Item 15 Design with reuse in mind. Software Engineering –
Object Oriented Design
Item 18 Always be exception-aware. Know what code might emit
exceptions.
Programmer Skill
Item 20 Prefer writing “a op= b;” instead of “a = a op b;” (where op
stands for any operator). It’s clearer, and it’s often more
efficient.
Maintenance
Efficiency
If you supply a standalone version of an operator (for
example, operator+), always supply an assignment version
of the same operator (for example, operator+=) and prefer
implementing the forms in terms of the latter. Also, always
preserve the natural relationship between op and op= (where
op stands for any operator).
Rule 3.5.2 (direct)
Rule 3.5.3 (direct)
Software Engineering –
Object Oriented Design
No auto
QAC++
The standard requires that operators = () [] and -> must be
members, and class specific operators new, new[], delete,
and delete[] must be static members. For all other functions:
if the function is operator>> or operator<< for stream I/O, or
if it needs type conversions on its leftmost argument, or if it
can be implemented using the class’s public interface alone,
make it a nonmember (and friend if needed in the first two
cases) – if it needs to behave virtually, add a virtual member
function to provide the virtual behaviour and implement it in
terms of that – else make it a member.
Rule 12.7 (direct)
Guideline 3.4.7 (direct)
Software Engineering –
Object Oriented Design
QAC++
No auto
Always return stream references from operator<< and
operator>>.New Rule (1)
Rule 3.3.10
No auto
QAC++ partial
PC-Lint partial
Item 21 Make base class destructors virtual (unless you are certain
that no one will ever attempt to delete a derived object
through a pointer to base).
Rule 3.3.2 (direct) QAC++
When providing a function with the same name as an
inherited function, be sure to bring the inherited functions
into scope with a using-declaration if you don’t want to hide
them.
Rule 8.2.1 (avoids) QAC++
Never change the default parameters of overridden inherited
functions.
Rule 3.3.12 (direct) QAC++
Item 22 Never use public inheritance except to model true Liskov IS-
A and WORKS-LIKE-A. All overridden member functions
must require no more and promise no less.
Rule 3.3.1 (direct)
Software Engineering –
Object Oriented Design
QAC++
Never inherit publicly to reuse code (in the base class);
inherit publicly in order to be reused (by code that uses base
objects polymorphically).
Rule 3.3.1 (direct)
Software Engineering –
Object Oriented Design
QAC++
When modelling “is implemented in terms of”, always
prefer membership/containment, not inheritance. Use private
inheritance only when inheritance is absolutely necessary –
that is, when you need access to protected members or you
need to override a virtual function. Never use public
inheritance for code reuse.
Rule 3.3.1 (avoids)
Software Engineering –
Object Oriented Design
QAC++
Item 23 Know about and use design patterns. Programmer Skill
For widely used classes, prefer to use the compiler-firewall
idiom (Pimpl Idiom) to hide implementation details. Use an
opaque pointer (a pointer to a declared but undefined class)
declared as “struct XxxxImpl; XxxxImple * pimpl_;” to
store private members (including both state variables and
member functions).
Software Engineering –
Object Oriented Design
Item 24 Prefer containment (a.k.a. “composition”, “layering”, “HAS-
A”, “delegation”) to inheritance. When modelling IS-
IMPLEMENTED-IN-TERMS-OF, always prefer expressing
it using containment, not inheritance.
Rule 3.3.1 (direct)
Rule 3.4.5 (direct)
Rule 3.4.6 (direct)
Software Engineering –
Object Oriented Design
QAC++
QAC++
No auto
6-3
Exceptional C++ Item Control Enforced
Item 26 Never #include unnecessary header files. Rule 14.11 (direct)
Rule 14.13 (direct)
QAC++
PC-Lint partial
Prefer to #include <iosfwd> when a forward declaration of a
stream will suffice.
Rule 14.11 (direct)
Rule 14.13 (direct)
Maintenance
QAC++
PC-Lint partial
Never #include a header when a forward declaration will
suffice.
Rule 14.11 (direct)
Rule 14.13 (direct)
Maintenance
QAC++
PC-Lint partial
Item 28 Never inherit when composition is sufficient. Rule 3.3.1 (direct)
Software Engineering –
Object Oriented Design
QAC++
Item 30 Avoid inlining or detailed tuning until performance profiles
prove then need.
Rule 3.1.6 (direct)
Rule 3.1.7 (direct)
Rule 11.8 (direct)
QAC++
QAC++
QAC++
Item 34 Use namespaces wisely. If you write a class in some
namespace N, be sure to put all helper functions and
operators into N, too. If you don’t, you may discover
surprising effects in your code.
Guideline 8.1.1 (direct)
Guideline 8.1.2 (direct)
Guideline 8.1.3 (direct)
Guideline 8.2.3 (direct)
Guideline 8.2.4 (direct)
Rule 11.2
Programmer Skill
QAC++
QAC++
QAC++
QAC++
QAC++
No auto
Item 35 Understand the five major distinct memory stores, why
they’re different, and how they behave: stack (automatic
variables); free store (new/delete); heap (malloc/free); global
space (statics, global variables, file scope variables, and so
forth); const data (string literals, and so forth).
Programmer Knowledge
Prefer using the free store (new/delete). Avoid using the
heap (malloc/free).
Rule 12.2 (direct) QAC++
Item 36 Always provide both class-specific new (or new[]) and
class-specific delete (or delete[]) if you provide either.
Rule 12.6 (direct) QAC++
Always explicitly declare operator new() and operator
delete() as static functions. They are never nonstatic member
functions.
Rule 12.7 (direct) QAC++
Never treat arrays polymorphically. Rule 8.4.9 (avoids)
Rule 17.9 (avoids)
QAC++
No auto
Prefer using <vector> or <deque> instead of arrays. Rule 8.4.9 (direct)
Rule 17.9 (direct)
QAC++
No auto
Item 38 Never write a copy assignment operator that relies on a
check for self-assignment in order to work properly; a copy
assignment operator that uses the create-a-temporary-and-
swap idiom is automatically both strongly exception-safe
and safe for self-assignment.
Rule 3.1.5 (direct) QAC++
It’s all right to use a self-assignment check as an
optimisation to avoid needless work.
Rule 3.1.5 (direct)
Programmer Skill
QAC++
Item 39 Avoid writing conversion operators. Avoid non-explicit
constructors.
Rule 3.1.10 (direct)
Rule 3.1.11 (direct)
Rule 3.2.3 (avoid)
QAC++
QAC++
QAC++
Item 40 Avoid the “dusty corners” of a language; use the simplest
techniques that are effective.
Use of a Subset
Software Engineering
Programmer Skill
Maintenance
QAC++ partial
PC-Lint partial
Item 41 Avoid unnecessarily terse or clever code, even if it’s
perfectly clear to you when you first write it.
Maintenance No auto
Prefer providing a nonthrowing Swap() and implement copy
assignment in terms of copy construction.
Rule 3.1.4 (direct) QAC++
6-4
Exceptional C++ Item Control Enforced
Item 42 This is always initialisation ; it is never assignment, and so it
never calls T::operator=(). Yes, I know there’s an “=”
character is there, but don’t let that throw you. That’s just a
syntax holdover from C, not an assignment operation.
Rule 3.1.2 (avoids)
Programmer Skill
QAC++
Prefer using the form “T t(u);” instead of “T t = u;” where
possible. The former usually works wherever the latter
works, and has advantages – for example, it can take
multiple parameters.
Rule 3.1.2 (direct)
Programmer Skill
QAC++
Item 43 Avoid const pass-by-value parameters in function
declarations. Still make the parameter const in the same
function’s definition if it won’t be modified.
Rule 11.4 (avoids)
Rule 11.5 (direct)
QAC++
PC-Lint partial
When using return-by-value for non-builtin return types,
prefer returning a const value.
Rule 3.4.2 (direct)
Rule 3.4.3 (direct)
QAC++
QAC++
Item 44 Prefer new style casts. Rule 7.1 (direct) QAC++
Avoid casting away const. Rule 7.4 (direct) QAC++
Avoid downcasts. Rule 3.3.3 (direct) QAC++
Item 46 Prefer to pass objects by reference instead of by value, using
const whenever possible.
Rule 3.4.2 (direct)
Rule 3.4.3 (direct)
Rule 11.4 (direct)
Rule 11.5 (direct)
QAC++
QAC++
QAC++
PC-Lint partial
Item 47 Avoid using global or static objects. If you must use a global
or static object, always be very careful about the order of
initialisation rules.
Rule 8.2.2 (direct) QAC++
Always list base classes in a constructor’s initialisation list
in the same order in which they appear in the class
definition.
Rule 3.2.2 (direct) QAC++
Always list the data members in a constructor’s initialisation
list in the same order in which they appear in the class
definition.
Rule 3.2.2 (direct) QAC++
Never write code that depends on the order of evaluation of
function arguments.
Rule 10.3 (direct) QAC++
Table 6-1: HICPP Coverage of Exceptional C++ Items
7-1
Appendix 7 – HICPP Coverage of OOTiA Guidelines
The following table details the HICPP coverage of the guidelines presented in [OOT04].
OOTiA Guideline Control Enforced
3.3 Single Inheritance and Dynamic Dispatch
3.3.4 Inheritance with Overriding
Simple overriding rule: An operation may redefine an inherited
operation, and a method may implement an operation so long as changes
to its signature guarantee substitutability.
Software Engineering –
Object Oriented Design
Rule 3.3.10 (direct) QAC++ partial
PC-Lint partial
Accidental override rule: To ensure that overriding is always
intentional rather than accidental, design and code inspections should
consider whether locally defined features are intended to override
inherited features with a matching signature.
Software Engineering –
Object Oriented Design
Simple dispatch rule: When an operation is invoked on an object, a
method associated with the operation in its run time class should be
executed. This rule applies to all calls except explicit calls to superclass
methods, which should be addressed as described by the Method
Extension guidelines.
C++ Single Dispatch
Model
Complete initialisation rule: Each attribute must be initialised to a
value consistent with the class invariant by the class.
Rule 3.2.1 (direct)
Rule 8.4.3 (direct)
QAC++
QAC++
Initialisation dispatch rule: No overridden method should be called
during the initialisation (construction) of an object.
Rule 3.3.13 (direct) QAC++
Dispatch time rule: All dispatch times should be bounded and
deterministic.
Software Engineering –
Analysis and
Verification
Object code traceability rule: Everywhere concerns about source code
to object code traceability and timing analysis dictate, the compiler
vendor may be asked to provide evidence of deterministic, bounded
mapping of the dispatched call. If the evidence is not available from the
compiler vendor, it may be necessary to examine the structure of the
compiler-generated code and data structures (e.g. method tables) at the
point of call.
Software Engineering –
Analysis and
Verification
3.3.5 Method Extension
Method extension rule: When extending the functionality of an
inherited method, the subclass method should explicitly call the
superclass version of the same method.
Software Engineering –
Object Oriented Design
3.3.6 Sub-typing
Minimum compatibility rule: At a minimum, superclass/subclass
compatibility should be verified with respect to all classes involved in
the polymorphic assignment of different subclass instances to the same
variable or parameter during the execution of the system.
Software Engineering -
Verification
Substitutability compliance rule: Any approach used to verify
superclass/subclass compatibility should be consistent with the
principles of behavioural subtyping defined by Liskov and Wing.
Software Engineering –
Verification
3.3.7 Formal Sub-typing
Explicit pre/post-condition/invariant rule: To ensure that all classes
define their interfaces as contracts, all pre/postconditions and invariants
for operations and methods must be explicitly stated and all errors
returned by them must be specified. Unless the program is to be
subjected to automated format analysis, this includes pre/postconditions,
invariants, and error lists that are considered to be trivial (e.g.,
conditions whose value is true, and error lists that are empty).
Software Engineering –
Analysis and
Verification
7-2
OOTiA Guideline Control Enforced
Frame condition rule: Unless the language provides a separate
mechanism for indicating which variables may and may not change,
ideally each postcondition should also include a ‘frame condition’ which
indicates which variables are guaranteed not to change as a result of
executing the operation/method.
Rule 3.1.8 (direct)
Rule 7.4 (avoids)
Rule 8.4.11 (direct)
Rule 11.5 (direct)
Software Engineering –
Object Oriented Design,
Analysis and
Verification
QAC++
QAC++
QAC++ partial
PC-Lint partial
3.3.8 Unit Level Testing Suitability
Inherited test case rule: Every test case appearing in the set of test
cases associated with a class should appear in the set of test cases
associated with each of its subclasses.
Software Engineering -
Verification
Separate context rule: If dynamic dispatch is involved in the execution
of a method, the method should be separately tested in the context of
every concrete class in which it appears, irrespective of whether it is
defined by the class or inherited by it, provided that all such tests take
account of the method precondition(s) involved, taking account of any
dynamic binding involved in evaluating the precondition. An exception
is made for methods that are guaranteed not to directly or indirectly
invoke a method that is dynamically bound with respect to the current
object, for example, simple get and set methods that only assign a value
to, or return the value of an attribute or association. Such methods need
only be tested once, in the context of the defining class.
Software Engineering -
Verification
3.3.9 System Level Testing of Substitutability Using Assertions
Pre-condition assertion rule: An assertion to check the operation’s
precondition should appear before the body of all methods that
implement a public operation. In accordance with substitutability, this
precondition may only be weakened or the same in overridden versions
of the operation.
Software Engineering –
Design and Analysis
Post-condition assertion rule: An assertion to check the operation’s
postcondition should appear after the body of all methods that
implement a public operation. In accordance with substitutability, this
postcondition may only be strengthened or the same in overridden
versions of the operation.
Software Engineering –
Design and Analysis
Invariant assertion rule: An assertion to check the operation’s
invariant should be a part of the precondition check and the
postcondition check of all public operations. In accordance with
substitutability, the invariant may only be strengthened or the same in all
subclasses of a class.
Software Engineering –
Design and Analysis
Instrumented/un-instrumented testing rule: A test case run against an
instrumented version of the code should be considered to pass only if all
assertion checks associated with substitutability hold during its
execution. A test case run against an uninstrumented version of the code
should be considered to pass only if it produces the same result that it
did when run against an instrumented version of the same code.
Software Engineering –
Analysis
3.3.10 System Level Testing of Substitutability Using Specialised
Test Cases
Generalised test case rule: First construct a set of system level test
cases to meet the required DO-178B coverage criteria while considering
only the declared classes of objects and object references. The run time
classes of objects and dynamic dispatch should be ignored other than to
mark test cases that include dispatching calls as polymorphic.
Software Engineering -
Verification
Specialised test case rule: Next create a set of specialised test cases for
each polymorphic test case that are explicitly designed to test for
substitutability. The set of test cases generated from a given
polymorphic test case should be designed to drive dynamic dispatch
down different paths with regard to the selection of subclass methods.
The initial state and resulting state associated with each specialised test
case should be compatible (in terms of substitutability) with the more
general test case from which it was derived.
Software Engineering -
Verification
7-3
OOTiA Guideline Control Enforced
Min substitutability coverage rule: By this test case coverage criteria,
the full set of specialised test cases must exercise dynamic dispatch to
subclass methods to the extent required to meet the structural coverage
criteria of DO-178B.
Software Engineering -
Verification
Max substitutability coverage rule: By this test case coverage criteria,
the set of specialised test cases derived from each polymorphic test case
must exercise all reachable subclass methods at each point of call
involving dynamic dispatch.
Software Engineering -
Verification
Mid substitutability coverage rule: By this test case coverage criteria,
the full set of specialised test cases must meet the criteria set by the Min
Substitutability coverage rule. Additional specialised test cases,
however, are introduced to test specifically for the types of problems
raised by issues 20, 21, 22, 26, and 40 identified in Volume 2, Appendix
B of this Handbook.
Software Engineering -
Verification
3.3.11 Class Coupling
Client data abstraction rule:
• Clients should access the data representation of the class only
through its public operations.
• All attributes should be hidden (private or protected), and all
strategies associated with the choice of data representation should
be abstracted by its set of public operations.
• All hardware registers should be hidden (private or protected),
and all strategies associated with the use of a particular hardware
device should be abstracted by its set of public operations.
Rule 3.4.1 (direct)
Rule 3.4.2 (direct)
Rule 3.4.3 (direct)
Rule 3.4.4 (direct)
Rule 8.3.3 (direct)
Software Engineering –
Design and Analysis
QAC++
QAC++
QAC++
QAC++
QAC++
Invariant rule: The invariant for the class should be:
• An implicit or explicit part of the postcondition of every class
constructor,
• An implicit or explicit part of the precondition of the class
destructor (if any),
• An implicit or explicit part of the precondition and postcondition of
every other publicly accessible operation.
Software Engineering –
Design and Analysis
Subclass data abstraction rule:
• A subclass should access the data representation of its superclass
only through the superclass’ public and protected operations.
• All attributes should be hidden (private), and all strategies
associated with the choice of data representation should be
abstracted by its set of public and protected operations.
• All hardware registers should be hidden (private), and all strategies
associated with the use of a particular hardware device should be
abstracted by its set of public and protected operations.
• The class invariant should also be an implicit or explicit part of the
precondition and postcondition of each protected method of a class,
and part of the postcondition of every protected constructor.
Rule 3.4.1 (direct)
Rule 3.4.2 (direct)
Rule 3.4.3 (direct)
Rule 3.4.4 (direct)
Rule 8.3.3 (direct)
Software Engineering –
Design and Analysis
QAC++
QAC++
QAC++
QAC++
QAC++
3.3.12 Deep Hierarchy
Six deep rule: Any class hierarchy with a depth greater than six
warrants a careful review that specifically addresses the above issues
and weighs this against the need to isolate various proposed changes.
When extending an existing framework, depth should be measured from
the point at which the framework is first subclassed. When developing
an application specific class hierarchy, depth should be measured from
the root. In languages in which all classes implicitly inherit from a
common root class, this class should not be included in the count.
Rule 3.3.7 (avoids)
Rule 3.3.15 (avoids)
Rule 3.4.6 (avoids)
Guideline 3.4.7 (avoids)
Software Engineering –
Object Oriented Design
No auto
QAC++
No auto
No auto
3.4 Multiple Inheritance
3.4.4 Multiple Interface Inheritance
Repeated interface inheritance rule: When the same operation
declaration is inherited by an interface via more than one path through
the interface hierarchy without redeclaration or renaming, this should
result in a single operation in the subinterface.
Rule 3.3.1 (direct)
Rule 3.3.15 (direct)
Rule 3.4.6 (direct)
Software Engineering –
Object Oriented Design
QAC++
QAC++
No auto
7-4
OOTiA Guideline Control Enforced
Interface redefinition rule: When a subinterface inherits different
definitions of the same operation (as a result of redefinition along
separate paths), the definitions must be combined by explicitly defining
an operation in the subinterface that follows the Simple overriding rule
(section 3.3.4.3) with respect to each parent interface.
Rule 3.3.1 (direct)
Rule 3.3.15 (direct)
Rule 3.4.6 (direct)
Software Engineering –
Object Oriented Design
QAC++
QAC++
No auto
Independent interface definition rule: When more than one parent
independently defines an operation with the same signature, the user
must explicitly decide whether they represent the same operation or
whether this represents an error. Such decisions should be recorded as
explicit annotations to the source code. If the operations are not intended
to be the same, one of them should be renamed. If the operations are
intended to be the same, any preconditions and postconditions should
also be the same.
Rule 3.3.1 (direct)
Rule 3.3.15 (direct)
Rule 3.4.6 (direct)
Software Engineering –
Object Oriented Design
QAC++
QAC++
No auto
Compile time constant rule: All of the above rules apply to compile
time constants as well as operations. Constants whose value involves
run-time computation should not be permitted in interfaces.
New Rule (9)
3.4.5 Multiple Implementation Inheritance
Repeated interface inheritance rule: When the same feature (method
or attribute) is inherited by a class via more than one path through the
interface hierarchy, this should result in a single feature in the subclass.
Rule 3.3.15 (direct)
Rule 3.4.6 (direct)
Software Engineering –
Object Oriented Design
QAC++
No auto
Interface redefinition rule: When a subclass inherits different
definitions of the same method (as a result of redefinition along separate
paths), the definitions must be combined by explicitly defining a method
in the subclass that follows the Simple overriding rule: (section 3.3.4.3)
with respect to each parent class.
Rule 3.3.15 (direct)
Rule 3.4.6 (direct)
Software Engineering –
Object Oriented Design
QAC++
No auto
Independent interface definition rule: When more than one parent
independently defines a method with the same signature, the user must
explicitly decide whether they represent the same method or whether
this represents an error. If they are intended to be different, renaming
should be used to distinguish them. Otherwise, the definitions must be
combined by explicitly defining a method in the subclass that follows
the Simple overriding rule: (section 3.3.4.3) with respect to each parent
class.
Rule 3.3.15 (direct)
Rule 3.4.6 (direct)
Software Engineering –
Object Oriented Design
QAC++
No auto
3.4.7 Combination of Distinct Abstractions
No diamond rule: Repeated inheritance is not permitted, i.e. no
subclass may inherit from the same superclass via more than one path.
Rule 3.3.15 (direct)
Rule 3.4.6 (direct)
Software Engineering –
Object Oriented Design
QAC++
No auto
Independent implementation definition rule: When more than one
parent independently defines a method with the same signature, the user
must explicitly decide whether they represent the same method or
whether this represents an error. If they are intended to be different,
renaming should be used to distinguish them. Otherwise, the definitions
must be combined by explicitly defining a method in the subclass that
follows the Simple overriding rule with respect to each parent class.
(Identical to rule of same name in the section on Multiple
Implementation Inheritance)
Rule 3.3.15 (direct)
Rule 3.4.6 (direct)
Software Engineering –
Object Oriented Design
QAC++
No auto
3.4.8 Top Heavy Hierarchy
Three parents rule: Any class near the top of the hierarchy with three
or more parents warrants careful review.
Rule 3.3.7 (avoids)
Rule 3.3.15 (avoids)
Rule 3.4.6 (avoids)
Guideline 3.4.7 (avoids)
Software Engineering –
Object Oriented Design
No auto
QAC++
No auto
No auto
7-5
OOTiA Guideline Control Enforced
Top heavy composition rule : Any class near the top of the hierarchy
that inherits more than 20 features from each of two or more parent
classes warrants careful review.
Rule 3.3.7 (avoids)
Rule 3.3.15 (avoids)
Rule 3.4.6 (avoids)
Guideline 3.4.7 (avoids)
Software Engineering –
Object Oriented Design
No auto
QAC++
No auto
No auto
Top to bottom rule: Any class hierarchy that contains more classes near
the top of the hierarchy than near the bottom warrants careful review.
Rule 3.3.7 (avoids)
Rule 3.3.15 (avoids)
Rule 3.4.6 (avoids)
Guideline 3.4.7 (avoids)
Software Engineering –
Object Oriented Design
No auto
QAC++
No auto
No auto
3.5 Templates
3.5.3 Source Code Review
A template must be reviewed with respect to the actual parameters to
determine if the source code is verifiable.
Software Engineering -
Verification
3.5.4 Requirements-based Test Development, Review and Change
Each instance of a template with a unique set of arguments should be
tested.
Software Engineering -
Verification
3.5.5 Structural Coverage for Templates
Templates should be analysed for complexity and complex templates
should be avoided. Nested templates and templates used with other
language constructs should be analysed for complexity and justified.
Guideline 16.4 (direct)
Software Engineering –
Analysis and
Verification
No auto
Code sharing is not widely used. In general, code sharing should be
avoided.
Rule 3.3.1 (direct)
Guideline 16.4 (direct)
Software Engineering –
Object Oriented Design
QAC++
No auto
Data and control coupling associated with templates should be evaluated
with respect to the actual parameters.
Software Engineering –
Analysis and
Verification
3.6 Inlining
3.6.3 Inlining and Structural Coverage
Inlining should consist of simple expression only, which is almost
always one line of code. Virtual methods and methods that access other
class methods should not be inlined.
Rule 3.1.6 (direct)
Rule 3.1.7 (direct)
Rule 11.8 (direct)
QAC++
QAC++
QAC++
The structural coverage of the inlined method should be evaluated at the
point of each expansion.
Rule 3.1.6 (avoids)
Guideline 3.1.7 (avoids)
Rule 11.8 (avoids)
Software Engineering –
Verification
QAC++
QAC++
QAC++
For data coupling and control coupling, the verification approach should
address the inlining of code including worst case memory usage
analysis, stack usage analysis, timing analysis, call tree analysis, and
data set/use analysis.
Rule 3.1.6 (avoids)
Guideline 3.1.7 (avoids)
Rule 11.8 (avoids)
Software Engineering –
Analysis and
Verification
QAC++
QAC++
QAC++
3.6.4 Source Code Review of Inlined Code
Review of the inlined method against the low level requirements is
sufficient to verify the behaviour of all expansions.
Rule 3.1.6 (avoids)
Guideline 3.1.7 (avoids)
Rule 11.8 (avoids)
Software Engineering –
Requirements and
Analysis
QAC++
QAC++
QAC++
7-6
OOTiA Guideline Control Enforced
3.7 Type Conversion
3.7.4 Source Code Review, Checklist, and Coding Standards
Conversion rule: To help ensure intended function and verification, all
checked and unchecked conversions should be justified or should be
explicit, use the most restrictive conversion available, be conspicuously
marked (identified) in the program source code, and be permitted only
after thorough review and analysis of potential adverse effects.
Rule 3.2.3 (direct)
Rule 7.1 (direct)
Guideline 7.2 (direct)
Rule 7.3 (direct)
Rule 7.4 (direct)
Rule 7.5 (direct)
Rule 7.6 (direct)
Rule 7.7 (direct)
Rule 7.8 (direct)
QAC++
QAC++
QAC++
QAC++
QAC++
QAC++
QAC++
QAC++
QAC++
3.7.5 Loss of Precision in Type Conversions
Loss of information rule: To help ensure correctness, any conversions
that may result in loss of data or data accuracy and precision should be
justified or should: - be explicit, - use the most restrictive conversion
available, - be conspicuously marked (identified) in the program source
code, and only be permitted after thorough review and analysis of
potential adverse effects.
Rule 3.2.3 (direct)
Rule 7.1 (direct)
Guideline 7.2 (direct)
Rule 7.6 (direct)
Rule 7.7 (direct)
Rule 7.8 (direct)
QAC++
QAC++
QAC++
QAC++
QAC++
QAC++
3.7.6 Type Conversions of Reference and Pointers
Super-type rule: To help ensure intended function and verification, all
implicit type conversions involving references/pointers to class instances
should be justified or should only represent a conversion from a subtype
to one of its supertypes.
Rule 3.3.3 (direct)
Rule 7.5 (direct)
QAC++
QAC++
3.7.7 Language Specific Guidelines
All implicit conversions should be checked for potential loss of
precision or loss of data. Specifically the following should be justified:
From integer types to the floating point types (potential loss of
precision)
Rule 10.14 (direct)
Rule 10.15 (direct)
QAC++
QAC++
From a floating point type to an integer type (potential loss of data) Rule 7.6 (direct)
Rule 10.14 (direct)
QAC++
QAC++
From a more precise numeric type to a less precise version of the same
numeric type (potential loss of data and precision)
Rule 10.13 (direct)
Rule 10.15 (direct)
Rule 10.21 (direct)
QAC++
QAC++
QAC++
Implicit conversions between logically unrelated types should be
justified. Unless the single argument constructor was created with the
expressed purpose of permitting implicit conversion between the
argument type and the class type, the constructor should be declared
with the explicit keyword.
Rule 3.2.3 (direct) QAC++
3.8 Overloading and Method Resolution
3.8.3 Code Review Method
Overloaded method rule: Overloaded operations or methods should
form "families" that use the same semantics, share the same name, have
the same purpose, and that are differentiated by the types of their formal
parameters.
Rule 3.5.2 (direct)
Rule 3.5.3 (direct)
Software Engineering –
Object Oriented Design
No auto
QAC++
Overloaded operator rule: Overloaded operators should obey the
"natural" meaning and follow conventions of the language. For example,
a C++ operator "+=" should have the same meaning as "+" and "=".
Arithmetic operators should be overloaded using conventional notation
whenever possible.
Rule 3.5.2 (direct)
Rule 3.5.3 (direct)
No auto
QAC++
Overloading in general: When calls are overloaded, reviewers should
know exactly what is being called. Overloading of special language
constructs must be justified.
Rule 3.5.2 (avoids)
Rule 3.5.3 (avoids)
Software Engineering –
Object Oriented Design
and Analysis
No auto
QAC++
7-7
OOTiA Guideline Control Enforced
3.8.4 Implicit Conversion
The software user of any family of overloaded operators and methods
whose arguments (signatures) are implicitly convertible should perform
the call using arguments that do not need to be converted and perform
analysis appropriate to the level of the software to ensure the proper
method is being called.
Rule 3.1.10 (avoids)
Rule 3.1.11 (avoids)
Rule 3.2.3 (avoids)
Rule 3.5.2 (avoids)
Rule 7.8 (avoids)
Software Engineering –
Object Oriented Design
and Analysis
QAC++
QAC++
QAC++
No auto
QAC++
3.9 Dead and Deactivated Code and Reuse
3.9.3 Reuse of Software Components
Developer’s intent rule: All code must be exercised by requirements-
based tests (the requirements may be derived). Code not associated with
requirements should be carefully evaluated and either removed (if it is
dead code) or requirements should be developed for the code. Code
which exists due to derived requirements needs to be explicitly
identified by the developer and the associated requirements must be
noted as “derived” for inclusion in the SSA process by the integrator.
Software Engineering -
Verification
Cantata C++
facilitates this
testing
All code verified rule: All code verified rule: All code executed within
any aircraft or engine configuration must be verified per applicable DO-
178B objectives, even if it can be demonstrated that a particular piece of
code can never be activated in a specific system. Note that requirements
will be needed for all deactivated code associated with the various
aircraft or engine configurations (either derived requirements or explicit,
option-selectable requirements specified by the integrator).
Software Engineering –
Requirements and
Verification
Cantata C++
QAC++
3.9.5 Certification Credit for Reused but Modified Class Hierarchy
Flattened class re-verification rule: Flattened class re-verification rule:
When a change to an element of a class occurs, re-verification of all
subclasses whose flattened form contains the changed element is
recommended.
Software Engineering -
Verification
No auto
3.9.7 Service History Credit and Deactivated Code
Service history rule: Service history credit may only be given for
activated code and deactivation mechanisms that have been actually
executed. The target environment, certification basis, and SSA will need
to be considered in this process.
Software Engineering -
Verification
No auto
Table 7-1: HICPP Coverage of OOTiA Guidelines
8-1
Appendix 8 – Unspecified Behaviour (C++ Language)
The following table details unspecified behaviour in the C++ language and the applicable controls
that can be put in place to mitigate them. The behaviours have been extracted directly from [BSI03].
Page Item / Description Control Enforced
45 3 Basic Concepts
3.6.2 Initialisation of Non-local Objects (para 2)
The following example illustrates the point.
inline double fd() { return 1.0; }extern double d1;double d2 = d1; //unspecified
//may be statically initialised to0.0 or
//dynamically initialised to 1.0double d2 = fd(); //may be initialised statically to1.0
It is unspecified whether the value of d1 used will be the value of the fully
initialised d2 (because d2 was statically initialised) or will be the value of d2
merely zero-initialised. This is because objects with static storage duration
shall be zero-initialised before any other initialisation takes place. Also
objects with static storage duration defined in namespace scope in the same
translation unit and dynamically initialised shall be initialised in the order in
which they are defined in the translation unit. Thus it may not be possible to
guarantee that d1 is initialised before d2.
Rule 8.2.2 (direct)
Guideline 8.3.2
(direct)
Software
Engineering -
Design
QAC++
PC-Lint
partial
48 3.7.3.1 Allocation Functions (para 2)
The order, contiguity, and initial value of storage allocated by successive
calls to an allocation function is unspecified.
Rule 13.6 (avoids) QAC++
partial
65 5 Expressions (para 4) – Order of Evaluation
The order of evaluation of operands of individual operators and sub-
expressions of individual expressions, and the order in which side effects
take place is unspecified. The precedence of operators is not directly
specified, but it can be derived from the syntax.
i = v[i++]; //the behaviour is unspecifiedi = 7, i++, i++; //i becomes 9
i = ++i + 1; //the behaviour is unspecifiedi = i + 1; // the value of i is incremented
Rule 3.5.1 (avoids)
Rule 10.3 (direct)
Rule 10.9 (direct)
QAC++
QAC++
QAC++
70 5.2.2 Function Call (para 8) – Order of Argument Evaluation
The order of evaluation of arguments is unspecified. All side effects of
argument expression evaluations take effect before the function is entered.
The order of evaluation of the postfix expression and the argument
expression list is unspecified.
Rule 3.5.1 (avoids)
Rule 10.3 (direct)
QAC++
QAC++
72 5.2.8 Type Identification (para 1)
The result of a typeid expression is an lvalue of static type const
std::type_info and dynamic type const std::type_info or const
name where name is an implementation-defined class derived from
std::type_info which preserves the behaviour described in 18.5.1. The
lifetime of the object referred to by lvalue extends to the end of the program.
Whether or not the destructor is called for the type_info object at the end
of the program is unspecified.
New Rule (5) QAC++
75 5.2.9 Static Cast (para 7)
A value of integral or enumeration type can be explicitly converted to an
enumeration type. The value is unchanged if the original value is within the
range of enumeration values. Otherwise the resulting enumeration value is
unspecified.
Rule 15.4 (direct)
Guideline 7.2
(avoids)
QAC++
QAC++
8-2
Page Item / Description Control Enforced
76 5.2.10 Reinterpret Cast (para 6, 7, 9)
Except that converting an rvalue of type “pointer to T1” to the type “pointer
to T2” (where T1 and T2 are function types or objects) and back to its
original type yields the original pointer value, the result of such a conversion
is unspecified.
Except that converting an rvalue of type “pointer to T1” to the type “pointer
to T2” (where T1 and T2 are object types and where the alignment
requirements of T2 are no stricter than those of T1) and back to its original
type yields the original pointer value, the result of such a conversion is
unspecified.
An rvalue of type “pointer to member of X of type T1” can be explicitly
converted to an rvalue of type “pointer to member of Y of type T2” if T1
and T2 are both function types of both object types. The null member
pointer value is converted to the null member pointer value of the
destination type. The result of this conversion is unspecified in all but two
specifically specified cases.
Rule 7.5 (direct)
Guideline 7.2
(avoids)
QAC++
QAC++
83 5.3.4 New (para 21)
Whether the allocation function is called before evaluating the constructor
arguments or after evaluating the constructor arguments but before entering
the constructor is unspecified.
Whether the arguments to a constructor are evaluated if the allocation
function returns the null pointer or exits using the exception is unspecified.
Rule 10.3 (direct)
Rule 3.5.1 (avoids)
New Rule (3)
QAC++
QAC++
No auto
85 5.4 Explicit Type Conversion (para 6)
The operand of a cast using the cast notation can be an rvalue of type
“pointer to incomplete class type”. The destination type of a cast using the
cast notation can be “pointer to incomplete class type”. In such cases, even if
there is an inheritance relationship between the source and destination
classes, whether the static_cast or reinterpret_cast interpretation is
used is unspecified.
Rule 7.5 (avoids)
Guideline 7.2
(avoids)
QAC++
QAC++
89 5.9 Relational Operators (para 2) – Pointer Comparison
If two pointers p and q of the same type point to the same object or function,
or both point one past the end of the same array, or both are null, then p<=q
and p>=q both yield true and p<q and p>q both yield false.
If two pointers p and q of the same type point to different objects that are not
members of the same object or elements of the same array or different
functions, or if only one of them is null, the results of p<q, p>q, p<=q, and
p>=q are unspecified.
If two pointers point to non-static data members of the same object, or to
sub-objects or array elements of such members, recessively, the pointer to
the later declared member compares greater provided the two members are
not separated by an access-specifier label and provided their class is not a
union.
If two pointers point to non-static data members of the same object
separated by an access-specifier label the result is unspecified.
If two pointers point to data members of the same union object, they
compare equal (after conversion to void *, if necessary). If two pointers
point to elements of the same array or one beyond the end of the array, the
pointer to the object with the higher subscript compares higher.
All other pointer comparisons are unspecified.
Rule 5.2 (direct)
Guideline 10.6
(direct)
PC-Lint
partial
No auto
89 5.10 Equality Operators (para 2) – Pointer Comparison
If either pointer is a pointer to a virtual function, then the result is
unspecified.
Rule 3.3.4 (avoids)
Rule 5.2 (direct)
New Rule (7)
QAC++
PC-Lint
partial
No auto
8-3
Page Item / Description Control Enforced
114 7 Declarations
7.2 Enumeration Declarations (para 4, 9)
If no initialiser is specified for the first enumerator, the type is an
unspecified integral type. Otherwise the type is the same as the type of the
initialising value of the preceding enumerator unless the incremented value
is not representable in that type, in which case the type in an unspecified
integral type sufficient to contain the incremented value.
An expression of arithmetic or enumeration type can be converted to an
enumeration type explicitly. The value is unchanged if it is in the range of
enumeration values of the enumeration type; otherwise the resulting
enumeration value is unspecified.
Rule 13.6 (direct)
Rule 15.4
Guideline 7.2
(direct)
QAC++
partial
PC-Lint
partial
QAC++
QAC++
136 8 Declarators
8.3.2 References (para 3)
It is unspecified whether or not a reference requires storage.
Rule 13.6 (direct) QAC++
partial
PC-Lint
partial
143 8.3.6 Default Arguments (para 9)
Default arguments are evaluated each time the function is called. The order
of evaluation of function arguments is unspecified.
Rule 10.3 (direct) QAC++
159 9 Classes
9.2 Class Members (para 12) – Allocation
The order of allocation of non-static data members separated by an access
specifier is unspecified.
Rule 13.6 (direct) QAC++
partial
PC-Lint
partial
170 10 Derived Classes (para 3)
The order in which the base class sub-objects are allocated in the most
derived object is unspecified.
Rule 13.6 (direct) QAC++
partial
PC-Lint
partial
183 11 Member Access Control
11.1 Access Specifiers (para 2) – Allocation
The order of allocation of data members with separate access-specifier
labels is unspecified.
Rule 13.6 (direct) QAC++
partial
PC-Lint
partial
194 12 Special Member Functions (para 15) – Constructors
During the construction of a const object, if the value of the object or any of
its sub-objects is accessed through an lvalue that is not obtained, directly or
indirectly, from the constructor’s this pointer, that value of the object or sub-
object thus obtained is unspecified.
New Rule (2) QAC++
partial
PC-Lint
partial
196 12.2 Temporary Objects (para 5)
class C {public:
C();C(int);Friend C operator+(const C&, const C&);~C();
};C obj1;const C& cr = C(16)+C(23);C obj 2;
A first temporary T1 to hold the result of the expression C(16), a second
temporary T2 to hold the result of expression C(23), and a third temporary
T3 to hold the result of the addition of these two expressions. The temporary
T3 is then bound to the reference cr. It is unspecified whether T1 or T2 is
created first.
Rule 10.3 (direct)
Rule 3.5.1 (avoids)
QAC++
QAC++
215 12.8 Copying Class Objects (para 13)
It is unspecified whether sub-objects representing virtual base classes are
assigned more than once by the implicitly-defined copy assignment
operator.
Rule 3.1.3 (avoids)
Rule 3.1.5 (direct)
Rule 3.1.13
(avoids)
QAC++
QAC++
QAC++
8-4
Page Item / Description Control Enforced
282 14 Templates
14.7.1 Implicit Instantiation (para 5, 9)
If the overload resolution process can determine the correct function to call
without instantiating a class template definition, it is unspecified whether
instantiation actually takes place.
It is unspecified whether or not an implementation implicitly instantiates a
virtual member function of a class template if the virtual member function
would not otherwise be instantiated.
Rule 16.2 (avoids)
Rule 16.3 (avoids)
No auto
307 15 Exception Handling
15.1 Throwing an Exception (para 4)
When the last handler being executed for the exception exists by any means
other than throw; the temporary object is destroyed and the implementation
may de-allocate the memory for the temporary object; any such de-
allocation is done in an unspecified way.
New Rule (13) No auto
320 16 Preprocessing Directives
16.3.2 The # Operator (para 2)
The order of evaluation of # and # # operators is unspecified.
Rule 10.3 (direct) QAC++
320 16.3.3 The # # Operator (para 3)
The order of evaluation of # # operators is unspecified.
Rule 10.3 (direct) QAC++
Table 8-1: C++ Language Unspecified Behaviour [BSI03]
9-1
Appendix 9 – Unspecified Behaviour (C++ STL)
The following table details unspecified behaviour in the C++ STL and the applicable controls that
can be put in place to mitigate them. The behaviours have been extracted directly from [BSI03].
Page Item / Description Control Enforced
339 17 Library Introduction
17.4.4.3 Global, or Non-Member Functions (para 1)
It is unspecified whether any global or non-member functions in the C++
Standard Library are defined as inline.
Efficiency
339 17.4.4.4 Member Functions (para 1, 2)
It is unspecified whether any member functions in the C++ Standard Library
are defined as inline.
An implementation can declare additional non-virtual member function
signatures within a class by adding elements with default values to a
member function signature. Hence, taking the address of a member function
has an unspecified type.
Efficiency
Rule 13.6 (direct) QAC++
partial
PC-Lint
partial
340 17.4.4.6 Protection within Classes (para 1)
It is unspecified whether a function signature or class in clauses 18 through
27 is a friend of another class in the C++ Standard Library.
Guideline 13.1
(supports)
No auto
340 17.4.4.7 Derived Classes (para 1, 2)
It is unspecified whether a class in the C++ Standard Library is itself derived
from other classes (with names reserved to the implementation).
It is unspecified whether a class described in the C++ Standard Library as
derived from another class is derived from another class directly, or through
other classes (with names reserved to the implementation) that are derived
from the specified base class.
Guideline 13.1
(supports)
No auto
354-
35518 Language Library Support
18.4.1 Storage Allocation and De-allocation
18.4.1.1 Single-Object Forms (para 4, 8, 14)
void* operator new(std::size_t size)throw(std::bad_alloc)void* operator new(std::size_t size, conststd::nothrow_t&) throw();
This call executes a loop. Within the loop the function first attempts to
allocate the requested storage. Whether this attempt involves a call to the
Standard C Library function malloc is unspecified.
void operator delete(void* ptr) throw();void operator delete(void* ptr, const std::nothrow_t&)throw();
It is unspecified under what conditions part or all of such reclaimed storage
is allocated by a subsequent call to operator new or any of calloc, malloc,
or realloc, declared in <cstdlib>.
Guideline 13.1
(supports)
No auto
9-2
Page Item / Description Control Enforced
355-
35618.4.1 Storage Allocation and De-allocation
18.4.1.2 Array Forms (para 3,7,13)
void* operator new[](std::size_t size)throw(std::bad_alloc)void* operator new[](std::size_t size, conststd::nothrow_t&) throw();
This call executes a loop. Within the loop the function first attempts to
allocate the requested storage. Whether this attempt involves a call to the
Standard C Library function malloc is unspecified.
void operator delete[](void* ptr) throw();void operator delete[](void* ptr, const std::nothrow_t&)throw();
It is unspecified under what conditions part or all of such reclaimed storage
is allocated by a subsequent call to operator new or any of calloc, malloc,
or realloc, declared in <cstdlib>.
Guideline 13.1
(supports)
No auto
358 18.5 Type Identification
18.5.1 Class type_info (para 1)
The class type_info describes type information generated by the
implementation. Objects of this class effectively store a pointer to a name
for the type, and an encoded value suitable for comparing two types for
equality or collating order. The names, encoding rule and collating sequence
for types are all unspecified and may differ between programs.
Guideline 13.1
(supports)
Software
Engineering –
Object Oriented
Design
QAC++
partial
388 20 General Utilities Library
20.4.1.1 allocator Numbers (para 6, 10)
pointer allocate(size_type n,allocator<void>::const_pointer hint=0);
The storage is obtained by calling ::operator new(size_t), but it is
unspecified when or how often this function is called. The use of hint is
unspecified, but intended as an aid to locality if an implementation so
desires.
void deallocate(pointer p, size_type n);
Uses ::operator delete(void *), but it is unspecified when this
function is called.
Guideline 13.1
(supports)
No auto
396 21 String Library
21.1.1 Character Traits Requirements (para 1)
X::to_char_type(e)
X::eq_int_type(e,X::to_int_type(c)) is true, c; else some
unspecified value.
X::eq_int_type(e,f)
Yields for all c and d, X::eq(c,d) is equal to
X::eq_int_type(X::to_int_type(c), X::to_int_type(d));
otherwise, yields true if e and f are both copies of X::eof(); otherwise
yields false if one of e and f are copies of X::eof() and the other is not;
otherwise the value is unspecified.
Guideline 13.1
(supports)
No auto
407 21.3.1 basic_string Constructors (para 2)
explicit basic_string(const Allocator& a = Allocator());
A post condition of this function is that the element capacity() is an
unspecified value.
Guideline 13.1
(supports)
No auto
9-3
Page Item / Description Control Enforced
448 22 Localisation Library
22.2.1.5.2 codecvt Virtual Functions (para 3)
result do_out(stateT& state, const internT* from, constinternT* from_end, const internT* from_next, externT* to,externT* to_limit, externT*& to_next) const;
result do_out(stateT& state, const internT* from, constinternT* from_end, const internT* from_next, externT* to,externT* to_limit, externT*& to_next) const;
Its operations on state are unspecified.
Guideline 13.1
(supports)
No auto
464 22.2.5.1 Class Template time_get (para 1)
time_get is used to parse a character sequence, extracting components of a
time or date into a struct tm record. If the sequence being parsed matches the
correct format, the corresponding members of the struct tm argument are set
to the values used to produce the sequence; otherwise either an error is
reported or unspecified values are assigned.
Guideline 13.1
(supports)
No auto
475 22.2.7.1.2 messages Virtual Functions (para 6)
void do_close(catalog cat) const;
Releases unspecified resources associated with cat.
Guideline 13.1
(supports)
No auto
580 25 Algorithms Library
25.3.1.3 partial_sort (para 1)
Places the first middle – first sorted elements from the range [first, last] into
the range [first, middle]. The rest of the elements in the range [middle, last]
are placed in an unspecified order.
Guideline 13.1
(supports)
No auto
592 26 Numerics Library
26.2 Complex Numbers
The effect of instantiating a template complex for any type other than float,
double or long is unspecified.
Guideline 13.1
(supports)
No auto
608 26.3.2.7 valarray Member Functions (para 2)
If the array has length 0, the behaviour is undefined. If the array has length
1, sum() returns the value of element 0. Otherwise, the returned value is
calculated by applying operator+= to a copy of an element of the array
and all other elements of the array in an unspecified order.
Guideline 13.1
(supports)
No auto
633 27 Input/Output Library
27.4.2 Class ios_base (para 3)
static int index, specified the next available unique index for the
integer or pointer arrays maintained for the private use of the program
initialised to an unspecified value.
Guideline 13.1
(supports)
No auto
637 27.4.2.5 ios_base Static Members (para 2, 4)
long& iword(int idx);
If iarray is a null pointer, allocates an array of long of unspecified size and
stores a pointer to its first element in iarray.
Void* & pword(int idx);
If parray is a null pointer, allocates an array of pointers to void of
unspecified size and stores a pointer to its first element in parray.
Guideline 13.1
(supports)
No auto
639 27.4.3.2 fpos Requirements (para 1)
It is unspecified whether these operators are members of fpos, global
operators, or provided in some other way.
Guideline 13.1
(supports)
No auto
9-4
Page Item / Description Control Enforced
654 27.5.2.4.4 Putback (para 1)
int_type pbackfail(int_type c = traits::eof());
If traits::eq_int_type(c,traits::eof()) return false, then c is
prepended. Whether the input sequence is backed up or modified in any
other way is unspecified.
Guideline 13.1
(supports)
No auto
674,
67527.6.3 Standard Manipulators (para 3, 4, 5, 6, 7, 8)
smanip resetioflags(ios_base::fmtflags mask);smanip setiosflags(iosbase::fmtflags mask);smanip setbase(int base);smanip setprecision(int n);smanip setw(int n);
Returns an object s of unspecified type such that if out is an (instance of)
basic_ostream then the expression out<<s behaves as if f(s) were
called, and if in an (instance of) basic_istream then the expression
in>>s behaves as if f(s) were called.
smanip setfill(char_type c_;
Returns an object s of unspecified type such that if out is (or is derived from)
basic_ostream<charT,traits> and c has charT then the expression
out<<s behaves as if f(s) were called.
Guideline 13.1
(supports)
No auto
678,
68827.7.1.3 Overridden Virtual Functions (para 4)
27.8.1.4 Overridden Virtual Functions (para 7)
int_type pbackfail(int_type c = traits::eof());
Puts back the character designated by c to the input sequence, if possible in
one of three ways. If the function can succeed in more than one of these
ways, it is unspecified which way is chosen.
Guideline 13.1
(supports)
No auto
733 Annex D Compatibility Features
D.7.1.1 strstreambuf Constructors (para 2, 3)
strstreambuf(void* (*)(size_t), void (*)(void*))strstreambuf(charT*,streamsize,charT*)
A post-condition of these functions is that the element alsize is an
unspecified value.
Guideline 13.1
(supports)
No auto
735 D.7.1.3 strstreambuf Overridden Virtual Functions (para 3)
int_type overflow(int_type c = EOF);
The function can alter the number of write positions available as a result of a
call. To make a write position, the function reallocates an array object with a
sufficient number of elements n to hold the current array object, plus at least
one additional write position. How many additional write positions are made
available is otherwise unspecified.
Guideline 13.1
(supports)
Efficiency
No auto
Table 9-1: C++ STL Unspecified Behaviour [BSI03]
10-1
Appendix 10 – Undefined Behaviour (C++ Language)
The following table details undefined behaviour in the C++ language and the applicable controls
that can be put in place to mitigate them. The behaviours have been extracted directly from [BSI03].
Page Item / Description Control Enforced
9 2 Lexical Conventions
2.1 Phases of Translation (para 2, 4)
Each instance of a new-line character and an immediately preceding back-
slash character is deleted, splicing physical source lines to form logical
source lines. If, as a result, a character sequence that matches the syntax of
the universal-character-name is produced, the behaviour is undefined. If a
source file that is not empty does not end in a new-line character, or ends in
a new-line character immediately preceded by a back-slash character, the
behaviour is undefined.
Preprocessing directives are executed and macro invocations are expanded.
If a character sequence that matches the syntax of a universal-character-
name is produced by token concatenation, the behaviour is undefined.
Rule 6.4 (direct)
Rule 14.8 (direct)
Rule 14.7 (direct)
QAC++
QAC++
QAC++
11 2.4 Preprocessing Tokens (para 2)
If a ‘ or a “ character matches the last category (single non-whitespace
characters), the behaviour is undefined.
Rule 14.7 (avoids)
Rule 14.17 (avoids)
QAC++
partial
PC-Lint
partial
13 2.8 Header Names (para 2)
If either of the characters ‘ or \, or either of the character sequences /* or //
appear in a q-char-sequence or a h-char-sequence, or the character “ appears
in a h-char-sequence, the behaviour is undefined. Thus, sequences of
characters that resemble escape sequences cause undefined behaviour.
Rule 14.10 (direct)
Rule 14.17 (avoids)
QAC++
16 2.13.1 Integer Literals (para 2) - Type
The type of an integer literal depends on its form, value, and suffix. If it is
decimal and has no suffix, it has the first of these types in which its value
can be represented: int, long int; if the value cannot be represented as a
long int, the behaviour is undefined.
Rule 6.1 (avoids)
Rule 13.6 (direct)
No auto
QAC++
partial
PC-Lint
partial
18 2.13.2 Character Literals (para 3) – Escape Sequence
If the character following a back-slash is not one of those specified, the
behaviour is undefined.
Rule 6.4 (direct) QAC++
19 2.13.4 String Literals (para 2, 3)
The effect of attempting to modify a string literal is undefined.
In translation phase 6, adjacent narrow string literals are concatenated and
adjacent wide string literals are concatenated. If a narrow string literal token
is adjacent to a wide string literal token, the behaviour is undefined.
Rule 13.6 (direct)
Rule 6.5 (direct)
QAC++
partial
PC-Lint
partial
QAC++
23,
243 Basic Concepts
3.2 One Definition Rule (para 5)
If D is a template, and is defined in more than one translation unit, then the
last four requirements from the list above shall apply to names from the
template’s enclosing scope used in the template definition, and also to
dependant names at the point of instantiation. If the definitions of D satisfy
all these requirements, then the program shall behave as if there were a
single definition of D. If the definitions of D do not satisfy these
requirements, then the behaviour is undefined.
Rule 8.1.3 (direct)
Rule 8.3.4 (direct)
Rule 16.2
QAC++
QAC++
PC-Lint
partial
44 3.6.1 Main Function (para 4)
If exit is called to end a program during the destruction of an object with
static storage duration, the program has undefined behaviour.
Rule 5.9 (avoids) QAC++
46 3.6.3 Termination (para 2)
If a function contains a local object of static storage duration that has been
destroyed and the function is called during the destruction of an object with
static duration, the program has undefined behaviour if the flow of control
passes through the definition of the previously destroyed object.
Rule 5.9 (avoids)
Rule 8.2.2 (avoids)
QAC++
QAC++
10-2
Page Item / Description Control Enforced
48 3.7.3.1 Allocation Functions (para 2)
The effect of de-referencing a pointer returned as a request for zero size is
undefined.
New Rule (17) QAC++
partial
PC-Lint
partial
49 3.7.3.2 De-allocation Functions (para 4)
If the argument given to a de-allocation function in the standard library is a
pointer that is not the null pointer value, the de-allocation function shall de-
allocate the storage referenced by the pointer, rendering invalid all pointers
referring to any part of the de-allocated storage. The effect of using an
invalid pointer value (including passing it to a de-allocation function) is
undefined.
Rule 12.2 (direct)
Rule 12.8 (avoids)
QAC++
QAC++
partial
PC-Lint
partial
49-
513.8 Object Lifetime (para 4, 5, 6, 8, 9)
A program may end the lifetime of any object by reusing the storage which
the object occupies or by explicitly calling the destructor for an object of a
class type with a non-trivial destructor. For an object of a class type with
non-trivial destructor, the program is not required to call the destructor
explicitly before the storage which the object occupies is reused or released.
However if there is no explicit call to the destructor, the destructor shall not
be implicitly called and any program that depends on the side effects
produced by the destructor has undefined behaviour.
Before the lifetime of an object has started but after the storage which the
object will occupy has been allocated or, after the lifetime of an object has
ended and before the storage which the object occupied is reused or
released, any pointer that refers to the storage location where the object will
be or was located may be used but only in limited ways. If the object will be
or was of a class type with a non-trivial destructor, and the pointer is used as
the operand of a deleted-expression, the program has undefined behaviour.
If the object will be or was of non-POD class type, the program has
undefined behaviour in several cases.
Similarly, before the lifetime of an object has started but after the storage
which the object will occupy has been allocated or, after the lifetime of an
object has ended and before the storage which the object occupied is reused
or released, any lvalue which refers to the original object may be used but
only in limited ways. If an lvalue-to-rvalue conversion is applied to such an
lvalue, the program has undefined behaviour; if the original object will be or
was of a non-POD class type, the program has undefined behaviour in
several cases.
If a program ends the lifetime of an object of type T with static or automatic
storage duration and if T has a non-trivial destructor, the program must
ensure than an object of the original type occupies that same storage location
when the implicit destructor call takes place; otherwise the behaviour of the
program is undefined.
Creating a new object at the storage location that a const object with static or
automatic storage duration occupies or, at the storage location that such a
const object used to occupy before its lifetime ended results in undefined
behaviour.
Rule 12.2 (avoids)
May impact on
multithreaded
applications
May impact on
multithreaded
applications
Rule 8.2.2 (avoids)
Rule 12.2 (avoids)
QAC++
QAC++
QAC++
57 3.10 Lvalues and Rvalues (para 15)
If a program attempts to access the stored value of an object through an
lvalue of other than one of the following (listed) types the behaviour is
undefined.
Rule 13.6 (direct) QAC++
partial
PC-Lint
partial
60 4 Standard Conversions
4.1 Lvalue-to-rvalue Conversion (para 1)
An lvalue of a non-function, non-array type T can be converted to an rvalue.
If T is an incomplete type, a program that necessitates this conversion is ill-
formed. If the object to which the lvalue refers is not an object of type T or
is not an object derived from type T, or if the object is un-initialised, a
program that necessitates this conversion has undefined behaviour.
Rule 7.8 (direct)
Guideline 10.7
(direct)
QAC++
QAC++
10-3
Page Item / Description Control Enforced
62 4.8 Floating Point Conversions (para 1)
An rvalue of a floating point type can be converted to an rvalue of another
floating point type. If the source value can be exactly represented in the
destination type, the result of the conversion is that exact representation. If
the source value is between two adjacent destination values, the result of the
conversion is an implementation-defined choice of either of those values.
Otherwise, the behaviour is undefined.
Rule 10.15 (direct)
Rule 10.14 (direct)
Guideline 10.7
(direct)
QAC++
QAC++
QAC++
62 4.9 Floating Integral Conversion (para 1)
An rvalue of a floating point type can be converted to an rvalue of an integer
type. The conversion truncates; that is the fractional part is discarded. The
behaviour is undefined if the truncated value cannot be represented in the
destination type.
Rule 7.6 (avoids)
Guideline 10.7
(direct)
QAC++
QAC++
65 5 Expressions (para 4, 5)
If during the evaluation of an expression, the result is not mathematically
defined or not in the range of representable values for its type, the behaviour
is undefined, unless such an expression is a constant expression, in which
case the program is ill-formed.
Between the previous and next sequence point a scaler object shall have its
stored value modified at most once by the evaluation of an expression.
Further, the prior value shall be accessed only to determine the value to be
stored. The requirements of this paragraph shall be met for each allowable
ordering of the sub-expressions of a full expression, otherwise the behaviour
is undefined.
Rule 10.13 (direct)
Rule 10.17 (direct)
Rule 10.18 (direct)
ISO C++ Compiler
QAC++
QAC++
No auto
68,
705.2.2 Function Calls (para 1, 7)
Calling a function through an expression whose function type has a language
linkage that is different from the language linkage of the function type of the
called function’s definition is undefined.
When there is no parameter for a given argument, the argument is passed in
such a way that the receiving function can obtain the value of the argument
by invoking va_arg. The lvalue-to-rvalue, array-to-pointer, and function-to-
pointer standard conversions are performed on the argument expression. If
the argument has a non-POD class type, the behaviour is undefined.
New Guideline
(18)
Rule 10.3 (direct)
Rule 11.6 (avoids)
No auto
QAC++
QAC++
74 5.2.9 Static Cast (para 5, 8, 9)
An lvalue of type “cv1 B”, where B is a class type, can be cast to type
“reference to cv2 D”, where D is a class derived from B, if a valid standard
conversion from “pointer to D” to “pointer to B” exists, cv2 is the same cv-
qualification as, or greater cv-qualification than, cv1, and B is not a virtual
base class of D. The result is an lvalue of type “cv2 D”. If the lvalue of type
“cv1 B” is actually a sub-object of an object of type D, the lvalue refers to
the enclosing object of type D. Otherwise, the result of the cast is undefined.
An rvalue of type “pointer to cv1 B”, where B is class type, can be
converted to an rvalue of type “pointer to cv2 D”, where D is class derived
from B, if a valid standard conversion from “pointer to D” to “pointer to B”
exists. Cv2 is the same cv-qualification as, or greater cv-qualification than,
cv1, and B is not a virtual base class of D. The null pointer value is
converted to the null pointer value of the destination type. If the rvalue of
type “pointer to cv1 B” points to a B that is actually a sub-object of an
object of type D, the resulting pointer points to the enclosing object of type
D. Otherwise, the result of the cast is undefined.
An rvalue of type “pointer to member of D of type cv1 T” can be converted
to an rvalue of type “pointer to member of B of type cv2 D”, where B is a
base class of D, if a valid standard conversion from “pointer to member of B
of type T” to “pointer to member of D of type T” exists, and cv2 is the same
cv-qualification as, or greater cv-qualification than, cv1. The null pointer
value is converted to the null pointer value of the destination type. If class B
contains the original member, or is a base or derived class of the class
containing the original member, the resulting pointer to member points to
the original member. Otherwise, the result of the cast is undefined.
Rule 7.5 (direct)
Guideline 7.2
(avoids)
QAC++
QAC++
10-4
Page Item / Description Control Enforced
76 5.2.10 Reinterpret Cast (para 6)
A pointer to a function can be explicitly converted to a pointer to a function
of different type. The effect of calling a function through a pointer to
function type that is not the same as the type used in the definition of the
function is undefined.
Rule 7.5 (direct)
Guideline 7.2
(avoids)
QAC++
QAC++
77 5.2.11 Const Cast (para 7, 12)
Depending on the type of the object, a write operation through the pointer,
lvalue or pointer to data member resulting from a const_cast that casts
away a const qualifier may produce undefined behaviour.
Note: some conversions which involve only changes in cv-qualification
cannot be done using const_cast. For instance, conversions between
pointers to functions are not covered because such conversions lead to
values whose use can cause undefined behaviour.
Rule 7.3 (direct)
Guideline 7.2
(avoids)
QAC++
QAC++
79 5.3.1 Unary Operators (para 4)
The address of an object of incomplete type can be taken, but if the complete
type of that object is a class type that declares operator&() as a member
function, then the behaviour is undefined.
Rule 3.1.13
(avoids)
QAC++
81 5.3.4 New (para 6)
Every constant expression in a direct-new-declarator shall be an integral
constant expression and evaluate to a strictly positive value. The expression
in a direct-new-declarator shall have integral or enumeration type with a
non-negative value. If the value is negative, the effect is undefined.
New Rule (17) QAC++
partial
PC-Lint
partial
83,
845.3.5 Delete (para 2, 3, 5)
In delete object, the value of the operand of delete shall be a pointer to a
non-array object or pointer to a sub-object representing a base class of such
an object. If not, the behaviour is undefined. In delete array, the value of the
operand of delete shall be the pointer value that previously results from a
previous array new expression. If not, the behaviour is undefined.
In delete object, if the static type of the operand is different from its dynamic
type, the static type of the base class of the operand’s dynamic type and the
static type shall have a virtual destructor or the behaviour is undefined. In
delete array, if the dynamic type of the object to be deleted differs from its
static type, the behaviour is undefined.
If the object being deleted has incomplete class type at the point of deletion
and the complete class has a non-trivial destructor or de-allocation function,
the behaviour is undefined.
Rule 12.2 (direct)
Rule 12.3 (direct)
Rule 3.3.2 (direct)
Rule 8.4.9 (avoids)
Rule 3.1.13
(avoids)
QAC++
QAC++
QAC++
QAC++
QAC++
85-
865.5 Pointer to Member Operators (para 4, 6)
If the dynamic type of the object does not contain the member to which the
pointer refers, the behaviour is undefined.
If the result of .* or ->* is a function, then that result can only be used as
the operand for the function call operator ().
(ptr_to_obj->*ptr_to_mfct)(10);
This code calls the member function denoted by ptr_to_mfct for the
object pointer to by ptr_to_obj. The result of an .* expression is an
lvalue only if its first operand is an lvalue and its second operand is a pointer
to data member. The result of an ->* expression is an lvalue only if its
second operand is a pointer to data member. If the second operand is the null
pointer to member value, the behaviour is undefined.
Guideline 8.4.10
(avoids)
QAC++
86 5.6 Multiplicative Operators (para 4)
The binary / operator yields the quotient, and the binary % operator yields
the remainder from the division of the first expression by the second. If the
second operand of / or % is zero the behaviour is undefined.
Rule 10.17 (direct) QAC++
10-5
Page Item / Description Control Enforced
87 5.7 Additive Operators (para 5, 6)
When an expression that has integral type is added or subtracted from a
pointer, the result has the type of the pointer operand. If the pointer operand
points to an element of an array object, and the array is large enough, the
result points to an element offset from the original element such that the
difference of the subscripts of the resulting and original array elements
equals the integral expression. If both the pointer operand and the result
point to elements of the same array object, or one past the last element of the
array object, the evaluation shall not produce an overflow; otherwise the
behaviour is undefined.
When two pointers to elements of the same array are subtracted, the result is
the difference of the subscripts of the two array elements. If the result does
not fit within the space provided, the behaviour is undefined. Unless both
pointers point to elements of the same array object, or one past the last
element of the array object, the behaviour is undefined.
Rule 10.2 (direct)
Rule 8.4.9 (avoids)
QAC++
No auto
88 5.8 Shift Operators (para 1)
The behaviour is undefined if the right operand is negative, or greater than
or equal to the length in bits of the promoted left operand.
Rule 10.11 (direct)
Rule 10.12 (direct)
QAC++
QAC++
92 5.17 Assignment Operators (para 8)
If the value being stored in an object is accessed from another object that
overlaps in any way the storage of the first object, then the overlap shall be
exact and the two objects shall have the same type, otherwise the behaviour
is undefined.
Rule 13.6 (direct) QAC++
partial
PC-Lint
partial
100 6 Statements
6.6.3 The return Statement (para 2)
Flowing off the end of a function is equivalent to a return with no value; this
results in undefined behaviour in a value returning function.
Rule 5.10 (direct) QAC++
101 6.7 Declaration Statement (para 4)
If control re-enters the declaration (recursively) while the object is being
initialised, the behaviour is undefined.
New Rule (6) QAC++
Partial
109-
1107 Declarations
7.1.5.1 The cv-qualifiers (para 4, 7)
Except that any class member declared mutable can be modified, any
attempt to modify a const object during its lifetime results in undefined
behaviour.
If an attempt is made to refer to an object defined with a volatile-qualified
type through the use of an lvalue with a non-volatile-qualified type, the
program behaviour is undefined.
Rule 7.4 (direct)
Rule 7.3 (direct)
QAC++
QAC++
137 8 Declarators
8.3.2 References (para 4)
A null reference cannot exist in a well defined program, because the only
way to create such a reference would be to bind it to the “object” obtained
by dereferencing a null pointer, which causes undefined behaviour.
New Rule (10) QAC++
partial
PC-Lint
partial
161 9 Classes
9.3.1 Non-static Member Functions (para 1)
If a nonstatic member function of a class X is called for an object that is not
of type X, or if a type derived from X, the behaviour is undefined.
Rule 7.1 (avoids)
Guideline 7.2
(avoids)
QAC++
QAC++
179 10 Derived Classes
10.4 Abstract Classes (para 6)
Member functions can be called from a constructor (or destructor) of an
abstract class; the effect of making a virtual call to a pure virtual function
directly or indirectly for the object being created (or destroyed) from such a
constructor (or destructor) is undefined.
Rule 3.3.13 (direct) QAC++
10-6
Page Item / Description Control Enforced
201,
20212 Special Member Functions
12.4 Destructors (para 12, 14)
The invocation of a destructor is subject to the usual rules for member
functions, that is, if the object is not of the destructor’s class type and not of
a class derived from the destructor’s class type, the program has undefined
behaviour (except that invoking delete on a null pointer has no effect).
Once a destructor is invoked for an object, the object no longer exists; the
behaviour is undefined if the destructor is invoked for an object whose
lifetime has ended.
Rule 7.1 (avoids)
Guideline 7.2
(avoids)
Rule 12.8 (avoids)
QAC++
QAC++
No auto
208 12.6.2 Initialising Bases and Members (para 8)
Member functions can be called for an object under construction. Similarly,
an object under construction can be the operand of the type_id operator or
of a dynamic_cast. However, if these operations are performed in a ctor-
initialiser (or in a function called directly or indirectly from a ctor-initialiser)
before all mem-initialisers for base classes have completed, the result of the
operation is undefined.
New Rule (5)
New Rule (2)
Guideline 7.2
(avoids)
QAC++
No auto
QAC++
209-
21112.7 Construction and Destruction (para 1, 2, 3, 4, 5)
For an object of non-POD class type, before the constructor begins
execution and after the destructor finishes execution, referring to any non-
static member or base class of the object results in undefined behaviour.
To explicitly or implicitly convert a pointer (lvalue) referring to an object of
class X to a pointer (reference) to a direct or indirect case class B of X, the
construction of X and the construction of all of its direct or indirect bases
that directly or indirectly derive from B shall have started and the
destruction of these classes shall not have completed, otherwise the
conversion results in undefined behaviour.
To form a pointer to (or access the value of) a direct non-static member of
an object obj, the construction of obj shall have started and its destruction
shall not have completed, otherwise the computation of the pointer value (or
accessing the member value) results in undefined behaviour.
If the virtual function call uses an explicit class member access and the
object-expression refers to the object under construction or destruction but
its type is neither the constructor or destructor’s own class or one of its
bases, the result of the call is undefined.
If the operand of type_id refers to the object under construction or
destruction and the static type of the operand is neither the constructor or
destructor’s class nor one of its bases, the result of typeid is undefined.
If the operand of the dynamic_cast refers to the object under construction
or destruction and the static type of the operand is not a pointer to or object
of the constructor or destructor’s own class or one of its bases, the
dynamic_cast results in undefined behaviour.
Rule 12.8 (avoids)
Rule 7.1 (direct)
Guideline 7.2
(avoids)
No auto
QAC++
QAC++
279 14 Templates
14.6.4.2 Candidate Functions (para 1)
If the call would be ill-formed or would find a better match had the lookup
within the associated namespaces considered all the function declarations
with external linkage introduced in those namespaces in all translations
units, not just considering those declarations found in the template definition
and template instantiation contexts, then the program has undefined
behaviour.
Rule 8.3.4 (direct)
Guideline 8.3.2
(direct)
Rule 14.13
QAC++
partial
PC-Lint
partial
No auto
283 14.7.1 Implicit Instantiation (para 14)
The result of an infinite recursion in instantiation is undefined.
Rule 13.3 (avoids) No auto
10-7
Page Item / Description Control Enforced
309,
31015 Exception Handling
15.3 Handling an Exception (para 10, 16)
Referring to any non-static member or base class of an object in the handler
for a function-try-block of a constructor or destructor for that object results
in undefined behaviour.
Flowing off the end of a function-try-block is equivalent to a return with no
value; this results in undefined behaviour in a value-returning function.
New Rule (14)
New Rule (14) QAC++
316 16 Preprocessing Directives
16.1 Conditional Inclusion (para 4)
If the token defined is generated as a result of this replacement process or
use of the defined unary operator does not match one of the two specified
forms prior to macro replacement, the behaviour is undefined.
Rule 14.5 (avoids) QAC++
318 16.2 Source File Inclusion (para 4)
If the directive resulting after all replacements does not match one of the two
previous forms, the behaviour is undefined.
Rule 14.9 (direct) QAC++
319 16.3 Macro Replacement (para 10)
If (before argument substitution) any argument consists of no pre-processing
tokens, the behaviour is undefined.
If there are sequences of pre-processing tokens within the list of arguments
that would otherwise act as pre-processing directives, the behaviour is
undefined.
Rule 14.14 (avoids) QAC++
320 16.3.2 The # Operator (para 2)
If, in the replacement list, a parameter is immediately preceded by a # pre-
processing token, both are replaced by a single character literal pro-
processing token that contains the spelling of the pre-processing token
sequence for the corresponding argument. If the replacement that results is
not a valid character string literal, the behaviour is undefined.
New Rule (19) QAC++
320 16.3.3 The # # Operator (para 3)
For both object-like and function-like macro invocations, before the
replacement list is re-examined for more macro names to replace, each
instance of a # # pre-processing token in this replacement list (not from an
argument) is deleted and the preceding pre-processing token is concatenated
with the following pre-processing token. If the result is not a valid pre-
processing token, the behaviour is undefined.
New Rule (19) QAC++
322 16.4 Line Control (para 3, 5)
A pre-processing directive of the form
# line digit-sequence new-line
If the digit sequence specifies zero or a number greater than 32767, the
behaviour is undefined.
A pre-processor directive of the form
# line pp-tokens new-line
If the directive resulting after all replacements does not match one of the two
previous forms, the behaviour is undefined; otherwise the result is processed
as appropriate.
New Rule (20) No auto
323 16.8 Predefined Macro Names (para 3)
If any of the pre-defined macro names in this subclause, or the identifier
defined, is the subject of a #define or a #undef pre-processing directive,
the behaviour is undefined.
Rule 13.1 (avoids)
Rule 13.4 (avoids)
QAC++
partial
PC-Lint
partial
QAC++
Table 10-1: C++ Language Undefined Behaviour [BSI03]
11-1
Appendix 11 – Undefined Behaviour (C++ STL)
The following table details undefined behaviour in the C++ STL and the applicable controls that
can be put in place to mitigate them. The behaviours have been extracted directly from [BSI03].
Page Item / Description Control Enforced
327 17 Library Introduction
17.1.15 Required Behaviour
If a function defined in the C++ program fails to meet the required
behaviour when it executes, behaviour is undefined.
Use a validated
compiler and STL
implementation
N/A
336 17.4.3.1 Reserved Names (para 1, 3)
It is undefined for a C++ program to add declarations or definitions to
namespace std or namespaces with namespace std unless otherwise
specified. A program may add specialisations for any standard library
template to namespace std. Such a specialisation (complete or partial) of a
standard library template results in undefined behaviour unless the
declaration depends on a user-defined name of external linkage and unless
the specialisation meets the standard library requirements for the original
template.
If a program declares or defines a name in a context where it is reserved,
other than as explicitly allowed, the behaviour is undefined.
Use a validated ISO
C++ compiler and
STL set
Rule 8.3.4 (direct) QAC++
partial
PC-Lint
partial
337 17.4.3.2 Headers (para 1)
If a file with a name equivalent to the derived file name for one of the C++
Standard Library headers is not provided as part of the implementation, and
a file with that name is placed in any of the standard places for a source file
to be included, the behaviour is undefined.
Use a ISO C++
compiler and
library set
338 17.4.3.7 Function Arguments (para 1)
If an argument to a function has an invalid value (such as a value outside the
domain of the function, or a pointer invalid for its intended use), the
behaviour is undefined.
New Rule (27)
New Rule (32)
No auto
No auto
339 17.4.3.8 Required Paragraph (para 1)
Violation of the preconditions specified in a function’s Required Behaviour
paragraph results in undefined behaviour unless the function’s Throw
paragraph specifies throwing an exception when the pre-condition is
violated.
New Rule (27)
New Rule (32)
No auto
No auto
344 18 Language Support Library
18.1 Types (para 5)
The macro offsetof accepts a restricted set of type arguments in this
International Standard. Type shall be POD structure and POD union. The
result of applying the offsetof macro to a field that is a static data member
or a function member is undefined.
New Rule (28) No auto
364 18.7 Other Runtime Support (para 3, 5)
The restrictions that ISO C places on the second parameter to the
va_start() macro in header <stdarg.h> are different in this
International Standard. If the parameter parmN is declared within a function,
array, or reference type, or with a type that is not compatible with the type
that results when passing an argument for which there is no parameter, the
behaviour is undefined.
The function signature longjmp(jmp_buf jbuf, int val) has more
restricted behaviour in this International Standard. If any automatic objects
would be destroyed by a thrown exception transferring control to another
point in the program, then a call to longjmp(jbuf, val) at the throw
point that transfers control to the same point has undefined behaviour.
Rule 17.1 (avoids) QAC++
11-2
Page Item / Description Control Enforced
391 20 General Utilities Library
20.4.5 Class Template auto_ptr (para 3)
If more than one auto_ptr owns the same object at the same time the
behaviour is undefined.
The uses of auto_ptr include providing temporary exception-safety for
dynamically allocated memory, passing ownership of dynamically allocated
memory to a function, and returning dynamically allocated memory from a
function. auto_ptr does not meet the CopyConstructible and Assignable
requirements for Standard Library container elements and thus instantiating
a Standard Library container with an auto_ptr results in undefined
behaviour.
Rule 17.8 (direct)
Guideline 17.21
(direct)
No auto
No auto
411 21 String Library
21.3.4 basic_string Element Access (para 1)
const_reference operator[](size_type pos) const;reference operator[](size_type pos);
If pos < size(), returns data()[pos]. Otherwise, if pos ==
size(), the const version returns charT(). Otherwise the behaviour is
undefined.
New Rule (27)
New Rule (32)
No auto
No auto
501 23 Containers Library
23.2.2.4 list Operations (para 12)
void splice(iterator position, list<T,Allocator>& x,iterator first, iterator last);
The result is undefined if position is an iterator in the range [first, last].
New Rule (27) No auto
534 24 Iterator Library
24.1 Iterator Requirements (para 5, 7)
Results of most expressions are undefined for singular values; the only
exception is an assignment of a non-singular value to an iterator that holds
for a singular value.
The result of the application of functions in the library to invalid ranges is
undefined.
New Rule (29)
New Rule (27)
No auto
No auto
557 24.5.3 Class Template istreambuf_interator (para 2)
The result of operator*() on an end of stream is undefined.
New Rule (27) No auto
592 26 Numerics Library
26.1 Numeric Type Requirements (para 2, 3)
If any operation on T throws an exception the effects are undefined.
In addition, many member and related functions of valarray<T> can be
successfully instantiated and will exhibit well-defined behaviour if and only
if T satisfies additional requirements specified for each such member or
related function.
New Rule (30)
Rule 17.9 (avoids)
New Rule (27)
No auto
No auto
No auto
605 26.3.2.1 valarray Constructors (para 4)
valarray(const T*, size_t);
If the value of the second argument is greater than the number of values
pointed to by the first argument, the behaviour is undefined.
Rule 17.9 (avoids)
New Rule (27)
No auto
No auto
11-3
Page Item / Description Control Enforced
605-
60626.3.2.2 valarray Assignment (para 1, 4)
valarray<T>& operator=(const valarray<T>&);
The resulting behaviour is undefined if the length of the argument array is
not equal to the length of the *this array.
Valarray<T>& operator=(const slice_array<T>&);Valarray<T>& operator=(const gslice_array<T>&);Valarray<T>& operator=(const mask_array<T>&);Valarray<T>& operator=(const indirect_array<T>&);
If the value of the element in the left hand side of a valarray assignment
operator depends on the value of another element in that left hand side, the
resulting behaviour is undefined.
Rule 17.9 (avoids)
New Rule (27)
No auto
No auto
606 26.3.2.3 valarray Element Access (para 6)
T operator[] (size_t) const;T& operator[] (size_t);
If the subscript operator is invoked with a size_t argument whose value is
not less than the length of the array, the behaviour is undefined.
Rule 17.9 (avoids)
New Rule (27)
No auto
No auto
607 26.3.2.6 valarray Computer Assignment (para 3, 4)
valarray<T>& operator*= (const valarray<T>&);valarray<T>& operator/= (const valarray<T>&);valarray<T>& operator%= (const valarray<T>&);valarray<T>& operator+= (const valarray<T>&);valarray<T>& operator-= (const valarray<T>&);valarray<T>& operator^= (const valarray<T>&);valarray<T>& operator|= (const valarray<T>&);valarray<T>& operator<<= (const valarray<T>&);valarray<T>& operator>>= (const valarray<T>&);
If the array and the argument array do not have the same length, the
behaviour is undefined.
If the value of an element in the left hand side of a valarray computed
assignment depends on the value of another element in that left hand side,
the resulting behaviour is undefined.
Rule 17.9 (avoids)
New Rule (27)
No auto
No auto
608 26.3.2.7 valarray Member Function (para 2, 3, 4)
T sum() const;T min() const;T max() const;
If the array has length 0, the behaviour is undefined.
Rule 17.9 (avoids)
New Rule (27)
No auto
No auto
11-4
Page Item / Description Control Enforced
609 26.3.3.1 valarray Binary Operators (para 3)
template<class T> valarray<T> operator* (constvalarray<T>&, const valarray<T>&);
template<class T> valarray<T> operator/ (constvalarray<T>&, const valarray<T>&);
template<class T> valarray<T> operator% (constvalarray<T>&, const valarray<T>&);
template<class T> valarray<T> operator+ (constvalarray<T>&, const valarray<T>&);
template<class T> valarray<T> operator- (constvalarray<T>&, const valarray<T>&);
template<class T> valarray<T> operator& (constvalarray<T>&, const valarray<T>&);
template<class T> valarray<T> operator| (constvalarray<T>&, const valarray<T>&);
template<class T> valarray<T> operator<< (constvalarray<T>&, const valarray<T>&);
template<class T> valarray<T> operator>> (constvalarray<T>&, const valarray<T>&);
If the argument arrays do not have the same length, the behaviour is
undefined.
Rule 17.9 (avoids)
New Rule (27)
No auto
No auto
610 26.3.3.2 valarray Logical Operators (para 3)
template<class T> valarray<T> operator== (constvalarray<T>&, const valarray<T>&);
template<class T> valarray<T> operator!= (constvalarray<T>&, const valarray<T>&);
template<class T> valarray<T> operator< (constvalarray<T>&, const valarray<T>&);
template<class T> valarray<T> operator> (constvalarray<T>&, const valarray<T>&);
template<class T> valarray<T> operator<= (constvalarray<T>&, const valarray<T>&);
template<class T> valarray<T> operator>= (constvalarray<T>&, const valarray<T>&);
template<class T> valarray<T> operator&& (constvalarray<T>&, const valarray<T>&);
template<class T> valarray<T> operator|| (constvalarray<T>&, const valarray<T>&);
If the argument arrays do not have the same length, the behaviour is
undefined.
Rule 17.9 (avoids)
New Rule (27)
No auto
No auto
615 26.3.6 The gslice Class (6)
If a degenerate slice is being used as the argument to the non-const version
of operator[](const gclice&), the resulting behaviour is undefined.
Rule 17.9 (avoids)
New Rule (27)
No auto
No auto
619 26.3.9.2 indirect_array Assignment (para 2)
void operator=(const valarray<T>&) const;indirect_array& operator=(const indirect_array&);
If the indirect_array specifies an element in the valarray<T> object to
which it refers more than once, the behaviour is undefined.
Rule 17.9 (avoids)
New Rule (27)
No auto
No auto
11-5
Page Item / Description Control Enforced
620 26.3.9.3 indirect_array Computed Assignment (para 2)
void operator*= (const valarray<T>&) const;void operator/= (const valarray<T>&) const;void operator%= (const valarray<T>&) const;void operator+= (const valarray<T>&) const;void operator-= (const valarray<T>&) const;void operator^= (const valarray<T>&) const;void operator&= (const valarray<T>&) const;void operator|= (const valarray<T>&) const;void operator<<= (const valarray<T>&) const;void operator>>= (const valarray<T>&) const;
If the indirect_array specifies an element in the valarray<T> object to
which it refers more than once, the behaviour is undefined.
Rule 17.9 (avoids)
New Rule (27)
No auto
No auto
625 27 Input/Output Library
27.1.1 imbue Limitations
No function described in clause 27 except for ios_base::imbue causes an
instance of basic_ios::imbue or basic_streambuf::imbue to be
called. If any user function called from a function declared in clause 27 or as
an overriding virtual function of any class declared in clause 27 calls imbue,
the behaviour is undefined.
New Rule (31) No auto
639 27.4.3.2 fpos Requirements (para 2)
Stream operations that return a value of type traits::pos_type return
P(O(-1)) as an invalid value to signal an error. If this value is used as an
argument to any iostream, ostream, or streambuf member that accepts
a value of type traits::pos_type then the behaviour of that function is
undefined.
New Rule (27) No auto
641 27.4.4.1 basic_ios Constructors
basic_ios();
Constructs an object of class basic_ios leaving its member objects
uninitialised. The object must be initialised by calling its init member
function. If it is destroyed before it has been initialised the behaviour is
undefined.
New Rule (27) No auto
680 27.7.1.3 Overridden Virtual Function (para 14)
Alters the stream position within the controlled sequences, if possible, to
correspond to the stream position stored in sp (as described below).
If sp is an invalid stream position, or if the function positions neither
sequence, the positioning operation fails. If sp has not been obtained by a
previous successful call to one of the positioning functions (seekoff,
seekpos, tellg, tellb) the effect is undefined.
New Rule (27) No auto
685 27.8.1.1 Class Template basic_filebuf (para 4)
An instance of basic_filebuf behaves as described in 27.8.1.1 provided
traits::pos_type is fpos<traits::state_type>. Otherwise the
behaviour is undefined.
New Rule (27) No auto
689 27.8.1.4 Overridden Virtual Functions (para 14)
pos_type seekpos(pos_type sp, ios_base::openmode which =ios_base::in | ios_base::out);
If sp has not been obtained by a previous successful call to one of the
positioning functions (seekoff or seekpos) on the same file the effects are
undefined.
New Rule (27) No auto
Table 11-1: C++ STL Undefined Behaviour [BSI03]
12-1
Appendix 12 – Implementation-Defined Behaviour (C++ Lang)
The following table details implementation-defined behaviour in the C++ language and the
applicable controls that can be put in place to mitigate them. The behaviours have been extracted
directly from [BSI03].
Page Item / Description Control Enforced
9, 10 2 Lexical Conventions
2.1 Phases of Translation (para 1, 3, 8)
Physical source file characters are mapped, in an implementation-defined
manner, to the basic source character set (introducing new-line characters
for end-of-line indicators) if necessary.
Whether each non-empty sequence of white space characters other than
new-line is retained or replaced by one space character is implementation-
defined.
The definitions of the required templates are located. It is implementation-
defined whether the source of the translation units containing these
definitions is required to be available.
Guideline 13.1
(supports)
Rule 14.8 (direct)
Use a complete ISO
C++ compiler and
STL
implementation
No auto
QAC++
10 2.2 Character Sets (para 3)
The values of the members of the execution character sets are
implementation-defined, and any additional members are locale-specific.
Guideline 13.1
(supports)
No auto
13 2.8 Header Names (para 1)
The sequences in both forms of header-names are mapped in an
implementation-defined manner to headers or external source file names as
specified in 16.2.
Rule 14.9 (direct)
Rule 14.10 (direct)
Rule 14.12 (direct)
Guideline 13.1
(supports)
QAC++
QAC++
QAC++
No auto
17-
182.13.2 Character Literals (para 1, 2, 4, 5)
A multi-character literal has type int and implementation-defined value.
The value of a wide-character literal containing multiple c-chars is
implementation-defined.
The value of a character literal is implementation-defined if it falls outside
of the implementation-defined range defined for char (for ordinary literals)
or wchar_t (for wide literals).
A universal-character-name is translated to the encoding, in the execution
character set, of the character named. If there is no such encoding, the
universal-character-name is translated to an implementation defined
encoding.
Guideline 13.1
(supports)
Rule 13.6 (direct)
No auto
QAC++
partial
19 2.13.3 Floating Literals (para 1)
If the scaled value is in the range of representable values for its type, the
result is the scaled value if representable, else the larger or smaller
representable value nearest the scaled value, chosen in an implementation-
defined manner.
Rule 10.14 (direct)
Rule 10.15 (avoids)
Guideline 13.1
(supports)
Rule 6.2 (direct)
QAC++
QAC++
No auto
QAC++
19 2.13.4 String Literals (para 2)
Whether all string literals are distinct (that is, are stored in non-overlapping
objects) is implementation-defined.
Rule 13.6 (direct)
Guideline 13.1
(supports)
QAC++
partial
PC-Lint
partial
No auto
12-2
Page Item / Description Control Enforced
44 3 Basic Concepts
3.6.1 Main Function (para 1, 2, 3)
A program shall contain a global function called main, which is the
designated start of the program. It is implementation-defined whether a
program on a free-standing environment is required to define a main
function.
An implementation shall not predefine the main function. This function
shall not be overloaded. It shall have a return type of type int, but
otherwise its type is implementation defined. It is recommended that any
further (optional) parameters be added after argv.
The function main shall not be used within a program. The linkage of main
is implementation defined.
Guideline 13.1
(supports)
No auto
QAC++
PC-Lint
45 3.6.2 Initialisation of Non-Local Objects (para 3)
It is implementation-defined whether or not the dynamic initialisation of an
object of namespace scope is done before the first statement of main.
Guideline 13.1
(supports)
Rule 8.2.2 (direct)
No auto
QAC++
partial
53 3.9 Types (para 4, 5)
For POD types, the value representation is a set of bits in the object
representation that determines a value, which is one discrete element of an
implementation-defined set of values.
The alignment of a complete object type is an implementation-defined
integer value representing a number of bytes; an object is allocated an
address that meets the alignment requirements of its object type.
Guideline 13.1
(supports)
Rule 13.6 (direct)
No auto
QAC++
partial
PC-Lint
partial
54-
553.9.1 Fundamental Types (para 1, 2, 5, 8)
Objects declared as characters (char) shall be large enough to store any
member of the implementation’s basic character set. It is implementation
defined whether a char can hold negative values. In any particular
implementation, a plain char object can take on either the same values as a
signed char or an unsigned char; which is implementation defined.
Plain ints have the natural size suggested by the architecture of the execution
environment; other signed integer types are provided to meet special needs.
Type wchar_t is a distinct type whose values can represent distinct codes
for all members of the largest extended character set specified among the
support locales.
The value representation of floating point types is implementation defined.
Specialisations of the standard template numeric limits shall specify the
maximum and minimum values of each arithmetic type for an
implementation.
Guideline 2.2
(direct)
Rule 8.4.5 (direct)
Guideline 8.4.13
(direct)
Guideline 13.1
(supports)
Guideline 13.6
(direct)
No auto
PC-Lint
partial
PC-Lint
partial
QAC++
Partial
No auto
QAC++
partial
PC-Lint
partial
56 3.9.2 Compound Types (para 3)
The value representation of pointer types is implementation-defined.
Guideline 13.1
(supports)
Rule 13.6 (direct)
No auto
QAC++
partial
PC-Lint
partial
12-3
Page Item / Description Control Enforced
62 4 Standard Conversions
4.7 Integral Conversions (para 3)
If the destination type is signed, the value is unchanged if it can be
represented in the destination type (and bit-field width); otherwise, the value
is implementation defined.
Guideline 13.1
(supports)
Guideline 8.4.13
(direct)
Guideline 10.7
(avoids)
Rule 10.13 (direct)
No auto
QAC++
partial
PC-Lint
partial
QAC++
QAC++
62 4.8 Floating Point Conversions (para 1)
If the source value is between two adjacent destination values, the result of
the conversion is an implementation-defined choice of either of these values.
Guideline 10.7
(direct)
Rule 10.14 (direct)
Rule 10.15 (direct)
Guideline 13.1
(supports)
QAC++
QAC++
QAC++
No auto
62 4.9 Floating-Integral Conversions (para 2)
An rvalue of an integer type or of an enumeration type can be converted to
an rvalue of a floating point type. The result is exact if possible. Otherwise it
is an implementation-defined choice of either the next lower or higher
representable value.
Rule 10.14 (direct)
Guideline 13.1
(supports)
QAC++
No auto
73 5 Expressions
5.2.8 Type Identification (para 1)
The result of a typeid expression is an lvalue of static type const
std::type_info and dynamic type const std::type_info or const
name where name is an implementation-defined class derived from
std::type_info which preserves the behaviour described in 18.5.1.
Guideline 13.1
(supports)
QAC++
76 5.2.10 Reinterpret Cast (para 3, 4, 5)
The mapping performed by reinterpret_cast is implementation-
defined.
A pointer can be explicitly converted to any integral type large enough to
hold it. The mapping function is implementation defined.
A value of an integral type or enumeration type can be explicitly converted
to a pointer. A pointer converted to an integer of sufficient size and back to
the same pointer type will have its original value; mappings between
pointers and integers are otherwise implementation-defined.
Guideline 7.2
(avoids)
Rule 7.5 (avoids)
Rule 7.7 (avoids)
Guideline 13.1
(supports)
QAC++
QAC++
QAC++
No auto
79 5.3.3 Sizeof (para 1)
sizeof(char), sizeof(signed char) and sizeof(unsigned char)
are 1; the result of sizeof applied to any other fundamental type is
implementation defined. In particular sizeof(bool) and
sizeof(wchar_t) are implementation defined.
Guideline 13.1
(supports)
Rule 13.6 (direct)
No auto
QAC++
partial
81 5.3.4 New (para 8)
An implementation shall provide default definitions for the global allocation
functions (3.7.3, 18.4.1.1, 18.4.1.2).
Guideline 13.1
(supports)
No auto
86 5.6 Multiplicative Operators (para 4)
The binary / operator yields the quotient, and the binary % operator yields
the remainder from the division of the first expression by the second. If both
operands are non-negative then the remainder is non-negative; if not the sign
of the remainder is implementation-defined.
Guideline 10.18
(direct)
Guideline 13.1
(supports)
QAC++
partial
PC-Lint
partial
87 5.7 Additive Operators (para 6)
When two pointers to elements of the same array object are subtracted, the
result is the difference of the subscripts of the two array elements. The type
of the result is an implementation-defined signed integral type; this type
shall be the same type that is defined as ptrdiff_t in the <cstddef>
header.
Guideline 13.1
(supports)
No auto
12-4
Page Item / Description Control Enforced
88 5.8 Shift Operators (para 3)
The value E1 >> E2 is E1 (interpreted as a bit pattern) left shifted E2 bit
positions. If E1 has an unsigned type or if E1 has a signed type and a
nonnegative value, the value result in the integral part of the quotient of E1
divided by the quantity 2 raised to the power E2. If E1 has a signed type and
a negative value, the resulting value is implementation-defined.
Rule 10.11 (direct)
Rule 10.12 (direct)
Guideline 13.1
(supports)
QAC++
QAC++
112 7 Declarations
7.1.5.2 Simple Type Specifiers (para 1)
It is implementation-defined whether bit-fields and objects of char type are
represented as signed or unsigned quantities.
Rule 2.2 (direct)
Rule 8.4.5 (direct)
Guideline 13.1
(supports)
Rule 13.6 (direct)
No auto
QAC++
partial
PC-Lint
partial
QAC++
partial
PC-Lint
partial
114 7.2 Enumeration Declarations (para 5)
It is implementation-defined which integral type is used in the underlying
type for an enumeration except that the underlying type shall not be larger
than int unless the value of an enumerator cannot fit in an int or
unsigned int.
Guideline 13.1
(supports)
Rule 13.6 (direct)
No auto
QAC++
partial
PC-Lint
partial
127 7.4 The asm Declaration (para 1)
The meaning of the asm declaration is implementation-defined.
Rule 13.5 (direct)
Guideline 13.1
(supports)
QAC++
No auto
128,
1307.5 Linkage Specification (para 1, 2, 3, 9)
Some of the properties associated with an entity with language linkage are
specific to each implementation and are not described here.
The string literal indicates the required language linkage. The meaning of
the string literal is implementation defined. A linkage-specification with a
string that is unknown to the implementation is ill-formed. When the string-
literal in a linkage-specification names a programming language, the
spelling of the programming language’s name is implementation defined.
The semantics of a language linkage other than C++ or C are
implementation defined.
Every implementation shall provide for linkage to functions written in the C
programming language, “C”, and linkage to C++ functions, “C++”.
Linkage from C++ to objects defined in other languages and to objects
defined in C++ from other languages is implementation-defined and
language-dependant.
Guideline 13.1
(supports)
New Guideline
(18)
Rule 14.6 (direct)
No auto
No auto
No auto
152 8 Declarators
8.5.3 References (para 5)
A reference to type “cv1 T1” is initialised by an expression if the initialiser
expression is an lvalue and “cv1 T1” is reference-compatible with “cv2 T2”,
or has a class type and can be implicitly converted to an lvalue of type “cv3
T3”, where “cv1 T1” is reference compatible with “cv3 T3”. Otherwise the
reference shall be to a non-volatile const type. If the initialiser expression is
an rvalue, with T2 a class type, and “cv1 T1” is reference-compatible with
“cv2 T2”, the reference is bound in one of the several ways (the choice is
implementation defined).
Guideline 13.1
(supports)
Guideline 10.7
(direct)
No auto
QAC++
166 9 Classes
9.6 Bit-Fields (para 1, 3)
Allocation of bit-fields within a class object is implementation defined.
Alignment of bit-fields is implementation-defined.
It is implementation defined whether a plain (neither explicitly signed or
unsigned) char, short, int or long bit-field is signed or unsigned.
Guideline 13.1
(supports)
Rule 13.6 (direct)
Rule 10.13 (direct)
Rule 2.2 (direct)
No auto
QAC++
partial
PC-Lint
partial
QAC++
No auto
12-5
Page Item / Description Control Enforced
246 14 Templates (para 4)
A template name has linkage. If the linkage of one of these is something
other than C or C++, the behaviour is implementation-defined.
Guideline 13.1
(supports)
New Guideline
(18)
No auto
No auto
283 14.7.1 Implicit Instantiation (para 14)
There is an implementation-defined quantity that specifies the limit of the
total depth of recursive instantiations, which could involve more than one
template.
Guideline 13.1
(supports)
Rule 13.3 (direct)
No auto
No auto
309 15 Exception Handling
15.3 Handling an Exception (para 9)
If no matching handler is found in a program, the function terminate() is
called; whether or not the stack is unwound before this call to
terminate() is implementation-defined.
Guideline 13.1
(supports)
No auto
313 15.5.2 The unexpected() Function (para 2)
If the exception-specification does not include the class
std::bad_exception then the function terminate() is called,
otherwise the thrown exception is replaced by an implementation-defined
object of the type std::bad_exception and the search for another
handler will continue at the call of the function whose exception-
specification was violated.
Guideline 13.1
(supports)
No auto
316,
31716 Preprocessing Directives
16.1 Conditional Inclusion (para 4)
This includes interpreting character literals, which may involve converting
escape sequences into execution character set members. Whether the
numeric character value for these character literals matches the value
obtained when an identical character literal occurs in the expression (other
than within a #if or #elif directive) is implementation-defined.
Also, whether a single-character character literal may have a negative value
is implementation-defined.
Guideline 13.1
(supports)
Guideline 8.4.13
(direct)
Rule 6.4 (direct)
No auto
QAC++
QAC++
317,
31816.2 Source File Inclusion (para 2, 3, 4, 5, 6)
A preprocessor directive of the form# include <h-char-sequence> new-line
searches a sequence of implementation-defined places for a header identified
uniquely by the specified sequence between the < and > delimiters, and
causes the replacement of that directive by the entire contents of the header.
How the places are specified or the header identified is implementation-
defined.
A preprocessor directive of the form# include “q-char-sequence” new-line
causes the replacement of that directive by the entire contents of the source
file identified by the specified sequence between the “ delimiters. The names
source file is searched in an implementation-defined manner.
A preprocessor directive of the form# include pp-tokens new-line
is permitted. The method by which the sequence of preprocessing tokens
between a < and a > preprocessing token pair or a pair of “ characters is
combined into a single header name preprocessing token is implementation
defined.
The mapping between the delimited sequence and the external source file
name is implementation defined.
A #include preprocessing directive may appear in a source file that has been
read because of a #include directive in another a file, up to an
implementation-defined nesting limit.
Guideline 13.1
(supports)
Rule 14.9 (direct)
Rule 14.10 (direct)
Rule 14.12 (direct)
No auto
QAC++
QAC++
QAC++
12-6
Page Item / Description Control Enforced
323 16.6 Pragma Directive (para 1)
A preprocessing directive of the form
# pragma pp-tokensopt new-line
causes the implementation to behave in an implementation-defined manner.
Guideline 13.1
(supports)
Rule 13.4 (direct)
No auto
QAC++
323 16.8 Predefined Macro Names (para 1)
The following macro names shall be defined by the implementation:
__LINE__
__FILE__
__DATE__: If the date of translation is not available, an implementation-
defined valid date is supplied.
__TIME__: If the time of translation is not available, an implementation-
defined valid time is supplied.
__STDC__: Whether __STDC__ is predefined and if so, what its value is, is
implementation-defined.
__cplusplus
Guideline 13.1
(supports)
Rule 13.4 (direct)
No auto
QAC++
Table 12-1: C++ Language Implementation-Defined Behaviour [BSI03]
13-1
Appendix 13 – Implementation-Defined Behaviour (C++ STL)
The following table details implementation-defined behaviour in the C++ STL and the applicable
controls that can be put in place to mitigate them. The behaviours have been extracted directly from
[BSI03].
Page Item / Description Control Enforced
330 17 Library Introduction
17.3.2.1 Type Descriptions (para 2)
Certain types described in this clause are used to describe implementation-
define types, and member function.
Noted control not
required
N/A
330 17.3.2.1.1 Enumeration Types (para 1)
Each enumerated type may be implemented as an enumeration or as a
synonym for an enumeration.
Rule 13.6 (avoids) No auto
335 17.4.1.3 Freestanding Implementations (para 2)
A freestanding implementation has an implementation-defined set of
headers. This set shall include at the least the following headers: <cstddef>,
<limits>, <cstdlib>, <new>, <type_info>, <exception>, <cstdarg>.
Rule 17.1 (direct) QAC++
335 17.4.2.2 Linkage (para 2)
It is implementation-defined whether a name from the Standard C Library
declared with external linkage has extern “C” or extern “C++” linkage.
Rule 17.1 (avoids)
Rule 14.6 (direct)
QAC++
No auto
339 17.4.4.3 Global or Non-member Functions (para 2)
A call to a global or non-member function signature in clauses 18 through
27 behaves the same as if the implementation declares no additional global
or non-member function signatures. An implementation may also define
additional global and non-member functions that would otherwise not be
called by a valid C++ program.
Efficiency
Guideline 13.1
(supports)
No auto
340 17.4.4.5 Reentrancy (para 1)
Which of the functions in the C++ Standard Library that are not reentrant
subroutines is implementation-defined.
Guideline 13.1
(supports)
No auto
341 17.4.4.8 Restrictions on Exception Handling (para 1, 3)
An implementation may strengthen the exception-specification for a non-
virtual function by removing listed exceptions.
No destructor operation defined in the C++ Standard Library will throw an
exception. Any other functions defined in the C++ Standard Library that do
not have an exception-specification may throw implementation-defined
exceptions unless otherwise specified. An implementation may strengthen
this implicit exception-specification by adding an explicit one. This implies
that the implementation may list implementation-defined types in such an
exception-specification.
Guideline 13.1
(supports)
No auto
343 18 Language Support Library
18.1 Types (para 4)
The macro NULL is an implementation-defined C++ null pointer constant in
this International Standard. Possible definitions include 0, 0L, but not
(void *) 0.
Rule 14.16 (direct) QAC++
353 18.3 Start and Termination (para 8)
Finally, control is returned to the host environment. If status is zero or
EXIT_SUCCESS, an implementation-defined form of the status successful
termination is returned. If status is EXIT_FAILURE, an implementation-
defined form of the status unsuccessful termination is returned. Otherwise
the status returned is implementation-defined.
Guideline 13.1
(supports)
No auto
357 18.4.2.1 Class bad_alloc (para 3, 5)
The result of calling what() on the newly constructed object is
implementation-defined.
virtual const char* what() const throw();
Returns an implementation-defined NTBS
Guideline 13.1
(supports)
No auto
13-2
Page Item / Description Control Enforced
359 18.5.1 Class type_info (para 7)
const char* name() const;
Returns an implementation-defined NTBS
Guideline 13.1
(supports)
No auto
359 18.5.2 Class bad_cast (para 3, 5)
The result of calling what() on the newly constructed object is
implementation-defined.
virtual const char* what() const throw();
Returns an implementation-defined NTBS
Guideline 13.1
(supports)
No auto
360 18.5.2 Class bad_typeid (para 3, 5)
The result of calling what() on the newly constructed object is
implementation-defined.
virtual const char* what() const throw();
Returns an implementation-defined NTBS
Guideline 13.1
(supports)
No auto
361 18.6.1 Class exception (5, 8)
The effects of calling what() after assignment are implementation-defined.
virtual const char* what() const throw();
Returns an implementation-defined NTBS
Guideline 13.1
(supports)
No auto
362 18.5.2 Class bad_exception (para 3, 5)
The result of calling what() on the newly constructed object is
implementation-defined.
virtual const char* what() const throw();
Returns an implementation-defined NTBS
Guideline 13.1
(supports)
No auto
364 18.7 Other Run-Time Support (para 5)
All signal handlers shall have C linkage. A POF that could be used as a
signal handler in a conforming C program does not produce undefined
behaviour when used as a signal handler in a C++ program. The behaviour
of any other function used as a signal handler in a C++ program is
implementation-defined.
Guideline 13.1
(supports)
No auto
375 20 General Utilities Library
20.1.5 Allocator Requirements
Implementors are encouraged to supply libraries that can accept allocators
than encapsulate more general memory models and that support non-equal
instances. In such implementations, any requirements imposed on allocators
by containers beyond those requirements that appear in Table 32, and the
semantics of containers and algorithms when allocator instances compare
non-equal, are implementation-defined.
Guideline 13.1
(supports)
No auto
398 21 Strings Library
21.1.3.1 struct char_traits<char> (para 3, 4, 5)
The type streampos is an implementation-defined type that satisfies the
requirements for POS_T in 21.1.2.
The type streamoff is an implementation-defined type that satisfies the
requirements for OFF_T in 21.1.2.
The type mbstate_t is defined in <cwchar> and can represent any of the
conversion states possible to occur in an implementation-defined set of
supported multibyte character encoding rules.
Guideline 13.1
(supports)
No auto
13-3
Page Item / Description Control Enforced
399 21.1.3.2 struct char_traits<wchar_t> (para 2, 4)
The type wstreampos is an implementation-defined type that satisfies the
requirements for POS_T in 21.1.2.
The type mbstate_t is defined in <cwchar> and can represent any of the
conversion states possible to occur in an implementation-defined set of
supported multibyte character encoding rules.
Guideline 13.1
(supports)
No auto
436 22 Localisation Library
22.1.1.2 locale Constructors and Destructor (para 8)
explicit locale(const char* std_name);
The set of valid string argument values is “C”, “ “, and any implementation-
defined values.
Guideline 13.1
(supports)
No auto
436 22.1.1.3 locale Members (para 5)
basic_string<char> name() const;
Returns the name of *this, if it has one; otherwise, the string “*”. If *this
has a name, then locale(name().c_str()) is equivalent to *this.
Details of the contents of the result string are otherwise implementation
defined.
Guideline 13.1
(supports)
No auto
437 22.1.1.5 locale Static Members (para 2)
static locale global(const locale& loc);
Causes future calls to the constructor locale() to return a copy of the
argument. If the argument has a name, does std::setlocale(LC_ALL,
loc.name().c_str()); otherwise, the effect on the C locale, if any, is
implementation-defined.
Guideline 13.1
(supports)
No auto
444 22.2.1.3 ctype Specialisations (para 1)
A specialisation ctype<char> is provided so that a member function of type
char can be implemented inline. The implementation-define value of
member table_size is at least 256.
Guideline 13.1
(supports)
No auto
444 22.2.1.3.2 ctype<char> Members (para 1)
In the following member descriptions, for unsigned char values v where
(v >= table_size), table()[v] is assumed to have an
implementation-define value (possibly different for each such value v)
without performing the array lookup.
Guideline 13.1
(supports)
No auto
447 22.2.1.5 Class Template codecvt (para 3)
The instantiations required in the Table 51, namely
codecvt<wchar_t,char,mbstate_t> and
codecvt<char,char,mbstate_t>, convert the implementation-defined
native character set.
Guideline 13.1
(supports)
No auto
467 22.2.5.3.2 time_put Virtual Functions (para 1)
iter_type do_put(iter_type s, ios_base&, char_type fill,const tm* t, char format, char modifier) const;
Formats the contents of the parameter t into characters placed on the output
sequence s. Formatting is controlled by the parameters format and modifier,
interpreted identically as the format specifiers in the string argument to the
standard library strftime(). Interpretation of the modifier argument is
implementation defined, but should follow POSIX conventions. Except that
the sequence of characters produced for those specifiers that are described as
depending on the C locale are instead implementation-defined.
Guideline 13.1
(supports)
No auto
13-4
Page Item / Description Control Enforced
494 23 Container Library
23.2.1 Class Template deque (para 2)
23.2.2 Class Template list (para 2)
23.2.4 Class Template vector (para 2)
The typedefs iterator, const_iterator, size_type,
difference_type are implementation-defined.
Guideline 13.1
(supports)
Guideline 17.16
No auto
No auto
599 26 Numerics Library
26.2.8 complex Transcendentals (para 9)
template<class T> complex<T> pow<const complex<T>& x, inty);
template<class T> complex<T> pow<const complex<T>& x,const complex<T>& y);
template<class T> complex<T> pow<const complex<T>& x,const T& y);
template<class T> complex<T> pow<const T& x, constcomplex<T>& y);
Returns the complex power of base x raised to the y-th power, defined as
exp(y*log(x)). The value returned for pow(0,0) is implementation-
defined.
Guideline 13.1
(supports)
No auto
625 27 Input/Output Library
27.1.2 Positioning Type Limitations
The classes of clause 27 with template arguments charT and traits behave
as described if traits::pos_type and traits::off_type are
streampos and streamoff respectively. Except as noted explicitly below,
their behaviour when traits::pos_type and traits::off_type are
other types is implementation defined.
Guideline 13.1
(supports)
No auto
631 27.4.1 Types (para 1)
The type streamoff is an implementation-defined type that satisfies the
requirements of 27.4.3.2.
Guideline 13.1
(supports)
No auto
637 27.4.2.5 ios_base Storage Functions (para 2)
long& iword(int idx);
Each newly allocated element of the array is initialised to zero. The
reference returned is invalid after any other operations on the object. An
implementation is free to implement both the integer array pointed at by
iarray and the pointer array pointed at by parray as sparse data
structures, possibly with a one element cache for each.
Guideline 13.1
(supports)
No auto
643 27.4.4.3 basic_ios iostate Flags Function (para 5)
void clear(iostate state = goodbit);
If (rdstate() & exceptions()) ==0, returns. Otherwise, the function
throws an object fail of class_ios::failure, constructed with
implementation defined argument values.
Guideline 13.1
(supports)
No auto
659 27.6.1.1.2 Class basic_istream::sentry (para 5)
If, after any preparation is completed, is.good() is true, ok_ != false
otherwise ok_ == false. During preparation, the constructor may call
setstate(failbit). The sentry constructor and destructor can also
perform additional implementation-dependant operations.
Guideline 13.1
(supports)
No auto
669 27.6.2.3 Class basic_ostream::sentry (para 3)
If, after any preparation is completed, os.good() is true, ok_ != false
otherwise ok_ == false. During preparation, the constructor may call
setstate(failbit). The sentry constructor and destructor can also
perform additional implementation-dependant operations.
Guideline 13.1
(supports)
No auto
13-5
Page Item / Description Control Enforced
674 27.6.3 Standard Manipulators (para 2)
The type designated smanip in each of the following function descriptions
is implementation-specified and may be different for each function.
smanip resetiosflags(ios_base::fmtflags mask);smanip setiosflags(ios_base::fmtflags mask);smanip setbase(int base);smanip setfill(char_type c);smanip setprecision(int n);smanip setw(int n);
Guideline 13.1
(supports)
No auto
680 27.7.1.3 Overridden Virtual Functions(para 16)
basic_streambuf<charT,traits>* setbuf(charT* s,streamsize n);
The effects are implementation-defined, except that setbuf(0,0) has no
effect.
Guideline 13.1
(supports)
No auto
688-
68927.8.1.4 Overridden Virtual Functions (para 10, 16)
basic_streambuf<charT,traits>* setbuf(charT* s,streamsize n);
If setbuf(0,0) is called on a stream before any I/O has occurred on that
stream, the stream becomes unbuffered. Otherwise the results are
implementation defined.
int sunc();
If a put area exists, calls filebuf::overflow to write the characters to the
file. If a get area exists, the effect is implementation defined.
Guideline 13.1
(supports)
No auto
713 Annex B Implementation Quantities
The limits may constrain quantities that include those described below or
others. The bracketed number following each quantity is recommended as
the minimum for that quantity. However, these quantities are only guidelines
and do not determine compliance.
Guideline 13.1
(supports)
No auto
727 C.2.2.3 Macro NULL (para 1)
The macro NULL, defined in any of <clocale>, <cstddef>, <cstdio>,
<cstdlib>, <cstring>, <ctime>, or <cwchar>, in an implementation-defined
C++ null pointer constant in this International Standard.
Rule 14.16 (direct) QAC++
730 D.6 Old iostream Members (para 5, 6, 7, 8)
The type streampos is an implementation-defined type that satisfies the
requirements of POS_T.
The type streamoff is an implementation-defined type that satisfies the
requirements of OFF_T.
An implementation may provide the following additional member function,
which has the effect of calling sbumpc().
An implementation may provide the following member functions that
overload signatures specified in clause 27.
Guideline 13.1
(supports)
No auto
Table 13-1: C++ STL Implementation-Defined Behaviour [BSI03]
14-1
Appendix 14 – Indeterminate Behaviour (C++ Language)
The following table details indeterminate behaviour in the C++ language and the applicable controls
that can be put in place to mitigate them. The behaviours have been extracted directly from [BSI03].
Page Item / Description Control Enforced
25 3 Basic Concepts
3.3.1 Point of Declaration (para 1)
int x = 12;{ int x = x; }
Here the second x is initialised with its own (indeterminate) value.
Rule 8.2.1 (direct)
New Rule 8
QAC++
QAC++
partial
PC-Lint
partial
82 5 Expressions
5.3.4 New (para 15)
A new-expression that creates an object of type T initialises the object as
follows: If the initialiser is omitted and if T is a non-POD class type (or
array thereof), the object is default initialised. Otherwise, the object created
has indeterminate value.
Rule 8.4.3 (direct) QAC++
84 5.3.5 Delete (para 4)
The value of a pointer that refers to de-allocated storage is indeterminate.
Rule 12.8 (avoids) QAC++
partial
PC-Lint
partial
147 8 Declarators
8.5 Initialisers (para 9)
If no initialiser is specified for an object, and the object is of non-POD class
type (or array thereof), the object shall be default initialised; if the object is
of const-qualified type the underlying class type shall have a user-declared
default constructor. Otherwise, if no initialiser is specified for a non-static
object, the object and its sub-objects, if any, have an indeterminate value.
Rule 8.4.3 (direct) QAC++
206 12 Special Member Functions
12.6.2 Initialising Bases and Members (para 4)
After the call to a constructor for class X has completed, if a member of X is
neither specified in the constructor’s mem-initialisers, nor default-initialised,
nor value-initialised, nor given a value during execution of the body of the
constructor, the member has indeterminate value.
Rule 8.4.3 (direct) QAC++
Table 14-1: C++ Language Indeterminate Behaviour [BSI03].
15-1
Appendix 15 – Rule and Guideline Enforcement Required
Guideline 2.2 – Specify in your compiler configuration that plain ‘char’ is implemented as
‘unsigned char’. Enforcement: Static, Environment
Rule 3.1.9 – Behaviour should be implemented by only one member function in a class.
Enforcement: Static, Design
Rule 3.2.5 – Ensure destructors release all resources owned by the object. Enforcement: Static
& Dynamic, Design & Coding
Rule 3.3.6 – If a virtual function in a base class is not overridden in any derived class then
make it non virtual. Enforcement: Static, Design
Rule 3.3.7 – Only define virtual functions in a base class if the behaviour will always be valid
default behaviour for derived classes. Enforcement: Static, Design
Rule 3.3.8 – Declare a function pure virtual in the base class if each derived class has to
provide specific behaviour. Enforcement: Static, Design
Rule 3.3.9 – If a virtual function is overridden in each derived class with the same
implementation then make it a non-virtual function in the base class. Enforcement: Static,
Design
Rule 3.3.10 – Ensure that the return type of the virtual function being overridden is
compatible. Enforcement: Static, Design
Rule 3.4.6 – Write derived classes to have at most one base class which is not a pure abstract
class. Enforcement: Static, Design
Guideline 3.4.7 – All members of a public base class must be valid for a derived class.
Enforcement: Static, Design
Rule 3.5.2 – Always write operations, that are normally equivalent, to be equivalent when
overloaded. Enforcement: Static, Design
Rule 6.1 – Use suffixes L, U, and UL for all constants of type ‘long’, ‘unsigned int’ and
‘unsigned long’. Enforcement: Static, Coding
Guideline 6.6 – Global and static data should be const. Enforcement: Static, Design & Coding
Guideline 8.3.2 – Restrict the use of the ‘extern’ keyword. Do not write ‘extern’ where it is
implicit. Enforcement: Static, Coding
Rule 8.3.5 – Avoid ambiguous grammar between function style casts and declarations.
Enforcement: Static, Coding
Rule 8.4.4 – Postpone variable definitions as long as possible. Enforcement: Static, Design &
Coding
Guideline 8.4.6 – Use class types or typedefs to indicate scaler quantities. Enforcement: Static,
Design & Coding
15-2
Rule 8.4.9 – Do not use unbounded (C-style) aggregate types. Enforcement: Static, Design &
Coding
Rule 8.4.11 – Use ‘const’ whenever possible. Enforcement: Static, Design & Coding
Guideline 8.4.12 – Directly append the ‘*’ and ‘&’ to type names in declarations and
definitions. Enforcement: Static, Coding
Guideline 9.4 – Only use the C++ exception handling mechanism to handle error conditions.
Enforcement: Static, Design
Guideline 9.5 – Each application must have some scheme for ensuring that all orphaned
resources are properly released when an exception is thrown. Enforcement: Dynamic, Design
Guideline 9.6 – Each application that acquires resources that are not automatically freed at
program termination must use some mechanism to ensure that acquired resources are freed if
the program unexpectedly terminates. Enforcement: Dynamic, Design
Rule 10.6 – When comparing variables and constants for equality always place the constant
on the left hand side. Enforcement: Static, Coding
Rule 10.8 – Ensure expressions used in assertions are free from side-effects. Enforcement:
Static & Dynamic, Design & Coding
Rule 10.18 – Guard the modulas operation to ensure that both arguments are non-negative.
Enforcement: Static, Coding
Rule 11.2 – Enclose all non-member functions that are not part of the external interface in the
unnamed namespace in the source file. Enforcement: Static, Design & Coding
Rule 11.5 – Declare read-only parameters of class type as const references. Pass by value
read-only parameters that are of fundamental type. Enforcement: Static, Coding
Rule 12.1 – Do not use default arguments with overloaded functions. Enforcement: Static,
Coding
Rule 12.5 – Do not return a de-referenced pointer initialised by dynamic allocation with a
function. Enforcement: Static & Dynamic, Design & Coding
Rule 12.8 – On use of delete always set the pointer to zero after the delete. Enforcement: Static,
Coding
Guideline 13.1 – Avoid implementation behaviour. Enforcement: Static, Design & Coding
Rule 13.3 – Do not exceed the translation limits imposed by the ISO C++ standard.
Enforcement: Static, Design
Rule 13.6 – Do not make any assumptions about the internal representation of a value or
object. Enforcement: Static, Design & Coding
Rule 14.6 – Use the __cplusplus identifier to distinguish between C and C++ compilation.
Enforcement: Static, Coding
15-3
Rule 14.13 – Write header files such that all files necessary for their compilation are included.
Enforcement: Static, Design & Coding
Rule 16.2 – Do not define a class template with potentially conflicting methods. Enforcement:
Static, Coding
Rule 16.3 – Only instantiate templates with template arguments which fulfil the interface
requirements of the ‘template’. Enforcement: Static & Dynamic, Design
Rule 16.4 – Only use templates when behaviour of the class or function template is completely
independent of the type of the object to which it is applied. Enforcement: Static, Design
Rule 17.2 – Use Standard Template Library containers and algorithms in preference to
custom designs. Enforcement: Static, Design
Guideline 17.3 – Make copying efficient for objects in containers. Enforcement: Static, Design
Guideline 17.4 – Where copying is expensive use containers of pointers or smart pointers.
Enforcement: Static, Design
Rule 17.5 – Do not attempt to insert derived class objects in a container that holds base class
objects. Enforcement: Static, Design & Coding
Rule 17.6 – Use empty() instead of checking size() against zero. Enforcement: Static, Design
Guideline 17.7 – Do not use STL containers as public base classes. Enforcement: Static, Design
Rule 17.8 – Never create containers of auto_ptrs. Enforcement: Static, Design & Coding
Rule 17.9 – Use vector and string in place of dynamically allocated arrays. Enforcement: Static,
Design
Rule 17.10 – Where possible pre-allocate in containers to save unnecessary reallocations.
Enforcement: Static, Design
Rule 17.11 – When passing vector types to C style functions use '&v[ 0 ]'. Enforcement: Static,
Coding
Rule 17.12 – Only use STL string's member c_str to get a const char* to use with legacy
functions. Enforcement: Static, Coding
Rule 17.13 – Do not use vector<bool>. Enforcement: Static, Coding
Rule 17.14 – Return false for equivalent values in relational predicates. Enforcement: Static,
Design & Coding
Rule 17.15 – Never modify the key part of a set or multiset element. Enforcement: Static,
Design & Coding
Guideline 17.16 – Minimise mixing of iterator types. Enforcement: Static, Design & Coding
Guideline 17.17 – The result of a predicate should depend only on its parameters.
Enforcement: Static, Design & Coding
15-4
Guideline 17.18 – Use STL algorithms rather than hand-written loops. Enforcement: Static,
Design
Rule 17.19 – Use container member functions rather than algorithms with the same name.
Enforcement: Static, Design
Rule 17.20 – Directly include necessary STL headers. Enforcement: Static, Design & Coding
Guideline 17.21 – Minimise use of the Standard Template Library 'auto_ptr'. Enforcement:
Static, Design & Coding
New Rule 1 – Always return stream references from operator << and operator >>.
Enforcement: Static, Design & Coding
New Rule 3 – Do not assume constructor arguments will or will not be evaluated prior to the
allocation of the object occurring. Enforcement: Static, Design
New Rule 7 – Do not perform equality comparisons on pointers to virtual functions.
Enforcement: Static & Dynamic, Design & Coding
New Rule 13 – Do not rely on the lifetime of temporary exception objects. Enforcement:
Dynamic, Design
New Guideline 16 – Be prepared for out of memory conditions. Enforcement: Dynamic, Design
New Guideline 18 – Avoid linking to languages other than C++ or C. Enforcement: Static,
Design
New Rule 20 – Ensure that the digit sequence for the # line pre-processing directive is > 0
and < 32768. Enforcement: Static, Coding
New Guideline 21 - Choose carefully among erasing options. Enforcement: Static, Design
New Guideline 22 – Ensure allocator conventions and restrictions are conformed to.
Enforcement: Static, Design
New Guideline 23 - Specify comparison types for associative containers of pointers and
iterators. Enforcement: Static, Design
New Rule 24 - Make sure destination ranges are big enough. Enforcement: Static & Dynamic,
Design & Coding
New Rule 25 - Avoid remove-like algorithms on containers of pointers. Enforcement: Static,
Design
New Rule 26 – Never dereference an invalid iterator. Enforcement: Static & Dynamic, Design &
Coding
New Rule 27 – Always check and ensure compliance with the pre-conditions for STL
functions. Enforcement: Static & Dynamic, Design & Coding
New Rule 28 – Only use the macro offsetof in <cstddef> with non-static POD types.
Enforcement: Static, Coding
15-5
New Rule 29 – Do not use iterators to hold singular values. Enforcement: Static, Design
New Rule 30 – Operations on types used with the complex and valarray classes shall not
throw exceptions. Enforcement: Static, Design
New Rule 32– Avoid using operator[] to access STL containers, use iterators instead.
Enforcement: Static, Coding
16-1
Appendix 16 – Programming Language Selection Pattern
Justification of Programming Language Selection PatternAuthor Derek W. Reinhardt
Created 09 July 2004 Last Modified 11 September 2004
Intent This pattern provides a framework for arguing the selection of programming language for safety
critical systems. The argument is based of numerous criteria that relate both to the language
specification and the environment in which the language is employed (people, process and tools).
The pattern recognises that few languages would be arguable purely on the language itself and that
tools play an important role in providing evidence to support the argument.
Also Known As • Programming Language Pattern
• Selection of Programming Language Pattern
Motivation This pattern was developed for the following reasons:
• To provide a framework for arguing the selection of the programming language for safety
critical systems.
• To allow the selection of the programming language to be justified within the context of
numerous standards including IEC61508, DO-178B, Defence Standard 00-55 Issue 2 and
Defence Standard 00-56 Issue 3.
Structure
G.TOP
{LangX} supports the
correct implementation of
{SystemY}'s software
design
G3.1.1
High quality, certified and/
or verified language
translators, analysis and
support tools are used for
{LangX}
S3.1
Argument that tools
used in development,
analysis and verification
of the design in {LangX}
are high quality and are
certified or verified
C.TOP.2
{SystemY} definition
C3.1A
Certification and
verification criteria
for tools
C3.1B
Definition of "high
quality"
G1.2
{LangX} features support
maintaining the
implementation over
{SystemY}'s operational
lifetime
S1
Argument over {LangX}
supporting the correct
implementation of the
design during initial
development and during
{SystemY}'s operational
lifetime
G1.1
{LangX} supports the
correct implementation of
the design during initial
development of {SystemY}
G2.1
{LangX} is well understood
by the programmers and
this supports the correct
implementation of the
design
S2
Argument over the
programmers' roles in
correctly implementing
{SystemY}'s software
design
S1.2
Argument over features
of {LangX} that support
maintaining the
implementation over
{SystemY}'s operational
lifetime
G1.2.1
{LangX} provides support
for user documentation
and comments
G1.2.2
Coding style guidelines for
{LangX} support
development consistency /
maintenance
S2.1
Argument that the
development team has
the expertise to develop
software in {LangX} for
{SystemY}'s design
G2.1.1
Development team has the
expertise to develop
software in {LangX} for
{SystemY}'s design
G1.2.3
{LangX} provides support
for other features that
maintain the correct
implementation of the
design over {SystemY}'s
operational lifetime
S1.1A
Argument over means of
preventing and/or
detecting errors
S1.1B
Argument over features
required by {LangX} in
order to implement the
design
G1.1A.1
Occurrences of errors in
the implementation of the
design in {LangX} are
prevented
G1.1A.2
Occurrences of errors in
the implementation of the
design in {LangX} are
detected
G1.1B
{LangX} supports
{FeatureZ} that is required
in order to correctly
implement the design
S3
Argument over the tools'
roles in correctly
implementing
{SystemY}'s software
design
G3.1
Tools for development in
{LangX} support the
correct implementation of
{SystemY}'s software
design
ref. Figure 16-3ref. Figure 16-2
A.TOP
{SystemY}'s software
design is shown to be
acceptably safe
elsewhere A
n-of-2
C.TOP.1
{LangX} definition
n
Figure 16-1: Top-Level Argument
16-2
G1.1A.1.2
Occurrences of run-time
errors in the
implementation of the
design are prevented
S1.1A.1
Argument over
instances at which
errors that might occur
in the implementation of
the design
ref. Figure 16-4
G1.1A.1
Occurrences of errors in
the implementation of the
design in {LangX} are
prevented
G1.1A.1.1
Errors are not introduced
in the translation of the
implementation (source
code) into executables
A1.1A.1
Source code is
grammatically correct
from Figure 16-1
G1.1A.1.1.1.1
Fully verified and/or
formally proven compiler
is used for {LangX}
G1.1A.1.1.1
Errors in translation are
not possible
G1.1A.1.1.2
Translation errors are
possible, but those parts
of the translator are known
and avoided
G1.1A.1.1.2.1
Error prone translation
properties of a compiler
are well known and
documented
S1.1A.1.1
Argument over absence
and/or avoidance of
errors in the translation
G1.1A.1.1.2.2
Known error prone
properties of a compiler
are avoided
A
Figure 16-2: Error Prevention Argument
ref. Figure P-9G1.1A.2B.1
{LangX} has features to
restrict and manage
complexity
S1.1A.2B
Argument over types of
implementation features
that facilitate the
detection of errors in the
design
G1.1A.2A.2
{LangX} lends itself to
dynamic testing to
complement the static
analysis
S1.1A.2A
Argument to show that
errors in the design
would be detected
though analysing and
verifying the
implementation in
{LangX}
G1.1A.2A.1
{LangX} lends itself to a
significant proportion of
static analysis
ref. Figure 16-10 ref. Figure 16-11
G1.1A.2B.2
{LangX} supports
abstraction and
information hiding
G1.1A.2
Occurrences of errors in
the implementation of the
design in {LangX} are
detected
G1.1A.2B.3
{LangX} supports other
features that facilitate the
detection of errors in the
design
from Figure 16-1
Figure 16-3: Error Detection Argument
16-3
G1.1A.1.2B.2A.1
{LangX} lends itself to the
application of defensive
programming techniques
G1.1A.1.2B.2B.1
Proven design patterns
are available for
{LangX}
G1.1A.1.2B.2B.2
{LangX} supports the
reuse of previously
verified code
from Figure 16-2
G1.1A.1.2B.1
Sources of commonly
introduced run-time errors
are identified and avoided
G1.1A.1.2B.2
{LangX} supports the
application of design
techniques that avoid and
mitigate run-time errors
S1.1A.1.2B.2A
Argument over {LangX}
features that avoid or
mitigate run-time errors
G1.1A.1.2
Occurrences of run-time
errors in the
implementation of the
design are prevented
S1.1A.1.2B
Argument over means of
avoiding, mitigating,
detecting and handling
non-definition related
errors at run-time
G1.1A.1.2A.1
Only completely and
unambiguously defined
aspects of {LangX} are
used for {System Y}
S1.1A.1.2A
Argument that no errors,
omissions or
inconsistencies relating
to {LangX}'s definition
will contribute to run-
time errors in the
implementation of the
design
ref. Figure 16-5
C1.1A.1.2A
{LangX} definition
G1.1A.1.2B.3
{LangX} supports a robust
run-time error detection
(or exception) system and
handling mechanism
G1.1A.1.2B.2A.2
{LangX} supports the
checking of assertions at
run-time
S1.1A.1.2B.2B
Argument over design
techniques that facilitate
the use of previously
verified code that is
known to contain no
run-time errors
ref. Figure 16-7
G1.1A.1.2B.2A.3
{LangX} supports other
features that avoid or
mitigate run-time errors
G1.1A.1.2B.2B.3
{LangX} supports other
features that facilitate the
use of previously verified
code that is known to
contain no run-time errors
Figure 16-4: Run-time Error Argument
G1.1A.1.2A.1A.1
Base language of
{LangX} has been
internationally
standardised
S1.1A.1.2A.1A
Argument that the
standardisation of
{LangX} eliminates
ambiguities relating to
variations in definition
G1.1A.1.2A.1B.1
{LangX} has no
unspecified, undefined,
indeterminate and
implementation defined
behaviours
G1.1A.1.2A.1B.2
A subset of {LangX}
sufficiently restricts the
unspecified, undefined,
indeterminate and
implementation defined
behaviours of {LangX}
G1.1A.1.2A.1A.2
Library support for
{LangX} has been
internationally
standardised
G1.1A.1.2A.1
Only completely and
unambiguously defined
features of {LangX} used
for {System Y}
S1.1A.1.2A.1B
Argument that only the
completely and
unambiguously defined
features of {LangX} are
to be used
ref. Figure 16-6
from Figure 16-4
Figure 16-5: Definition Argument
16-4
G1.1A.1.2A.1B.2.1
Undefined behaviour of
{LangX} is identified and
restricted
G1.1A.1.2A.1B.2.2
Unspecified behaviour of
{LangX} is identified and
restricted
G1.1A.1.2A.1B.2.3
Implementation-defined
behaviour of {LangX} is
identified and restricted
G1.1A.1.2A.1B.2.4
Indeterminate behaviour
of {LangX} is identified
and restricted
G1.1A.1.2A.1B.2
A subset of {LangX}
sufficiently restricts the
unspecified, undefined,
indeterminate and
implementation defined
behaviours of {LangX}
from Figure 16-5
C1.1A.1.2A.1B.2
Definition of subset of
{LangX}
Figure 16-6: Behaviours Subset Argument
G.SIDE_EFFECT.1
{LangX} is not prone to
side effects in expression
G.MISTAKES
{LangX} has features to
facilitate the detection of
programming typos and
unintentional mistakes
G.JUMPS.1
{LangX} supports a
modular, structured
approach (restrictions on
jumps between scopes)
G.VARIABLES.1
Declaration and
initialisation of variables is
explicit
G.TYPE.1
{LangX} is strongly typed
to ensure type safety and
to avoid type related
errors at run-time
ref. Figure 16-9
G.VARIABLES
Uninitialised and implicitly
initialised variables that
are a likely source of error
at run-time are avoided
G.SIDE_EFFECT
Side effects in expression
that are a likely source of
error at run-time are
avoided
G.MISTAKES
Unintentional
programming mistakes
that are a likely source of
run-time error are avoided
S1.1A.1.2B.1
Argument across the
identified sources of
commonly introduced
run-time errors
G.JUMPS
Jumps between scopes
that are a likely source of
error in an implementation
of a design are avoided
G.TYPE
Type related features that
are a likely source of error
at run-time are avoided
G.PARADIGM.1
{LangX}'s implementation
of the paradigm's features
is error free
G1.1A.1.2B.1
Sources of commonly
introduced run-time errors
are identified and avoided
J1.1A.1.2B.1
Identified sources of
commonly introduced
run-time error are
adequate
G.PARADIGM
Paradigm related sources
of commonly introduced
run-time errors are
avoided
G1.1A.1.2B.1.1
Data related sources of
commonly introduced run-
time errors in an
implementation are
restricted
G1.1A.1.2B.1.2
Control flow related
sources of commonly
introduced run-time errors
in an implementation are
restricted
from Figure 16-4
G1.1A.1.2B.1.4
Resource availability
related sources of
commonly introduced run-
time errors in an
implementation are
restricted
G.MEMORY
Memory allocation/
deallocation activities that
are a likely cause of error
in an implementation of a
design are avoided.
G.MEMORY.1
{LangX} is not prone to
memory leaks
G.MATH
Mathematical operations
and results that are a
likely source of error at
run-time are avoided
G.MATH.1
{LangX} is not prone to
invalid mathematical
operations and results
G1.1A.1.2B.1.5
Other sources of
commonly introduced run-
time errors in an
implementation of a
design are restricted
ref. Figure 16-8
G1.1A.1.2B.1.3
Run-time exceptions
leading to abnormal
program termination in an
implementation are
restricted
J
Generic language argument
shall address all relationships.
Some relationships may be
simplified in relation to the
specific design context of
{SystemY}.
Figure 16-7: Common Error Sources Argument
16-5
G1.1A.1.2B.1.5.2
Language constructs or
library functions that are
known to be prone to
misunderstanding or being
misused are restricted
S1.1A.1.2B.1.5
Argument that other
misused, misunderstood
and prone to error
{LangX} features are
known and restricted
G1.1A.1.2B.1.5.1
Language constructs or
library functions that are
prone to misunderstanding
or being misused are well
known and documented
G1.1A.1.2B.1.5
Other sources of
commonly introduced run-
time errors in an
implementation of a
design are restricted
from Figure 16-7
Figure 16-8: Other Error Sources Argument
G1.1A.1.2B.1.1.1.1.3.1
{LangX} principally
supports static types,
including sub-types and
enumerations
G1.1A.1.2B.1.1.1.1.1.1
Implicit conversions are
not allowed
G1.1A.1.2B.1.1.1.1.3.2
Types including user
defined types are statically
analysable
G1.1A.1.2B.1.1.1.1.1.2
Explicit conversions are
permitted only where
justifiably necessary
G1.1A.1.2B.1.1.1.1.2.2
Access types and pointers
should only be permitted
where justifiably
necessary
G1.1A.1.2B.1.1.1.1.2.1
{LangX} supports the
checking of array bounds
G1.1A.1.2B.1.1.1.1.4
Types in {LangX} are
checkable at run time
G1.1A.1.2B.1.1.1.1
{LangX} is strongly typed
to ensure type safety and
to avoid type related
errors at run-time
from Figure 16-7
S1.1A.1.2B.1.1.1.1
Argument across
features that make a
language strongly typed
G1.1A.1.2B.1.1.1.1.1
Type conversions in
{LangX} are controlled
G1.1A.1.2B.1.1.1.1.2
Access to types in {LangX}
is controlled
G1.1A.1.2B.1.1.1.1.3
Types in {LangX} are
statically analysable
Figure 16-9: Strongly Typed Argument
16-6
G1.1A.2A.1A.1
Use of dynamic variables
is restricted except where
justifiably necessary
G1.1A.2A.1B.3.1
{LangX} lends itself to
control flow, data flow, and
information flow analysis
G1.1A.2A.1B.1
{LangX}'s run-time
resource usage is
analysable and
predictable
G1.1A.2A.1A.3
Use of recursion is
restricted except where
justifiably necessary
G1.1A.2A.1A.2
Use of interrupts is
restricted except where
justifiably necessary
G1.1A.2A.1A
{LangX} features that
inhibit the capabilities of
static analysis are
restricted
G1.1A.2A.1B.3.2
{LangX} support the use of
assertions/annotations in
analysing preconditions,
postconditions and
invariants
G1.1A.2A.1
{LangX} lends itself to a
significant proportion of
static analysis
from Figure 16-3
S1.1A.2A.1A
Argument over a
restriction on those
features of {LangX} that
inhibit static analysis
G1.1A.2A.1B.3.4
{LangX} lends itself to
symbolic execution
G1.1A.2A.1B.2
{LangX}'s temporal
behaviour is analysable
and predictable
G1.1A.2A.1B.3
{LangX}'s functional
behaviour is analysable
and predictable
G1.1A.2A.1B.3.3
{LangX} lends itself to
formal code verification
(formal methods)
S1.1A.2A.1B
Argument that {LangX}
is predictable and that it
lends itself to static
analysis
S1.1A.2A.1C
Argument that static
analysis of {LangX}
meets the relevant
standards
G1.1A.2A.1C
Static analysis of {LangX}
meets the relevant
standards
C1.1A.2A.1
Definition of "significant
proportion"
C1.1A.2A.1C
Identified relevant
standards
G1.1A.2A.1A.4
Use of other {LangX}
constructs that inhibit the
capabilities of static
analysis is restricted
S1.1A.2A.1B.3
Argument over means of
analysing {LangX}'s
functional behaviour
n-of-4/5
G1.1A.2A.1B.3.5
Other means of analysing
{LangX}'s functional
behaviour are used
Figure 16-10: Static Analysis Argument
G1.1A.2A.2
{LangX} lends itself to
dynamic testing to
complement the static
analysis
G1.1A.2A.2A.2
{LangX}'s run-time
resource usage is testable
and predictable
G1.1A.2A.2A.1
{LangX}'s temporal
behaviour is testable and
predictable
G1.1A.2A.2A.3
{LangX}'s functional
behaviour is testable and
predictable
S1.1A.2A.2B
Argument that dynamic
testing of {LangX} meets
the relevant standards
G1.1A.2A.2B
Dynamic testing of
{LangX} meets the
relevant standards
S1.1A.2A.2A
Argument that
appropriate aspects of
{LangX}'s behaviour are
dynamically testable.
C1.1A.2A.2A
Identified coverage and
limitations of the statically
analysable aspects of
{LangX}
from Figure 16-3
C1.1A.2A.2B
Identified relevant
standards
Figure 16-11: Dynamic Testing Argument
16-7
Participants The following participant descriptions include additional information to those described in Figures
16-1 to 16-11.
Figure 16-1 G1.1B Claims that {Lang X} supports a {FeatureZ} that is required in order to
correctly implement the design. These features may include such things
as support for interfacing to modules written in other languages, and
concurrency or parallel processing.
G1.2 Claims that {Lang X}’s features support maintaining the
implementation over {System Y}’s operational lifetime by ensuring that
the decisions of the initial development are clearly communicated to
future maintainers.
Figure 16-2 G1.1A.1.1.2
G1.1A.1.1.2.1
G1.1A.1.1.2.2
Claims that errors in translation are possible, but those parts of the
translator are known and avoided. For example, code optimisation is a
possible source of error in a translator.
Figure 16-3 S1.1A.2A Identifies the approach that errors in the design will be detected through
analysing and verifying the design. This pattern recognises that static
analysis is not applicable to all situations.
Figure 16-5 S1.1A.1.2A.1A Identifies the approach that the standardisation of {Lang X} eliminates
ambiguities relating to variations in definition. For example, prior to
official standardisation various draft language definitions may be
available.
Figure 16-7 J1.1A.1.2B.1 Justifies that the identified sources of commonly introduced run-time
errors are adequate. This is because the error types (data, control flow,
run-time exceptions/terminations and resource availability) can be
associated in totality with the language properties (strongly typed,
variable initialisation, side effects, etc.).
Collaborations This pattern is structured on the following key arguments:
• Argument over {Lang X} supporting the correct implementation of the design – S1
• Argument over the programmers’ roles is correctly implementing the design – S2
• Argument over the tools’ roles in correctly implementing the design – S3
There are collaborations between the tools argued under S1 and the tools argued under S3.
Importantly the certification and verification criteria C3.1A will therefore have an impact on the
evidence provided in arguing S1.
There are also collaborations between the errors and techniques argued under S1 and the
programmers’ argued under S2. This implicitly implies that programmers argued under S2 should
have a detailed knowledge as to how the correct implementation is supported under S1.
At a lower level there are collaborations between the error prevention argument (G1.1A.1) and
error detection argument (G1.1A.2). Particular focus should be given to detecting errors for which
the prevention is weak and preventing errors for which the detection capability is weak.
At a slightly lower level there are collaborations between the static analysis (G1.1A.2A.1) and the
dynamic testing (G1.1A.2A.2). The argument is structured such that both forms of analysis and
verification are complementary to each other. Thus if both goals are satisfied then this implicitly
implies that all desired properties of the software are known.
Figure 16-7 presents a complex set of relationships between error types and language
characteristics. Thus there are significant collaborations between the two levels of the argument
here also. These goals are further addressed under the implementation section of this pattern.
Applicability This pattern is applicable where the safety case is required to justify the selection of programming
language for use in the safety critical system.
In order to instantiate this pattern the following contextual information is required:
• {Lang X} definition, including reference to the standard and any subset that is to be applied –
C.TOP1, C1.1A.1.2A, C1.1A.1.2A.1B.2
• {System Y} definition, including design, application and domain – C.TOP2
• Certification and verification criteria for tools – C3.1A (likely to come directly from standards
or from requirements imposed by clients or regulators)
• “High quality” tools definition, and ideally this will be a tool that does not contribute to the
errors argued under G1.1 and G1.2. – C.3.1B (likely to be interpreted from the standards or
16-8
defined internally within the context of ISO9000)
• “Significant proportion” of static analysis definition – C1.1A.2A.1 (likely to be defined based
on achieving the required verification confidence)
• Identification of relevant standards – C1.1A.2A.1C, C1.1A.2A.2B
• Identification of the coverage and limitations of the statically analysable aspects of {Lang X} –
C1.1A.2A.2A (likely to be defined based on achieving the require verification confidence)
Consequences After instantiating this pattern, a significant number of unresolved goals will remain to be
instantiated and developed. This activity is intended to be carried out for a particular language (or
language subset) choice. Note that for most languages the unresolved goals will not be resolved
through the language alone, and additionally a combination of tools will be required. The goals
requiring further development or instantiation are as follows. Refer to Figures 16-1 to 16-11 and
the participants section for the respective definitions.
• Translator: G1.1A.1.1.1.1, G1.1A.1.1.2.1, G1.1A.1.1.2.2
• Language standardisation: G1.1A.1.2A.1A.1, G1.1A.1.2A.1A.2
• Language behaviour: G1.1A.1.2A.1B.1, G1.1A.1.2A.1B.2.1, G1.1A.1.2A.1B.2.2,
G1.1A.1.2A.1B.2.3, G1.1A.1.2A.1B.2.4
• Strong types: G1.1A.1.2B.1.1.1.1.1.1, G1.1A.1.2B.1.1.1.1.1.2, G1.1A.1.2B.1.1.1.1.2.1,
G1.1A.1.2B.1.1.1.1.2.2, G1.1A.1.2B.1.1.1.1.3.1, G1.1A.1.2B.1.1.1.1.3.2,
G1.1A.1.2B.1.1.1.1.4
• Run-time errors: G.VARIABLES.1, G.MATH.1, G.PARADIGM.1, G.MISTAKES.1,
G.SIDE_EFFECT.1, G.JUMPS.1, G.MEMORY.1, G1.1A.1.2B.1.5.1, G1.1A.1.2B.1.5.2
• Error avoidance and mitigation: G1.1A.1.2B.2A.1, G1.1A.1.2B.2A.2, G1.1A.1.2B.2A.3
• Code reuse: G1.1A.1.2B.2B.1, G1.1A.1.2B.2B.2, G1.1A.1.2B.2B.3
• Exception detection and handling: G1.1A.1.2B.3
• Features restricting static analysis: G1.1A.2A.1A.1, G1.1A.2A.1A.2, G1.1A.2A.1A.3,
G1.1A.2A.1A.4
• Static analysis: G1.1A.2A.1B.1, G1.1A.2A.1B.2, G1.1A.2A.1B.3, G1.1A.2A.1B.3.1,
G1.1A.2A.1B.3.2, G1.1A.2A.1B.3.3, G1.1A.2A.1B.3.4, G1.1A.2A.1B.3.5, G1.1A.2A.1C
• Dynamic testing: G1.1A.2A.2A.1, G1.1A.2A.2A.2, G1.1A.2A.2A.3, G1.1A.2A.2B
• Language features for preventing errors: G1.1A.2B.1, G1.1A.2B.2, G1.1A.2B.3
• Language features required by design: G1.1B
• Documentation, comments, coding style: G1.2.1, G1.2.2, G1.2.3
• Development team expertise: G2.1.1
• Tool quality: G3.1.1
Implementation Implementation of this pattern involves first instantiating all the contexts. This will involve
selecting the programming language for which the pattern will be instantiated. Users may wish to
familiarise themselves with the pattern prior to making the language selection, as this will ensure
they select a language for which a justifiable argument has potential to be supported.
Having established all the contexts, each of the main strategies should be examined (S1, S2, S3). In
attempting to satisfy S1, numerous decisions need to be made. These are as follows:
• The balance and types of static analysis and dynamic testing – G1.1A.2A.1, G1.1A.2A.2
• The balance of error prevention and detection – G1.1A.1 and G1.1A.2
• The number of features required by the design – G1.1B
• Whether to use a formally verified translator or to find the errors in an existing translator –
G1.1A.1.1.1, G1.1A.1.1.2
• Whether to use a completely and unambiguously defined language or to use a language
definition subset – G1.1A.1.2A.1B.1, G1.1A.1.2A.1B.2
• The static techniques to be applied to establish confidence in the software’s functional
behaviour – G1.1A.2A.1B.3.1, G1.1A.2A.1B.3.2, G1.1A.2A.1B.3.3, G1.1A.2A.1B.3.4
From these decisions, the lower level goals can be instantiated and developed where required.
These can then be built up to satisfy higher level goals and thus eventually satisfying G.TOP.
Satisfying goals G1.1A.1.2B.1.1, G1.1A.1.2B.1.2, G1.1A.1.2B.1.3, G1.1A.1.2B.1.4, and
G1.1A.1.2B.1.5 is not a simple task. This is due to the complex relationships between subset
restriction categories (G.TYPE, G.VARIABLES, etc) and the data, control flow, run-time
exceptions and resource availability. The pattern recognises that absolute proof for these goals is
difficult and that the confidence deficit will often be established through static analysis and
dynamic testing.
16-9
Possible Pitfalls.
• Attempting to instantiate the pattern for a language that is immature and lacks a body of
knowledge on its application.
• Not recognising the importance of both static and dynamic testing.
• Not recognising the importance of both error prevention and detection.
• Not recognising the importance that the features provided by the language relate appropriately
to the design.
• Not recognising that, where a subset is used to restrict language features in order to satisfy the
lower level goals, a consideration is also required as to what proportion of the subset will
be auto-enforced.
• Not recognising that tools used to support lower level goal claims are likely to also require to
be addressed under S3.
• Underestimating the relationships between the restriction categories (G.TYPE,
G.VARIABLES, etc) and the data, control flow, run-time exceptions and resource
availability goals.
Example
Applications
This argument pattern can potentially be applied to any programming language, and has been
developed with appreciation for Ada, SPARK, C and C++. Specifically, groundwork has been
done in applying the pattern for the use of the C++ programming language in safety critical
systems.
Known Users This pattern has yet to be applied to a real world example.
Related Patterns • Fault Free Software Argument Pattern
• Diverse Argument Pattern
• Software Safety Case Patterns Catalogue
Table 16-1: Programming Language Selection Pattern