assert in C

K

Keith Thompson

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.[/QUOTE]

And it doesn't *always* provoke an error.

For example, in at least one implementation (gcc with glibc), this
program:

#include <stdio.h>
int main(void)
{
char *nullptr = NULL;
printf("nullptr = %s\n", nullptr);
return 0;
}

prints

nullptr = (null)

Apparently the glibc implementation of printf's "%s" format
"helpfully" recognizes null pointers and prints "(null)" rather than
crashing. I've seen "(null)" appear in the output of production
programs because of this, an error that probably would have been
caught if the code had crashed.

Undefined behavior is undefined behavior; it doesn't mean "the program
will crash".
 
S

Squeamizh

I'm talking specifically about C's assertions, i.e. assert(), which
prints a message and aborts the program. If you're talking about some
other kind of assertion, we are talking at cross-purposes.

It is common practice, it least in my experience, to redefine the
assert macro. That is what I meant; I should have been more clear.
 
N

Nick Keighley

(e-mail address removed) wrote:


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

do you never make mistakes? You may think your testing is perfect but
the real world can surprise you. The sooner the program detects it is
at fault and closes down the easier it is to find the problem.
 
N

Nick Keighley

I don't have special magic "debug" code. Well ok, there are versions
with more checking enabled; but the production still has some checks
left in it. I'm not perfect.
No, I'm not saying that. After all, it would be trivial to disprove
(simply by deliberately designing an inadequate test pack). The above
comment specifically addressed your point - i.e. that leaving the
assertions in would not in any case have found The Last Bug. Nothing
/ever/ finds The Last Bug.


Ideally, developers *should not be doing the testing*!

not everyone has this two tier system available
There are people
who earn a very good living as specialised testers, and their first rule
is a simple one: "YOU do the debugging; WE will do the testing."

done that. I'd recomend every software devoloper spends a stint in
test. It chnages your point of view! I kept a list of Reasons Why This
Isn't A Bug. "but the user would never do that!" and "but the code
says that's supposed to happen!" being my favourites. Oh, and "I did't
see that light flash".

This
isn't demarcation for the sake of it, but for the important reason that
a tester has a completely different approach to testing than a
developer.

the developer wants to see it work the tester wants to Break It!

It's much the same as in comp.lang.c - although it sometimes
happens that a person requesting help with a problem finds his own
solution, it is far more normal for someone else to find it - a person
with a different set of eyes, and a more critical attitude. It is very
difficult to approach one's own code with a sufficiently critical eye.

I have, on occasion, had testers succeed in firing my assertions. They
were always heartily pleased with themselves for so doing (and rightly
so),

I would be!

and of course it's a bit deflating to see one's code broken in that
way,

oh definitly. An assert that fires in system test is deeply
embarassing. Though substantially better than firing on a customer's
site!

but it does result in more reliable software.
yes


After a competent
tester has thumped the code good and hard, the chance of an assertion
condition being met in production is vastly reduced. Can you eliminate
the possibility entirely? No, of course not. But you can reduce the risk
sufficiently that to worry about it would be disproportionate, compared
to all the other things that could go wrong. (Analogy: yes, you can
reduce your risk of a car accident by checking your tyre tread every
hundred yards or so, but to do so would be disproportionate - the payoff
is so epsilon it's practically zeta.) If your assertions are time-costly
(as many of mine are),

mine vary
the performance cost would be prohibitive.

I look at it this way - if I have the slightest concern that an
assertion could conceivably fire in production, I'll code around it (*as
well as* asserting it).

yes
 
N

Nick Keighley

     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.

I got some installation procedures upgraded

N: these installation procedures are a bit difficult for a naive user
(I was blunter)
X: who cares? the system is always installed by a developer
N: you're going to <central continent> in <bad season> are you?
X: ah...
 
F

Frank

Certainly the idea of leaving the asserts in is something that I would want
as a customer, but I'm not paying anyone to program. I do buy books about
C, and Plauger's work has asserts all over it.
Is your PRD_ASSERT home grown:
Sorry, nothing was found in the compleat manual for search PRD_ASSERT
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.)

Is it as easy as just undefining it before including assert.h?

static void dummy()
{ /* test dummy assert macro */
int i = 0;

assert(i == 0);
assert(i == 1);
}

#undef NDEBUG
#include <assert.h>

int main()
{ /* test both dummy and working forms */
assert(signal(SIGABRT, &field_abort) != SIG_ERR);
dummy();
assert(val == 0); /* should not abort */
++val;
fputs("Sample assertion failure message --\n", stderr);
assert(val == 0); /* should abort */
puts("FAILURE testing <assert.h>");
return (EXIT_FAILURE);
}
 
F

Frank

Sure - but it can do so in a graceful way, that guides the user through
the reasoning for closing down the program, and explains in
user-friendly detail what to do about it. An abort is not graceful.

What about Jens's abort that sends an e-mail with the data that led to the
failure. I'm curious how he does this with C.
 
N

Nick

Frank said:
What about Jens's abort that sends an e-mail with the data that led to the
failure. I'm curious how he does this with C.

I do it. It's completely undefined behaviour: I use signal handling, so
I catch segmentation faults as well. But although undefined (the
undefined bit is actually doing anything in a signal handler), it's
doable with (almost) completely standard C: trap the signal, collect
together the information and call an external email program. The
"almost" is because in practice I open a pipe to the program rather than
write the information to a file. Despite the fact you are doing all
sorts of things (like opening external programs) even after a
segmentation violation, it works remarkably well.
 
F

Flash Gordon

Nick said:
I do it. It's completely undefined behaviour: I use signal handling, so
I catch segmentation faults as well. But although undefined (the
undefined bit is actually doing anything in a signal handler), it's
doable with (almost) completely standard C: trap the signal, collect
together the information and call an external email program. The
"almost" is because in practice I open a pipe to the program rather than
write the information to a file. Despite the fact you are doing all
sorts of things (like opening external programs) even after a
segmentation violation, it works remarkably well.

I do something similar, except I open a socket and talk SMTP to an email
server to send the email. This being on a long-running daemon it is
extremely useful to my customers that they get an email if the
unexpected happens and the daemon crashes.
 
R

Richard Tobin

Richard Heathfield said:
If you leave assertions on and they never fire in production, you have a
performance cost for no gain.

In the case of my asserts, this is negligible, probably unmeasurable.
If you leave assertions and and they /do/
fire, you gain a bug report (possibly) at the expense of a (possibly)
annoyed and disaffected customer - assertion messages are unfailingly
user-hostile.

No. I suppose that might be your situation, but it seems a bit
odd. Would your customers prefer the program to continue when
something is wrong? I can imagine situations where that is true - a
computer game for example - but is that what you are doing?

By the way, like many programmers, I don't have customers, I
have users.
If you turn assertions off and they would never have fired
anyway, you gain full performance at no cost.

As above; there is no significant gain in my case.
If you turn assertions off
and they /would/ have fired anyway, you gain performance but lose
correctness (i.e. a program assumption was incorrect, with heaven knows
what consequences).

Given my users, the consequences of undetected errors would probably
be worse than even moderate costs; they might publish scientific
papers with incorrect conclusions, for example.
So it is with assertions *off* that we have both the greatest potential
gain

Not in my case.
and the greatest potential loss.
Yes.

The question is how likely it is
that assertions will fire. Rigorous testing should make it
extraordinarily unlikely,

That may be practical in your situation, but not mine. I have
no testers except me and my users, and no-one is paying me even to
produce the code; I just do it as part of my research.
and coding defensively around the least
unlikely problems should make the highly improbable extremely highly
improbable.

Using assertions *is* coding defensively. It makes it more likely that
my errors will have a benign consequence, viz. an abort.

-- Richard
 
B

Beej Jorgensen

No. I would imagine that *any* user would prefer the program to stop
gracefully when something is wrong.

Depends on the circumstances. Sometimes we wish the program to continue
as gracefully as possible when something is wrong...

-Beej
 
B

Beej Jorgensen

So as long as the asserts do not degrade the performance to a level that
hurts the customer leaving them switched on seems a good option.

If you're going to do this, why would you not simply put in some real
error handling for all these cases, instead of using assert()?

-Beej
 
R

Richard Tobin

Richard Heathfield said:
Your circumstances are unusual in that your users are very
technically-minded people who, I would guess, can get you on the phone
very easily(?).

We have had e-mail for several years now...

-- Richard
 
F

Flash Gordon

Keith said:
Interprocess communication is off-topic.

:)

Except when done by simply writing to a file which some other process
later reads... so write the error report to a file and tell the user to
send the file to the developer :)

Not an entirely daft suggestion, sometimes it can be a very good way of
providing a user friendly error message and a detailed report for the
developer. The problem with nice seeming error reporting mechanisms is
that you also have to trap errors occurring in your error trapping and
handle that nicely... so in some of our code we have a handler on
SIGSEGV which keeps track of whether it has been called recursively and
each time it is nested tries to do less.
 
B

Beej Jorgensen

Some errors are unrecoverable.
And an abort is better than an incorrect result.

I agree, but that doesn't necessarily mean calling C99 assert(). One
could call some more reasonable error reporting code, instead,
especially if the error is one that could occur in a production environment.

-Beej
 
R

Richard Tobin

Oh, true. I use an ASSERT() macro which prints the failed condition,
line number, source file etc, to stdout and stderr....

Programs that send error messages to stdout are a pain. If you're
running a pipeline of programs, there's no guarantee that the
downstream program will get terminated before it tries to process the
error message as data, resulting in a cascade of errors from which it
is tedious to extract the real problem.

Of course, progams which send errors to stdout and *not* stderr
are even worse.

-- Richard
 
N

Nick

Richard Heathfield said:
This point has been made over and over again - by you, by me, by Uncle
Tom Cobbley, and by all. It doesn't matter, though - the
assert()-in-production lobby thinks not asserting means not
terminating, and aren't about to let the facts confuse the matter.

One of the (small) benefits is that everybody knows "assert" is "check
condition and die if not met", and is practically costless (even when
not turned off). When they come across My_Assert() or Gerferken() or
whatever they are going to have to look it up. Not a big issue, but a
real one nevertheless.
 
R

Richard Tobin

Can you do that with my program?

I've no idea. I assumed you were telling comp.lang.c what you do
because other people might find it useful. I'm telling them why it
might be a bad idea, which it is for most programs.

I must say the rest of your post is rather an overreaction!

-- 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,774
Messages
2,569,596
Members
45,135
Latest member
VeronaShap
Top