jfh@rpp386.cactus.org (John F. Haugh II) (10/26/90)
In article <8645:Oct2521:49:5790@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: >In article <1893@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes: >> Surely you mean that if you don't know how to handle a specific recovery >> (for some unspecified error type) it's still treated as failure? > >Not at all. This might be true for calls that give me information, but >close() is not such a call. Do you check the return value of assert()? Sure, why not. You do know that assert() is documented as returning to the invoker? You have to read the abort() page to find this out, but coding assert (some impossible condition); function (! some impossible condition allowed); is naive in non-user code. What is going to happen one day when the user does for (i = 1;i < NSIG;i++) (void) signal (i, SIG_IGN); You better start checking the return code for assert() as well. -- John F. Haugh II UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 832-8832 Domain: jfh@rpp386.cactus.org "SCCS, the source motel! Programs check in and never check out!" -- Ken Thompson
daveb@nostromo.austin.ibm.com (Dave Burton) (10/30/90)
In article <18647@rpp386.cactus.org> jfh@rpp386.cactus.org (John F. Haugh II) writes: |In article <8645:Oct2521:49:5790@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: |>This might be true for calls that give me information, but |>close() is not such a call. Do you check the return value of assert()? | |Sure, why not. You do know that assert() is documented as returning |to the invoker? You have to read the abort() page to find this out, Bzzt. assert() only "returns" to the invoker when the assertion is false. Asserts are handled in XPG3 by calling abort(), about which it states: "The _abort_() function does not return." [emphasis theirs] and "SIGABRT is not intended to be caught." BSD4.3 by: directly calling exit(2). SVR2.1 by: calling _assert(), which calls abort(), which calls kill(getpid(), SIGIOT); which, admittedly, could be caught. SVR3.x by: <reference not available; hopefully better than SVR2.1> AIX3.x by: calling _assert(), which calls abort(), which raise()s SIGABRT. If SIGABRT is caught and returns, it is masked out, and raise()d again. If that doesn't make it, then exit() is called. If SIGABRT doesn't return then the point is moot; the handler exit()d. |but coding | assert (some impossible condition); | function (! some impossible condition allowed); |is naive in non-user code. What is going to happen one day when the |user does | for (i = 1;i < NSIG;i++) | (void) signal (i, SIG_IGN); |You better start checking the return code for assert() as well. See the above "citations" regarding signal trapping. All manuals (I have seen) state that the _assert_() macro returns no value. And what happens to code _if_ assert() _did_ return a value? Consider: #define NDEBUG if (assert(x==y) == -1) { /* bogus usage */ perror("assert returned"); exit(1); } Since assert() is usually (XPG3, SVR2.x, BSD4.3, AIX3) defined as a null macro if NDEBUG is #define'd, such code would not be portable (nor correct). No, John. The intent of assert() is that it compile away to nothing in the presence of NDEBUG, without the baggage of #ifdef/#endif blocks. The design of assert() is that it behave as a null statement when the assertion is true, otherwise it should abort() the program. This also corresponds nicely to the kernel functionality of assert() - it panic()s. -- Dave Burton inet: daveb@bach.austin.ibm.com uucp: cs.utexas.edu!ibmchs!auschs!nostromo!daveb
daveb@nostromo.austin.ibm.com (Dave Burton) (10/30/90)
In article <4057@awdprime.UUCP> daveb@bach.austin.ibm.com (myself) wrote: |Bzzt. assert() only "returns" to the invoker when the assertion is false. ^^^^^ Bzzt myself. Of course I meant true. If the assertion is false, the program aborts. -- Dave Burton inet: daveb@bach.austin.ibm.com uucp: cs.utexas.edu!ibmchs!auschs!nostromo!daveb
jfh@rpp386.cactus.org (John F. Haugh II) (10/30/90)
In article <4057@awdprime.UUCP> daveb@bach.austin.ibm.com (Dave Burton) writes: >In article <18647@rpp386.cactus.org> jfh@rpp386.cactus.org (John F. Haugh II) writes: >No, John. The intent of assert() is that it compile away to nothing >in the presence of NDEBUG, without the baggage of #ifdef/#endif blocks. >The design of assert() is that it behave as a null statement when the >assertion is true, otherwise it should abort() the program. so, you will always assume that failing asserts never return? this means that your portable programs aren't. accepting the statement that assert() returns control to your program in strange and unexpected ways only requires that you pay careful attention to the placement of your assert() statements, whereas rejecting this statement may lead to strange problems if you have an assert() with the SIGIOT signal ignored or caught. you could splatter your code with feature test macros for each and every one of those versions you listed, with special behavior to be followed. or you could take the easy way out, listen to your uncle fred, and just put an exit after failing assert() calls. this is easy, portable, and foolproof. it has the novel property that it always works. > This also >corresponds nicely to the kernel functionality of assert() - it panic()s. that may be true - but the kernel assert() function is not defined in the System V Programmer's Reference Manual sitting next to me. i checked the namelist on the kernel running here. no assert. hmmm. perhaps this is another IBMism? always assume the worst; never count on undocumented behavior or nonstandard features. the point of this article was to illustrate that ignoring unexpected returns can lead to unexpected results, not to serve as an oppurtunity for someone to research every version of assert(). close() may return an error. assert() may return on failure. this is how you write robust code. you can argue if catching strange returns is worth it, or you can sit back and count your bug reports. -- John F. Haugh II UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 832-8832 Domain: jfh@rpp386.cactus.org "SCCS, the source motel! Programs check in and never check out!" -- Ken Thompson
seanf@sco.COM (Sean Fagan) (10/31/90)
In article <18658@rpp386.cactus.org> jfh@rpp386.cactus.org (John F. Haugh II) writes: >so, you will always assume that failing asserts never return? Yes. I believe that's what ANSI (and POSIX) says. At least one implementation (ours, to be honest 8-)) makes sure that abort() will not return. The only way, from my glancing of the object code (disassembled, of course), to get it to return would be to send the process a signal it *does* catch, and then longjmp() out of that signal handler. But there's now way I know of to make sure that such a thing doesn't happen. (Well, you could, in abort(), block all signals, I suppose, and, now that I think about it, I think I'll see about getting us to do so 8-).) -- -----------------+ Sean Eric Fagan | "Quoth the raven," seanf@sco.COM | "Eat my shorts!" uunet!sco!seanf | -- Lisa and Bart Simpson (408) 458-1422 | Any opinions expressed are my own, not my employers'.
jim@segue.segue.com (Jim Balter) (10/31/90)
In article <18658@rpp386.cactus.org> jfh@rpp386.cactus.org (John F. Haugh II) writes: >you could take the easy way out, listen to >your uncle fred, and just put an exit after failing assert() >calls. this is easy, portable, and foolproof. it has the novel >property that it always works. You could avoid some embarrassment by testing your claims before making them public. It would appear that you've never actually used assert, or that when you do you don't follow the practice you recommend. The only way to achieve what you suggest is assert(condition); if ( !condition ) exit(1); Of course, only a fool would code this way to account for the possibility that SIGABORT is being caught and the signal routine returns. Such a SIGABORT handler is a coding error; adding a firewall to "guard" against that coding error, especially after a failed assert, is idiotic. Given that you were lucky enough to get to the assert in the first place, who the hell cares what happens after the assert? The assert means that the program is in an unexpected, undefined, unpredictable state. Then again, perhaps I can bump my code production for the code line counters and improve my code robustness at the same time by adding the following every few lines: assert(0 == 0); /* check that compiler is still working */ if ( 0 != 0 ) { abort(); /* in case assert didn't call abort */ exit(1); /* in case abort returned */ printf("exit returned unexpectedly\n"); /* perhaps the library exit routine has been overridden with a routine that returns; here we follow the pseudo-wizardly principle that all errors must be reported to the user */ /* etc. */ }
jfh@rpp386.cactus.org (John F. Haugh II) (11/01/90)
In article <4430@segue.segue.com> jim@segue.segue.com (Jim Balter) writes: >You could avoid some embarrassment by testing your claims before making them >public. It would appear that you've never actually used assert, or that when >you do you don't follow the practice you recommend. ah, but i do try these things out - | Script is typescript, started Wed Oct 31 08:09:42 1990 | rpp386-> cat abort.c | #include <signal.h> | #include <assert.h> | #include <stdio.h> | | main (argc, argv) | int argc; | char **argv; | { | signal (SIGIOT, SIG_IGN); | assert (argc == 2); | printf ("hi dave!\n"); | } | rpp386-> cc -o abort abort.c | abort.c | rpp386-> ./abort | Assertion failed: expr, file abort.c, line 10 | hi dave! | rpp386-> exit | Script done Wed Oct 31 08:10:00 1990 some people ... -- John F. Haugh II UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 832-8832 Domain: jfh@rpp386.cactus.org "SCCS, the source motel! Programs check in and never check out!" -- Ken Thompson
jim@segue.segue.com (Jim Balter) (11/02/90)
In article <18664@rpp386.cactus.org> jfh@rpp386.cactus.org (John F. Haugh II) writes: >In article <4430@segue.segue.com> jim@segue.segue.com (Jim Balter) writes: >>You could avoid some embarrassment by testing your claims before making them >>public. It would appear that you've never actually used assert, or that when >>you do you don't follow the practice you recommend. > >ah, but i do try these things out - >| signal (SIGIOT, SIG_IGN); >| assert (argc == 2); >| printf ("hi dave!\n"); The claim I was referring to was not that assert can be made to return on some systems, but rather that easy portable programming of asserts involve a call to exit. In the normal use of assert, the code following the assert is executed under normal conditions. The examples you give are simply not real uses of assert. Assert is not intended to be used to print error messages, as you seem to use it in your malloc example. A reasonable use is something like assert(ptr != NULL); /* I (the programmer) believe that the logic of the program precludes the possibility of ptr being NULL at this point. If there is a coding error that does allow ptr to be NULL, this assert will detect it and prevent the next line from referencing location 0, as long as the program is not being compiled with NDEBUG defined */ foo(*ptr); Now, just where do you intend to insert the exit in this fragment of code? >some people ... Indeed.
jfh@rpp386.cactus.org (John F. Haugh II) (11/04/90)
In article <4447@segue.segue.com> jim@segue.segue.com (Jim Balter) writes: >In the normal use of assert, the code following the assert is executed under >normal conditions. The examples you give are simply not real uses of assert. >Assert is not intended to be used to print error messages, as you seem to use >it in your malloc example. A reasonable use is something like as i said, it was a fake example. you pay your money, you take your chances. i typically don't use assert, for exactly the reasons i've mentioned. if i want a core dump, i write "abort()". if i want an error message, i use perror or fprintf. but i have found assert to vary from machine to machine enough to be useless. on one system, it may core dump. on another, it exits with no core dump ever. on yet another it always exits even if you ignore the signal and keep it from dumping core. on still yet another you can't ignore or catch the signal and it always dumps core (and always exits). so, describe the exact behavior of assert() without reference to a standards document. as another poster wrote, it appears that ANSI C (yes, i've had my eyes checked lately ;-) specifies that abort() can't return. this is good news. -- John F. Haugh II UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 832-8832 Domain: jfh@rpp386.cactus.org "SCCS, the source motel! Programs check in and never check out!" -- Ken Thompson
jim@segue.segue.com (Jim Balter) (11/05/90)
In article <18689@rpp386.cactus.org> jfh@rpp386.cactus.org (John F. Haugh II) writes: >as i said, it was a fake example. you pay your money, you take your chances. I hope no one is paying you money for your advice. >i typically don't use assert, for exactly the reasons i've mentioned. if i >want a core dump, i write "abort()". if i want an error message, i use >perror or fprintf. And if you want to make an assertion about a logical state, you ... oh, a new concept for you, eh? >but i have found assert to vary from machine to machine >enough to be useless. In other words, all your talk about how to use assert portably is hot air. Why did you bother? The fact of the matter is that there is plenty of portable code that uses assert, without an explicit call to exit. What assert does after it prints a message is irrelevant to portability because proper usage of assert (as opposed to your examples) in working code never prints a message. An assertion failure should only occur during debugging, and indicates a logic error in the program. The fact that some implementations may return from assert if SIGABORT is ignored is irrelevant because (a) no real program ignores SIGABORT (b) the printing of an assert message is an indication that the program has malfunctioned and needs debugging, and the behavior of the program *after* the assert message is printed is of little concern. And whether abort dumps core or not is an issue outside the ANSI C standard and is hardly a portability issue. Once you get an assert failure; it is time to debug; you can force all the core dumps you want.
jfh@rpp386.cactus.org (John F. Haugh II) (11/07/90)
In article <4460@segue.segue.com> jim@segue.segue.com (Jim Balter) writes: >In article <18689@rpp386.cactus.org> jfh@rpp386.cactus.org (John F. Haugh II) writes: >>as i said, it was a fake example. you pay your money, you take your chances. > >I hope no one is paying you money for your advice. well, there appears to be some confusion. it is not my "opinion" or my "advice" that assert() may return, but rather a statement of reality. like it or not, on certain machines signal (SIGIOT, SIG_IGN); assert (0 == 1); puts ("this will never print out"); WILL print out. i don't have to agree with it or disagree with it or like it or not - it is simply a statement of fact. furthermore, the statement that assert() prints an error and then calls abort() is likewise false. if your application (for example, debugging) =expects= that assert(FALSE) generate a core dump due to abort() being called, you are making an assumption that does not take into account every perverse implementation of assert() ever made - including a very popular unix-derivative from microsoft called "xenix". again, i neither have to agree or disagree that this is a good idea - i am simply reporting a fact. > And whether abort dumps core >or not is an issue outside the ANSI C standard and is hardly a portability >issue. Once you get an assert failure; it is time to debug; you can force all >the core dumps you want. there are more compilers in this world that ANSI C compilers. if you want to pretend ANSI C is the only C language out there, then of course "assert" always gives the expected result. i mean, in a perfect world everything is perfect. i have to use at least 3 different C compilers every day. i don't have the luxury of assuming every C compiler is ANSI compliant. -- John F. Haugh II UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 832-8832 Domain: jfh@rpp386.cactus.org "SCCS, the source motel! Programs check in and never check out!" -- Ken Thompson