assert in C

S

stan

Richard said:
(e-mail address removed) wrote:



If you need to leave the assertions in your production code, it is not
yet ready for release.

I agree and follow this as a general rule, but I'm a strong believer
in context.

Not really relevant rant follows.

Once on a project I had something like the following fail code review.

if (p == NULL) {
fprintf(stderr, "Phil fix your !@@^%$# code you moron\n");
kill(phil);
}

while this was accepted
assert(p != NULL); /* If you can read this, call Phil x5667 */


Sadly, the assert worked. The code was delivered, failed, and
corrected after a maintenance call. It was a military job and
sometimes you have to play the hand you're dealt.
One might think of it this way: assertions are intended to reveal bugs
in the program, not bugs in the data. A wrong program needs the
programmer's attention, but wrong data is, at least in theory,
susceptible to correction by the user, so one should make it
(relatively) easy for the user to correct the data, for example by
offering another opportunity to provide it. One does not do this by
bombing out of the program.

I like it but I'd include system resources in the misuses.
 
D

Dann Corbit

I agree and follow this as a general rule, but I'm a strong believer
in context.

Not really relevant rant follows.

Once on a project I had something like the following fail code review.

if (p == NULL) {
fprintf(stderr, "Phil fix your !@@^%$# code you moron\n");
kill(phil);
}

while this was accepted
assert(p != NULL); /* If you can read this, call Phil x5667 */


Sadly, the assert worked. The code was delivered, failed, and
corrected after a maintenance call. It was a military job and
sometimes you have to play the hand you're dealt.


I like it but I'd include system resources in the misuses.

When code is compiled in release mode, an assert() call does nothing at
all. If an assert() fires, then code was delivered to a customer
without having NDEBUG defined at compile time.

So the burning question is, why is debug code being delivered in the
first place?

7.2 Diagnostics <assert.h>
1 The header <assert.h> defines the assert macro and refers to another
macro, NDEBUG which is not defined by <assert.h>. If NDEBUG is defined
as a macro name at the point in the source file where <assert.h> is
included, the assert macro is defined simply as
#define assert(ignore) ((void)0)
The assert macro is redefined according to the current state of NDEBUG
each time that <assert.h> is included.
 
E

Eric Sosman

[...]
So the burning question is, why is debug code being delivered in the
first place?

Because the deliverers are negligent, having failed to
remove The Last Bug before delivery?
 
S

stan

Dann Corbit wrote:

When code is compiled in release mode, an assert() call does nothing at
all. If an assert() fires, then code was delivered to a customer
without having NDEBUG defined at compile time.

So the burning question is, why is debug code being delivered in the
first place?

Policy from on high. Most likely cause is the Peter Principle.
 
K

Keith Thompson

stan said:
Dann Corbit wrote:


Policy from on high. Most likely cause is the Peter Principle.

Or because, even in released software, having the program crash with
an error message might be considered better than having it continue to
execute with random results.
 
E

Eric Sosman

Dann Corbit wrote:



Policy from on high. Most likely cause is the Peter Principle.

You mentioned that the code was written for a military
customer. In the USA, the military and NASA and various other
agencies are big believers in "Test what you'll fly; fly what
you tested."

The policy proved invaluable when Mars Pathfinder landed on
Mars and *then* started doing uncontrollable and unscheduled
reboots; the debugging code that was still onboard allowed
ground control to diagnose and patch the problem. Sending a
field engineer on a 240 million mile round trip would have
been inconvenient.
 
E

Eric Sosman

[...] Sending a
field engineer on a 240 million mile round trip would have
been inconvenient.

Sorry; the distance is wrong. I got it from the Pathfinder
web site, where they've obviously converted kilometers to miles
incorrectly. There seems to be a history of units confusion on
Mars missions ...
 
J

Jens Thoms Toerring

Dann Corbit said:
When code is compiled in release mode, an assert() call does nothing at
all. If an assert() fires, then code was delivered to a customer
without having NDEBUG defined at compile time.
So the burning question is, why is debug code being delivered in the
first place?

There can be situations where it simply isn't possible to do
rigorous testing before delivery. I am often writing code for
controlling lab equiment that's far too expensive to have
around (beside not having room to put it nor, in some cases,
the necessary supply of LN2 or LHe2 to operate it;-). And
there's not enough time (and money) for doing in-depth tes-
ting on-site. So the customer understands that there probably
still will be bugs in the code, both due to me getting it
wrong or the manuals for the equipment not being correct and/
or complete (which happens quite a lot, unfortunately). And
since bad code can, at least in some situations, damage the
equiment I very much try to err on the side of having the
program trigger an assert() than having it do something that
may be very expensive to repair if I got it wrong...

Thus I put asserts in the code in all kinds of places I am
in principle convinced of they never can be reached and have
a framework in place that sends me an email with a backtrace
if an assert() is triggered anyway. That way the customer
and me both benefit - I get a rather reliable indication of
what went wrong, the customers equipment doesn't get damaged,
s/he gets an error message that stands out plus I can quickly
react without him/her having to explain what exactly they were
doing at the moment the assert() was triggered (which is often
very hard to figure out without a backtrace or lots of trial
and error to reproduce the exact same conditions). And I tend
to leave the asserts in even if after some time nothing unto-
ward happened since a) I never can be sure how much of the code
has really been used and thus tested and b) a replacement device
with new firmware may behave differently in unpredictable ways
from the original one.

Of course, that could be seen as a mis-use of asserts, but
then they're simply convenient to use and the time spend on
checking asserts is negligible compared to the time spend on
waiting for devices to react (and the code is also littered
with all kinds of tests for other things that could go wrong
and asserts are just an emergency break if nothing else caught
the problem before, i.e. the cases that I assumed to be impos-
sible but were not 150% sure).
Regards, Jens
 
K

Keith Thompson

Richard Heathfield said:
Then you can use an assert-like mechanism that isn't assert(). Using
assert() for testing conditions in production code is like using a
hammer for driving in screws. Although it works, there are better
tools for the job. In your situation, I would probably write a
PRD_ASSERT macro, with whatever semantics you need but which isn't
affected by NDEBUG. That would give you the best of both worlds.

<snip>

If the behavior of assert() is suitable for his purposes, what
advantage would a PRD_ASSERT macro have? (It's easy enough to refrain
from defining NDEBUG.)
 
K

Keith Thompson

Richard Heathfield said:
The macro would re-establish the distinction between development aids
and debugging aids. Personally, I find that distinction immensely
useful.

Ok, that's a good point. For expensive checks (checking whether a
tree is balanced, or an array is sorted), it's good to be able to
disable them in production code, even if they're valuable during
development.
The way I see it, if you want to check something in production
code, you can easily do that without using assertions. The assert()
macro is specifically designed to be capable of being switched off for
production code, and is unnecessarily aggressive if left /in/
production code. If you don't trust the assertion never to fire in
production even if it were enabled, then I would argue that the proper
course is to put in code to handle the eventuality in a more graceful
way.

You're assuming that there's a more graceful way to handle the error
than aborting the program. Sometimes there is, sometimes there isn't.
 
S

stan

Eric said:
You mentioned that the code was written for a military
customer. In the USA, the military and NASA and various other
agencies are big believers in "Test what you'll fly; fly what
you tested."

Actually it wasn't a military customer, I was active duty. I agree
with the policy mentioned and I wasn't overly torn by keeping assert
active in the final code, although I thought it was subobtimal. There
were few asserts that couldn't have been improved with better panic
information. At that point your getting close to considering the
conditions as handled errors rather than inconsistent state.

My rant was more because we had an idiot who either wouldn't or
couldn't understand that you must check the returns and handle system
resource failures. The system being what it was decided that it was
easier to simply include an assert to recognize an inevitable failure
rather than fix the known problem.

Your point has merit but my situation was a little different. In the
specific case that firing assert clearly indicated a failure of
management more than code. The incident colors my view of asserts to
this day. Bottom line is that the assert fixed both the bad code and
clueless management. As the saying went back then "wrong thing done right".
The policy proved invaluable when Mars Pathfinder landed on
Mars and *then* started doing uncontrollable and unscheduled
reboots; the debugging code that was still onboard allowed
ground control to diagnose and patch the problem. Sending a
field engineer on a 240 million mile round trip would have
been inconvenient.

But the per diem would be sweet!
 
E

Eric Sosman

Eric said:
[...]
So the burning question is, why is debug code being delivered in the
first place?

Because the deliverers are negligent, having failed to
remove The Last Bug before delivery?


But since they didn't assert the last bug to be absent anyway, there is
no point in leaving the assertions in.

Not sure I understand you: Are you saying an assert() that
never fired during testing can never fire in production?

Diligent developers test as thoroughly as they can, but it
is rare to be able to test *every* combination of circumstances
a program will confront. Or, as Roseanne Roseannadanna said,
"It's always something."
 
S

Stefan Ram

There can be situations where it simply isn't possible to do
rigorous testing before delivery. I am often writing code for
controlling lab equiment that's far too expensive to have
around

A report about software manufacturing for
controlling expensive equipment:

http://www.fastcompany.com/node/28121/print

.
program trigger an assert() than having it do something that
(...)
what went wrong, the customers equipment doesn't get damaged,

Of course, /not/ doing something at a certain instant
might cause just as much damage as doing something.

In the end it's the customers decision, when he does
not want to pay more time and/oe money for better code.
 
N

Nobody

OK, then if I compile the c program in release mode, the assert
statement should not workable, is it wrong?
If it is wrong, then how to disable the assert statement by gcc?

"release mode" is a concept popularised by some Windows IDEs. It isn't
defined by any standard, or recognised by compilers.

The aforementioned IDEs typically create two profiles whenever you create
a workspace. The "debug" profile enables debug info and disables
optimisations, while the "release" profile disables debug info (and
possibly assert()s) and enables some level of optimisation.

C compilers typically provide entirely separate options for debug info and
optimisations. E.g. with no switches, gcc doesn't provide debug info and
doesn't perform optimisation.

OTOH, autoconf-based configure scripts will normally set CFLAGS to
"-g -O2" (debug info generated and most optimisations enabled) if
the C compiler is gcc, unless overridden by the user.

The rationale is that -O2 is suitable for production binaries (whether
or not it's a good idea to use -O3 varies with the code, the platform and
the compiler version), and the added debug information might be useful (if
it isn't, and you actually need to reduce the size of binaries, you
can "strip" them later).

There is no performance issue with including debug info (it won't be
mapped into RAM for normal execution), and projects using autoconf are
mostly free software where you're not worried about the debug info
facilitating reverse engineering.
 
S

Squeamizh

I'm a big believer in that, too. The code should be tested with
assertions in place, and every assertion should have tests designed to
cause it to fire if possible. If and only if rigorous testing fails to
fire any assertions, they should be removed. And THEN you test AGAIN -
because, as you say, you should test what you ship and ship what you tested.


It sounds like they had a good infrastructure design. It also sounds
like they didn't have assertions firing, since assertions don't reboot
the machine - they just abort the program.

Assertions do whatever you want them to do. As I mentioned earlier in
the thread, my asserts generate a coredump and reboot the device.
This has been an extremely mechanism for debugging unforeseen problems
in the field.
 
R

Richard Tobin

Richard Heathfield said:
You will, however, not be surprised to learn that there is a
considerable body of opinion to the effect that assertions should be
left *on* in production code.

I leave assertions on in the compiled versions of my code that I
distribute. On the other hand, I don't say anyone *should*
leave them on.
The analogy that this view's supporters
like to trot out is "you wouldn't take the lifeboats off a ship before
sending it out to sea"...

I've never used such an analogy.

The assertions in my code are fairly cheap, and their presence makes
it more likely that I will be find out about bugs. And for many of my
users undetected errors would worse than an abort.

You might reasonably say that I should use something else rather than
assert, and perhaps some time I will go through the code changing it,
but it hasn't become a high priority.

-- Richard
 
R

Richard Tobin

Richard said:
Asserts suck because of the termination. In 99% of test cases where that
assert triggers you can also merely run the program in a debugger and
get a backtrace there and then and "live debug".

I can't see what you're getting at here. In the cases where I use
assert, I want the program to terminate, to ensure that no-one uses
the (probably incorrect) results. If I then run the program under the
debugger, the abort resulting from assertion failure will be caught by
the debugger and I can debug from there.

-- Richard
 
R

Richard Tobin

Richard Heathfield said:
If you need to leave the assertions in your production code, it is not
yet ready for release.

And yet many - probably almost all - released programs have errors
that are, or could be, caught by assertions. You may conclude that
most programs are released when they are not ready, but turning off
assertions is not going to fix that.

The only reason to turn off assertions is if their overhead outweighs
their advantage. If their overhead is small, why turn them off at all?
What do you gain?

-- Richard
 
R

Richard Tobin

Because the deliverers are negligent, having failed to
remove The Last Bug before delivery?
[/QUOTE]
But since they didn't assert the last bug to be absent anyway, there is
no point in leaving the assertions in.

This is ridiculous. It may mean that bugs are never noticed, and
incorrect results are used, or it may require much more effort to
debug, say, a segmentation fault.

-- Richard
 
R

Richard Tobin

You're assuming that there's a more graceful way to handle the error
than aborting the program. Sometimes there is, sometimes there isn't.
[/QUOTE]
For a null pointer because of some crazy exec path possibly there is :
ignore it.

A null pointer will generally provoke an error sooner or later. An
assertion is useful for making it happen sooner: several times I've
immediately been able to work out what the error is from an assertion
message, while a segmentation fault some time later would have
required substantial debugging.

-- Richard
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top