27

I see in a lot of legacy software and bad tutorials on the Internet that recommend using exit(-1), return -1 or similar to represent "abnormal termination". The problem is, in POSIX at least, -1 has never been and is not a valid status code. man 3 exit illustrates that exit() returns the value of status & 0377 to the parent, meaning that -1 becomes 255. On non-POSIX systems, EXIT_FAILURE is recommended for portability. But I never see "-1 means abnormal termination" in conjunction with "EXIT_FAILURE may be something other than 1", indicating that they clearly believe "-1" is conventional even on non-POSIX systems.

Here's an example of a StackOverflow question that perpetuates this. The software "unrealircd" is also an example of a program that uses exit(-1) to terminate the program. In practice, this makes it difficult to interface with systemd.

Where did this anti-pattern come from? Is it valid in some context?

user222973
  • 279
  • 1
  • 3
  • 3
  • 1
    "Unix-like systems have a strong convention that an exit status of 0 denotes success, and any non-zero exit status denotes failure... This convention is pretty much hard wired into Unix shells..." ([Non-zero exit status for clean exit](http://programmers.stackexchange.com/a/153934/31260)) – gnat Apr 02 '16 at 19:31
  • @gnat According to the [libc manual](https://www.gnu.org/software/libc/manual/html_node/Exit-Status.html) the exit status is explicitly 0 to 255 inclusive. If there's an answer somewhere that states that negative values were at one point valid, I would accept that, but I find that highly doubtful. – user222973 Apr 02 '16 at 19:39
  • 1
    @gnat "255" easily fits into an `unsigned char`. – user222973 Apr 02 '16 at 19:46
  • 1
    ["in UNIX/POSIX, the exit code of a program is defined to be an unsigned 8-bit value. Converting -1 to unsigned 8-bit gives 255..."](http://unix.stackexchange.com/a/37917/9466) – gnat Apr 02 '16 at 19:48
  • 1
    @gnat A byte in "Java" is not an unsigned char, it is more equivalent to a `char` since its range of values is -128 to 127. Further, I already stated "-1" gets converted to "255" in my question body. – user222973 Apr 02 '16 at 19:50
  • What makes you think an exit code of 255 is "not a valid status code"? – Lightness Races in Orbit Apr 02 '16 at 20:53
  • He is stating that -1 by itself is not valid. His question is stemming from the fact that exit(-1) is used often to terminate a program. Just because -1 converts to 255 (via unsigned 8 bit), should not mean it's valid. His example of 'unrealircd' is correct that they call exit(-1) numerous times. So even when the program terminates gracefully (not a crash or error), it returns 255 as a result, and the system treats it as an error. – Sokel Apr 02 '16 at 21:26
  • Bit arithmetic aside, my hypothesis is that the actual cause for the `exit(-1)` disease stems from people seeing how many POSIX functions return –1 to signal error conditions and they blindly transfer that to program exit codes. – 5gon12eder Apr 03 '16 at 12:36

1 Answers1

26

Almost all Unix computers use twos-complement for integers, and in twos-complement -1 is always "all bits 1" regardless of the word size. If you want the largest possible exit code regardless of the size of the program's exit status, using -1 and letting the library truncate it conveniently does the trick.

That's useful because when scripts or programs have more than one possible exit status (see grep for a simple example) the meaningful ones are usually assigned to the smallest numbers, making the largest possible exit code a good one to use for "unknown error" or "abort" since it's unlikely to ever conflict with a meaningful status value.

Todd Knarr
  • 1,019
  • 1
  • 9
  • 11
  • Take glibc as an example, which implements `exit()` as `status &= 0xff`. Is there a "word size" in which `-1 & 0xff` is not 255? Of course not, because the whole purpose is to make it fit in the range of 0-255. Regardless, your last sentence doesn't make sense: status codes 128-255 do have special purpose in UNIX systems. – user222973 Apr 02 '16 at 21:43
  • 3
    Don't confuse Bash exit values (which are 0-127, 128+ being special Bash values) with program exit values (which are 0-255, see http://pubs.opengroup.org/onlinepubs/009695399/functions/exit.html). As for the size, remember that C programmers have been dealing with multiple word sizes (originally 12, 16, and 32 bits) since the beginning so we automatically try for idioms that don't require us to consider word size. Since Unix predates Posix by 2 decades there wasn't always the 8-bit limitation so we wrote so it didn't matter. – Todd Knarr Apr 03 '16 at 02:02