The Joint Strike Fighter Coding Standard - Bill Emshoff - CppCon 2014.pptx

30 

Loading.... (view fulltext now)

Loading....

Loading....

Loading....

Loading....

Full text

(1)

B

Bilill l EEmmsshohoff ff 

 S

 Senienior Sor Stataff Eff Embedded mbedded SS//W EW Engngiineer neer 

L

Lockockheeheed Mad Martin Artin Aeronaeronaututicicss

Bill.R.Emshoff@lmco.com Bill.R.Emshoff@lmco.com

JSF++

JSF++

Using C++ on Mission

Using C++ on Mission

and Safety Critical

and Safety Critical

Platforms

(2)

Background and Philosophy behind the

Background and Philosophy behind the JSF++

JSF++

standard

standard

Coding Issues Distinct to JSF++

Coding Issues Distinct to JSF++

(vs. those for General-Purpose Software)

(vs. those for General-Purpose Software)

Automated JSF++ compliance testing

Automated JSF++ compliance testing

Lessons Learned

Lessons Learned

Overview

(3)

Background and Philosophy behind the

Background and Philosophy behind the JSF++

JSF++

standard

standard

Coding Issues Distinct to JSF++

Coding Issues Distinct to JSF++

(vs. those for General-Purpose Software)

(vs. those for General-Purpose Software)

Automated JSF++ compliance testing

Automated JSF++ compliance testing

Lessons Learned

Lessons Learned

Overview

(4)

In the late 1990’s, Lockheed Martin selected

In the late 1990’s, Lockheed Martin selected C++

C++

as the programming language to be used

as the programming language to be used for Joint

for Joint

Strike Fighter embedded softw

Strike Fighter embedded software development

are development

 –

 –

 A

 A da

da tool

tool cchai

hains

ns wer

were

e iin decli

n decline

ne

 –

 –

C

C+

++

+ ttool

ools

s we

werre imp

e imprrovi

oving

ng

 –

 –

C

C+

++

+ wa

was

s a

attttrra

accttiive t

ve to p

o prros

os pe

peccttiive e

ve eng

ng iinee

neerrss

History (1/2)

(5)

In the Fall of 2003, Bjarne Stroustrup provided

assistance to JSF engineers in the development of

coding guidelines – “JSF++”

 –

 Many s ources of C and C++ prog ramming

 g uidelines were available, but no s ing le s et of

 g uidelines were found suitable for the

cons traints of our environment 

(6)

• MISRA C 1998

 –

Us ed as the bas is for J S F++, but:

 –

Limited to C lang uag e cons tructs

 –

C++ obviates the need for many C -s pecific rules

 – Stronger type-checking

 – Templates can replace macros

 – Container classes are safer alternatives to C

arrays

 – Smart Pointers are safer alternatives to C

pointers

• Embedded C++

 –

Overly limited subs et of C++ omitting features deemed

ess ential to larg e projects

• No namespaces, templates, or multiple inheritance

(7)

• Hard Real Time

 – Failure to meet schedule can be a fatal error 

• Limited Memory

 – Memory is fixed to that physically available - no memory

paging

• Safety and/or Mission Critical Applications  – Failure can cause loss of life or aircraft • Portability

 – Code must run on multiple operating systems to support

development and simulation

• Maintainability

 – Code will likely need to be maintained for

decades

(8)

C makes it eas y to shoot yours elf in the foot; C ++ makes it

harder, but when you do it blows your whole leg off.

― Bjarne Stroustrup

• Define a common style for all developers that is easy to

comprehend and maintain

• Avoid undefined, unspecified, and implementation-defined

behavior 

 –

Code s hould have predictable and portable s emantics

and performance

• Provide safe alternatives to unsafe or error-prone features  –

Often in the form of library components

• Automatic verification of guidelines is an important goal  –

Promote s tatic over dynamic error detection whenever

 pos s ible

(9)

• Resource Management in JSF++ • Arrays

• Multiple Inheritance

• Fault Handling

without 

exceptions

• Life without RTTI (Run-time type information)

• Templates

• Summary Comparison of JSF++ and MISRA C++ 2008

Coding Standard topics relevant to

JSF++

(10)

• Allocation from the free store (global new/delete) is

prohibited except during initialization (JSF Rule 206)

 –

Fragmentation of the heap due to repeated

allocation/de-allocation leads to non-determinis tic performance

• The JSF container library provides STL-style, class-specific

allocators as alternatives to eliminate the possibility of fragmentation

 – C++ STL vector’s interface allows class-specific

allocators as an

option

; for JSF’s container library, they are essentially

required

 – By defining fixed-size memory pools at initialization time,

constant-time new/delete can be guaranteed

 – No need to pay overhead costs for thread-safe allocators

for objects only accessed in a single thread

(11)

• Replacing global new/delete with custom allocators resolves

some performance issues but doesn’t guarantee safe operation

• C pointers and raw resource handles can lead to a host of

potential problems:

T* p = new T;

if (p->fail1) return 0; // leak!

if (p->fail2) delete p; // p is now a dangling pointer! return p; // does caller know he now “owns” p?

R eturn values s hould not obs cure res ource owners hip

(12)

RAII to the Rescue

• The Resource Acquisition Is Initialization (RAII) idiom solves

many pointer problems:

shared_ptr<T> p ( new T);

if (p->fail1) return 0; // No leak!

if (p->fail2) delete p; // Does not even compile! return p; // caller gets ownership,

(13)

With self-managed (RAII) class attributes, the

implementer is relieved of a lot of work in

class implementation

The compiler-generated copy constructor,

assignment operator, and destructor should

 just “do the right thing”, so there is no need

for the developer to write one (JSF rule 80)

RAII is not limited to pointers – mutexes are

likewise wrapped in RAII classes (e.g. C++11

std::lock_guard<>)

(14)

• The use of arrays in interfaces is prohibited in JSF++

 –

The problems of pointer decay have a long , notorious

history 

 foo( int*p ) // a function taking a pointer to an integer   foo( int[2] )  // really no different…

• JSF’s container library provides Array-like container classes

that avoid these problems

F oo( A rray<int,2>& )

// much s afer  

 – Containers know their own size and don’t participate in

implicit pointer convers ions

For the s pecial cas e of dealing with external / leg acy

interfaces implemented with arrays , template wrapper

 functions can help:

template <clas s T, s ize_t N> void foo(T (&p)[N]) …

(15)

• MI is allowed in a restricted form to allow for clean,

maintainable designs (JSF rule 88):

 – Unlimited public

interface

inheritance

 – Unlimited private

implementation

inheritance

 – Plus at most 1 protected, inherited implementation

 – MI is specifically allowed for “policy-based design” [1],

with each base class representing independent facets of the derived class

• For the purposes of this JSF++ rule, an

interface

may

contain :

 – non-virtual, protected methods

 – small data items if they function as part of the interface

[1]

 Modern C++ Des ig n

, by Andrei Alexandrescu

(16)

• Exceptions are prohibited in JSF++

 –

 A t the time J S F++ was defined, various C++ compiler

implementations res ulted in widely varying overheads

 –

B etter tool s upport was deemed neces s ary prior to

allowing C ++ exceptions in critical code

• Will all exceptions be caught?

• Is all affected code exception-safe?

• Are all possible control-paths covered?

• Disabling C++ exceptions doesn't eliminate the need for

fault handling though…

Fault Handling

without 

exceptions

(1/3)

(17)

• In general, functions should return error information, and

calling functions must test it (JSF rule 115)

 –

Problem for automated verification:

how is

“error information”

defined and returned? 

 S implis tic tool ass umption:

if a function returns a value, it must be used or cast to void

Fault Handling

without 

exceptions

(2/3)

(18)

• What about constructors, overloaded operators, or other

functions that don't return a status value?

 – Consider moving potentially-failing constructor code to

separate initialization / factory methods

 – Use a class attribute as a status indication, e.g.,

Matrix m = a + b; //

what to do if a + b fails ? 

if (m.is_bad()) { /* handle error case */ }

Compilers and lint-tools handily complain about

unused return values, but relying on users to check

error codes set as side-effects is inherently error-prone (a reason why JSF++ disparages use of errno).

 – Some errors are patently unrecoverable

For never-should-happen errors (failed assertions, watchdog timeouts, hardware failures) – log the fault data and try a reboot

Fault Handling

without 

exceptions

(3/3)

(19)

• For somewhat similar reasons that JSF++ banned C++ exceptions,

RTTI is also banned (JSF rule 178)

 – Worst-case overhead not easily predictable

• Often, a perceived need for RTTI is an indication of design

problems better solved with abstract methods

• In lieu of dynamic_cast, the Visitor Pattern can be used – this

requires no typecasts at all; users can derive from a class such as this:

class DefaultVisitor : Visitor { virtual defaultImpl(Base&) {}

virtual visit(Derived1& d) { defaultImpl(d); } virtual visit(Derived2& d) { defaultImpl(d); } ...

};

Life without RTTI

(20)

• JSF++ allows templates as a means to achieve type-safe,

high-performance code; however, C++ template usage

introduces additional challenges for development, analysis, and testing

 – Template code cannot be completely analyzed until

instantiated

 – Each unique template instantiation requires its own test

and review if in critical code

(21)

• MISRA C++ builds on JSF++ as JSF++ built on MISRA C • With an additional ~five years of compiler and developer

community maturity, MISRA 2008 allows, with restrictions,

 – C++ exceptions

 – dynamic_cast (RTTI)

• In keeping with original MISRA C rules, MISRA 2008

disallows

all

use of the free store (heap), even for initialization

• JSF++ forbids use of NULL macro due to C++ type checking;

MISRA

requires

it (as being more expressive than “0”)

 – Should consider C++11’s nullptr for future coding

standards

• JSF++ includes style guidelines; MISRA C++ recognizes

style is subjective, and given its more general target

audience, only suggests that an in-house style guide should exist

Summary Comparison of JSF++ and

MISRA C++ 2008

(22)

• Commercial static analysis tools providing automated

compliance checking are available from multiple vendors

 – Rules that are checked automatically are rules that

developers don’t need to waste review time on, and can instead concentrate on the tough problems

 – Automatic rule checkers catch issues commonly missed

by human eyes, sometimes even testing, e.g.,

• use of “=” vs. “==”

• inadvertent semi-colon following a conditional

expression

• ensuring all attributes of a class are initialized in a

constructor 

(23)

 – Static analysis is essential (and relatively cheap) but no

substitute for code review

 – Issues of style or that require human interpretation are

especially problematic for automated checks, e.g.,

• JSF rule 45 - words in an ID will be separated by ‘_’.

 – How should a tool determine what is a “word” 

• JSF rule 88 – multiple public interface inheritance

 – R ule text includes intent in the definition of interface.

• JSF rule 113 - multiple return statements are banned

unless s uch a s tructure would obscure or otherwis e

 s ig nificantly

complicate…

 – How s hould a tool implement this rule? 

(24)

 – Automated rules produce tradeoffs

• Tools erring towards catching more true positives at

the expense of more false positives result in

increased developer time to review and filter results and possibly “fix” or annotate code to meet tool

expectations

• Tools erring towards generating fewer false positives

tend to do so at the expense of missing some true positives

Often, code that triggers a “false” positive is code that

may be too clever and could stand a bit of critical

review anyway 

(25)

• A consistent, easy-to-read coding style for naming, braces, and

indention is more important than the particular style itself 

 – Developers modifying legacy code modules should be

encouraged to follow the existing style in those modules rather than resort to either leaving a module in JSF++ / K&R mixed style or refactoring existing working code

• Even in the absence of exceptions, the “resource acquisition is

initialization” (RAII) idiom generally, and smart pointers

specifically, should be explicitly required for resource handling

• Rules with subtle or exceptional cases can be difficult to analyze

mechanically.

• JSF++ includes guidelines on good template design, but failed to

specifically identify portability issues related to templates, notably

 – Some compilers didn't require typename at all; some allowed it

in contexts prohibited by others (and by the C++ standard)

 – Dependent base class name lookup implementations varied

widely

(26)

• A rationale for each rule educates developers and gets their buy-in  – Compliance comes easier when developers understand

rationales

• Interpretation of rules would be enhanced by more pass/fail

examples

 – not just novices, but even experienced implementers of

rule-checker software have sometimes missed the full intent of rules

• Rules should be written with automated compliance in mind,

leaving little to ambiguity

Consider rule 142, “All variables shall be initialized before use”. This could be enforced for local variables by requiring

initialization at declaration, but the standard is largely silent on how this rule is to be verified. By comparison, the related MISRA rule 8-5-1 specifically does not require initialization at

declaration, but does require class constructors to initialize all non-static members.

(27)

• Don’t over-specify

 – rather than prescribe use of a particular “Array” class in lieu of

an array, simply specify that library container classes be used

• Provide more clear guidance on how to deal with non-compliant

automatically-generated code, such as from UML tools

 – Where possible, common tool configuration settings should be

supplied to teams to achieve consistent code generation, as consistent with the coding standard as practical

(28)

• With a more mature C++ developer community, and better tool

support, C++ exception handling should be considered for future safety-critical applications

 –  A llows error handling log ic to be cons olidated at a hig her level

than deeply-nested functions

 – E liminates need for code to explicitly check and pas s error

 s tatus for truly exceptional events

• The coding standards will need to be revised for future

applications using C++11 (C++14?), which in many ways “feels like a new language” to quote Bjarne Stroustrup

(29)

 – After 15 years and more than 8 million lines of software

code [1], JSF++ has been a decided success for the JSF program

C ++ is now in widespread us e throug hout indus try

with excellent tool chains broadly available

Lig ht-weig ht, express ive abstraction mechanis ms

 provide J S F eng ineers with crucial s upport for

manag ing complexity without incurring performance

 penalties

When aug mented with reas onable g uidelines and

 s uitable libraries , C++ has proven its elf for s

afety-critical application

100+ F-

35’s in the field today 

• [1] https://www.f35.com/about/life-cycle/software

(30)

Figure

Updating...

References

Updating...

Related subjects :