standards: Semantics

1 
1 4.2 Writing Robust Programs
1 ===========================
1 
1 Avoid arbitrary limits on the length or number of _any_ data structure,
1 including file names, lines, files, and symbols, by allocating all data
1 structures dynamically.  In most Unix utilities, "long lines are
1 silently truncated".  This is not acceptable in a GNU utility.
1 
1    Utilities reading files should not drop NUL characters, or any other
1 nonprinting characters.  Programs should work properly with multibyte
1 character encodings, such as UTF-8.  You can use libiconv to deal with a
1 range of encodings.
1 
1    Check every system call for an error return, unless you know you wish
1 to ignore errors.  Include the system error text (from 'strerror', or
1 equivalent) in _every_ error message resulting from a failing system
1 call, as well as the name of the file if any and the name of the
1 utility.  Just "cannot open foo.c" or "stat failed" is not sufficient.
1 
1    Check every call to 'malloc' or 'realloc' to see if it returned
1 'NULL'.  Check 'realloc' even if you are making the block smaller; in a
1 system that rounds block sizes to a power of 2, 'realloc' may get a
1 different block if you ask for less space.
1 
1    You must expect 'free' to alter the contents of the block that was
1 freed.  Anything you want to fetch from the block, you must fetch before
1 calling 'free'.
1 
1    If 'malloc' fails in a noninteractive program, make that a fatal
1 error.  In an interactive program (one that reads commands from the
1 user), it is better to abort the command and return to the command
1 reader loop.  This allows the user to kill other processes to free up
1 virtual memory, and then try the command again.
1 
1    Use 'getopt_long' to decode arguments, unless the argument syntax
1 makes this unreasonable.
1 
1    When static storage is to be written in during program execution, use
1 explicit C code to initialize it.  This way, restarting the program
1 (without reloading it), or part of it, will reinitialize those
1 variables.  Reserve C initialized declarations for data that will not be
1 changed.
1 
1    Try to avoid low-level interfaces to obscure Unix data structures
1 (such as file directories, utmp, or the layout of kernel memory), since
1 these are less likely to work compatibly.  If you need to find all the
1 files in a directory, use 'readdir' or some other high-level interface.
1 These are supported compatibly by GNU.
1 
1    The preferred signal handling facilities are the BSD variant of
1 'signal', and the POSIX 'sigaction' function; the alternative USG
1 'signal' interface is an inferior design.
1 
1    Nowadays, using the POSIX signal functions may be the easiest way to
1 make a program portable.  If you use 'signal', then on GNU/Linux systems
1 running GNU libc version 1, you should include 'bsd/signal.h' instead of
1 'signal.h', so as to get BSD behavior.  It is up to you whether to
1 support systems where 'signal' has only the USG behavior, or give up on
1 them.
1 
1    In error checks that detect "impossible" conditions, just abort.
1 There is usually no point in printing any message.  These checks
1 indicate the existence of bugs.  Whoever wants to fix the bugs will have
1 to read the source code and run a debugger.  So explain the problem with
1 comments in the source.  The relevant data will be in variables, which
1 are easy to examine with the debugger, so there is no point moving them
1 elsewhere.
1 
1    Do not use a count of errors as the exit status for a program.  _That
1 does not work_, because exit status values are limited to 8 bits (0
1 through 255).  A single run of the program might have 256 errors; if you
1 try to return 256 as the exit status, the parent process will see 0 as
1 the status, and it will appear that the program succeeded.
1 
1    If you make temporary files, check the 'TMPDIR' environment variable;
1 if that variable is defined, use the specified directory instead of
1 '/tmp'.
1 
1    In addition, be aware that there is a possible security problem when
1 creating temporary files in world-writable directories.  In C, you can
1 avoid this problem by creating temporary files in this manner:
1 
1      fd = open (filename, O_WRONLY | O_CREAT | O_EXCL, 0600);
1 
11 or by using the 'mkstemps' function from Gnulib (⇒
 (gnulib)mkstemps).
1 
1    In bash, use 'set -C' (long name 'noclobber') to avoid this problem.
1 In addition, the 'mktemp' utility is a more general solution for
11 creating temporary files from shell scripts (⇒(coreutils)mktemp
 invocation).
1