Libraries can be used to record interface information. A library containing information about the Standard C Library is used to enable checking of library calls. Program libraries can be created to enable fast checking of single modules in a large program.
Standard Libraries
In order to check calls to library functions, LCLint uses an annotated standard library. This contains more information about function interfaces then is available in the system header files since it uses annotations. Further, it contains only those functions documented in the ANSI Standard. Many systems include extra functions in their system libraries; programs that use these functions cannot be compiled on other systems that do not provide them. Certain types defined by the library are treated as abstract types (e.g., a program should not rely on how the FILE type is implemented). When checking source code, LCLint does include system headers according to include directive in the source code, but instead uses the library description of the standard library.
The LCLint distribution includes several different standard libraries: the ANSI standard library, the POSIX standard library , and an ad hoc UNIX library. Each library comes in two versions: the standard version and the strict version.
ANSI Library
The default behavior of LCLint is to use the ANSI standard library (loaded from ansi.lcd). This library is based on the standard library described in the ANSI C Standard. It includes functions and types added by Amendment 1 to the ANSI C Standard.
POSIX Library
The POSIX library is selected by the +posixlib flag. The POSIX library is based on the IEEE Std 1003.1-1990.
UNIX Library
The UNIX library is selected by the +unixlib flag. This library is an ad hoc attempt to capture additional functionality provided by many UNIX platforms. Unfortunately, UNIX systems vary widely and very few are consistent with the ANSI Standard.
The differences between the UNIX library and the POSIX library are:
Code checked using the UNIX library can probably be ported to some UNIX systems without difficulty. To enhance the likelihood that a program is portable, the POSIX library should be used instead.
Strict Libraries
Stricter versions of the libraries are used if the -ansi-strict, posix-strict-lib or unix-strct-lib flag is used. These libraries use a stricter interpretation of the library. They will detect more errors in some programs, but may to produce many spurious errors for typical code.
The differences between the standard libraries and the strict libraries are:
Generating the Standard Libraries
The standard libraries are generated from header files included in the LCLint distribution. Some libraries are generated from more than one header file. Since the POSIX library includes the ANSI library, the headers for the ANSI and POSIX libraries are combined to produce the POSIX library. Similarly, the UNIX library is composed of the ANSI, POSIX and UNIX headers. The header files include some sections that are conditionally selected by defining STRICT.
The commands to generate the standard libraries are:
lclint -nolib ansi.h -dump ansi lclint -nolib -DSTRICT ansi.h -dump ansistrict lclint -nolib ansi.h posix.h -dump posix lclint -nolib -DSTRICT ansi.h posix.h -dump posixstrict lclint -nolib ansi.h posix.h unix.h -dump unix lclint -nolib -DSTRICT ansi.h posix.h unix.h -dump unixstrict
User Libraries
To enable running LCLint on large systems, mechanisms are provided for creating libraries containing necessary information. This means source files can be checked independently, after a library has been created. The command line option -dump library stores information in the file library (the default extension, .lcd[27], is added). Then, -load library loads the library. The library contains interface information from the files checked when the library was created.
Header File Inclusion
The standard behavior of LCLint on encountering
Sometimes headers in system directories contain non-standard syntax
which LCLint is unable to parse. The +skip-sys-headers flag
may be used to prevent any include file in a system directory from being
included.
LCLint is fast enough that it can be run on medium-size (10,000
line) programs without performance concerns. It takes about one second to
process a thousand source lines on a DEC Alpha. Libraries can be used to
enable efficient checking of small modules in large programs. To further
improve performance, header file inclusion can be optimized.
When processing a complete system in which many files include the same headers,
a large fraction of processing time is wasted re-reading header files
unnecessarily. If you are checking a 100-file program, and every file includes
utils.h, LCLint will have to process utils.h 100 times (as would most C
compilers). If the +singleinclude flag is used, each header file is processed
only once. Single header file processing produces a significant efficiency
improvement when checking large programs split into many files, but is only
safe if the same header file included in different contexts always has the same
meaning (i.e., it does not depend on preprocessor variable defined differently
at different inclusion sites).
When processing a single file in a large system, a large fraction of the time
is spent processing included header files. This can be avoided if the
information in the header files is stored in a library instead. If
+neverinclude is set, inclusion of files ending in .h is prevented. Files with
different suffixes are included normally. To do this the header files must not
include any expanded macros. That is, the header file must be processed with
+allmacros, and there must be no /*@notfunction@*/ control comments in the
header. Then, the +neverinclude flag may be used to prevent inclusion of header
files. Alternately, non-function macros can be moved to a different file with
a name that does not end in .h. Remember, that this file must be included
directly from the .c file, since if it is included from a .h file indirectly,
that .h file is ignored so the other file is never included.
These options can be used for significant performance improvements on large
systems. The performance depends on how the code is structured, but checking a
single module in a large program is several times faster if libraries and
+neverinclude are used.
Next: Appendix G. Specifications
#include <X.h>
is to search for a file named X.h on the include search path
(set using -I) and then the system base include path (usually
/usr/include, default is set when LCLint is compiled). If X.h is the name of a header file in a loaded standard library (either
ANSI or POSIX) and X.h is found in a directory that is a system
directory (as set by the -sysdirs flag; the default is /usr/include),
X.h will not be included if skip-ansi-headers or
skip-posix-headers (depending on whether X.h is an
ANSI or POSIX header file) is on (both are on by default). To force all
headers to be included normally, use -skip-ansi-headers and
-skip-posix-headers.
Contents