C H A P T E R  5

lint Source Code Checker

This chapter explains how you can use the lint program to check your C code for errors that may cause a compilation failure or unexpected results at runtime. In many cases, lint warns you about incorrect, error-prone, or nonstandard code that the compiler does not necessarily flag.

The lint program issues every error and warning message produced by the C compiler. It also issues warnings about potential bugs and portability problems. Many messages issued by lint can assist you in improving your program's effectiveness, including reducing its size and required memory.

The lint program uses the same locale as the compiler and the output from lint is directed to stderr. See Chapter 6 for more information on and examples of how to use lint to check code before you perform type-based alias-disambiguation.


5.1 Basic and Enhanced lint Modes

The lint program operates in two modes:

In both basic and enhanced modes, lint compensates for separate and independent compilation in C by flagging inconsistencies in definition and use across files, including any libraries you have used. In a large project environment especially, where the same function may be used by different programmers in hundreds of separate modules of code, lint can help discover bugs that otherwise might be difficult to find. A function called with one less argument than expected, for example, looks at the stack for a value the call has never pushed, with results correct in one condition, incorrect in another, depending on whatever happens to be in memory at that stack location. By identifying dependencies like this one and dependencies on machine architecture as well, lint can improve the reliability of code run on your machine or someone else's.

In enhanced mode, lint provides more detailed reporting than in basic mode. In basic mode, lint's capabilities include:

In enhanced mode, lint can detect these problems:


5.2 Using lint

Invoke the lint program and its options from the command line. To invoke lint in the basic mode, use the following command:

% lint file1.c file2.c

Enhanced lint is invoked with the -Nlevel or -Ncheck option. For example, you can invoke enhanced lint as follows:

% lint -Nlevel=3 file1.c file2.c

lint examines code in two passes. In the first pass, lint checks for error conditions within C source files; in the second pass, it checks for inconsistencies across C source files. This process is invisible to the user unless lint is invoked with -c:

% lint -c file1.c file2.c

That command directs lint to execute the first pass only and collect information relevant to the second--about inconsistencies in definition and use across file1.c and file2.c--in intermediate files named file1.ln and file2.ln:

% ls 
file1.c
file1.ln
file2.c
file2.ln

This way, the -c option to lint is analogous to the -c option to cc, which suppresses the link editing phase of compilation. Generally speaking, lint's command-line syntax closely follows cc's.

When the .ln files are linted:

% lint file1.ln file2.ln

the second pass is executed. lint processes any number of .c or .ln files in their command-line order. Thus,

% lint file1.ln file2.ln file3.c

directs lint to check file3.c for errors internal to it and all three files for consistency.

lint searches directories for included header files in the same order as cc. You can use the -I option to lint as you would the -I option to cc. See Section 2.14, How to Specify Include Files.

You can specify multiple options to lint on the same command line. Options can be concatenated unless one of the options takes an argument or if the option has more than one letter:

% lint -cp -Idir1 -Idir2 file1.c file2.c

That command directs lint to:

lint has many options you can use to direct lint to perform certain tasks and report on certain conditions.


5.3 The lint Options

The lint program is a static analyzer. It cannot evaluate the runtime consequences of the dependencies it detects. Certain programs, for instance, may contain hundreds of unreachable break statements that are of little importance, but which lint flags nevertheless. This is one example where the lint command-line options and directives--special comments embedded in the source text--come in:

The lint options are listed below alphabetically. Several lint options relate to suppressing lint diagnostic messages. These options are also listed in TABLE 5-8, following the alphabetized options, along with the specific messages they suppress. The options for invoking enhanced lint begin with -N.

lint recognizes many cc command-line options, including -A, -D, -E, -g, -H, -O, -P, -U, -Xa, -Xc, -Xs, -Xt, and -Y, although -g and -O are ignored. Unrecognized options are warned about and ignored.

5.3.1 -#

Turns on verbose mode, showing each component as it is invoked.

5.3.2 -###

Shows each component as it is invoked, but does not actually execute it.

5.3.3 -a

Suppresses certain messages. Refer to TABLE 5-8.

5.3.4 -b

Suppresses certain messages. Refer to TABLE 5-8.

5.3.5 -C filename

Creates a .ln file with the file name specified. These .ln files are the product of lint's first pass only. filename can be a complete path name.

5.3.6 -c

Creates a .ln file consisting of information relevant to lint's second pass for every .c file named on the command line. The second pass is not executed.

5.3.7 -dirout=dir

Specifies the directory dir where the lint output files (.ln files) will be placed. This option affects the -c option.

5.3.8 -err=warn

-err=warn is a macro for -errwarn=%all. See Section 5.3.15, -errwarn=t.

5.3.9 -errchk=l(, l)

Perform additional checking as specified by l. The default is -errchk=%none. Specifying -errchk is equivalent to specifying -errchk=%all. l is a comma-separated list of checks that consists of one or more of the following. For example, -errchk=longptr64,structarg.

TABLE 5-1 The -errchk Flags

Value

Meaning

%all

Perform all of -errchk's checks.

%none

Perform none of -errchk's checks. This is the default.

[no%]locfmtchk

Check for printf-like format strings during the first pass of lint. Regardless of whether or not you use -errchk=locfmtchk, lint always checks for printf-like format strings in its second pass.

[no%]longptr64

Check portability to environment for which the size of long integers and pointers is 64 bits and the size of plain integers is 32 bits. Check assignments of pointer expressions and long integer expressions to plain integers, even when explicit cast is used.

[no%]structarg

Check structural arguments passed by value and report the cases when formal parameter type is not known.

[no%]parentheses

Check the clarity of precedence within your code. Use this option to enhance the maintainability of code. If -errchk=parentheses returns a warning, consider using additional parentheses to clearly signify the precedence of operations within the code.

[no%]signext

Check for situations in which the normal ISO C value-preserving rules allow the extension of the sign of a signed-integral value in an expression of unsigned-integral type. This option only produces error messages when you specify -errchk=longptr64 as well.

[no%]sizematch

Check for the assignment of a larger integer to a smaller integer and issue a warning. These warnings are also issued for assignment between same size integers that have different signs (unsigned int gets a signed int).


5.3.10 -errfmt=f

Specifies the format of lint output. f can be one of the following: macro, simple, src, or tab.

TABLE 5-2 The -errfmt Flags

Value

Meaning

macro

Displays the source code, the line number, and the place of the error, with macro unfolding

simple

Displays the line number and the place number, in brackets, of the error, for one-line (simple) diagnostic messages. Similar to the -s option, but includes error-position information

src

Displays the source code, the line number, and the place of the error (no macro unfolding)

tab

Displays in tabular format. This is the default.


The default is -errfmt=tab. Specifying -errfmt is equivalent to specifying -errfmt=tab.

If more than one format is specified, the last format specified is used, and lint warns about the unused formats.

5.3.11 -errhdr=h

Enables the reporting of certain messages for header files when used with -Ncheck. h is a comma-separated list that consists of one or more of the following: dir, no%dir, %all, %none, %user.

TABLE 5-3 The -errhdr Flags

Value

Meaning

dir

Checks header files used in the directory dir

no%dir

Does not check header files used in the directory dir

%all

Checks all used header files

%none

Does not check header files. This is the default.

%user

Checks all used user header files, that is, all header files except those in /usr/include and its subdirectories, as well as those supplied by the compiler


The default is -errhdr=%none. Specifying -errhdr is equivalent to specifying -errhdr=%user.

Examples:

% lint -errhdr=inc1 -errhdr=../inc2

checks used header files in directories inc1 and ../inc2.

% lint -errhdr=%all,no%../inc

checks all used header files except those in the directory ../inc.

5.3.12 -erroff=tag(, tag)

Suppresses or enables lint error messages.

t is a comma-separated list that consists of one or more of the following: tag, no%tag, %all, %none.

TABLE 5-4 The -erroff Flags

Value

Meaning

tag

Suppresses the message specified by this tag. You can display the tag for a message by using the -errtags=yes option.

no%tag

Enables the message specified by this tag

%all

Suppresses all messages

%none

Enables all messages. This is the default.


The default is -erroff=%none. Specifying -erroff is equivalent to specifying -erroff=%all.

Examples:

% lint -erroff=%all,no%E_ENUM_NEVER_DEF,no%E_STATIC_UNUSED

prints only the messages "enum never defined" and "static unused", and suppresses other messages.

% lint -erroff=E_ENUM_NEVER_DEF,E_STATIC_UNUSED

suppresses only the messages "enum never defined" and "static unused".

5.3.13 -errsecurity=v

Use the -errsecurity option to check your code for security loopholes.

v must be one of the following:

TABLE 5-5 The -errsecurity Flags

Option

Meaning

core

This level checks for source code constructs that are almost always either unsafe or difficult to verify. Checks at this level include:

  • Use of variable format strings with the printf() and scanf() family of functions
  • Use of unbounded string (%s) formats in scanf() functions
  • Use of functions with no safe usage: gets(), cftime(), ascftime(), creat()
  • Incorrect use of open() with O_CREAT

Consider source code that produces warnings at this level to be a bug. The source code in question should be changed. In all cases, straightforward safer alternatives are available.

standard

This level includes all checks from the core level plus constructs that may be safe, but have better alternatives available. This level is recommended when checking newly-written code. Additional checks at this level include:

  • Use of string copy functions other than strlcpy()
  • Use of weak random number functions
  • Use of unsafe functions to generate temporary files
  • Use of fopen() to create files
  • Use of functions that invoke the shell

Replace source code that produces warnings at this level with new or significantly modified code. Balance addressing these warnings in legacy code against the risks of destabilizing the application.

security

This level contains the most complete set of checks, including everything from the Core and Standard levels. In addition, a number of warnings are generated about constructs that may be unsafe in some situations. The checks at this level are useful as an aid in reviewing code, but need not be used as a standard with which acceptable source code must comply. Additional checks at this level include:

  • Calls to getc() or fgetc() inside a loop
  • Use of functions prone to pathname race conditions
  • Use of the exec() family of functions
  • Race conditions between stat() and other functions

Review source code which produces warnings at this level to determine if the potential security issue is present.

%none

Turns off -errsecurity checks


If you do not specify a setting for -errsecurity, the lint sets it to -errsecury=%none. If you do specify -errsecurity but not an argument, the lint sets it to -errsecurity=standard.

5.3.14 -errtags=a

Displays the message tag for each error message. a can be either yes or no. The default is -errtags=no. Specifying -errtags is equivalent to specifying -errtags=yes.

Works with all -errfmt options.

5.3.15 -errwarn=t

If the indicated warning message is issued, lint exits with a failure status. t is a comma-separated list that consists of one or more of the following: tag, no%tag, %all, %none. Order is important; for example %all,no%tag causes lint to exit with a fatal status if any warning except tag is issued. The following table list the -errwarn values:

TABLE 5-6 The -errwarn Flags

tag

Cause lint to exit with a fatal status if the message specified by this tag is issued as a warning message. Has no effect if tag is not issued.

no%tag

Prevent lint from exiting with a fatal status if the message specified by tag is issued only as a warning message. Has no effect if tag is not issued. Use this option to revert a warning message that was previously specified by this option with tag or %all from causing lint to exit with a fatal status when issued as a warning message.

%all

Cause lint to exit with a fatal status if any warning messages are issued. %all can be followed by no%tag to exempt specific warning messages from this behavior.

%none

Prevents any warning message from causing lint to exit with a fatal status should any warning message be issued.


The default is -errwarn=%none. If you specify -errwarn alone, it is equivalent to -errwarn=%all.

5.3.16 -F

Prints the path names as supplied on the command line rather than only their base names when referring to the .c files named on the command line.

5.3.17 -fd

Reports about old-style function definitions or declarations.

5.3.18 -flagsrc=file

Executes lint with options contained in the file file. Multiple options can be specified in file, one per line.

5.3.19 -h

Suppresses certain messages. Refer to TABLE 5-8.

5.3.20 -Idir

Searches the directory dir for included header files.

5.3.21 -k

Alter the behavior of /* LINTED [message] */ directives or NOTE(LINTED(message)) annotations. Normally, lint suppresses warning messages for the code following these directives. Instead of suppressing the messages, lint prints an additional message containing the comment inside the directive or annotation.

5.3.22 -Ldir

Searches for a lint library in the directory dir when used with -l.

5.3.23 -lx

Accesses the lint library llib-lx.ln.

5.3.24 -m

Suppresses certain messages. Refer to TABLE 5-8.

5.3.25 -Ncheck=c

Checks header files for corresponding declarations; checks macros. c is a comma-separated list of checks that consists of one or more of the following: macro, extern, %all, %none, no%macro, no%extern.

TABLE 5-7 The -Ncheck Flags

Value

Meaning

macro

Checks for consistency of macro definitions across files

extern

Checks for one-to-one correspondence of declarations between source files and their associated header files (for example, for file1.c and file1.h). Ensure that there are neither extraneous nor missing extern declarations in a header file.

%all

Performs all of -Ncheck's checks

%none

Performs none of -Ncheck's checks. This is the default.

no%macro

Performs none of -Ncheck's macro checks

no%extern

Performs none of -Ncheck's extern checks


The default is -Ncheck=%none. Specifying -Ncheck is equivalent to specifying -Ncheck=%all.

Values may be combined with a comma, for example, -Ncheck=extern,macro.

Example:

% lint -Ncheck=%all,no%macro

performs all checks except macro checks.

5.3.26 -Nlevel=n

Turns on enhanced lint mode by specifying the level of enhanced lint analysis for reporting problems. This option allows you to control the amount of detected errors. The higher the level, the longer the verification time. n is a number: 1, 2, 3, or 4. There is no default. If you do not specify -Nlevel, lint uses its basic analysis mode. If you specify -Nlevel without an argument, lint sets -Nlevel=4.

See Section 5.2, Using lint for an explanation of basic and enhanced lint modes.

5.3.26.1 -Nlevel=1

Analyzes single procedures. Reports unconditional errors that occur on some program execution paths. Does not do global data and control flow analysis.

5.3.26.2 -Nlevel=2

Analyzes the whole program, including global data and control flow. Reports unconditional errors that occur on some program execution paths.

5.3.26.3 -Nlevel=3

Analyzes the whole program, including constant propagation, cases when constants are used as actual arguments, as well as the analysis performed under -Nlevel=2.

Verification of a C program at this analysis level takes two to four times longer then at the preceding level. The extra time is required because lint assumes partial interpretation of the program by creating sets of possible values for program variables. These sets of variables are created on the basis of constants and conditional statements that contain constant operands available in the program. The sets form the basis for creating other sets (a form of constant propagation). Sets received as the result of the analysis are evaluated for correctness according to the following algorithm:

If a correct value exists among all possible values of an object, then that correct value is used as the basis for further propagation; otherwise an error is diagnosed.

5.3.26.4 -Nlevel=4

Analyzes the whole program, and reports conditional errors that could occur when certain program execution paths are used, as well as the analysis performed under -Nlevel=3.

At this analysis level, there are additional diagnostic messages. The analysis algorithm generally corresponds to the analysis algorithm of -Nlevel=3 with the exception that any invalid values now generate an error message. The amount of time required for analysis at this level can increase as much as two orders (about 20 to 100 time more slowly). In this case the extra time required is directly proportional to the program complexity as characterized by recursion, conditional statements etc. As a result of this, it may be difficult to use this level of analysis for a program that exceeds 100,000 lines.

5.3.27 -n

Suppresses checks for compatibility with the default lint standard C library.

5.3.28 -ox

Causes lint to create a lint library with the name llib-lx.ln. This library is created from all the .ln files that lint used in its second pass. The -c option nullifies any use of the -o option. To produce a llib-lx.ln without extraneous messages, you can use the -x option. The -v option is useful if the source file(s) for the lint library are just external interfaces. The lint library produced can be used later if lint is invoked with -lx.

By default, you create libraries in lint's basic format. If you use lint's enhanced mode, the library created will be in enhanced format, and can only be used in enhanced mode.

5.3.29 -p

Enables certain messages relating to portability issues.

5.3.30 -Rfile

Write a .ln file to file, for use by cxref(1). This option disables the enhanced mode, if it is switched on.

5.3.31 -s

Converts compound messages into simple ones.

5.3.32 -u

Suppresses certain messages. Refer to TABLE 5-8. This option is suitable for running lint on a subset of files of a larger program.

5.3.33 -V

Writes the product name and releases to standard error.

5.3.34 -v

Suppresses certain messages. Refer to TABLE 5-8.

5.3.35 -Wfile

Write a .ln file to file, for use by cflow(1). This option disables the enhanced mode, if it is switched on.

5.3.36 -XCC=a

Accepts C++-style comments. In particular, // can be used to indicate the start of a comment. a can be either yes or no. The default is -XCC=no. Specifying -XCC is equivalent to specifying -XCC=yes.



Note - You only need to use this option if you use -xc99=none. Under -xc99=all (the default), lint accepts comments which are indicated by //.



5.3.37 -Xalias_level[=l]

where l is one of any, basic, weak, layout, strict, std, or strong. See TABLE B-11 for a detailed explanation of the different levels of disambiguation.

If you do not specify -Xalias_level, the default of the flag is -Xalias_level=any. This means that there is no type-based alias-analysis. If you specify -Xalias_level but do not supply a level, the default is -Xalias_level=layout.

Be sure to run lint at a level of disambiguation that is no more strict than the level at which you ran the compiler. If you run lint at a level of disambiguation that is more strict than the level at which you compiled, the results will be difficult to interpret and possibly misleading.

See Chapter 6 for a detailed explanation of disambiguation as well as a list of pragmas designed to help with disambiguation.

5.3.38 -Xarch=v9

Predefines the __sparcv9 macro and searches for v9 versions of lint libraries.

5.3.39 -Xc99[=o]

The -Xc99 flag controls compiler recognition of the implemented features from the C99 standard (ISO/IEC 9899:1999, Programming Language - C).

o can be one of the following: all, none.

-Xc99=none turns off recognition of C99 features. -Xc99=all turns on recognition of supported C99 features.

Specifying -Xc99 without any arguments is the same as -Xc99=all.



Note - Though the compiler support-level defaults to the features of C99 listed in Appendix D, the standard headers provided by Solaris software in /usr/include do not yet conform with the 1999 ISO/IEC C standard. If you encounter error messages, try using -Xc99=none to obtain the 1990 ISO/IEC C standard behavior for these headers.



5.3.40 -Xexplicitpar=a

(SPARC) Directs lint to recognize #pragma MP directives. a can be either yes or no. The default is -Xexplicitpar=no. Specifying -Xexplicitpar is equivalent to specifying -Xexplicitpar=yes.

5.3.41 -Xkeeptmp=a

Keeps temporary files created during linting instead of deleting them automatically. a can be either yes or no. The default is -Xkeeptmp=no. Specifying -Xkeeptmp is equivalent to specifying -Xkeeptmp=yes.

5.3.42 -Xtemp=dir

Sets the directory for temporary files to dir. Without this option, temporary files go into /tmp.

5.3.43 -Xtime=a

Reports the execution time for each lint pass. a can be either yes or no. The default is -Xtime=no. Specifying -Xtime is equivalent to specifying -Xtime=yes.

5.3.44 -Xtransition=a

Issues warnings for the differences between K&R C and Sun ISO C. a can be either yes or no. The default is -Xtransition=no. Specifying -Xtransition is equivalent to specifying -Xtransition=yes.

5.3.45 -Xustr={ascii_utf16_ushort|no}

This option enables recognition of string literals of the form U"ASCII_string" as an array of unsigned short int. The default is -Xustr=no which disables compiler recognition of U"ASCII_string string literals. "-Xustr=ascii_utf16_ushort enables compiler recognition of U"ASCII_string" string literals.

5.3.46 -x

Suppresses certain messages. Refer to TABLE 5-8.

5.3.47 -y

Treats every .c file named on the command line as if it begins with the directive /* LINTLIBRARY */ or the annotation NOTE(LINTLIBRARY). A lint library is normally created using the /* LINTLIBRARY */ directive or the NOTE(LINTLIBRARY) annotation.


5.4 lint Messages

Most of lint's messages are simple, one-line statements printed for each occurrence of the problem they diagnose. Errors detected in included files are reported multiple times by the compiler, but only once by lint, no matter how many times the file is included in other source files. Compound messages are issued for inconsistencies across files and, in a few cases, for problems within them as well. A single message describes every occurrence of the problem in the file or files being checked. When use of a lint filter (see Section 5.6.2, lint Libraries) requires that a message be printed for each occurrence, compound diagnostics can be converted to the simple type by invoking lint with the -s option.

lint's messages are written to stderr.

5.4.1 Options to Suppress Messages

You can use several lint options to suppress lint diagnostic messages. Messages can be suppressed with the -erroff option, followed by one or more tags. These mnemonic tags can be displayed with the -errtags=yes option.

The following table lists the options that suppress lint messages.

TABLE 5-8 lint Options to Suppress Messages

Option

Messages Suppressed

-a

assignment causes implicit narrowing conversion

conversion to larger integral type may sign-extend incorrectly

-b

statement not reached (unreachable break and empty statements)

-h

assignment operator "=" found where equality operator "==" was expected

constant operand to op: "!"

fallthrough on case statements

pointer cast may result in improper alignment

precedence confusion possible; parenthesize

statement has no consequent: if

statement has no consequent: else

-m

declared global, could be static

-erroff=tag

One or more lint messages specified by tag

-u

name defined but never used

name used but not defined

-v

arguments unused in function

-x

name declared but never used or defined


5.4.2 lint Message Formats

The lint program can, with certain options, show precise source file lines with pointers to the line position where the error occurred. The option enabling this feature is -errfmt=f. Under this option, lint provides the following information:

For example, the following program, Test1.c, contains an error.

1 #include <string.h>
2 static void cpv(char *s, char* v, unsigned n)
3 { int i;
4   for (i=0; i<=n; i++){
5        *v++ = *s++;}
6 }
7 void main(int argc, char* argv[])
8 {
9     if (argc != 0){
10        cpv(argv[0], argc, strlen(argv[0]));}
11}

Using lint on Test1.c with the option:

% lint -errfmt=src -Nlevel=2 Test1.c

produces the following output:

      |static void cpv(char *s, char* v, unsigned n)
      |            ^  line 2, Test1.c
      |
      |         cpv(argv[0], argc, strlen(argv[0]));
      |                      ^  line 10, Test1.c
warning: improper pointer/integer combination: arg #2
      |
      |static void cpv(char *s, char* v, unsigned n)
      |                               ^  line 2, Test1.c
      |
      |cpv(argv[0], argc, strlen(argv[0]));
      |                       ^ line 10, Test1.c
      |
      |        *v++ = *s++;
      |         ^  line 5, Test1.c
warning:use of a pointer produced in a questionable way
	v defined at Test1.c(2)	::Test1.c(5)
	  call stack:
		  main()                ,	Test1.c(10)
		  cpv()                 ,	Test1.c(5)

The first warning indicates two source lines that are contradictory. The second warning shows the call stack, with the control flow leading to the error.

Another program, Test2.c, contains a different error:

1 #define AA(b) AR[b+l]
2 #define B(c,d) c+AA(d)
3
4 int x=0;
5
6 int AR[10]={1,2,3,4,5,6,77,88,99,0};
7
8 main()
9  {
10  int y=-5, z=5;
11  return B(y,z);
12 }

Using lint on Test2.c with the option:

% lint -errfmt=macro Test2.c

produces the following output, showing the steps of macro substitution:

      | return B(y,z);
      |        ^  line 11, Test2.c
      |
      |#define B(c,d) c+AA(d)
      |                 ^  line 2, Test2.c
      |
      |#define AA(b) AR[b+l]
      |                   ^  line 1, Test2.c
error: undefined symbol: l
|
      |    return B(y,z);
      |           ^  line 11, Test2.c
      |
      |#define B(c,d) c+AA(d)
      |                 ^  line 2, Test2.c
      |
      |#define AA(b) AR[b+l]
      |                   ^  line 1, Test2.c
variable may be used before set: l
lint: errors in Test2.c; no output created
lint: pass2 not run - errors in Test2.c


5.5 lint Directives

5.5.1 Predefined Values

The following predefinitions are valid in all modes:

These predefinitions are not valid in -Xc mode:

5.5.2 Directives

lint directives in the form of /*...*/ are supported for existing annotations, but will not be supported for future annotations. Directives in the form of source code annotations, NOTE(...), are recommended for all annotations.

Specify lint directives in the form of source code annotations by including the file note.h, for example:

#include <note.h>

Lint shares the Source Code Annotations scheme with several other tools. When you install the Sun C compiler, you also automatically install the file /usr/lib/note/SUNW_SPRO-lint, which contains the names of all the annotations that LockLint understands. However, the Sun C source code checker, lint, also checks all the files in /usr/lib/note and /opt/SUNWspro/prod/lib/note for all valid annotations.

You may specify a location other than /usr/lib/note by setting the environment variable NOTEPATH, as in:

setenv NOTEPATH $NOTEPATH:other_location

The following table lists the lint directives along with their actions.

TABLE 5-9 The lint Directives

Directive

Action

NOTE(ALIGNMENT(fname,n)) where n=1, 2, 4, 8, 16, 32, 64, 128

Makes lint set the following function result alignment in n bytes. For example, malloc() is defined as returning a char* or void* when in fact it really returns pointers that are word, or even doubleword, aligned.

Suppresses the following message:

  • improper alignment

NOTE(ARGSUSED(n))

/*ARGSUSEDn*/

This directive acts like the -v option for the next function.

Suppresses the following message for every argument but the first n in the function definition it precedes. Default is 0. For the NOTE format, n must be specified.

  • argument unused in function

NOTE(ARGUNUSED

(par_name[,par_name...]))

Makes lint not check the mentioned arguments for usage (this option acts only for the next function).

Suppresses the following message for every argument listed in NOTE or directive.

  • argument unused in function

NOTE(CONSTCOND)

/*CONSTCOND*/

Suppresses complaints about constant operands for the conditional expression. Suppresses the following messages for the constructs it precedes. Also NOTE(CONSTANTCONDITION) or

/* CONSTANTCONDITION */.

constant in conditional context

constant operands to op: "!"

logical expression always false: op "&&"

logical expression always true: op "||"

NOTE(EMPTY) /*EMPTY*/

Suppresses complaints about a null statement consequent on an if statement. This directive should be placed after the test expression, and before the semicolon. This directive is supplied to support empty if statements when a valid else statement follows. It suppresses messages on an empty else consequent.

Suppresses the following messages when inserted between the controlling expression of the if and semicolon.

  • statement has no consequent: else

when inserted between the else and semicolon;

  • statement has no consequent: if

NOTE(FALLTHRU)

/*FALLTHRU*/

Suppresses complaints about a fall through to a case or default labelled statement. This directive should be placed immediately preceding the label.

Suppresses the following message for the case statement it precedes. Also NOTE(FALLTHROUGH) or /* FALLTHROUGH */.

  • fallthrough on case statement

NOTE(LINTED (msg))

/*LINTED [msg]*/

Suppresses any intra-file warning except those dealing with unused variables or functions. This directive should be placed on the line immediately preceding where the lint warning occurred. The -k option alters the way in which lint handles this directive. Instead of suppressing messages, lint prints an additional message, if any, contained in the comments. This directive is useful in conjunction with the -s option for post-lint filtering.

When -k is not invoked, suppresses every warning pertaining to an intra-file problem, except:

  • argument unused in function
  • declarations unused in block
  • set but not used in function
  • static unused
  • variable not used in function

for the line of code it precedes. msg is ignored.

NOTE(LINTLIBRARY)

/*LINTLIBRARY*/

When -o is invoked, writes to a library .ln file only definitions in the .c file it heads. This directive suppresses complaints about unused functions and function arguments in this file.

NOTE(NOTREACHED)

/*NOTREACHED*/

At appropriate points, stops comments about unreachable code. This comment is typically placed just after calls to functions such as exit(2).

Suppresses the following messages for the closing curly brace it precedes at the end of the function.

  • statement not reached

for the unreached statements it precedes;

  • fallthrough on case statement

for the case it precedes that cannot be reached from the preceding case;

  • function falls off bottom without returning value

NOTE(PRINTFLIKE(n))

NOTE(PRINTFLIKE(fun_name,n))

/*PRINTFLIKEn*/

Treats the nth argument of the function definition it precedes as a [fs]printf() format string and issues the following messages for mismatches between the remaining arguments and the conversion specifications. lint issues these warnings by default for errors in the calls to [fs]printf() functions provided by the standard C library.

For the NOTE format, n must be specified.

  • malformed format strings

for invalid conversion specifications in that argument, and function argument type inconsistent with format;

  • too few arguments for format
  • too many arguments for format

NOTE(PROTOLIB(n))

/*PROTOLIBn*/

When n is 1 and NOTE(LINTLIBRARY) or /* LINTLIBRARY */ is used, writes to a library .ln file only function prototype declarations in the .c file it heads. The default is 0, which cancels the process.

For the NOTE format, n must be specified.

NOTE(SCANFLIKE(n))

NOTE(SCANLIKE(fun_name,n))

/*SCANFLIKEn*/

Same as NOTE(PRINTFLIKE(n)) or /* PRINTFLIKEn */, except that the nth argument of the function definition is treated as a [fs]scanf() format string. By default, lint issues warnings for errors in the calls to [fs]scanf() functions provided by the standard C library.

For the NOTE format, n must be specified.

NOTE(VARARGS(n))

NOTE(VARARGS(fun_name,n))

/*VARARGSn*/

Suppresses the usual checking for variable numbers of arguments in the following function declaration. The data types of the first n arguments are checked; a missing n is taken to be 0. The use of the ellipsis (...) terminator in the definition is suggested in new or updated code.

For the function whose definition it precedes, suppresses the following message for calls to the function with n or more arguments. For the NOTE format, n must be specified.

  • functions called with variable number of arguments


5.6 lint Reference and Examples

This section provides reference information on lint, including checks performed by lint, lint libraries, and lint filters.

5.6.1 Diagnostics Performed by lint

lint-specific diagnostics are issued for three broad categories of conditions: inconsistent use, nonportable code, and questionable constructs. In this section, we review examples of lint's behavior in each of these areas, and suggest possible responses to the issues they raise.

5.6.1.1 Consistency Checks

Inconsistent use of variables, arguments, and functions is checked within files as well as across them. Generally speaking, the same checks are performed for prototype uses, declarations, and parameters as lint checks for old-style functions. If your program does not use function prototypes, lint checks the number and types of parameters in each call to a function more strictly than the compiler. lint also identifies mismatches of conversion specifications and arguments in [fs]printf() and [fs]scanf() control strings.

Examples:

Invoke the -x option to suppress the first complaint, -u to suppress the latter two.

5.6.1.2 Portability Checks

Some nonportable code is flagged by lint in its default behavior, and a few more cases are diagnosed when lint is invoked with -p or -Xc. The latter causes lint to check for constructs that do not conform to the ISO C standard. For the messages issued under -p and -Xc, see Section 5.6.2, lint Libraries.

Examples:

where EOF has the value -1, always fails on machines where character variables take on nonnegative values. lint invoked with -p checks all comparisons that imply a plain char may have a negative value. However, declaring c as a signed char in the above example eliminates the diagnostic, not the problem. That's because getchar() must return all possible characters and a distinct EOF value, so a char cannot store its value. We cite this example, perhaps the most common one arising from implementation-defined sign-extension, to show how a thoughtful application of lint's portability option can help you discover bugs not related to portability. In any case, declare c as an int.

lint flags all such assignments by default; the diagnostic can be suppressed by invoking the -a option. Bear in mind that you may be suppressing other diagnostics when you invoke lint with this or any other option. Check the list in Section 5.6.2, lint Libraries for the options that suppress more than one diagnostic.

because, on most machines, an int cannot start on an arbitrary byte boundary, whereas a char can. You can suppress the diagnostic by invoking lint with -h, although, again, you may be disabling other messages. Better still, eliminate the problem by using the generic pointer void *.

In this example, the value of a[1] may be 1 if one compiler is used, 2 if another. The bitwise logical operator & can give rise to this diagnostic when it is mistakenly used in place of the logical operator &&:

if ((c = getchar()) != EOF & c != '0')

5.6.1.3 Questionable Constructs

lint flags a miscellany of legal constructs that may not represent what the programmer intended. Examples:

always fails. The test:

unsigned x;
if (x > 0) ...

is equivalent to:

if (x != 0) ...

This may not be the intended action. lint flags questionable comparisons of unsigned variables with negative constants or 0. To compare an unsigned variable to the bit pattern of a negative number, cast it to unsigned:

if (u == (unsigned) -1) ... 

Or use the U suffix:

if (u == -1U) ... 

is evaluated as:

if (x & (a == 0)) ...

which is most likely not what you intended. Invoking lint with -h disables the diagnostic.

5.6.2 lint Libraries

You can use lint libraries to check your program for compatibility with the library functions you have called in it--the declaration of the function return type, the number and types of arguments the function expects, and so on. The standard lint libraries correspond to libraries supplied by the C compilation system, and generally are stored in a standard place on your system. By convention, lint libraries have names of the form llib-lx.ln.

The lint standard C library, llib-lc.ln, is appended to the lint command line by default; checks for compatibility with it can be suppressed by invoking the -n option. Other lint libraries are accessed as arguments to -l. That is:

% lint -lx file1.c file2.c

directs lint to check the usage of functions and variables in file1.c and file2.c for compatibility with the lint library llib-lx.ln. The library file, which consists only of definitions, is processed exactly as are ordinary source files and ordinary .ln files, except that functions and variables used inconsistently in the library file, or defined in the library file but not used in the source files, elicit no complaints.

To create your own lint library, insert the directive NOTE(LINTLIBRARY) at the head of a C source file, then invoke lint for that file with the -o option and the library name given to -l:

% lint -ox file1.c file2.c

causes only definitions in the source files headed by NOTE(LINTLIBRARY) to be written to the file llib-lx.ln. (Note the analogy of lint -o to cc -o.) A library can be created from a file of function prototype declarations in the same way, except that both NOTE(LINTLIBRARY) and NOTE(PROTOLIB(n))must be inserted at the head of the declarations file. If n is 1, prototype declarations are written to a library .ln file just as are old-style definitions. If n is 0, the default, the process is cancelled. Invoking lint with -y is another way of creating a lint library. The command line:

% lint -y -ox file1.c file2.c

causes each source file named on that line to be treated as if it begins with NOTE(LINTLIBRARY), and only its definitions to be written to llib-lx.ln.

By default, lint searches for lint libraries in the standard place. To direct lint to search for a lint library in a directory other than the standard place, specify the path of the directory with the -L option:

% lint -Ldir -lx file1.c file2.c

In enhanced mode, lint produces .ln files which store additional information than .ln files produced in basic mode. In enhanced mode, lint can read and understand all .ln files generated by either basic or enhanced lint modes. In basic mode, lint can read and understand .ln files generated only using basic lint mode.

By default, lint uses libraries from the /usr/lib directory. These libraries are in the basic lint format. You can run a makefile once, and create enhanced lint libraries in a new format, which will enable enhanced lint to work more effectively. To run the makefile and create the new libraries, enter the command:

% cd /opt/SUNWspro/prod/src/lintlib; make

where /opt/SUNWspro/prod is the installation directory. After the makefile is run, lint uses the new libraries in enhanced mode, instead of the libraries in the /usr/lib directory.

The specified directory is searched before the standard place.

5.6.3 lint Filters

A lint filter is a project-specific post-processor that typically uses an awk script or similar program to read the output of lint and discard messages that your project has deemed as not identifying real problems--string functions, for instance, returning values that are sometimes or always ignored. lint filters generate customized diagnostic reports when lint options and directives do not provide sufficient control over output.

Two options to lint are particularly useful in developing a filter:

Refer to the list of directives in TABLE 5-9 for an explanation of what lint does when -k is not invoked for a file containing NOTE(LINTED(msg)).