Discussion:
C++ for safety critical software
(too old to reply)
Rob
2003-10-05 09:08:31 UTC
Permalink
I'm interested in gathering peoples views on the use of C++ for
safety critical systems. I have seen some evidence of debates
in safety communities but I have seen little evidence of thought
on this specific area since C++ was standardised.

To start the discussion, some views on the topic follow.

The major challenge of developing safety critical software is
understanding and clearly articulating the requirements. Once
that is done, the impact of selected programming language becomes
significant. Higher levels of safety integrity, such as SIL4
(Safety Integrity Level 4) or D0178B (Level A) is that system testing
can not provide adequate levels of assurance, and this normally
implies a need to demonstrate, to an independent third party who
has the authority to initiate system design changes, that the design
is correct. In practice, this demonstration is usually required to
be sufficient to demonstrate that the compiled code actually
represents the design correctly and unambiguously. The basic
assumption of these safety levels is that *any* error in a design
or in coding may cause loss of life.

While it is reasonable to assume that any language is used
intelligently, it is equally unreasonable to assume every programmer
is an expert. In a large language like C++ this becomes a concern for
safety critical systems, because there is a distinct possibility that
two programmers may examine a body of code, and draw different
conclusions about what it does. Regular questions in this newsgroup
on the interpretation of parts of the language are a symptom of this.
In fairness, C++ is not the only language like this; even Ada --- a
language intended to be used without subsetting for developing safety
critical systems --- has subsets defined to remove certain language
features before it can be safely used for SIL4 software development
(eg the Spark subset). But areas on concern include:

a) areas where the standard explicitly states there is "undefined
behaviour", or "implementation defined behaviour". In other words,
two implementations may generate different results from the same
source code, and both may be correct! Some of these implementation
freedoms may influence the behaviour of correct programs, resulting
in unpredictable flows of execution. In principle, this could be
addressed by examining machine code output by a compiler, but that is
possibly too time consuming to be effective when verifying flows
of execution in large bodies of code.

b) it is often difficult to demonstrate that there is no resource
leak, or to bound resource usage statically. There are several
design techniques (eg RAII) to help prevent resource leaks, but how
can an independent reviewer determine if these techniques are
always being applied? With the use of the STL [as an example] how
is it possible to ensure that resource usage does not grow in
unexpected ways?

c) there are some language features that, even though precisely
defined, may fairly be described as difficult to understand or easy
to abuse in ways that may deceive an independent reviewer. Multiple
inheritence and some uses of templates arguably fall into this
category: language features that give significant benefits if used
well, but are also open to abuse (whether deliberate or accidentally).

Having raised some concerns with C++, there are some points in its
favour;

a) There is a large infrastructure based on research, experience,
and excellent publications about better ways to use C++.

b) Several tools are available for C or C++ well before they become
available for other languages. Several tool manufacturers don't even
bother with other languages. Many of these tools make it easier to
spot mistakes and to test code. Other tools make it easier to write
code with fewer errors in the first place --- and they do it
automatically. Some system engineering tools help with requirements
capture, and help ensure a direct connection between the design and
the code that implements it.

c) It is relatively easy to find a software engineer who is familiar
with C++. For example, it could be argued that it is more difficult
to find a skilled Ada person than it is to find a skilled C++ person,
simply because there are more commercial applications of C++ than Ada,
so people are more likely to develop skills and then keep their hand
in with C++.

Whether or not these "big picture" arguments adequately address the
weaknesses of C++ (eg at the language level) for safety critical
applications is obviously a point for discussion.






[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Chris Newton
2003-10-05 23:37:03 UTC
Permalink
Rob wrote...
Post by Rob
I'm interested in gathering peoples views on the use of C++ for
safety critical systems.
I like C++ for many tasks, but I wouldn't dream of using it for
something safety critical. It's all about the difference between a
development environment that's amenable to debugging, and a development
environment that absolutely prevents bugs in the first place.

Several factors immediately place C++ based developments in the former
category, such as:
- its over-complicated specification, particularly the grammar
- possibilities for abusing pointers (and more importantly, the
difficulty in identifying where such possibilities exist)
- lack of control over exceptional cases such as memory exhaustion (not
just dynamically allocated, but stack in a deeply recursive algorithm).

Cheers,
Chris


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
James Rogers
2003-10-05 23:38:00 UTC
Permalink
Post by Rob
While it is reasonable to assume that any language is used
intelligently, it is equally unreasonable to assume every programmer
is an expert. In a large language like C++ this becomes a concern for
safety critical systems, because there is a distinct possibility that
two programmers may examine a body of code, and draw different
conclusions about what it does. Regular questions in this newsgroup
on the interpretation of parts of the language are a symptom of this.
In fairness, C++ is not the only language like this; even Ada --- a
language intended to be used without subsetting for developing safety
critical systems --- has subsets defined to remove certain language
features before it can be safely used for SIL4 software development
As many of you know, I am not a C++ expert. What I contribute here is
intended to help clarify the discussion, and is not meant as a
judgement of C++ or any other language.

Spark is a subset of Ada with the following attributes:

All functions and procedures have clearly documented pre-conditions and
post-conditions.

Dynamic memory allocation is forbidden.

Tasking (i.e. threads) are forbidden.

The propogation of language-defined exceptions is prohibited.

Global variables are forbidden.

Prohibits the use of any Ada syntax with undefined or implementation
defined behavior.


No application is written entirely in Spark. Only the parts that are
SIL4 or DO178B (Level A) are written in Spark. Other parts of the
application are written in other languages such as Ada, C++, Assembler,
or Java. The SIL4 or DO178B (Level A) portion must be partitioned from
the rest of the application so that faults in the rest of the application
will not result in a failure in the most safety critical partition of the
application.

The purpose of the Spark subset of Ada is that the program can be
statically analyzed to demonstrate its behavior. A tool called
Spark Examiner exists to perform that static analysis.

The Spark approach is good, but not perfect. Actual practice shows
that Spark, when used carefully, will result in a product with 10%
of the defects normally found in safety critical code. It does not
eliminate all defects. It also is not a rapid development approach.
The cost of using Spark is the primary reason for limiting its use
to only the portions of code that absolutely need to be as fault
free as possible.

Consider how C++ might fit into some of the limitations imposed by
Spark. Which features of C++ would be used in a SIL4 level safety
critical subset?

If dynamic memory allocation is prohibited, how much of the STL
would you be able to use?

If implicit conversions were prohibited you would need to wrap all
data, including numerics, in classes.

If dynamic memory allocation is prohibited, what implications are
there for the use of virtual functions?

Would references be allowed, while pointers are prohibited?

What implications are there for handling arrays?

Would preprocessor macros be prohibited?

Jim Rogers

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
David Abrahams
2003-10-06 11:37:41 UTC
Permalink
Post by James Rogers
If dynamic memory allocation is prohibited, how much of the STL
would you be able to use?
If you treat the STL as a black box provided by the language (at least
when the default allocator is used), and you assume that built-in
language facilities are bug-free (a reasonable assumption), you can
use all of it. Just think of it as a component of a high-level
language.

Now, other problems such as the potential for invalid iterators may
get in the way of accepting the STL for safety-critical applications,
but I don't see any reason that the STL containers' use of dynamic
allocation, in and of itself, has to be an obstacle, any more than
Java/Python/Lisp's use of dynamic allocation for *everything* has to
be an obstacle.
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Mirek Fidler
2003-10-06 18:27:05 UTC
Permalink
Post by David Abrahams
Post by James Rogers
If dynamic memory allocation is prohibited, how much of the STL
would you be able to use?
If you treat the STL as a black box provided by the language (at least
when the default allocator is used), and you assume that built-in
language facilities are bug-free (a reasonable assumption), you can
use all of it. Just think of it as a component of a high-level
language.
Well, with unlimited memory, maybe.

Anyway, I think that prohibiting dynamic memory has another
purpose - that code never fails due to out of memory problem (e.g.
caused by fragmentation). In most cases, throwing a bad_alloc is not an
option.
Post by David Abrahams
get in the way of accepting the STL for safety-critical applications,
but I don't see any reason that the STL containers' use of dynamic
allocation, in and of itself, has to be an obstacle, any more than
Java/Python/Lisp's use of dynamic allocation for *everything* has to
be an obstacle.
Nobody suggests using Java/Python/Lisp for safety-critical
applications.

Mirek



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Chris Newton
2003-10-12 09:32:59 UTC
Permalink
Mirek Fidler wrote...
Post by Mirek Fidler
Anyway, I think that prohibiting dynamic memory has another
purpose - that code never fails due to out of memory problem (e.g.
caused by fragmentation). In most cases, throwing a bad_alloc is not an
option.
You can run out of memory anyway. Try calling this function:

void oops()
{
int enormous[1000000000];
}

I doubt many systems run with 1GB of stack available.

A more realistic example would be deeply recursive function calls
exhausting the stack; the problem is the same.

Cheers,
Chris


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
James Rogers
2003-10-12 22:35:34 UTC
Permalink
Post by Chris Newton
Mirek Fidler wrote...
Post by Mirek Fidler
Anyway, I think that prohibiting dynamic memory has another
purpose - that code never fails due to out of memory problem (e.g.
caused by fragmentation). In most cases, throwing a bad_alloc is not an
option.
void oops()
{
int enormous[1000000000];
}
I doubt many systems run with 1GB of stack available.
A more realistic example would be deeply recursive function calls
exhausting the stack; the problem is the same.
The problem with the array is easily caught in testing.
Just try to run the "oops" function once.
It is also relatively easy to catch such a problem during code review,
before any tests are executed.

Recursive calls are prohibited using the Spark model because of
the unbounded nature of their memory usage.

Jim Rogers

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Ben Hutchings
2003-10-14 21:19:04 UTC
Permalink
<snip>
Post by James Rogers
Post by Chris Newton
void oops()
{
int enormous[1000000000];
}
I doubt many systems run with 1GB of stack available.
A more realistic example would be deeply recursive function calls
exhausting the stack; the problem is the same.
The problem with the array is easily caught in testing.
Just try to run the "oops" function once.
It is also relatively easy to catch such a problem during code review,
before any tests are executed.
Recursive calls are prohibited using the Spark model because of
the unbounded nature of their memory usage.
That's a false premise - recursion can be limited. For example,
the following function:

void f(int n)
{
assert(n > 0 && n <= 16);
if (n >= 2)
f(n / 2);
f(n - n / 2);
}

has a fairly obvious limited recursion depth and running time.
However, this is not easy to determine automatically. The real
benefit I see is that in the absence of recursion it's possible
to determine maximum stack usage from a call graph and the size
of each function's stack frame.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
John Potter
2003-10-15 10:43:21 UTC
Permalink
On 14 Oct 2003 17:19:04 -0400, Ben Hutchings
Post by Ben Hutchings
That's a false premise - recursion can be limited. For example,
void f(int n)
{
assert(n > 0 && n <= 16);
if (n >= 2)
f(n / 2);
f(n - n / 2);
}
has a fairly obvious limited recursion depth and running time.
Consider f(1). Assertion passes. If condition is false. Calls
f(1 - 1 / 2) which is f(1). Infinite recursion.
Post by Ben Hutchings
However, this is not easy to determine automatically.
Of course, in particular when it is false.

John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Ben Hutchings
2003-10-16 10:07:46 UTC
Permalink
Post by John Potter
On 14 Oct 2003 17:19:04 -0400, Ben Hutchings
Post by Ben Hutchings
That's a false premise - recursion can be limited. For example,
<snip stupid code>
Post by John Potter
Post by Ben Hutchings
has a fairly obvious limited recursion depth and running time.
Consider f(1). Assertion passes. If condition is false. Calls
f(1 - 1 / 2) which is f(1). Infinite recursion.
Post by Ben Hutchings
However, this is not easy to determine automatically.
Of course, in particular when it is false.
How embarrassing. Of course I meant to include both recursive
calls in the if statement:

void f(int n)
{
assert(n > 0 && n <= 16);
if (n >= 2)
{
f(n / 2);
f(n - n / 2);
}
/* else do something useful */
}

Recursion depth is logarithmic in n and running time is linear
in n; the limit on n limits both of them. Some sorting
algorithms would have similar characteristics, given a limit on
the input size.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Shay
2003-10-16 14:52:06 UTC
Permalink
Post by Ben Hutchings
Post by Ben Hutchings
That's a false premise - recursion can be limited. For example,
<snip stupid code>
Post by Ben Hutchings
has a fairly obvious limited recursion depth and running time.
[snip]
Post by Ben Hutchings
How embarrassing. Of course I meant to include both recursive
void f(int n)
{
assert(n > 0 && n <= 16);
if (n >= 2)
{
f(n / 2);
f(n - n / 2);
}
/* else do something useful */
}
[snip]

If I were writing something where recursion depth was critical to
control, I'd not trust myself beyond explicit counting. This would
probably also make it much easier for a static proof tool:

void f( int n, int depth = 0 )
{
assert( depth < max_depth );
++depth;
if ( n >= 2 )
{
f( n / 2, depth );
f( n - n / 2, depth );
}
// ...
}
--
Shay

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
James Rogers
2003-10-15 12:52:48 UTC
Permalink
Post by Ben Hutchings
That's a false premise - recursion can be limited. For example,
void f(int n)
{
assert(n > 0 && n <= 16);
if (n >= 2)
f(n / 2);
f(n - n / 2);
}
has a fairly obvious limited recursion depth and running time.
However, this is not easy to determine automatically. The real
benefit I see is that in the absence of recursion it's possible
to determine maximum stack usage from a call graph and the size
of each function's stack frame.
Let's see, what happens when n == 1?
The assertion condition is true.
the call 'f(n - n/2)' is executed.

When n == 1 the calculation evaluates to f(1 - 0), which again
is 1. In other words, the recursion continues forever.

Your stack usage is not as limited as you seem to think.

Jim Rogers

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Raoul Gough
2003-10-16 14:34:53 UTC
Permalink
Post by James Rogers
Post by Ben Hutchings
That's a false premise - recursion can be limited. For example,
void f(int n)
{
assert(n > 0 && n <= 16);
if (n >= 2)
f(n / 2);
f(n - n / 2);
}
has a fairly obvious limited recursion depth and running time.
However, this is not easy to determine automatically. The real
benefit I see is that in the absence of recursion it's possible
to determine maximum stack usage from a call graph and the size
of each function's stack frame.
Let's see, what happens when n == 1?
The assertion condition is true.
the call 'f(n - n/2)' is executed.
When n == 1 the calculation evaluates to f(1 - 0), which again
is 1. In other words, the recursion continues forever.
Your stack usage is not as limited as you seem to think.
Are you and John suggesting that a non-recursive implementation with
the infinite loop would be better? I would guess that either way your
system is going to fail if you have infinite loops in it.
--
Raoul Gough.
(setq dabbrev-case-fold-search nil)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
David Abrahams
2003-10-17 15:52:52 UTC
Permalink
Post by Raoul Gough
Are you and John suggesting that a non-recursive implementation with
the infinite loop would be better? I would guess that either way your
system is going to fail if you have infinite loops in it.
The difference is that, for some applications at least, your computer
has an unbounded amount of time at its disposal, but not an unbounded
amount of memory. A program that blows the stack is not quite the same
as a program that never terminates, because it might've worked on a
computer with more memory.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
James Rogers
2003-10-17 16:32:15 UTC
Permalink
Post by Raoul Gough
Are you and John suggesting that a non-recursive implementation with
the infinite loop would be better? I would guess that either way your
system is going to fail if you have infinite loops in it.
I am not suggesting that an infininte loop is always better.
I am pointing out that the example given was not a controlled
recursion. In another response the OP states that both recursive
calls should have been controlled by the conditional.

Infinite loops do not cause safety critical systems to fail.
They do allow a safety critical program to run from the point
of power-on to the point of power-off. This is important for
safety critical embedded systems. If, for instance, you create
a robotic control system for an unmanned air vehicle you want
the program to run until it is shut down. The controlling
software cannot terminate after some pre-set number of iterations.
Similarly, the controlling software cannot use an infinite amount
of stack space.

This makes an infinite loop more appropriate than infinite
recursion for a control system that needs to run for an
indefinite time.

Jim Rogers

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Raoul Gough
2003-10-18 22:02:40 UTC
Permalink
Post by James Rogers
Post by Raoul Gough
Are you and John suggesting that a non-recursive implementation with
the infinite loop would be better? I would guess that either way your
system is going to fail if you have infinite loops in it.
I am not suggesting that an infininte loop is always better.
I am pointing out that the example given was not a controlled
recursion. In another response the OP states that both recursive
calls should have been controlled by the conditional.
Infinite loops do not cause safety critical systems to fail.
They do allow a safety critical program to run from the point
of power-on to the point of power-off. This is important for
safety critical embedded systems. If, for instance, you create
a robotic control system for an unmanned air vehicle you want
the program to run until it is shut down. The controlling
software cannot terminate after some pre-set number of iterations.
Similarly, the controlling software cannot use an infinite amount
of stack space.
This makes an infinite loop more appropriate than infinite
recursion for a control system that needs to run for an
indefinite time.
Yes, I should have been more specific. I was referring to an
"unintentional" infinite loop, which in cases of programming error in
an iterative loop will probably trigger some kind of watchdog timer.

I guess the original point is that recursion can, in some cases, be
shown to use a bounded amount of memory. This is not possible in
general, of course, but nor is it possible, in general, to show that
an iterative routine uses a bounded amount of run-time.
--
Raoul Gough.
(setq dabbrev-case-fold-search nil)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
David J. Littleboy
2003-10-15 22:39:27 UTC
Permalink
Post by James Rogers
Recursive calls are prohibited using the Spark model because of
the unbounded nature of their memory usage.
By the same logic, iteration should be prohibited because of the unbounded
nature of infinite loops.

(Did I manage to say how incredibly stupid I find that rule without being
rude and actually calling it incredibly stupid???)

David J. Littleboy
Tokyo, Japan




[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
James Rogers
2003-10-16 14:16:46 UTC
Permalink
Post by David J. Littleboy
Post by James Rogers
Recursive calls are prohibited using the Spark model because of
the unbounded nature of their memory usage.
By the same logic, iteration should be prohibited because of the
unbounded nature of infinite loops.
(Did I manage to say how incredibly stupid I find that rule without
being rude and actually calling it incredibly stupid???)
It does appear so at first blush. On the other hand, every
recursion instance requires additional stack space, while this is
not generally true of iterations, even infinite loops.

Infinite loops provide unbounded execution time, not necessarily
unbounded memory usage.

In fact many real time control systems contain at least one
infinite loop so that they will run until the system is shut
down.

Jim Rogers

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
James Rogers
2003-10-06 18:30:31 UTC
Permalink
Post by David Abrahams
Post by James Rogers
If dynamic memory allocation is prohibited, how much of the STL
would you be able to use?
If you treat the STL as a black box provided by the language (at least
when the default allocator is used), and you assume that built-in
language facilities are bug-free (a reasonable assumption), you can
use all of it. Just think of it as a component of a high-level
language.
The problem with that approach is the SIL4 and DO178B standards.
They both prohibit such an assumption. *All* code in a DO178B
(Level A) code partition must meet all requirements and restrictions.
All code must be proveably correct upon inspection. If your bug-free
code violates the proveability rule it cannot be used in the
highest levels of safety-critical software.

Jim Rogers

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Tim Rowe
2003-10-06 19:00:31 UTC
Permalink
On 6 Oct 2003 07:37:41 -0400, David Abrahams
Post by David Abrahams
Post by James Rogers
If dynamic memory allocation is prohibited, how much of the STL
would you be able to use?
If you treat the STL as a black box provided by the language (at least
when the default allocator is used), and you assume that built-in
language facilities are bug-free (a reasonable assumption), you can
use all of it. Just think of it as a component of a high-level
language.
Doesn't work. Dynamic memory allocation isn't excluded just because
of the possible problems of getting the allocation wrong but also
because it's hard for a static analysier to handle the case of running
out of memory.
Post by David Abrahams
allocation, in and of itself, has to be an obstacle, any more than
Java/Python/Lisp's use of dynamic allocation for *everything* has to
be an obstacle.
I don't think you'll find any of those languages to be popular for
SIL4 applications, either!

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Attila Feher
2003-10-06 17:49:49 UTC
Permalink
James Rogers wrote:
[SNIP]
Post by James Rogers
Consider how C++ might fit into some of the limitations imposed by
Spark. Which features of C++ would be used in a SIL4 level safety
critical subset?
If dynamic memory allocation is prohibited, how much of the STL
would you be able to use?
[SNIP]

In C++ prohibiting the use of dynamic memory allocations is a call for
buffer overruns. It will not increase safety in this language.

BTW I always wonder about those safe applications... Where do they run? I
mean I am yet to see (even the simplest) OS, which is close to be robust -
not safe. And if the base HW/SW is not safe I cannot see how safe code can
run on top of it.

--
Attila aka WW



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jim Rogers
2003-10-07 18:40:09 UTC
Permalink
Post by Attila Feher
BTW I always wonder about those safe applications... Where do they run? I
mean I am yet to see (even the simplest) OS, which is close to be robust -
not safe. And if the base HW/SW is not safe I cannot see how safe code can
run on top of it.
You are correct. The OS for such systems needs to be validated to at least
the same level of software safety as the safety-critical application.

There are some real-time operating systems available that have already
been validated to the DO178B standard. Green Hills Software sells an
OS named Integrity-178B which is claimed to be fully certified to
DO178B level A. They also sell C and Ada compilers for use with
that OS. Green Hills sells C++ compilers, but their web page
does not say that those compilers are available for the
Integrity-178B OS.

Jim Rogers

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
k***@gabi-soft.fr
2003-10-07 19:03:14 UTC
Permalink
Post by Attila Feher
[SNIP]
Post by James Rogers
Consider how C++ might fit into some of the limitations imposed by
Spark. Which features of C++ would be used in a SIL4 level safety
critical subset?
If dynamic memory allocation is prohibited, how much of the STL
would you be able to use?
[SNIP]
In C++ prohibiting the use of dynamic memory allocations is a call for
buffer overruns. It will not increase safety in this language.
There are well established techniques for avoiding buffer overruns,
which static analysis can verify. As far as I know, there are NO well
established techniques for proving that allocation won't fail
(e.g. because of fragmentation, etc.).

The applications in question aren't allowed to fail. Period. It's that
simple.
Post by Attila Feher
BTW I always wonder about those safe applications... Where do they
run?
Well, the one I worked on controlled the air presure in a locomotive
break line. One small programming error, and the train had no breaks.

I also know of some others: auto-pilots for commercial aircraft, for
example.
Post by Attila Feher
I mean I am yet to see (even the simplest) OS, which is close to be
robust - not safe.
All of the applications I'm aware of in this field used home written
real-time kernels. And the OS's were simple -- after all, no disks, no
network, no terminals... That means that you can strip a lot of the
complicated parts out. (I once wrote a real time kernel for 8086. 1.2
Kb in all, and it did everything that was needed: process scheduling,
semaphores and message passing, etc.)
Post by Attila Feher
And if the base HW/SW is not safe I cannot see how safe code can run
on top of it.
Obviously, you don't use everyday, commercial processors in such
applications.

--
James Kanze GABI Software mailto:***@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Martin Prange
2003-10-06 18:20:01 UTC
Permalink
James Rogers <***@att.net> writes:
[...]
All functions and procedures have clearly documented pre-conditions and post-conditions.
Dynamic memory allocation is forbidden.
Tasking (i.e. threads) are forbidden.
The propogation of language-defined exceptions is prohibited.
Global variables are forbidden.
[...]
Consider how C++ might fit into some of the limitations imposed by
Spark. Which features of C++ would be used in a SIL4 level safety
critical subset?
If dynamic memory allocation is prohibited, how much of the STL
would you be able to use?
If implicit conversions were prohibited you would need to wrap all
data, including numerics, in classes.
If dynamic memory allocation is prohibited, what implications are
there for the use of virtual functions?
Would references be allowed, while pointers are prohibited?
What implications are there for handling arrays?
Would preprocessor macros be prohibited?
From my POV ( I have been involved in SIL4-based software development
for the german highspeed-train ICE3 within the ETCS2000 project),
the restrictions you stated above hold completely for the use of C++:

No use of dynamically allocated memory.
In general, all arrays were static and the Object pointers in them were
preassigned whereever possible. ( All this to allow static checking ! )
Not even databases were allowed to read in the roadmap from; they were
hardcoded ( which effectively means they were generated by codegenerators
and linked statically to the application. )
( relaxed view: Dynamically allocated memory was allowedm but ONLY in initialisation stage!)

Virtual functions were allowed.

No exceptions were allowed ( at the time I joined that project).

No templates were allowed ( well, this answers you question about STL ;-)

no pointer arithmetics.

All containers use indexes instead of pointers to nodes, objects.

References were allowed as formal arguments.

No setjmp() , threading, etc.: They used a cooperative scheduling system (TAS).

All the code had to be checked by QAC++ (with the most strict ruleset).

The "strage" stuff comes at last:
Operators had to be written with their "speaking" name, there even was a
header file ( enXXXXX.h, cannot remember the number ) for it:
#define eq ==
#define neq !=
#define ge >=
...
you'll get the idea.

[[ This remembered me at the sources of Steve Bournes "sh":
http://minnie.tuhs.org/UnixTree/V7/usr/src/cmd/sh/mac.h.html
#define BEGIN {
#define END }
#define SWITCH switch(
#define IN ){
#define ENDSW }
...
]]
Well, this is what I can remember about that subject.
ETCS2000-expats might be able to correct me though.

regards
Martin
--
Martin Prange, OO SW-Consultant, european space agency ( ESA )

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Ed Avis
2003-10-12 00:42:35 UTC
Permalink
I have been involved in SIL4-based software development for the
german highspeed-train ICE3 within the ETCS2000 project
[long list of rules, including:]
All containers use indexes instead of pointers to nodes, objects.
Might this not reduce type safety? In that it would be easier to pass
an index into the wrong array.
Consider: When you have a pointer to an object, it is a name for
exactly that object and no other. That sounds trivial, but look at
np
node[i]
The first points to a node, the second evaluates to (say) the same
node. But the second form is an expression; it is not so simple. To
interpret it, we must know what node is, what i is, and that i and
node are related by the (probably unspecified) rules of the
surrounding program. Nothing about the expression in isolation can
show that i is a valid index of node, let alone the index of the
element we want. If i and j and k are all indices into the node
array, it's very easy to slip up, and the compiler cannot help. It's
particularly easy to make mistakes when passing things to
subroutines: a pointer is a single thing; an array and an index must
be believed to belong together in the receiving subroutine.
Or is this not what your coding standard means?
--
Ed Avis <***@membled.com>

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Martin Prange
2003-10-16 17:55:31 UTC
Permalink
[reposted it ; dunno why this didn't show up the first time]
[..]
Post by Ed Avis
Post by Martin Prange
All containers use indexes instead of pointers to nodes, objects.
[..]
Post by Ed Avis
Might this not reduce type safety? In that it would be easier to pass
an index into the wrong array.
Post by Martin Prange
Consider: When you have a pointer to an object, it is a name for
exactly that object and no other. That sounds trivial, but look at
np
node[i]
The first points to a node, the second evaluates to (say) the same
node. But the second form is an expression; it is not so simple.
[..]
Of course, if you have the opportunity to name its it had to be named,
I just forgot to mention that in the list, you are right.
The thing with the indexes is of coursae that the index is easy checkable
against validity, whereas a pointer is not.
All the indexes had to be checked for validity before use, of course.
[ I also forgot to mention that in the list.]
Oh, my brain hurts ;-)
But anyway, hope I could help with some european rules to support SIL-4;
they were brought up by the "Eisenbahnbundesamt in Braunschweig, Germany",
the federal office for railway transport systems left over from the time
before the german railway "Deutsche Bundesbahn" was actually denationalized.
A quock googling brought up nothing; I don't have too much contact anymore to
be more specific at present, sorry.
May be some expats of ETCS-2000 actually can put more food here:
Robert, could you be more specific here ?

regards
Martin Prange
--
Martin Prange, OO SW-Consultant, european space agency ( ESA )

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Martin Prange
2003-10-16 21:15:33 UTC
Permalink
[..]
Post by Ed Avis
Post by Martin Prange
All containers use indexes instead of pointers to nodes, objects.
[..]
Post by Ed Avis
Might this not reduce type safety? In that it would be easier to pass
an index into the wrong array.
Post by Martin Prange
Consider: When you have a pointer to an object, it is a name for
exactly that object and no other. That sounds trivial, but look at
np
node[i]
The first points to a node, the second evaluates to (say) the same
node. But the second form is an expression; it is not so simple.
[..]
Of course, if you have the opportunity to name its it had to be named,
I just forgot to mention that in the list, you are right.
The thing with the indexes is of coursae that the index is easy checkable
against validity, whereas a pointer is not.
All the indexes had to be checked for validity before use, of course.
[ I also forgot to mention that in the list.]
Oh, my brain hurts ;-)
But anyway, hope I could help with some european rules to support SIL-4;
they were brought up by the "Eisenbahnbundesamt in Braunschweig, Germany",
the federal office for railway transport systems left over from the time
before the german railway "Deutsche Bundesbahn" was actually denationalized.
A quock googling brought up nothing; I don't have too much contact anymore to
be more specific at present, sorry.
May be some expats of ETCS-2000 actually can put more food here:
Robert, could you be more specific here ?

regards
Martin Prange
--
Martin Prange, OO SW-Consultant, european space agency ( ESA )


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Ed Avis
2003-10-18 09:20:16 UTC
Permalink
An array index is checkable for validity at run time; but a pointer is
checkable for having the right type at compile time. Maybe the ideal
system would combine both in some way.

string ss[10];
char cs[5];
string_index si = 3;
ss[si]; // okay
cs[si]; // type error
char_index ci = 8;
cs[ci]; // runtime bounds error

I don't know if this really makes any sense.
--
Ed Avis <***@membled.com>


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Martin Prange
2003-10-20 22:05:16 UTC
Permalink
Post by Ed Avis
An array index is checkable for validity at run time; but a pointer is
checkable for having the right type at compile time. Maybe the ideal
system would combine both in some way.
string ss[10];
char cs[5];
string_index si = 3;
ss[si]; // okay
cs[si]; // type error
char_index ci = 8;
cs[ci]; // runtime bounds error
I don't know if this really makes any sense.
Well, I have just reported what the "outer" requirements have been.
If I would have been responsible for it, I would definitely us a
complete typed approach ( no typedefs, real classes) to make sure
nobody may even compare
an xxx_index to a yyy_index, of course. This is what C++ does better
without
hidden costs if you remember how much code actually can be inlined,
virtuality can be resolved when the type is completely known at
compiletime.
This is why c++ will always have their traditional big share in field
in telecommunication, transport systems, aviation and space research.

Martin Prange
--
Martin Prange, OO SW-Consultant, european space agency ( ESA )

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

k***@gabi-soft.fr
2003-10-06 18:25:35 UTC
Permalink
James Rogers <***@att.net> wrote in message news:<***@204.127.36.1>...

[...]
Post by James Rogers
Consider how C++ might fit into some of the limitations imposed by
Spark. Which features of C++ would be used in a SIL4 level safety
critical subset?
If dynamic memory allocation is prohibited, how much of the STL would
you be able to use?
Probably none of it. If you cannot allocate dynamically, however, C
style arrays provide all of the required functionality. Not always in a
convenient form -- the implicit conversion to a pointer is a pain. But
it can be done.
Post by James Rogers
If implicit conversions were prohibited you would need to wrap all
data, including numerics, in classes.
If implicit conversions were prohibited, I think you would either have
to exclude C++, or limit the number of types used. If the only basic
type used is int (which could be reasonable in some cases), you're
probably safe.
Post by James Rogers
If dynamic memory allocation is prohibited, what implications are
there for the use of virtual functions?
I suspect that at that level of critical, you don't want virtual
functions anyway. For the type of analysis required, if the code says
a.f(), the reader must be able to tell immediately what f is called.
The decision cannot wait until runtime.
Post by James Rogers
Would references be allowed, while pointers are prohibited?
Or vice-versa ?
Post by James Rogers
What implications are there for handling arrays?
First, I think that only C style arrays, or a non-template class
wrapping a C style array, would be permitted. Certainly no
std::vector. And the implicit conversion to a pointer is probably the
biggest problem in the works -- most of the others can be solved by
simply banning use of parts of the language.
Post by James Rogers
Would preprocessor macros be prohibited?
The monitor could always read the preprocessed output:-).


IMHO, there is one real problem which you don't seem to have mentioned:
what confidence do we have that the compiler actually translates the
code correctly. Although things have improved greatly since I started
C++, my experience with C++ compilers is that they aren't the most
reliable pieces of software around. (On the other hand, today most of
the problems seem to be in the more exotic features, which would be
banned anyway.)

--
James Kanze GABI Software mailto:***@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jim Rogers
2003-10-07 18:39:20 UTC
Permalink
Post by k***@gabi-soft.fr
what confidence do we have that the compiler actually translates the
code correctly. Although things have improved greatly since I started
C++, my experience with C++ compilers is that they aren't the most
reliable pieces of software around. (On the other hand, today most of
the problems seem to be in the more exotic features, which would be
banned anyway.)
Yes, one of the expensive parts of DO178B is that compilers must also
be validated to the level of the application you are building.
Fortunately, several compiler vendors produce compilers that have
passed a DO178B level A certification. I do not know of any C++
compilers in that list. I do know there are several C and Ada
compilers in the list.

Jim Rogers

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Thorsten Ottosen
2003-10-07 15:18:17 UTC
Permalink
I don't know how they do it, but according to
http://www.research.att.com/~bs/applications.html, then

"a major ballistic missile defense system being done using C++."

cheers

Thorsten



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Ron Natalie
2003-10-07 18:51:29 UTC
Permalink
Post by Thorsten Ottosen
I don't know how they do it, but according to
http://www.research.att.com/~bs/applications.html, then
"a major ballistic missile defense system being done using C++."
The new navigation display in my plane is running NT (4.0).



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Loading...