Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

asserts considered harmful

139 views
Skip to first unread message

Mr Flibble

unread,
Feb 23, 2016, 5:20:09 PM2/23/16
to
Code containing asserts will behave differently depending on whether or
not the macro NDEBUG is defined. This is dangerous as it may result in
undetected bugs in a release build manifesting as undefined behaviour
that doesn't cause a straight crash but does something more serious.

One should prefer exceptions to asserts. One should have many exception
types and many throws (a throw statement should have no performance
impact in a decent implementation for the code path where no exception
is thrown) but few try/catches.

I recommend having a top level try/catch in main() and a few other
try/catches where appropriate (for exceptional cases that are
recoverable without terminating the application).

Remember: asserts considered harmful.

/Flibble

Ian Collins

unread,
Feb 23, 2016, 5:27:13 PM2/23/16
to
Mr Flibble wrote:
> Code containing asserts will behave differently depending on whether or
> not the macro NDEBUG is defined. This is dangerous as it may result in
> undetected bugs in a release build manifesting as undefined behaviour
> that doesn't cause a straight crash but does something more serious.

So don't change NDEBUG in your release builds.

--
Ian Collins

Mr Flibble

unread,
Feb 23, 2016, 5:33:04 PM2/23/16
to
You are assuming everyone does that: they don't.

/Flibble


Ian Collins

unread,
Feb 23, 2016, 5:44:32 PM2/23/16
to
I'm not assuming, I'm recommending.

--
Ian Collins

Alf P. Steinbach

unread,
Feb 23, 2016, 6:00:25 PM2/23/16
to
On 23.02.2016 23:19, Mr Flibble wrote:
> Code containing asserts will behave differently depending on whether or
> not the macro NDEBUG is defined. This is dangerous as it may result in
> undetected bugs in a release build manifesting as undefined behaviour
> that doesn't cause a straight crash but does something more serious.

Well, you can define a wrapper that throws an exception in NDEBUG
(a.k.a. “release”) mode, then preferably a “hard exception” that has
maximum chances of propagating all the way up to `main`.

The main problem with that, as I see it, is that cleanup via stack
unwinding can be dangerous when an assertion has failed.

But I think the chances favor attempted cleanup as typically less
destructive, less costly to the user, than a simple crash or just
continuing with UB, which can do all kinds of Very Bad Things™. Of
course one might ask the user. That's what the robots in Asimov's novels
failed to consider, to just ask those that they served, before going all
out with xenocide of the galaxy and mind control of humans.

Anyway, as bonus points such a wrapper can do away with the silly
restriction that the `assert` argument must be of scalar type (in C++ it
can be enough that it's convertible to `bool`); the wrapper can possibly
include logging; and the wrapper can be `constexpr`, which unfortunately
is not guaranteed for plain `assert`.

See <url:
https://github.com/alf-p-steinbach/cppx/blob/master/source_code/cppx/basics/execution/assertions/CPPX_ASSERT.hpp>
for an example (does not include logging, nor asking, but is `constexpr`).


> One should prefer exceptions to asserts. One should have many exception
> types and many throws (a throw statement should have no performance
> impact in a decent implementation for the code path where no exception
> is thrown) but few try/catches.

I think this is much like an argument that one should prefer runtime
type checking, namely based on a conflation of issues, and designed to
make one particular chosen approach to things seem preferable.

An assertion expresses an INCORRECT ASSUMPTION, strongly associated with
preconditions.

This is a contract breach by a caller, or by preceding code, and it
indicates something wrong up there, often with no way to be sure exactly
where or what.

Throwing an ordinary exception misinforms the calling code, which will
handle the ordinary exception as if this code, not itself, had failed.

An exception (a standard exception) throwing, OTOH., expresses a GOAL
ACHIEVEMENT FAILURE, strongly associated with postconditions.

This is a local failure. One knows what's wrong, e.g. some resource
exhausted, some item not found, whatever, including the case where some
lower level function failed, possibly via exception. And the design
called for such failure to be communicated back up via an exception.


> I recommend having a top level try/catch in main() and a few other
> try/catches where appropriate (for exceptional cases that are
> recoverable without terminating the application).

Yes, I agree that's useful.

In particular, otherwise a Windows GUI subsystem program can just
silently terminate...

And there's also the issue of stack unwinding not being guaranteed for
an unhandled exception.


> Remember: asserts considered harmful.

No. :)


Cheers!,

- Alf

Mr Flibble

unread,
Feb 23, 2016, 6:20:53 PM2/23/16
to
On 23/02/2016 23:00, Alf P. Steinbach wrote:
> On 23.02.2016 23:19, Mr Flibble wrote:
>
>> One should prefer exceptions to asserts. One should have many exception
>> types and many throws (a throw statement should have no performance
>> impact in a decent implementation for the code path where no exception
>> is thrown) but few try/catches.
>
> I think this is much like an argument that one should prefer runtime
> type checking, namely based on a conflation of issues, and designed to
> make one particular chosen approach to things seem preferable.
>
> An assertion expresses an INCORRECT ASSUMPTION, strongly associated with
> preconditions.
>
> This is a contract breach by a caller, or by preceding code, and it
> indicates something wrong up there, often with no way to be sure exactly
> where or what.
>
> Throwing an ordinary exception misinforms the calling code, which will
> handle the ordinary exception as if this code, not itself, had failed.
>
> An exception (a standard exception) throwing, OTOH., expresses a GOAL
> ACHIEVEMENT FAILURE, strongly associated with postconditions.
>
> This is a local failure. One knows what's wrong, e.g. some resource
> exhausted, some item not found, whatever, including the case where some
> lower level function failed, possibly via exception. And the design
> called for such failure to be communicated back up via an exception.

Not true: std::logic_error is meant for coding errors including
incorrect assumptions. One should derive custom exceptions from
std::logic_error and throw these instead of asserting.

/Flibble




Ian Collins

unread,
Feb 23, 2016, 7:00:44 PM2/23/16
to
Alf P. Steinbach wrote:
> On 23.02.2016 23:19, Mr Flibble wrote:
>> Code containing asserts will behave differently depending on whether or
>> not the macro NDEBUG is defined. This is dangerous as it may result in
>> undetected bugs in a release build manifesting as undefined behaviour
>> that doesn't cause a straight crash but does something more serious.
>
> Well, you can define a wrapper that throws an exception in NDEBUG
> (a.k.a. “release”) mode, then preferably a “hard exception” that has
> maximum chances of propagating all the way up to `main`.
>
> The main problem with that, as I see it, is that cleanup via stack
> unwinding can be dangerous when an assertion has failed.

Not only that, but unless you can capture enough context, it offers
little help in diagnosing the cause. I much prefer to have a decent
core dump to analyse than an exception report. I guess things are
different on platforms that lack support for cores, but even in embedded
systems, you are often better off rebooting than trying to handle an
unexpected condition.

The discussion should be around where to use assert and where to throw
an exception, forget about NDEBUG. I'm guessing the former is less
frequent in most code, but when it is used, the options for recovery are
sparse and the code to handle it nonexistent. So swapping an assert for
an exception in production builds may be even more dangerous.

My advice is to use asserts sparingly and keep them in!

--
Ian Collins

Alf P. Steinbach

unread,
Feb 23, 2016, 7:02:51 PM2/23/16
to
Well, it's certainly true that SOMEONE once meant you to use
`std::logic_error` in that way, otherwise it wouldn't be there.

Counting against that, when thrown from deep down in a call chain
`std::logic_error` is almost guaranteed to be caught by a general
`std::exception` handler, and this code will treat it as a failure by
the throwing code – instead of as indicating its own failure. So it's
almost sure to be handled in the Wrong Way™. I consider this, about very
concrete advantages/disadvantages, to be much more important for my
use/don't use decision than the SOMEONE's opinion somewhere pre 1998.

Are there other indications, beside `std::logic_error`, that the
standard exception hierarchy & machinery is not at all well designed?

Yes, for example that these critical exceptions can do dynamic allocation.

And for example, that the semantics of `throw` exception specifications
were never implemented by Microsoft and were deprecated in C++11.

Oh, and `std::uncaught_exception`.

Not to mention the extreme shenanigans one must go to, complex and
inefficient, with internal re-throwing and catching, to extract full
exception information with C++11 and later's nested exceptions.

Well, and more.

So, regarding what to use, I don't assign much weight to the SOMEONE's
authority. ;-)


- Alf

Mr Flibble

unread,
Feb 23, 2016, 7:17:32 PM2/23/16
to
std::logic_error exceptions can be caught, logged and re-thrown
(terminating application) which is the only acceptable course of action:
logic errors are non-recoverable; if one has been detected something is
seriously amiss and to try to carry on regardless would be extremely
unwise. Education is necessary to ensure this is done by the coder:
just because some people might be handling it incorrectly doesn't mean
it is unsound advice to follow especially for new non-legacy code.

/Flibble

Mr Flibble

unread,
Feb 23, 2016, 7:24:11 PM2/23/16
to
On 24/02/2016 00:00, Ian Collins wrote:
> Alf P. Steinbach wrote:
>> On 23.02.2016 23:19, Mr Flibble wrote:
>>> Code containing asserts will behave differently depending on whether or
>>> not the macro NDEBUG is defined. This is dangerous as it may result in
>>> undetected bugs in a release build manifesting as undefined behaviour
>>> that doesn't cause a straight crash but does something more serious.
>>
>> Well, you can define a wrapper that throws an exception in NDEBUG
>> (a.k.a. “release”) mode, then preferably a “hard exception” that has
>> maximum chances of propagating all the way up to `main`.
>>
>> The main problem with that, as I see it, is that cleanup via stack
>> unwinding can be dangerous when an assertion has failed.
>
> Not only that, but unless you can capture enough context, it offers
> little help in diagnosing the cause. I much prefer to have a decent
> core dump to analyse than an exception report. I guess things are
> different on platforms that lack support for cores, but even in embedded
> systems, you are often better off rebooting than trying to handle an
> unexpected condition.

If stack unwinding can be dangerous in the face of a detected logic
error (and I agree it is technically possible) then why can
std::vector::at() throw an exception in the first place? In fact why
does std::logic_error exist at all?

Following your logic to its ultimate conclusion there should exist a
proposal to deprecate/remove std::logic_error and exceptions derived
from it from C++.

/Flibble



Ian Collins

unread,
Feb 23, 2016, 7:26:05 PM2/23/16
to
Mr Flibble wrote:
>
> std::logic_error exceptions can be caught, logged and re-thrown
> (terminating application) which is the only acceptable course of action:
> logic errors are non-recoverable; if one has been detected something is
> seriously amiss and to try to carry on regardless would be extremely
> unwise. Education is necessary to ensure this is done by the coder:
> just because some people might be handling it incorrectly doesn't mean
> it is unsound advice to follow especially for new non-legacy code.

Unless you control all of the code, how can you grantee that there isn't
a catch or std::exception somewhere in the call frame between your throw
and catch of std::logic_error? If (and that is a big if) you are going
to use an exception rather than an assert, it should be something
outside of the standard exception hierarchy.

--
Ian Collins

Ian Collins

unread,
Feb 23, 2016, 7:34:16 PM2/23/16
to
Mr Flibble wrote:
> On 24/02/2016 00:00, Ian Collins wrote:
>> Alf P. Steinbach wrote:
>>> On 23.02.2016 23:19, Mr Flibble wrote:
>>>> Code containing asserts will behave differently depending on whether or
>>>> not the macro NDEBUG is defined. This is dangerous as it may result in
>>>> undetected bugs in a release build manifesting as undefined behaviour
>>>> that doesn't cause a straight crash but does something more serious.
>>>
>>> Well, you can define a wrapper that throws an exception in NDEBUG
>>> (a.k.a. “release”) mode, then preferably a “hard exception” that has
>>> maximum chances of propagating all the way up to `main`.
>>>
>>> The main problem with that, as I see it, is that cleanup via stack
>>> unwinding can be dangerous when an assertion has failed.
>>
>> Not only that, but unless you can capture enough context, it offers
>> little help in diagnosing the cause. I much prefer to have a decent
>> core dump to analyse than an exception report. I guess things are
>> different on platforms that lack support for cores, but even in embedded
>> systems, you are often better off rebooting than trying to handle an
>> unexpected condition.
>
> If stack unwinding can be dangerous in the face of a detected logic
> error (and I agree it is technically possible) then why can
> std::vector::at() throw an exception in the first place? In fact why
> does std::logic_error exist at all?

Because std::vector is designed to do so?

If for an example an invalid pointer triggers an assert, I would want to
know how this condition occurred, an assert and a core would give me the
best chance of doing so. Even if the alternative exception captured the
stack, it wouldn't help if the bad data came from another thread.

Use exceptions where recovery is an option, asserts where it isn't.

> Following your logic to its ultimate conclusion there should exist a
> proposal to deprecate/remove std::logic_error and exceptions derived
> from it from C++.

I think you lost the way somewhere. std::logic_error has its place, but
that place isn't as a substitute for assert.

--
Ian Collins

Mr Flibble

unread,
Feb 23, 2016, 8:21:56 PM2/23/16
to
You are missing the point. If an incorrect index is being passed to
at() then it is likely that something is seriously amiss.

>
>> Following your logic to its ultimate conclusion there should exist a
>> proposal to deprecate/remove std::logic_error and exceptions derived
>> from it from C++.
>
> I think you lost the way somewhere. std::logic_error has its place, but
> that place isn't as a substitute for assert.

Yes it is.

/Flibble


Ian Collins

unread,
Feb 23, 2016, 8:55:33 PM2/23/16
to
Mr Flibble wrote:
> On 24/02/2016 00:34, Ian Collins wrote:
>> Mr Flibble wrote:

>> If for an example an invalid pointer triggers an assert, I would want to
>> know how this condition occurred, an assert and a core would give me the
>> best chance of doing so. Even if the alternative exception captured the
>> stack, it wouldn't help if the bad data came from another thread.
>>
>> Use exceptions where recovery is an option, asserts where it isn't.
>
> You are missing the point. If an incorrect index is being passed to
> at() then it is likely that something is seriously amiss.

But it shouldn't be a "this can never happen and if it does, we're
screwed" condition where an assert is appropriate.

>>> Following your logic to its ultimate conclusion there should exist a
>>> proposal to deprecate/remove std::logic_error and exceptions derived
>>> from it from C++.
>>
>> I think you lost the way somewhere. std::logic_error has its place, but
>> that place isn't as a substitute for assert.
>
> Yes it is.

Only if you control 100% of the code base and aren't too interested in
fault finding the case of the throw.

--
Ian Collins

Öö Tiib

unread,
Feb 23, 2016, 9:47:54 PM2/23/16
to
That 'vector::at()' is likely for cases when out of range index can be
result of valid processing for example it was read from some potentially
dirty stream. Otherwise it is better to 'assert' and to use [].

>
> >
> >> Following your logic to its ultimate conclusion there should exist a
> >> proposal to deprecate/remove std::logic_error and exceptions derived
> >> from it from C++.
> >
> > I think you lost the way somewhere. std::logic_error has its place, but
> > that place isn't as a substitute for assert.
>
> Yes it is.

It is matter of contract of function interface. In general if caller is
supposed to avoid error situation then abort, if caller is not supposed to
avoid it (and especially when it can not avoid it) then throw.

Bugs must be fixed, but thrown error may lose context. It is cheaper to
analyse defect by post-mortem debugging of crash dump and throwing on
bugs just risks losing valuable context.

Paavo Helde

unread,
Feb 24, 2016, 4:48:43 AM2/24/16
to
On 24.02.2016 2:34, Ian Collins wrote:
>
> I think you lost the way somewhere. std::logic_error has its place, but
> that place isn't as a substitute for assert.

I think it depends very much on the modularity of the component which
has failed and needs to be restarted.

If the OS fails with a blue screen or kernel panic, then the execution
flow goes back to the hardware and the computer is restarted either
automatically or by the user.

If an app gets terminated via an assert, then the execution flow
basically goes back to OS and user or another program can restart the app.

If a component in an app fails with an assert-style exception, the
execution flow goes back to the main driver component of the app and the
user or another routine can restart the component.

If the component state is corrupted and restarting it does not work, the
next level (app) restart is needed.

If the computer state is corrupted and the app does not work after
restart, the next level (computer) restart is needed (not a rare
scenario in Windows).

The most tricky part is to find the correct level of restart needed at
any given situation. Assert is not always the best choice, and neither
is std::logic_error.

Just my 2 cents.





Ian Collins

unread,
Feb 24, 2016, 5:14:22 AM2/24/16
to
A fair summary.

I agree with the theory, but I've seldom seen component restarts
implemented well in practice! Most applications are monolithic, so
there is nothing to restart. Long running threaded applications are a
good candidate for trapping errors with exceptions and restarting a
thread while multi-process applications are a good candidate for
asserts. Most long running applications I've seen (such as system
services) are happy to abort and rely on what ever started them to do
the restart. It is often safer and no doubt easier to code them this way.

--
Ian Collins

mark

unread,
Feb 24, 2016, 8:43:46 AM2/24/16
to
On 2016-02-24 01:00, Ian Collins wrote:

> My advice is to use asserts sparingly and keep them in!

IMO, multiple levels of asserts should be used; release asserts that are
always active and multiple debug assert versions that perform checks too
expensive for release builds.

Debug asserts should be used extensively.

Öö Tiib

unread,
Feb 24, 2016, 8:52:15 AM2/24/16
to
On Wednesday, 24 February 2016 11:48:43 UTC+2, Paavo Helde wrote:
>
> If an app gets terminated via an assert, then the execution flow
> basically goes back to OS and user or another program can restart the app.
>
> If a component in an app fails with an assert-style exception, the
> execution flow goes back to the main driver component of the app and the
> user or another routine can restart the component.

There is a component (that throws exceptions about being buggy). The
memory of whole process is apparently shared (or how else it did throw
exceptions) and so whatever corrupted component's state possibly
corrupted something else alike. That makes restart of whole application
likely safer on case of "I'm insane" exception.

If the component is implemented as separate process then there is
memory access barrier and so it can't throw exceptions anyway.

Öö Tiib

unread,
Feb 24, 2016, 9:23:14 AM2/24/16
to
On Wednesday, 24 February 2016 15:43:46 UTC+2, mark wrote:
> On 2016-02-24 01:00, Ian Collins wrote:
>
> > My advice is to use asserts sparingly and keep them in!
>
> IMO, multiple levels of asserts should be used; release asserts that are
> always active and multiple debug assert versions that perform checks too
> expensive for release builds.

Assert typically just checks integrals or pointers or flags. That can be
done billions of times during second. When assert is seriously affecting
performance of optimized release build then it likely runs complicated
checks (that may be also defective and so should contain asserts) and
the debug build is likely inhumanly torturous to test thanks to such.
Better reconsider such asserts.

>
> Debug asserts should be used extensively.

About 5-10% of whole product code base is executed during 98% of profile.
So it is likely better idea to use real asserts extensively and replace
those with debug asserts only in that 5-10% of code and only when
profiling of product suggests to.

Mr Flibble

unread,
Feb 24, 2016, 12:52:18 PM2/24/16
to
That would be an inappropriate use of vector::at(). Invalid user input
is a runtime error not a logic error and passing an invalid index to
vector::at() is a logic error evidenced by the fact that
std::out_of_range is derived from std::logic_error. The correct thing
to do is validate your input first and then you can use
vector::operator[]() instead of vector::at() which in my opinion is
redundantly defensive as we should design our code in such away that
logic errors are mitigated against.

/Flibble

Öö Tiib

unread,
Feb 24, 2016, 2:14:50 PM2/24/16
to
Who said that potentially dirty stream comes from human? World is full
of automated dirty stream sources. That 'at()' *is* validating input and
exception is perfectly fine since likely a whole transaction containing
invalid index has to be canceled and rejected; there's no need to
validate it any further. I agree that 'at()' of most containers is
rarely useful, instead assert and [] are common but it was you who
brought it up.

Mr Flibble

unread,
Feb 24, 2016, 2:42:20 PM2/24/16
to
Who said "user" was a human? It still makes no difference: you should
still validate your input whatever its source and at() is not the place
to do that validation as propagating a logic error exception is
inappropriate for invalid runtime data.

/Flibble

Cholo Lennon

unread,
Feb 24, 2016, 2:50:00 PM2/24/16
to
Long time ago I had to deal with a nasty assert enabled in release
builds. From time to time (very seldom) our application crashed in a
production environment. The application used an internal dynamic library
which in turns used a third party library. The latter had an assert for
an unusual situation (a network packet not recognized). The author
decided that instead of just ignoring the packet o logging it, he had to
assert. It was a bad decision combined with asserts enabled by default
in release build.

assert (I'm talking about C assert) must be used carefully and IMHO must
not be enabled in release. If you need to report unsusual situations use
exceptions or create a new assert macro on top of C++ exceptions.

In my personal case I'm using asserts for pre/post conditions
(expects/ensures) in a similar way to thoses described here:

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md

(from the link see "State preconditions (if any)" and "State
postconditions")

My macros are build on top of C++ exceptions and can be enabled/disabled
in release builds.

Regards


--
Cholo Lennon
Bs.As.
ARG

Öö Tiib

unread,
Feb 24, 2016, 3:59:09 PM2/24/16
to
Where it is written that I should use "logic error" for reporting
defects in my code? I use unit tests, 'static_assert' and 'assert'
to check for defects in my code. Every of those is stop the show
and back to drawing board, it is not "exceptional situation" that
I made a defect. I make one every hour or so, it is part of work.

I do not know if the index was produced run time by that "user" or
was carved into rock like that since stone age. It is index that does
not make sense, so it is violating logical preconditions and data
invariants and so is logic error. "Out of range" is clearest
explanation of the error.

As contrast writing code that checks and throws something else like
"range error" on my own instead of using 'at()' would be wrong. Wrong
exception, pointless duplication of already existing standard feature
and needless bloat.

Vir Campestris

unread,
Feb 24, 2016, 4:27:53 PM2/24/16
to
On 23/02/2016 23:20, Mr Flibble wrote:
> Not true: std::logic_error is meant for coding errors including
> incorrect assumptions. One should derive custom exceptions from
> std::logic_error and throw these instead of asserting.

That doesn't mean assert is bad.

Assert in debug builds can cause your program to blow up with a nice
dump that's easy for you to sort out - the program has made no attempt
to clean up before reporting the problem.

But when the code is out in the field - imagine a word processor. The
use has been typing for an hour, and hasn't saved. He inserts some funny
field, the program asserts, and he loses his edits. Or the program
doesn't assert, does its best to recover the error, forgets how it got
in that situation - but there's at least a chance of saving the document.

Also enough asserts will be big and slow. Just as I turn on the
optimiser in the compiler before release, I disable lots of debug
logging - and asserts.

Andy

Mr Flibble

unread,
Feb 24, 2016, 4:49:28 PM2/24/16
to
Why are you being so obtuse? If you let at() throw then you ARE using a
logic error for something that is not a logic error. YOU ARE DOING IT WRONG.

>
> As contrast writing code that checks and throws something else like
> "range error" on my own instead of using 'at()' would be wrong. Wrong
> exception, pointless duplication of already existing standard feature
> and needless bloat.

Nobody is suggesting that .. STOP BEING SO OBTUSE.

/Flibble


Ian Collins

unread,
Feb 24, 2016, 5:00:01 PM2/24/16
to
A reasonable counter example to your word processor is a compiler. If
the code generator hits an "impossible" condition it can't handle,
bailing is the only option. Even your word processor, if it realised
its internal state was corrupt, would have little choice but to abort.
To do anything else would be courting disaster.

The key point Flibble either doesn't get (or more likely, chooses to
ignore) is asserts really should be used for exceptional conditions
*from which there is no recovery*. In those situations you (as a
developer) need as much information about the state of the application
as you can get, hence aborting with a core dump or (as on OSX) an
opportunity for the user to send a crash report. These asserts should
never be removed from the code.

Throwing an exception when you know something (possibly the stack) is
corrupt is madness.

--
Ian Collins

Öö Tiib

unread,
Feb 24, 2016, 5:03:37 PM2/24/16
to
You are doing it wrong. You are asserting something baldly and then
discussing mine mental capabilities instead of discussing the points
that I made and the detail of it you consider incorrect.

>
> >
> > As contrast writing code that checks and throws something else like
> > "range error" on my own instead of using 'at()' would be wrong. Wrong
> > exception, pointless duplication of already existing standard feature
> > and needless bloat.
>
> Nobody is suggesting that .. STOP BEING SO OBTUSE.

You are mirroring. Everybody tells you that stop asserting that "sky is
blue" crap baldly and obtusely. Instead elaborate what you are suggesting
and be constructive.

Öö Tiib

unread,
Feb 24, 2016, 5:13:45 PM2/24/16
to
On Wednesday, 24 February 2016 23:27:53 UTC+2, Vir Campestris wrote:
>
> But when the code is out in the field - imagine a word processor. The
> use has been typing for an hour, and hasn't saved. He inserts some funny
> field, the program asserts, and he loses his edits. Or the program
> doesn't assert, does its best to recover the error, forgets how it got
> in that situation - but there's at least a chance of saving the document.

Aborting in unexpected state is likely safest choice for any serious
software. Most word processors on market keep documents saved all time.
Try. Turn computer's power off and on then run the word processor
again. Majority of those tell that document was recovered (or couple
of documents). If you really have one that does not do that then
uninstall it and download LibreOffice or something.

Avoiding aborting program on case of error makes sense on case of
entertainment software because little defect in art or something can
keep it enjoyable but a crash seriously annoys.

Scott Lurndal

unread,
Feb 24, 2016, 7:12:18 PM2/24/16
to
=?ISO-8859-1?Q?=D6=F6_Tiib?= <oot...@hot.ee> writes:
>On Wednesday, 24 February 2016 23:27:53 UTC+2, Vir Campestris wrote:
>>
>> But when the code is out in the field - imagine a word processor. The
>> use has been typing for an hour, and hasn't saved. He inserts some funny
>> field, the program asserts, and he loses his edits. Or the program
>> doesn't assert, does its best to recover the error, forgets how it got
>> in that situation - but there's at least a chance of saving the document.
>
>Aborting in unexpected state is likely safest choice for any serious
>software.

Most serious software (e.g. safety critical or life critical) cannot _abort_
in unexpected state. It needs to fail safe, which isn't just calling 'assert'.

We allow static_assert for compile-time invariants, but never asserts at
runtime for any reason.

David Brown

unread,
Feb 24, 2016, 7:23:40 PM2/24/16
to
That would depend on what you mean by "abort". For some safety systems,
an "abort" that immediately disabled all outputs then hangs the
processor could be the ideal fail-safe behaviour. Or perhaps "abort"
could be used to force the hardware to restart with a minimal fail-safe
firmware image. You are free to implement "abort" in whatever way makes
sense for the system in question.

Öö Tiib

unread,
Feb 24, 2016, 8:33:05 PM2/24/16
to
On Thursday, 25 February 2016 02:12:18 UTC+2, Scott Lurndal wrote:
> =?ISO-8859-1?Q?=D6=F6_Tiib?= <oot...@hot.ee> writes:
> >On Wednesday, 24 February 2016 23:27:53 UTC+2, Vir Campestris wrote:
> >>
> >> But when the code is out in the field - imagine a word processor. The
> >> use has been typing for an hour, and hasn't saved. He inserts some funny
> >> field, the program asserts, and he loses his edits. Or the program
> >> doesn't assert, does its best to recover the error, forgets how it got
> >> in that situation - but there's at least a chance of saving the document.
> >
> >Aborting in unexpected state is likely safest choice for any serious
> >software.
>
> Most serious software (e.g. safety critical or life critical) cannot _abort_
> in unexpected state. It needs to fail safe, which isn't just calling 'assert'.

If there are some special ways to do suicide quicker than with abort
then indeed do it but don't attempt to repair anything. Don't forget
the software just detected that it is insane.

Somewhat safety critical system can be such that one process is
"running" and other is waiting as "backup". If "running" process
aborts then the "backup" takes over becomes "running" (and new
"backup" is prepared). That is typically used when downtime of
a service must be minimal.

Somewhat better safety critical is to run 3 systems in parallel.
Design software of each separately by different team. If one
will give different output from other two then trust the majority
kill the idiot and let 4th system (from 4th team) to take over.
That is typically worth it when life of people can be on stake.

>
> We allow static_assert for compile-time invariants, but never asserts at
> runtime for any reason.

Never try to fix any insanity run-time, it is simply impossible. The
defect did slip in and no test did detect it before so running mad
software can no way deal with it. It can only suicide fast to give
control over to more sane powers.

Ian Collins

unread,
Feb 24, 2016, 9:30:08 PM2/24/16
to
Those were certainly considerations for the last few control systems I
worked on. The last was a propulsion and helm control system where a
dead stop, painful as it could be, was better than destroying an engine
or ramming a jetty at 40 knots! An earlier example was a telco power
system controller, again, aborting (via assert) and falling back to
hardware defaults was better than allowing outputs that could fry
millions of dollars of kit.

As you say, the result of a "abort" will vary from system to system but
in all cases it must happen immediately when a problem is detected, not
after some potentially catastrophic attempts at clean up.

--
Ian Collins

Vir Campestris

unread,
Feb 25, 2016, 6:05:49 PM2/25/16
to
On 25/02/2016 02:29, Ian Collins wrote:
> The last was a propulsion and helm control system where a dead stop,
> painful as it could be, was better than destroying an engine or ramming
> a jetty at 40 knots!

I'll assume your stuff was pretty good, but... if you're on a destroyer
approaching harbour at 40kts, and the engine management throws a wobbly
you are in deep doodoo - because it's the brakes as well. There's no
such thing as a dead stop on water.

The big tankers take _miles_ to stop or turn even when everything is
working.


Andy

Ian Collins

unread,
Feb 26, 2016, 1:41:30 AM2/26/16
to
Vir Campestris wrote:
> On 25/02/2016 02:29, Ian Collins wrote:
>> The last was a propulsion and helm control system where a dead stop,
>> painful as it could be, was better than destroying an engine or ramming
>> a jetty at 40 knots!
>
> I'll assume your stuff was pretty good, but... if you're on a destroyer
> approaching harbour at 40kts, and the engine management throws a wobbly
> you are in deep doodoo - because it's the brakes as well. There's no
> such thing as a dead stop on water.

A jet boat dropping its reversing buckets comes pretty close!

--
Ian Collins

David Brown

unread,
Feb 26, 2016, 11:11:32 AM2/26/16
to
I think it is a fair assumption that Ian knew such details when making
the software - or at least the customer who specified "if there is a
serious problem, turn off all outputs" knew about them.


woodb...@gmail.com

unread,
Mar 9, 2016, 2:32:30 PM3/9/16
to
> > Following your logic to its ultimate conclusion there should exist a
> > proposal to deprecate/remove std::logic_error and exceptions derived
> > from it from C++.
>
> I think you lost the way somewhere. std::logic_error has its place, but
> that place isn't as a substitute for assert.
>

What place is left for std::logic_error? I've never
used it and only know of one guy that has:

http://stackoverflow.com/questions/2924058/confused-about-stdruntime-error-vs-stdlogic-error/6476858

He (Vladimir) said he was thinking about stopping using it
a few years ago.

Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net
0 new messages