2
\$\begingroup\$

Here you go:

#define abort(msg) (fprintf(stderr, msg) && *((char*)0))
\$\endgroup\$
  • 3
    \$\begingroup\$ I'm pretty sure others are going to agree with me on this, but this is way way too short to be considered for a code review. \$\endgroup\$ – Mark Loeser Feb 2 '11 at 14:44
  • 1
    \$\begingroup\$ Also, interesting that you want to cause a SIGSEGV instead of a SIGABRT. \$\endgroup\$ – Mark Loeser Feb 2 '11 at 14:49
  • 2
    \$\begingroup\$ @mark: I'm not so sure, I think a meaty one liner could count as a minimum size. Of course the answers are going to be more limited, but they could cover style and efficiency. \$\endgroup\$ – winwaed Feb 2 '11 at 15:48
  • \$\begingroup\$ Do you intend your code to be platform-independent? The correct implementation may be platform specific. At the end of that function, it may need to raise a certain signal, or some other system call. \$\endgroup\$ – rwong Feb 3 '11 at 7:21
  • \$\begingroup\$ I think accessing the null pointer results in undefined behavior. On some operating systems it might silently return some value instead of crashing. \$\endgroup\$ – CodesInChaos Feb 5 '11 at 17:15
15
\$\begingroup\$

Non-standard interface to standard function

The obvious criticism of that implementation is that it has a different interface from what the C standard requires:

§7.20.4.1 The abort function

Synopsis

#include <stdlib.h>
void abort(void);

Description

The abort function causes abnormal program termination to occur, unless the signal SIGABRT is being caught and the signal handler does not return. Whether open streams with unwritten buffered data are flushed, open streams are closed, or temporary files are removed is implementation-defined. An implementation-defined form of the status unsuccessful termination is returned to the host environment by means of the function call raise(SIGABRT).

Returns

The abort function does not return to its caller.

Unreliable implementation of 'crash'

There were systems, notoriously the DEC VAX, where accessing the memory at address 0 did not cause problems (until the programs that were written on the VAX were ported to other platforms that did abort).

Dereferencing a null pointer is undefined behaviour - that means anything could happen, including 'no crash'.

Nitpicks in implementation

If, for some reason, fprintf() returns 0, your program will not abort. For example:

abort("");

does not abort. It is also dangerous to use the string as the format string; you should use:

#define abort(msg) (fprintf(stderr, "%s\n", msg) && *((char*)0))

It would be better to use a comma operator in place of the &&:

#define abort(msg) (fprintf(stderr, "%s\n", msg), raise(SIGABRT))

Since the standard library could have defined a macro abort(), you should #undef it before defining it yourself.

\$\endgroup\$
  • \$\begingroup\$ maybe prefer fputs? \$\endgroup\$ – Ben Voigt Oct 16 '11 at 1:29
  • \$\begingroup\$ One reason not to use fputs() is that it does not add a newline to the string (unlike puts() - but that writes to stdout instead of stderr), so you'd have to call it twice, once with the user string and once with the newline. It seems simpler to call fprintf() once. \$\endgroup\$ – Jonathan Leffler Oct 16 '11 at 3:34
  • \$\begingroup\$ @Johnathan: I'm pretty sure that fputs followed by fputc(stderr, '\n') (and then flush) would be far faster than fprintf. When you're reporting an error, you usually want to use the most trivial functions possible (lest data corruption prevent them from running) and fputs and fputc are much much simpler than fprintf. \$\endgroup\$ – Ben Voigt Oct 16 '11 at 3:55
5
\$\begingroup\$

My criticism is you are trying to abort via a crash:

*((char*)0))

This invokes undefined behavior. It does not necessarily invoke a crash (or termination).

If you want to raise the abort signal do so explicitly:

raise(SIGABRT)

Also you are re-defing a system method using #define (I am relatively sure this is not allowed and causes undefined behavior though I can not quote chapter and verse).

#define abort(msg) 

Also by doing this you need to search through all the source to find any current usage of abort. As this may clash with the new usage (or will the pre-processor be intelligent about it. The fact that I ask the question should make you worry let alone the answer).

Why not define your own function with a slightly different name (this will also allow you to call the system abort).

#define abortWithMsg(msg) do { fprintf(stderr, msg); abort(); } while (false)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.